@devalade/algolang 1.0.1 → 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 -191
  2. package/dist/index.js +1435 -385
  3. package/package.json +1 -1
package/dist/cli.js CHANGED
@@ -2632,6 +2632,268 @@ 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
+
2635
2897
  // src/lexer/lexer.ts
2636
2898
  class Lexer {
2637
2899
  source;
@@ -2641,37 +2903,7 @@ class Lexer {
2641
2903
  keywords;
2642
2904
  constructor(source) {
2643
2905
  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
- ]);
2906
+ this.keywords = new Map(Object.entries(KEYWORDS).filter(([, e]) => e.tokenType !== null).map(([label, e]) => [label, e.tokenType]));
2675
2907
  }
2676
2908
  tokenize() {
2677
2909
  const tokens = [];
@@ -2744,6 +2976,8 @@ class Lexer {
2744
2976
  return this.createToken("MULTIPLY" /* MULTIPLY */, this.advance());
2745
2977
  case "/":
2746
2978
  return this.createToken("DIVIDE" /* DIVIDE */, this.advance());
2979
+ case "%":
2980
+ return this.createToken("MODULO" /* MODULO */, this.advance());
2747
2981
  case "=":
2748
2982
  return this.createToken("EQUAL" /* EQUAL */, this.advance());
2749
2983
  case "<":
@@ -2762,6 +2996,10 @@ class Lexer {
2762
2996
  return this.createToken("LEFT_PAREN" /* LEFT_PAREN */, this.advance());
2763
2997
  case ")":
2764
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());
2765
3003
  default:
2766
3004
  throw new Error(`Caractère non reconnu '${char}' à la ligne ${this.line}, colonne ${this.column}`);
2767
3005
  }
@@ -2954,87 +3192,108 @@ class Lexer {
2954
3192
  }
2955
3193
  }
2956
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
+
2957
3283
  // src/parser/parser.ts
2958
3284
  class Parser {
2959
3285
  tokens;
2960
3286
  current = 0;
2961
3287
  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
- ]);
3288
+ reservedKeywords = new Set(Object.entries(KEYWORDS).filter(([, e]) => e.tokenType !== null).map(([label]) => label.toLowerCase()));
2995
3289
  constructor(tokens) {
2996
3290
  this.tokens = tokens;
2997
- this.symbolTable = {
2998
- symbols: new Map,
2999
- children: [],
3000
- scopeName: "global"
3001
- };
3002
3291
  }
3003
3292
  isReservedKeyword(identifier) {
3004
3293
  return this.reservedKeywords.has(identifier.toLowerCase());
3005
3294
  }
3006
3295
  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);
3296
+ return Object.values(KEYWORDS).some((e) => e.tokenType === tokenType);
3038
3297
  }
3039
3298
  createReservedKeywordError(identifier, token) {
3040
3299
  this.errors.push({
@@ -3049,30 +3308,22 @@ class Parser {
3049
3308
  });
3050
3309
  }
3051
3310
  parse() {
3311
+ let ast;
3052
3312
  try {
3053
- const program2 = this.parseProgram();
3054
- return {
3055
- ast: program2,
3056
- errors: this.errors,
3057
- symbolTable: this.symbolTable
3058
- };
3313
+ ast = this.parseProgram();
3059
3314
  } 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
- };
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
+ });
3075
3324
  }
3325
+ const { symbolTable, errors: semanticErrors } = new SemanticAnalyzer().analyze(ast);
3326
+ return { ast, errors: [...this.errors, ...semanticErrors], symbolTable };
3076
3327
  }
3077
3328
  parseProgram() {
3078
3329
  const programToken = this.expect("PROGRAMME" /* PROGRAM */, 'Le programme doit commencer par le mot-clé "programme"');
@@ -3088,17 +3339,25 @@ class Parser {
3088
3339
  }
3089
3340
  parseBlock() {
3090
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
+ }
3091
3350
  const compoundStatement = this.parseCompoundStatement();
3092
3351
  return {
3093
3352
  type: "BLOCK" /* BLOCK */,
3094
- children: [declarations, compoundStatement]
3353
+ children: [declarations, ...subprograms, compoundStatement]
3095
3354
  };
3096
3355
  }
3097
3356
  parseDeclarations() {
3098
3357
  const declarations = [];
3099
3358
  while (this.check("VAR" /* VAR */)) {
3100
3359
  this.advance();
3101
- while (!this.check("DEBUT" /* BEGIN */) && !this.isAtEnd()) {
3360
+ while (!this.check("DEBUT" /* BEGIN */) && !this.check("FONCTION" /* FUNCTION */) && !this.check("PROCEDURE" /* PROCEDURE */) && !this.isAtEnd()) {
3102
3361
  const declaration = this.parseVariableDeclaration();
3103
3362
  declarations.push(declaration);
3104
3363
  if (!this.check("SEMICOLON" /* SEMICOLON */)) {
@@ -3139,31 +3398,27 @@ class Parser {
3139
3398
  }
3140
3399
  } while (true);
3141
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
+ }
3142
3420
  const typeToken = this.expect(["ENTIER" /* INTEGER */, "REEL" /* REAL */, "BOOLEEN" /* BOOLEAN */, "CHAINE" /* STRING */], "Type de variable attendu");
3143
3421
  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
3422
  return {
3168
3423
  type: "VAR_DECLARATION" /* VAR_DECLARATION */,
3169
3424
  value: type,
@@ -3180,9 +3435,16 @@ class Parser {
3180
3435
  while (!this.check("FIN" /* END */) && !this.isAtEnd()) {
3181
3436
  const statement = this.parseStatement();
3182
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);
3183
3445
  if (this.check("SEMICOLON" /* SEMICOLON */)) {
3184
3446
  this.advance();
3185
- } 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 */)) {
3186
3448
  this.errors.push({
3187
3449
  type: "ERROR",
3188
3450
  message: "Point-virgule attendu après l'instruction",
@@ -3225,6 +3487,16 @@ class Parser {
3225
3487
  if (this.check("ECRIRE" /* WRITE */)) {
3226
3488
  return this.parseWriteStatement();
3227
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
+ }
3228
3500
  return this.parseAssignment();
3229
3501
  }
3230
3502
  parseIfStatement(isElseIf = false) {
@@ -3344,14 +3616,23 @@ class Parser {
3344
3616
  parseReadStatement() {
3345
3617
  const readToken = this.advance();
3346
3618
  this.expect("LEFT_PAREN" /* LEFT_PAREN */, 'Parenthèse ouvrante attendue après "lire"');
3347
- let variable;
3619
+ let target;
3348
3620
  if (this.check("IDENTIFIER" /* IDENTIFIER */)) {
3349
- 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
+ }
3350
3630
  } else {
3351
3631
  const currentToken = this.peek();
3352
3632
  if (this.isKeywordToken(currentToken.type)) {
3353
- variable = this.advance();
3633
+ const variable = this.advance();
3354
3634
  this.createReservedKeywordError(variable.value, variable);
3635
+ target = { type: "VARIABLE" /* VARIABLE */, value: variable.value, token: variable };
3355
3636
  } else {
3356
3637
  this.expect("IDENTIFIER" /* IDENTIFIER */, 'Variable attendue dans "lire"');
3357
3638
  throw new Error('Variable attendue dans "lire"');
@@ -3360,9 +3641,7 @@ class Parser {
3360
3641
  this.expect("RIGHT_PAREN" /* RIGHT_PAREN */, 'Parenthèse fermante attendue dans "lire"');
3361
3642
  return {
3362
3643
  type: "READ_STATEMENT" /* READ_STATEMENT */,
3363
- children: [
3364
- { type: "VARIABLE" /* VARIABLE */, value: variable.value, token: variable }
3365
- ],
3644
+ children: [target],
3366
3645
  token: readToken
3367
3646
  };
3368
3647
  }
@@ -3490,7 +3769,7 @@ class Parser {
3490
3769
  }
3491
3770
  parseMultiplicativeExpression() {
3492
3771
  let left = this.parseUnaryExpression();
3493
- while (this.check(["MULTIPLY" /* MULTIPLY */, "DIVIDE" /* DIVIDE */])) {
3772
+ while (this.check(["MULTIPLY" /* MULTIPLY */, "DIVIDE" /* DIVIDE */, "MODULO" /* MODULO */])) {
3494
3773
  const operator = this.advance();
3495
3774
  const right = this.parseUnaryExpression();
3496
3775
  left = {
@@ -3539,7 +3818,7 @@ class Parser {
3539
3818
  const token2 = this.advance();
3540
3819
  return {
3541
3820
  type: "LITERAL" /* LITERAL */,
3542
- value: token2.value === "vrai",
3821
+ value: token2.value.toLowerCase() === "vrai",
3543
3822
  token: token2
3544
3823
  };
3545
3824
  }
@@ -3553,6 +3832,20 @@ class Parser {
3553
3832
  }
3554
3833
  if (this.check("IDENTIFIER" /* IDENTIFIER */)) {
3555
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
+ }
3556
3849
  if (this.isReservedKeyword(token2.value)) {
3557
3850
  this.createReservedKeywordError(token2.value, token2);
3558
3851
  }
@@ -3596,14 +3889,14 @@ class Parser {
3596
3889
  parseRepeatStatement() {
3597
3890
  const repeatToken = this.advance();
3598
3891
  const statements = [];
3599
- while (!this.check("JUSQUA" /* UNTIL */) && !this.isAtEnd()) {
3892
+ while (!this.check("JUSQU'A" /* UNTIL */) && !this.isAtEnd()) {
3600
3893
  const statement = this.parseStatement();
3601
3894
  statements.push(statement);
3602
3895
  if (this.check("SEMICOLON" /* SEMICOLON */)) {
3603
3896
  this.advance();
3604
3897
  }
3605
3898
  }
3606
- 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`);
3607
3900
  const condition = this.parseExpression();
3608
3901
  return {
3609
3902
  type: "REPEAT_STATEMENT" /* REPEAT_STATEMENT */,
@@ -3611,6 +3904,127 @@ class Parser {
3611
3904
  token: repeatToken
3612
3905
  };
3613
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
+ }
3614
4028
  check(type) {
3615
4029
  if (this.isAtEnd())
3616
4030
  return false;
@@ -3760,6 +4174,8 @@ class CodeGenerator {
3760
4174
  return this.generateBlock(node);
3761
4175
  case "VAR_DECLARATION":
3762
4176
  return this.generateVariableDeclaration(node);
4177
+ case "ARRAY_DECLARATION":
4178
+ return this.generateArrayDeclaration(node);
3763
4179
  case "COMPOUND_STATEMENT":
3764
4180
  return this.generateCompoundStatement(node);
3765
4181
  case "ASSIGNMENT":
@@ -3776,6 +4192,12 @@ class CodeGenerator {
3776
4192
  return this.generateReadStatement(node);
3777
4193
  case "WRITE_STATEMENT":
3778
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);
3779
4201
  case "BINARY_OP":
3780
4202
  return this.generateBinaryOp(node);
3781
4203
  case "UNARY_OP":
@@ -3784,6 +4206,10 @@ class CodeGenerator {
3784
4206
  return this.generateLiteral(node);
3785
4207
  case "VARIABLE":
3786
4208
  return this.generateVariable(node);
4209
+ case "ARRAY_ACCESS":
4210
+ return this.generateArrayAccess(node);
4211
+ case "FUNCTION_CALL":
4212
+ return this.generateFunctionCall(node);
3787
4213
  default:
3788
4214
  this.errors.push({
3789
4215
  type: "ERROR",
@@ -3798,14 +4224,25 @@ class CodeGenerator {
3798
4224
  }
3799
4225
  generateProgram(node) {
3800
4226
  const lines = [];
4227
+ const block = node.children?.[0];
3801
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
+ }
3802
4237
  lines.push("async function main() {");
3803
4238
  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));
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
+ }
3809
4246
  }
3810
4247
  }
3811
4248
  }
@@ -3843,7 +4280,8 @@ class CodeGenerator {
3843
4280
  for (const child of node.children) {
3844
4281
  const childCode = this.generateNode(child);
3845
4282
  if (childCode) {
3846
- lines.push(this.indent(childCode));
4283
+ const stmt = child.type === "FUNCTION_CALL" ? childCode.replace(/^\(|\)$/g, "") + ";" : childCode;
4284
+ lines.push(this.indent(stmt));
3847
4285
  }
3848
4286
  }
3849
4287
  }
@@ -3854,15 +4292,107 @@ class CodeGenerator {
3854
4292
  if (!node.children || node.children.length < 2) {
3855
4293
  return "";
3856
4294
  }
3857
- const variable = node.children[0];
4295
+ const target = node.children[0];
3858
4296
  const expression = node.children[1];
3859
- if (!variable || !expression) {
4297
+ if (!target || !expression) {
3860
4298
  return "";
3861
4299
  }
3862
- const variableName = variable.value;
3863
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;
3864
4307
  return `${variableName} = ${expressionCode};`;
3865
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
+ }
3866
4396
  generateIfStatement(node) {
3867
4397
  if (!node.children || node.children.length < 2) {
3868
4398
  return "";
@@ -3964,34 +4494,20 @@ class CodeGenerator {
3964
4494
  return code;
3965
4495
  }
3966
4496
  generateReadStatement(node) {
3967
- if (!node.children || node.children.length === 0) {
4497
+ if (!node.children || node.children.length === 0)
3968
4498
  return "";
3969
- }
3970
- const variable = node.children[0];
3971
- if (!variable) {
4499
+ const target = node.children[0];
4500
+ if (!target)
3972
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(""));`;
3973
4509
  }
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
- }
4510
+ return `${varName} = await lire("");`;
3995
4511
  }
3996
4512
  generateWriteStatement(node) {
3997
4513
  if (!node.children || node.children.length === 0) {
@@ -4090,6 +4606,8 @@ class CodeGenerator {
4090
4606
  return ">";
4091
4607
  case ">=":
4092
4608
  return ">=";
4609
+ case "%":
4610
+ return "%";
4093
4611
  case "et":
4094
4612
  return "&&";
4095
4613
  case "ou":