gofront 0.0.9 → 1.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.
- package/README.md +5 -5
- package/package.json +7 -4
- package/src/cli-core.js +65 -0
- package/src/codegen/expressions.js +523 -1717
- package/src/codegen/index.js +576 -0
- package/src/codegen/runtime.js +151 -0
- package/src/codegen/statements.js +308 -296
- package/src/codegen/stdlib/builder.js +39 -0
- package/src/codegen/stdlib/bytes.js +65 -0
- package/src/codegen/stdlib/errors.js +20 -0
- package/src/codegen/stdlib/fmt.js +104 -0
- package/src/codegen/stdlib/gom.js +155 -0
- package/src/codegen/stdlib/html.js +20 -0
- package/src/codegen/stdlib/index.js +98 -0
- package/src/codegen/stdlib/io.js +36 -0
- package/src/codegen/stdlib/maps.js +45 -0
- package/src/codegen/stdlib/math.js +56 -0
- package/src/codegen/stdlib/os.js +13 -0
- package/src/codegen/stdlib/path.js +34 -0
- package/src/codegen/stdlib/rand.js +27 -0
- package/src/codegen/stdlib/regexp.js +54 -0
- package/src/codegen/stdlib/slices.js +51 -0
- package/src/codegen/stdlib/sort.js +31 -0
- package/src/codegen/stdlib/strconv.js +33 -0
- package/src/codegen/stdlib/strings.js +86 -0
- package/src/codegen/stdlib/time.js +57 -0
- package/src/codegen/stdlib/unicode.js +25 -0
- package/src/codegen/stdlib/utf8.js +26 -0
- package/src/codegen/templ.js +284 -0
- package/src/compiler.js +142 -77
- package/src/dts-parser.js +355 -371
- package/src/index.js +32 -162
- package/src/lexer.js +186 -272
- package/src/minifier.js +305 -318
- package/src/{parser.js → parser/declarations.js} +18 -175
- package/src/parser/expressions.js +51 -34
- package/src/parser/index.js +161 -0
- package/src/parser/statements.js +24 -34
- package/src/parser/types.js +31 -29
- package/src/templ-parser.js +2 -2
- package/src/tokens.js +109 -0
- package/src/typechecker/assignability.js +261 -0
- package/src/typechecker/expressions.js +568 -549
- package/src/typechecker/index.js +556 -0
- package/src/typechecker/resolve.js +428 -0
- package/src/typechecker/statements.js +270 -280
- package/src/typechecker/stdlib/core.js +592 -0
- package/src/typechecker/stdlib/extended.js +332 -0
- package/src/typechecker/stdlib.js +9 -1060
- package/src/typechecker/termination.js +86 -0
- package/src/typechecker/types.js +1 -0
- package/src/codegen.js +0 -882
- 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
|
-
|
|
81
|
+
this._skipLineComment();
|
|
71
82
|
continue;
|
|
72
83
|
}
|
|
73
84
|
if (c === "/" && this.ch1() === "*") {
|
|
74
|
-
this.
|
|
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
|
-
|
|
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++;
|
|
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
|
-
|
|
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
|
-
|
|
309
|
-
if (c === "
|
|
310
|
-
|
|
311
|
-
|
|
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
|
-
|
|
366
|
+
_skipEnumBody() {
|
|
403
367
|
this.skip();
|
|
404
|
-
|
|
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
|
-
|
|
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
|
-
|
|
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
|
-
|
|
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
|
-
|
|
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
|
-
|
|
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
|
-
|
|
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
|
-
|
|
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.
|
|
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
|
-
|
|
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
|
-
|
|
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
|
-
|
|
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
|
-
|
|
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
|
-
|
|
628
|
-
|
|
629
|
-
|
|
630
|
-
|
|
631
|
-
|
|
632
|
-
|
|
633
|
-
|
|
634
|
-
|
|
635
|
-
|
|
636
|
-
|
|
637
|
-
|
|
638
|
-
|
|
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
|