xanascript 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/src/parser.js ADDED
@@ -0,0 +1,819 @@
1
+ import * as A from "./ast.js";
2
+ import { XSError, expected, undefinedVar, invalidSyntax } from "./errors.js";
3
+
4
+ const PRECEDENCE = {
5
+ "?": 0,
6
+ "||": 1,
7
+ "&&": 2,
8
+ "==": 3,
9
+ "!=": 3,
10
+ "~=": 3,
11
+ "<": 4,
12
+ "<=": 4,
13
+ ">": 4,
14
+ ">=": 4,
15
+ "+": 5,
16
+ "-": 5,
17
+ "*": 6,
18
+ "/": 6,
19
+ "%": 6
20
+ };
21
+
22
+ export function parse(tokens) {
23
+ let i = 0;
24
+ const peek = () => tokens[i];
25
+ const next = () => tokens[i++];
26
+ const expect = (t) => {
27
+ const tok = next();
28
+ if (tok.type !== t) {
29
+ const err = expected(tok.type, t, tok.loc);
30
+ err.message = `Esperado \`${t}\`, encontrado \`${tok.type}\``;
31
+ if (tok.value) err.message += ` (\`${tok.value}\`)`;
32
+ throw err;
33
+ }
34
+ A.setLoc(tok.loc);
35
+ return tok;
36
+ };
37
+ const matchSeq = (...types) => {
38
+ for (let k = 0; k < types.length; k++) {
39
+ if (tokens[i + k]?.type !== types[k]) return false;
40
+ }
41
+ return true;
42
+ };
43
+
44
+ function matchPhrase(name, parts) {
45
+ if (!matchSeq(...parts)) return null;
46
+ const tok = tokens[i];
47
+ parts.forEach(() => next());
48
+ A.setLoc(tok.loc);
49
+ return A.Ident(name);
50
+ }
51
+
52
+ function parseProgram() {
53
+ const body = [];
54
+ if (peek().type === "PARTIU") {
55
+ expect("PARTIU"); expect("("); expect(")");
56
+ A.setLoc(peek().loc);
57
+ while (peek().type !== "ACABOU") {
58
+ body.push(parseStmt());
59
+ }
60
+ expect("ACABOU"); expect("("); expect(")");
61
+ } else {
62
+ A.setLoc(peek().loc);
63
+ while (peek().type !== "EOF") {
64
+ body.push(parseStmt());
65
+ }
66
+ }
67
+ expect("EOF");
68
+ return A.Program(body);
69
+ }
70
+
71
+ function parseFunction() {
72
+ expect("CHAMA"); expect("ESSE"); expect("CARA");
73
+ const nameTok = expect("IDENT");
74
+ const name = nameTok.value;
75
+ A.setLoc(nameTok.loc);
76
+ expect("(");
77
+ const params = [];
78
+ if (peek().type !== ")") {
79
+ do {
80
+ const p = expect("IDENT");
81
+ params.push(p.value);
82
+ if (peek().type !== ",") break;
83
+ next();
84
+ } while (true);
85
+ }
86
+ expect(")");
87
+ const body = parseBlock();
88
+ return A.FunctionDecl(name, params, body);
89
+ }
90
+
91
+ function parseReturn() {
92
+ expect("VOLTA");
93
+ A.setLoc(peek().loc);
94
+ let arg = null;
95
+ if (peek().type !== "}" && peek().type !== "EOF" && peek().type !== ")") arg = parseExpr();
96
+ optionalSemicolon();
97
+ return A.ReturnStmt(arg);
98
+ }
99
+
100
+ function parseExport() {
101
+ expect("EXPORTA");
102
+ const nameTok = expect("IDENT");
103
+ A.setLoc(nameTok.loc);
104
+ optionalSemicolon();
105
+ return A.ExportStmt(nameTok.value);
106
+ }
107
+
108
+ function parseStmt() {
109
+ A.setLoc(peek().loc);
110
+
111
+ if (peek().type === "EXPORTA") return parseExport();
112
+ if (matchSeq("CHAMA", "ESSE", "CARA")) return parseFunction();
113
+ if (peek().type === "VOLTA") return parseReturn();
114
+ if (peek().type === "CRIA") return parseVarDecl();
115
+ if (matchSeq("SE", "LIGA", "SO")) return parseIf();
116
+ if (matchSeq("REPETE", "NA", "MORAL")) return parseFor();
117
+ if (matchSeq("REPETE", "AI")) return parseWhile();
118
+ if (peek().type === "TENTA") return parseTryCatch();
119
+ if (peek().type === "VOA") { next(); expect("("); expect(")"); optionalSemicolon(); return A.BreakStmt(); }
120
+ if (peek().type === "CONTINUA") { next(); expect("("); expect(")"); optionalSemicolon(); return A.ContinueStmt(); }
121
+ if (peek().type === "IMPORTA") return parseImport();
122
+ if (peek().type === "CLASSE") return parseClass();
123
+ if (peek().type === "ESCOLHE") return parseSwitch();
124
+ if (peek().type === "COMBINA") return parseMatch();
125
+ if (peek().type === "TESTE") return parseTest();
126
+ if (peek().type === "TAREFA") return parseTask();
127
+ if (peek().type === "AFIRMA") return parseAssert();
128
+ if (peek().type === "ASSUNTO") return parseAssertEqual();
129
+ if (peek().type === "TABELA") return parseTable();
130
+ if (peek().type === "MACRO") return parseMacro();
131
+
132
+ const expr = parseExpr();
133
+ optionalSemicolon();
134
+ return expr;
135
+ }
136
+
137
+ function parseTest() {
138
+ expect("TESTE");
139
+ const nameTok = expect("STRING");
140
+ A.setLoc(nameTok.loc);
141
+ const body = parseBlock();
142
+ return A.TestStmt(nameTok.value, body);
143
+ }
144
+
145
+ function parseAssert() {
146
+ expect("AFIRMA");
147
+ expect("(");
148
+ A.setLoc(peek().loc);
149
+ const test = parseExpr();
150
+ expect(")");
151
+ optionalSemicolon();
152
+ return A.AssertStmt(test, null);
153
+ }
154
+
155
+ function parseAssertEqual() {
156
+ expect("ASSUNTO");
157
+ expect("(");
158
+ A.setLoc(peek().loc);
159
+ const a = parseExpr();
160
+ expect(",");
161
+ const b = parseExpr();
162
+ expect(")");
163
+ optionalSemicolon();
164
+ return A.Call(A.Ident("ASSUNTO"), [a, b]);
165
+ }
166
+
167
+ function parseTask() {
168
+ expect("TAREFA");
169
+ const nameTok = expect("IDENT");
170
+ A.setLoc(nameTok.loc);
171
+ const body = parseBlock();
172
+ return A.TaskDecl(nameTok.value, body);
173
+ }
174
+
175
+ function parseTable() {
176
+ expect("TABELA");
177
+ const nameTok = expect("IDENT");
178
+ A.setLoc(nameTok.loc);
179
+ expect("{");
180
+ const props = [];
181
+ while (peek().type !== "}") {
182
+ const propName = expect("IDENT").value;
183
+ expect(":");
184
+ const typeTok = next();
185
+ const val = typeTok.value || typeTok.type;
186
+ props.push(A.TableProp(propName, val));
187
+ if (peek().type === ",") next();
188
+ }
189
+ expect("}");
190
+ return A.TableDecl(nameTok.value, props);
191
+ }
192
+
193
+ function parseMacro() {
194
+ expect("MACRO");
195
+ const nameTok = expect("IDENT");
196
+ A.setLoc(nameTok.loc);
197
+ expect("(");
198
+ const params = [];
199
+ if (peek().type !== ")") {
200
+ do {
201
+ params.push(expect("IDENT").value);
202
+ if (peek().type !== ",") break;
203
+ next();
204
+ } while (true);
205
+ }
206
+ expect(")");
207
+ const body = parseBlock();
208
+ return A.MacroDecl(nameTok.value, params, body);
209
+ }
210
+
211
+ function parseBlock() {
212
+ expect("{");
213
+ A.setLoc(peek().loc);
214
+ const body = [];
215
+ while (peek().type !== "}") body.push(parseStmt());
216
+ expect("}");
217
+ return A.Block(body);
218
+ }
219
+
220
+ function parseVarDecl(expectSemi = true) {
221
+ expect("CRIA");
222
+ const idTok = expect("IDENT");
223
+ A.setLoc(idTok.loc);
224
+ const id = idTok.value;
225
+ let type = null;
226
+ if (peek().type === ":") {
227
+ next();
228
+ type = expect("IDENT").value;
229
+ }
230
+ expect("=");
231
+ const init = parseExpr();
232
+
233
+ if (expectSemi) optionalSemicolon();
234
+
235
+ return { ...A.VarDecl(id, init), typeHint: type };
236
+ }
237
+
238
+ function parseIf() {
239
+ expect("SE"); expect("LIGA"); expect("SO");
240
+ expect("(");
241
+ A.setLoc(peek().loc);
242
+ const test = parseExpr();
243
+ expect(")");
244
+ const cons = parseBlock();
245
+ let alt = null;
246
+ if (peek().type === "SENAO") {
247
+ next();
248
+ if (matchSeq("SE", "LIGA", "SO")) {
249
+ alt = parseIf();
250
+ } else {
251
+ alt = parseBlock();
252
+ }
253
+ }
254
+ return A.IfStmt(test, cons, alt);
255
+ }
256
+
257
+ function parseFor() {
258
+ expect("REPETE"); expect("NA"); expect("MORAL");
259
+ expect("(");
260
+ A.setLoc(peek().loc);
261
+
262
+ let init = null;
263
+
264
+ if (peek().type !== ";") {
265
+ if (peek().type === "CRIA") {
266
+ init = parseVarDecl(false);
267
+ } else {
268
+ init = parseExpr();
269
+ }
270
+ }
271
+
272
+ expect(";");
273
+
274
+ const test = parseExpr();
275
+ expect(";");
276
+
277
+ const update = parseExpr();
278
+ expect(")");
279
+
280
+ const body = parseBlock();
281
+
282
+ return A.ForStmt(init, test, update, body);
283
+ }
284
+
285
+ function parseWhile() {
286
+ expect("REPETE"); expect("AI");
287
+ expect("(");
288
+ A.setLoc(peek().loc);
289
+ const test = parseExpr();
290
+ expect(")");
291
+ const body = parseBlock();
292
+ return A.WhileStmt(test, body);
293
+ }
294
+
295
+ function parseImport() {
296
+ expect("IMPORTA");
297
+ A.setLoc(peek().loc);
298
+
299
+ let target;
300
+
301
+ if (peek().type === "STRING") {
302
+ target = next().value;
303
+ } else {
304
+ target = expect("IDENT").value;
305
+ }
306
+
307
+ let alias = null;
308
+ if (peek().type === "IDENT" && peek().value?.toLowerCase() === "as") {
309
+ next();
310
+ alias = expect("IDENT").value;
311
+ }
312
+
313
+ optionalSemicolon();
314
+ return A.ImportStmt(target, alias);
315
+ }
316
+
317
+ function parseClass() {
318
+ expect("CLASSE");
319
+ const nameTok = expect("IDENT");
320
+ A.setLoc(nameTok.loc);
321
+ const name = nameTok.value;
322
+ let superClass = null;
323
+ if (peek().type === "HERDA") {
324
+ next();
325
+ superClass = expect("IDENT").value;
326
+ }
327
+ expect("{");
328
+ const methods = [];
329
+ while (peek().type !== "}") {
330
+ if (peek().type === "CONSTRUTOR") {
331
+ next();
332
+ A.setLoc(peek().loc);
333
+ expect("(");
334
+ const params = [];
335
+ if (peek().type !== ")") {
336
+ do {
337
+ params.push(expect("IDENT").value);
338
+ if (peek().type !== ",") break;
339
+ next();
340
+ } while (true);
341
+ }
342
+ expect(")");
343
+ const body = parseBlock();
344
+ methods.push(A.Method(null, params, body, true));
345
+ } else if (peek().type === "METODO") {
346
+ next();
347
+ const nameTok = expect("IDENT");
348
+ A.setLoc(nameTok.loc);
349
+ expect("(");
350
+ const params = [];
351
+ if (peek().type !== ")") {
352
+ do {
353
+ params.push(expect("IDENT").value);
354
+ if (peek().type !== ",") break;
355
+ next();
356
+ } while (true);
357
+ }
358
+ expect(")");
359
+ const body = parseBlock();
360
+ methods.push(A.Method(nameTok.value, params, body, false));
361
+ } else if (peek().type === "IDENT") {
362
+ const nameTok = expect("IDENT");
363
+ A.setLoc(nameTok.loc);
364
+ expect("(");
365
+ const params = [];
366
+ if (peek().type !== ")") {
367
+ do {
368
+ params.push(expect("IDENT").value);
369
+ if (peek().type !== ",") break;
370
+ next();
371
+ } while (true);
372
+ }
373
+ expect(")");
374
+ const body = parseBlock();
375
+ methods.push(A.Method(nameTok.value, params, body, false));
376
+ } else {
377
+ const err = invalidSyntax("Esperado método ou CONSTRUTOR na classe", peek().loc);
378
+ throw err;
379
+ }
380
+ }
381
+ expect("}");
382
+ return A.ClassDecl(name, superClass, methods);
383
+ }
384
+
385
+ function parseSwitch() {
386
+ expect("ESCOLHE");
387
+ expect("(");
388
+ A.setLoc(peek().loc);
389
+ const test = parseExpr();
390
+ expect(")");
391
+ expect("{");
392
+ const cases = [];
393
+ while (peek().type !== "}") {
394
+ if (peek().type === "CASO") {
395
+ next();
396
+ A.setLoc(peek().loc);
397
+ const value = parseExpr();
398
+ expect(":");
399
+ const body = parseStmt();
400
+ cases.push(A.SwitchCase(value, body));
401
+ } else if (peek().type === "PADRAO") {
402
+ next();
403
+ expect(":");
404
+ A.setLoc(peek().loc);
405
+ const body = parseStmt();
406
+ cases.push(A.SwitchCase(null, body));
407
+ } else {
408
+ const err = invalidSyntax("Esperado CASO ou PADRAO no ESCOLHE", peek().loc);
409
+ throw err;
410
+ }
411
+ }
412
+ expect("}");
413
+ return A.SwitchStmt(test, cases);
414
+ }
415
+
416
+ function parseMatch() {
417
+ expect("COMBINA");
418
+ expect("(");
419
+ A.setLoc(peek().loc);
420
+ const test = parseExpr();
421
+ expect(")");
422
+ expect("{");
423
+ const cases = [];
424
+ while (peek().type !== "}") {
425
+ if (peek().type === "CASO") {
426
+ next();
427
+ A.setLoc(peek().loc);
428
+ const pattern = parsePattern();
429
+ let guard = null;
430
+ if (peek().type === "=>") {
431
+ next();
432
+ const body = parseExpr();
433
+ cases.push(A.MatchCase(pattern, body, guard));
434
+ } else if (peek().type === "->") {
435
+ next();
436
+ const body = parseExpr();
437
+ cases.push(A.MatchCase(pattern, body, guard));
438
+ } else {
439
+ expect(":");
440
+ const body = parseStmt();
441
+ cases.push(A.MatchCase(pattern, body, guard));
442
+ }
443
+ if (peek().type === ",") next();
444
+ } else if (peek().type === "PADRAO") {
445
+ next();
446
+ A.setLoc(peek().loc);
447
+ if (peek().type === "=>") {
448
+ next();
449
+ const body = parseExpr();
450
+ cases.push(A.MatchCase(null, body, null));
451
+ } else if (peek().type === "->") {
452
+ next();
453
+ const body = parseExpr();
454
+ cases.push(A.MatchCase(null, body, null));
455
+ } else {
456
+ expect(":");
457
+ const body = parseStmt();
458
+ cases.push(A.MatchCase(null, body, null));
459
+ }
460
+ } else {
461
+ const err = invalidSyntax("Esperado CASO ou PADRAO no COMBINA", peek().loc);
462
+ throw err;
463
+ }
464
+ }
465
+ expect("}");
466
+ return A.MatchExpr(test, cases);
467
+ }
468
+
469
+ function parsePattern() {
470
+ A.setLoc(peek().loc);
471
+ const t = peek();
472
+
473
+ if (t.type === "NUMBER") {
474
+ next();
475
+ return A.PatternLiteral(t.value);
476
+ }
477
+ if (t.type === "STRING") {
478
+ next();
479
+ return A.PatternLiteral(t.value);
480
+ }
481
+ if (t.type === "VERDADEIRO") {
482
+ next();
483
+ return A.PatternLiteral(true);
484
+ }
485
+ if (t.type === "FALSO") {
486
+ next();
487
+ return A.PatternLiteral(false);
488
+ }
489
+ if (t.type === "NULO") {
490
+ next();
491
+ return A.PatternLiteral(null);
492
+ }
493
+
494
+ if (t.type === "[") {
495
+ next();
496
+ const elements = [];
497
+ while (peek().type !== "]") {
498
+ if (peek().type === "...") {
499
+ next();
500
+ elements.push(A.PatternRest());
501
+ break;
502
+ }
503
+ elements.push(parsePattern());
504
+ if (peek().type !== ",") break;
505
+ next();
506
+ }
507
+ expect("]");
508
+ return A.PatternArray(elements);
509
+ }
510
+
511
+ if (t.type === "{") {
512
+ next();
513
+ const props = [];
514
+ while (peek().type !== "}") {
515
+ const keyTok = expect("IDENT");
516
+ A.setLoc(keyTok.loc);
517
+ if (peek().type === ":") {
518
+ next();
519
+ props.push({ key: keyTok.value, pattern: parsePattern() });
520
+ } else {
521
+ props.push({ key: keyTok.value, pattern: A.PatternIdent(keyTok.value) });
522
+ }
523
+ if (peek().type !== ",") break;
524
+ next();
525
+ }
526
+ expect("}");
527
+ return A.PatternObject(props);
528
+ }
529
+
530
+ if (t.type === "IDENT" && t.value === "_") {
531
+ next();
532
+ return A.PatternIdent("_");
533
+ }
534
+
535
+ if (t.type === "IDENT") {
536
+ next();
537
+ return A.PatternIdent(t.value);
538
+ }
539
+
540
+ const err = invalidSyntax("Pattern inesperado: " + t.type, t.loc);
541
+ throw err;
542
+ }
543
+
544
+ function optionalSemicolon() {
545
+ if (peek().type === ";") next();
546
+ }
547
+
548
+ function parseExpr() {
549
+ return parseAssignment();
550
+ }
551
+
552
+ function parseAssignment() {
553
+ let left = parseBinary(0);
554
+ const compoundOps = { "+=": "+", "-=": "-", "*=": "*", "/=": "/", "%=": "%" };
555
+ if (peek().type === "=" || compoundOps[peek().type]) {
556
+ const op = next().type;
557
+ const right = parseAssignment();
558
+ if (left.type !== "Ident" && left.type !== "Member" && left.type !== "IndexExpr") {
559
+ const err = invalidSyntax("Lado esquerdo inválido para atribuição", peek().loc);
560
+ throw err;
561
+ }
562
+ if (op === "=") return A.Assign(left, right);
563
+ return A.Assign(left, A.Binary(compoundOps[op], left, right));
564
+ }
565
+ return left;
566
+ }
567
+
568
+ function parseBinary(minPrec) {
569
+ let left = parseUnary();
570
+ A.setLoc(peek().loc);
571
+ while (true) {
572
+ const op = peek().type;
573
+ const prec = PRECEDENCE[op];
574
+ if (prec === undefined || prec < minPrec) break;
575
+ next();
576
+ if (op === "?") {
577
+ const cons = parseExpr();
578
+ expect(":");
579
+ const alt = parseBinary(prec);
580
+ left = A.Ternary(left, cons, alt);
581
+ } else {
582
+ const right = parseBinary(prec + 1);
583
+ left = A.Binary(op, left, right);
584
+ }
585
+ }
586
+ return left;
587
+ }
588
+
589
+ function parseUnary() {
590
+ if (peek().type === "-" || peek().type === "!") {
591
+ const op = next().type;
592
+ A.setLoc(peek().loc);
593
+ return A.Unary(op, parseUnary());
594
+ }
595
+ return parseCall();
596
+ }
597
+
598
+ function parseCall() {
599
+ A.setLoc(peek().loc);
600
+ let expr = parsePrimary();
601
+ while (true) {
602
+ if (peek().type === "(") {
603
+ next();
604
+ const args = [];
605
+ if (peek().type !== ")") {
606
+ do {
607
+ args.push(parseExpr());
608
+ if (peek().type !== ",") break;
609
+ next();
610
+ } while (true);
611
+ }
612
+ expect(")");
613
+ expr = A.Call(expr, args);
614
+ } else if (peek().type === ".") {
615
+ next();
616
+ const propTok = expect("IDENT");
617
+ expr = A.Member(expr, propTok.value);
618
+ } else if (peek().type === "[") {
619
+ next();
620
+ const index = parseExpr();
621
+ expect("]");
622
+ expr = A.IndexExpr(expr, index);
623
+ } else break;
624
+ }
625
+ return expr;
626
+ }
627
+
628
+ function parseArrowFunction() {
629
+ let isAsync = false;
630
+ if (peek().type === "ASSINCRONO") {
631
+ next();
632
+ isAsync = true;
633
+ }
634
+ expect("(");
635
+ const params = [];
636
+ if (peek().type !== ")") {
637
+ do {
638
+ params.push(expect("IDENT").value);
639
+ if (peek().type !== ",") break;
640
+ next();
641
+ } while (true);
642
+ }
643
+ expect(")");
644
+ expect("=>");
645
+ let body;
646
+ if (peek().type === "{") {
647
+ body = parseBlock();
648
+ } else {
649
+ body = parseExpr();
650
+ }
651
+ return A.ArrowFunction(params, body, isAsync);
652
+ }
653
+
654
+ function parseTryCatch() {
655
+ expect("TENTA");
656
+ A.setLoc(peek().loc);
657
+ const tryBlock = parseBlock();
658
+ expect("PEGA");
659
+ expect("(");
660
+ const errTok = expect("IDENT");
661
+ expect(")");
662
+ const catchBlock = parseBlock();
663
+ return A.TryCatchStmt(tryBlock, errTok.value, catchBlock);
664
+ }
665
+
666
+ function parsePrimary() {
667
+ const phrase =
668
+ matchPhrase("SOLTA_O_GRITO", ["SOLTA", "O", "GRITO"]) ||
669
+ matchPhrase("FALA_BAIXO", ["FALA", "BAIXO"]) ||
670
+ matchPhrase("AGORA_VAI", ["AGORA", "VAI"]) ||
671
+ matchPhrase("ESPERA_AI", ["ESPERA", "AI"]) ||
672
+ matchPhrase("OUVE_AQUI", ["OUVE", "AQUI"]) ||
673
+ matchPhrase("CRIA_SERVIDOR", ["CRIA", "SERVIDOR"]) ||
674
+ matchPhrase("PARA_SERVIDOR", ["PARA", "SERVIDOR"]) ||
675
+ matchPhrase("DIVIDE_TEXTO", ["DIVIDE", "TEXTO"]) ||
676
+ matchPhrase("DECODIFICA_URL", ["DECODIFICA", "URL"]);
677
+
678
+ if (phrase) return phrase;
679
+
680
+ const t = peek();
681
+ A.setLoc(t.loc);
682
+
683
+ if (t.type === "SORTEIA") {
684
+ next();
685
+ return A.Ident("SORTEIA");
686
+ }
687
+
688
+ if (t.type === "PARSEIA") {
689
+ next();
690
+ return A.Ident("PARSEIA");
691
+ }
692
+
693
+ if (t.type === "VERDADEIRO") {
694
+ next();
695
+ return A.Bool(true);
696
+ }
697
+
698
+ if (t.type === "FALSO") {
699
+ next();
700
+ return A.Bool(false);
701
+ }
702
+
703
+ if (t.type === "NULO") {
704
+ next();
705
+ return A.Nil();
706
+ }
707
+
708
+ if (t.type === "ISTO") {
709
+ next();
710
+ return A.ThisExpr();
711
+ }
712
+
713
+ if (t.type === "NOVA") {
714
+ next();
715
+ const callee = parseCall();
716
+ return A.NewExpr(callee, []);
717
+ }
718
+
719
+ if (t.type === "IMPORTA") {
720
+ next();
721
+ let target;
722
+ if (peek().type === "STRING") {
723
+ target = next().value;
724
+ } else {
725
+ target = expect("IDENT").value;
726
+ }
727
+ return A.ImportExpr(target);
728
+ }
729
+
730
+ if (peek().type === "TENTA") {
731
+ return parseTryCatch();
732
+ }
733
+
734
+ if (t.type === "(") {
735
+ let j = i;
736
+ while (tokens[j] && tokens[j].type !== ")") {
737
+ j++;
738
+ }
739
+ if (tokens[j + 1]?.type === "=>") {
740
+ return parseArrowFunction();
741
+ }
742
+ }
743
+
744
+ if (t.type === "{") {
745
+ next();
746
+ const props = [];
747
+ if (peek().type !== "}") {
748
+ do {
749
+ const keyTok = expect("IDENT");
750
+ expect(":");
751
+ const value = parseExpr();
752
+ props.push({ key: keyTok.value, value });
753
+ if (peek().type !== ",") break;
754
+ next();
755
+ } while (true);
756
+ }
757
+ expect("}");
758
+ return A.ObjectExpr(props);
759
+ }
760
+
761
+ if (t.type === "[") {
762
+ next();
763
+ const items = [];
764
+ if (peek().type !== "]") {
765
+ do {
766
+ items.push(parseExpr());
767
+ if (peek().type !== ",") break;
768
+ next();
769
+ } while (true);
770
+ }
771
+ expect("]");
772
+ return A.ArrayExpr(items);
773
+ }
774
+
775
+ if (t.type === "TEMPLATE") {
776
+ next();
777
+ const parts = t.parts.map(p => {
778
+ if (p.type === "TEMPLATE_STR") return A.Str(p.value);
779
+ const lexed = lex(p.value);
780
+ const exprAst = parse(lexed);
781
+ if (exprAst.body.length === 1) return exprAst.body[0];
782
+ return exprAst;
783
+ });
784
+ if (parts.length === 1) return parts[0];
785
+ let result = parts[0];
786
+ for (let k = 1; k < parts.length; k++) {
787
+ result = A.Binary("+", result, parts[k]);
788
+ }
789
+ return result;
790
+ }
791
+
792
+ if (t.type === "NUMBER") {
793
+ next();
794
+ return A.Num(t.value);
795
+ }
796
+
797
+ if (t.type === "STRING") {
798
+ next();
799
+ return A.Str(t.value);
800
+ }
801
+
802
+ if (t.type === "IDENT") {
803
+ next();
804
+ return A.Ident(t.value);
805
+ }
806
+
807
+ if (t.type === "(") {
808
+ next();
809
+ const e = parseExpr();
810
+ expect(")");
811
+ return e;
812
+ }
813
+
814
+ const err = invalidSyntax("Token inesperado: " + (t.type + (t.value ? ` (${t.value})` : "")), t.loc);
815
+ throw err;
816
+ }
817
+
818
+ return parseProgram();
819
+ }