gofront 0.0.9 → 1.0.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (50) hide show
  1. package/README.md +6 -6
  2. package/package.json +7 -4
  3. package/src/codegen/expressions.js +520 -1717
  4. package/src/codegen/index.js +576 -0
  5. package/src/codegen/runtime.js +151 -0
  6. package/src/codegen/statements.js +305 -296
  7. package/src/codegen/stdlib/builder.js +36 -0
  8. package/src/codegen/stdlib/bytes.js +62 -0
  9. package/src/codegen/stdlib/errors.js +17 -0
  10. package/src/codegen/stdlib/fmt.js +101 -0
  11. package/src/codegen/stdlib/gom.js +152 -0
  12. package/src/codegen/stdlib/html.js +17 -0
  13. package/src/codegen/stdlib/index.js +95 -0
  14. package/src/codegen/stdlib/io.js +33 -0
  15. package/src/codegen/stdlib/maps.js +42 -0
  16. package/src/codegen/stdlib/math.js +53 -0
  17. package/src/codegen/stdlib/os.js +10 -0
  18. package/src/codegen/stdlib/path.js +31 -0
  19. package/src/codegen/stdlib/rand.js +24 -0
  20. package/src/codegen/stdlib/regexp.js +51 -0
  21. package/src/codegen/stdlib/slices.js +48 -0
  22. package/src/codegen/stdlib/sort.js +28 -0
  23. package/src/codegen/stdlib/strconv.js +30 -0
  24. package/src/codegen/stdlib/strings.js +83 -0
  25. package/src/codegen/stdlib/time.js +54 -0
  26. package/src/codegen/stdlib/unicode.js +22 -0
  27. package/src/codegen/stdlib/utf8.js +23 -0
  28. package/src/codegen/templ.js +281 -0
  29. package/src/compiler.js +80 -74
  30. package/src/dts-parser.js +355 -371
  31. package/src/index.js +13 -49
  32. package/src/lexer.js +186 -272
  33. package/src/minifier.js +305 -318
  34. package/src/parser/expressions.js +51 -34
  35. package/src/{parser.js → parser/index.js} +4 -4
  36. package/src/parser/statements.js +24 -34
  37. package/src/parser/types.js +31 -29
  38. package/src/templ-parser.js +2 -2
  39. package/src/tokens.js +109 -0
  40. package/src/typechecker/assignability.js +258 -0
  41. package/src/typechecker/expressions.js +559 -549
  42. package/src/typechecker/index.js +555 -0
  43. package/src/typechecker/resolve.js +421 -0
  44. package/src/typechecker/statements.js +267 -280
  45. package/src/typechecker/stdlib/core.js +592 -0
  46. package/src/typechecker/stdlib/extended.js +332 -0
  47. package/src/typechecker/stdlib.js +9 -1060
  48. package/src/typechecker/termination.js +83 -0
  49. package/src/codegen.js +0 -882
  50. package/src/typechecker.js +0 -1299
package/src/dts-parser.js CHANGED
@@ -59,6 +59,17 @@ export class DtsParser {
59
59
  return this.src[this.pos + 1];
60
60
  }
61
61
 
62
+ _skipLineComment() {
63
+ while (!this.eof() && this.ch() !== "\n") this.pos++;
64
+ }
65
+
66
+ _skipBlockComment() {
67
+ this.pos += 2;
68
+ while (!this.eof() && !(this.ch() === "*" && this.ch1() === "/"))
69
+ this.pos++;
70
+ if (!this.eof()) this.pos += 2;
71
+ }
72
+
62
73
  skip() {
63
74
  while (!this.eof()) {
64
75
  const c = this.ch();
@@ -67,14 +78,11 @@ export class DtsParser {
67
78
  continue;
68
79
  }
69
80
  if (c === "/" && this.ch1() === "/") {
70
- while (!this.eof() && this.ch() !== "\n") this.pos++;
81
+ this._skipLineComment();
71
82
  continue;
72
83
  }
73
84
  if (c === "/" && this.ch1() === "*") {
74
- this.pos += 2;
75
- while (!this.eof() && !(this.ch() === "*" && this.ch1() === "/"))
76
- this.pos++;
77
- if (!this.eof()) this.pos += 2;
85
+ this._skipBlockComment();
78
86
  continue;
79
87
  }
80
88
  break;
@@ -162,62 +170,30 @@ export class DtsParser {
162
170
  }
163
171
  }
164
172
 
173
+ _trackBracketDepth(c, depths) {
174
+ const open = { "<": 0, "(": 1, "[": 2, "{": 3 };
175
+ const close = { ">": 0, ")": 1, "]": 2, "}": 3 };
176
+ if (c in open) {
177
+ depths[open[c]]++;
178
+ return true;
179
+ }
180
+ if (c in close && depths[close[c]] > 0) {
181
+ depths[close[c]]--;
182
+ return true;
183
+ }
184
+ return false;
185
+ }
186
+
165
187
  // Skip to the end of a type expression (stops at ; | , | ) | } | { | newline-after-token)
166
188
  skipTypeExpr(stopAt = ";,)}{") {
167
- let angleBrackets = 0,
168
- parens = 0,
169
- brackets = 0,
170
- curlies = 0;
189
+ const depths = [0, 0, 0, 0];
171
190
  while (!this.eof()) {
172
191
  const c = this.ch();
173
- if (c === "<") {
174
- angleBrackets++;
175
- this.pos++;
176
- continue;
177
- }
178
- if (c === ">" && angleBrackets > 0) {
179
- angleBrackets--;
180
- this.pos++;
181
- continue;
182
- }
183
- if (c === "(") {
184
- parens++;
185
- this.pos++;
186
- continue;
187
- }
188
- if (c === ")" && parens > 0) {
189
- parens--;
190
- this.pos++;
191
- continue;
192
- }
193
- if (c === "[") {
194
- brackets++;
195
- this.pos++;
196
- continue;
197
- }
198
- if (c === "]" && brackets > 0) {
199
- brackets--;
200
- this.pos++;
201
- continue;
202
- }
203
- if (c === "{") {
204
- curlies++;
205
- this.pos++;
206
- continue;
207
- }
208
- if (c === "}" && curlies > 0) {
209
- curlies--;
192
+ if (this._trackBracketDepth(c, depths)) {
210
193
  this.pos++;
211
194
  continue;
212
195
  }
213
- if (
214
- angleBrackets === 0 &&
215
- parens === 0 &&
216
- brackets === 0 &&
217
- curlies === 0 &&
218
- stopAt.includes(c)
219
- )
220
- break;
196
+ if (!depths.some(Boolean) && stopAt.includes(c)) break;
221
197
  if (c === '"' || c === "'") {
222
198
  this.skipStringLit();
223
199
  continue;
@@ -272,83 +248,71 @@ export class DtsParser {
272
248
  return base;
273
249
  }
274
250
 
251
+ _parseParenType() {
252
+ this.pos++;
253
+ this.skipTypeExpr(")");
254
+ this.consume(")");
255
+ this.skip();
256
+ if (this.startsWith("=>")) {
257
+ this.pos += 2;
258
+ this.parseType();
259
+ }
260
+ return ANY;
261
+ }
262
+
263
+ _parseTemplateLit() {
264
+ while (!this.eof() && this.ch() !== "`") this.pos++;
265
+ this.pos++;
266
+ return { kind: "basic", name: "string" };
267
+ }
268
+
269
+ _parseNumericLit() {
270
+ while (!this.eof() && /[0-9._-]/.test(this.ch())) this.pos++;
271
+ return { kind: "basic", name: "float64" };
272
+ }
273
+
274
+ _parseNamedType(name) {
275
+ if (TS_PRIMITIVES[name]) {
276
+ this.skipGenerics();
277
+ return TS_PRIMITIVES[name];
278
+ }
279
+ if (name === "true" || name === "false")
280
+ return { kind: "basic", name: "bool" };
281
+ this.skipGenerics();
282
+ while (this.ch() === ".") {
283
+ this.pos++;
284
+ this.readIdent();
285
+ }
286
+ return { kind: "basic", name: "any", alias: name };
287
+ }
288
+
275
289
  _parseBaseType() {
276
290
  this.skip();
277
291
  const c = this.ch();
278
-
279
- // Tuple / array literal type: [T, U]
280
292
  if (c === "[") {
281
- this.pos++; // consume opening [, so skipTypeExpr stops at depth-0 ]
293
+ this.pos++;
282
294
  this.skipTypeExpr("]");
283
295
  this.consume("]");
284
296
  return ANY;
285
297
  }
286
- // Object literal type: { x: T }
287
298
  if (c === "{") {
288
299
  this.skipBlock();
289
300
  return ANY;
290
301
  }
291
- // Parenthesised type or function type: (params) => T
292
- if (c === "(") {
293
- this.pos++; // consume opening (, so skipTypeExpr stops at depth-0 )
294
- this.skipTypeExpr(")");
295
- this.consume(")");
296
- this.skip();
297
- if (this.startsWith("=>")) {
298
- this.pos += 2;
299
- this.parseType();
300
- }
301
- return ANY;
302
- }
303
- // String literal type: "foo"
302
+ if (c === "(") return this._parseParenType();
304
303
  if (c === '"' || c === "'") {
305
304
  this.skipStringLit();
306
305
  return { kind: "basic", name: "string" };
307
306
  }
308
- // Template literal: `...`
309
- if (c === "`") {
310
- while (!this.eof() && this.ch() !== "`") this.pos++;
311
- this.pos++;
312
- return { kind: "basic", name: "string" };
313
- }
314
- // Numeric literal
315
- if (
316
- /[0-9]/.test(c) ||
317
- (c === "-" && /[0-9]/.test(this.src[this.pos + 1]))
318
- ) {
319
- while (!this.eof() && /[0-9._-]/.test(this.ch())) this.pos++;
320
- return { kind: "basic", name: "float64" };
321
- }
322
-
323
- // Named type (including primitives)
324
- let name = "";
325
- while (!this.eof() && /[a-zA-Z0-9_$]/.test(this.ch()))
326
- name += this.src[this.pos++];
307
+ if (c === "`") return this._parseTemplateLit();
308
+ if (/[0-9]/.test(c) || (c === "-" && /[0-9]/.test(this.src[this.pos + 1])))
309
+ return this._parseNumericLit();
310
+ const name = this.readIdent();
327
311
  if (!name) {
328
312
  this.pos++;
329
313
  return ANY;
330
- } // skip unknown char
331
-
332
- if (TS_PRIMITIVES[name]) {
333
- this.skipGenerics();
334
- return TS_PRIMITIVES[name];
335
- }
336
-
337
- // true / false
338
- if (name === "true" || name === "false")
339
- return { kind: "basic", name: "bool" };
340
-
341
- // Generic application: T<U> — skip the parameters
342
- this.skipGenerics();
343
-
344
- // Qualified name: A.B
345
- while (this.ch() === ".") {
346
- this.pos++;
347
- while (!this.eof() && /[a-zA-Z0-9_$]/.test(this.ch())) this.pos++;
348
314
  }
349
-
350
- // Return as a named any-alias (the type checker will resolve or fall back to any)
351
- return { kind: "basic", name: "any", alias: name };
315
+ return this._parseNamedType(name);
352
316
  }
353
317
 
354
318
  // ── Parameter list ───────────────────────────────────────────
@@ -399,11 +363,22 @@ export class DtsParser {
399
363
  return members;
400
364
  }
401
365
 
402
- _parseMember(out) {
366
+ _skipEnumBody() {
403
367
  this.skip();
404
- if (this.eof() || this.ch() === "}") return;
368
+ this.consume("{");
369
+ while (!this.eof() && this.ch() !== "}") {
370
+ this.readIdent();
371
+ this.skip();
372
+ if (this.ch() === "=") {
373
+ this.pos++;
374
+ this.skipTypeExpr(",}");
375
+ }
376
+ this.consume(",");
377
+ }
378
+ this.consume("}");
379
+ }
405
380
 
406
- // Skip modifiers (export, declare, static, readonly, etc.)
381
+ _skipModifiers() {
407
382
  while (true) {
408
383
  this.skip();
409
384
  let found = false;
@@ -415,76 +390,106 @@ export class DtsParser {
415
390
  }
416
391
  if (!found) break;
417
392
  }
393
+ }
418
394
 
395
+ _parseMemberFuncDecl(out) {
396
+ const name = this.readIdent();
397
+ this.skipGenerics();
398
+ const params = this.parseParams();
419
399
  this.skip();
420
- if (this.eof() || this.ch() === "}") return;
400
+ let ret = VOID;
401
+ if (this.ch() === ":") {
402
+ this.pos++;
403
+ ret = this.parseType();
404
+ }
405
+ this.consume(";");
406
+ if (name)
407
+ out[name] = {
408
+ kind: "func",
409
+ params: params.map((p) => p.type),
410
+ returns: [ret],
411
+ };
412
+ }
421
413
 
422
- // Read the first identifier (keyword or name)
414
+ _parseMemberNewSig() {
415
+ this.skipGenerics();
416
+ this.parseParams();
417
+ this.skip();
418
+ if (this.ch() === ":") {
419
+ this.pos++;
420
+ this.parseType();
421
+ }
422
+ this.consume(";");
423
+ }
424
+
425
+ _parseMemberTypeDecl(out) {
426
+ const name = this.readIdent();
427
+ this.skipGenerics();
428
+ this.skip();
429
+ let type = ANY;
430
+ if (this.ch() === "=") {
431
+ this.pos++;
432
+ type = this.parseType();
433
+ }
434
+ this.consume(";");
435
+ if (name) out[name] = type;
436
+ }
437
+
438
+ _parseMemberClassDecl(out) {
439
+ const name = this.readIdent();
440
+ this.skipGenerics();
441
+ while (!this.eof() && this.ch() !== "{") this.pos++;
442
+ this.consume("{");
443
+ const body = this.parseBody();
444
+ this.consume("}");
445
+ this.consume(";");
446
+ if (name) out[name] = { kind: "namespace", name, members: body };
447
+ }
448
+
449
+ _parseMemberVarDecl(out) {
450
+ const name = this.readIdent();
451
+ this.skip();
452
+ this.consume("?");
453
+ let type = ANY;
454
+ if (this.ch() === ":") {
455
+ this.pos++;
456
+ type = this.parseType();
457
+ }
458
+ this.skip();
459
+ if (this.ch() === "=") {
460
+ this.pos++;
461
+ this.skipTypeExpr();
462
+ }
463
+ this.consume(";");
464
+ if (name) out[name] = type;
465
+ }
466
+
467
+ _parseMember(out) {
468
+ this.skip();
469
+ if (this.eof() || this.ch() === "}") return;
470
+ this._skipModifiers();
471
+ this.skip();
472
+ if (this.eof() || this.ch() === "}") return;
423
473
  const kw = this.readIdent();
424
474
  if (!kw) {
425
475
  this.pos++;
426
476
  return;
427
477
  }
428
-
429
478
  this.skip();
430
479
  switch (kw) {
431
- case "function": {
432
- const name = this.readIdent();
433
- this.skipGenerics();
434
- const params = this.parseParams();
435
- this.skip();
436
- let ret = VOID;
437
- if (this.ch() === ":") {
438
- this.pos++;
439
- ret = this.parseType();
440
- }
441
- this.consume(";");
442
- if (name)
443
- out[name] = {
444
- kind: "func",
445
- params: params.map((p) => p.type),
446
- returns: [ret],
447
- };
480
+ case "function":
481
+ this._parseMemberFuncDecl(out);
448
482
  break;
449
- }
450
- case "new": {
451
- // constructor signature in interface
452
- this.skipGenerics();
453
- this.parseParams();
454
- this.skip();
455
- if (this.ch() === ":") {
456
- this.pos++;
457
- this.parseType();
458
- }
459
- this.consume(";");
483
+ case "new":
484
+ this._parseMemberNewSig();
460
485
  break;
461
- }
462
- case "type": {
463
- const name = this.readIdent();
464
- this.skipGenerics();
465
- this.skip();
466
- let type = ANY;
467
- if (this.ch() === "=") {
468
- this.pos++;
469
- type = this.parseType();
470
- }
471
- this.consume(";");
472
- if (name) out[name] = type;
486
+ case "type":
487
+ this._parseMemberTypeDecl(out);
473
488
  break;
474
- }
475
489
  case "interface":
476
- case "class": {
477
- const name = this.readIdent();
478
- this.skipGenerics();
479
- // skip extends/implements
480
- while (!this.eof() && this.ch() !== "{") this.pos++;
481
- this.consume("{");
482
- const body = this.parseBody();
483
- this.consume("}");
484
- this.consume(";");
485
- if (name) out[name] = { kind: "namespace", name, members: body };
490
+ case "class":
491
+ this._parseMemberClassDecl(out);
486
492
  break;
487
- }
488
493
  case "namespace":
489
494
  case "module": {
490
495
  const name = this.readIdent() || this._readStringLit();
@@ -498,80 +503,53 @@ export class DtsParser {
498
503
  }
499
504
  case "enum": {
500
505
  const name = this.readIdent();
501
- this.skip();
502
- this.consume("{");
503
- // skip enum body — members are string/number constants
504
- while (!this.eof() && this.ch() !== "}") {
505
- this.readIdent();
506
- this.skip();
507
- if (this.ch() === "=") {
508
- this.pos++;
509
- this.skipTypeExpr(",}");
510
- }
511
- this.consume(",");
512
- }
513
- this.consume("}");
506
+ this._skipEnumBody();
514
507
  if (name) out[name] = ANY;
515
508
  break;
516
509
  }
517
510
  case "const":
518
511
  case "let":
519
- case "var": {
520
- const name = this.readIdent();
521
- this.skip();
522
- this.consume("?");
523
- let type = ANY;
524
- if (this.ch() === ":") {
525
- this.pos++;
526
- type = this.parseType();
527
- }
528
- this.skip();
529
- if (this.ch() === "=") {
530
- this.pos++;
531
- this.skipTypeExpr();
532
- }
533
- this.consume(";");
534
- if (name) out[name] = type;
512
+ case "var":
513
+ this._parseMemberVarDecl(out);
535
514
  break;
536
- }
537
- default: {
538
- // Could be: propertyName: Type or methodName(params): Type
539
- const name = kw;
540
- this.skip();
541
- this.consume("?"); // optional property
542
- this.skipGenerics();
543
- this.skip();
544
-
545
- if (this.ch() === "(") {
546
- // Method signature
547
- const params = this.parseParams();
548
- this.skip();
549
- let ret = VOID;
550
- if (this.ch() === ":") {
551
- this.pos++;
552
- ret = this.parseType();
553
- }
554
- this.consume(";");
555
- out[name] = {
556
- kind: "func",
557
- params: params.map((p) => p.type),
558
- returns: [ret],
559
- };
560
- } else if (this.ch() === ":") {
561
- this.pos++;
562
- const type = this.parseType();
563
- this.consume(";");
564
- out[name] = type;
565
- } else {
566
- // Unknown — skip to next ;
567
- this.skipTypeExpr();
568
- this.consume(";");
569
- }
515
+ default:
516
+ this._parseMemberDefault(kw, out);
570
517
  break;
571
- }
572
518
  }
573
519
  }
574
520
 
521
+ _parseMemberDefault(name, out) {
522
+ this.skip();
523
+ this.consume("?"); // optional property
524
+ this.skipGenerics();
525
+ this.skip();
526
+
527
+ if (this.ch() === "(") {
528
+ // Method signature
529
+ const params = this.parseParams();
530
+ this.skip();
531
+ let ret = VOID;
532
+ if (this.ch() === ":") {
533
+ this.pos++;
534
+ ret = this.parseType();
535
+ }
536
+ this.consume(";");
537
+ out[name] = {
538
+ kind: "func",
539
+ params: params.map((p) => p.type),
540
+ returns: [ret],
541
+ };
542
+ } else if (this.ch() === ":") {
543
+ this.pos++;
544
+ const type = this.parseType();
545
+ this.consume(";");
546
+ out[name] = type;
547
+ } else {
548
+ // Unknown — skip to next ;
549
+ this.skipTypeExpr();
550
+ this.consume(";");
551
+ }
552
+ }
575
553
  _readStringLit() {
576
554
  this.skip();
577
555
  const c = this.ch();
@@ -585,34 +563,26 @@ export class DtsParser {
585
563
 
586
564
  // ── Top-level parse ──────────────────────────────────────────
587
565
 
588
- parse() {
589
- const types = new Map(); // type namespace (for type annotations)
590
- const values = new Map(); // value namespace (for expressions)
591
-
592
- // If wrapped in `declare module "name" { ... }`, strip the wrapper
593
- this.skip();
566
+ _parseDeclareModuleWrapper() {
594
567
  if (this.matchKw("declare") && this.matchKw("module")) {
595
568
  this._readStringLit() || this.readIdent();
596
569
  this.skip();
597
570
  this.consume("{");
598
571
  }
572
+ }
573
+
574
+ parse() {
575
+ const types = new Map();
576
+ const values = new Map();
577
+
578
+ this.skip();
579
+ this._parseDeclareModuleWrapper();
599
580
 
600
581
  while (!this.eof() && this.peek() !== "}") {
601
582
  this.skip();
602
583
  if (this.eof() || this.ch() === "}") break;
603
584
 
604
- // Collect modifiers
605
- while (true) {
606
- this.skip();
607
- let found = false;
608
- for (const mod of SKIP_MODIFIERS) {
609
- if (this.matchKw(mod)) {
610
- found = true;
611
- break;
612
- }
613
- }
614
- if (!found) break;
615
- }
585
+ this._skipModifiers();
616
586
 
617
587
  this.skip();
618
588
  if (this.eof() || this.ch() === "}") break;
@@ -624,131 +594,145 @@ export class DtsParser {
624
594
  }
625
595
 
626
596
  this.skip();
627
- switch (kw) {
628
- case "import":
629
- case "export":
630
- // skip import { ... } from "..." or export { ... }
631
- this.skipTypeExpr();
632
- this.consume(";");
633
- break;
634
- case "type": {
635
- const name = this.readIdent();
636
- this.skipGenerics();
637
- this.skip();
638
- let type = ANY;
639
- if (this.ch() === "=") {
640
- this.pos++;
641
- type = this.parseType();
642
- }
643
- this.consume(";");
644
- if (name) types.set(name, type);
645
- break;
646
- }
647
- case "interface": {
648
- const name = this.readIdent();
649
- this.skipGenerics();
650
- while (!this.eof() && this.ch() !== "{") this.pos++;
651
- this.consume("{");
652
- const body = this.parseBody();
653
- this.consume("}");
654
- this.consume(";");
655
- if (name)
656
- types.set(name, {
657
- kind: "namespace",
658
- name,
659
- members: body,
660
- });
661
- break;
662
- }
663
- case "namespace":
664
- case "module": {
665
- const name = this.readIdent() || this._readStringLit();
666
- this.skip();
667
- this.consume("{");
668
- const body = this.parseBody();
669
- this.consume("}");
670
- this.consume(";");
671
- if (name) {
672
- const ns = { kind: "namespace", name, members: body };
673
- types.set(name, ns);
674
- values.set(name, ns);
675
- }
676
- break;
677
- }
678
- case "class": {
679
- const name = this.readIdent();
680
- this.skipGenerics();
681
- while (!this.eof() && this.ch() !== "{") this.pos++;
682
- this.consume("{");
683
- const body = this.parseBody();
684
- this.consume("}");
685
- this.consume(";");
686
- if (name) {
687
- const ns = { kind: "namespace", name, members: body };
688
- types.set(name, ns);
689
- values.set(name, ns);
690
- }
691
- break;
692
- }
693
- case "enum": {
694
- const name = this.readIdent();
695
- this.skipBlock();
696
- this.consume(";");
697
- if (name) {
698
- types.set(name, ANY);
699
- values.set(name, ANY);
700
- }
701
- break;
702
- }
703
- case "function": {
704
- const name = this.readIdent();
705
- this.skipGenerics();
706
- const params = this.parseParams();
707
- this.skip();
708
- let ret = VOID;
709
- if (this.ch() === ":") {
710
- this.pos++;
711
- ret = this.parseType();
712
- }
713
- this.consume(";");
714
- if (name)
715
- values.set(name, {
716
- kind: "func",
717
- params: params.map((p) => p.type),
718
- returns: [ret],
719
- });
720
- break;
721
- }
722
- case "const":
723
- case "let":
724
- case "var": {
725
- const name = this.readIdent();
726
- this.skip();
727
- this.consume("?");
728
- let type = ANY;
729
- if (this.ch() === ":") {
730
- this.pos++;
731
- type = this.parseType();
732
- }
733
- this.skip();
734
- if (this.ch() === "=") {
735
- this.pos++;
736
- this.skipTypeExpr();
737
- }
738
- this.consume(";");
739
- if (name) values.set(name, type);
740
- break;
741
- }
742
- default:
743
- // Unknown top-level construct — skip to next ;
744
- this.skipTypeExpr();
745
- this.consume(";");
746
- break;
597
+ const savedPos = this.pos;
598
+ try {
599
+ this._parseTopLevelDecl(kw, types, values);
600
+ } catch (err) {
601
+ this.pos = savedPos;
602
+ // skip to next top-level boundary (;, }, or EOF) to resume parsing
603
+ while (!this.eof() && this.ch() !== ";" && this.ch() !== "}")
604
+ this.pos++;
605
+ this.consume(";");
606
+ console.warn(
607
+ `[dts-parser] skipping malformed declaration '${kw}': ${err.message}`,
608
+ );
747
609
  }
748
610
  }
749
611
 
750
612
  return { types, values };
751
613
  }
614
+
615
+ _parseTopLevelTypeAlias(types) {
616
+ const name = this.readIdent();
617
+ this.skipGenerics();
618
+ this.skip();
619
+ let type = ANY;
620
+ if (this.ch() === "=") {
621
+ this.pos++;
622
+ type = this.parseType();
623
+ }
624
+ this.consume(";");
625
+ if (name) types.set(name, type);
626
+ }
627
+
628
+ _parseTopLevelClassDecl(kw, types, values) {
629
+ const name = this.readIdent();
630
+ this.skipGenerics();
631
+ while (!this.eof() && this.ch() !== "{") this.pos++;
632
+ this.consume("{");
633
+ const body = this.parseBody();
634
+ this.consume("}");
635
+ this.consume(";");
636
+ if (name) {
637
+ const ns = { kind: "namespace", name, members: body };
638
+ types.set(name, ns);
639
+ if (kw === "class") values.set(name, ns);
640
+ }
641
+ }
642
+
643
+ _parseTopLevelNamespaceDecl(types, values) {
644
+ const name = this.readIdent() || this._readStringLit();
645
+ this.skip();
646
+ this.consume("{");
647
+ const body = this.parseBody();
648
+ this.consume("}");
649
+ this.consume(";");
650
+ if (name) {
651
+ const ns = { kind: "namespace", name, members: body };
652
+ types.set(name, ns);
653
+ values.set(name, ns);
654
+ }
655
+ }
656
+
657
+ _parseTopLevelFuncDecl(values) {
658
+ const name = this.readIdent();
659
+ this.skipGenerics();
660
+ const params = this.parseParams();
661
+ this.skip();
662
+ let ret = VOID;
663
+ if (this.ch() === ":") {
664
+ this.pos++;
665
+ ret = this.parseType();
666
+ }
667
+ this.consume(";");
668
+ if (name)
669
+ values.set(name, {
670
+ kind: "func",
671
+ params: params.map((p) => p.type),
672
+ returns: [ret],
673
+ });
674
+ }
675
+
676
+ _parseTopLevelVarDecl(values) {
677
+ const name = this.readIdent();
678
+ this.skip();
679
+ this.consume("?");
680
+ let type = ANY;
681
+ if (this.ch() === ":") {
682
+ this.pos++;
683
+ type = this.parseType();
684
+ }
685
+ this.skip();
686
+ if (this.ch() === "=") {
687
+ this.pos++;
688
+ this.skipTypeExpr();
689
+ }
690
+ this.consume(";");
691
+ if (name) values.set(name, type);
692
+ }
693
+
694
+ _parseTopLevelDecl(kw, types, values) {
695
+ switch (kw) {
696
+ case "import":
697
+ case "export":
698
+ this.skipTypeExpr();
699
+ this.consume(";");
700
+ break;
701
+ case "type":
702
+ this._parseTopLevelTypeAlias(types);
703
+ break;
704
+ case "interface":
705
+ case "class":
706
+ this._parseTopLevelClassDecl(kw, types, values);
707
+ break;
708
+ case "namespace":
709
+ case "module":
710
+ this._parseTopLevelNamespaceDecl(types, values);
711
+ break;
712
+ case "enum": {
713
+ const name = this.readIdent();
714
+ this.skipBlock();
715
+ this.consume(";");
716
+ if (name) {
717
+ types.set(name, ANY);
718
+ values.set(name, ANY);
719
+ }
720
+ break;
721
+ }
722
+ case "function":
723
+ this._parseTopLevelFuncDecl(values);
724
+ break;
725
+ case "const":
726
+ case "let":
727
+ case "var":
728
+ this._parseTopLevelVarDecl(values);
729
+ break;
730
+ default:
731
+ this.skipTypeExpr();
732
+ this.consume(";");
733
+ break;
734
+ }
735
+ }
752
736
  }
753
737
 
754
738
  // Helper: parse a .d.ts file and return { types, values } Maps