@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/index.js CHANGED
@@ -1,6 +1,269 @@
1
1
  #!/usr/bin/env bun
2
2
  // @bun
3
3
 
4
+ // src/keywords.ts
5
+ var KEYWORDS = {
6
+ PROGRAMME: {
7
+ tokenType: "PROGRAMME" /* PROGRAM */,
8
+ kind: "control",
9
+ detail: "Mot-clé PROGRAMME",
10
+ documentation: "**PROGRAMME** : Début d'un programme AlgoLang."
11
+ },
12
+ DEBUT: {
13
+ tokenType: "DEBUT" /* BEGIN */,
14
+ kind: "control",
15
+ detail: "Mot-clé DEBUT",
16
+ documentation: "**DEBUT** : Début du bloc d'instructions principal."
17
+ },
18
+ FIN: {
19
+ tokenType: "FIN" /* END */,
20
+ kind: "control",
21
+ detail: "Mot-clé FIN",
22
+ documentation: "**FIN** : Fin du bloc d'instructions ou du programme."
23
+ },
24
+ VAR: {
25
+ tokenType: "VAR" /* VAR */,
26
+ kind: "declaration",
27
+ detail: "Mot-clé VAR",
28
+ documentation: "**VAR** : Section de déclaration des variables."
29
+ },
30
+ ENTIER: {
31
+ tokenType: "ENTIER" /* INTEGER */,
32
+ kind: "type",
33
+ detail: "Type ENTIER",
34
+ documentation: "**ENTIER** : Type de donnée pour les nombres entiers."
35
+ },
36
+ REEL: {
37
+ tokenType: "REEL" /* REAL */,
38
+ kind: "type",
39
+ detail: "Type REEL",
40
+ documentation: "**REEL** : Type de donnée pour les nombres à virgule."
41
+ },
42
+ BOOLEEN: {
43
+ tokenType: "BOOLEEN" /* BOOLEAN */,
44
+ kind: "type",
45
+ detail: "Type BOOLEEN",
46
+ documentation: "**BOOLEEN** : Type de donnée logique (VRAI/FAUX)."
47
+ },
48
+ CHAINE: {
49
+ tokenType: "CHAINE" /* STRING */,
50
+ kind: "type",
51
+ detail: "Type CHAINE",
52
+ documentation: "**CHAINE** : Type de donnée pour le texte."
53
+ },
54
+ SI: {
55
+ tokenType: "SI" /* IF */,
56
+ kind: "control",
57
+ detail: "Mot-clé SI",
58
+ documentation: "**SI** : Structure conditionnelle."
59
+ },
60
+ ALORS: {
61
+ tokenType: "ALORS" /* THEN */,
62
+ kind: "control",
63
+ detail: "Mot-clé ALORS",
64
+ documentation: "**ALORS** : Début du bloc exécuté si la condition est vraie."
65
+ },
66
+ SINON: {
67
+ tokenType: "SINON" /* ELSE */,
68
+ kind: "control",
69
+ detail: "Mot-clé SINON",
70
+ documentation: "**SINON** : Début du bloc exécuté si la condition est fausse."
71
+ },
72
+ FINSI: {
73
+ tokenType: "FINIF" /* ENDIF */,
74
+ kind: "control",
75
+ detail: "Mot-clé FINSI",
76
+ documentation: "**FINSI** : Fin d'une structure conditionnelle."
77
+ },
78
+ TANTQUE: {
79
+ tokenType: "TANTQUE" /* WHILE */,
80
+ kind: "control",
81
+ detail: "Mot-clé TANTQUE",
82
+ documentation: "**TANTQUE** : Boucle répétitive tant qu'une condition est vraie."
83
+ },
84
+ FAIRE: {
85
+ tokenType: "FAIRE" /* DO */,
86
+ kind: "control",
87
+ detail: "Mot-clé FAIRE",
88
+ documentation: "**FAIRE** : Début du corps d'une boucle."
89
+ },
90
+ FINTANTQUE: {
91
+ tokenType: "FINTANTQUE" /* ENDWHILE */,
92
+ kind: "control",
93
+ detail: "Mot-clé FINTANTQUE",
94
+ documentation: "**FINTANTQUE** : Fin d'une boucle TANTQUE."
95
+ },
96
+ POUR: {
97
+ tokenType: "POUR" /* FOR */,
98
+ kind: "control",
99
+ detail: "Mot-clé POUR",
100
+ documentation: "**POUR** : Boucle avec compteur."
101
+ },
102
+ ALLANT: {
103
+ tokenType: "ALLANT" /* ALLANT */,
104
+ kind: "control",
105
+ detail: "Mot-clé ALLANT",
106
+ documentation: "**ALLANT** : Utilisé dans une boucle POUR pour spécifier la plage."
107
+ },
108
+ DE: {
109
+ tokenType: "DE" /* DE */,
110
+ kind: "control",
111
+ detail: "Mot-clé DE",
112
+ documentation: "**DE** : Spécifie le début d'une plage dans une boucle POUR."
113
+ },
114
+ A: {
115
+ tokenType: "A" /* TO */,
116
+ kind: "control",
117
+ detail: "Mot-clé A",
118
+ documentation: "**A** : Spécifie la fin d'une plage dans une boucle POUR."
119
+ },
120
+ FINPOUR: {
121
+ tokenType: "FINPOUR" /* ENDFOR */,
122
+ kind: "control",
123
+ detail: "Mot-clé FINPOUR",
124
+ documentation: "**FINPOUR** : Fin d'une boucle POUR."
125
+ },
126
+ REPETER: {
127
+ tokenType: "REPETER" /* REPEAT */,
128
+ kind: "control",
129
+ detail: "Mot-clé REPETER",
130
+ documentation: "**REPETER** : Boucle exécutée au moins une fois."
131
+ },
132
+ "JUSQU'A": {
133
+ tokenType: "JUSQU'A" /* UNTIL */,
134
+ kind: "control",
135
+ detail: "Mot-clé JUSQU'A",
136
+ documentation: "**JUSQU'A** : Condition de fin d'une boucle REPETER."
137
+ },
138
+ LIRE: {
139
+ tokenType: "LIRE" /* READ */,
140
+ kind: "io",
141
+ detail: "Fonction LIRE",
142
+ documentation: "**LIRE(variable)** : Lit une valeur depuis l'entrée standard."
143
+ },
144
+ ECRIRE: {
145
+ tokenType: "ECRIRE" /* WRITE */,
146
+ kind: "io",
147
+ detail: "Fonction ECRIRE",
148
+ documentation: "**ECRIRE(...)** : Affiche des valeurs dans la console."
149
+ },
150
+ VRAI: {
151
+ tokenType: "VRAI" /* TRUE */,
152
+ kind: "literal",
153
+ detail: "Constante VRAI",
154
+ documentation: "**VRAI** : Valeur booléenne vraie."
155
+ },
156
+ FAUX: {
157
+ tokenType: "FAUX" /* FALSE */,
158
+ kind: "literal",
159
+ detail: "Constante FAUX",
160
+ documentation: "**FAUX** : Valeur booléenne fausse."
161
+ },
162
+ ET: {
163
+ tokenType: "ET" /* AND */,
164
+ kind: "operator",
165
+ detail: "Opérateur ET",
166
+ documentation: "**ET** : Opérateur logique ET (AND)."
167
+ },
168
+ OU: {
169
+ tokenType: "OU" /* OR */,
170
+ kind: "operator",
171
+ detail: "Opérateur OU",
172
+ documentation: "**OU** : Opérateur logique OU (OR)."
173
+ },
174
+ NON: {
175
+ tokenType: "NON" /* NOT */,
176
+ kind: "operator",
177
+ detail: "Opérateur NON",
178
+ documentation: "**NON** : Opérateur logique NON (NOT)."
179
+ },
180
+ TABLEAU: {
181
+ tokenType: "TABLEAU" /* ARRAY */,
182
+ kind: "declaration",
183
+ detail: "Type TABLEAU",
184
+ documentation: "**TABLEAU** : Déclare un tableau de n éléments.\nSyntaxe : `t: TABLEAU[10] DE ENTIER`"
185
+ },
186
+ FONCTION: {
187
+ tokenType: "FONCTION" /* FUNCTION */,
188
+ kind: "declaration",
189
+ detail: "Mot-clé FONCTION",
190
+ documentation: "**FONCTION** nom(params): TYPE : Déclare une fonction qui retourne une valeur.\nExemple : `FONCTION carre(n: ENTIER): ENTIER`"
191
+ },
192
+ PROCEDURE: {
193
+ tokenType: "PROCEDURE" /* PROCEDURE */,
194
+ kind: "declaration",
195
+ detail: "Mot-clé PROCEDURE",
196
+ documentation: "**PROCEDURE** nom(params) : Déclare une procédure (sans valeur de retour).\nExemple : `PROCEDURE afficher(s: CHAINE)`"
197
+ },
198
+ RETOURNER: {
199
+ tokenType: "RETOURNER" /* RETURN */,
200
+ kind: "declaration",
201
+ detail: "Mot-clé RETOURNER",
202
+ documentation: "**RETOURNER** expr : Retourne une valeur depuis une fonction."
203
+ },
204
+ abs: {
205
+ tokenType: null,
206
+ kind: "builtin-function",
207
+ detail: "Fonction abs(x)",
208
+ documentation: "**abs(x)** : Retourne la valeur absolue de x."
209
+ },
210
+ max: {
211
+ tokenType: null,
212
+ kind: "builtin-function",
213
+ detail: "Fonction max(a, b)",
214
+ documentation: "**max(a, b)** : Retourne le plus grand des deux nombres."
215
+ },
216
+ min: {
217
+ tokenType: null,
218
+ kind: "builtin-function",
219
+ detail: "Fonction min(a, b)",
220
+ documentation: "**min(a, b)** : Retourne le plus petit des deux nombres."
221
+ },
222
+ mod: {
223
+ tokenType: null,
224
+ kind: "builtin-function",
225
+ detail: "Fonction mod(a, b)",
226
+ documentation: "**mod(a, b)** : Retourne le reste de la division de a par b. Équivalent à `a % b`."
227
+ },
228
+ racine_carree: {
229
+ tokenType: null,
230
+ kind: "builtin-function",
231
+ detail: "Fonction racine_carree(x)",
232
+ documentation: "**racine_carree(x)** : Retourne la racine carrée de x."
233
+ },
234
+ taille: {
235
+ tokenType: null,
236
+ kind: "builtin-function",
237
+ detail: "Fonction taille(x)",
238
+ documentation: "**taille(x)** : Retourne la taille d'un tableau ou la longueur d'une chaîne."
239
+ },
240
+ sous_chaine: {
241
+ tokenType: null,
242
+ kind: "builtin-function",
243
+ detail: "Fonction sous_chaine(s, i, n)",
244
+ documentation: "**sous_chaine(s, i, n)** : Retourne n caractères de la chaîne s à partir de l'indice i."
245
+ },
246
+ concat: {
247
+ tokenType: null,
248
+ kind: "builtin-function",
249
+ detail: "Fonction concat(a, b)",
250
+ documentation: "**concat(a, b)** : Concatène deux chaînes de caractères."
251
+ },
252
+ entier_en_reel: {
253
+ tokenType: null,
254
+ kind: "builtin-function",
255
+ detail: "Fonction entier_en_reel(x)",
256
+ documentation: "**entier_en_reel(x)** : Convertit un entier en réel."
257
+ },
258
+ reel_en_entier: {
259
+ tokenType: null,
260
+ kind: "builtin-function",
261
+ detail: "Fonction reel_en_entier(x)",
262
+ documentation: "**reel_en_entier(x)** : Convertit un réel en entier (troncature)."
263
+ }
264
+ };
265
+ var BUILTIN_NAMES = new Set(Object.entries(KEYWORDS).filter(([, e]) => e.tokenType === null).map(([label]) => label));
266
+
4
267
  // src/lexer/lexer.ts
5
268
  class Lexer {
6
269
  source;
@@ -10,37 +273,7 @@ class Lexer {
10
273
  keywords;
11
274
  constructor(source) {
12
275
  this.source = source;
13
- this.keywords = new Map([
14
- ["PROGRAMME", "PROGRAMME" /* PROGRAM */],
15
- ["DEBUT", "DEBUT" /* BEGIN */],
16
- ["FIN", "FIN" /* END */],
17
- ["VAR", "VAR" /* VAR */],
18
- ["ENTIER", "ENTIER" /* INTEGER */],
19
- ["REEL", "REEL" /* REAL */],
20
- ["BOOLEEN", "BOOLEEN" /* BOOLEAN */],
21
- ["CHAINE", "CHAINE" /* STRING */],
22
- ["SI", "SI" /* IF */],
23
- ["ALORS", "ALORS" /* THEN */],
24
- ["SINON", "SINON" /* ELSE */],
25
- ["FINSI", "FINIF" /* ENDIF */],
26
- ["TANTQUE", "TANTQUE" /* WHILE */],
27
- ["FAIRE", "FAIRE" /* DO */],
28
- ["POUR", "POUR" /* FOR */],
29
- ["ALLANT", "ALLANT" /* ALLANT */],
30
- ["DE", "DE" /* DE */],
31
- ["A", "A" /* TO */],
32
- ["REPETER", "REPETER" /* REPEAT */],
33
- ["JUSQUA", "JUSQUA" /* UNTIL */],
34
- ["LIRE", "LIRE" /* READ */],
35
- ["ECRIRE", "ECRIRE" /* WRITE */],
36
- ["VRAI", "VRAI" /* TRUE */],
37
- ["FAUX", "FAUX" /* FALSE */],
38
- ["ET", "ET" /* AND */],
39
- ["OU", "OU" /* OR */],
40
- ["NON", "NON" /* NOT */],
41
- ["FINPOUR", "FINPOUR" /* ENDFOR */],
42
- ["FINTANTQUE", "FINTANTQUE" /* ENDWHILE */]
43
- ]);
276
+ this.keywords = new Map(Object.entries(KEYWORDS).filter(([, e]) => e.tokenType !== null).map(([label, e]) => [label, e.tokenType]));
44
277
  }
45
278
  tokenize() {
46
279
  const tokens = [];
@@ -113,6 +346,8 @@ class Lexer {
113
346
  return this.createToken("MULTIPLY" /* MULTIPLY */, this.advance());
114
347
  case "/":
115
348
  return this.createToken("DIVIDE" /* DIVIDE */, this.advance());
349
+ case "%":
350
+ return this.createToken("MODULO" /* MODULO */, this.advance());
116
351
  case "=":
117
352
  return this.createToken("EQUAL" /* EQUAL */, this.advance());
118
353
  case "<":
@@ -131,6 +366,10 @@ class Lexer {
131
366
  return this.createToken("LEFT_PAREN" /* LEFT_PAREN */, this.advance());
132
367
  case ")":
133
368
  return this.createToken("RIGHT_PAREN" /* RIGHT_PAREN */, this.advance());
369
+ case "[":
370
+ return this.createToken("LEFT_BRACKET" /* LEFT_BRACKET */, this.advance());
371
+ case "]":
372
+ return this.createToken("RIGHT_BRACKET" /* RIGHT_BRACKET */, this.advance());
134
373
  default:
135
374
  throw new Error(`Caractère non reconnu '${char}' à la ligne ${this.line}, colonne ${this.column}`);
136
375
  }
@@ -322,87 +561,117 @@ class Lexer {
322
561
  ` || char === "\r";
323
562
  }
324
563
  }
564
+ // src/semantic/semantic-analyzer.ts
565
+ class SemanticAnalyzer {
566
+ symbolTable = {
567
+ symbols: new Map,
568
+ children: [],
569
+ scopeName: "global"
570
+ };
571
+ errors = [];
572
+ analyze(ast) {
573
+ this.walk(ast);
574
+ return { symbolTable: this.symbolTable, errors: this.errors };
575
+ }
576
+ walk(node) {
577
+ switch (node.type) {
578
+ case "VAR_DECLARATION" /* VAR_DECLARATION */:
579
+ this.collectVarDeclaration(node);
580
+ break;
581
+ case "ARRAY_DECLARATION" /* ARRAY_DECLARATION */:
582
+ this.collectArrayDeclaration(node);
583
+ break;
584
+ default:
585
+ node.children?.forEach((child) => this.walk(child));
586
+ break;
587
+ }
588
+ }
589
+ collectVarDeclaration(node) {
590
+ const algoType = node.value;
591
+ const line = node.token?.line ?? 0;
592
+ const column = node.token?.column ?? 0;
593
+ const position = node.token?.position ?? 0;
594
+ for (const child of node.children ?? []) {
595
+ if (child.type !== "VARIABLE" /* VARIABLE */)
596
+ continue;
597
+ const name = child.value;
598
+ if (this.validateName(name, line, column, position)) {
599
+ this.defineSymbol(name, algoType, line, column);
600
+ }
601
+ }
602
+ }
603
+ collectArrayDeclaration(node) {
604
+ const elemType = node.value;
605
+ const sizeNode = node.children?.[0];
606
+ const size = sizeNode?.value;
607
+ const typeLabel = `TABLEAU[${size}] DE ${elemType}`;
608
+ const line = node.token?.line ?? 0;
609
+ const column = node.token?.column ?? 0;
610
+ const position = node.token?.position ?? 0;
611
+ for (const child of (node.children ?? []).slice(1)) {
612
+ if (child.type !== "VARIABLE" /* VARIABLE */)
613
+ continue;
614
+ const name = child.value;
615
+ if (this.validateName(name, line, column, position)) {
616
+ this.defineSymbol(name, typeLabel, line, column);
617
+ }
618
+ }
619
+ }
620
+ validateName(name, line, column, position) {
621
+ if (BUILTIN_NAMES.has(name)) {
622
+ this.errors.push({
623
+ type: "ERROR",
624
+ message: `Le nom '${name}' est une fonction intégrée et ne peut pas être utilisé comme nom de variable`,
625
+ line,
626
+ column,
627
+ position,
628
+ code: "BUILTIN_SHADOWING",
629
+ explanation: `'${name}' est une fonction intégrée d'AlgoLang`,
630
+ suggestion: `Choisissez un autre nom, par exemple '${name}Valeur' ou 'mon${name.charAt(0).toUpperCase()}${name.slice(1)}'`
631
+ });
632
+ return false;
633
+ }
634
+ if (this.symbolTable.symbols.has(name)) {
635
+ this.errors.push({
636
+ type: "ERROR",
637
+ message: `La variable '${name}' est déjà déclarée`,
638
+ line,
639
+ column,
640
+ position,
641
+ code: "DUPLICATE_VARIABLE",
642
+ explanation: "Chaque variable doit avoir un nom unique dans son scope",
643
+ suggestion: `Choisissez un autre nom pour la variable '${name}'`
644
+ });
645
+ return false;
646
+ }
647
+ return true;
648
+ }
649
+ defineSymbol(name, type, line, column) {
650
+ const info = {
651
+ name,
652
+ type,
653
+ scope: this.symbolTable.scopeName,
654
+ line,
655
+ column
656
+ };
657
+ this.symbolTable.symbols.set(name, info);
658
+ }
659
+ }
660
+
325
661
  // src/parser/parser.ts
326
662
  class Parser {
327
663
  tokens;
328
664
  current = 0;
329
665
  errors = [];
330
- symbolTable;
331
- reservedKeywords = new Set([
332
- "programme",
333
- "debut",
334
- "fin",
335
- "var",
336
- "entier",
337
- "reel",
338
- "booleen",
339
- "chaine",
340
- "si",
341
- "alors",
342
- "sinon",
343
- "finsi",
344
- "tantque",
345
- "faire",
346
- "fintantque",
347
- "pour",
348
- "a",
349
- "finpour",
350
- "repeter",
351
- "jusqua",
352
- "lire",
353
- "ecrire",
354
- "vrai",
355
- "faux",
356
- "et",
357
- "ou",
358
- "non",
359
- "fonction",
360
- "procedure",
361
- "retourner"
362
- ]);
666
+ reservedKeywords = new Set(Object.entries(KEYWORDS).filter(([, e]) => e.tokenType !== null).map(([label]) => label.toLowerCase()));
363
667
  constructor(tokens) {
364
668
  this.tokens = tokens;
365
- this.symbolTable = {
366
- symbols: new Map,
367
- children: [],
368
- scopeName: "global"
369
- };
370
669
  }
371
670
  isReservedKeyword(identifier) {
372
671
  return this.reservedKeywords.has(identifier.toLowerCase());
373
672
  }
374
673
  isKeywordToken(tokenType) {
375
- return [
376
- "PROGRAMME" /* PROGRAM */,
377
- "DEBUT" /* BEGIN */,
378
- "FIN" /* END */,
379
- "VAR" /* VAR */,
380
- "ENTIER" /* INTEGER */,
381
- "REEL" /* REAL */,
382
- "BOOLEEN" /* BOOLEAN */,
383
- "CHAINE" /* STRING */,
384
- "SI" /* IF */,
385
- "ALORS" /* THEN */,
386
- "SINON" /* ELSE */,
387
- "TANTQUE" /* WHILE */,
388
- "FAIRE" /* DO */,
389
- "POUR" /* FOR */,
390
- "ALLANT" /* ALLANT */,
391
- "DE" /* DE */,
392
- "A" /* TO */,
393
- "REPETER" /* REPEAT */,
394
- "JUSQUA" /* UNTIL */,
395
- "LIRE" /* READ */,
396
- "ECRIRE" /* WRITE */,
397
- "VRAI" /* TRUE */,
398
- "FAUX" /* FALSE */,
399
- "ET" /* AND */,
400
- "OU" /* OR */,
401
- "NON" /* NOT */,
402
- "FINPOUR" /* ENDFOR */,
403
- "FINIF" /* ENDIF */,
404
- "FINTANTQUE" /* ENDWHILE */
405
- ].includes(tokenType);
674
+ return Object.values(KEYWORDS).some((e) => e.tokenType === tokenType);
406
675
  }
407
676
  createReservedKeywordError(identifier, token) {
408
677
  this.errors.push({
@@ -417,30 +686,22 @@ class Parser {
417
686
  });
418
687
  }
419
688
  parse() {
689
+ let ast;
420
690
  try {
421
- const program = this.parseProgram();
422
- return {
423
- ast: program,
424
- errors: this.errors,
425
- symbolTable: this.symbolTable
426
- };
691
+ ast = this.parseProgram();
427
692
  } catch (error) {
428
- return {
429
- ast: { type: "PROGRAM" /* PROGRAM */, children: [] },
430
- errors: [
431
- ...this.errors,
432
- {
433
- type: "ERROR",
434
- message: error instanceof Error ? error.message : "Erreur de parsing inconnue",
435
- line: 1,
436
- column: 1,
437
- position: 0,
438
- code: "PARSE_ERROR"
439
- }
440
- ],
441
- symbolTable: this.symbolTable
442
- };
443
- }
693
+ ast = { type: "PROGRAM" /* PROGRAM */, children: [] };
694
+ this.errors.push({
695
+ type: "ERROR",
696
+ message: error instanceof Error ? error.message : "Erreur de parsing inconnue",
697
+ line: 1,
698
+ column: 1,
699
+ position: 0,
700
+ code: "PARSE_ERROR"
701
+ });
702
+ }
703
+ const { symbolTable, errors: semanticErrors } = new SemanticAnalyzer().analyze(ast);
704
+ return { ast, errors: [...this.errors, ...semanticErrors], symbolTable };
444
705
  }
445
706
  parseProgram() {
446
707
  const programToken = this.expect("PROGRAMME" /* PROGRAM */, 'Le programme doit commencer par le mot-clé "programme"');
@@ -456,17 +717,25 @@ class Parser {
456
717
  }
457
718
  parseBlock() {
458
719
  const declarations = this.parseDeclarations();
720
+ const subprograms = [];
721
+ while (this.check(["FONCTION" /* FUNCTION */, "PROCEDURE" /* PROCEDURE */])) {
722
+ if (this.check("FONCTION" /* FUNCTION */)) {
723
+ subprograms.push(this.parseFunctionDeclaration());
724
+ } else {
725
+ subprograms.push(this.parseProcedureDeclaration());
726
+ }
727
+ }
459
728
  const compoundStatement = this.parseCompoundStatement();
460
729
  return {
461
730
  type: "BLOCK" /* BLOCK */,
462
- children: [declarations, compoundStatement]
731
+ children: [declarations, ...subprograms, compoundStatement]
463
732
  };
464
733
  }
465
734
  parseDeclarations() {
466
735
  const declarations = [];
467
736
  while (this.check("VAR" /* VAR */)) {
468
737
  this.advance();
469
- while (!this.check("DEBUT" /* BEGIN */) && !this.isAtEnd()) {
738
+ while (!this.check("DEBUT" /* BEGIN */) && !this.check("FONCTION" /* FUNCTION */) && !this.check("PROCEDURE" /* PROCEDURE */) && !this.isAtEnd()) {
470
739
  const declaration = this.parseVariableDeclaration();
471
740
  declarations.push(declaration);
472
741
  if (!this.check("SEMICOLON" /* SEMICOLON */)) {
@@ -507,31 +776,27 @@ class Parser {
507
776
  }
508
777
  } while (true);
509
778
  this.expect("COLON" /* COLON */, "Deux-points attendus après les identificateurs");
779
+ if (this.check("TABLEAU" /* ARRAY */)) {
780
+ this.advance();
781
+ this.expect("LEFT_BRACKET" /* LEFT_BRACKET */, '"[" attendu après TABLEAU');
782
+ const sizeToken = this.expect("NUMBER" /* NUMBER */, "Taille du tableau attendue");
783
+ this.expect("RIGHT_BRACKET" /* RIGHT_BRACKET */, '"]" attendu après la taille du tableau');
784
+ this.expect("DE" /* DE */, '"DE" attendu après la taille du tableau');
785
+ const elemTypeToken = this.expect(["ENTIER" /* INTEGER */, "REEL" /* REAL */, "BOOLEEN" /* BOOLEAN */, "CHAINE" /* STRING */], "Type des éléments du tableau attendu");
786
+ const elemType = this.tokenTypeToDataType(elemTypeToken.type);
787
+ const size = parseInt(sizeToken.value);
788
+ return {
789
+ type: "ARRAY_DECLARATION" /* ARRAY_DECLARATION */,
790
+ value: elemType,
791
+ children: [
792
+ { type: "LITERAL" /* LITERAL */, value: size },
793
+ ...identifiers.map((name) => ({ type: "VARIABLE" /* VARIABLE */, value: name }))
794
+ ],
795
+ token: elemTypeToken
796
+ };
797
+ }
510
798
  const typeToken = this.expect(["ENTIER" /* INTEGER */, "REEL" /* REAL */, "BOOLEEN" /* BOOLEAN */, "CHAINE" /* STRING */], "Type de variable attendu");
511
799
  const type = this.tokenTypeToDataType(typeToken.type);
512
- for (const identifier of identifiers) {
513
- if (this.symbolTable.symbols.has(identifier)) {
514
- this.errors.push({
515
- type: "ERROR",
516
- message: `La variable '${identifier}' est déjà déclarée`,
517
- line: typeToken.line,
518
- column: typeToken.column,
519
- position: typeToken.position,
520
- code: "DUPLICATE_VARIABLE",
521
- explanation: "Chaque variable doit avoir un nom unique dans son scope",
522
- suggestion: `Choisissez un autre nom pour la variable '${identifier}'`
523
- });
524
- } else {
525
- const symbolInfo = {
526
- name: identifier,
527
- type,
528
- scope: this.symbolTable.scopeName,
529
- line: typeToken.line,
530
- column: typeToken.column
531
- };
532
- this.symbolTable.symbols.set(identifier, symbolInfo);
533
- }
534
- }
535
800
  return {
536
801
  type: "VAR_DECLARATION" /* VAR_DECLARATION */,
537
802
  value: type,
@@ -548,9 +813,16 @@ class Parser {
548
813
  while (!this.check("FIN" /* END */) && !this.isAtEnd()) {
549
814
  const statement = this.parseStatement();
550
815
  statements.push(statement);
816
+ const isBlockStatement = [
817
+ "IF_STATEMENT" /* IF_STATEMENT */,
818
+ "WHILE_STATEMENT" /* WHILE_STATEMENT */,
819
+ "FOR_STATEMENT" /* FOR_STATEMENT */,
820
+ "REPEAT_STATEMENT" /* REPEAT_STATEMENT */,
821
+ "COMPOUND_STATEMENT" /* COMPOUND_STATEMENT */
822
+ ].includes(statement.type);
551
823
  if (this.check("SEMICOLON" /* SEMICOLON */)) {
552
824
  this.advance();
553
- } else if (!this.check("FIN" /* END */) && !this.check("FINIF" /* ENDIF */) && !this.check("FINTANTQUE" /* ENDWHILE */)) {
825
+ } else if (!isBlockStatement && !this.check("FIN" /* END */) && !this.check("FINIF" /* ENDIF */) && !this.check("FINTANTQUE" /* ENDWHILE */) && !this.check("FINPOUR" /* ENDFOR */)) {
554
826
  this.errors.push({
555
827
  type: "ERROR",
556
828
  message: "Point-virgule attendu après l'instruction",
@@ -593,6 +865,16 @@ class Parser {
593
865
  if (this.check("ECRIRE" /* WRITE */)) {
594
866
  return this.parseWriteStatement();
595
867
  }
868
+ if (this.check("RETOURNER" /* RETURN */)) {
869
+ return this.parseReturnStatement();
870
+ }
871
+ if (this.check("IDENTIFIER" /* IDENTIFIER */) && this.peekAhead(1)?.type === "LEFT_PAREN" /* LEFT_PAREN */) {
872
+ const nameToken = this.advance();
873
+ return this.parseFunctionCall(nameToken);
874
+ }
875
+ if (this.check("IDENTIFIER" /* IDENTIFIER */) && this.peekAhead(1)?.type === "LEFT_BRACKET" /* LEFT_BRACKET */) {
876
+ return this.parseArrayAssignment();
877
+ }
596
878
  return this.parseAssignment();
597
879
  }
598
880
  parseIfStatement(isElseIf = false) {
@@ -712,14 +994,23 @@ class Parser {
712
994
  parseReadStatement() {
713
995
  const readToken = this.advance();
714
996
  this.expect("LEFT_PAREN" /* LEFT_PAREN */, 'Parenthèse ouvrante attendue après "lire"');
715
- let variable;
997
+ let target;
716
998
  if (this.check("IDENTIFIER" /* IDENTIFIER */)) {
717
- variable = this.advance();
999
+ const variable = this.advance();
1000
+ if (this.check("LEFT_BRACKET" /* LEFT_BRACKET */)) {
1001
+ this.advance();
1002
+ const index = this.parseExpression();
1003
+ this.expect("RIGHT_BRACKET" /* RIGHT_BRACKET */, `"]" attendu après l'index`);
1004
+ target = { type: "ARRAY_ACCESS" /* ARRAY_ACCESS */, value: variable.value, children: [index], token: variable };
1005
+ } else {
1006
+ target = { type: "VARIABLE" /* VARIABLE */, value: variable.value, token: variable };
1007
+ }
718
1008
  } else {
719
1009
  const currentToken = this.peek();
720
1010
  if (this.isKeywordToken(currentToken.type)) {
721
- variable = this.advance();
1011
+ const variable = this.advance();
722
1012
  this.createReservedKeywordError(variable.value, variable);
1013
+ target = { type: "VARIABLE" /* VARIABLE */, value: variable.value, token: variable };
723
1014
  } else {
724
1015
  this.expect("IDENTIFIER" /* IDENTIFIER */, 'Variable attendue dans "lire"');
725
1016
  throw new Error('Variable attendue dans "lire"');
@@ -728,9 +1019,7 @@ class Parser {
728
1019
  this.expect("RIGHT_PAREN" /* RIGHT_PAREN */, 'Parenthèse fermante attendue dans "lire"');
729
1020
  return {
730
1021
  type: "READ_STATEMENT" /* READ_STATEMENT */,
731
- children: [
732
- { type: "VARIABLE" /* VARIABLE */, value: variable.value, token: variable }
733
- ],
1022
+ children: [target],
734
1023
  token: readToken
735
1024
  };
736
1025
  }
@@ -858,7 +1147,7 @@ class Parser {
858
1147
  }
859
1148
  parseMultiplicativeExpression() {
860
1149
  let left = this.parseUnaryExpression();
861
- while (this.check(["MULTIPLY" /* MULTIPLY */, "DIVIDE" /* DIVIDE */])) {
1150
+ while (this.check(["MULTIPLY" /* MULTIPLY */, "DIVIDE" /* DIVIDE */, "MODULO" /* MODULO */])) {
862
1151
  const operator = this.advance();
863
1152
  const right = this.parseUnaryExpression();
864
1153
  left = {
@@ -907,7 +1196,7 @@ class Parser {
907
1196
  const token2 = this.advance();
908
1197
  return {
909
1198
  type: "LITERAL" /* LITERAL */,
910
- value: token2.value === "vrai",
1199
+ value: token2.value.toLowerCase() === "vrai",
911
1200
  token: token2
912
1201
  };
913
1202
  }
@@ -921,6 +1210,20 @@ class Parser {
921
1210
  }
922
1211
  if (this.check("IDENTIFIER" /* IDENTIFIER */)) {
923
1212
  const token2 = this.advance();
1213
+ if (this.check("LEFT_PAREN" /* LEFT_PAREN */)) {
1214
+ return this.parseFunctionCall(token2);
1215
+ }
1216
+ if (this.check("LEFT_BRACKET" /* LEFT_BRACKET */)) {
1217
+ this.advance();
1218
+ const index = this.parseExpression();
1219
+ this.expect("RIGHT_BRACKET" /* RIGHT_BRACKET */, `"]" attendu après l'index`);
1220
+ return {
1221
+ type: "ARRAY_ACCESS" /* ARRAY_ACCESS */,
1222
+ value: token2.value,
1223
+ children: [index],
1224
+ token: token2
1225
+ };
1226
+ }
924
1227
  if (this.isReservedKeyword(token2.value)) {
925
1228
  this.createReservedKeywordError(token2.value, token2);
926
1229
  }
@@ -964,14 +1267,14 @@ class Parser {
964
1267
  parseRepeatStatement() {
965
1268
  const repeatToken = this.advance();
966
1269
  const statements = [];
967
- while (!this.check("JUSQUA" /* UNTIL */) && !this.isAtEnd()) {
1270
+ while (!this.check("JUSQU'A" /* UNTIL */) && !this.isAtEnd()) {
968
1271
  const statement = this.parseStatement();
969
1272
  statements.push(statement);
970
1273
  if (this.check("SEMICOLON" /* SEMICOLON */)) {
971
1274
  this.advance();
972
1275
  }
973
1276
  }
974
- this.expect("JUSQUA" /* UNTIL */, '"jusqua" attendu à la fin de la boucle repeter');
1277
+ this.expect("JUSQU'A" /* UNTIL */, `"jusqu'a" attendu à la fin de la boucle repeter`);
975
1278
  const condition = this.parseExpression();
976
1279
  return {
977
1280
  type: "REPEAT_STATEMENT" /* REPEAT_STATEMENT */,
@@ -979,6 +1282,127 @@ class Parser {
979
1282
  token: repeatToken
980
1283
  };
981
1284
  }
1285
+ parseFunctionCall(nameToken) {
1286
+ this.advance();
1287
+ const args = [];
1288
+ if (!this.check("RIGHT_PAREN" /* RIGHT_PAREN */)) {
1289
+ args.push(this.parseExpression());
1290
+ while (this.check("COMMA" /* COMMA */)) {
1291
+ this.advance();
1292
+ args.push(this.parseExpression());
1293
+ }
1294
+ }
1295
+ this.expect("RIGHT_PAREN" /* RIGHT_PAREN */, '")` attendu après les arguments');
1296
+ return {
1297
+ type: "FUNCTION_CALL" /* FUNCTION_CALL */,
1298
+ value: nameToken.value,
1299
+ children: args,
1300
+ token: nameToken
1301
+ };
1302
+ }
1303
+ parseArrayAssignment() {
1304
+ const nameToken = this.advance();
1305
+ this.advance();
1306
+ const index = this.parseExpression();
1307
+ this.expect("RIGHT_BRACKET" /* RIGHT_BRACKET */, `"]" attendu après l'index`);
1308
+ this.expect("ASSIGN" /* ASSIGN */, `":=" attendu dans l'affectation`);
1309
+ const value = this.parseExpression();
1310
+ return {
1311
+ type: "ASSIGNMENT" /* ASSIGNMENT */,
1312
+ children: [
1313
+ { type: "ARRAY_ACCESS" /* ARRAY_ACCESS */, value: nameToken.value, children: [index], token: nameToken },
1314
+ value
1315
+ ],
1316
+ token: nameToken
1317
+ };
1318
+ }
1319
+ parseReturnStatement() {
1320
+ const token = this.advance();
1321
+ const expr = this.parseExpression();
1322
+ return {
1323
+ type: "RETURN_STATEMENT" /* RETURN_STATEMENT */,
1324
+ children: [expr],
1325
+ token
1326
+ };
1327
+ }
1328
+ parseParameterList() {
1329
+ this.expect("LEFT_PAREN" /* LEFT_PAREN */, '"(" attendu dans la déclaration');
1330
+ const params = [];
1331
+ if (!this.check("RIGHT_PAREN" /* RIGHT_PAREN */)) {
1332
+ params.push(this.parseParameter());
1333
+ while (this.check("SEMICOLON" /* SEMICOLON */) || this.check("COMMA" /* COMMA */)) {
1334
+ this.advance();
1335
+ if (this.check("RIGHT_PAREN" /* RIGHT_PAREN */))
1336
+ break;
1337
+ params.push(this.parseParameter());
1338
+ }
1339
+ }
1340
+ this.expect("RIGHT_PAREN" /* RIGHT_PAREN */, '")" attendu après les paramètres');
1341
+ return { type: "PARAMETER_LIST" /* PARAMETER_LIST */, children: params };
1342
+ }
1343
+ parseParameter() {
1344
+ const nameToken = this.expect("IDENTIFIER" /* IDENTIFIER */, "Nom de paramètre attendu");
1345
+ this.expect("COLON" /* COLON */, '":" attendu après le nom du paramètre');
1346
+ if (this.check("TABLEAU" /* ARRAY */)) {
1347
+ this.advance();
1348
+ let size;
1349
+ if (this.check("LEFT_BRACKET" /* LEFT_BRACKET */)) {
1350
+ this.advance();
1351
+ const sizeToken = this.expect("NUMBER" /* NUMBER */, "Taille attendue");
1352
+ this.expect("RIGHT_BRACKET" /* RIGHT_BRACKET */, '"]" attendu');
1353
+ size = parseInt(sizeToken.value);
1354
+ }
1355
+ this.expect("DE" /* DE */, '"DE" attendu après TABLEAU');
1356
+ const elemTypeToken = this.expect(["ENTIER" /* INTEGER */, "REEL" /* REAL */, "BOOLEEN" /* BOOLEAN */, "CHAINE" /* STRING */], "Type des éléments attendu");
1357
+ const elemType = this.tokenTypeToDataType(elemTypeToken.type);
1358
+ const typeLabel = size !== undefined ? `TABLEAU[${size}] DE ${elemType}` : `TABLEAU DE ${elemType}`;
1359
+ return {
1360
+ type: "PARAMETER" /* PARAMETER */,
1361
+ value: nameToken.value,
1362
+ token: nameToken,
1363
+ symbolInfo: { name: nameToken.value, type: typeLabel, scope: "param" }
1364
+ };
1365
+ }
1366
+ const typeToken = this.expect(["ENTIER" /* INTEGER */, "REEL" /* REAL */, "BOOLEEN" /* BOOLEAN */, "CHAINE" /* STRING */], "Type du paramètre attendu");
1367
+ const paramType = this.tokenTypeToDataType(typeToken.type);
1368
+ return {
1369
+ type: "PARAMETER" /* PARAMETER */,
1370
+ value: nameToken.value,
1371
+ token: nameToken,
1372
+ symbolInfo: { name: nameToken.value, type: paramType, scope: "param" }
1373
+ };
1374
+ }
1375
+ parseFunctionDeclaration() {
1376
+ const token = this.advance();
1377
+ const nameToken = this.expect("IDENTIFIER" /* IDENTIFIER */, "Nom de fonction attendu");
1378
+ const paramList = this.parseParameterList();
1379
+ this.expect("COLON" /* COLON */, '":" attendu pour le type de retour');
1380
+ const retTypeToken = this.expect(["ENTIER" /* INTEGER */, "REEL" /* REAL */, "BOOLEEN" /* BOOLEAN */, "CHAINE" /* STRING */], "Type de retour attendu");
1381
+ const retType = this.tokenTypeToDataType(retTypeToken.type);
1382
+ const body = this.parseCompoundStatement();
1383
+ return {
1384
+ type: "FUNCTION_DECLARATION" /* FUNCTION_DECLARATION */,
1385
+ value: nameToken.value,
1386
+ children: [
1387
+ paramList,
1388
+ { type: "TYPE_SPECIFIER" /* TYPE_SPECIFIER */, value: retType },
1389
+ body
1390
+ ],
1391
+ token
1392
+ };
1393
+ }
1394
+ parseProcedureDeclaration() {
1395
+ const token = this.advance();
1396
+ const nameToken = this.expect("IDENTIFIER" /* IDENTIFIER */, "Nom de procédure attendu");
1397
+ const paramList = this.parseParameterList();
1398
+ const body = this.parseCompoundStatement();
1399
+ return {
1400
+ type: "PROCEDURE_DECLARATION" /* PROCEDURE_DECLARATION */,
1401
+ value: nameToken.value,
1402
+ children: [paramList, body],
1403
+ token
1404
+ };
1405
+ }
982
1406
  check(type) {
983
1407
  if (this.isAtEnd())
984
1408
  return false;
@@ -1127,6 +1551,8 @@ class CodeGenerator {
1127
1551
  return this.generateBlock(node);
1128
1552
  case "VAR_DECLARATION":
1129
1553
  return this.generateVariableDeclaration(node);
1554
+ case "ARRAY_DECLARATION":
1555
+ return this.generateArrayDeclaration(node);
1130
1556
  case "COMPOUND_STATEMENT":
1131
1557
  return this.generateCompoundStatement(node);
1132
1558
  case "ASSIGNMENT":
@@ -1143,6 +1569,12 @@ class CodeGenerator {
1143
1569
  return this.generateReadStatement(node);
1144
1570
  case "WRITE_STATEMENT":
1145
1571
  return this.generateWriteStatement(node);
1572
+ case "FUNCTION_DECLARATION":
1573
+ return this.generateFunctionDeclaration(node);
1574
+ case "PROCEDURE_DECLARATION":
1575
+ return this.generateProcedureDeclaration(node);
1576
+ case "RETURN_STATEMENT":
1577
+ return this.generateReturnStatement(node);
1146
1578
  case "BINARY_OP":
1147
1579
  return this.generateBinaryOp(node);
1148
1580
  case "UNARY_OP":
@@ -1151,6 +1583,10 @@ class CodeGenerator {
1151
1583
  return this.generateLiteral(node);
1152
1584
  case "VARIABLE":
1153
1585
  return this.generateVariable(node);
1586
+ case "ARRAY_ACCESS":
1587
+ return this.generateArrayAccess(node);
1588
+ case "FUNCTION_CALL":
1589
+ return this.generateFunctionCall(node);
1154
1590
  default:
1155
1591
  this.errors.push({
1156
1592
  type: "ERROR",
@@ -1165,14 +1601,25 @@ class CodeGenerator {
1165
1601
  }
1166
1602
  generateProgram(node) {
1167
1603
  const lines = [];
1604
+ const block = node.children?.[0];
1168
1605
  lines.push(`// Programme: ${node.value}`);
1606
+ if (block?.children) {
1607
+ for (const child of block.children) {
1608
+ if (child.type === "FUNCTION_DECLARATION" || child.type === "PROCEDURE_DECLARATION") {
1609
+ lines.push(this.generateNode(child));
1610
+ lines.push("");
1611
+ }
1612
+ }
1613
+ }
1169
1614
  lines.push("async function main() {");
1170
1615
  this.indentLevel++;
1171
- if (node.children && node.children.length > 0) {
1172
- for (const child of node.children) {
1173
- const childCode = this.generateNode(child);
1174
- if (childCode) {
1175
- lines.push(this.indent(childCode));
1616
+ if (block?.children) {
1617
+ for (const child of block.children) {
1618
+ if (child.type !== "FUNCTION_DECLARATION" && child.type !== "PROCEDURE_DECLARATION") {
1619
+ const childCode = this.generateNode(child);
1620
+ if (childCode) {
1621
+ lines.push(this.indent(childCode));
1622
+ }
1176
1623
  }
1177
1624
  }
1178
1625
  }
@@ -1210,7 +1657,8 @@ class CodeGenerator {
1210
1657
  for (const child of node.children) {
1211
1658
  const childCode = this.generateNode(child);
1212
1659
  if (childCode) {
1213
- lines.push(this.indent(childCode));
1660
+ const stmt = child.type === "FUNCTION_CALL" ? childCode.replace(/^\(|\)$/g, "") + ";" : childCode;
1661
+ lines.push(this.indent(stmt));
1214
1662
  }
1215
1663
  }
1216
1664
  }
@@ -1221,15 +1669,107 @@ class CodeGenerator {
1221
1669
  if (!node.children || node.children.length < 2) {
1222
1670
  return "";
1223
1671
  }
1224
- const variable = node.children[0];
1672
+ const target = node.children[0];
1225
1673
  const expression = node.children[1];
1226
- if (!variable || !expression) {
1674
+ if (!target || !expression) {
1227
1675
  return "";
1228
1676
  }
1229
- const variableName = variable.value;
1230
1677
  const expressionCode = this.generateNode(expression);
1678
+ if (target.type === "ARRAY_ACCESS") {
1679
+ const arrayName = target.value;
1680
+ const index = this.generateNode(target.children[0]);
1681
+ return `${arrayName}[${index}] = ${expressionCode};`;
1682
+ }
1683
+ const variableName = target.value;
1231
1684
  return `${variableName} = ${expressionCode};`;
1232
1685
  }
1686
+ generateArrayDeclaration(node) {
1687
+ if (!node.children || node.children.length < 2)
1688
+ return "";
1689
+ const size = node.children[0].value;
1690
+ const elemType = node.value;
1691
+ const defaultValue = elemType === "BOOLEEN" ? "false" : elemType === "CHAINE" ? '""' : "0";
1692
+ const names = node.children.slice(1).map((c) => c.value);
1693
+ return names.map((name) => `let ${name} = new Array(${size}).fill(${defaultValue});`).join(`
1694
+ `);
1695
+ }
1696
+ generateArrayAccess(node) {
1697
+ const name = node.value;
1698
+ const index = this.generateNode(node.children[0]);
1699
+ return `${name}[${index}]`;
1700
+ }
1701
+ generateFunctionCall(node) {
1702
+ const name = node.value;
1703
+ const args = (node.children ?? []).map((c) => {
1704
+ const code = this.generateNode(c);
1705
+ if (c.type === "VARIABLE") {
1706
+ const sym = this.symbolTable.symbols.get(c.value);
1707
+ if (sym?.type?.startsWith("TABLEAU"))
1708
+ return `${code}.slice()`;
1709
+ }
1710
+ return code;
1711
+ });
1712
+ switch (name.toLowerCase()) {
1713
+ case "abs":
1714
+ return `Math.abs(${args[0]})`;
1715
+ case "max":
1716
+ return `Math.max(${args.join(", ")})`;
1717
+ case "min":
1718
+ return `Math.min(${args.join(", ")})`;
1719
+ case "mod":
1720
+ return `(${args[0]} % ${args[1]})`;
1721
+ case "racine_carree":
1722
+ return `Math.sqrt(${args[0]})`;
1723
+ case "taille":
1724
+ return `${args[0]}.length`;
1725
+ case "sous_chaine":
1726
+ return `${args[0]}.substring(${args[1]}, ${args[1]} + ${args[2]})`;
1727
+ case "concat":
1728
+ return args.join(" + ");
1729
+ case "entier_en_reel":
1730
+ return `${args[0]}`;
1731
+ case "reel_en_entier":
1732
+ return `Math.trunc(${args[0]})`;
1733
+ default:
1734
+ return `(await ${name}(${args.join(", ")}))`;
1735
+ }
1736
+ }
1737
+ generateFunctionDeclaration(node) {
1738
+ const name = node.value;
1739
+ const [paramList, , body] = node.children ?? [];
1740
+ const params = this.generateParamList(paramList);
1741
+ const bodyCode = this.generateNode(body);
1742
+ const lines = [`async function ${name}(${params}) {`];
1743
+ this.indentLevel++;
1744
+ lines.push(this.indent(bodyCode));
1745
+ this.indentLevel--;
1746
+ lines.push("}");
1747
+ return lines.join(`
1748
+ `);
1749
+ }
1750
+ generateProcedureDeclaration(node) {
1751
+ const name = node.value;
1752
+ const [paramList, body] = node.children ?? [];
1753
+ const params = this.generateParamList(paramList);
1754
+ const bodyCode = this.generateNode(body);
1755
+ const lines = [`async function ${name}(${params}) {`];
1756
+ this.indentLevel++;
1757
+ lines.push(this.indent(bodyCode));
1758
+ this.indentLevel--;
1759
+ lines.push("}");
1760
+ return lines.join(`
1761
+ `);
1762
+ }
1763
+ generateParamList(paramList) {
1764
+ if (!paramList?.children)
1765
+ return "";
1766
+ return paramList.children.map((p) => p.value).join(", ");
1767
+ }
1768
+ generateReturnStatement(node) {
1769
+ if (!node.children?.[0])
1770
+ return "return;";
1771
+ return `return ${this.generateNode(node.children[0])};`;
1772
+ }
1233
1773
  generateIfStatement(node) {
1234
1774
  if (!node.children || node.children.length < 2) {
1235
1775
  return "";
@@ -1331,34 +1871,20 @@ class CodeGenerator {
1331
1871
  return code;
1332
1872
  }
1333
1873
  generateReadStatement(node) {
1334
- if (!node.children || node.children.length === 0) {
1874
+ if (!node.children || node.children.length === 0)
1335
1875
  return "";
1336
- }
1337
- const variable = node.children[0];
1338
- if (!variable) {
1876
+ const target = node.children[0];
1877
+ if (!target)
1339
1878
  return "";
1879
+ const isArray = target.type === "ARRAY_ACCESS";
1880
+ const varName = isArray ? `${target.value}[${this.generateNode(target.children[0])}]` : target.value;
1881
+ const symbolName = target.value;
1882
+ const symbolInfo = this.symbolTable.symbols.get(symbolName);
1883
+ const typeHint = symbolInfo?.type ?? "";
1884
+ if (typeHint.startsWith("ENTIER") || typeHint === "REEL" || typeHint.startsWith("TABLEAU")) {
1885
+ return `${varName} = parseInt(await lire(""));`;
1340
1886
  }
1341
- const variableName = variable.value;
1342
- const symbolInfo = this.symbolTable.symbols.get(variableName);
1343
- let conversion = "";
1344
- if (symbolInfo) {
1345
- switch (symbolInfo.type) {
1346
- case "ENTIER":
1347
- case "REEL":
1348
- conversion = "parseInt(";
1349
- break;
1350
- case "BOOLEEN":
1351
- conversion = "(";
1352
- break;
1353
- default:
1354
- conversion = "";
1355
- }
1356
- }
1357
- if (conversion) {
1358
- return `${variableName} = ${conversion}await lire(""));`;
1359
- } else {
1360
- return `${variableName} = await lire("");`;
1361
- }
1887
+ return `${varName} = await lire("");`;
1362
1888
  }
1363
1889
  generateWriteStatement(node) {
1364
1890
  if (!node.children || node.children.length === 0) {
@@ -1457,6 +1983,8 @@ class CodeGenerator {
1457
1983
  return ">";
1458
1984
  case ">=":
1459
1985
  return ">=";
1986
+ case "%":
1987
+ return "%";
1460
1988
  case "et":
1461
1989
  return "&&";
1462
1990
  case "ou":
@@ -1480,37 +2008,7 @@ class Lexer2 {
1480
2008
  keywords;
1481
2009
  constructor(source) {
1482
2010
  this.source = source;
1483
- this.keywords = new Map([
1484
- ["PROGRAMME", "PROGRAMME" /* PROGRAM */],
1485
- ["DEBUT", "DEBUT" /* BEGIN */],
1486
- ["FIN", "FIN" /* END */],
1487
- ["VAR", "VAR" /* VAR */],
1488
- ["ENTIER", "ENTIER" /* INTEGER */],
1489
- ["REEL", "REEL" /* REAL */],
1490
- ["BOOLEEN", "BOOLEEN" /* BOOLEAN */],
1491
- ["CHAINE", "CHAINE" /* STRING */],
1492
- ["SI", "SI" /* IF */],
1493
- ["ALORS", "ALORS" /* THEN */],
1494
- ["SINON", "SINON" /* ELSE */],
1495
- ["FINSI", "FINIF" /* ENDIF */],
1496
- ["TANTQUE", "TANTQUE" /* WHILE */],
1497
- ["FAIRE", "FAIRE" /* DO */],
1498
- ["POUR", "POUR" /* FOR */],
1499
- ["ALLANT", "ALLANT" /* ALLANT */],
1500
- ["DE", "DE" /* DE */],
1501
- ["A", "A" /* TO */],
1502
- ["REPETER", "REPETER" /* REPEAT */],
1503
- ["JUSQUA", "JUSQUA" /* UNTIL */],
1504
- ["LIRE", "LIRE" /* READ */],
1505
- ["ECRIRE", "ECRIRE" /* WRITE */],
1506
- ["VRAI", "VRAI" /* TRUE */],
1507
- ["FAUX", "FAUX" /* FALSE */],
1508
- ["ET", "ET" /* AND */],
1509
- ["OU", "OU" /* OR */],
1510
- ["NON", "NON" /* NOT */],
1511
- ["FINPOUR", "FINPOUR" /* ENDFOR */],
1512
- ["FINTANTQUE", "FINTANTQUE" /* ENDWHILE */]
1513
- ]);
2011
+ this.keywords = new Map(Object.entries(KEYWORDS).filter(([, e]) => e.tokenType !== null).map(([label, e]) => [label, e.tokenType]));
1514
2012
  }
1515
2013
  tokenize() {
1516
2014
  const tokens = [];
@@ -1583,6 +2081,8 @@ class Lexer2 {
1583
2081
  return this.createToken("MULTIPLY" /* MULTIPLY */, this.advance());
1584
2082
  case "/":
1585
2083
  return this.createToken("DIVIDE" /* DIVIDE */, this.advance());
2084
+ case "%":
2085
+ return this.createToken("MODULO" /* MODULO */, this.advance());
1586
2086
  case "=":
1587
2087
  return this.createToken("EQUAL" /* EQUAL */, this.advance());
1588
2088
  case "<":
@@ -1601,6 +2101,10 @@ class Lexer2 {
1601
2101
  return this.createToken("LEFT_PAREN" /* LEFT_PAREN */, this.advance());
1602
2102
  case ")":
1603
2103
  return this.createToken("RIGHT_PAREN" /* RIGHT_PAREN */, this.advance());
2104
+ case "[":
2105
+ return this.createToken("LEFT_BRACKET" /* LEFT_BRACKET */, this.advance());
2106
+ case "]":
2107
+ return this.createToken("RIGHT_BRACKET" /* RIGHT_BRACKET */, this.advance());
1604
2108
  default:
1605
2109
  throw new Error(`Caractère non reconnu '${char}' à la ligne ${this.line}, colonne ${this.column}`);
1606
2110
  }
@@ -1798,82 +2302,15 @@ class Parser2 {
1798
2302
  tokens;
1799
2303
  current = 0;
1800
2304
  errors = [];
1801
- symbolTable;
1802
- reservedKeywords = new Set([
1803
- "programme",
1804
- "debut",
1805
- "fin",
1806
- "var",
1807
- "entier",
1808
- "reel",
1809
- "booleen",
1810
- "chaine",
1811
- "si",
1812
- "alors",
1813
- "sinon",
1814
- "finsi",
1815
- "tantque",
1816
- "faire",
1817
- "fintantque",
1818
- "pour",
1819
- "a",
1820
- "finpour",
1821
- "repeter",
1822
- "jusqua",
1823
- "lire",
1824
- "ecrire",
1825
- "vrai",
1826
- "faux",
1827
- "et",
1828
- "ou",
1829
- "non",
1830
- "fonction",
1831
- "procedure",
1832
- "retourner"
1833
- ]);
2305
+ reservedKeywords = new Set(Object.entries(KEYWORDS).filter(([, e]) => e.tokenType !== null).map(([label]) => label.toLowerCase()));
1834
2306
  constructor(tokens) {
1835
2307
  this.tokens = tokens;
1836
- this.symbolTable = {
1837
- symbols: new Map,
1838
- children: [],
1839
- scopeName: "global"
1840
- };
1841
2308
  }
1842
2309
  isReservedKeyword(identifier) {
1843
2310
  return this.reservedKeywords.has(identifier.toLowerCase());
1844
2311
  }
1845
2312
  isKeywordToken(tokenType) {
1846
- return [
1847
- "PROGRAMME" /* PROGRAM */,
1848
- "DEBUT" /* BEGIN */,
1849
- "FIN" /* END */,
1850
- "VAR" /* VAR */,
1851
- "ENTIER" /* INTEGER */,
1852
- "REEL" /* REAL */,
1853
- "BOOLEEN" /* BOOLEAN */,
1854
- "CHAINE" /* STRING */,
1855
- "SI" /* IF */,
1856
- "ALORS" /* THEN */,
1857
- "SINON" /* ELSE */,
1858
- "TANTQUE" /* WHILE */,
1859
- "FAIRE" /* DO */,
1860
- "POUR" /* FOR */,
1861
- "ALLANT" /* ALLANT */,
1862
- "DE" /* DE */,
1863
- "A" /* TO */,
1864
- "REPETER" /* REPEAT */,
1865
- "JUSQUA" /* UNTIL */,
1866
- "LIRE" /* READ */,
1867
- "ECRIRE" /* WRITE */,
1868
- "VRAI" /* TRUE */,
1869
- "FAUX" /* FALSE */,
1870
- "ET" /* AND */,
1871
- "OU" /* OR */,
1872
- "NON" /* NOT */,
1873
- "FINPOUR" /* ENDFOR */,
1874
- "FINIF" /* ENDIF */,
1875
- "FINTANTQUE" /* ENDWHILE */
1876
- ].includes(tokenType);
2313
+ return Object.values(KEYWORDS).some((e) => e.tokenType === tokenType);
1877
2314
  }
1878
2315
  createReservedKeywordError(identifier, token) {
1879
2316
  this.errors.push({
@@ -1888,30 +2325,22 @@ class Parser2 {
1888
2325
  });
1889
2326
  }
1890
2327
  parse() {
2328
+ let ast;
1891
2329
  try {
1892
- const program = this.parseProgram();
1893
- return {
1894
- ast: program,
1895
- errors: this.errors,
1896
- symbolTable: this.symbolTable
1897
- };
2330
+ ast = this.parseProgram();
1898
2331
  } catch (error) {
1899
- return {
1900
- ast: { type: "PROGRAM" /* PROGRAM */, children: [] },
1901
- errors: [
1902
- ...this.errors,
1903
- {
1904
- type: "ERROR",
1905
- message: error instanceof Error ? error.message : "Erreur de parsing inconnue",
1906
- line: 1,
1907
- column: 1,
1908
- position: 0,
1909
- code: "PARSE_ERROR"
1910
- }
1911
- ],
1912
- symbolTable: this.symbolTable
1913
- };
1914
- }
2332
+ ast = { type: "PROGRAM" /* PROGRAM */, children: [] };
2333
+ this.errors.push({
2334
+ type: "ERROR",
2335
+ message: error instanceof Error ? error.message : "Erreur de parsing inconnue",
2336
+ line: 1,
2337
+ column: 1,
2338
+ position: 0,
2339
+ code: "PARSE_ERROR"
2340
+ });
2341
+ }
2342
+ const { symbolTable, errors: semanticErrors } = new SemanticAnalyzer().analyze(ast);
2343
+ return { ast, errors: [...this.errors, ...semanticErrors], symbolTable };
1915
2344
  }
1916
2345
  parseProgram() {
1917
2346
  const programToken = this.expect("PROGRAMME" /* PROGRAM */, 'Le programme doit commencer par le mot-clé "programme"');
@@ -1927,17 +2356,25 @@ class Parser2 {
1927
2356
  }
1928
2357
  parseBlock() {
1929
2358
  const declarations = this.parseDeclarations();
2359
+ const subprograms = [];
2360
+ while (this.check(["FONCTION" /* FUNCTION */, "PROCEDURE" /* PROCEDURE */])) {
2361
+ if (this.check("FONCTION" /* FUNCTION */)) {
2362
+ subprograms.push(this.parseFunctionDeclaration());
2363
+ } else {
2364
+ subprograms.push(this.parseProcedureDeclaration());
2365
+ }
2366
+ }
1930
2367
  const compoundStatement = this.parseCompoundStatement();
1931
2368
  return {
1932
2369
  type: "BLOCK" /* BLOCK */,
1933
- children: [declarations, compoundStatement]
2370
+ children: [declarations, ...subprograms, compoundStatement]
1934
2371
  };
1935
2372
  }
1936
2373
  parseDeclarations() {
1937
2374
  const declarations = [];
1938
2375
  while (this.check("VAR" /* VAR */)) {
1939
2376
  this.advance();
1940
- while (!this.check("DEBUT" /* BEGIN */) && !this.isAtEnd()) {
2377
+ while (!this.check("DEBUT" /* BEGIN */) && !this.check("FONCTION" /* FUNCTION */) && !this.check("PROCEDURE" /* PROCEDURE */) && !this.isAtEnd()) {
1941
2378
  const declaration = this.parseVariableDeclaration();
1942
2379
  declarations.push(declaration);
1943
2380
  if (!this.check("SEMICOLON" /* SEMICOLON */)) {
@@ -1978,31 +2415,27 @@ class Parser2 {
1978
2415
  }
1979
2416
  } while (true);
1980
2417
  this.expect("COLON" /* COLON */, "Deux-points attendus après les identificateurs");
2418
+ if (this.check("TABLEAU" /* ARRAY */)) {
2419
+ this.advance();
2420
+ this.expect("LEFT_BRACKET" /* LEFT_BRACKET */, '"[" attendu après TABLEAU');
2421
+ const sizeToken = this.expect("NUMBER" /* NUMBER */, "Taille du tableau attendue");
2422
+ this.expect("RIGHT_BRACKET" /* RIGHT_BRACKET */, '"]" attendu après la taille du tableau');
2423
+ this.expect("DE" /* DE */, '"DE" attendu après la taille du tableau');
2424
+ const elemTypeToken = this.expect(["ENTIER" /* INTEGER */, "REEL" /* REAL */, "BOOLEEN" /* BOOLEAN */, "CHAINE" /* STRING */], "Type des éléments du tableau attendu");
2425
+ const elemType = this.tokenTypeToDataType(elemTypeToken.type);
2426
+ const size = parseInt(sizeToken.value);
2427
+ return {
2428
+ type: "ARRAY_DECLARATION" /* ARRAY_DECLARATION */,
2429
+ value: elemType,
2430
+ children: [
2431
+ { type: "LITERAL" /* LITERAL */, value: size },
2432
+ ...identifiers.map((name) => ({ type: "VARIABLE" /* VARIABLE */, value: name }))
2433
+ ],
2434
+ token: elemTypeToken
2435
+ };
2436
+ }
1981
2437
  const typeToken = this.expect(["ENTIER" /* INTEGER */, "REEL" /* REAL */, "BOOLEEN" /* BOOLEAN */, "CHAINE" /* STRING */], "Type de variable attendu");
1982
2438
  const type = this.tokenTypeToDataType(typeToken.type);
1983
- for (const identifier of identifiers) {
1984
- if (this.symbolTable.symbols.has(identifier)) {
1985
- this.errors.push({
1986
- type: "ERROR",
1987
- message: `La variable '${identifier}' est déjà déclarée`,
1988
- line: typeToken.line,
1989
- column: typeToken.column,
1990
- position: typeToken.position,
1991
- code: "DUPLICATE_VARIABLE",
1992
- explanation: "Chaque variable doit avoir un nom unique dans son scope",
1993
- suggestion: `Choisissez un autre nom pour la variable '${identifier}'`
1994
- });
1995
- } else {
1996
- const symbolInfo = {
1997
- name: identifier,
1998
- type,
1999
- scope: this.symbolTable.scopeName,
2000
- line: typeToken.line,
2001
- column: typeToken.column
2002
- };
2003
- this.symbolTable.symbols.set(identifier, symbolInfo);
2004
- }
2005
- }
2006
2439
  return {
2007
2440
  type: "VAR_DECLARATION" /* VAR_DECLARATION */,
2008
2441
  value: type,
@@ -2019,9 +2452,16 @@ class Parser2 {
2019
2452
  while (!this.check("FIN" /* END */) && !this.isAtEnd()) {
2020
2453
  const statement = this.parseStatement();
2021
2454
  statements.push(statement);
2455
+ const isBlockStatement = [
2456
+ "IF_STATEMENT" /* IF_STATEMENT */,
2457
+ "WHILE_STATEMENT" /* WHILE_STATEMENT */,
2458
+ "FOR_STATEMENT" /* FOR_STATEMENT */,
2459
+ "REPEAT_STATEMENT" /* REPEAT_STATEMENT */,
2460
+ "COMPOUND_STATEMENT" /* COMPOUND_STATEMENT */
2461
+ ].includes(statement.type);
2022
2462
  if (this.check("SEMICOLON" /* SEMICOLON */)) {
2023
2463
  this.advance();
2024
- } else if (!this.check("FIN" /* END */) && !this.check("FINIF" /* ENDIF */) && !this.check("FINTANTQUE" /* ENDWHILE */)) {
2464
+ } else if (!isBlockStatement && !this.check("FIN" /* END */) && !this.check("FINIF" /* ENDIF */) && !this.check("FINTANTQUE" /* ENDWHILE */) && !this.check("FINPOUR" /* ENDFOR */)) {
2025
2465
  this.errors.push({
2026
2466
  type: "ERROR",
2027
2467
  message: "Point-virgule attendu après l'instruction",
@@ -2064,6 +2504,16 @@ class Parser2 {
2064
2504
  if (this.check("ECRIRE" /* WRITE */)) {
2065
2505
  return this.parseWriteStatement();
2066
2506
  }
2507
+ if (this.check("RETOURNER" /* RETURN */)) {
2508
+ return this.parseReturnStatement();
2509
+ }
2510
+ if (this.check("IDENTIFIER" /* IDENTIFIER */) && this.peekAhead(1)?.type === "LEFT_PAREN" /* LEFT_PAREN */) {
2511
+ const nameToken = this.advance();
2512
+ return this.parseFunctionCall(nameToken);
2513
+ }
2514
+ if (this.check("IDENTIFIER" /* IDENTIFIER */) && this.peekAhead(1)?.type === "LEFT_BRACKET" /* LEFT_BRACKET */) {
2515
+ return this.parseArrayAssignment();
2516
+ }
2067
2517
  return this.parseAssignment();
2068
2518
  }
2069
2519
  parseIfStatement(isElseIf = false) {
@@ -2183,14 +2633,23 @@ class Parser2 {
2183
2633
  parseReadStatement() {
2184
2634
  const readToken = this.advance();
2185
2635
  this.expect("LEFT_PAREN" /* LEFT_PAREN */, 'Parenthèse ouvrante attendue après "lire"');
2186
- let variable;
2636
+ let target;
2187
2637
  if (this.check("IDENTIFIER" /* IDENTIFIER */)) {
2188
- variable = this.advance();
2638
+ const variable = this.advance();
2639
+ if (this.check("LEFT_BRACKET" /* LEFT_BRACKET */)) {
2640
+ this.advance();
2641
+ const index = this.parseExpression();
2642
+ this.expect("RIGHT_BRACKET" /* RIGHT_BRACKET */, `"]" attendu après l'index`);
2643
+ target = { type: "ARRAY_ACCESS" /* ARRAY_ACCESS */, value: variable.value, children: [index], token: variable };
2644
+ } else {
2645
+ target = { type: "VARIABLE" /* VARIABLE */, value: variable.value, token: variable };
2646
+ }
2189
2647
  } else {
2190
2648
  const currentToken = this.peek();
2191
2649
  if (this.isKeywordToken(currentToken.type)) {
2192
- variable = this.advance();
2650
+ const variable = this.advance();
2193
2651
  this.createReservedKeywordError(variable.value, variable);
2652
+ target = { type: "VARIABLE" /* VARIABLE */, value: variable.value, token: variable };
2194
2653
  } else {
2195
2654
  this.expect("IDENTIFIER" /* IDENTIFIER */, 'Variable attendue dans "lire"');
2196
2655
  throw new Error('Variable attendue dans "lire"');
@@ -2199,9 +2658,7 @@ class Parser2 {
2199
2658
  this.expect("RIGHT_PAREN" /* RIGHT_PAREN */, 'Parenthèse fermante attendue dans "lire"');
2200
2659
  return {
2201
2660
  type: "READ_STATEMENT" /* READ_STATEMENT */,
2202
- children: [
2203
- { type: "VARIABLE" /* VARIABLE */, value: variable.value, token: variable }
2204
- ],
2661
+ children: [target],
2205
2662
  token: readToken
2206
2663
  };
2207
2664
  }
@@ -2329,7 +2786,7 @@ class Parser2 {
2329
2786
  }
2330
2787
  parseMultiplicativeExpression() {
2331
2788
  let left = this.parseUnaryExpression();
2332
- while (this.check(["MULTIPLY" /* MULTIPLY */, "DIVIDE" /* DIVIDE */])) {
2789
+ while (this.check(["MULTIPLY" /* MULTIPLY */, "DIVIDE" /* DIVIDE */, "MODULO" /* MODULO */])) {
2333
2790
  const operator = this.advance();
2334
2791
  const right = this.parseUnaryExpression();
2335
2792
  left = {
@@ -2378,7 +2835,7 @@ class Parser2 {
2378
2835
  const token2 = this.advance();
2379
2836
  return {
2380
2837
  type: "LITERAL" /* LITERAL */,
2381
- value: token2.value === "vrai",
2838
+ value: token2.value.toLowerCase() === "vrai",
2382
2839
  token: token2
2383
2840
  };
2384
2841
  }
@@ -2392,6 +2849,20 @@ class Parser2 {
2392
2849
  }
2393
2850
  if (this.check("IDENTIFIER" /* IDENTIFIER */)) {
2394
2851
  const token2 = this.advance();
2852
+ if (this.check("LEFT_PAREN" /* LEFT_PAREN */)) {
2853
+ return this.parseFunctionCall(token2);
2854
+ }
2855
+ if (this.check("LEFT_BRACKET" /* LEFT_BRACKET */)) {
2856
+ this.advance();
2857
+ const index = this.parseExpression();
2858
+ this.expect("RIGHT_BRACKET" /* RIGHT_BRACKET */, `"]" attendu après l'index`);
2859
+ return {
2860
+ type: "ARRAY_ACCESS" /* ARRAY_ACCESS */,
2861
+ value: token2.value,
2862
+ children: [index],
2863
+ token: token2
2864
+ };
2865
+ }
2395
2866
  if (this.isReservedKeyword(token2.value)) {
2396
2867
  this.createReservedKeywordError(token2.value, token2);
2397
2868
  }
@@ -2435,14 +2906,14 @@ class Parser2 {
2435
2906
  parseRepeatStatement() {
2436
2907
  const repeatToken = this.advance();
2437
2908
  const statements = [];
2438
- while (!this.check("JUSQUA" /* UNTIL */) && !this.isAtEnd()) {
2909
+ while (!this.check("JUSQU'A" /* UNTIL */) && !this.isAtEnd()) {
2439
2910
  const statement = this.parseStatement();
2440
2911
  statements.push(statement);
2441
2912
  if (this.check("SEMICOLON" /* SEMICOLON */)) {
2442
2913
  this.advance();
2443
2914
  }
2444
2915
  }
2445
- this.expect("JUSQUA" /* UNTIL */, '"jusqua" attendu à la fin de la boucle repeter');
2916
+ this.expect("JUSQU'A" /* UNTIL */, `"jusqu'a" attendu à la fin de la boucle repeter`);
2446
2917
  const condition = this.parseExpression();
2447
2918
  return {
2448
2919
  type: "REPEAT_STATEMENT" /* REPEAT_STATEMENT */,
@@ -2450,6 +2921,127 @@ class Parser2 {
2450
2921
  token: repeatToken
2451
2922
  };
2452
2923
  }
2924
+ parseFunctionCall(nameToken) {
2925
+ this.advance();
2926
+ const args = [];
2927
+ if (!this.check("RIGHT_PAREN" /* RIGHT_PAREN */)) {
2928
+ args.push(this.parseExpression());
2929
+ while (this.check("COMMA" /* COMMA */)) {
2930
+ this.advance();
2931
+ args.push(this.parseExpression());
2932
+ }
2933
+ }
2934
+ this.expect("RIGHT_PAREN" /* RIGHT_PAREN */, '")` attendu après les arguments');
2935
+ return {
2936
+ type: "FUNCTION_CALL" /* FUNCTION_CALL */,
2937
+ value: nameToken.value,
2938
+ children: args,
2939
+ token: nameToken
2940
+ };
2941
+ }
2942
+ parseArrayAssignment() {
2943
+ const nameToken = this.advance();
2944
+ this.advance();
2945
+ const index = this.parseExpression();
2946
+ this.expect("RIGHT_BRACKET" /* RIGHT_BRACKET */, `"]" attendu après l'index`);
2947
+ this.expect("ASSIGN" /* ASSIGN */, `":=" attendu dans l'affectation`);
2948
+ const value = this.parseExpression();
2949
+ return {
2950
+ type: "ASSIGNMENT" /* ASSIGNMENT */,
2951
+ children: [
2952
+ { type: "ARRAY_ACCESS" /* ARRAY_ACCESS */, value: nameToken.value, children: [index], token: nameToken },
2953
+ value
2954
+ ],
2955
+ token: nameToken
2956
+ };
2957
+ }
2958
+ parseReturnStatement() {
2959
+ const token = this.advance();
2960
+ const expr = this.parseExpression();
2961
+ return {
2962
+ type: "RETURN_STATEMENT" /* RETURN_STATEMENT */,
2963
+ children: [expr],
2964
+ token
2965
+ };
2966
+ }
2967
+ parseParameterList() {
2968
+ this.expect("LEFT_PAREN" /* LEFT_PAREN */, '"(" attendu dans la déclaration');
2969
+ const params = [];
2970
+ if (!this.check("RIGHT_PAREN" /* RIGHT_PAREN */)) {
2971
+ params.push(this.parseParameter());
2972
+ while (this.check("SEMICOLON" /* SEMICOLON */) || this.check("COMMA" /* COMMA */)) {
2973
+ this.advance();
2974
+ if (this.check("RIGHT_PAREN" /* RIGHT_PAREN */))
2975
+ break;
2976
+ params.push(this.parseParameter());
2977
+ }
2978
+ }
2979
+ this.expect("RIGHT_PAREN" /* RIGHT_PAREN */, '")" attendu après les paramètres');
2980
+ return { type: "PARAMETER_LIST" /* PARAMETER_LIST */, children: params };
2981
+ }
2982
+ parseParameter() {
2983
+ const nameToken = this.expect("IDENTIFIER" /* IDENTIFIER */, "Nom de paramètre attendu");
2984
+ this.expect("COLON" /* COLON */, '":" attendu après le nom du paramètre');
2985
+ if (this.check("TABLEAU" /* ARRAY */)) {
2986
+ this.advance();
2987
+ let size;
2988
+ if (this.check("LEFT_BRACKET" /* LEFT_BRACKET */)) {
2989
+ this.advance();
2990
+ const sizeToken = this.expect("NUMBER" /* NUMBER */, "Taille attendue");
2991
+ this.expect("RIGHT_BRACKET" /* RIGHT_BRACKET */, '"]" attendu');
2992
+ size = parseInt(sizeToken.value);
2993
+ }
2994
+ this.expect("DE" /* DE */, '"DE" attendu après TABLEAU');
2995
+ const elemTypeToken = this.expect(["ENTIER" /* INTEGER */, "REEL" /* REAL */, "BOOLEEN" /* BOOLEAN */, "CHAINE" /* STRING */], "Type des éléments attendu");
2996
+ const elemType = this.tokenTypeToDataType(elemTypeToken.type);
2997
+ const typeLabel = size !== undefined ? `TABLEAU[${size}] DE ${elemType}` : `TABLEAU DE ${elemType}`;
2998
+ return {
2999
+ type: "PARAMETER" /* PARAMETER */,
3000
+ value: nameToken.value,
3001
+ token: nameToken,
3002
+ symbolInfo: { name: nameToken.value, type: typeLabel, scope: "param" }
3003
+ };
3004
+ }
3005
+ const typeToken = this.expect(["ENTIER" /* INTEGER */, "REEL" /* REAL */, "BOOLEEN" /* BOOLEAN */, "CHAINE" /* STRING */], "Type du paramètre attendu");
3006
+ const paramType = this.tokenTypeToDataType(typeToken.type);
3007
+ return {
3008
+ type: "PARAMETER" /* PARAMETER */,
3009
+ value: nameToken.value,
3010
+ token: nameToken,
3011
+ symbolInfo: { name: nameToken.value, type: paramType, scope: "param" }
3012
+ };
3013
+ }
3014
+ parseFunctionDeclaration() {
3015
+ const token = this.advance();
3016
+ const nameToken = this.expect("IDENTIFIER" /* IDENTIFIER */, "Nom de fonction attendu");
3017
+ const paramList = this.parseParameterList();
3018
+ this.expect("COLON" /* COLON */, '":" attendu pour le type de retour');
3019
+ const retTypeToken = this.expect(["ENTIER" /* INTEGER */, "REEL" /* REAL */, "BOOLEEN" /* BOOLEAN */, "CHAINE" /* STRING */], "Type de retour attendu");
3020
+ const retType = this.tokenTypeToDataType(retTypeToken.type);
3021
+ const body = this.parseCompoundStatement();
3022
+ return {
3023
+ type: "FUNCTION_DECLARATION" /* FUNCTION_DECLARATION */,
3024
+ value: nameToken.value,
3025
+ children: [
3026
+ paramList,
3027
+ { type: "TYPE_SPECIFIER" /* TYPE_SPECIFIER */, value: retType },
3028
+ body
3029
+ ],
3030
+ token
3031
+ };
3032
+ }
3033
+ parseProcedureDeclaration() {
3034
+ const token = this.advance();
3035
+ const nameToken = this.expect("IDENTIFIER" /* IDENTIFIER */, "Nom de procédure attendu");
3036
+ const paramList = this.parseParameterList();
3037
+ const body = this.parseCompoundStatement();
3038
+ return {
3039
+ type: "PROCEDURE_DECLARATION" /* PROCEDURE_DECLARATION */,
3040
+ value: nameToken.value,
3041
+ children: [paramList, body],
3042
+ token
3043
+ };
3044
+ }
2453
3045
  check(type) {
2454
3046
  if (this.isAtEnd())
2455
3047
  return false;
@@ -2599,6 +3191,8 @@ class CodeGenerator2 {
2599
3191
  return this.generateBlock(node);
2600
3192
  case "VAR_DECLARATION":
2601
3193
  return this.generateVariableDeclaration(node);
3194
+ case "ARRAY_DECLARATION":
3195
+ return this.generateArrayDeclaration(node);
2602
3196
  case "COMPOUND_STATEMENT":
2603
3197
  return this.generateCompoundStatement(node);
2604
3198
  case "ASSIGNMENT":
@@ -2615,6 +3209,12 @@ class CodeGenerator2 {
2615
3209
  return this.generateReadStatement(node);
2616
3210
  case "WRITE_STATEMENT":
2617
3211
  return this.generateWriteStatement(node);
3212
+ case "FUNCTION_DECLARATION":
3213
+ return this.generateFunctionDeclaration(node);
3214
+ case "PROCEDURE_DECLARATION":
3215
+ return this.generateProcedureDeclaration(node);
3216
+ case "RETURN_STATEMENT":
3217
+ return this.generateReturnStatement(node);
2618
3218
  case "BINARY_OP":
2619
3219
  return this.generateBinaryOp(node);
2620
3220
  case "UNARY_OP":
@@ -2623,6 +3223,10 @@ class CodeGenerator2 {
2623
3223
  return this.generateLiteral(node);
2624
3224
  case "VARIABLE":
2625
3225
  return this.generateVariable(node);
3226
+ case "ARRAY_ACCESS":
3227
+ return this.generateArrayAccess(node);
3228
+ case "FUNCTION_CALL":
3229
+ return this.generateFunctionCall(node);
2626
3230
  default:
2627
3231
  this.errors.push({
2628
3232
  type: "ERROR",
@@ -2637,14 +3241,25 @@ class CodeGenerator2 {
2637
3241
  }
2638
3242
  generateProgram(node) {
2639
3243
  const lines = [];
3244
+ const block = node.children?.[0];
2640
3245
  lines.push(`// Programme: ${node.value}`);
3246
+ if (block?.children) {
3247
+ for (const child of block.children) {
3248
+ if (child.type === "FUNCTION_DECLARATION" || child.type === "PROCEDURE_DECLARATION") {
3249
+ lines.push(this.generateNode(child));
3250
+ lines.push("");
3251
+ }
3252
+ }
3253
+ }
2641
3254
  lines.push("async function main() {");
2642
3255
  this.indentLevel++;
2643
- if (node.children && node.children.length > 0) {
2644
- for (const child of node.children) {
2645
- const childCode = this.generateNode(child);
2646
- if (childCode) {
2647
- lines.push(this.indent(childCode));
3256
+ if (block?.children) {
3257
+ for (const child of block.children) {
3258
+ if (child.type !== "FUNCTION_DECLARATION" && child.type !== "PROCEDURE_DECLARATION") {
3259
+ const childCode = this.generateNode(child);
3260
+ if (childCode) {
3261
+ lines.push(this.indent(childCode));
3262
+ }
2648
3263
  }
2649
3264
  }
2650
3265
  }
@@ -2682,7 +3297,8 @@ class CodeGenerator2 {
2682
3297
  for (const child of node.children) {
2683
3298
  const childCode = this.generateNode(child);
2684
3299
  if (childCode) {
2685
- lines.push(this.indent(childCode));
3300
+ const stmt = child.type === "FUNCTION_CALL" ? childCode.replace(/^\(|\)$/g, "") + ";" : childCode;
3301
+ lines.push(this.indent(stmt));
2686
3302
  }
2687
3303
  }
2688
3304
  }
@@ -2693,15 +3309,107 @@ class CodeGenerator2 {
2693
3309
  if (!node.children || node.children.length < 2) {
2694
3310
  return "";
2695
3311
  }
2696
- const variable = node.children[0];
3312
+ const target = node.children[0];
2697
3313
  const expression = node.children[1];
2698
- if (!variable || !expression) {
3314
+ if (!target || !expression) {
2699
3315
  return "";
2700
3316
  }
2701
- const variableName = variable.value;
2702
3317
  const expressionCode = this.generateNode(expression);
3318
+ if (target.type === "ARRAY_ACCESS") {
3319
+ const arrayName = target.value;
3320
+ const index = this.generateNode(target.children[0]);
3321
+ return `${arrayName}[${index}] = ${expressionCode};`;
3322
+ }
3323
+ const variableName = target.value;
2703
3324
  return `${variableName} = ${expressionCode};`;
2704
3325
  }
3326
+ generateArrayDeclaration(node) {
3327
+ if (!node.children || node.children.length < 2)
3328
+ return "";
3329
+ const size = node.children[0].value;
3330
+ const elemType = node.value;
3331
+ const defaultValue = elemType === "BOOLEEN" ? "false" : elemType === "CHAINE" ? '""' : "0";
3332
+ const names = node.children.slice(1).map((c) => c.value);
3333
+ return names.map((name) => `let ${name} = new Array(${size}).fill(${defaultValue});`).join(`
3334
+ `);
3335
+ }
3336
+ generateArrayAccess(node) {
3337
+ const name = node.value;
3338
+ const index = this.generateNode(node.children[0]);
3339
+ return `${name}[${index}]`;
3340
+ }
3341
+ generateFunctionCall(node) {
3342
+ const name = node.value;
3343
+ const args = (node.children ?? []).map((c) => {
3344
+ const code = this.generateNode(c);
3345
+ if (c.type === "VARIABLE") {
3346
+ const sym = this.symbolTable.symbols.get(c.value);
3347
+ if (sym?.type?.startsWith("TABLEAU"))
3348
+ return `${code}.slice()`;
3349
+ }
3350
+ return code;
3351
+ });
3352
+ switch (name.toLowerCase()) {
3353
+ case "abs":
3354
+ return `Math.abs(${args[0]})`;
3355
+ case "max":
3356
+ return `Math.max(${args.join(", ")})`;
3357
+ case "min":
3358
+ return `Math.min(${args.join(", ")})`;
3359
+ case "mod":
3360
+ return `(${args[0]} % ${args[1]})`;
3361
+ case "racine_carree":
3362
+ return `Math.sqrt(${args[0]})`;
3363
+ case "taille":
3364
+ return `${args[0]}.length`;
3365
+ case "sous_chaine":
3366
+ return `${args[0]}.substring(${args[1]}, ${args[1]} + ${args[2]})`;
3367
+ case "concat":
3368
+ return args.join(" + ");
3369
+ case "entier_en_reel":
3370
+ return `${args[0]}`;
3371
+ case "reel_en_entier":
3372
+ return `Math.trunc(${args[0]})`;
3373
+ default:
3374
+ return `(await ${name}(${args.join(", ")}))`;
3375
+ }
3376
+ }
3377
+ generateFunctionDeclaration(node) {
3378
+ const name = node.value;
3379
+ const [paramList, , body] = node.children ?? [];
3380
+ const params = this.generateParamList(paramList);
3381
+ const bodyCode = this.generateNode(body);
3382
+ const lines = [`async function ${name}(${params}) {`];
3383
+ this.indentLevel++;
3384
+ lines.push(this.indent(bodyCode));
3385
+ this.indentLevel--;
3386
+ lines.push("}");
3387
+ return lines.join(`
3388
+ `);
3389
+ }
3390
+ generateProcedureDeclaration(node) {
3391
+ const name = node.value;
3392
+ const [paramList, body] = node.children ?? [];
3393
+ const params = this.generateParamList(paramList);
3394
+ const bodyCode = this.generateNode(body);
3395
+ const lines = [`async function ${name}(${params}) {`];
3396
+ this.indentLevel++;
3397
+ lines.push(this.indent(bodyCode));
3398
+ this.indentLevel--;
3399
+ lines.push("}");
3400
+ return lines.join(`
3401
+ `);
3402
+ }
3403
+ generateParamList(paramList) {
3404
+ if (!paramList?.children)
3405
+ return "";
3406
+ return paramList.children.map((p) => p.value).join(", ");
3407
+ }
3408
+ generateReturnStatement(node) {
3409
+ if (!node.children?.[0])
3410
+ return "return;";
3411
+ return `return ${this.generateNode(node.children[0])};`;
3412
+ }
2705
3413
  generateIfStatement(node) {
2706
3414
  if (!node.children || node.children.length < 2) {
2707
3415
  return "";
@@ -2803,34 +3511,20 @@ class CodeGenerator2 {
2803
3511
  return code;
2804
3512
  }
2805
3513
  generateReadStatement(node) {
2806
- if (!node.children || node.children.length === 0) {
3514
+ if (!node.children || node.children.length === 0)
2807
3515
  return "";
2808
- }
2809
- const variable = node.children[0];
2810
- if (!variable) {
3516
+ const target = node.children[0];
3517
+ if (!target)
2811
3518
  return "";
3519
+ const isArray = target.type === "ARRAY_ACCESS";
3520
+ const varName = isArray ? `${target.value}[${this.generateNode(target.children[0])}]` : target.value;
3521
+ const symbolName = target.value;
3522
+ const symbolInfo = this.symbolTable.symbols.get(symbolName);
3523
+ const typeHint = symbolInfo?.type ?? "";
3524
+ if (typeHint.startsWith("ENTIER") || typeHint === "REEL" || typeHint.startsWith("TABLEAU")) {
3525
+ return `${varName} = parseInt(await lire(""));`;
2812
3526
  }
2813
- const variableName = variable.value;
2814
- const symbolInfo = this.symbolTable.symbols.get(variableName);
2815
- let conversion = "";
2816
- if (symbolInfo) {
2817
- switch (symbolInfo.type) {
2818
- case "ENTIER":
2819
- case "REEL":
2820
- conversion = "parseInt(";
2821
- break;
2822
- case "BOOLEEN":
2823
- conversion = "(";
2824
- break;
2825
- default:
2826
- conversion = "";
2827
- }
2828
- }
2829
- if (conversion) {
2830
- return `${variableName} = ${conversion}await lire(""));`;
2831
- } else {
2832
- return `${variableName} = await lire("");`;
2833
- }
3527
+ return `${varName} = await lire("");`;
2834
3528
  }
2835
3529
  generateWriteStatement(node) {
2836
3530
  if (!node.children || node.children.length === 0) {
@@ -2929,6 +3623,8 @@ class CodeGenerator2 {
2929
3623
  return ">";
2930
3624
  case ">=":
2931
3625
  return ">=";
3626
+ case "%":
3627
+ return "%";
2932
3628
  case "et":
2933
3629
  return "&&";
2934
3630
  case "ou":
@@ -3201,7 +3897,7 @@ var TokenType2;
3201
3897
  TokenType3["DE"] = "DE";
3202
3898
  TokenType3["TO"] = "A";
3203
3899
  TokenType3["REPEAT"] = "REPETER";
3204
- TokenType3["UNTIL"] = "JUSQUA";
3900
+ TokenType3["UNTIL"] = "JUSQU'A";
3205
3901
  TokenType3["READ"] = "LIRE";
3206
3902
  TokenType3["WRITE"] = "ECRIRE";
3207
3903
  TokenType3["TRUE"] = "VRAI";
@@ -3212,10 +3908,15 @@ var TokenType2;
3212
3908
  TokenType3["ENDFOR"] = "FINPOUR";
3213
3909
  TokenType3["ENDIF"] = "FINIF";
3214
3910
  TokenType3["ENDWHILE"] = "FINTANTQUE";
3911
+ TokenType3["ARRAY"] = "TABLEAU";
3912
+ TokenType3["FUNCTION"] = "FONCTION";
3913
+ TokenType3["PROCEDURE"] = "PROCEDURE";
3914
+ TokenType3["RETURN"] = "RETOURNER";
3215
3915
  TokenType3["PLUS"] = "PLUS";
3216
3916
  TokenType3["MINUS"] = "MINUS";
3217
3917
  TokenType3["MULTIPLY"] = "MULTIPLY";
3218
3918
  TokenType3["DIVIDE"] = "DIVIDE";
3919
+ TokenType3["MODULO"] = "MODULO";
3219
3920
  TokenType3["ASSIGN"] = "ASSIGN";
3220
3921
  TokenType3["EQUAL"] = "EQUAL";
3221
3922
  TokenType3["NOT_EQUAL"] = "NOT_EQUAL";
@@ -3229,6 +3930,8 @@ var TokenType2;
3229
3930
  TokenType3["DOT"] = "DOT";
3230
3931
  TokenType3["LEFT_PAREN"] = "LEFT_PAREN";
3231
3932
  TokenType3["RIGHT_PAREN"] = "RIGHT_PAREN";
3933
+ TokenType3["LEFT_BRACKET"] = "LEFT_BRACKET";
3934
+ TokenType3["RIGHT_BRACKET"] = "RIGHT_BRACKET";
3232
3935
  TokenType3["NUMBER"] = "NUMBER";
3233
3936
  TokenType3["IDENTIFIER"] = "IDENTIFIER";
3234
3937
  TokenType3["STRING_LITERAL"] = "STRING_LITERAL";
@@ -3253,6 +3956,13 @@ var NodeType2;
3253
3956
  NodeType3["UNARY_OP"] = "UNARY_OP";
3254
3957
  NodeType3["LITERAL"] = "LITERAL";
3255
3958
  NodeType3["VARIABLE"] = "VARIABLE";
3959
+ NodeType3["FUNCTION_CALL"] = "FUNCTION_CALL";
3960
+ NodeType3["ARRAY_ACCESS"] = "ARRAY_ACCESS";
3961
+ NodeType3["ARRAY_DECLARATION"] = "ARRAY_DECLARATION";
3962
+ NodeType3["FUNCTION_DECLARATION"] = "FUNCTION_DECLARATION";
3963
+ NodeType3["PROCEDURE_DECLARATION"] = "PROCEDURE_DECLARATION";
3964
+ NodeType3["RETURN_STATEMENT"] = "RETURN_STATEMENT";
3965
+ NodeType3["PARAMETER"] = "PARAMETER";
3256
3966
  NodeType3["BLOCK"] = "BLOCK";
3257
3967
  NodeType3["PARAMETER_LIST"] = "PARAMETER_LIST";
3258
3968
  })(NodeType2 ||= {});
@@ -3264,12 +3974,373 @@ var DataType2;
3264
3974
  DataType3["STRING"] = "CHAINE";
3265
3975
  DataType3["VOID"] = "VIDE";
3266
3976
  })(DataType2 ||= {});
3977
+ // src/keywords.ts
3978
+ var KEYWORDS2 = {
3979
+ PROGRAMME: {
3980
+ tokenType: "PROGRAMME" /* PROGRAM */,
3981
+ kind: "control",
3982
+ detail: "Mot-clé PROGRAMME",
3983
+ documentation: "**PROGRAMME** : Début d'un programme AlgoLang."
3984
+ },
3985
+ DEBUT: {
3986
+ tokenType: "DEBUT" /* BEGIN */,
3987
+ kind: "control",
3988
+ detail: "Mot-clé DEBUT",
3989
+ documentation: "**DEBUT** : Début du bloc d'instructions principal."
3990
+ },
3991
+ FIN: {
3992
+ tokenType: "FIN" /* END */,
3993
+ kind: "control",
3994
+ detail: "Mot-clé FIN",
3995
+ documentation: "**FIN** : Fin du bloc d'instructions ou du programme."
3996
+ },
3997
+ VAR: {
3998
+ tokenType: "VAR" /* VAR */,
3999
+ kind: "declaration",
4000
+ detail: "Mot-clé VAR",
4001
+ documentation: "**VAR** : Section de déclaration des variables."
4002
+ },
4003
+ ENTIER: {
4004
+ tokenType: "ENTIER" /* INTEGER */,
4005
+ kind: "type",
4006
+ detail: "Type ENTIER",
4007
+ documentation: "**ENTIER** : Type de donnée pour les nombres entiers."
4008
+ },
4009
+ REEL: {
4010
+ tokenType: "REEL" /* REAL */,
4011
+ kind: "type",
4012
+ detail: "Type REEL",
4013
+ documentation: "**REEL** : Type de donnée pour les nombres à virgule."
4014
+ },
4015
+ BOOLEEN: {
4016
+ tokenType: "BOOLEEN" /* BOOLEAN */,
4017
+ kind: "type",
4018
+ detail: "Type BOOLEEN",
4019
+ documentation: "**BOOLEEN** : Type de donnée logique (VRAI/FAUX)."
4020
+ },
4021
+ CHAINE: {
4022
+ tokenType: "CHAINE" /* STRING */,
4023
+ kind: "type",
4024
+ detail: "Type CHAINE",
4025
+ documentation: "**CHAINE** : Type de donnée pour le texte."
4026
+ },
4027
+ SI: {
4028
+ tokenType: "SI" /* IF */,
4029
+ kind: "control",
4030
+ detail: "Mot-clé SI",
4031
+ documentation: "**SI** : Structure conditionnelle."
4032
+ },
4033
+ ALORS: {
4034
+ tokenType: "ALORS" /* THEN */,
4035
+ kind: "control",
4036
+ detail: "Mot-clé ALORS",
4037
+ documentation: "**ALORS** : Début du bloc exécuté si la condition est vraie."
4038
+ },
4039
+ SINON: {
4040
+ tokenType: "SINON" /* ELSE */,
4041
+ kind: "control",
4042
+ detail: "Mot-clé SINON",
4043
+ documentation: "**SINON** : Début du bloc exécuté si la condition est fausse."
4044
+ },
4045
+ FINSI: {
4046
+ tokenType: "FINIF" /* ENDIF */,
4047
+ kind: "control",
4048
+ detail: "Mot-clé FINSI",
4049
+ documentation: "**FINSI** : Fin d'une structure conditionnelle."
4050
+ },
4051
+ TANTQUE: {
4052
+ tokenType: "TANTQUE" /* WHILE */,
4053
+ kind: "control",
4054
+ detail: "Mot-clé TANTQUE",
4055
+ documentation: "**TANTQUE** : Boucle répétitive tant qu'une condition est vraie."
4056
+ },
4057
+ FAIRE: {
4058
+ tokenType: "FAIRE" /* DO */,
4059
+ kind: "control",
4060
+ detail: "Mot-clé FAIRE",
4061
+ documentation: "**FAIRE** : Début du corps d'une boucle."
4062
+ },
4063
+ FINTANTQUE: {
4064
+ tokenType: "FINTANTQUE" /* ENDWHILE */,
4065
+ kind: "control",
4066
+ detail: "Mot-clé FINTANTQUE",
4067
+ documentation: "**FINTANTQUE** : Fin d'une boucle TANTQUE."
4068
+ },
4069
+ POUR: {
4070
+ tokenType: "POUR" /* FOR */,
4071
+ kind: "control",
4072
+ detail: "Mot-clé POUR",
4073
+ documentation: "**POUR** : Boucle avec compteur."
4074
+ },
4075
+ ALLANT: {
4076
+ tokenType: "ALLANT" /* ALLANT */,
4077
+ kind: "control",
4078
+ detail: "Mot-clé ALLANT",
4079
+ documentation: "**ALLANT** : Utilisé dans une boucle POUR pour spécifier la plage."
4080
+ },
4081
+ DE: {
4082
+ tokenType: "DE" /* DE */,
4083
+ kind: "control",
4084
+ detail: "Mot-clé DE",
4085
+ documentation: "**DE** : Spécifie le début d'une plage dans une boucle POUR."
4086
+ },
4087
+ A: {
4088
+ tokenType: "A" /* TO */,
4089
+ kind: "control",
4090
+ detail: "Mot-clé A",
4091
+ documentation: "**A** : Spécifie la fin d'une plage dans une boucle POUR."
4092
+ },
4093
+ FINPOUR: {
4094
+ tokenType: "FINPOUR" /* ENDFOR */,
4095
+ kind: "control",
4096
+ detail: "Mot-clé FINPOUR",
4097
+ documentation: "**FINPOUR** : Fin d'une boucle POUR."
4098
+ },
4099
+ REPETER: {
4100
+ tokenType: "REPETER" /* REPEAT */,
4101
+ kind: "control",
4102
+ detail: "Mot-clé REPETER",
4103
+ documentation: "**REPETER** : Boucle exécutée au moins une fois."
4104
+ },
4105
+ "JUSQU'A": {
4106
+ tokenType: "JUSQU'A" /* UNTIL */,
4107
+ kind: "control",
4108
+ detail: "Mot-clé JUSQU'A",
4109
+ documentation: "**JUSQU'A** : Condition de fin d'une boucle REPETER."
4110
+ },
4111
+ LIRE: {
4112
+ tokenType: "LIRE" /* READ */,
4113
+ kind: "io",
4114
+ detail: "Fonction LIRE",
4115
+ documentation: "**LIRE(variable)** : Lit une valeur depuis l'entrée standard."
4116
+ },
4117
+ ECRIRE: {
4118
+ tokenType: "ECRIRE" /* WRITE */,
4119
+ kind: "io",
4120
+ detail: "Fonction ECRIRE",
4121
+ documentation: "**ECRIRE(...)** : Affiche des valeurs dans la console."
4122
+ },
4123
+ VRAI: {
4124
+ tokenType: "VRAI" /* TRUE */,
4125
+ kind: "literal",
4126
+ detail: "Constante VRAI",
4127
+ documentation: "**VRAI** : Valeur booléenne vraie."
4128
+ },
4129
+ FAUX: {
4130
+ tokenType: "FAUX" /* FALSE */,
4131
+ kind: "literal",
4132
+ detail: "Constante FAUX",
4133
+ documentation: "**FAUX** : Valeur booléenne fausse."
4134
+ },
4135
+ ET: {
4136
+ tokenType: "ET" /* AND */,
4137
+ kind: "operator",
4138
+ detail: "Opérateur ET",
4139
+ documentation: "**ET** : Opérateur logique ET (AND)."
4140
+ },
4141
+ OU: {
4142
+ tokenType: "OU" /* OR */,
4143
+ kind: "operator",
4144
+ detail: "Opérateur OU",
4145
+ documentation: "**OU** : Opérateur logique OU (OR)."
4146
+ },
4147
+ NON: {
4148
+ tokenType: "NON" /* NOT */,
4149
+ kind: "operator",
4150
+ detail: "Opérateur NON",
4151
+ documentation: "**NON** : Opérateur logique NON (NOT)."
4152
+ },
4153
+ TABLEAU: {
4154
+ tokenType: "TABLEAU" /* ARRAY */,
4155
+ kind: "declaration",
4156
+ detail: "Type TABLEAU",
4157
+ documentation: "**TABLEAU** : Déclare un tableau de n éléments.\nSyntaxe : `t: TABLEAU[10] DE ENTIER`"
4158
+ },
4159
+ FONCTION: {
4160
+ tokenType: "FONCTION" /* FUNCTION */,
4161
+ kind: "declaration",
4162
+ detail: "Mot-clé FONCTION",
4163
+ documentation: "**FONCTION** nom(params): TYPE : Déclare une fonction qui retourne une valeur.\nExemple : `FONCTION carre(n: ENTIER): ENTIER`"
4164
+ },
4165
+ PROCEDURE: {
4166
+ tokenType: "PROCEDURE" /* PROCEDURE */,
4167
+ kind: "declaration",
4168
+ detail: "Mot-clé PROCEDURE",
4169
+ documentation: "**PROCEDURE** nom(params) : Déclare une procédure (sans valeur de retour).\nExemple : `PROCEDURE afficher(s: CHAINE)`"
4170
+ },
4171
+ RETOURNER: {
4172
+ tokenType: "RETOURNER" /* RETURN */,
4173
+ kind: "declaration",
4174
+ detail: "Mot-clé RETOURNER",
4175
+ documentation: "**RETOURNER** expr : Retourne une valeur depuis une fonction."
4176
+ },
4177
+ abs: {
4178
+ tokenType: null,
4179
+ kind: "builtin-function",
4180
+ detail: "Fonction abs(x)",
4181
+ documentation: "**abs(x)** : Retourne la valeur absolue de x."
4182
+ },
4183
+ max: {
4184
+ tokenType: null,
4185
+ kind: "builtin-function",
4186
+ detail: "Fonction max(a, b)",
4187
+ documentation: "**max(a, b)** : Retourne le plus grand des deux nombres."
4188
+ },
4189
+ min: {
4190
+ tokenType: null,
4191
+ kind: "builtin-function",
4192
+ detail: "Fonction min(a, b)",
4193
+ documentation: "**min(a, b)** : Retourne le plus petit des deux nombres."
4194
+ },
4195
+ mod: {
4196
+ tokenType: null,
4197
+ kind: "builtin-function",
4198
+ detail: "Fonction mod(a, b)",
4199
+ documentation: "**mod(a, b)** : Retourne le reste de la division de a par b. Équivalent à `a % b`."
4200
+ },
4201
+ racine_carree: {
4202
+ tokenType: null,
4203
+ kind: "builtin-function",
4204
+ detail: "Fonction racine_carree(x)",
4205
+ documentation: "**racine_carree(x)** : Retourne la racine carrée de x."
4206
+ },
4207
+ taille: {
4208
+ tokenType: null,
4209
+ kind: "builtin-function",
4210
+ detail: "Fonction taille(x)",
4211
+ documentation: "**taille(x)** : Retourne la taille d'un tableau ou la longueur d'une chaîne."
4212
+ },
4213
+ sous_chaine: {
4214
+ tokenType: null,
4215
+ kind: "builtin-function",
4216
+ detail: "Fonction sous_chaine(s, i, n)",
4217
+ documentation: "**sous_chaine(s, i, n)** : Retourne n caractères de la chaîne s à partir de l'indice i."
4218
+ },
4219
+ concat: {
4220
+ tokenType: null,
4221
+ kind: "builtin-function",
4222
+ detail: "Fonction concat(a, b)",
4223
+ documentation: "**concat(a, b)** : Concatène deux chaînes de caractères."
4224
+ },
4225
+ entier_en_reel: {
4226
+ tokenType: null,
4227
+ kind: "builtin-function",
4228
+ detail: "Fonction entier_en_reel(x)",
4229
+ documentation: "**entier_en_reel(x)** : Convertit un entier en réel."
4230
+ },
4231
+ reel_en_entier: {
4232
+ tokenType: null,
4233
+ kind: "builtin-function",
4234
+ detail: "Fonction reel_en_entier(x)",
4235
+ documentation: "**reel_en_entier(x)** : Convertit un réel en entier (troncature)."
4236
+ }
4237
+ };
4238
+ var BUILTIN_NAMES2 = new Set(Object.entries(KEYWORDS2).filter(([, e]) => e.tokenType === null).map(([label]) => label));
4239
+ // src/semantic/semantic-analyzer.ts
4240
+ class SemanticAnalyzer2 {
4241
+ symbolTable = {
4242
+ symbols: new Map,
4243
+ children: [],
4244
+ scopeName: "global"
4245
+ };
4246
+ errors = [];
4247
+ analyze(ast) {
4248
+ this.walk(ast);
4249
+ return { symbolTable: this.symbolTable, errors: this.errors };
4250
+ }
4251
+ walk(node) {
4252
+ switch (node.type) {
4253
+ case "VAR_DECLARATION" /* VAR_DECLARATION */:
4254
+ this.collectVarDeclaration(node);
4255
+ break;
4256
+ case "ARRAY_DECLARATION" /* ARRAY_DECLARATION */:
4257
+ this.collectArrayDeclaration(node);
4258
+ break;
4259
+ default:
4260
+ node.children?.forEach((child) => this.walk(child));
4261
+ break;
4262
+ }
4263
+ }
4264
+ collectVarDeclaration(node) {
4265
+ const algoType = node.value;
4266
+ const line = node.token?.line ?? 0;
4267
+ const column = node.token?.column ?? 0;
4268
+ const position = node.token?.position ?? 0;
4269
+ for (const child of node.children ?? []) {
4270
+ if (child.type !== "VARIABLE" /* VARIABLE */)
4271
+ continue;
4272
+ const name = child.value;
4273
+ if (this.validateName(name, line, column, position)) {
4274
+ this.defineSymbol(name, algoType, line, column);
4275
+ }
4276
+ }
4277
+ }
4278
+ collectArrayDeclaration(node) {
4279
+ const elemType = node.value;
4280
+ const sizeNode = node.children?.[0];
4281
+ const size = sizeNode?.value;
4282
+ const typeLabel = `TABLEAU[${size}] DE ${elemType}`;
4283
+ const line = node.token?.line ?? 0;
4284
+ const column = node.token?.column ?? 0;
4285
+ const position = node.token?.position ?? 0;
4286
+ for (const child of (node.children ?? []).slice(1)) {
4287
+ if (child.type !== "VARIABLE" /* VARIABLE */)
4288
+ continue;
4289
+ const name = child.value;
4290
+ if (this.validateName(name, line, column, position)) {
4291
+ this.defineSymbol(name, typeLabel, line, column);
4292
+ }
4293
+ }
4294
+ }
4295
+ validateName(name, line, column, position) {
4296
+ if (BUILTIN_NAMES.has(name)) {
4297
+ this.errors.push({
4298
+ type: "ERROR",
4299
+ message: `Le nom '${name}' est une fonction intégrée et ne peut pas être utilisé comme nom de variable`,
4300
+ line,
4301
+ column,
4302
+ position,
4303
+ code: "BUILTIN_SHADOWING",
4304
+ explanation: `'${name}' est une fonction intégrée d'AlgoLang`,
4305
+ suggestion: `Choisissez un autre nom, par exemple '${name}Valeur' ou 'mon${name.charAt(0).toUpperCase()}${name.slice(1)}'`
4306
+ });
4307
+ return false;
4308
+ }
4309
+ if (this.symbolTable.symbols.has(name)) {
4310
+ this.errors.push({
4311
+ type: "ERROR",
4312
+ message: `La variable '${name}' est déjà déclarée`,
4313
+ line,
4314
+ column,
4315
+ position,
4316
+ code: "DUPLICATE_VARIABLE",
4317
+ explanation: "Chaque variable doit avoir un nom unique dans son scope",
4318
+ suggestion: `Choisissez un autre nom pour la variable '${name}'`
4319
+ });
4320
+ return false;
4321
+ }
4322
+ return true;
4323
+ }
4324
+ defineSymbol(name, type, line, column) {
4325
+ const info = {
4326
+ name,
4327
+ type,
4328
+ scope: this.symbolTable.scopeName,
4329
+ line,
4330
+ column
4331
+ };
4332
+ this.symbolTable.symbols.set(name, info);
4333
+ }
4334
+ }
3267
4335
  export {
3268
4336
  TokenType2 as TokenType,
4337
+ SemanticAnalyzer2 as SemanticAnalyzer,
3269
4338
  Parser,
3270
4339
  NodeType2 as NodeType,
3271
4340
  Lexer,
4341
+ KEYWORDS2 as KEYWORDS,
3272
4342
  DataType2 as DataType,
3273
4343
  CodeGenerator,
4344
+ BUILTIN_NAMES2 as BUILTIN_NAMES,
3274
4345
  AlgoLangCompiler
3275
4346
  };