@devalade/algolang 1.0.0 → 2.0.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (3) hide show
  1. package/dist/cli.js +709 -192
  2. package/dist/index.js +1435 -385
  3. package/package.json +7 -2
package/dist/cli.js CHANGED
@@ -1,5 +1,4 @@
1
1
  #!/usr/bin/env node
2
- #!/usr/bin/env bun
3
2
  // @bun
4
3
  import { createRequire } from "node:module";
5
4
  var __create = Object.create;
@@ -2633,6 +2632,268 @@ var chalk = createChalk();
2633
2632
  var chalkStderr = createChalk({ level: stderrColor ? stderrColor.level : 0 });
2634
2633
  var source_default = chalk;
2635
2634
 
2635
+ // src/keywords.ts
2636
+ var KEYWORDS = {
2637
+ PROGRAMME: {
2638
+ tokenType: "PROGRAMME" /* PROGRAM */,
2639
+ kind: "control",
2640
+ detail: "Mot-clé PROGRAMME",
2641
+ documentation: "**PROGRAMME** : Début d'un programme AlgoLang."
2642
+ },
2643
+ DEBUT: {
2644
+ tokenType: "DEBUT" /* BEGIN */,
2645
+ kind: "control",
2646
+ detail: "Mot-clé DEBUT",
2647
+ documentation: "**DEBUT** : Début du bloc d'instructions principal."
2648
+ },
2649
+ FIN: {
2650
+ tokenType: "FIN" /* END */,
2651
+ kind: "control",
2652
+ detail: "Mot-clé FIN",
2653
+ documentation: "**FIN** : Fin du bloc d'instructions ou du programme."
2654
+ },
2655
+ VAR: {
2656
+ tokenType: "VAR" /* VAR */,
2657
+ kind: "declaration",
2658
+ detail: "Mot-clé VAR",
2659
+ documentation: "**VAR** : Section de déclaration des variables."
2660
+ },
2661
+ ENTIER: {
2662
+ tokenType: "ENTIER" /* INTEGER */,
2663
+ kind: "type",
2664
+ detail: "Type ENTIER",
2665
+ documentation: "**ENTIER** : Type de donnée pour les nombres entiers."
2666
+ },
2667
+ REEL: {
2668
+ tokenType: "REEL" /* REAL */,
2669
+ kind: "type",
2670
+ detail: "Type REEL",
2671
+ documentation: "**REEL** : Type de donnée pour les nombres à virgule."
2672
+ },
2673
+ BOOLEEN: {
2674
+ tokenType: "BOOLEEN" /* BOOLEAN */,
2675
+ kind: "type",
2676
+ detail: "Type BOOLEEN",
2677
+ documentation: "**BOOLEEN** : Type de donnée logique (VRAI/FAUX)."
2678
+ },
2679
+ CHAINE: {
2680
+ tokenType: "CHAINE" /* STRING */,
2681
+ kind: "type",
2682
+ detail: "Type CHAINE",
2683
+ documentation: "**CHAINE** : Type de donnée pour le texte."
2684
+ },
2685
+ SI: {
2686
+ tokenType: "SI" /* IF */,
2687
+ kind: "control",
2688
+ detail: "Mot-clé SI",
2689
+ documentation: "**SI** : Structure conditionnelle."
2690
+ },
2691
+ ALORS: {
2692
+ tokenType: "ALORS" /* THEN */,
2693
+ kind: "control",
2694
+ detail: "Mot-clé ALORS",
2695
+ documentation: "**ALORS** : Début du bloc exécuté si la condition est vraie."
2696
+ },
2697
+ SINON: {
2698
+ tokenType: "SINON" /* ELSE */,
2699
+ kind: "control",
2700
+ detail: "Mot-clé SINON",
2701
+ documentation: "**SINON** : Début du bloc exécuté si la condition est fausse."
2702
+ },
2703
+ FINSI: {
2704
+ tokenType: "FINIF" /* ENDIF */,
2705
+ kind: "control",
2706
+ detail: "Mot-clé FINSI",
2707
+ documentation: "**FINSI** : Fin d'une structure conditionnelle."
2708
+ },
2709
+ TANTQUE: {
2710
+ tokenType: "TANTQUE" /* WHILE */,
2711
+ kind: "control",
2712
+ detail: "Mot-clé TANTQUE",
2713
+ documentation: "**TANTQUE** : Boucle répétitive tant qu'une condition est vraie."
2714
+ },
2715
+ FAIRE: {
2716
+ tokenType: "FAIRE" /* DO */,
2717
+ kind: "control",
2718
+ detail: "Mot-clé FAIRE",
2719
+ documentation: "**FAIRE** : Début du corps d'une boucle."
2720
+ },
2721
+ FINTANTQUE: {
2722
+ tokenType: "FINTANTQUE" /* ENDWHILE */,
2723
+ kind: "control",
2724
+ detail: "Mot-clé FINTANTQUE",
2725
+ documentation: "**FINTANTQUE** : Fin d'une boucle TANTQUE."
2726
+ },
2727
+ POUR: {
2728
+ tokenType: "POUR" /* FOR */,
2729
+ kind: "control",
2730
+ detail: "Mot-clé POUR",
2731
+ documentation: "**POUR** : Boucle avec compteur."
2732
+ },
2733
+ ALLANT: {
2734
+ tokenType: "ALLANT" /* ALLANT */,
2735
+ kind: "control",
2736
+ detail: "Mot-clé ALLANT",
2737
+ documentation: "**ALLANT** : Utilisé dans une boucle POUR pour spécifier la plage."
2738
+ },
2739
+ DE: {
2740
+ tokenType: "DE" /* DE */,
2741
+ kind: "control",
2742
+ detail: "Mot-clé DE",
2743
+ documentation: "**DE** : Spécifie le début d'une plage dans une boucle POUR."
2744
+ },
2745
+ A: {
2746
+ tokenType: "A" /* TO */,
2747
+ kind: "control",
2748
+ detail: "Mot-clé A",
2749
+ documentation: "**A** : Spécifie la fin d'une plage dans une boucle POUR."
2750
+ },
2751
+ FINPOUR: {
2752
+ tokenType: "FINPOUR" /* ENDFOR */,
2753
+ kind: "control",
2754
+ detail: "Mot-clé FINPOUR",
2755
+ documentation: "**FINPOUR** : Fin d'une boucle POUR."
2756
+ },
2757
+ REPETER: {
2758
+ tokenType: "REPETER" /* REPEAT */,
2759
+ kind: "control",
2760
+ detail: "Mot-clé REPETER",
2761
+ documentation: "**REPETER** : Boucle exécutée au moins une fois."
2762
+ },
2763
+ "JUSQU'A": {
2764
+ tokenType: "JUSQU'A" /* UNTIL */,
2765
+ kind: "control",
2766
+ detail: "Mot-clé JUSQU'A",
2767
+ documentation: "**JUSQU'A** : Condition de fin d'une boucle REPETER."
2768
+ },
2769
+ LIRE: {
2770
+ tokenType: "LIRE" /* READ */,
2771
+ kind: "io",
2772
+ detail: "Fonction LIRE",
2773
+ documentation: "**LIRE(variable)** : Lit une valeur depuis l'entrée standard."
2774
+ },
2775
+ ECRIRE: {
2776
+ tokenType: "ECRIRE" /* WRITE */,
2777
+ kind: "io",
2778
+ detail: "Fonction ECRIRE",
2779
+ documentation: "**ECRIRE(...)** : Affiche des valeurs dans la console."
2780
+ },
2781
+ VRAI: {
2782
+ tokenType: "VRAI" /* TRUE */,
2783
+ kind: "literal",
2784
+ detail: "Constante VRAI",
2785
+ documentation: "**VRAI** : Valeur booléenne vraie."
2786
+ },
2787
+ FAUX: {
2788
+ tokenType: "FAUX" /* FALSE */,
2789
+ kind: "literal",
2790
+ detail: "Constante FAUX",
2791
+ documentation: "**FAUX** : Valeur booléenne fausse."
2792
+ },
2793
+ ET: {
2794
+ tokenType: "ET" /* AND */,
2795
+ kind: "operator",
2796
+ detail: "Opérateur ET",
2797
+ documentation: "**ET** : Opérateur logique ET (AND)."
2798
+ },
2799
+ OU: {
2800
+ tokenType: "OU" /* OR */,
2801
+ kind: "operator",
2802
+ detail: "Opérateur OU",
2803
+ documentation: "**OU** : Opérateur logique OU (OR)."
2804
+ },
2805
+ NON: {
2806
+ tokenType: "NON" /* NOT */,
2807
+ kind: "operator",
2808
+ detail: "Opérateur NON",
2809
+ documentation: "**NON** : Opérateur logique NON (NOT)."
2810
+ },
2811
+ TABLEAU: {
2812
+ tokenType: "TABLEAU" /* ARRAY */,
2813
+ kind: "declaration",
2814
+ detail: "Type TABLEAU",
2815
+ documentation: "**TABLEAU** : Déclare un tableau de n éléments.\nSyntaxe : `t: TABLEAU[10] DE ENTIER`"
2816
+ },
2817
+ FONCTION: {
2818
+ tokenType: "FONCTION" /* FUNCTION */,
2819
+ kind: "declaration",
2820
+ detail: "Mot-clé FONCTION",
2821
+ documentation: "**FONCTION** nom(params): TYPE : Déclare une fonction qui retourne une valeur.\nExemple : `FONCTION carre(n: ENTIER): ENTIER`"
2822
+ },
2823
+ PROCEDURE: {
2824
+ tokenType: "PROCEDURE" /* PROCEDURE */,
2825
+ kind: "declaration",
2826
+ detail: "Mot-clé PROCEDURE",
2827
+ documentation: "**PROCEDURE** nom(params) : Déclare une procédure (sans valeur de retour).\nExemple : `PROCEDURE afficher(s: CHAINE)`"
2828
+ },
2829
+ RETOURNER: {
2830
+ tokenType: "RETOURNER" /* RETURN */,
2831
+ kind: "declaration",
2832
+ detail: "Mot-clé RETOURNER",
2833
+ documentation: "**RETOURNER** expr : Retourne une valeur depuis une fonction."
2834
+ },
2835
+ abs: {
2836
+ tokenType: null,
2837
+ kind: "builtin-function",
2838
+ detail: "Fonction abs(x)",
2839
+ documentation: "**abs(x)** : Retourne la valeur absolue de x."
2840
+ },
2841
+ max: {
2842
+ tokenType: null,
2843
+ kind: "builtin-function",
2844
+ detail: "Fonction max(a, b)",
2845
+ documentation: "**max(a, b)** : Retourne le plus grand des deux nombres."
2846
+ },
2847
+ min: {
2848
+ tokenType: null,
2849
+ kind: "builtin-function",
2850
+ detail: "Fonction min(a, b)",
2851
+ documentation: "**min(a, b)** : Retourne le plus petit des deux nombres."
2852
+ },
2853
+ mod: {
2854
+ tokenType: null,
2855
+ kind: "builtin-function",
2856
+ detail: "Fonction mod(a, b)",
2857
+ documentation: "**mod(a, b)** : Retourne le reste de la division de a par b. Équivalent à `a % b`."
2858
+ },
2859
+ racine_carree: {
2860
+ tokenType: null,
2861
+ kind: "builtin-function",
2862
+ detail: "Fonction racine_carree(x)",
2863
+ documentation: "**racine_carree(x)** : Retourne la racine carrée de x."
2864
+ },
2865
+ taille: {
2866
+ tokenType: null,
2867
+ kind: "builtin-function",
2868
+ detail: "Fonction taille(x)",
2869
+ documentation: "**taille(x)** : Retourne la taille d'un tableau ou la longueur d'une chaîne."
2870
+ },
2871
+ sous_chaine: {
2872
+ tokenType: null,
2873
+ kind: "builtin-function",
2874
+ detail: "Fonction sous_chaine(s, i, n)",
2875
+ documentation: "**sous_chaine(s, i, n)** : Retourne n caractères de la chaîne s à partir de l'indice i."
2876
+ },
2877
+ concat: {
2878
+ tokenType: null,
2879
+ kind: "builtin-function",
2880
+ detail: "Fonction concat(a, b)",
2881
+ documentation: "**concat(a, b)** : Concatène deux chaînes de caractères."
2882
+ },
2883
+ entier_en_reel: {
2884
+ tokenType: null,
2885
+ kind: "builtin-function",
2886
+ detail: "Fonction entier_en_reel(x)",
2887
+ documentation: "**entier_en_reel(x)** : Convertit un entier en réel."
2888
+ },
2889
+ reel_en_entier: {
2890
+ tokenType: null,
2891
+ kind: "builtin-function",
2892
+ detail: "Fonction reel_en_entier(x)",
2893
+ documentation: "**reel_en_entier(x)** : Convertit un réel en entier (troncature)."
2894
+ }
2895
+ };
2896
+
2636
2897
  // src/lexer/lexer.ts
2637
2898
  class Lexer {
2638
2899
  source;
@@ -2642,37 +2903,7 @@ class Lexer {
2642
2903
  keywords;
2643
2904
  constructor(source) {
2644
2905
  this.source = source;
2645
- this.keywords = new Map([
2646
- ["PROGRAMME", "PROGRAMME" /* PROGRAM */],
2647
- ["DEBUT", "DEBUT" /* BEGIN */],
2648
- ["FIN", "FIN" /* END */],
2649
- ["VAR", "VAR" /* VAR */],
2650
- ["ENTIER", "ENTIER" /* INTEGER */],
2651
- ["REEL", "REEL" /* REAL */],
2652
- ["BOOLEEN", "BOOLEEN" /* BOOLEAN */],
2653
- ["CHAINE", "CHAINE" /* STRING */],
2654
- ["SI", "SI" /* IF */],
2655
- ["ALORS", "ALORS" /* THEN */],
2656
- ["SINON", "SINON" /* ELSE */],
2657
- ["FINSI", "FINIF" /* ENDIF */],
2658
- ["TANTQUE", "TANTQUE" /* WHILE */],
2659
- ["FAIRE", "FAIRE" /* DO */],
2660
- ["POUR", "POUR" /* FOR */],
2661
- ["ALLANT", "ALLANT" /* ALLANT */],
2662
- ["DE", "DE" /* DE */],
2663
- ["A", "A" /* TO */],
2664
- ["REPETER", "REPETER" /* REPEAT */],
2665
- ["JUSQUA", "JUSQUA" /* UNTIL */],
2666
- ["LIRE", "LIRE" /* READ */],
2667
- ["ECRIRE", "ECRIRE" /* WRITE */],
2668
- ["VRAI", "VRAI" /* TRUE */],
2669
- ["FAUX", "FAUX" /* FALSE */],
2670
- ["ET", "ET" /* AND */],
2671
- ["OU", "OU" /* OR */],
2672
- ["NON", "NON" /* NOT */],
2673
- ["FINPOUR", "FINPOUR" /* ENDFOR */],
2674
- ["FINTANTQUE", "FINTANTQUE" /* ENDWHILE */]
2675
- ]);
2906
+ this.keywords = new Map(Object.entries(KEYWORDS).filter(([, e]) => e.tokenType !== null).map(([label, e]) => [label, e.tokenType]));
2676
2907
  }
2677
2908
  tokenize() {
2678
2909
  const tokens = [];
@@ -2745,6 +2976,8 @@ class Lexer {
2745
2976
  return this.createToken("MULTIPLY" /* MULTIPLY */, this.advance());
2746
2977
  case "/":
2747
2978
  return this.createToken("DIVIDE" /* DIVIDE */, this.advance());
2979
+ case "%":
2980
+ return this.createToken("MODULO" /* MODULO */, this.advance());
2748
2981
  case "=":
2749
2982
  return this.createToken("EQUAL" /* EQUAL */, this.advance());
2750
2983
  case "<":
@@ -2763,6 +2996,10 @@ class Lexer {
2763
2996
  return this.createToken("LEFT_PAREN" /* LEFT_PAREN */, this.advance());
2764
2997
  case ")":
2765
2998
  return this.createToken("RIGHT_PAREN" /* RIGHT_PAREN */, this.advance());
2999
+ case "[":
3000
+ return this.createToken("LEFT_BRACKET" /* LEFT_BRACKET */, this.advance());
3001
+ case "]":
3002
+ return this.createToken("RIGHT_BRACKET" /* RIGHT_BRACKET */, this.advance());
2766
3003
  default:
2767
3004
  throw new Error(`Caractère non reconnu '${char}' à la ligne ${this.line}, colonne ${this.column}`);
2768
3005
  }
@@ -2955,87 +3192,108 @@ class Lexer {
2955
3192
  }
2956
3193
  }
2957
3194
 
3195
+ // src/semantic/semantic-analyzer.ts
3196
+ class SemanticAnalyzer {
3197
+ symbolTable = {
3198
+ symbols: new Map,
3199
+ children: [],
3200
+ scopeName: "global"
3201
+ };
3202
+ errors = [];
3203
+ analyze(ast) {
3204
+ this.walk(ast);
3205
+ return { symbolTable: this.symbolTable, errors: this.errors };
3206
+ }
3207
+ walk(node) {
3208
+ switch (node.type) {
3209
+ case "VAR_DECLARATION" /* VAR_DECLARATION */:
3210
+ this.collectVarDeclaration(node);
3211
+ break;
3212
+ case "ARRAY_DECLARATION" /* ARRAY_DECLARATION */:
3213
+ this.collectArrayDeclaration(node);
3214
+ break;
3215
+ default:
3216
+ node.children?.forEach((child) => this.walk(child));
3217
+ break;
3218
+ }
3219
+ }
3220
+ collectVarDeclaration(node) {
3221
+ const algoType = node.value;
3222
+ const line = node.token?.line ?? 0;
3223
+ const column = node.token?.column ?? 0;
3224
+ for (const child of node.children ?? []) {
3225
+ if (child.type !== "VARIABLE" /* VARIABLE */)
3226
+ continue;
3227
+ const name = child.value;
3228
+ if (this.symbolTable.symbols.has(name)) {
3229
+ this.errors.push({
3230
+ type: "ERROR",
3231
+ message: `La variable '${name}' est déjà déclarée`,
3232
+ line,
3233
+ column,
3234
+ position: node.token?.position ?? 0,
3235
+ code: "DUPLICATE_VARIABLE",
3236
+ explanation: "Chaque variable doit avoir un nom unique dans son scope",
3237
+ suggestion: `Choisissez un autre nom pour la variable '${name}'`
3238
+ });
3239
+ } else {
3240
+ this.defineSymbol(name, algoType, line, column);
3241
+ }
3242
+ }
3243
+ }
3244
+ collectArrayDeclaration(node) {
3245
+ const elemType = node.value;
3246
+ const sizeNode = node.children?.[0];
3247
+ const size = sizeNode?.value;
3248
+ const typeLabel = `TABLEAU[${size}] DE ${elemType}`;
3249
+ const line = node.token?.line ?? 0;
3250
+ const column = node.token?.column ?? 0;
3251
+ for (const child of (node.children ?? []).slice(1)) {
3252
+ if (child.type !== "VARIABLE" /* VARIABLE */)
3253
+ continue;
3254
+ const name = child.value;
3255
+ if (this.symbolTable.symbols.has(name)) {
3256
+ this.errors.push({
3257
+ type: "ERROR",
3258
+ message: `La variable '${name}' est déjà déclarée`,
3259
+ line,
3260
+ column,
3261
+ position: node.token?.position ?? 0,
3262
+ code: "DUPLICATE_VARIABLE",
3263
+ explanation: "Chaque variable doit avoir un nom unique dans son scope",
3264
+ suggestion: `Choisissez un autre nom pour la variable '${name}'`
3265
+ });
3266
+ } else {
3267
+ this.defineSymbol(name, typeLabel, line, column);
3268
+ }
3269
+ }
3270
+ }
3271
+ defineSymbol(name, type, line, column) {
3272
+ const info = {
3273
+ name,
3274
+ type,
3275
+ scope: this.symbolTable.scopeName,
3276
+ line,
3277
+ column
3278
+ };
3279
+ this.symbolTable.symbols.set(name, info);
3280
+ }
3281
+ }
3282
+
2958
3283
  // src/parser/parser.ts
2959
3284
  class Parser {
2960
3285
  tokens;
2961
3286
  current = 0;
2962
3287
  errors = [];
2963
- symbolTable;
2964
- reservedKeywords = new Set([
2965
- "programme",
2966
- "debut",
2967
- "fin",
2968
- "var",
2969
- "entier",
2970
- "reel",
2971
- "booleen",
2972
- "chaine",
2973
- "si",
2974
- "alors",
2975
- "sinon",
2976
- "finsi",
2977
- "tantque",
2978
- "faire",
2979
- "fintantque",
2980
- "pour",
2981
- "a",
2982
- "finpour",
2983
- "repeter",
2984
- "jusqua",
2985
- "lire",
2986
- "ecrire",
2987
- "vrai",
2988
- "faux",
2989
- "et",
2990
- "ou",
2991
- "non",
2992
- "fonction",
2993
- "procedure",
2994
- "retourner"
2995
- ]);
3288
+ reservedKeywords = new Set(Object.entries(KEYWORDS).filter(([, e]) => e.tokenType !== null).map(([label]) => label.toLowerCase()));
2996
3289
  constructor(tokens) {
2997
3290
  this.tokens = tokens;
2998
- this.symbolTable = {
2999
- symbols: new Map,
3000
- children: [],
3001
- scopeName: "global"
3002
- };
3003
3291
  }
3004
3292
  isReservedKeyword(identifier) {
3005
3293
  return this.reservedKeywords.has(identifier.toLowerCase());
3006
3294
  }
3007
3295
  isKeywordToken(tokenType) {
3008
- return [
3009
- "PROGRAMME" /* PROGRAM */,
3010
- "DEBUT" /* BEGIN */,
3011
- "FIN" /* END */,
3012
- "VAR" /* VAR */,
3013
- "ENTIER" /* INTEGER */,
3014
- "REEL" /* REAL */,
3015
- "BOOLEEN" /* BOOLEAN */,
3016
- "CHAINE" /* STRING */,
3017
- "SI" /* IF */,
3018
- "ALORS" /* THEN */,
3019
- "SINON" /* ELSE */,
3020
- "TANTQUE" /* WHILE */,
3021
- "FAIRE" /* DO */,
3022
- "POUR" /* FOR */,
3023
- "ALLANT" /* ALLANT */,
3024
- "DE" /* DE */,
3025
- "A" /* TO */,
3026
- "REPETER" /* REPEAT */,
3027
- "JUSQUA" /* UNTIL */,
3028
- "LIRE" /* READ */,
3029
- "ECRIRE" /* WRITE */,
3030
- "VRAI" /* TRUE */,
3031
- "FAUX" /* FALSE */,
3032
- "ET" /* AND */,
3033
- "OU" /* OR */,
3034
- "NON" /* NOT */,
3035
- "FINPOUR" /* ENDFOR */,
3036
- "FINIF" /* ENDIF */,
3037
- "FINTANTQUE" /* ENDWHILE */
3038
- ].includes(tokenType);
3296
+ return Object.values(KEYWORDS).some((e) => e.tokenType === tokenType);
3039
3297
  }
3040
3298
  createReservedKeywordError(identifier, token) {
3041
3299
  this.errors.push({
@@ -3050,30 +3308,22 @@ class Parser {
3050
3308
  });
3051
3309
  }
3052
3310
  parse() {
3311
+ let ast;
3053
3312
  try {
3054
- const program2 = this.parseProgram();
3055
- return {
3056
- ast: program2,
3057
- errors: this.errors,
3058
- symbolTable: this.symbolTable
3059
- };
3313
+ ast = this.parseProgram();
3060
3314
  } catch (error) {
3061
- return {
3062
- ast: { type: "PROGRAM" /* PROGRAM */, children: [] },
3063
- errors: [
3064
- ...this.errors,
3065
- {
3066
- type: "ERROR",
3067
- message: error instanceof Error ? error.message : "Erreur de parsing inconnue",
3068
- line: 1,
3069
- column: 1,
3070
- position: 0,
3071
- code: "PARSE_ERROR"
3072
- }
3073
- ],
3074
- symbolTable: this.symbolTable
3075
- };
3315
+ ast = { type: "PROGRAM" /* PROGRAM */, children: [] };
3316
+ this.errors.push({
3317
+ type: "ERROR",
3318
+ message: error instanceof Error ? error.message : "Erreur de parsing inconnue",
3319
+ line: 1,
3320
+ column: 1,
3321
+ position: 0,
3322
+ code: "PARSE_ERROR"
3323
+ });
3076
3324
  }
3325
+ const { symbolTable, errors: semanticErrors } = new SemanticAnalyzer().analyze(ast);
3326
+ return { ast, errors: [...this.errors, ...semanticErrors], symbolTable };
3077
3327
  }
3078
3328
  parseProgram() {
3079
3329
  const programToken = this.expect("PROGRAMME" /* PROGRAM */, 'Le programme doit commencer par le mot-clé "programme"');
@@ -3089,17 +3339,25 @@ class Parser {
3089
3339
  }
3090
3340
  parseBlock() {
3091
3341
  const declarations = this.parseDeclarations();
3342
+ const subprograms = [];
3343
+ while (this.check(["FONCTION" /* FUNCTION */, "PROCEDURE" /* PROCEDURE */])) {
3344
+ if (this.check("FONCTION" /* FUNCTION */)) {
3345
+ subprograms.push(this.parseFunctionDeclaration());
3346
+ } else {
3347
+ subprograms.push(this.parseProcedureDeclaration());
3348
+ }
3349
+ }
3092
3350
  const compoundStatement = this.parseCompoundStatement();
3093
3351
  return {
3094
3352
  type: "BLOCK" /* BLOCK */,
3095
- children: [declarations, compoundStatement]
3353
+ children: [declarations, ...subprograms, compoundStatement]
3096
3354
  };
3097
3355
  }
3098
3356
  parseDeclarations() {
3099
3357
  const declarations = [];
3100
3358
  while (this.check("VAR" /* VAR */)) {
3101
3359
  this.advance();
3102
- while (!this.check("DEBUT" /* BEGIN */) && !this.isAtEnd()) {
3360
+ while (!this.check("DEBUT" /* BEGIN */) && !this.check("FONCTION" /* FUNCTION */) && !this.check("PROCEDURE" /* PROCEDURE */) && !this.isAtEnd()) {
3103
3361
  const declaration = this.parseVariableDeclaration();
3104
3362
  declarations.push(declaration);
3105
3363
  if (!this.check("SEMICOLON" /* SEMICOLON */)) {
@@ -3140,31 +3398,27 @@ class Parser {
3140
3398
  }
3141
3399
  } while (true);
3142
3400
  this.expect("COLON" /* COLON */, "Deux-points attendus après les identificateurs");
3401
+ if (this.check("TABLEAU" /* ARRAY */)) {
3402
+ this.advance();
3403
+ this.expect("LEFT_BRACKET" /* LEFT_BRACKET */, '"[" attendu après TABLEAU');
3404
+ const sizeToken = this.expect("NUMBER" /* NUMBER */, "Taille du tableau attendue");
3405
+ this.expect("RIGHT_BRACKET" /* RIGHT_BRACKET */, '"]" attendu après la taille du tableau');
3406
+ this.expect("DE" /* DE */, '"DE" attendu après la taille du tableau');
3407
+ const elemTypeToken = this.expect(["ENTIER" /* INTEGER */, "REEL" /* REAL */, "BOOLEEN" /* BOOLEAN */, "CHAINE" /* STRING */], "Type des éléments du tableau attendu");
3408
+ const elemType = this.tokenTypeToDataType(elemTypeToken.type);
3409
+ const size = parseInt(sizeToken.value);
3410
+ return {
3411
+ type: "ARRAY_DECLARATION" /* ARRAY_DECLARATION */,
3412
+ value: elemType,
3413
+ children: [
3414
+ { type: "LITERAL" /* LITERAL */, value: size },
3415
+ ...identifiers.map((name) => ({ type: "VARIABLE" /* VARIABLE */, value: name }))
3416
+ ],
3417
+ token: elemTypeToken
3418
+ };
3419
+ }
3143
3420
  const typeToken = this.expect(["ENTIER" /* INTEGER */, "REEL" /* REAL */, "BOOLEEN" /* BOOLEAN */, "CHAINE" /* STRING */], "Type de variable attendu");
3144
3421
  const type = this.tokenTypeToDataType(typeToken.type);
3145
- for (const identifier of identifiers) {
3146
- if (this.symbolTable.symbols.has(identifier)) {
3147
- this.errors.push({
3148
- type: "ERROR",
3149
- message: `La variable '${identifier}' est déjà déclarée`,
3150
- line: typeToken.line,
3151
- column: typeToken.column,
3152
- position: typeToken.position,
3153
- code: "DUPLICATE_VARIABLE",
3154
- explanation: "Chaque variable doit avoir un nom unique dans son scope",
3155
- suggestion: `Choisissez un autre nom pour la variable '${identifier}'`
3156
- });
3157
- } else {
3158
- const symbolInfo = {
3159
- name: identifier,
3160
- type,
3161
- scope: this.symbolTable.scopeName,
3162
- line: typeToken.line,
3163
- column: typeToken.column
3164
- };
3165
- this.symbolTable.symbols.set(identifier, symbolInfo);
3166
- }
3167
- }
3168
3422
  return {
3169
3423
  type: "VAR_DECLARATION" /* VAR_DECLARATION */,
3170
3424
  value: type,
@@ -3181,9 +3435,16 @@ class Parser {
3181
3435
  while (!this.check("FIN" /* END */) && !this.isAtEnd()) {
3182
3436
  const statement = this.parseStatement();
3183
3437
  statements.push(statement);
3438
+ const isBlockStatement = [
3439
+ "IF_STATEMENT" /* IF_STATEMENT */,
3440
+ "WHILE_STATEMENT" /* WHILE_STATEMENT */,
3441
+ "FOR_STATEMENT" /* FOR_STATEMENT */,
3442
+ "REPEAT_STATEMENT" /* REPEAT_STATEMENT */,
3443
+ "COMPOUND_STATEMENT" /* COMPOUND_STATEMENT */
3444
+ ].includes(statement.type);
3184
3445
  if (this.check("SEMICOLON" /* SEMICOLON */)) {
3185
3446
  this.advance();
3186
- } else if (!this.check("FIN" /* END */) && !this.check("FINIF" /* ENDIF */) && !this.check("FINTANTQUE" /* ENDWHILE */)) {
3447
+ } else if (!isBlockStatement && !this.check("FIN" /* END */) && !this.check("FINIF" /* ENDIF */) && !this.check("FINTANTQUE" /* ENDWHILE */) && !this.check("FINPOUR" /* ENDFOR */)) {
3187
3448
  this.errors.push({
3188
3449
  type: "ERROR",
3189
3450
  message: "Point-virgule attendu après l'instruction",
@@ -3226,6 +3487,16 @@ class Parser {
3226
3487
  if (this.check("ECRIRE" /* WRITE */)) {
3227
3488
  return this.parseWriteStatement();
3228
3489
  }
3490
+ if (this.check("RETOURNER" /* RETURN */)) {
3491
+ return this.parseReturnStatement();
3492
+ }
3493
+ if (this.check("IDENTIFIER" /* IDENTIFIER */) && this.peekAhead(1)?.type === "LEFT_PAREN" /* LEFT_PAREN */) {
3494
+ const nameToken = this.advance();
3495
+ return this.parseFunctionCall(nameToken);
3496
+ }
3497
+ if (this.check("IDENTIFIER" /* IDENTIFIER */) && this.peekAhead(1)?.type === "LEFT_BRACKET" /* LEFT_BRACKET */) {
3498
+ return this.parseArrayAssignment();
3499
+ }
3229
3500
  return this.parseAssignment();
3230
3501
  }
3231
3502
  parseIfStatement(isElseIf = false) {
@@ -3345,14 +3616,23 @@ class Parser {
3345
3616
  parseReadStatement() {
3346
3617
  const readToken = this.advance();
3347
3618
  this.expect("LEFT_PAREN" /* LEFT_PAREN */, 'Parenthèse ouvrante attendue après "lire"');
3348
- let variable;
3619
+ let target;
3349
3620
  if (this.check("IDENTIFIER" /* IDENTIFIER */)) {
3350
- variable = this.advance();
3621
+ const variable = this.advance();
3622
+ if (this.check("LEFT_BRACKET" /* LEFT_BRACKET */)) {
3623
+ this.advance();
3624
+ const index = this.parseExpression();
3625
+ this.expect("RIGHT_BRACKET" /* RIGHT_BRACKET */, `"]" attendu après l'index`);
3626
+ target = { type: "ARRAY_ACCESS" /* ARRAY_ACCESS */, value: variable.value, children: [index], token: variable };
3627
+ } else {
3628
+ target = { type: "VARIABLE" /* VARIABLE */, value: variable.value, token: variable };
3629
+ }
3351
3630
  } else {
3352
3631
  const currentToken = this.peek();
3353
3632
  if (this.isKeywordToken(currentToken.type)) {
3354
- variable = this.advance();
3633
+ const variable = this.advance();
3355
3634
  this.createReservedKeywordError(variable.value, variable);
3635
+ target = { type: "VARIABLE" /* VARIABLE */, value: variable.value, token: variable };
3356
3636
  } else {
3357
3637
  this.expect("IDENTIFIER" /* IDENTIFIER */, 'Variable attendue dans "lire"');
3358
3638
  throw new Error('Variable attendue dans "lire"');
@@ -3361,9 +3641,7 @@ class Parser {
3361
3641
  this.expect("RIGHT_PAREN" /* RIGHT_PAREN */, 'Parenthèse fermante attendue dans "lire"');
3362
3642
  return {
3363
3643
  type: "READ_STATEMENT" /* READ_STATEMENT */,
3364
- children: [
3365
- { type: "VARIABLE" /* VARIABLE */, value: variable.value, token: variable }
3366
- ],
3644
+ children: [target],
3367
3645
  token: readToken
3368
3646
  };
3369
3647
  }
@@ -3491,7 +3769,7 @@ class Parser {
3491
3769
  }
3492
3770
  parseMultiplicativeExpression() {
3493
3771
  let left = this.parseUnaryExpression();
3494
- while (this.check(["MULTIPLY" /* MULTIPLY */, "DIVIDE" /* DIVIDE */])) {
3772
+ while (this.check(["MULTIPLY" /* MULTIPLY */, "DIVIDE" /* DIVIDE */, "MODULO" /* MODULO */])) {
3495
3773
  const operator = this.advance();
3496
3774
  const right = this.parseUnaryExpression();
3497
3775
  left = {
@@ -3540,7 +3818,7 @@ class Parser {
3540
3818
  const token2 = this.advance();
3541
3819
  return {
3542
3820
  type: "LITERAL" /* LITERAL */,
3543
- value: token2.value === "vrai",
3821
+ value: token2.value.toLowerCase() === "vrai",
3544
3822
  token: token2
3545
3823
  };
3546
3824
  }
@@ -3554,6 +3832,20 @@ class Parser {
3554
3832
  }
3555
3833
  if (this.check("IDENTIFIER" /* IDENTIFIER */)) {
3556
3834
  const token2 = this.advance();
3835
+ if (this.check("LEFT_PAREN" /* LEFT_PAREN */)) {
3836
+ return this.parseFunctionCall(token2);
3837
+ }
3838
+ if (this.check("LEFT_BRACKET" /* LEFT_BRACKET */)) {
3839
+ this.advance();
3840
+ const index = this.parseExpression();
3841
+ this.expect("RIGHT_BRACKET" /* RIGHT_BRACKET */, `"]" attendu après l'index`);
3842
+ return {
3843
+ type: "ARRAY_ACCESS" /* ARRAY_ACCESS */,
3844
+ value: token2.value,
3845
+ children: [index],
3846
+ token: token2
3847
+ };
3848
+ }
3557
3849
  if (this.isReservedKeyword(token2.value)) {
3558
3850
  this.createReservedKeywordError(token2.value, token2);
3559
3851
  }
@@ -3597,14 +3889,14 @@ class Parser {
3597
3889
  parseRepeatStatement() {
3598
3890
  const repeatToken = this.advance();
3599
3891
  const statements = [];
3600
- while (!this.check("JUSQUA" /* UNTIL */) && !this.isAtEnd()) {
3892
+ while (!this.check("JUSQU'A" /* UNTIL */) && !this.isAtEnd()) {
3601
3893
  const statement = this.parseStatement();
3602
3894
  statements.push(statement);
3603
3895
  if (this.check("SEMICOLON" /* SEMICOLON */)) {
3604
3896
  this.advance();
3605
3897
  }
3606
3898
  }
3607
- this.expect("JUSQUA" /* UNTIL */, '"jusqua" attendu à la fin de la boucle repeter');
3899
+ this.expect("JUSQU'A" /* UNTIL */, `"jusqu'a" attendu à la fin de la boucle repeter`);
3608
3900
  const condition = this.parseExpression();
3609
3901
  return {
3610
3902
  type: "REPEAT_STATEMENT" /* REPEAT_STATEMENT */,
@@ -3612,6 +3904,127 @@ class Parser {
3612
3904
  token: repeatToken
3613
3905
  };
3614
3906
  }
3907
+ parseFunctionCall(nameToken) {
3908
+ this.advance();
3909
+ const args = [];
3910
+ if (!this.check("RIGHT_PAREN" /* RIGHT_PAREN */)) {
3911
+ args.push(this.parseExpression());
3912
+ while (this.check("COMMA" /* COMMA */)) {
3913
+ this.advance();
3914
+ args.push(this.parseExpression());
3915
+ }
3916
+ }
3917
+ this.expect("RIGHT_PAREN" /* RIGHT_PAREN */, '")` attendu après les arguments');
3918
+ return {
3919
+ type: "FUNCTION_CALL" /* FUNCTION_CALL */,
3920
+ value: nameToken.value,
3921
+ children: args,
3922
+ token: nameToken
3923
+ };
3924
+ }
3925
+ parseArrayAssignment() {
3926
+ const nameToken = this.advance();
3927
+ this.advance();
3928
+ const index = this.parseExpression();
3929
+ this.expect("RIGHT_BRACKET" /* RIGHT_BRACKET */, `"]" attendu après l'index`);
3930
+ this.expect("ASSIGN" /* ASSIGN */, `":=" attendu dans l'affectation`);
3931
+ const value = this.parseExpression();
3932
+ return {
3933
+ type: "ASSIGNMENT" /* ASSIGNMENT */,
3934
+ children: [
3935
+ { type: "ARRAY_ACCESS" /* ARRAY_ACCESS */, value: nameToken.value, children: [index], token: nameToken },
3936
+ value
3937
+ ],
3938
+ token: nameToken
3939
+ };
3940
+ }
3941
+ parseReturnStatement() {
3942
+ const token = this.advance();
3943
+ const expr = this.parseExpression();
3944
+ return {
3945
+ type: "RETURN_STATEMENT" /* RETURN_STATEMENT */,
3946
+ children: [expr],
3947
+ token
3948
+ };
3949
+ }
3950
+ parseParameterList() {
3951
+ this.expect("LEFT_PAREN" /* LEFT_PAREN */, '"(" attendu dans la déclaration');
3952
+ const params = [];
3953
+ if (!this.check("RIGHT_PAREN" /* RIGHT_PAREN */)) {
3954
+ params.push(this.parseParameter());
3955
+ while (this.check("SEMICOLON" /* SEMICOLON */) || this.check("COMMA" /* COMMA */)) {
3956
+ this.advance();
3957
+ if (this.check("RIGHT_PAREN" /* RIGHT_PAREN */))
3958
+ break;
3959
+ params.push(this.parseParameter());
3960
+ }
3961
+ }
3962
+ this.expect("RIGHT_PAREN" /* RIGHT_PAREN */, '")" attendu après les paramètres');
3963
+ return { type: "PARAMETER_LIST" /* PARAMETER_LIST */, children: params };
3964
+ }
3965
+ parseParameter() {
3966
+ const nameToken = this.expect("IDENTIFIER" /* IDENTIFIER */, "Nom de paramètre attendu");
3967
+ this.expect("COLON" /* COLON */, '":" attendu après le nom du paramètre');
3968
+ if (this.check("TABLEAU" /* ARRAY */)) {
3969
+ this.advance();
3970
+ let size;
3971
+ if (this.check("LEFT_BRACKET" /* LEFT_BRACKET */)) {
3972
+ this.advance();
3973
+ const sizeToken = this.expect("NUMBER" /* NUMBER */, "Taille attendue");
3974
+ this.expect("RIGHT_BRACKET" /* RIGHT_BRACKET */, '"]" attendu');
3975
+ size = parseInt(sizeToken.value);
3976
+ }
3977
+ this.expect("DE" /* DE */, '"DE" attendu après TABLEAU');
3978
+ const elemTypeToken = this.expect(["ENTIER" /* INTEGER */, "REEL" /* REAL */, "BOOLEEN" /* BOOLEAN */, "CHAINE" /* STRING */], "Type des éléments attendu");
3979
+ const elemType = this.tokenTypeToDataType(elemTypeToken.type);
3980
+ const typeLabel = size !== undefined ? `TABLEAU[${size}] DE ${elemType}` : `TABLEAU DE ${elemType}`;
3981
+ return {
3982
+ type: "PARAMETER" /* PARAMETER */,
3983
+ value: nameToken.value,
3984
+ token: nameToken,
3985
+ symbolInfo: { name: nameToken.value, type: typeLabel, scope: "param" }
3986
+ };
3987
+ }
3988
+ const typeToken = this.expect(["ENTIER" /* INTEGER */, "REEL" /* REAL */, "BOOLEEN" /* BOOLEAN */, "CHAINE" /* STRING */], "Type du paramètre attendu");
3989
+ const paramType = this.tokenTypeToDataType(typeToken.type);
3990
+ return {
3991
+ type: "PARAMETER" /* PARAMETER */,
3992
+ value: nameToken.value,
3993
+ token: nameToken,
3994
+ symbolInfo: { name: nameToken.value, type: paramType, scope: "param" }
3995
+ };
3996
+ }
3997
+ parseFunctionDeclaration() {
3998
+ const token = this.advance();
3999
+ const nameToken = this.expect("IDENTIFIER" /* IDENTIFIER */, "Nom de fonction attendu");
4000
+ const paramList = this.parseParameterList();
4001
+ this.expect("COLON" /* COLON */, '":" attendu pour le type de retour');
4002
+ const retTypeToken = this.expect(["ENTIER" /* INTEGER */, "REEL" /* REAL */, "BOOLEEN" /* BOOLEAN */, "CHAINE" /* STRING */], "Type de retour attendu");
4003
+ const retType = this.tokenTypeToDataType(retTypeToken.type);
4004
+ const body = this.parseCompoundStatement();
4005
+ return {
4006
+ type: "FUNCTION_DECLARATION" /* FUNCTION_DECLARATION */,
4007
+ value: nameToken.value,
4008
+ children: [
4009
+ paramList,
4010
+ { type: "TYPE_SPECIFIER" /* TYPE_SPECIFIER */, value: retType },
4011
+ body
4012
+ ],
4013
+ token
4014
+ };
4015
+ }
4016
+ parseProcedureDeclaration() {
4017
+ const token = this.advance();
4018
+ const nameToken = this.expect("IDENTIFIER" /* IDENTIFIER */, "Nom de procédure attendu");
4019
+ const paramList = this.parseParameterList();
4020
+ const body = this.parseCompoundStatement();
4021
+ return {
4022
+ type: "PROCEDURE_DECLARATION" /* PROCEDURE_DECLARATION */,
4023
+ value: nameToken.value,
4024
+ children: [paramList, body],
4025
+ token
4026
+ };
4027
+ }
3615
4028
  check(type) {
3616
4029
  if (this.isAtEnd())
3617
4030
  return false;
@@ -3761,6 +4174,8 @@ class CodeGenerator {
3761
4174
  return this.generateBlock(node);
3762
4175
  case "VAR_DECLARATION":
3763
4176
  return this.generateVariableDeclaration(node);
4177
+ case "ARRAY_DECLARATION":
4178
+ return this.generateArrayDeclaration(node);
3764
4179
  case "COMPOUND_STATEMENT":
3765
4180
  return this.generateCompoundStatement(node);
3766
4181
  case "ASSIGNMENT":
@@ -3777,6 +4192,12 @@ class CodeGenerator {
3777
4192
  return this.generateReadStatement(node);
3778
4193
  case "WRITE_STATEMENT":
3779
4194
  return this.generateWriteStatement(node);
4195
+ case "FUNCTION_DECLARATION":
4196
+ return this.generateFunctionDeclaration(node);
4197
+ case "PROCEDURE_DECLARATION":
4198
+ return this.generateProcedureDeclaration(node);
4199
+ case "RETURN_STATEMENT":
4200
+ return this.generateReturnStatement(node);
3780
4201
  case "BINARY_OP":
3781
4202
  return this.generateBinaryOp(node);
3782
4203
  case "UNARY_OP":
@@ -3785,6 +4206,10 @@ class CodeGenerator {
3785
4206
  return this.generateLiteral(node);
3786
4207
  case "VARIABLE":
3787
4208
  return this.generateVariable(node);
4209
+ case "ARRAY_ACCESS":
4210
+ return this.generateArrayAccess(node);
4211
+ case "FUNCTION_CALL":
4212
+ return this.generateFunctionCall(node);
3788
4213
  default:
3789
4214
  this.errors.push({
3790
4215
  type: "ERROR",
@@ -3799,14 +4224,25 @@ class CodeGenerator {
3799
4224
  }
3800
4225
  generateProgram(node) {
3801
4226
  const lines = [];
4227
+ const block = node.children?.[0];
3802
4228
  lines.push(`// Programme: ${node.value}`);
4229
+ if (block?.children) {
4230
+ for (const child of block.children) {
4231
+ if (child.type === "FUNCTION_DECLARATION" || child.type === "PROCEDURE_DECLARATION") {
4232
+ lines.push(this.generateNode(child));
4233
+ lines.push("");
4234
+ }
4235
+ }
4236
+ }
3803
4237
  lines.push("async function main() {");
3804
4238
  this.indentLevel++;
3805
- if (node.children && node.children.length > 0) {
3806
- for (const child of node.children) {
3807
- const childCode = this.generateNode(child);
3808
- if (childCode) {
3809
- lines.push(this.indent(childCode));
4239
+ if (block?.children) {
4240
+ for (const child of block.children) {
4241
+ if (child.type !== "FUNCTION_DECLARATION" && child.type !== "PROCEDURE_DECLARATION") {
4242
+ const childCode = this.generateNode(child);
4243
+ if (childCode) {
4244
+ lines.push(this.indent(childCode));
4245
+ }
3810
4246
  }
3811
4247
  }
3812
4248
  }
@@ -3844,7 +4280,8 @@ class CodeGenerator {
3844
4280
  for (const child of node.children) {
3845
4281
  const childCode = this.generateNode(child);
3846
4282
  if (childCode) {
3847
- lines.push(this.indent(childCode));
4283
+ const stmt = child.type === "FUNCTION_CALL" ? childCode.replace(/^\(|\)$/g, "") + ";" : childCode;
4284
+ lines.push(this.indent(stmt));
3848
4285
  }
3849
4286
  }
3850
4287
  }
@@ -3855,15 +4292,107 @@ class CodeGenerator {
3855
4292
  if (!node.children || node.children.length < 2) {
3856
4293
  return "";
3857
4294
  }
3858
- const variable = node.children[0];
4295
+ const target = node.children[0];
3859
4296
  const expression = node.children[1];
3860
- if (!variable || !expression) {
4297
+ if (!target || !expression) {
3861
4298
  return "";
3862
4299
  }
3863
- const variableName = variable.value;
3864
4300
  const expressionCode = this.generateNode(expression);
4301
+ if (target.type === "ARRAY_ACCESS") {
4302
+ const arrayName = target.value;
4303
+ const index = this.generateNode(target.children[0]);
4304
+ return `${arrayName}[${index}] = ${expressionCode};`;
4305
+ }
4306
+ const variableName = target.value;
3865
4307
  return `${variableName} = ${expressionCode};`;
3866
4308
  }
4309
+ generateArrayDeclaration(node) {
4310
+ if (!node.children || node.children.length < 2)
4311
+ return "";
4312
+ const size = node.children[0].value;
4313
+ const elemType = node.value;
4314
+ const defaultValue = elemType === "BOOLEEN" ? "false" : elemType === "CHAINE" ? '""' : "0";
4315
+ const names = node.children.slice(1).map((c) => c.value);
4316
+ return names.map((name) => `let ${name} = new Array(${size}).fill(${defaultValue});`).join(`
4317
+ `);
4318
+ }
4319
+ generateArrayAccess(node) {
4320
+ const name = node.value;
4321
+ const index = this.generateNode(node.children[0]);
4322
+ return `${name}[${index}]`;
4323
+ }
4324
+ generateFunctionCall(node) {
4325
+ const name = node.value;
4326
+ const args = (node.children ?? []).map((c) => {
4327
+ const code = this.generateNode(c);
4328
+ if (c.type === "VARIABLE") {
4329
+ const sym = this.symbolTable.symbols.get(c.value);
4330
+ if (sym?.type?.startsWith("TABLEAU"))
4331
+ return `${code}.slice()`;
4332
+ }
4333
+ return code;
4334
+ });
4335
+ switch (name.toLowerCase()) {
4336
+ case "abs":
4337
+ return `Math.abs(${args[0]})`;
4338
+ case "max":
4339
+ return `Math.max(${args.join(", ")})`;
4340
+ case "min":
4341
+ return `Math.min(${args.join(", ")})`;
4342
+ case "mod":
4343
+ return `(${args[0]} % ${args[1]})`;
4344
+ case "racine_carree":
4345
+ return `Math.sqrt(${args[0]})`;
4346
+ case "taille":
4347
+ return `${args[0]}.length`;
4348
+ case "sous_chaine":
4349
+ return `${args[0]}.substring(${args[1]}, ${args[1]} + ${args[2]})`;
4350
+ case "concat":
4351
+ return args.join(" + ");
4352
+ case "entier_en_reel":
4353
+ return `${args[0]}`;
4354
+ case "reel_en_entier":
4355
+ return `Math.trunc(${args[0]})`;
4356
+ default:
4357
+ return `(await ${name}(${args.join(", ")}))`;
4358
+ }
4359
+ }
4360
+ generateFunctionDeclaration(node) {
4361
+ const name = node.value;
4362
+ const [paramList, , body] = node.children ?? [];
4363
+ const params = this.generateParamList(paramList);
4364
+ const bodyCode = this.generateNode(body);
4365
+ const lines = [`async function ${name}(${params}) {`];
4366
+ this.indentLevel++;
4367
+ lines.push(this.indent(bodyCode));
4368
+ this.indentLevel--;
4369
+ lines.push("}");
4370
+ return lines.join(`
4371
+ `);
4372
+ }
4373
+ generateProcedureDeclaration(node) {
4374
+ const name = node.value;
4375
+ const [paramList, body] = node.children ?? [];
4376
+ const params = this.generateParamList(paramList);
4377
+ const bodyCode = this.generateNode(body);
4378
+ const lines = [`async function ${name}(${params}) {`];
4379
+ this.indentLevel++;
4380
+ lines.push(this.indent(bodyCode));
4381
+ this.indentLevel--;
4382
+ lines.push("}");
4383
+ return lines.join(`
4384
+ `);
4385
+ }
4386
+ generateParamList(paramList) {
4387
+ if (!paramList?.children)
4388
+ return "";
4389
+ return paramList.children.map((p) => p.value).join(", ");
4390
+ }
4391
+ generateReturnStatement(node) {
4392
+ if (!node.children?.[0])
4393
+ return "return;";
4394
+ return `return ${this.generateNode(node.children[0])};`;
4395
+ }
3867
4396
  generateIfStatement(node) {
3868
4397
  if (!node.children || node.children.length < 2) {
3869
4398
  return "";
@@ -3965,34 +4494,20 @@ class CodeGenerator {
3965
4494
  return code;
3966
4495
  }
3967
4496
  generateReadStatement(node) {
3968
- if (!node.children || node.children.length === 0) {
4497
+ if (!node.children || node.children.length === 0)
3969
4498
  return "";
3970
- }
3971
- const variable = node.children[0];
3972
- if (!variable) {
4499
+ const target = node.children[0];
4500
+ if (!target)
3973
4501
  return "";
4502
+ const isArray = target.type === "ARRAY_ACCESS";
4503
+ const varName = isArray ? `${target.value}[${this.generateNode(target.children[0])}]` : target.value;
4504
+ const symbolName = target.value;
4505
+ const symbolInfo = this.symbolTable.symbols.get(symbolName);
4506
+ const typeHint = symbolInfo?.type ?? "";
4507
+ if (typeHint.startsWith("ENTIER") || typeHint === "REEL" || typeHint.startsWith("TABLEAU")) {
4508
+ return `${varName} = parseInt(await lire(""));`;
3974
4509
  }
3975
- const variableName = variable.value;
3976
- const symbolInfo = this.symbolTable.symbols.get(variableName);
3977
- let conversion = "";
3978
- if (symbolInfo) {
3979
- switch (symbolInfo.type) {
3980
- case "ENTIER":
3981
- case "REEL":
3982
- conversion = "parseInt(";
3983
- break;
3984
- case "BOOLEEN":
3985
- conversion = "(";
3986
- break;
3987
- default:
3988
- conversion = "";
3989
- }
3990
- }
3991
- if (conversion) {
3992
- return `${variableName} = ${conversion}await lire(""));`;
3993
- } else {
3994
- return `${variableName} = await lire("");`;
3995
- }
4510
+ return `${varName} = await lire("");`;
3996
4511
  }
3997
4512
  generateWriteStatement(node) {
3998
4513
  if (!node.children || node.children.length === 0) {
@@ -4091,6 +4606,8 @@ class CodeGenerator {
4091
4606
  return ">";
4092
4607
  case ">=":
4093
4608
  return ">=";
4609
+ case "%":
4610
+ return "%";
4094
4611
  case "et":
4095
4612
  return "&&";
4096
4613
  case "ou":