gofront 1.6.0 → 1.7.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/README.md +35 -39
- package/package.json +37 -4
- package/src/backend/js/expressions.js +559 -144
- package/src/backend/js/index.js +174 -49
- package/src/backend/js/runtime.js +1518 -54
- package/src/backend/js/statements.js +91 -73
- package/src/backend/js/stdlib/base64.js +12 -0
- package/src/backend/js/stdlib/binary.js +102 -0
- package/src/backend/js/stdlib/bits.js +15 -1
- package/src/backend/js/stdlib/builder.js +28 -9
- package/src/backend/js/stdlib/bytes.js +75 -18
- package/src/backend/js/stdlib/errors.js +25 -1
- package/src/backend/js/stdlib/fmt.js +70 -13
- package/src/backend/js/stdlib/hex.js +17 -0
- package/src/backend/js/stdlib/html.js +1 -1
- package/src/backend/js/stdlib/index.js +28 -0
- package/src/backend/js/stdlib/io.js +105 -3
- package/src/backend/js/stdlib/json.js +972 -0
- package/src/backend/js/stdlib/math.js +13 -1
- package/src/backend/js/stdlib/path.js +18 -4
- package/src/backend/js/stdlib/rand.js +10 -5
- package/src/backend/js/stdlib/sha256.js +12 -0
- package/src/backend/js/stdlib/simd.js +24 -0
- package/src/backend/js/stdlib/slices.js +52 -26
- package/src/backend/js/stdlib/strconv.js +21 -5
- package/src/backend/js/stdlib/strings.js +148 -15
- package/src/backend/js/stdlib/sync.js +13 -0
- package/src/backend/js/stdlib/time.js +90 -19
- package/src/backend/js/stdlib/unicode.js +2 -2
- package/src/backend/wasm/boundary.js +1225 -41
- package/src/backend/wasm/const-fold.js +205 -0
- package/src/backend/wasm/emit-builtins.js +220 -76
- package/src/backend/wasm/emit-exprs.js +475 -276
- package/src/backend/wasm/emit-maps.js +144 -8
- package/src/backend/wasm/emit-stdlib.js +12 -3005
- package/src/backend/wasm/emit-stmts.js +264 -270
- package/src/backend/wasm/emit.js +124 -87
- package/src/backend/wasm/encode.js +140 -29
- package/src/backend/wasm/index.js +1001 -32
- package/src/backend/wasm/optimize.js +17 -6
- package/src/backend/wasm/stdlib/bytes.js +5039 -0
- package/src/backend/wasm/stdlib/core.js +8903 -0
- package/src/backend/wasm/stdlib/index.js +43 -0
- package/src/backend/wasm/stdlib/io.js +2161 -0
- package/src/backend/wasm/stdlib/packages.js +2400 -0
- package/src/backend/wasm/stdlib/pure.js +720 -0
- package/src/backend/wasm/stdlib/simd.js +234 -0
- package/src/backend/wasm/stdlib/time.js +1200 -0
- package/src/backend/wasm/types.js +174 -1
- package/src/backend/wasm/wat.js +37 -0
- package/src/cli-core.js +1 -1
- package/src/compiler.js +18 -4
- package/src/dts-parser.js +150 -140
- package/src/index.js +2 -6
- package/src/lexer.js +80 -29
- package/src/lower/boxing.js +1 -7
- package/src/lower/captures.js +2 -6
- package/src/lower/embedding.js +2 -1
- package/src/lower/ownership.js +30 -9
- package/src/minifier.js +20 -68
- package/src/parser/declarations.js +3 -6
- package/src/parser/expressions.js +3 -8
- package/src/parser/index.js +18 -3
- package/src/parser/statements.js +25 -38
- package/src/parser/struct-tag.js +144 -0
- package/src/parser/types.js +64 -8
- package/src/resolver.js +2 -27
- package/src/templ-lexer.js +29 -63
- package/src/templ-parser.js +22 -45
- package/src/typechecker/assignability.js +126 -13
- package/src/typechecker/expressions.js +168 -16
- package/src/typechecker/index.js +35 -8
- package/src/typechecker/resolve.js +187 -8
- package/src/typechecker/statements.js +68 -9
- package/src/typechecker/stdlib/core.js +280 -89
- package/src/typechecker/stdlib/extended.js +490 -1
- package/src/typechecker/stdlib/simd.js +73 -0
- package/src/typechecker/stdlib.js +2 -0
- package/src/typechecker/types.js +362 -9
- package/src/vendor.js +86 -11
package/src/dts-parser.js
CHANGED
|
@@ -109,10 +109,9 @@ export class DtsParser {
|
|
|
109
109
|
|
|
110
110
|
readIdent() {
|
|
111
111
|
this.skip();
|
|
112
|
-
|
|
113
|
-
while (!this.eof() && /[a-zA-Z0-9_$]/.test(this.ch()))
|
|
114
|
-
|
|
115
|
-
return s;
|
|
112
|
+
const start = this.pos;
|
|
113
|
+
while (!this.eof() && /[a-zA-Z0-9_$]/.test(this.ch())) this.pos++;
|
|
114
|
+
return this.src.slice(start, this.pos);
|
|
116
115
|
}
|
|
117
116
|
|
|
118
117
|
consume(ch) {
|
|
@@ -171,14 +170,14 @@ export class DtsParser {
|
|
|
171
170
|
}
|
|
172
171
|
|
|
173
172
|
_trackBracketDepth(c, depths) {
|
|
174
|
-
const
|
|
175
|
-
|
|
176
|
-
|
|
177
|
-
depths[open[c]]++;
|
|
173
|
+
const oi = "<([{".indexOf(c);
|
|
174
|
+
if (oi >= 0) {
|
|
175
|
+
depths[oi]++;
|
|
178
176
|
return true;
|
|
179
177
|
}
|
|
180
|
-
|
|
181
|
-
|
|
178
|
+
const ci = ">)]}".indexOf(c);
|
|
179
|
+
if (ci >= 0 && depths[ci] > 0) {
|
|
180
|
+
depths[ci]--;
|
|
182
181
|
return true;
|
|
183
182
|
}
|
|
184
183
|
return false;
|
|
@@ -204,9 +203,48 @@ export class DtsParser {
|
|
|
204
203
|
|
|
205
204
|
// ── Type parsing ─────────────────────────────────────────────
|
|
206
205
|
|
|
206
|
+
_parseTupleElement() {
|
|
207
|
+
this.skip();
|
|
208
|
+
if (this.startsWith("...")) this.pos += 3;
|
|
209
|
+
|
|
210
|
+
const savedPos = this.pos;
|
|
211
|
+
const ident = this.readIdent();
|
|
212
|
+
if (ident) {
|
|
213
|
+
this.skip();
|
|
214
|
+
if (this.ch() === "?") {
|
|
215
|
+
this.pos++;
|
|
216
|
+
this.skip();
|
|
217
|
+
}
|
|
218
|
+
if (this.ch() === ":") {
|
|
219
|
+
this.pos++;
|
|
220
|
+
return this.parseType(false);
|
|
221
|
+
}
|
|
222
|
+
}
|
|
223
|
+
this.pos = savedPos;
|
|
224
|
+
return this.parseType(false);
|
|
225
|
+
}
|
|
226
|
+
|
|
227
|
+
_parseTupleType(inReturn) {
|
|
228
|
+
this.consume("[");
|
|
229
|
+
const elements = [];
|
|
230
|
+
while (!this.eof() && this.peek() !== "]") {
|
|
231
|
+
this.skip();
|
|
232
|
+
if (this.ch() === "]") break;
|
|
233
|
+
elements.push(this._parseTupleElement());
|
|
234
|
+
this.skip();
|
|
235
|
+
if (this.ch() !== ",") break;
|
|
236
|
+
this.pos++;
|
|
237
|
+
}
|
|
238
|
+
this.consume("]");
|
|
239
|
+
if (inReturn) {
|
|
240
|
+
return { kind: "tuple", types: elements };
|
|
241
|
+
}
|
|
242
|
+
return { kind: "slice", elem: ANY };
|
|
243
|
+
}
|
|
244
|
+
|
|
207
245
|
// Parse a TypeScript type expression and return a GoFront type.
|
|
208
246
|
// Always returns something; falls back to ANY for complex types.
|
|
209
|
-
parseType() {
|
|
247
|
+
parseType(inReturn = false) {
|
|
210
248
|
this.skip();
|
|
211
249
|
|
|
212
250
|
// Skip modifiers
|
|
@@ -227,13 +265,16 @@ export class DtsParser {
|
|
|
227
265
|
this.skip();
|
|
228
266
|
if (this.ch() === "|" || this.ch() === "&") this.pos++;
|
|
229
267
|
|
|
230
|
-
let base = this._parseBaseType();
|
|
268
|
+
let base = this._parseBaseType(inReturn);
|
|
231
269
|
|
|
232
270
|
this.skip();
|
|
233
271
|
// Array suffix: T[] or T[][]
|
|
234
272
|
while (this.startsWith("[]")) {
|
|
235
273
|
this.pos += 2;
|
|
236
|
-
base = {
|
|
274
|
+
base = {
|
|
275
|
+
kind: "slice",
|
|
276
|
+
elem: base.kind === "tuple" ? { kind: "slice", elem: ANY } : base,
|
|
277
|
+
};
|
|
237
278
|
this.skip();
|
|
238
279
|
}
|
|
239
280
|
|
|
@@ -286,14 +327,11 @@ export class DtsParser {
|
|
|
286
327
|
return { kind: "basic", name: "any", alias: name };
|
|
287
328
|
}
|
|
288
329
|
|
|
289
|
-
_parseBaseType() {
|
|
330
|
+
_parseBaseType(inReturn = false) {
|
|
290
331
|
this.skip();
|
|
291
332
|
const c = this.ch();
|
|
292
333
|
if (c === "[") {
|
|
293
|
-
this.
|
|
294
|
-
this.skipTypeExpr("]");
|
|
295
|
-
this.consume("]");
|
|
296
|
-
return ANY;
|
|
334
|
+
return this._parseTupleType(inReturn);
|
|
297
335
|
}
|
|
298
336
|
if (c === "{") {
|
|
299
337
|
this.skipBlock();
|
|
@@ -392,7 +430,7 @@ export class DtsParser {
|
|
|
392
430
|
}
|
|
393
431
|
}
|
|
394
432
|
|
|
395
|
-
|
|
433
|
+
_parseFuncDecl() {
|
|
396
434
|
const name = this.readIdent();
|
|
397
435
|
this.skipGenerics();
|
|
398
436
|
const params = this.parseParams();
|
|
@@ -400,15 +438,26 @@ export class DtsParser {
|
|
|
400
438
|
let ret = VOID;
|
|
401
439
|
if (this.ch() === ":") {
|
|
402
440
|
this.pos++;
|
|
403
|
-
ret = this.parseType();
|
|
441
|
+
ret = this.parseType(true);
|
|
404
442
|
}
|
|
405
443
|
this.consume(";");
|
|
406
|
-
|
|
407
|
-
|
|
444
|
+
const isVariadic = params.some((p) => p.variadic);
|
|
445
|
+
return {
|
|
446
|
+
name,
|
|
447
|
+
val: {
|
|
408
448
|
kind: "func",
|
|
409
|
-
params: params.map((p) =>
|
|
410
|
-
|
|
411
|
-
|
|
449
|
+
params: params.map((p) =>
|
|
450
|
+
p.variadic && p.type?.kind === "slice" ? p.type.elem : p.type,
|
|
451
|
+
),
|
|
452
|
+
returns:
|
|
453
|
+
ret.kind === "tuple"
|
|
454
|
+
? ret.types.length > 0
|
|
455
|
+
? ret.types
|
|
456
|
+
: [VOID]
|
|
457
|
+
: [ret],
|
|
458
|
+
...(isVariadic ? { variadic: true } : {}),
|
|
459
|
+
},
|
|
460
|
+
};
|
|
412
461
|
}
|
|
413
462
|
|
|
414
463
|
_parseMemberNewSig() {
|
|
@@ -422,7 +471,7 @@ export class DtsParser {
|
|
|
422
471
|
this.consume(";");
|
|
423
472
|
}
|
|
424
473
|
|
|
425
|
-
|
|
474
|
+
_parseTypeDecl() {
|
|
426
475
|
const name = this.readIdent();
|
|
427
476
|
this.skipGenerics();
|
|
428
477
|
this.skip();
|
|
@@ -432,10 +481,10 @@ export class DtsParser {
|
|
|
432
481
|
type = this.parseType();
|
|
433
482
|
}
|
|
434
483
|
this.consume(";");
|
|
435
|
-
|
|
484
|
+
return { name, type };
|
|
436
485
|
}
|
|
437
486
|
|
|
438
|
-
|
|
487
|
+
_parseClassDecl() {
|
|
439
488
|
const name = this.readIdent();
|
|
440
489
|
this.skipGenerics();
|
|
441
490
|
while (!this.eof() && this.ch() !== "{") this.pos++;
|
|
@@ -443,10 +492,20 @@ export class DtsParser {
|
|
|
443
492
|
const body = this.parseBody();
|
|
444
493
|
this.consume("}");
|
|
445
494
|
this.consume(";");
|
|
446
|
-
|
|
495
|
+
return { name, ns: { kind: "namespace", name, members: body } };
|
|
447
496
|
}
|
|
448
497
|
|
|
449
|
-
|
|
498
|
+
_parseNamespaceDecl() {
|
|
499
|
+
const name = this.readIdent() || this._readStringLit();
|
|
500
|
+
this.skip();
|
|
501
|
+
this.consume("{");
|
|
502
|
+
const body = this.parseBody();
|
|
503
|
+
this.consume("}");
|
|
504
|
+
this.consume(";");
|
|
505
|
+
return { name, ns: { kind: "namespace", name, members: body } };
|
|
506
|
+
}
|
|
507
|
+
|
|
508
|
+
_parseVarDecl() {
|
|
450
509
|
const name = this.readIdent();
|
|
451
510
|
this.skip();
|
|
452
511
|
this.consume("?");
|
|
@@ -461,7 +520,7 @@ export class DtsParser {
|
|
|
461
520
|
this.skipTypeExpr();
|
|
462
521
|
}
|
|
463
522
|
this.consume(";");
|
|
464
|
-
|
|
523
|
+
return { name, type };
|
|
465
524
|
}
|
|
466
525
|
|
|
467
526
|
_parseMember(out) {
|
|
@@ -477,28 +536,29 @@ export class DtsParser {
|
|
|
477
536
|
}
|
|
478
537
|
this.skip();
|
|
479
538
|
switch (kw) {
|
|
480
|
-
case "function":
|
|
481
|
-
this.
|
|
539
|
+
case "function": {
|
|
540
|
+
const { name, val } = this._parseFuncDecl();
|
|
541
|
+
if (name) out[name] = val;
|
|
482
542
|
break;
|
|
543
|
+
}
|
|
483
544
|
case "new":
|
|
484
545
|
this._parseMemberNewSig();
|
|
485
546
|
break;
|
|
486
|
-
case "type":
|
|
487
|
-
this.
|
|
547
|
+
case "type": {
|
|
548
|
+
const { name, type } = this._parseTypeDecl();
|
|
549
|
+
if (name) out[name] = type;
|
|
488
550
|
break;
|
|
551
|
+
}
|
|
489
552
|
case "interface":
|
|
490
|
-
case "class":
|
|
491
|
-
this.
|
|
553
|
+
case "class": {
|
|
554
|
+
const { name, ns } = this._parseClassDecl();
|
|
555
|
+
if (name) out[name] = ns;
|
|
492
556
|
break;
|
|
557
|
+
}
|
|
493
558
|
case "namespace":
|
|
494
559
|
case "module": {
|
|
495
|
-
const name
|
|
496
|
-
|
|
497
|
-
this.consume("{");
|
|
498
|
-
const body = this.parseBody();
|
|
499
|
-
this.consume("}");
|
|
500
|
-
this.consume(";");
|
|
501
|
-
if (name) out[name] = { kind: "namespace", name, members: body };
|
|
560
|
+
const { name, ns } = this._parseNamespaceDecl();
|
|
561
|
+
if (name) out[name] = ns;
|
|
502
562
|
break;
|
|
503
563
|
}
|
|
504
564
|
case "enum": {
|
|
@@ -509,9 +569,11 @@ export class DtsParser {
|
|
|
509
569
|
}
|
|
510
570
|
case "const":
|
|
511
571
|
case "let":
|
|
512
|
-
case "var":
|
|
513
|
-
this.
|
|
572
|
+
case "var": {
|
|
573
|
+
const { name, type } = this._parseVarDecl();
|
|
574
|
+
if (name) out[name] = type;
|
|
514
575
|
break;
|
|
576
|
+
}
|
|
515
577
|
default:
|
|
516
578
|
this._parseMemberDefault(kw, out);
|
|
517
579
|
break;
|
|
@@ -531,13 +593,22 @@ export class DtsParser {
|
|
|
531
593
|
let ret = VOID;
|
|
532
594
|
if (this.ch() === ":") {
|
|
533
595
|
this.pos++;
|
|
534
|
-
ret = this.parseType();
|
|
596
|
+
ret = this.parseType(true);
|
|
535
597
|
}
|
|
536
598
|
this.consume(";");
|
|
599
|
+
const isVariadic = params.some((p) => p.variadic);
|
|
537
600
|
out[name] = {
|
|
538
601
|
kind: "func",
|
|
539
|
-
params: params.map((p) =>
|
|
540
|
-
|
|
602
|
+
params: params.map((p) =>
|
|
603
|
+
p.variadic && p.type?.kind === "slice" ? p.type.elem : p.type,
|
|
604
|
+
),
|
|
605
|
+
returns:
|
|
606
|
+
ret.kind === "tuple"
|
|
607
|
+
? ret.types.length > 0
|
|
608
|
+
? ret.types
|
|
609
|
+
: [VOID]
|
|
610
|
+
: [ret],
|
|
611
|
+
...(isVariadic ? { variadic: true } : {}),
|
|
541
612
|
};
|
|
542
613
|
} else if (this.ch() === ":") {
|
|
543
614
|
this.pos++;
|
|
@@ -550,13 +621,15 @@ export class DtsParser {
|
|
|
550
621
|
this.consume(";");
|
|
551
622
|
}
|
|
552
623
|
}
|
|
624
|
+
|
|
553
625
|
_readStringLit() {
|
|
554
626
|
this.skip();
|
|
555
627
|
const c = this.ch();
|
|
556
628
|
if (c !== '"' && c !== "'") return null;
|
|
557
629
|
this.pos++;
|
|
558
|
-
|
|
559
|
-
while (!this.eof() && this.ch() !== c)
|
|
630
|
+
const start = this.pos;
|
|
631
|
+
while (!this.eof() && this.ch() !== c) this.pos++;
|
|
632
|
+
const s = this.src.slice(start, this.pos);
|
|
560
633
|
this.pos++;
|
|
561
634
|
return s;
|
|
562
635
|
}
|
|
@@ -612,85 +685,6 @@ export class DtsParser {
|
|
|
612
685
|
return { types, values };
|
|
613
686
|
}
|
|
614
687
|
|
|
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
688
|
_parseTopLevelDecl(kw, types, values) {
|
|
695
689
|
switch (kw) {
|
|
696
690
|
case "import":
|
|
@@ -698,17 +692,29 @@ export class DtsParser {
|
|
|
698
692
|
this.skipTypeExpr();
|
|
699
693
|
this.consume(";");
|
|
700
694
|
break;
|
|
701
|
-
case "type":
|
|
702
|
-
this.
|
|
695
|
+
case "type": {
|
|
696
|
+
const { name, type } = this._parseTypeDecl();
|
|
697
|
+
if (name) types.set(name, type);
|
|
703
698
|
break;
|
|
699
|
+
}
|
|
704
700
|
case "interface":
|
|
705
|
-
case "class":
|
|
706
|
-
this.
|
|
701
|
+
case "class": {
|
|
702
|
+
const { name, ns } = this._parseClassDecl();
|
|
703
|
+
if (name) {
|
|
704
|
+
types.set(name, ns);
|
|
705
|
+
if (kw === "class") values.set(name, ns);
|
|
706
|
+
}
|
|
707
707
|
break;
|
|
708
|
+
}
|
|
708
709
|
case "namespace":
|
|
709
|
-
case "module":
|
|
710
|
-
this.
|
|
710
|
+
case "module": {
|
|
711
|
+
const { name, ns } = this._parseNamespaceDecl();
|
|
712
|
+
if (name) {
|
|
713
|
+
types.set(name, ns);
|
|
714
|
+
values.set(name, ns);
|
|
715
|
+
}
|
|
711
716
|
break;
|
|
717
|
+
}
|
|
712
718
|
case "enum": {
|
|
713
719
|
const name = this.readIdent();
|
|
714
720
|
this.skipBlock();
|
|
@@ -719,14 +725,18 @@ export class DtsParser {
|
|
|
719
725
|
}
|
|
720
726
|
break;
|
|
721
727
|
}
|
|
722
|
-
case "function":
|
|
723
|
-
this.
|
|
728
|
+
case "function": {
|
|
729
|
+
const { name, val } = this._parseFuncDecl();
|
|
730
|
+
if (name) values.set(name, val);
|
|
724
731
|
break;
|
|
732
|
+
}
|
|
725
733
|
case "const":
|
|
726
734
|
case "let":
|
|
727
|
-
case "var":
|
|
728
|
-
this.
|
|
735
|
+
case "var": {
|
|
736
|
+
const { name, type } = this._parseVarDecl();
|
|
737
|
+
if (name) values.set(name, type);
|
|
729
738
|
break;
|
|
739
|
+
}
|
|
730
740
|
default:
|
|
731
741
|
this.skipTypeExpr();
|
|
732
742
|
this.consume(";");
|
package/src/index.js
CHANGED
|
@@ -13,11 +13,6 @@
|
|
|
13
13
|
// gofront <file.go> --tokens — dump tokens of first file (debug)
|
|
14
14
|
// gofront init [dir] — scaffold a new GoFront project
|
|
15
15
|
|
|
16
|
-
import { createRequire } from "node:module";
|
|
17
|
-
|
|
18
|
-
const _require = createRequire(import.meta.url);
|
|
19
|
-
const { version } = _require("../package.json");
|
|
20
|
-
|
|
21
16
|
import { statSync } from "node:fs";
|
|
22
17
|
import { dirname, relative, resolve } from "node:path";
|
|
23
18
|
import { copyAssets } from "./asset-manager.js";
|
|
@@ -25,6 +20,7 @@ import {
|
|
|
25
20
|
formatBuildSummary,
|
|
26
21
|
formatPrepSummary,
|
|
27
22
|
formatWrittenDesc,
|
|
23
|
+
GOFRONT_VERSION,
|
|
28
24
|
handleBuild,
|
|
29
25
|
handleCheck,
|
|
30
26
|
handleDev,
|
|
@@ -47,7 +43,7 @@ import { colors, formatDiagnostic, log, ms, stamp } from "./colors.js";
|
|
|
47
43
|
|
|
48
44
|
const args = process.argv.slice(2);
|
|
49
45
|
if (args[0] === "--version" || args[0] === "-v") {
|
|
50
|
-
console.log(`gofront ${
|
|
46
|
+
console.log(`gofront ${GOFRONT_VERSION}`);
|
|
51
47
|
process.exit(0);
|
|
52
48
|
}
|
|
53
49
|
|
package/src/lexer.js
CHANGED
|
@@ -203,11 +203,25 @@ export class Lexer {
|
|
|
203
203
|
const l = this.line,
|
|
204
204
|
c = this.col;
|
|
205
205
|
this.advance(); // opening "
|
|
206
|
-
|
|
207
|
-
|
|
208
|
-
|
|
209
|
-
|
|
210
|
-
|
|
206
|
+
let start = this.pos;
|
|
207
|
+
let parts = null;
|
|
208
|
+
while (this.pos < this.src.length) {
|
|
209
|
+
const ch = this.src[this.pos];
|
|
210
|
+
if (ch === '"') {
|
|
211
|
+
if (parts === null) {
|
|
212
|
+
const str = this.src.slice(start, this.pos);
|
|
213
|
+
this.advance(); // closing "
|
|
214
|
+
return str;
|
|
215
|
+
}
|
|
216
|
+
parts.push(this.src.slice(start, this.pos));
|
|
217
|
+
this.advance(); // closing "
|
|
218
|
+
return parts.join("");
|
|
219
|
+
}
|
|
220
|
+
if (ch === "\n") this.err("Unterminated string literal");
|
|
221
|
+
if (ch === "\\") {
|
|
222
|
+
if (parts === null) parts = [];
|
|
223
|
+
if (this.pos > start) parts.push(this.src.slice(start, this.pos));
|
|
224
|
+
this.advance(); // skip \
|
|
211
225
|
const esc = this.advance();
|
|
212
226
|
switch (esc) {
|
|
213
227
|
case "n":
|
|
@@ -231,14 +245,12 @@ export class Lexer {
|
|
|
231
245
|
default:
|
|
232
246
|
parts.push(`\\${esc}`);
|
|
233
247
|
}
|
|
248
|
+
start = this.pos;
|
|
234
249
|
} else {
|
|
235
|
-
|
|
250
|
+
this.advance();
|
|
236
251
|
}
|
|
237
252
|
}
|
|
238
|
-
|
|
239
|
-
throw new LexError("Unterminated string", l, c, this.filename, this.src);
|
|
240
|
-
this.advance(); // closing "
|
|
241
|
-
return parts.join("");
|
|
253
|
+
throw new LexError("Unterminated string", l, c, this.filename, this.src);
|
|
242
254
|
}
|
|
243
255
|
|
|
244
256
|
readRawString() {
|
|
@@ -383,39 +395,78 @@ export class Lexer {
|
|
|
383
395
|
_readDecimalExponent(n) {
|
|
384
396
|
n += this.advance(); // consume e/E
|
|
385
397
|
if (this.peek() === "+" || this.peek() === "-") n += this.advance();
|
|
386
|
-
while (this.pos < this.src.length
|
|
387
|
-
const
|
|
388
|
-
if (
|
|
398
|
+
while (this.pos < this.src.length) {
|
|
399
|
+
const c = this.src.charCodeAt(this.pos);
|
|
400
|
+
if (c >= 48 && c <= 57) {
|
|
401
|
+
n += this.advance();
|
|
402
|
+
} else if (c === 95) {
|
|
403
|
+
this.advance();
|
|
404
|
+
} else {
|
|
405
|
+
break;
|
|
406
|
+
}
|
|
389
407
|
}
|
|
390
408
|
return n;
|
|
391
409
|
}
|
|
392
410
|
|
|
393
411
|
_readDecimalNumber(n) {
|
|
394
412
|
let isFloat = false;
|
|
395
|
-
while (this.pos < this.src.length
|
|
396
|
-
const
|
|
397
|
-
if (
|
|
413
|
+
while (this.pos < this.src.length) {
|
|
414
|
+
const c = this.src.charCodeAt(this.pos);
|
|
415
|
+
if (c >= 48 && c <= 57) {
|
|
416
|
+
n += this.advance();
|
|
417
|
+
} else if (c === 95) {
|
|
418
|
+
this.advance(); // skip _
|
|
419
|
+
} else {
|
|
420
|
+
break;
|
|
421
|
+
}
|
|
398
422
|
}
|
|
399
|
-
if (
|
|
400
|
-
|
|
401
|
-
|
|
402
|
-
|
|
403
|
-
|
|
404
|
-
|
|
423
|
+
if (
|
|
424
|
+
this.pos + 1 < this.src.length &&
|
|
425
|
+
this.src.charCodeAt(this.pos) === 46
|
|
426
|
+
) {
|
|
427
|
+
const next = this.src.charCodeAt(this.pos + 1);
|
|
428
|
+
if (next >= 48 && next <= 57) {
|
|
429
|
+
isFloat = true;
|
|
430
|
+
n += this.advance();
|
|
431
|
+
while (this.pos < this.src.length) {
|
|
432
|
+
const c = this.src.charCodeAt(this.pos);
|
|
433
|
+
if (c >= 48 && c <= 57) {
|
|
434
|
+
n += this.advance();
|
|
435
|
+
} else if (c === 95) {
|
|
436
|
+
this.advance(); // skip _
|
|
437
|
+
} else {
|
|
438
|
+
break;
|
|
439
|
+
}
|
|
440
|
+
}
|
|
405
441
|
}
|
|
406
442
|
}
|
|
407
|
-
if (this.
|
|
408
|
-
|
|
409
|
-
|
|
443
|
+
if (this.pos < this.src.length) {
|
|
444
|
+
const c = this.src.charCodeAt(this.pos);
|
|
445
|
+
if (c === 101 || c === 69) {
|
|
446
|
+
isFloat = true;
|
|
447
|
+
n = this._readDecimalExponent(n);
|
|
448
|
+
}
|
|
410
449
|
}
|
|
411
450
|
return { n, isFloat };
|
|
412
451
|
}
|
|
413
452
|
|
|
414
453
|
readIdent() {
|
|
415
|
-
|
|
416
|
-
while (this.pos < this.src.length
|
|
417
|
-
|
|
418
|
-
|
|
454
|
+
const start = this.pos;
|
|
455
|
+
while (this.pos < this.src.length) {
|
|
456
|
+
const code = this.src.charCodeAt(this.pos);
|
|
457
|
+
if (
|
|
458
|
+
(code >= 97 && code <= 122) ||
|
|
459
|
+
(code >= 65 && code <= 90) ||
|
|
460
|
+
(code >= 48 && code <= 57) ||
|
|
461
|
+
code === 95
|
|
462
|
+
) {
|
|
463
|
+
this.pos++;
|
|
464
|
+
} else {
|
|
465
|
+
break;
|
|
466
|
+
}
|
|
467
|
+
}
|
|
468
|
+
this.col += this.pos - start;
|
|
469
|
+
return this.src.slice(start, this.pos);
|
|
419
470
|
}
|
|
420
471
|
|
|
421
472
|
// ── Semicolon insertion ──────────────────────────────────────
|
package/src/lower/boxing.js
CHANGED
|
@@ -6,13 +6,7 @@ import { forEachChild } from "./walk.js";
|
|
|
6
6
|
export function isReferenceType(t) {
|
|
7
7
|
if (!t) return false;
|
|
8
8
|
const base = t.kind === "named" ? t.underlying : t;
|
|
9
|
-
return
|
|
10
|
-
base?.kind === "struct" ||
|
|
11
|
-
base?.kind === "slice" ||
|
|
12
|
-
base?.kind === "map" ||
|
|
13
|
-
base?.kind === "func" ||
|
|
14
|
-
base?.kind === "interface"
|
|
15
|
-
);
|
|
9
|
+
return base?.kind === "struct" || base?.kind === "func";
|
|
16
10
|
}
|
|
17
11
|
|
|
18
12
|
// Scan AST node for _addressTaken idents on scalars and populate a Set of boxed variable names.
|
package/src/lower/captures.js
CHANGED
|
@@ -2,7 +2,7 @@
|
|
|
2
2
|
// Identifies free variables captured by closures and determines which ones
|
|
3
3
|
// are mutated and thus require heap-allocated environment cells for WASM closures.
|
|
4
4
|
|
|
5
|
-
import { collectMutatedVars
|
|
5
|
+
import { collectMutatedVars } from "./ownership.js";
|
|
6
6
|
import { forEachChild } from "./walk.js";
|
|
7
7
|
|
|
8
8
|
/**
|
|
@@ -151,11 +151,7 @@ export function analyzeCaptures(fnDecl) {
|
|
|
151
151
|
result.capturesByClosure.set(node, captured);
|
|
152
152
|
|
|
153
153
|
for (const varName of captured) {
|
|
154
|
-
if (
|
|
155
|
-
mutatedVars.has(varName) ||
|
|
156
|
-
nodeMutatesVar(fnDecl.body, varName) ||
|
|
157
|
-
nodeMutatesVar(node.body, varName)
|
|
158
|
-
) {
|
|
154
|
+
if (mutatedVars.has(varName)) {
|
|
159
155
|
result.mutatedCaptures.add(varName);
|
|
160
156
|
}
|
|
161
157
|
}
|
package/src/lower/embedding.js
CHANGED
|
@@ -9,7 +9,8 @@ export function computeEmbeddedStubs(name, methodDecls, checker) {
|
|
|
9
9
|
const declared = new Set(methodDecls.map((m) => m.name));
|
|
10
10
|
const stubs = [];
|
|
11
11
|
|
|
12
|
-
for (const
|
|
12
|
+
for (const rawEmbed of resolvedType._embeds) {
|
|
13
|
+
const embed = rawEmbed.kind === "pointer" ? rawEmbed.base : rawEmbed;
|
|
13
14
|
const embedName = embed.kind === "named" ? embed.name : null;
|
|
14
15
|
if (!embedName) continue;
|
|
15
16
|
const embedBase = embed.kind === "named" ? embed.underlying : embed;
|