hispano-lang 1.0.8 → 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.
package/dist/parser.js CHANGED
@@ -20,7 +20,7 @@ class Parser {
20
20
  statements.push(this.declaration());
21
21
 
22
22
  // Consume semicolon if present between statements
23
- if (this.match('SEMICOLON')) {
23
+ if (this.match("SEMICOLON")) {
24
24
  // Semicolon consumed
25
25
  }
26
26
  }
@@ -34,47 +34,67 @@ class Parser {
34
34
  */
35
35
  declaration() {
36
36
  try {
37
- if (this.match('VARIABLE')) {
37
+ if (this.match("VARIABLE")) {
38
38
  return this.variableDeclaration();
39
39
  }
40
40
 
41
- if (this.match('FUNCION')) {
41
+ if (this.match("CONSTANTE")) {
42
+ return this.constantDeclaration();
43
+ }
44
+
45
+ if (this.match("FUNCION")) {
42
46
  return this.functionDeclaration();
43
47
  }
44
48
 
45
- if (this.match('MOSTRAR')) {
49
+ if (this.match("CLASE")) {
50
+ return this.classDeclaration();
51
+ }
52
+
53
+ if (this.match("MOSTRAR")) {
46
54
  return this.mostrarStatement();
47
55
  }
48
56
 
49
- if (this.match('LEER')) {
57
+ if (this.match("LEER")) {
50
58
  return this.leerStatement();
51
59
  }
52
60
 
53
- if (this.match('SI')) {
61
+ if (this.match("SI")) {
54
62
  return this.ifStatement();
55
63
  }
56
64
 
57
- if (this.match('MIENTRAS')) {
65
+ if (this.match("MIENTRAS")) {
58
66
  return this.whileStatement();
59
67
  }
60
68
 
61
- if (this.match('PARA')) {
69
+ if (this.match("PARA")) {
70
+ // Check if it's "para cada" (for-each) or regular "para" (for)
71
+ if (this.match("CADA")) {
72
+ return this.forEachStatement();
73
+ }
62
74
  return this.forStatement();
63
75
  }
64
76
 
65
- if (this.match('RETORNAR')) {
77
+ if (this.match("ELEGIR")) {
78
+ return this.elegirStatement();
79
+ }
80
+
81
+ if (this.match("HACER")) {
82
+ return this.hacerMientrasStatement();
83
+ }
84
+
85
+ if (this.match("RETORNAR")) {
66
86
  return this.returnStatement();
67
87
  }
68
88
 
69
- if (this.match('ROMPER')) {
89
+ if (this.match("ROMPER")) {
70
90
  return this.breakStatement();
71
91
  }
72
92
 
73
- if (this.match('CONTINUAR')) {
93
+ if (this.match("CONTINUAR")) {
74
94
  return this.continueStatement();
75
95
  }
76
96
 
77
- if (this.match('INTENTAR')) {
97
+ if (this.match("INTENTAR")) {
78
98
  return this.tryStatement();
79
99
  }
80
100
 
@@ -91,21 +111,46 @@ class Parser {
91
111
  */
92
112
  variableDeclaration() {
93
113
  let name;
94
- if (this.match('IDENTIFIER')) {
114
+ if (this.match("IDENTIFIER")) {
95
115
  name = this.previous();
96
- } else if (this.match('AND')) {
116
+ } else if (this.match("AND")) {
97
117
  name = this.previous();
98
118
  } else {
99
- throw new Error('Se esperaba un nombre de variable');
119
+ throw new Error("Se esperaba un nombre de variable");
100
120
  }
101
121
 
102
122
  let initializer = null;
103
- if (this.match('EQUAL')) {
123
+ if (this.match("EQUAL")) {
104
124
  initializer = this.expression();
105
125
  }
106
126
 
107
127
  return {
108
- type: 'VariableDeclaration',
128
+ type: "VariableDeclaration",
129
+ name: name.lexeme,
130
+ initializer,
131
+ };
132
+ }
133
+
134
+ /**
135
+ * Parses a constant declaration
136
+ * @returns {Object} Constant declaration
137
+ */
138
+ constantDeclaration() {
139
+ let name;
140
+ if (this.match("IDENTIFIER")) {
141
+ name = this.previous();
142
+ } else {
143
+ throw new Error("Se esperaba un nombre de constante");
144
+ }
145
+
146
+ if (!this.match("EQUAL")) {
147
+ throw new Error("Las constantes deben ser inicializadas");
148
+ }
149
+
150
+ const initializer = this.expression();
151
+
152
+ return {
153
+ type: "ConstantDeclaration",
109
154
  name: name.lexeme,
110
155
  initializer,
111
156
  };
@@ -116,40 +161,143 @@ class Parser {
116
161
  * @returns {Object} Function declaration
117
162
  */
118
163
  functionDeclaration() {
119
- const name = this.consume('IDENTIFIER', 'Expected function name');
120
- this.consume('LEFT_PAREN', 'Expected ( after function name');
164
+ const name = this.consume("IDENTIFIER", "Expected function name");
165
+ this.consume("LEFT_PAREN", "Expected ( after function name");
121
166
 
122
167
  const parameters = [];
123
- if (!this.check('RIGHT_PAREN')) {
168
+ if (!this.check("RIGHT_PAREN")) {
124
169
  do {
125
170
  if (parameters.length >= 255) {
126
- throw new Error('No se pueden tener más de 255 parámetros');
171
+ throw new Error("No se pueden tener más de 255 parámetros");
127
172
  }
128
173
  let param;
129
- if (this.match('IDENTIFIER')) {
174
+ if (this.match("IDENTIFIER")) {
130
175
  param = this.previous();
131
- } else if (this.match('AND')) {
176
+ } else if (this.match("AND")) {
132
177
  param = this.previous();
133
178
  } else {
134
- throw new Error('Se esperaba un nombre de parámetro');
179
+ throw new Error("Se esperaba un nombre de parámetro");
135
180
  }
136
181
  parameters.push(param.lexeme);
137
- } while (this.match('COMMA'));
182
+ } while (this.match("COMMA"));
138
183
  }
139
184
 
140
- this.consume('RIGHT_PAREN', 'Expected ) after parameters');
141
- this.consume('LEFT_BRACE', 'Expected { before function body');
185
+ this.consume("RIGHT_PAREN", "Expected ) after parameters");
186
+ this.consume("LEFT_BRACE", "Expected { before function body");
142
187
  const body = this.block();
143
- this.consume('RIGHT_BRACE', 'Expected } after function body');
188
+ this.consume("RIGHT_BRACE", "Expected } after function body");
144
189
 
145
190
  return {
146
- type: 'FunctionDeclaration',
191
+ type: "FunctionDeclaration",
147
192
  name: name.lexeme,
148
193
  parameters,
149
194
  body,
150
195
  };
151
196
  }
152
197
 
198
+ /**
199
+ * Parses a class declaration
200
+ * @returns {Object} Class declaration
201
+ */
202
+ classDeclaration() {
203
+ const name = this.consume("IDENTIFIER", "Se esperaba un nombre de clase");
204
+
205
+ // Check for inheritance
206
+ let superclass = null;
207
+ if (this.match("EXTIENDE")) {
208
+ this.consume("IDENTIFIER", "Se esperaba el nombre de la clase padre");
209
+ superclass = this.previous().lexeme;
210
+ }
211
+
212
+ this.consume("LEFT_BRACE", "Se esperaba { después del nombre de clase");
213
+
214
+ // Parse class body (constructor and methods)
215
+ let constructor = null;
216
+ const methods = [];
217
+
218
+ while (!this.check("RIGHT_BRACE") && !this.isAtEnd()) {
219
+ if (this.match("CONSTRUCTOR")) {
220
+ // Parse constructor
221
+ this.consume("LEFT_PAREN", "Se esperaba ( después de constructor");
222
+ const parameters = [];
223
+ if (!this.check("RIGHT_PAREN")) {
224
+ do {
225
+ if (parameters.length >= 255) {
226
+ throw new Error("No se pueden tener más de 255 parámetros");
227
+ }
228
+ const param = this.consume(
229
+ "IDENTIFIER",
230
+ "Se esperaba nombre de parámetro",
231
+ );
232
+ parameters.push(param.lexeme);
233
+ } while (this.match("COMMA"));
234
+ }
235
+ this.consume("RIGHT_PAREN", "Se esperaba ) después de parámetros");
236
+ this.consume(
237
+ "LEFT_BRACE",
238
+ "Se esperaba { antes del cuerpo del constructor",
239
+ );
240
+ const body = this.block();
241
+ this.consume(
242
+ "RIGHT_BRACE",
243
+ "Se esperaba } después del cuerpo del constructor",
244
+ );
245
+
246
+ constructor = {
247
+ parameters,
248
+ body,
249
+ };
250
+ } else if (this.match("IDENTIFIER")) {
251
+ // Parse method
252
+ const methodName = this.previous().lexeme;
253
+ this.consume(
254
+ "LEFT_PAREN",
255
+ "Se esperaba ( después del nombre del método",
256
+ );
257
+ const parameters = [];
258
+ if (!this.check("RIGHT_PAREN")) {
259
+ do {
260
+ if (parameters.length >= 255) {
261
+ throw new Error("No se pueden tener más de 255 parámetros");
262
+ }
263
+ const param = this.consume(
264
+ "IDENTIFIER",
265
+ "Se esperaba nombre de parámetro",
266
+ );
267
+ parameters.push(param.lexeme);
268
+ } while (this.match("COMMA"));
269
+ }
270
+ this.consume("RIGHT_PAREN", "Se esperaba ) después de parámetros");
271
+ this.consume("LEFT_BRACE", "Se esperaba { antes del cuerpo del método");
272
+ const body = this.block();
273
+ this.consume(
274
+ "RIGHT_BRACE",
275
+ "Se esperaba } después del cuerpo del método",
276
+ );
277
+
278
+ methods.push({
279
+ name: methodName,
280
+ parameters,
281
+ body,
282
+ });
283
+ } else {
284
+ throw new Error(
285
+ "Se esperaba constructor o método en el cuerpo de la clase",
286
+ );
287
+ }
288
+ }
289
+
290
+ this.consume("RIGHT_BRACE", "Se esperaba } después del cuerpo de la clase");
291
+
292
+ return {
293
+ type: "ClassDeclaration",
294
+ name: name.lexeme,
295
+ superclass,
296
+ constructor,
297
+ methods,
298
+ };
299
+ }
300
+
153
301
  /**
154
302
  * Parses a show statement
155
303
  * @returns {Object} Show statement
@@ -158,7 +306,7 @@ class Parser {
158
306
  const value = this.expression();
159
307
 
160
308
  return {
161
- type: 'MostrarStatement',
309
+ type: "MostrarStatement",
162
310
  expression: value,
163
311
  };
164
312
  }
@@ -170,18 +318,18 @@ class Parser {
170
318
  leerStatement() {
171
319
  // Parse the variable name to store the input
172
320
  const variableName = this.consume(
173
- 'IDENTIFIER',
174
- 'Expected variable name after leer'
321
+ "IDENTIFIER",
322
+ "Expected variable name after leer",
175
323
  );
176
324
 
177
325
  // Optional prompt message
178
326
  let prompt = null;
179
- if (this.match('STRING')) {
327
+ if (this.match("STRING")) {
180
328
  prompt = this.previous().literal;
181
329
  }
182
330
 
183
331
  return {
184
- type: 'LeerStatement',
332
+ type: "LeerStatement",
185
333
  variable: variableName.lexeme,
186
334
  prompt: prompt,
187
335
  };
@@ -193,19 +341,19 @@ class Parser {
193
341
  */
194
342
  ifStatement() {
195
343
  const condition = this.expression();
196
- this.consume('LEFT_BRACE', 'Expected { after condition');
344
+ this.consume("LEFT_BRACE", "Expected { after condition");
197
345
  const thenBranch = this.block();
198
- this.consume('RIGHT_BRACE', 'Expected } after block');
346
+ this.consume("RIGHT_BRACE", "Expected } after block");
199
347
  let elseBranch = null;
200
348
 
201
- if (this.match('SINO')) {
202
- this.consume('LEFT_BRACE', 'Expected { after else');
349
+ if (this.match("SINO")) {
350
+ this.consume("LEFT_BRACE", "Expected { after else");
203
351
  elseBranch = this.block();
204
- this.consume('RIGHT_BRACE', 'Expected } after else block');
352
+ this.consume("RIGHT_BRACE", "Expected } after else block");
205
353
  }
206
354
 
207
355
  return {
208
- type: 'IfStatement',
356
+ type: "IfStatement",
209
357
  condition,
210
358
  thenBranch,
211
359
  elseBranch,
@@ -218,12 +366,12 @@ class Parser {
218
366
  */
219
367
  whileStatement() {
220
368
  const condition = this.expression();
221
- this.consume('LEFT_BRACE', 'Expected { after condition');
369
+ this.consume("LEFT_BRACE", "Expected { after condition");
222
370
  const body = this.block();
223
- this.consume('RIGHT_BRACE', 'Expected } after block');
371
+ this.consume("RIGHT_BRACE", "Expected } after block");
224
372
 
225
373
  return {
226
- type: 'WhileStatement',
374
+ type: "WhileStatement",
227
375
  condition,
228
376
  body,
229
377
  };
@@ -234,18 +382,18 @@ class Parser {
234
382
  * @returns {Object} For statement
235
383
  */
236
384
  forStatement() {
237
- this.consume('LEFT_PAREN', 'Expected ( after para');
385
+ this.consume("LEFT_PAREN", "Expected ( after para");
238
386
 
239
387
  // Initializer (optional)
240
388
  let initializer = null;
241
- if (!this.check('SEMICOLON')) {
242
- if (this.match('VARIABLE')) {
389
+ if (!this.check("SEMICOLON")) {
390
+ if (this.match("VARIABLE")) {
243
391
  initializer = this.variableDeclaration();
244
392
  } else {
245
393
  initializer = this.expressionStatement();
246
394
  }
247
395
  // Consume the semicolon after initializer
248
- this.consume('SEMICOLON', 'Expected ; after for initializer');
396
+ this.consume("SEMICOLON", "Expected ; after for initializer");
249
397
  } else {
250
398
  // Skip the first semicolon if no initializer
251
399
  this.advance();
@@ -253,24 +401,24 @@ class Parser {
253
401
 
254
402
  // Condition (optional)
255
403
  let condition = null;
256
- if (!this.check('SEMICOLON')) {
404
+ if (!this.check("SEMICOLON")) {
257
405
  condition = this.expression();
258
406
  }
259
- this.consume('SEMICOLON', 'Expected ; after condition');
407
+ this.consume("SEMICOLON", "Expected ; after condition");
260
408
 
261
409
  // Increment (optional)
262
410
  let increment = null;
263
- if (!this.check('RIGHT_PAREN')) {
411
+ if (!this.check("RIGHT_PAREN")) {
264
412
  increment = this.expression();
265
413
  }
266
- this.consume('RIGHT_PAREN', 'Expected ) after for clause');
414
+ this.consume("RIGHT_PAREN", "Expected ) after for clause");
267
415
 
268
- this.consume('LEFT_BRACE', 'Expected { after for clause');
416
+ this.consume("LEFT_BRACE", "Expected { after for clause");
269
417
  const body = this.block();
270
- this.consume('RIGHT_BRACE', 'Expected } after block');
418
+ this.consume("RIGHT_BRACE", "Expected } after block");
271
419
 
272
420
  return {
273
- type: 'ForStatement',
421
+ type: "ForStatement",
274
422
  initializer,
275
423
  condition,
276
424
  increment,
@@ -285,12 +433,12 @@ class Parser {
285
433
  returnStatement() {
286
434
  const keyword = this.previous();
287
435
  let value = null;
288
- if (!this.check('RIGHT_BRACE')) {
436
+ if (!this.check("RIGHT_BRACE")) {
289
437
  value = this.expression();
290
438
  }
291
439
 
292
440
  return {
293
- type: 'ReturnStatement',
441
+ type: "ReturnStatement",
294
442
  keyword,
295
443
  value,
296
444
  };
@@ -303,7 +451,7 @@ class Parser {
303
451
  breakStatement() {
304
452
  const keyword = this.previous();
305
453
  return {
306
- type: 'BreakStatement',
454
+ type: "BreakStatement",
307
455
  keyword,
308
456
  };
309
457
  }
@@ -315,7 +463,7 @@ class Parser {
315
463
  continueStatement() {
316
464
  const keyword = this.previous();
317
465
  return {
318
- type: 'ContinueStatement',
466
+ type: "ContinueStatement",
319
467
  keyword,
320
468
  };
321
469
  }
@@ -327,7 +475,7 @@ class Parser {
327
475
  block() {
328
476
  const statements = [];
329
477
 
330
- while (!this.check('RIGHT_BRACE') && !this.isAtEnd()) {
478
+ while (!this.check("RIGHT_BRACE") && !this.isAtEnd()) {
331
479
  statements.push(this.declaration());
332
480
  }
333
481
 
@@ -341,7 +489,7 @@ class Parser {
341
489
  expressionStatement() {
342
490
  const expr = this.expression();
343
491
  return {
344
- type: 'ExpressionStatement',
492
+ type: "ExpressionStatement",
345
493
  expression: expr,
346
494
  };
347
495
  }
@@ -361,7 +509,7 @@ class Parser {
361
509
  parseExpression() {
362
510
  let expr = this.equality();
363
511
 
364
- while (this.match('LEFT_BRACKET')) {
512
+ while (this.match("LEFT_BRACKET")) {
365
513
  expr = this.finishArrayAccess(expr);
366
514
  }
367
515
 
@@ -373,68 +521,76 @@ class Parser {
373
521
  * @returns {Object} Parsed assignment
374
522
  */
375
523
  assignment() {
376
- let expr = this.logicalOr();
524
+ const expr = this.logicalOr();
377
525
 
378
- if (this.match('EQUAL')) {
526
+ if (this.match("EQUAL")) {
379
527
  const equals = this.previous();
380
528
  const value = this.logicalOr();
381
529
 
382
- if (expr.type === 'Variable') {
530
+ if (expr.type === "Variable") {
383
531
  const name = expr.name;
384
532
  return {
385
- type: 'Assign',
533
+ type: "Assign",
386
534
  name,
387
535
  value,
388
536
  };
389
537
  }
390
538
 
391
- if (expr.type === 'ArrayAccess') {
539
+ if (expr.type === "ArrayAccess") {
392
540
  return {
393
- type: 'ArrayAssign',
541
+ type: "ArrayAssign",
394
542
  array: expr.array,
395
543
  index: expr.index,
396
544
  value,
397
545
  };
398
546
  }
399
547
 
400
- if (expr.type === 'PropertyAccess') {
548
+ if (expr.type === "PropertyAccess") {
401
549
  return {
402
- type: 'PropertyAssign',
550
+ type: "PropertyAssign",
403
551
  object: expr.object,
404
552
  name: expr.name,
405
553
  value,
406
554
  };
407
555
  }
408
556
 
409
- throw new Error('Objetivo de asignación inválido');
557
+ if (expr.type === "ThisPropertyAccess") {
558
+ return {
559
+ type: "ThisPropertyAssign",
560
+ property: expr.property,
561
+ value,
562
+ };
563
+ }
564
+
565
+ throw new Error("Objetivo de asignación inválido");
410
566
  }
411
567
 
412
568
  // Handle compound assignment operators
413
569
  if (
414
570
  this.match(
415
- 'PLUS_EQUAL',
416
- 'MINUS_EQUAL',
417
- 'STAR_EQUAL',
418
- 'SLASH_EQUAL',
419
- 'PERCENT_EQUAL'
571
+ "PLUS_EQUAL",
572
+ "MINUS_EQUAL",
573
+ "STAR_EQUAL",
574
+ "SLASH_EQUAL",
575
+ "PERCENT_EQUAL",
420
576
  )
421
577
  ) {
422
578
  const operator = this.previous();
423
579
  const value = this.logicalOr();
424
580
 
425
- if (expr.type === 'Variable') {
581
+ if (expr.type === "Variable") {
426
582
  const name = expr.name;
427
583
  return {
428
- type: 'CompoundAssign',
584
+ type: "CompoundAssign",
429
585
  name,
430
586
  operator: operator.type,
431
587
  value,
432
588
  };
433
589
  }
434
590
 
435
- if (expr.type === 'ArrayAccess') {
591
+ if (expr.type === "ArrayAccess") {
436
592
  return {
437
- type: 'CompoundArrayAssign',
593
+ type: "CompoundArrayAssign",
438
594
  array: expr.array,
439
595
  index: expr.index,
440
596
  operator: operator.type,
@@ -442,9 +598,9 @@ class Parser {
442
598
  };
443
599
  }
444
600
 
445
- if (expr.type === 'PropertyAccess') {
601
+ if (expr.type === "PropertyAccess") {
446
602
  return {
447
- type: 'CompoundPropertyAssign',
603
+ type: "CompoundPropertyAssign",
448
604
  object: expr.object,
449
605
  name: expr.name,
450
606
  operator: operator.type,
@@ -452,7 +608,7 @@ class Parser {
452
608
  };
453
609
  }
454
610
 
455
- throw new Error('Objetivo de asignación compuesta inválido');
611
+ throw new Error("Objetivo de asignación compuesta inválido");
456
612
  }
457
613
 
458
614
  return expr;
@@ -465,11 +621,11 @@ class Parser {
465
621
  equality() {
466
622
  let expr = this.comparison();
467
623
 
468
- while (this.match('EQUAL_EQUAL', 'BANG_EQUAL')) {
624
+ while (this.match("EQUAL_EQUAL", "BANG_EQUAL")) {
469
625
  const operator = this.previous();
470
626
  const right = this.comparison();
471
627
  expr = {
472
- type: 'Binary',
628
+ type: "Binary",
473
629
  left: expr,
474
630
  operator: operator.type,
475
631
  right,
@@ -486,11 +642,11 @@ class Parser {
486
642
  logicalAnd() {
487
643
  let expr = this.equality();
488
644
 
489
- while (this.match('AND')) {
645
+ while (this.match("AND")) {
490
646
  const operator = this.previous();
491
647
  const right = this.equality();
492
648
  expr = {
493
- type: 'Logical',
649
+ type: "Logical",
494
650
  left: expr,
495
651
  operator: operator.type,
496
652
  right,
@@ -507,11 +663,11 @@ class Parser {
507
663
  logicalOr() {
508
664
  let expr = this.logicalAnd();
509
665
 
510
- while (this.match('OR')) {
666
+ while (this.match("OR")) {
511
667
  const operator = this.previous();
512
668
  const right = this.logicalAnd();
513
669
  expr = {
514
- type: 'Logical',
670
+ type: "Logical",
515
671
  left: expr,
516
672
  operator: operator.type,
517
673
  right,
@@ -528,11 +684,11 @@ class Parser {
528
684
  comparison() {
529
685
  let expr = this.term();
530
686
 
531
- while (this.match('GREATER', 'GREATER_EQUAL', 'LESS', 'LESS_EQUAL')) {
687
+ while (this.match("GREATER", "GREATER_EQUAL", "LESS", "LESS_EQUAL")) {
532
688
  const operator = this.previous();
533
689
  const right = this.term();
534
690
  expr = {
535
- type: 'Binary',
691
+ type: "Binary",
536
692
  left: expr,
537
693
  operator: operator.type,
538
694
  right,
@@ -549,11 +705,11 @@ class Parser {
549
705
  term() {
550
706
  let expr = this.factor();
551
707
 
552
- while (this.match('MINUS', 'PLUS')) {
708
+ while (this.match("MINUS", "PLUS")) {
553
709
  const operator = this.previous();
554
710
  const right = this.factor();
555
711
  expr = {
556
- type: 'Binary',
712
+ type: "Binary",
557
713
  left: expr,
558
714
  operator: operator.type,
559
715
  right,
@@ -570,11 +726,11 @@ class Parser {
570
726
  factor() {
571
727
  let expr = this.unary();
572
728
 
573
- while (this.match('SLASH', 'STAR', 'PERCENT')) {
729
+ while (this.match("SLASH", "STAR", "PERCENT")) {
574
730
  const operator = this.previous();
575
731
  const right = this.unary();
576
732
  expr = {
577
- type: 'Binary',
733
+ type: "Binary",
578
734
  left: expr,
579
735
  operator: operator.type,
580
736
  right,
@@ -589,11 +745,11 @@ class Parser {
589
745
  * @returns {Object} Unary expression
590
746
  */
591
747
  unary() {
592
- if (this.match('BANG', 'MINUS')) {
748
+ if (this.match("BANG", "MINUS")) {
593
749
  const operator = this.previous();
594
750
  const right = this.unary();
595
751
  return {
596
- type: 'Unary',
752
+ type: "Unary",
597
753
  operator: operator.type,
598
754
  right,
599
755
  };
@@ -609,10 +765,10 @@ class Parser {
609
765
  postfix() {
610
766
  let expr = this.call();
611
767
 
612
- while (this.match('PLUS_PLUS', 'MINUS_MINUS')) {
768
+ while (this.match("PLUS_PLUS", "MINUS_MINUS")) {
613
769
  const operator = this.previous();
614
770
  expr = {
615
- type: 'Postfix',
771
+ type: "Postfix",
616
772
  operator: operator.type,
617
773
  operand: expr,
618
774
  };
@@ -629,10 +785,44 @@ class Parser {
629
785
  let expr = this.primary();
630
786
 
631
787
  while (true) {
632
- if (this.match('LEFT_BRACKET')) {
788
+ if (this.match("LEFT_BRACKET")) {
633
789
  expr = this.finishArrayAccess(expr);
634
- } else if (this.match('DOT')) {
790
+ } else if (this.match("DOT")) {
635
791
  expr = this.finishPropertyAccess(expr);
792
+ } else if (this.match("LEFT_PAREN")) {
793
+ // Handle method/function calls on PropertyAccess or ThisPropertyAccess
794
+ if (expr.type === "PropertyAccess") {
795
+ const args = [];
796
+ if (!this.check("RIGHT_PAREN")) {
797
+ do {
798
+ args.push(this.expression());
799
+ } while (this.match("COMMA"));
800
+ }
801
+ this.consume("RIGHT_PAREN", "Expected ) after method arguments");
802
+ expr = {
803
+ type: "MethodCall",
804
+ object: expr.object,
805
+ method: expr.name,
806
+ arguments: args,
807
+ };
808
+ } else if (expr.type === "ThisPropertyAccess") {
809
+ const args = [];
810
+ if (!this.check("RIGHT_PAREN")) {
811
+ do {
812
+ args.push(this.expression());
813
+ } while (this.match("COMMA"));
814
+ }
815
+ this.consume("RIGHT_PAREN", "Expected ) after method arguments");
816
+ expr = {
817
+ type: "ThisMethodCall",
818
+ method: expr.property,
819
+ arguments: args,
820
+ };
821
+ } else {
822
+ // Put back the LEFT_PAREN for other handlers
823
+ this.current--;
824
+ break;
825
+ }
636
826
  } else {
637
827
  break;
638
828
  }
@@ -646,60 +836,173 @@ class Parser {
646
836
  * @returns {Object} Primary expression
647
837
  */
648
838
  primary() {
649
- if (this.match('FALSE')) return { type: 'Literal', value: false };
650
- if (this.match('TRUE')) return { type: 'Literal', value: true };
651
- if (this.match('NULL')) return { type: 'Literal', value: null };
652
- if (this.match('UNDEFINED')) return { type: 'Literal', value: undefined };
653
- if (this.match('NUMBER', 'STRING')) {
839
+ if (this.match("FALSE")) return { type: "Literal", value: false };
840
+ if (this.match("TRUE")) return { type: "Literal", value: true };
841
+ if (this.match("NULL")) return { type: "Literal", value: null };
842
+ if (this.match("UNDEFINED")) return { type: "Literal", value: undefined };
843
+ if (this.match("NUMBER", "STRING")) {
654
844
  return {
655
- type: 'Literal',
845
+ type: "Literal",
656
846
  value: this.previous().literal,
657
847
  };
658
848
  }
659
849
 
660
- if (this.match('IDENTIFIER')) {
850
+ if (this.match("TEMPLATE_STRING")) {
851
+ return this.templateStringExpression();
852
+ }
853
+
854
+ if (this.match("IDENTIFIER")) {
661
855
  const identifier = this.previous();
662
- if (this.check('LEFT_PAREN')) {
856
+ if (this.check("LEFT_PAREN")) {
663
857
  this.advance(); // Consume the LEFT_PAREN
664
858
  return this.finishCall(identifier);
665
859
  }
666
860
  return {
667
- type: 'Variable',
861
+ type: "Variable",
668
862
  name: identifier.lexeme,
669
863
  };
670
864
  }
671
865
 
672
- if (this.match('AND')) {
866
+ if (this.match("AND")) {
673
867
  const identifier = this.previous();
674
- if (this.check('LEFT_PAREN')) {
868
+ if (this.check("LEFT_PAREN")) {
675
869
  this.advance(); // Consume the LEFT_PAREN
676
870
  return this.finishCall(identifier);
677
871
  }
678
872
  return {
679
- type: 'Variable',
873
+ type: "Variable",
680
874
  name: identifier.lexeme,
681
875
  };
682
876
  }
683
877
 
684
- if (this.match('LEFT_PAREN')) {
878
+ if (this.match("LEFT_PAREN")) {
685
879
  const expr = this.expression();
686
- this.consume('RIGHT_PAREN', 'Expected ) after expression');
880
+ this.consume("RIGHT_PAREN", "Expected ) after expression");
687
881
  return expr;
688
882
  }
689
883
 
690
- if (this.match('LEFT_BRACKET')) {
884
+ if (this.match("LEFT_BRACKET")) {
691
885
  return this.arrayLiteral();
692
886
  }
693
887
 
694
- if (this.match('LEFT_BRACE')) {
888
+ if (this.match("LEFT_BRACE")) {
695
889
  return this.objectLiteral();
696
890
  }
697
891
 
698
- if (this.match('FUNCION')) {
892
+ if (this.match("FUNCION")) {
699
893
  return this.anonymousFunction();
700
894
  }
701
895
 
702
- throw new Error('Se esperaba una expresión');
896
+ if (this.match("NUEVO")) {
897
+ return this.newExpression();
898
+ }
899
+
900
+ if (this.match("ESTE")) {
901
+ return this.thisExpression();
902
+ }
903
+
904
+ if (this.match("SUPER")) {
905
+ return this.superExpression();
906
+ }
907
+
908
+ throw new Error("Se esperaba una expresión");
909
+ }
910
+
911
+ /**
912
+ * Parses a new expression for class instantiation
913
+ * @returns {Object} New expression
914
+ */
915
+ newExpression() {
916
+ const className = this.consume(
917
+ "IDENTIFIER",
918
+ "Se esperaba el nombre de la clase después de 'nuevo'",
919
+ );
920
+ this.consume("LEFT_PAREN", "Se esperaba ( después del nombre de la clase");
921
+
922
+ const args = [];
923
+ if (!this.check("RIGHT_PAREN")) {
924
+ do {
925
+ args.push(this.expression());
926
+ } while (this.match("COMMA"));
927
+ }
928
+
929
+ this.consume("RIGHT_PAREN", "Se esperaba ) después de los argumentos");
930
+
931
+ return {
932
+ type: "NewExpression",
933
+ className: className.lexeme,
934
+ arguments: args,
935
+ };
936
+ }
937
+
938
+ /**
939
+ * Parses 'este' (this) expression
940
+ * @returns {Object} This expression
941
+ */
942
+ thisExpression() {
943
+ // Check if accessing a property
944
+ if (this.match("DOT")) {
945
+ const property = this.consume(
946
+ "IDENTIFIER",
947
+ "Se esperaba el nombre de la propiedad después de 'este.'",
948
+ );
949
+ return {
950
+ type: "ThisPropertyAccess",
951
+ property: property.lexeme,
952
+ };
953
+ }
954
+ return {
955
+ type: "This",
956
+ };
957
+ }
958
+
959
+ /**
960
+ * Parses 'super' expression for parent class calls
961
+ * @returns {Object} Super expression
962
+ */
963
+ superExpression() {
964
+ this.consume("LEFT_PAREN", "Se esperaba ( después de 'super'");
965
+
966
+ const args = [];
967
+ if (!this.check("RIGHT_PAREN")) {
968
+ do {
969
+ args.push(this.expression());
970
+ } while (this.match("COMMA"));
971
+ }
972
+
973
+ this.consume(
974
+ "RIGHT_PAREN",
975
+ "Se esperaba ) después de los argumentos de super",
976
+ );
977
+
978
+ return {
979
+ type: "SuperCall",
980
+ arguments: args,
981
+ };
982
+ }
983
+
984
+ /**
985
+ * Parses a template string expression
986
+ * @returns {Object} Template string expression with parsed expressions
987
+ */
988
+ templateStringExpression() {
989
+ const token = this.previous();
990
+ const { parts, expressions } = token.literal;
991
+ const Tokenizer = require("./tokenizer.js");
992
+
993
+ // Parse each expression string into an AST
994
+ const parsedExpressions = expressions.map((exprSource) => {
995
+ const tokenizer = new Tokenizer();
996
+ const exprTokens = tokenizer.tokenize(exprSource);
997
+ const exprParser = new Parser(exprTokens);
998
+ return exprParser.expression();
999
+ });
1000
+
1001
+ return {
1002
+ type: "TemplateString",
1003
+ parts,
1004
+ expressions: parsedExpressions,
1005
+ };
703
1006
  }
704
1007
 
705
1008
  /**
@@ -707,33 +1010,33 @@ class Parser {
707
1010
  * @returns {Object} Anonymous function expression
708
1011
  */
709
1012
  anonymousFunction() {
710
- this.consume('LEFT_PAREN', 'Expected ( after funcion');
1013
+ this.consume("LEFT_PAREN", "Expected ( after funcion");
711
1014
 
712
1015
  const parameters = [];
713
- if (!this.check('RIGHT_PAREN')) {
1016
+ if (!this.check("RIGHT_PAREN")) {
714
1017
  do {
715
1018
  if (parameters.length >= 255) {
716
- throw new Error('No se pueden tener más de 255 parámetros');
1019
+ throw new Error("No se pueden tener más de 255 parámetros");
717
1020
  }
718
1021
  let param;
719
- if (this.match('IDENTIFIER')) {
1022
+ if (this.match("IDENTIFIER")) {
720
1023
  param = this.previous();
721
- } else if (this.match('AND')) {
1024
+ } else if (this.match("AND")) {
722
1025
  param = this.previous();
723
1026
  } else {
724
- throw new Error('Se esperaba un nombre de parámetro');
1027
+ throw new Error("Se esperaba un nombre de parámetro");
725
1028
  }
726
1029
  parameters.push(param.lexeme);
727
- } while (this.match('COMMA'));
1030
+ } while (this.match("COMMA"));
728
1031
  }
729
1032
 
730
- this.consume('RIGHT_PAREN', 'Expected ) after parameters');
731
- this.consume('LEFT_BRACE', 'Expected { before function body');
1033
+ this.consume("RIGHT_PAREN", "Expected ) after parameters");
1034
+ this.consume("LEFT_BRACE", "Expected { before function body");
732
1035
  const body = this.block();
733
- this.consume('RIGHT_BRACE', 'Expected } after function body');
1036
+ this.consume("RIGHT_BRACE", "Expected } after function body");
734
1037
 
735
1038
  return {
736
- type: 'AnonymousFunction',
1039
+ type: "AnonymousFunction",
737
1040
  parameters,
738
1041
  body,
739
1042
  };
@@ -746,10 +1049,10 @@ class Parser {
746
1049
  */
747
1050
  finishArrayAccess(array) {
748
1051
  const index = this.expression();
749
- this.consume('RIGHT_BRACKET', 'Expected ] after array index');
1052
+ this.consume("RIGHT_BRACKET", "Expected ] after array index");
750
1053
 
751
1054
  return {
752
- type: 'ArrayAccess',
1055
+ type: "ArrayAccess",
753
1056
  array,
754
1057
  index,
755
1058
  };
@@ -761,63 +1064,101 @@ class Parser {
761
1064
  * @returns {Object} Property access expression
762
1065
  */
763
1066
  finishPropertyAccess(object) {
764
- this.consume('IDENTIFIER', 'Expected property name after .');
1067
+ this.consume("IDENTIFIER", "Expected property name after .");
765
1068
  const name = this.previous();
766
1069
 
767
- // Check if this is a method call (array or string)
1070
+ // Check if this is a method call (array, string, or number)
768
1071
  if (
769
- name.lexeme === 'longitud' ||
770
- name.lexeme === 'primero' ||
771
- name.lexeme === 'ultimo' ||
772
- name.lexeme === 'agregar' ||
773
- name.lexeme === 'remover' ||
774
- name.lexeme === 'contiene' ||
775
- name.lexeme === 'recorrer' ||
776
- name.lexeme === 'mayusculas' ||
777
- name.lexeme === 'minusculas'
1072
+ name.lexeme === "longitud" ||
1073
+ name.lexeme === "primero" ||
1074
+ name.lexeme === "ultimo" ||
1075
+ name.lexeme === "agregar" ||
1076
+ name.lexeme === "remover" ||
1077
+ name.lexeme === "contiene" ||
1078
+ name.lexeme === "recorrer" ||
1079
+ name.lexeme === "mayusculas" ||
1080
+ name.lexeme === "minusculas" ||
1081
+ name.lexeme === "dividir" ||
1082
+ name.lexeme === "reemplazar" ||
1083
+ name.lexeme === "recortar" ||
1084
+ name.lexeme === "incluye" ||
1085
+ name.lexeme === "empiezaCon" ||
1086
+ name.lexeme === "terminaCon" ||
1087
+ name.lexeme === "caracter" ||
1088
+ name.lexeme === "subcadena" ||
1089
+ name.lexeme === "invertir" ||
1090
+ name.lexeme === "filtrar" ||
1091
+ name.lexeme === "mapear" ||
1092
+ name.lexeme === "reducir" ||
1093
+ name.lexeme === "ordenar" ||
1094
+ name.lexeme === "buscar" ||
1095
+ name.lexeme === "algunos" ||
1096
+ name.lexeme === "todos" ||
1097
+ name.lexeme === "unir" ||
1098
+ name.lexeme === "cortar" ||
1099
+ name.lexeme === "insertar" ||
1100
+ name.lexeme === "esPar" ||
1101
+ name.lexeme === "esImpar" ||
1102
+ name.lexeme === "esPositivo" ||
1103
+ name.lexeme === "esNegativo" ||
1104
+ name.lexeme === "aTexto"
778
1105
  ) {
779
1106
  // Check if there are parentheses (method call syntax)
780
- if (this.match('LEFT_PAREN')) {
1107
+ if (this.match("LEFT_PAREN")) {
781
1108
  // Consume the opening parenthesis
782
1109
  // Check if there are arguments
783
- if (!this.check('RIGHT_PAREN')) {
784
- // Handle methods that accept arguments (like agregar, contiene, recorrer)
1110
+ if (!this.check("RIGHT_PAREN")) {
1111
+ // Handle methods that accept arguments
785
1112
  if (
786
- name.lexeme === 'agregar' ||
787
- name.lexeme === 'contiene' ||
788
- name.lexeme === 'recorrer'
1113
+ name.lexeme === "agregar" ||
1114
+ name.lexeme === "contiene" ||
1115
+ name.lexeme === "recorrer" ||
1116
+ name.lexeme === "dividir" ||
1117
+ name.lexeme === "reemplazar" ||
1118
+ name.lexeme === "incluye" ||
1119
+ name.lexeme === "empiezaCon" ||
1120
+ name.lexeme === "terminaCon" ||
1121
+ name.lexeme === "caracter" ||
1122
+ name.lexeme === "subcadena" ||
1123
+ name.lexeme === "filtrar" ||
1124
+ name.lexeme === "mapear" ||
1125
+ name.lexeme === "reducir" ||
1126
+ name.lexeme === "buscar" ||
1127
+ name.lexeme === "algunos" ||
1128
+ name.lexeme === "todos" ||
1129
+ name.lexeme === "unir" ||
1130
+ name.lexeme === "cortar" ||
1131
+ name.lexeme === "insertar"
789
1132
  ) {
790
1133
  const args = [];
791
1134
  do {
792
1135
  args.push(this.expression());
793
- } while (this.match('COMMA'));
794
- this.consume('RIGHT_PAREN', 'Expected ) after method call');
1136
+ } while (this.match("COMMA"));
1137
+ this.consume("RIGHT_PAREN", "Expected ) after method call");
795
1138
 
796
1139
  return {
797
- type: 'MethodCall',
1140
+ type: "MethodCall",
798
1141
  object,
799
1142
  method: name.lexeme,
800
1143
  arguments: args,
801
1144
  };
802
1145
  } else {
803
- throw new Error(
804
- `El método ${name.lexeme}() no acepta argumentos`
805
- );
1146
+ throw new Error(`El método ${name.lexeme}() no acepta argumentos`);
806
1147
  }
807
1148
  }
808
1149
  // Consume the closing parenthesis
809
- this.consume('RIGHT_PAREN', 'Expected ) after method call');
1150
+ this.consume("RIGHT_PAREN", "Expected ) after method call");
810
1151
  }
811
1152
 
812
1153
  return {
813
- type: 'MethodCall',
1154
+ type: "MethodCall",
814
1155
  object,
815
1156
  method: name.lexeme,
816
1157
  };
817
1158
  }
818
1159
 
819
1160
  return {
820
- type: 'PropertyAccess',
1161
+ type: "PropertyAccess",
821
1162
  object,
822
1163
  name: name.lexeme,
823
1164
  };
@@ -831,21 +1172,21 @@ class Parser {
831
1172
  finishCall(callee) {
832
1173
  const args = [];
833
1174
 
834
- if (!this.check('RIGHT_PAREN')) {
1175
+ if (!this.check("RIGHT_PAREN")) {
835
1176
  do {
836
1177
  if (args.length >= 255) {
837
- throw new Error('Cannot have more than 255 arguments');
1178
+ throw new Error("Cannot have more than 255 arguments");
838
1179
  }
839
1180
  args.push(this.expression());
840
- } while (this.match('COMMA'));
1181
+ } while (this.match("COMMA"));
841
1182
  }
842
1183
 
843
- const paren = this.consume('RIGHT_PAREN', 'Expected ) after arguments');
1184
+ const paren = this.consume("RIGHT_PAREN", "Expected ) after arguments");
844
1185
 
845
1186
  return {
846
- type: 'Call',
1187
+ type: "Call",
847
1188
  callee: {
848
- type: 'Variable',
1189
+ type: "Variable",
849
1190
  name: callee.lexeme,
850
1191
  },
851
1192
  arguments: args,
@@ -859,16 +1200,16 @@ class Parser {
859
1200
  arrayLiteral() {
860
1201
  const elements = [];
861
1202
 
862
- if (!this.check('RIGHT_BRACKET')) {
1203
+ if (!this.check("RIGHT_BRACKET")) {
863
1204
  do {
864
1205
  elements.push(this.expression());
865
- } while (this.match('COMMA'));
1206
+ } while (this.match("COMMA"));
866
1207
  }
867
1208
 
868
- this.consume('RIGHT_BRACKET', 'Expected ] after array elements');
1209
+ this.consume("RIGHT_BRACKET", "Expected ] after array elements");
869
1210
 
870
1211
  return {
871
- type: 'ArrayLiteral',
1212
+ type: "ArrayLiteral",
872
1213
  elements,
873
1214
  };
874
1215
  }
@@ -880,33 +1221,33 @@ class Parser {
880
1221
  objectLiteral() {
881
1222
  const properties = [];
882
1223
 
883
- if (!this.check('RIGHT_BRACE')) {
1224
+ if (!this.check("RIGHT_BRACE")) {
884
1225
  do {
885
1226
  // Parse property name (identifier or string)
886
1227
  let name;
887
- if (this.match('IDENTIFIER')) {
1228
+ if (this.match("IDENTIFIER")) {
888
1229
  name = this.previous().lexeme;
889
- } else if (this.match('STRING')) {
1230
+ } else if (this.match("STRING")) {
890
1231
  name = this.previous().literal;
891
1232
  } else {
892
- throw new Error('Se esperaba un nombre de propiedad');
1233
+ throw new Error("Se esperaba un nombre de propiedad");
893
1234
  }
894
1235
 
895
- this.consume('COLON', 'Expected : after property name');
1236
+ this.consume("COLON", "Expected : after property name");
896
1237
  const value = this.expression();
897
1238
 
898
1239
  properties.push({
899
- type: 'Property',
1240
+ type: "Property",
900
1241
  name,
901
1242
  value,
902
1243
  });
903
- } while (this.match('COMMA'));
1244
+ } while (this.match("COMMA"));
904
1245
  }
905
1246
 
906
- this.consume('RIGHT_BRACE', 'Expected } after object properties');
1247
+ this.consume("RIGHT_BRACE", "Expected } after object properties");
907
1248
 
908
1249
  return {
909
- type: 'ObjectLiteral',
1250
+ type: "ObjectLiteral",
910
1251
  properties,
911
1252
  };
912
1253
  }
@@ -950,7 +1291,7 @@ class Parser {
950
1291
  * @returns {boolean} True if we reached the end
951
1292
  */
952
1293
  isAtEnd() {
953
- return this.peek().type === 'EOF';
1294
+ return this.peek().type === "EOF";
954
1295
  }
955
1296
 
956
1297
  /**
@@ -988,21 +1329,23 @@ class Parser {
988
1329
  this.advance();
989
1330
 
990
1331
  while (!this.isAtEnd()) {
991
- if (this.previous().type === 'EOF') return;
1332
+ if (this.previous().type === "EOF") return;
992
1333
 
993
1334
  switch (this.peek().type) {
994
- case 'VARIABLE':
995
- case 'FUNCION':
996
- case 'MOSTRAR':
997
- case 'LEER':
998
- case 'SI':
999
- case 'MIENTRAS':
1000
- case 'PARA':
1001
- case 'RETORNAR':
1002
- case 'ROMPER':
1003
- case 'CONTINUAR':
1004
- case 'INTENTAR':
1005
- case 'CAPTURAR':
1335
+ case "VARIABLE":
1336
+ case "CONSTANTE":
1337
+ case "FUNCION":
1338
+ case "CLASE":
1339
+ case "MOSTRAR":
1340
+ case "LEER":
1341
+ case "SI":
1342
+ case "MIENTRAS":
1343
+ case "PARA":
1344
+ case "RETORNAR":
1345
+ case "ROMPER":
1346
+ case "CONTINUAR":
1347
+ case "INTENTAR":
1348
+ case "CAPTURAR":
1006
1349
  return;
1007
1350
  }
1008
1351
 
@@ -1016,34 +1359,136 @@ class Parser {
1016
1359
  */
1017
1360
  tryStatement() {
1018
1361
  // Parse the try block
1019
- this.consume('LEFT_BRACE', 'Expected { after intentar');
1362
+ this.consume("LEFT_BRACE", "Expected { after intentar");
1020
1363
  const tryBlock = this.block();
1021
- this.consume('RIGHT_BRACE', 'Expected } after intentar block');
1364
+ this.consume("RIGHT_BRACE", "Expected } after intentar block");
1022
1365
 
1023
1366
  // Look for catch block
1024
- if (this.match('CAPTURAR')) {
1367
+ if (this.match("CAPTURAR")) {
1025
1368
  // Parse catch parameter (error variable name)
1026
- this.consume('LEFT_PAREN', 'Expected ( after capturar');
1369
+ this.consume("LEFT_PAREN", "Expected ( after capturar");
1027
1370
  const errorVariable = this.consume(
1028
- 'IDENTIFIER',
1029
- 'Expected error variable name'
1371
+ "IDENTIFIER",
1372
+ "Expected error variable name",
1030
1373
  );
1031
- this.consume('RIGHT_PAREN', 'Expected ) after error variable');
1374
+ this.consume("RIGHT_PAREN", "Expected ) after error variable");
1032
1375
 
1033
1376
  // Parse catch block
1034
- this.consume('LEFT_BRACE', 'Expected { after capturar');
1377
+ this.consume("LEFT_BRACE", "Expected { after capturar");
1035
1378
  const catchBlock = this.block();
1036
- this.consume('RIGHT_BRACE', 'Expected } after capturar block');
1379
+ this.consume("RIGHT_BRACE", "Expected } after capturar block");
1037
1380
 
1038
1381
  return {
1039
- type: 'TryCatch',
1382
+ type: "TryCatch",
1040
1383
  tryBlock,
1041
1384
  catchBlock,
1042
1385
  errorVariable: errorVariable.lexeme,
1043
1386
  };
1044
1387
  } else {
1045
- throw new Error('Se esperaba capturar después del bloque intentar');
1388
+ throw new Error("Se esperaba capturar después del bloque intentar");
1389
+ }
1390
+ }
1391
+
1392
+ /**
1393
+ * Parses an elegir (switch) statement
1394
+ * @returns {Object} Elegir statement
1395
+ */
1396
+ elegirStatement() {
1397
+ const discriminant = this.expression();
1398
+ this.consume("LEFT_BRACE", "Expected { after elegir expression");
1399
+
1400
+ const cases = [];
1401
+ let defaultCase = null;
1402
+
1403
+ while (!this.check("RIGHT_BRACE") && !this.isAtEnd()) {
1404
+ if (this.match("CASO")) {
1405
+ const testValue = this.expression();
1406
+ this.consume("COLON", "Expected : after caso value");
1407
+
1408
+ let consequent;
1409
+ if (this.check("LEFT_BRACE")) {
1410
+ this.advance();
1411
+ consequent = this.block();
1412
+ this.consume("RIGHT_BRACE", "Expected } after caso block");
1413
+ } else {
1414
+ consequent = [this.declaration()];
1415
+ }
1416
+
1417
+ cases.push({
1418
+ test: testValue,
1419
+ consequent,
1420
+ });
1421
+ } else if (this.match("PORDEFECTO")) {
1422
+ this.consume("COLON", "Expected : after pordefecto");
1423
+
1424
+ let consequent;
1425
+ if (this.check("LEFT_BRACE")) {
1426
+ this.advance();
1427
+ consequent = this.block();
1428
+ this.consume("RIGHT_BRACE", "Expected } after pordefecto block");
1429
+ } else {
1430
+ consequent = [this.declaration()];
1431
+ }
1432
+
1433
+ defaultCase = {
1434
+ consequent,
1435
+ };
1436
+ } else {
1437
+ throw new Error("Se esperaba caso o pordefecto dentro de elegir");
1438
+ }
1046
1439
  }
1440
+
1441
+ this.consume("RIGHT_BRACE", "Expected } after elegir block");
1442
+
1443
+ return {
1444
+ type: "ElegirStatement",
1445
+ discriminant,
1446
+ cases,
1447
+ defaultCase,
1448
+ };
1449
+ }
1450
+
1451
+ /**
1452
+ * Parses a hacer/mientras (do-while) statement
1453
+ * @returns {Object} HacerMientras statement
1454
+ */
1455
+ hacerMientrasStatement() {
1456
+ this.consume("LEFT_BRACE", "Expected { after hacer");
1457
+ const body = this.block();
1458
+ this.consume("RIGHT_BRACE", "Expected } after hacer block");
1459
+
1460
+ this.consume("MIENTRAS", "Expected mientras after hacer block");
1461
+ const condition = this.expression();
1462
+
1463
+ return {
1464
+ type: "HacerMientrasStatement",
1465
+ body,
1466
+ condition,
1467
+ };
1468
+ }
1469
+
1470
+ /**
1471
+ * Parses a para cada (for-each) statement
1472
+ * @returns {Object} ForEach statement
1473
+ */
1474
+ forEachStatement() {
1475
+ const iteratorName = this.consume(
1476
+ "IDENTIFIER",
1477
+ "Expected iterator variable name after cada",
1478
+ );
1479
+ this.consume("EN", "Expected en after iterator variable");
1480
+ const iterable = this.expression();
1481
+
1482
+ this.consume("LEFT_BRACE", "Expected { after iterable");
1483
+ const body = this.block();
1484
+ this.consume("RIGHT_BRACE", "Expected } after para cada block");
1485
+
1486
+ return {
1487
+ type: "ForEachStatement",
1488
+ iterator: iteratorName.lexeme,
1489
+ iterable,
1490
+ body,
1491
+ };
1047
1492
  }
1048
1493
  }
1049
1494