@devalade/algolang 1.0.1 → 2.0.1

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 +719 -191
  2. package/dist/index.js +1456 -385
  3. package/package.json +1 -1
package/dist/cli.js CHANGED
@@ -2632,6 +2632,269 @@ var chalk = createChalk();
2632
2632
  var chalkStderr = createChalk({ level: stderrColor ? stderrColor.level : 0 });
2633
2633
  var source_default = chalk;
2634
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
+ var BUILTIN_NAMES = new Set(Object.entries(KEYWORDS).filter(([, e]) => e.tokenType === null).map(([label]) => label));
2897
+
2635
2898
  // src/lexer/lexer.ts
2636
2899
  class Lexer {
2637
2900
  source;
@@ -2641,37 +2904,7 @@ class Lexer {
2641
2904
  keywords;
2642
2905
  constructor(source) {
2643
2906
  this.source = source;
2644
- this.keywords = new Map([
2645
- ["PROGRAMME", "PROGRAMME" /* PROGRAM */],
2646
- ["DEBUT", "DEBUT" /* BEGIN */],
2647
- ["FIN", "FIN" /* END */],
2648
- ["VAR", "VAR" /* VAR */],
2649
- ["ENTIER", "ENTIER" /* INTEGER */],
2650
- ["REEL", "REEL" /* REAL */],
2651
- ["BOOLEEN", "BOOLEEN" /* BOOLEAN */],
2652
- ["CHAINE", "CHAINE" /* STRING */],
2653
- ["SI", "SI" /* IF */],
2654
- ["ALORS", "ALORS" /* THEN */],
2655
- ["SINON", "SINON" /* ELSE */],
2656
- ["FINSI", "FINIF" /* ENDIF */],
2657
- ["TANTQUE", "TANTQUE" /* WHILE */],
2658
- ["FAIRE", "FAIRE" /* DO */],
2659
- ["POUR", "POUR" /* FOR */],
2660
- ["ALLANT", "ALLANT" /* ALLANT */],
2661
- ["DE", "DE" /* DE */],
2662
- ["A", "A" /* TO */],
2663
- ["REPETER", "REPETER" /* REPEAT */],
2664
- ["JUSQUA", "JUSQUA" /* UNTIL */],
2665
- ["LIRE", "LIRE" /* READ */],
2666
- ["ECRIRE", "ECRIRE" /* WRITE */],
2667
- ["VRAI", "VRAI" /* TRUE */],
2668
- ["FAUX", "FAUX" /* FALSE */],
2669
- ["ET", "ET" /* AND */],
2670
- ["OU", "OU" /* OR */],
2671
- ["NON", "NON" /* NOT */],
2672
- ["FINPOUR", "FINPOUR" /* ENDFOR */],
2673
- ["FINTANTQUE", "FINTANTQUE" /* ENDWHILE */]
2674
- ]);
2907
+ this.keywords = new Map(Object.entries(KEYWORDS).filter(([, e]) => e.tokenType !== null).map(([label, e]) => [label, e.tokenType]));
2675
2908
  }
2676
2909
  tokenize() {
2677
2910
  const tokens = [];
@@ -2744,6 +2977,8 @@ class Lexer {
2744
2977
  return this.createToken("MULTIPLY" /* MULTIPLY */, this.advance());
2745
2978
  case "/":
2746
2979
  return this.createToken("DIVIDE" /* DIVIDE */, this.advance());
2980
+ case "%":
2981
+ return this.createToken("MODULO" /* MODULO */, this.advance());
2747
2982
  case "=":
2748
2983
  return this.createToken("EQUAL" /* EQUAL */, this.advance());
2749
2984
  case "<":
@@ -2762,6 +2997,10 @@ class Lexer {
2762
2997
  return this.createToken("LEFT_PAREN" /* LEFT_PAREN */, this.advance());
2763
2998
  case ")":
2764
2999
  return this.createToken("RIGHT_PAREN" /* RIGHT_PAREN */, this.advance());
3000
+ case "[":
3001
+ return this.createToken("LEFT_BRACKET" /* LEFT_BRACKET */, this.advance());
3002
+ case "]":
3003
+ return this.createToken("RIGHT_BRACKET" /* RIGHT_BRACKET */, this.advance());
2765
3004
  default:
2766
3005
  throw new Error(`Caractère non reconnu '${char}' à la ligne ${this.line}, colonne ${this.column}`);
2767
3006
  }
@@ -2954,87 +3193,117 @@ class Lexer {
2954
3193
  }
2955
3194
  }
2956
3195
 
3196
+ // src/semantic/semantic-analyzer.ts
3197
+ class SemanticAnalyzer {
3198
+ symbolTable = {
3199
+ symbols: new Map,
3200
+ children: [],
3201
+ scopeName: "global"
3202
+ };
3203
+ errors = [];
3204
+ analyze(ast) {
3205
+ this.walk(ast);
3206
+ return { symbolTable: this.symbolTable, errors: this.errors };
3207
+ }
3208
+ walk(node) {
3209
+ switch (node.type) {
3210
+ case "VAR_DECLARATION" /* VAR_DECLARATION */:
3211
+ this.collectVarDeclaration(node);
3212
+ break;
3213
+ case "ARRAY_DECLARATION" /* ARRAY_DECLARATION */:
3214
+ this.collectArrayDeclaration(node);
3215
+ break;
3216
+ default:
3217
+ node.children?.forEach((child) => this.walk(child));
3218
+ break;
3219
+ }
3220
+ }
3221
+ collectVarDeclaration(node) {
3222
+ const algoType = node.value;
3223
+ const line = node.token?.line ?? 0;
3224
+ const column = node.token?.column ?? 0;
3225
+ const position = node.token?.position ?? 0;
3226
+ for (const child of node.children ?? []) {
3227
+ if (child.type !== "VARIABLE" /* VARIABLE */)
3228
+ continue;
3229
+ const name = child.value;
3230
+ if (this.validateName(name, line, column, position)) {
3231
+ this.defineSymbol(name, algoType, line, column);
3232
+ }
3233
+ }
3234
+ }
3235
+ collectArrayDeclaration(node) {
3236
+ const elemType = node.value;
3237
+ const sizeNode = node.children?.[0];
3238
+ const size = sizeNode?.value;
3239
+ const typeLabel = `TABLEAU[${size}] DE ${elemType}`;
3240
+ const line = node.token?.line ?? 0;
3241
+ const column = node.token?.column ?? 0;
3242
+ const position = node.token?.position ?? 0;
3243
+ for (const child of (node.children ?? []).slice(1)) {
3244
+ if (child.type !== "VARIABLE" /* VARIABLE */)
3245
+ continue;
3246
+ const name = child.value;
3247
+ if (this.validateName(name, line, column, position)) {
3248
+ this.defineSymbol(name, typeLabel, line, column);
3249
+ }
3250
+ }
3251
+ }
3252
+ validateName(name, line, column, position) {
3253
+ if (BUILTIN_NAMES.has(name)) {
3254
+ this.errors.push({
3255
+ type: "ERROR",
3256
+ message: `Le nom '${name}' est une fonction intégrée et ne peut pas être utilisé comme nom de variable`,
3257
+ line,
3258
+ column,
3259
+ position,
3260
+ code: "BUILTIN_SHADOWING",
3261
+ explanation: `'${name}' est une fonction intégrée d'AlgoLang`,
3262
+ suggestion: `Choisissez un autre nom, par exemple '${name}Valeur' ou 'mon${name.charAt(0).toUpperCase()}${name.slice(1)}'`
3263
+ });
3264
+ return false;
3265
+ }
3266
+ if (this.symbolTable.symbols.has(name)) {
3267
+ this.errors.push({
3268
+ type: "ERROR",
3269
+ message: `La variable '${name}' est déjà déclarée`,
3270
+ line,
3271
+ column,
3272
+ position,
3273
+ code: "DUPLICATE_VARIABLE",
3274
+ explanation: "Chaque variable doit avoir un nom unique dans son scope",
3275
+ suggestion: `Choisissez un autre nom pour la variable '${name}'`
3276
+ });
3277
+ return false;
3278
+ }
3279
+ return true;
3280
+ }
3281
+ defineSymbol(name, type, line, column) {
3282
+ const info = {
3283
+ name,
3284
+ type,
3285
+ scope: this.symbolTable.scopeName,
3286
+ line,
3287
+ column
3288
+ };
3289
+ this.symbolTable.symbols.set(name, info);
3290
+ }
3291
+ }
3292
+
2957
3293
  // src/parser/parser.ts
2958
3294
  class Parser {
2959
3295
  tokens;
2960
3296
  current = 0;
2961
3297
  errors = [];
2962
- symbolTable;
2963
- reservedKeywords = new Set([
2964
- "programme",
2965
- "debut",
2966
- "fin",
2967
- "var",
2968
- "entier",
2969
- "reel",
2970
- "booleen",
2971
- "chaine",
2972
- "si",
2973
- "alors",
2974
- "sinon",
2975
- "finsi",
2976
- "tantque",
2977
- "faire",
2978
- "fintantque",
2979
- "pour",
2980
- "a",
2981
- "finpour",
2982
- "repeter",
2983
- "jusqua",
2984
- "lire",
2985
- "ecrire",
2986
- "vrai",
2987
- "faux",
2988
- "et",
2989
- "ou",
2990
- "non",
2991
- "fonction",
2992
- "procedure",
2993
- "retourner"
2994
- ]);
3298
+ reservedKeywords = new Set(Object.entries(KEYWORDS).filter(([, e]) => e.tokenType !== null).map(([label]) => label.toLowerCase()));
2995
3299
  constructor(tokens) {
2996
3300
  this.tokens = tokens;
2997
- this.symbolTable = {
2998
- symbols: new Map,
2999
- children: [],
3000
- scopeName: "global"
3001
- };
3002
3301
  }
3003
3302
  isReservedKeyword(identifier) {
3004
3303
  return this.reservedKeywords.has(identifier.toLowerCase());
3005
3304
  }
3006
3305
  isKeywordToken(tokenType) {
3007
- return [
3008
- "PROGRAMME" /* PROGRAM */,
3009
- "DEBUT" /* BEGIN */,
3010
- "FIN" /* END */,
3011
- "VAR" /* VAR */,
3012
- "ENTIER" /* INTEGER */,
3013
- "REEL" /* REAL */,
3014
- "BOOLEEN" /* BOOLEAN */,
3015
- "CHAINE" /* STRING */,
3016
- "SI" /* IF */,
3017
- "ALORS" /* THEN */,
3018
- "SINON" /* ELSE */,
3019
- "TANTQUE" /* WHILE */,
3020
- "FAIRE" /* DO */,
3021
- "POUR" /* FOR */,
3022
- "ALLANT" /* ALLANT */,
3023
- "DE" /* DE */,
3024
- "A" /* TO */,
3025
- "REPETER" /* REPEAT */,
3026
- "JUSQUA" /* UNTIL */,
3027
- "LIRE" /* READ */,
3028
- "ECRIRE" /* WRITE */,
3029
- "VRAI" /* TRUE */,
3030
- "FAUX" /* FALSE */,
3031
- "ET" /* AND */,
3032
- "OU" /* OR */,
3033
- "NON" /* NOT */,
3034
- "FINPOUR" /* ENDFOR */,
3035
- "FINIF" /* ENDIF */,
3036
- "FINTANTQUE" /* ENDWHILE */
3037
- ].includes(tokenType);
3306
+ return Object.values(KEYWORDS).some((e) => e.tokenType === tokenType);
3038
3307
  }
3039
3308
  createReservedKeywordError(identifier, token) {
3040
3309
  this.errors.push({
@@ -3049,30 +3318,22 @@ class Parser {
3049
3318
  });
3050
3319
  }
3051
3320
  parse() {
3321
+ let ast;
3052
3322
  try {
3053
- const program2 = this.parseProgram();
3054
- return {
3055
- ast: program2,
3056
- errors: this.errors,
3057
- symbolTable: this.symbolTable
3058
- };
3323
+ ast = this.parseProgram();
3059
3324
  } catch (error) {
3060
- return {
3061
- ast: { type: "PROGRAM" /* PROGRAM */, children: [] },
3062
- errors: [
3063
- ...this.errors,
3064
- {
3065
- type: "ERROR",
3066
- message: error instanceof Error ? error.message : "Erreur de parsing inconnue",
3067
- line: 1,
3068
- column: 1,
3069
- position: 0,
3070
- code: "PARSE_ERROR"
3071
- }
3072
- ],
3073
- symbolTable: this.symbolTable
3074
- };
3325
+ ast = { type: "PROGRAM" /* PROGRAM */, children: [] };
3326
+ this.errors.push({
3327
+ type: "ERROR",
3328
+ message: error instanceof Error ? error.message : "Erreur de parsing inconnue",
3329
+ line: 1,
3330
+ column: 1,
3331
+ position: 0,
3332
+ code: "PARSE_ERROR"
3333
+ });
3075
3334
  }
3335
+ const { symbolTable, errors: semanticErrors } = new SemanticAnalyzer().analyze(ast);
3336
+ return { ast, errors: [...this.errors, ...semanticErrors], symbolTable };
3076
3337
  }
3077
3338
  parseProgram() {
3078
3339
  const programToken = this.expect("PROGRAMME" /* PROGRAM */, 'Le programme doit commencer par le mot-clé "programme"');
@@ -3088,17 +3349,25 @@ class Parser {
3088
3349
  }
3089
3350
  parseBlock() {
3090
3351
  const declarations = this.parseDeclarations();
3352
+ const subprograms = [];
3353
+ while (this.check(["FONCTION" /* FUNCTION */, "PROCEDURE" /* PROCEDURE */])) {
3354
+ if (this.check("FONCTION" /* FUNCTION */)) {
3355
+ subprograms.push(this.parseFunctionDeclaration());
3356
+ } else {
3357
+ subprograms.push(this.parseProcedureDeclaration());
3358
+ }
3359
+ }
3091
3360
  const compoundStatement = this.parseCompoundStatement();
3092
3361
  return {
3093
3362
  type: "BLOCK" /* BLOCK */,
3094
- children: [declarations, compoundStatement]
3363
+ children: [declarations, ...subprograms, compoundStatement]
3095
3364
  };
3096
3365
  }
3097
3366
  parseDeclarations() {
3098
3367
  const declarations = [];
3099
3368
  while (this.check("VAR" /* VAR */)) {
3100
3369
  this.advance();
3101
- while (!this.check("DEBUT" /* BEGIN */) && !this.isAtEnd()) {
3370
+ while (!this.check("DEBUT" /* BEGIN */) && !this.check("FONCTION" /* FUNCTION */) && !this.check("PROCEDURE" /* PROCEDURE */) && !this.isAtEnd()) {
3102
3371
  const declaration = this.parseVariableDeclaration();
3103
3372
  declarations.push(declaration);
3104
3373
  if (!this.check("SEMICOLON" /* SEMICOLON */)) {
@@ -3139,31 +3408,27 @@ class Parser {
3139
3408
  }
3140
3409
  } while (true);
3141
3410
  this.expect("COLON" /* COLON */, "Deux-points attendus après les identificateurs");
3411
+ if (this.check("TABLEAU" /* ARRAY */)) {
3412
+ this.advance();
3413
+ this.expect("LEFT_BRACKET" /* LEFT_BRACKET */, '"[" attendu après TABLEAU');
3414
+ const sizeToken = this.expect("NUMBER" /* NUMBER */, "Taille du tableau attendue");
3415
+ this.expect("RIGHT_BRACKET" /* RIGHT_BRACKET */, '"]" attendu après la taille du tableau');
3416
+ this.expect("DE" /* DE */, '"DE" attendu après la taille du tableau');
3417
+ const elemTypeToken = this.expect(["ENTIER" /* INTEGER */, "REEL" /* REAL */, "BOOLEEN" /* BOOLEAN */, "CHAINE" /* STRING */], "Type des éléments du tableau attendu");
3418
+ const elemType = this.tokenTypeToDataType(elemTypeToken.type);
3419
+ const size = parseInt(sizeToken.value);
3420
+ return {
3421
+ type: "ARRAY_DECLARATION" /* ARRAY_DECLARATION */,
3422
+ value: elemType,
3423
+ children: [
3424
+ { type: "LITERAL" /* LITERAL */, value: size },
3425
+ ...identifiers.map((name) => ({ type: "VARIABLE" /* VARIABLE */, value: name }))
3426
+ ],
3427
+ token: elemTypeToken
3428
+ };
3429
+ }
3142
3430
  const typeToken = this.expect(["ENTIER" /* INTEGER */, "REEL" /* REAL */, "BOOLEEN" /* BOOLEAN */, "CHAINE" /* STRING */], "Type de variable attendu");
3143
3431
  const type = this.tokenTypeToDataType(typeToken.type);
3144
- for (const identifier of identifiers) {
3145
- if (this.symbolTable.symbols.has(identifier)) {
3146
- this.errors.push({
3147
- type: "ERROR",
3148
- message: `La variable '${identifier}' est déjà déclarée`,
3149
- line: typeToken.line,
3150
- column: typeToken.column,
3151
- position: typeToken.position,
3152
- code: "DUPLICATE_VARIABLE",
3153
- explanation: "Chaque variable doit avoir un nom unique dans son scope",
3154
- suggestion: `Choisissez un autre nom pour la variable '${identifier}'`
3155
- });
3156
- } else {
3157
- const symbolInfo = {
3158
- name: identifier,
3159
- type,
3160
- scope: this.symbolTable.scopeName,
3161
- line: typeToken.line,
3162
- column: typeToken.column
3163
- };
3164
- this.symbolTable.symbols.set(identifier, symbolInfo);
3165
- }
3166
- }
3167
3432
  return {
3168
3433
  type: "VAR_DECLARATION" /* VAR_DECLARATION */,
3169
3434
  value: type,
@@ -3180,9 +3445,16 @@ class Parser {
3180
3445
  while (!this.check("FIN" /* END */) && !this.isAtEnd()) {
3181
3446
  const statement = this.parseStatement();
3182
3447
  statements.push(statement);
3448
+ const isBlockStatement = [
3449
+ "IF_STATEMENT" /* IF_STATEMENT */,
3450
+ "WHILE_STATEMENT" /* WHILE_STATEMENT */,
3451
+ "FOR_STATEMENT" /* FOR_STATEMENT */,
3452
+ "REPEAT_STATEMENT" /* REPEAT_STATEMENT */,
3453
+ "COMPOUND_STATEMENT" /* COMPOUND_STATEMENT */
3454
+ ].includes(statement.type);
3183
3455
  if (this.check("SEMICOLON" /* SEMICOLON */)) {
3184
3456
  this.advance();
3185
- } else if (!this.check("FIN" /* END */) && !this.check("FINIF" /* ENDIF */) && !this.check("FINTANTQUE" /* ENDWHILE */)) {
3457
+ } else if (!isBlockStatement && !this.check("FIN" /* END */) && !this.check("FINIF" /* ENDIF */) && !this.check("FINTANTQUE" /* ENDWHILE */) && !this.check("FINPOUR" /* ENDFOR */)) {
3186
3458
  this.errors.push({
3187
3459
  type: "ERROR",
3188
3460
  message: "Point-virgule attendu après l'instruction",
@@ -3225,6 +3497,16 @@ class Parser {
3225
3497
  if (this.check("ECRIRE" /* WRITE */)) {
3226
3498
  return this.parseWriteStatement();
3227
3499
  }
3500
+ if (this.check("RETOURNER" /* RETURN */)) {
3501
+ return this.parseReturnStatement();
3502
+ }
3503
+ if (this.check("IDENTIFIER" /* IDENTIFIER */) && this.peekAhead(1)?.type === "LEFT_PAREN" /* LEFT_PAREN */) {
3504
+ const nameToken = this.advance();
3505
+ return this.parseFunctionCall(nameToken);
3506
+ }
3507
+ if (this.check("IDENTIFIER" /* IDENTIFIER */) && this.peekAhead(1)?.type === "LEFT_BRACKET" /* LEFT_BRACKET */) {
3508
+ return this.parseArrayAssignment();
3509
+ }
3228
3510
  return this.parseAssignment();
3229
3511
  }
3230
3512
  parseIfStatement(isElseIf = false) {
@@ -3344,14 +3626,23 @@ class Parser {
3344
3626
  parseReadStatement() {
3345
3627
  const readToken = this.advance();
3346
3628
  this.expect("LEFT_PAREN" /* LEFT_PAREN */, 'Parenthèse ouvrante attendue après "lire"');
3347
- let variable;
3629
+ let target;
3348
3630
  if (this.check("IDENTIFIER" /* IDENTIFIER */)) {
3349
- variable = this.advance();
3631
+ const variable = this.advance();
3632
+ if (this.check("LEFT_BRACKET" /* LEFT_BRACKET */)) {
3633
+ this.advance();
3634
+ const index = this.parseExpression();
3635
+ this.expect("RIGHT_BRACKET" /* RIGHT_BRACKET */, `"]" attendu après l'index`);
3636
+ target = { type: "ARRAY_ACCESS" /* ARRAY_ACCESS */, value: variable.value, children: [index], token: variable };
3637
+ } else {
3638
+ target = { type: "VARIABLE" /* VARIABLE */, value: variable.value, token: variable };
3639
+ }
3350
3640
  } else {
3351
3641
  const currentToken = this.peek();
3352
3642
  if (this.isKeywordToken(currentToken.type)) {
3353
- variable = this.advance();
3643
+ const variable = this.advance();
3354
3644
  this.createReservedKeywordError(variable.value, variable);
3645
+ target = { type: "VARIABLE" /* VARIABLE */, value: variable.value, token: variable };
3355
3646
  } else {
3356
3647
  this.expect("IDENTIFIER" /* IDENTIFIER */, 'Variable attendue dans "lire"');
3357
3648
  throw new Error('Variable attendue dans "lire"');
@@ -3360,9 +3651,7 @@ class Parser {
3360
3651
  this.expect("RIGHT_PAREN" /* RIGHT_PAREN */, 'Parenthèse fermante attendue dans "lire"');
3361
3652
  return {
3362
3653
  type: "READ_STATEMENT" /* READ_STATEMENT */,
3363
- children: [
3364
- { type: "VARIABLE" /* VARIABLE */, value: variable.value, token: variable }
3365
- ],
3654
+ children: [target],
3366
3655
  token: readToken
3367
3656
  };
3368
3657
  }
@@ -3490,7 +3779,7 @@ class Parser {
3490
3779
  }
3491
3780
  parseMultiplicativeExpression() {
3492
3781
  let left = this.parseUnaryExpression();
3493
- while (this.check(["MULTIPLY" /* MULTIPLY */, "DIVIDE" /* DIVIDE */])) {
3782
+ while (this.check(["MULTIPLY" /* MULTIPLY */, "DIVIDE" /* DIVIDE */, "MODULO" /* MODULO */])) {
3494
3783
  const operator = this.advance();
3495
3784
  const right = this.parseUnaryExpression();
3496
3785
  left = {
@@ -3539,7 +3828,7 @@ class Parser {
3539
3828
  const token2 = this.advance();
3540
3829
  return {
3541
3830
  type: "LITERAL" /* LITERAL */,
3542
- value: token2.value === "vrai",
3831
+ value: token2.value.toLowerCase() === "vrai",
3543
3832
  token: token2
3544
3833
  };
3545
3834
  }
@@ -3553,6 +3842,20 @@ class Parser {
3553
3842
  }
3554
3843
  if (this.check("IDENTIFIER" /* IDENTIFIER */)) {
3555
3844
  const token2 = this.advance();
3845
+ if (this.check("LEFT_PAREN" /* LEFT_PAREN */)) {
3846
+ return this.parseFunctionCall(token2);
3847
+ }
3848
+ if (this.check("LEFT_BRACKET" /* LEFT_BRACKET */)) {
3849
+ this.advance();
3850
+ const index = this.parseExpression();
3851
+ this.expect("RIGHT_BRACKET" /* RIGHT_BRACKET */, `"]" attendu après l'index`);
3852
+ return {
3853
+ type: "ARRAY_ACCESS" /* ARRAY_ACCESS */,
3854
+ value: token2.value,
3855
+ children: [index],
3856
+ token: token2
3857
+ };
3858
+ }
3556
3859
  if (this.isReservedKeyword(token2.value)) {
3557
3860
  this.createReservedKeywordError(token2.value, token2);
3558
3861
  }
@@ -3596,14 +3899,14 @@ class Parser {
3596
3899
  parseRepeatStatement() {
3597
3900
  const repeatToken = this.advance();
3598
3901
  const statements = [];
3599
- while (!this.check("JUSQUA" /* UNTIL */) && !this.isAtEnd()) {
3902
+ while (!this.check("JUSQU'A" /* UNTIL */) && !this.isAtEnd()) {
3600
3903
  const statement = this.parseStatement();
3601
3904
  statements.push(statement);
3602
3905
  if (this.check("SEMICOLON" /* SEMICOLON */)) {
3603
3906
  this.advance();
3604
3907
  }
3605
3908
  }
3606
- this.expect("JUSQUA" /* UNTIL */, '"jusqua" attendu à la fin de la boucle repeter');
3909
+ this.expect("JUSQU'A" /* UNTIL */, `"jusqu'a" attendu à la fin de la boucle repeter`);
3607
3910
  const condition = this.parseExpression();
3608
3911
  return {
3609
3912
  type: "REPEAT_STATEMENT" /* REPEAT_STATEMENT */,
@@ -3611,6 +3914,127 @@ class Parser {
3611
3914
  token: repeatToken
3612
3915
  };
3613
3916
  }
3917
+ parseFunctionCall(nameToken) {
3918
+ this.advance();
3919
+ const args = [];
3920
+ if (!this.check("RIGHT_PAREN" /* RIGHT_PAREN */)) {
3921
+ args.push(this.parseExpression());
3922
+ while (this.check("COMMA" /* COMMA */)) {
3923
+ this.advance();
3924
+ args.push(this.parseExpression());
3925
+ }
3926
+ }
3927
+ this.expect("RIGHT_PAREN" /* RIGHT_PAREN */, '")` attendu après les arguments');
3928
+ return {
3929
+ type: "FUNCTION_CALL" /* FUNCTION_CALL */,
3930
+ value: nameToken.value,
3931
+ children: args,
3932
+ token: nameToken
3933
+ };
3934
+ }
3935
+ parseArrayAssignment() {
3936
+ const nameToken = this.advance();
3937
+ this.advance();
3938
+ const index = this.parseExpression();
3939
+ this.expect("RIGHT_BRACKET" /* RIGHT_BRACKET */, `"]" attendu après l'index`);
3940
+ this.expect("ASSIGN" /* ASSIGN */, `":=" attendu dans l'affectation`);
3941
+ const value = this.parseExpression();
3942
+ return {
3943
+ type: "ASSIGNMENT" /* ASSIGNMENT */,
3944
+ children: [
3945
+ { type: "ARRAY_ACCESS" /* ARRAY_ACCESS */, value: nameToken.value, children: [index], token: nameToken },
3946
+ value
3947
+ ],
3948
+ token: nameToken
3949
+ };
3950
+ }
3951
+ parseReturnStatement() {
3952
+ const token = this.advance();
3953
+ const expr = this.parseExpression();
3954
+ return {
3955
+ type: "RETURN_STATEMENT" /* RETURN_STATEMENT */,
3956
+ children: [expr],
3957
+ token
3958
+ };
3959
+ }
3960
+ parseParameterList() {
3961
+ this.expect("LEFT_PAREN" /* LEFT_PAREN */, '"(" attendu dans la déclaration');
3962
+ const params = [];
3963
+ if (!this.check("RIGHT_PAREN" /* RIGHT_PAREN */)) {
3964
+ params.push(this.parseParameter());
3965
+ while (this.check("SEMICOLON" /* SEMICOLON */) || this.check("COMMA" /* COMMA */)) {
3966
+ this.advance();
3967
+ if (this.check("RIGHT_PAREN" /* RIGHT_PAREN */))
3968
+ break;
3969
+ params.push(this.parseParameter());
3970
+ }
3971
+ }
3972
+ this.expect("RIGHT_PAREN" /* RIGHT_PAREN */, '")" attendu après les paramètres');
3973
+ return { type: "PARAMETER_LIST" /* PARAMETER_LIST */, children: params };
3974
+ }
3975
+ parseParameter() {
3976
+ const nameToken = this.expect("IDENTIFIER" /* IDENTIFIER */, "Nom de paramètre attendu");
3977
+ this.expect("COLON" /* COLON */, '":" attendu après le nom du paramètre');
3978
+ if (this.check("TABLEAU" /* ARRAY */)) {
3979
+ this.advance();
3980
+ let size;
3981
+ if (this.check("LEFT_BRACKET" /* LEFT_BRACKET */)) {
3982
+ this.advance();
3983
+ const sizeToken = this.expect("NUMBER" /* NUMBER */, "Taille attendue");
3984
+ this.expect("RIGHT_BRACKET" /* RIGHT_BRACKET */, '"]" attendu');
3985
+ size = parseInt(sizeToken.value);
3986
+ }
3987
+ this.expect("DE" /* DE */, '"DE" attendu après TABLEAU');
3988
+ const elemTypeToken = this.expect(["ENTIER" /* INTEGER */, "REEL" /* REAL */, "BOOLEEN" /* BOOLEAN */, "CHAINE" /* STRING */], "Type des éléments attendu");
3989
+ const elemType = this.tokenTypeToDataType(elemTypeToken.type);
3990
+ const typeLabel = size !== undefined ? `TABLEAU[${size}] DE ${elemType}` : `TABLEAU DE ${elemType}`;
3991
+ return {
3992
+ type: "PARAMETER" /* PARAMETER */,
3993
+ value: nameToken.value,
3994
+ token: nameToken,
3995
+ symbolInfo: { name: nameToken.value, type: typeLabel, scope: "param" }
3996
+ };
3997
+ }
3998
+ const typeToken = this.expect(["ENTIER" /* INTEGER */, "REEL" /* REAL */, "BOOLEEN" /* BOOLEAN */, "CHAINE" /* STRING */], "Type du paramètre attendu");
3999
+ const paramType = this.tokenTypeToDataType(typeToken.type);
4000
+ return {
4001
+ type: "PARAMETER" /* PARAMETER */,
4002
+ value: nameToken.value,
4003
+ token: nameToken,
4004
+ symbolInfo: { name: nameToken.value, type: paramType, scope: "param" }
4005
+ };
4006
+ }
4007
+ parseFunctionDeclaration() {
4008
+ const token = this.advance();
4009
+ const nameToken = this.expect("IDENTIFIER" /* IDENTIFIER */, "Nom de fonction attendu");
4010
+ const paramList = this.parseParameterList();
4011
+ this.expect("COLON" /* COLON */, '":" attendu pour le type de retour');
4012
+ const retTypeToken = this.expect(["ENTIER" /* INTEGER */, "REEL" /* REAL */, "BOOLEEN" /* BOOLEAN */, "CHAINE" /* STRING */], "Type de retour attendu");
4013
+ const retType = this.tokenTypeToDataType(retTypeToken.type);
4014
+ const body = this.parseCompoundStatement();
4015
+ return {
4016
+ type: "FUNCTION_DECLARATION" /* FUNCTION_DECLARATION */,
4017
+ value: nameToken.value,
4018
+ children: [
4019
+ paramList,
4020
+ { type: "TYPE_SPECIFIER" /* TYPE_SPECIFIER */, value: retType },
4021
+ body
4022
+ ],
4023
+ token
4024
+ };
4025
+ }
4026
+ parseProcedureDeclaration() {
4027
+ const token = this.advance();
4028
+ const nameToken = this.expect("IDENTIFIER" /* IDENTIFIER */, "Nom de procédure attendu");
4029
+ const paramList = this.parseParameterList();
4030
+ const body = this.parseCompoundStatement();
4031
+ return {
4032
+ type: "PROCEDURE_DECLARATION" /* PROCEDURE_DECLARATION */,
4033
+ value: nameToken.value,
4034
+ children: [paramList, body],
4035
+ token
4036
+ };
4037
+ }
3614
4038
  check(type) {
3615
4039
  if (this.isAtEnd())
3616
4040
  return false;
@@ -3760,6 +4184,8 @@ class CodeGenerator {
3760
4184
  return this.generateBlock(node);
3761
4185
  case "VAR_DECLARATION":
3762
4186
  return this.generateVariableDeclaration(node);
4187
+ case "ARRAY_DECLARATION":
4188
+ return this.generateArrayDeclaration(node);
3763
4189
  case "COMPOUND_STATEMENT":
3764
4190
  return this.generateCompoundStatement(node);
3765
4191
  case "ASSIGNMENT":
@@ -3776,6 +4202,12 @@ class CodeGenerator {
3776
4202
  return this.generateReadStatement(node);
3777
4203
  case "WRITE_STATEMENT":
3778
4204
  return this.generateWriteStatement(node);
4205
+ case "FUNCTION_DECLARATION":
4206
+ return this.generateFunctionDeclaration(node);
4207
+ case "PROCEDURE_DECLARATION":
4208
+ return this.generateProcedureDeclaration(node);
4209
+ case "RETURN_STATEMENT":
4210
+ return this.generateReturnStatement(node);
3779
4211
  case "BINARY_OP":
3780
4212
  return this.generateBinaryOp(node);
3781
4213
  case "UNARY_OP":
@@ -3784,6 +4216,10 @@ class CodeGenerator {
3784
4216
  return this.generateLiteral(node);
3785
4217
  case "VARIABLE":
3786
4218
  return this.generateVariable(node);
4219
+ case "ARRAY_ACCESS":
4220
+ return this.generateArrayAccess(node);
4221
+ case "FUNCTION_CALL":
4222
+ return this.generateFunctionCall(node);
3787
4223
  default:
3788
4224
  this.errors.push({
3789
4225
  type: "ERROR",
@@ -3798,14 +4234,25 @@ class CodeGenerator {
3798
4234
  }
3799
4235
  generateProgram(node) {
3800
4236
  const lines = [];
4237
+ const block = node.children?.[0];
3801
4238
  lines.push(`// Programme: ${node.value}`);
4239
+ if (block?.children) {
4240
+ for (const child of block.children) {
4241
+ if (child.type === "FUNCTION_DECLARATION" || child.type === "PROCEDURE_DECLARATION") {
4242
+ lines.push(this.generateNode(child));
4243
+ lines.push("");
4244
+ }
4245
+ }
4246
+ }
3802
4247
  lines.push("async function main() {");
3803
4248
  this.indentLevel++;
3804
- if (node.children && node.children.length > 0) {
3805
- for (const child of node.children) {
3806
- const childCode = this.generateNode(child);
3807
- if (childCode) {
3808
- lines.push(this.indent(childCode));
4249
+ if (block?.children) {
4250
+ for (const child of block.children) {
4251
+ if (child.type !== "FUNCTION_DECLARATION" && child.type !== "PROCEDURE_DECLARATION") {
4252
+ const childCode = this.generateNode(child);
4253
+ if (childCode) {
4254
+ lines.push(this.indent(childCode));
4255
+ }
3809
4256
  }
3810
4257
  }
3811
4258
  }
@@ -3843,7 +4290,8 @@ class CodeGenerator {
3843
4290
  for (const child of node.children) {
3844
4291
  const childCode = this.generateNode(child);
3845
4292
  if (childCode) {
3846
- lines.push(this.indent(childCode));
4293
+ const stmt = child.type === "FUNCTION_CALL" ? childCode.replace(/^\(|\)$/g, "") + ";" : childCode;
4294
+ lines.push(this.indent(stmt));
3847
4295
  }
3848
4296
  }
3849
4297
  }
@@ -3854,15 +4302,107 @@ class CodeGenerator {
3854
4302
  if (!node.children || node.children.length < 2) {
3855
4303
  return "";
3856
4304
  }
3857
- const variable = node.children[0];
4305
+ const target = node.children[0];
3858
4306
  const expression = node.children[1];
3859
- if (!variable || !expression) {
4307
+ if (!target || !expression) {
3860
4308
  return "";
3861
4309
  }
3862
- const variableName = variable.value;
3863
4310
  const expressionCode = this.generateNode(expression);
4311
+ if (target.type === "ARRAY_ACCESS") {
4312
+ const arrayName = target.value;
4313
+ const index = this.generateNode(target.children[0]);
4314
+ return `${arrayName}[${index}] = ${expressionCode};`;
4315
+ }
4316
+ const variableName = target.value;
3864
4317
  return `${variableName} = ${expressionCode};`;
3865
4318
  }
4319
+ generateArrayDeclaration(node) {
4320
+ if (!node.children || node.children.length < 2)
4321
+ return "";
4322
+ const size = node.children[0].value;
4323
+ const elemType = node.value;
4324
+ const defaultValue = elemType === "BOOLEEN" ? "false" : elemType === "CHAINE" ? '""' : "0";
4325
+ const names = node.children.slice(1).map((c) => c.value);
4326
+ return names.map((name) => `let ${name} = new Array(${size}).fill(${defaultValue});`).join(`
4327
+ `);
4328
+ }
4329
+ generateArrayAccess(node) {
4330
+ const name = node.value;
4331
+ const index = this.generateNode(node.children[0]);
4332
+ return `${name}[${index}]`;
4333
+ }
4334
+ generateFunctionCall(node) {
4335
+ const name = node.value;
4336
+ const args = (node.children ?? []).map((c) => {
4337
+ const code = this.generateNode(c);
4338
+ if (c.type === "VARIABLE") {
4339
+ const sym = this.symbolTable.symbols.get(c.value);
4340
+ if (sym?.type?.startsWith("TABLEAU"))
4341
+ return `${code}.slice()`;
4342
+ }
4343
+ return code;
4344
+ });
4345
+ switch (name.toLowerCase()) {
4346
+ case "abs":
4347
+ return `Math.abs(${args[0]})`;
4348
+ case "max":
4349
+ return `Math.max(${args.join(", ")})`;
4350
+ case "min":
4351
+ return `Math.min(${args.join(", ")})`;
4352
+ case "mod":
4353
+ return `(${args[0]} % ${args[1]})`;
4354
+ case "racine_carree":
4355
+ return `Math.sqrt(${args[0]})`;
4356
+ case "taille":
4357
+ return `${args[0]}.length`;
4358
+ case "sous_chaine":
4359
+ return `${args[0]}.substring(${args[1]}, ${args[1]} + ${args[2]})`;
4360
+ case "concat":
4361
+ return args.join(" + ");
4362
+ case "entier_en_reel":
4363
+ return `${args[0]}`;
4364
+ case "reel_en_entier":
4365
+ return `Math.trunc(${args[0]})`;
4366
+ default:
4367
+ return `(await ${name}(${args.join(", ")}))`;
4368
+ }
4369
+ }
4370
+ generateFunctionDeclaration(node) {
4371
+ const name = node.value;
4372
+ const [paramList, , body] = node.children ?? [];
4373
+ const params = this.generateParamList(paramList);
4374
+ const bodyCode = this.generateNode(body);
4375
+ const lines = [`async function ${name}(${params}) {`];
4376
+ this.indentLevel++;
4377
+ lines.push(this.indent(bodyCode));
4378
+ this.indentLevel--;
4379
+ lines.push("}");
4380
+ return lines.join(`
4381
+ `);
4382
+ }
4383
+ generateProcedureDeclaration(node) {
4384
+ const name = node.value;
4385
+ const [paramList, body] = node.children ?? [];
4386
+ const params = this.generateParamList(paramList);
4387
+ const bodyCode = this.generateNode(body);
4388
+ const lines = [`async function ${name}(${params}) {`];
4389
+ this.indentLevel++;
4390
+ lines.push(this.indent(bodyCode));
4391
+ this.indentLevel--;
4392
+ lines.push("}");
4393
+ return lines.join(`
4394
+ `);
4395
+ }
4396
+ generateParamList(paramList) {
4397
+ if (!paramList?.children)
4398
+ return "";
4399
+ return paramList.children.map((p) => p.value).join(", ");
4400
+ }
4401
+ generateReturnStatement(node) {
4402
+ if (!node.children?.[0])
4403
+ return "return;";
4404
+ return `return ${this.generateNode(node.children[0])};`;
4405
+ }
3866
4406
  generateIfStatement(node) {
3867
4407
  if (!node.children || node.children.length < 2) {
3868
4408
  return "";
@@ -3964,34 +4504,20 @@ class CodeGenerator {
3964
4504
  return code;
3965
4505
  }
3966
4506
  generateReadStatement(node) {
3967
- if (!node.children || node.children.length === 0) {
4507
+ if (!node.children || node.children.length === 0)
3968
4508
  return "";
3969
- }
3970
- const variable = node.children[0];
3971
- if (!variable) {
4509
+ const target = node.children[0];
4510
+ if (!target)
3972
4511
  return "";
4512
+ const isArray = target.type === "ARRAY_ACCESS";
4513
+ const varName = isArray ? `${target.value}[${this.generateNode(target.children[0])}]` : target.value;
4514
+ const symbolName = target.value;
4515
+ const symbolInfo = this.symbolTable.symbols.get(symbolName);
4516
+ const typeHint = symbolInfo?.type ?? "";
4517
+ if (typeHint.startsWith("ENTIER") || typeHint === "REEL" || typeHint.startsWith("TABLEAU")) {
4518
+ return `${varName} = parseInt(await lire(""));`;
3973
4519
  }
3974
- const variableName = variable.value;
3975
- const symbolInfo = this.symbolTable.symbols.get(variableName);
3976
- let conversion = "";
3977
- if (symbolInfo) {
3978
- switch (symbolInfo.type) {
3979
- case "ENTIER":
3980
- case "REEL":
3981
- conversion = "parseInt(";
3982
- break;
3983
- case "BOOLEEN":
3984
- conversion = "(";
3985
- break;
3986
- default:
3987
- conversion = "";
3988
- }
3989
- }
3990
- if (conversion) {
3991
- return `${variableName} = ${conversion}await lire(""));`;
3992
- } else {
3993
- return `${variableName} = await lire("");`;
3994
- }
4520
+ return `${varName} = await lire("");`;
3995
4521
  }
3996
4522
  generateWriteStatement(node) {
3997
4523
  if (!node.children || node.children.length === 0) {
@@ -4090,6 +4616,8 @@ class CodeGenerator {
4090
4616
  return ">";
4091
4617
  case ">=":
4092
4618
  return ">=";
4619
+ case "%":
4620
+ return "%";
4093
4621
  case "et":
4094
4622
  return "&&";
4095
4623
  case "ou":