gofront 1.5.1 → 1.6.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 +174 -466
- package/package.json +16 -20
- package/src/backend/js/expressions.js +288 -128
- package/src/backend/js/index.js +138 -56
- package/src/backend/js/runtime.js +1055 -53
- package/src/backend/js/source-map.js +32 -0
- package/src/backend/js/statements.js +151 -83
- 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 +22 -3
- package/src/backend/js/stdlib/fmt.js +95 -20
- 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 +19 -0
- package/src/backend/js/stdlib/io.js +105 -3
- package/src/backend/js/stdlib/maps.js +1 -1
- package/src/backend/js/stdlib/math.js +13 -1
- package/src/backend/js/stdlib/path.js +20 -6
- package/src/backend/js/stdlib/rand.js +10 -5
- package/src/backend/js/stdlib/sha256.js +12 -0
- package/src/backend/js/stdlib/shared.js +17 -0
- package/src/backend/js/stdlib/slices.js +53 -27
- package/src/backend/js/stdlib/sort.js +1 -1
- package/src/backend/js/stdlib/strconv.js +52 -11
- package/src/backend/js/stdlib/strings.js +152 -16
- package/src/backend/js/stdlib/sync.js +13 -0
- package/src/backend/js/stdlib/testing.js +2 -2
- package/src/backend/js/stdlib/time.js +93 -22
- package/src/backend/js/stdlib/unicode.js +2 -2
- package/src/backend/js/templ.js +1 -1
- package/src/backend/wasm/boundary.js +1677 -58
- package/src/backend/wasm/const-fold.js +205 -0
- package/src/backend/wasm/emit-builtins.js +1230 -0
- package/src/backend/wasm/emit-exprs.js +2096 -0
- package/src/backend/wasm/emit-maps.js +1999 -0
- package/src/backend/wasm/emit-shared.js +519 -0
- package/src/backend/wasm/emit-stdlib.js +13 -0
- package/src/backend/wasm/emit-stmts.js +2466 -0
- package/src/backend/wasm/emit.js +656 -5031
- package/src/backend/wasm/encode.js +259 -85
- package/src/backend/wasm/glue.js +19 -5
- package/src/backend/wasm/index.js +2432 -86
- package/src/backend/wasm/monomorph.js +711 -0
- package/src/backend/wasm/optimize.js +236 -0
- 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 +40 -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/time.js +1200 -0
- package/src/backend/wasm/types.js +312 -36
- package/src/backend/wasm/wat.js +49 -2
- package/src/cli-core.js +276 -73
- package/src/compiler.js +162 -25
- package/src/dts-parser.js +79 -126
- package/src/index.js +88 -121
- package/src/lexer.js +80 -29
- package/src/lower/boxing.js +4 -6
- package/src/lower/captures.js +12 -23
- package/src/lower/escape.js +4 -9
- package/src/lower/functions.js +277 -5
- package/src/lower/globals.js +7 -15
- package/src/lower/index.js +5 -2
- package/src/lower/ownership.js +35 -19
- package/src/lower/range.js +2 -5
- package/src/lower/walk.js +25 -0
- 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/types.js +1 -2
- package/src/resolver.js +3 -27
- package/src/templ-lexer.js +29 -63
- package/src/templ-parser.js +22 -45
- package/src/test-runner.js +20 -0
- package/src/typechecker/assignability.js +123 -14
- package/src/typechecker/expressions.js +244 -4
- package/src/typechecker/index.js +27 -1
- package/src/typechecker/resolve.js +71 -12
- package/src/typechecker/statements.js +0 -7
- package/src/typechecker/stdlib/core.js +292 -103
- package/src/typechecker/stdlib/extended.js +471 -4
- package/src/typechecker/stdlib/shared.js +53 -0
- package/src/typechecker/stdlib.js +2 -0
- package/src/typechecker/types.js +545 -8
- package/src/vendor.js +2 -2
package/src/backend/js/index.js
CHANGED
|
@@ -19,36 +19,53 @@
|
|
|
19
19
|
|
|
20
20
|
import {
|
|
21
21
|
computeEmbeddedStubs,
|
|
22
|
+
hasDirectRecover,
|
|
22
23
|
isReferenceType,
|
|
24
|
+
normalizeDefers,
|
|
23
25
|
scanAddressTaken,
|
|
24
26
|
} from "../../lower/index.js";
|
|
25
27
|
import { isComplex, isNumeric } from "../../typechecker/types.js";
|
|
26
28
|
import { expressionGenMethods } from "./expressions.js";
|
|
27
29
|
import {
|
|
28
30
|
HELPER_APPEND,
|
|
31
|
+
HELPER_BASE64,
|
|
32
|
+
HELPER_BINARY,
|
|
29
33
|
HELPER_CDIV,
|
|
30
34
|
HELPER_CMUL,
|
|
35
|
+
HELPER_CRYPTO_RAND,
|
|
36
|
+
HELPER_DURATION,
|
|
31
37
|
HELPER_EQUAL,
|
|
32
38
|
HELPER_ERROR,
|
|
39
|
+
HELPER_ERROR_AS,
|
|
33
40
|
HELPER_ERROR_IS,
|
|
41
|
+
HELPER_ERROR_JOIN,
|
|
42
|
+
HELPER_HEX,
|
|
34
43
|
HELPER_IFACE_BOX,
|
|
35
44
|
HELPER_INJECT_STYLES,
|
|
45
|
+
HELPER_IO_EOF,
|
|
36
46
|
HELPER_LEN,
|
|
47
|
+
HELPER_NIL_CALL,
|
|
48
|
+
HELPER_PANIC,
|
|
37
49
|
HELPER_PATH_CLEAN,
|
|
50
|
+
HELPER_PATH_ERROR,
|
|
38
51
|
HELPER_S,
|
|
39
52
|
HELPER_SCLONE,
|
|
53
|
+
HELPER_SHA256,
|
|
40
54
|
HELPER_SORT_SLICE,
|
|
41
55
|
HELPER_SPRINTF,
|
|
56
|
+
HELPER_STRCONV,
|
|
57
|
+
HELPER_STRCONV_ERROR,
|
|
58
|
+
HELPER_SYNC,
|
|
42
59
|
HELPER_TESTING,
|
|
43
60
|
HELPER_TIME_FMT,
|
|
44
61
|
HELPER_TIME_PARSE,
|
|
45
62
|
} from "./runtime.js";
|
|
46
|
-
import { buildSourceMap } from "./source-map.js";
|
|
63
|
+
import { buildSourceMap, buildWasmSourceMap } from "./source-map.js";
|
|
47
64
|
import { statementGenMethods } from "./statements.js";
|
|
48
65
|
import { stdlibGenMethods } from "./stdlib/index.js";
|
|
49
66
|
import { templGenMethods } from "./templ.js";
|
|
50
67
|
|
|
51
|
-
export { buildSourceMap };
|
|
68
|
+
export { buildSourceMap, buildWasmSourceMap };
|
|
52
69
|
|
|
53
70
|
// Valid Go identifiers that cannot be used as JS bindings; emitted with a `$` suffix.
|
|
54
71
|
const JS_RESERVED = new Set([
|
|
@@ -90,6 +107,42 @@ const JS_RESERVED = new Set([
|
|
|
90
107
|
const jsSafeName = (n) =>
|
|
91
108
|
typeof n === "string" && JS_RESERVED.has(n) ? `${n}$` : n;
|
|
92
109
|
|
|
110
|
+
// Runtime helpers by registry name, in output order. Mark one as needed with
|
|
111
|
+
// `this.useHelper(name)`; `_prependHelpers` emits every marked entry.
|
|
112
|
+
const HELPER_MAP = [
|
|
113
|
+
["len", HELPER_LEN],
|
|
114
|
+
["append", HELPER_APPEND],
|
|
115
|
+
["sliceGuard", HELPER_S],
|
|
116
|
+
["sclone", HELPER_SCLONE],
|
|
117
|
+
["ifaceBox", HELPER_IFACE_BOX],
|
|
118
|
+
["equal", HELPER_EQUAL],
|
|
119
|
+
["cmul", HELPER_CMUL],
|
|
120
|
+
["cdiv", HELPER_CDIV],
|
|
121
|
+
["panicRt", HELPER_PANIC],
|
|
122
|
+
["nilCall", HELPER_NIL_CALL],
|
|
123
|
+
["sprintf", HELPER_SPRINTF],
|
|
124
|
+
["error", HELPER_ERROR],
|
|
125
|
+
["errorIs", HELPER_ERROR_IS],
|
|
126
|
+
["errorAs", HELPER_ERROR_AS],
|
|
127
|
+
["errorJoin", HELPER_ERROR_JOIN],
|
|
128
|
+
["strconvError", HELPER_STRCONV_ERROR],
|
|
129
|
+
["pathError", HELPER_PATH_ERROR],
|
|
130
|
+
["ioEOF", HELPER_IO_EOF],
|
|
131
|
+
["strconv", HELPER_STRCONV],
|
|
132
|
+
["pathClean", HELPER_PATH_CLEAN],
|
|
133
|
+
["sortSlice", HELPER_SORT_SLICE],
|
|
134
|
+
["timeFmt", HELPER_TIME_FMT],
|
|
135
|
+
["timeParse", HELPER_TIME_PARSE],
|
|
136
|
+
["duration", HELPER_DURATION],
|
|
137
|
+
["testing", HELPER_TESTING],
|
|
138
|
+
["sync", HELPER_SYNC],
|
|
139
|
+
["cryptoRand", HELPER_CRYPTO_RAND],
|
|
140
|
+
["sha256", HELPER_SHA256],
|
|
141
|
+
["binary", HELPER_BINARY],
|
|
142
|
+
["hex", HELPER_HEX],
|
|
143
|
+
["base64", HELPER_BASE64],
|
|
144
|
+
];
|
|
145
|
+
|
|
93
146
|
export class CodeGen {
|
|
94
147
|
// jsImports: Map<importPath, string[]> — npm package imports to emit at top of file
|
|
95
148
|
// bundledPackages: Set<string> — GoFront package names bundled inline;
|
|
@@ -116,22 +169,7 @@ export class CodeGen {
|
|
|
116
169
|
this._currentSrcFileIdx = 0; // updated as each top-level decl is generated
|
|
117
170
|
this._boxedVars = new Set(); // address-taken scalar variables that need boxing
|
|
118
171
|
// Runtime helper usage tracking — only emit helpers that are actually used
|
|
119
|
-
this.
|
|
120
|
-
this._usesAppend = false;
|
|
121
|
-
this._usesSliceGuard = false;
|
|
122
|
-
this._usesSprintf = false;
|
|
123
|
-
this._usesEqual = false;
|
|
124
|
-
this._usesCmul = false;
|
|
125
|
-
this._usesCdiv = false;
|
|
126
|
-
this._usesError = false;
|
|
127
|
-
this._usesErrorIs = false;
|
|
128
|
-
this._usesPathClean = false;
|
|
129
|
-
this._usesSortSlice = false;
|
|
130
|
-
this._usesTimeFmt = false;
|
|
131
|
-
this._usesTimeParse = false;
|
|
132
|
-
this._usesTesting = false;
|
|
133
|
-
this._usesSClone = false;
|
|
134
|
-
this._usesIfaceBox = false;
|
|
172
|
+
this._helpers = new Set();
|
|
135
173
|
// Per-function context for Go value semantics (see _withFnCtx)
|
|
136
174
|
this._fnCtx = null;
|
|
137
175
|
// Iterator (range-over-func) context
|
|
@@ -217,6 +255,10 @@ export class CodeGen {
|
|
|
217
255
|
|
|
218
256
|
generate(program, options = {}) {
|
|
219
257
|
const isTest = options.isTest ?? false;
|
|
258
|
+
// Defer lowering (argument/receiver hoisting, recover-target marking) is
|
|
259
|
+
// idempotent and owned by the backends: the wasm path runs it via
|
|
260
|
+
// `lower()`, the JS path here.
|
|
261
|
+
normalizeDefers(program);
|
|
220
262
|
// Ensure _pkgName is set on all decls (generateAll sets it for
|
|
221
263
|
// multi-file; for single-file compiles we derive it from the AST).
|
|
222
264
|
const pkgName = program.pkg?.name;
|
|
@@ -407,28 +449,34 @@ export class CodeGen {
|
|
|
407
449
|
return methods;
|
|
408
450
|
}
|
|
409
451
|
|
|
452
|
+
/** Marks a runtime helper (key of HELPER_MAP) as needed by the output. */
|
|
453
|
+
useHelper(name) {
|
|
454
|
+
this._helpers.add(name);
|
|
455
|
+
if (
|
|
456
|
+
name === "strconvError" ||
|
|
457
|
+
name === "pathError" ||
|
|
458
|
+
name === "ioEOF" ||
|
|
459
|
+
name === "base64" ||
|
|
460
|
+
name === "hex"
|
|
461
|
+
) {
|
|
462
|
+
this._helpers.add("error");
|
|
463
|
+
}
|
|
464
|
+
if (name === "binary") {
|
|
465
|
+
this.useHelper("ioEOF");
|
|
466
|
+
this._helpers.add("error");
|
|
467
|
+
}
|
|
468
|
+
}
|
|
469
|
+
|
|
410
470
|
_prependHelpers(isTest = false) {
|
|
411
|
-
|
|
412
|
-
|
|
413
|
-
|
|
414
|
-
|
|
415
|
-
|
|
416
|
-
|
|
417
|
-
|
|
418
|
-
|
|
419
|
-
|
|
420
|
-
[this._usesCmul, HELPER_CMUL],
|
|
421
|
-
[this._usesCdiv, HELPER_CDIV],
|
|
422
|
-
[this._usesSprintf || needsTesting, HELPER_SPRINTF],
|
|
423
|
-
[this._usesError, HELPER_ERROR],
|
|
424
|
-
[this._usesErrorIs, HELPER_ERROR_IS],
|
|
425
|
-
[this._usesPathClean, HELPER_PATH_CLEAN],
|
|
426
|
-
[this._usesSortSlice, HELPER_SORT_SLICE],
|
|
427
|
-
[this._usesTimeFmt, HELPER_TIME_FMT],
|
|
428
|
-
[this._usesTimeParse, HELPER_TIME_PARSE],
|
|
429
|
-
[needsTesting, HELPER_TESTING],
|
|
430
|
-
];
|
|
431
|
-
const helpers = HELPER_MAP.filter(([flag]) => flag).map(([, h]) => h);
|
|
471
|
+
if (isTest || this._helpers.has("testing")) {
|
|
472
|
+
this.useHelper("sprintf");
|
|
473
|
+
this.useHelper("testing");
|
|
474
|
+
}
|
|
475
|
+
const helpers = [];
|
|
476
|
+
if (this.collectedCss.length > 0) helpers.push(HELPER_INJECT_STYLES);
|
|
477
|
+
for (const [name, src] of HELPER_MAP) {
|
|
478
|
+
if (this._helpers.has(name)) helpers.push(src);
|
|
479
|
+
}
|
|
432
480
|
if (helpers.length > 0) {
|
|
433
481
|
const helperLines = helpers.flatMap((h) => h.split("\n"));
|
|
434
482
|
helperLines.push("");
|
|
@@ -559,7 +607,7 @@ export class CodeGen {
|
|
|
559
607
|
.map((f) => `${f.name}: ${binding(f)} = ${f.zero}`)
|
|
560
608
|
.join(", ");
|
|
561
609
|
this.line(
|
|
562
|
-
`if (typeof ${first} === "object" && ${first} !== null && ${first}.constructor === Object) ({ ${pattern} } = ${first});`,
|
|
610
|
+
`if (arguments.length === 1 && typeof ${first} === "object" && ${first} !== null && ${first}.constructor === Object) ({ ${pattern} } = ${first});`,
|
|
563
611
|
);
|
|
564
612
|
}
|
|
565
613
|
for (const f of fields) {
|
|
@@ -661,7 +709,7 @@ export class CodeGen {
|
|
|
661
709
|
}
|
|
662
710
|
}
|
|
663
711
|
this._emitParamCopies(decl.params);
|
|
664
|
-
this._withNamedReturns(decl, () => this._genBody(decl.body));
|
|
712
|
+
this._withNamedReturns(decl, () => this._genBody(decl.body, decl));
|
|
665
713
|
}),
|
|
666
714
|
);
|
|
667
715
|
this._unwrappedRecv = prevUnwrapped;
|
|
@@ -718,7 +766,7 @@ export class CodeGen {
|
|
|
718
766
|
this._withFnCtx(decl.body, () =>
|
|
719
767
|
this.indented(() => {
|
|
720
768
|
this._emitParamCopies(decl.params);
|
|
721
|
-
this._withNamedReturns(decl, () => this._genBody(decl.body));
|
|
769
|
+
this._withNamedReturns(decl, () => this._genBody(decl.body, decl));
|
|
722
770
|
}),
|
|
723
771
|
);
|
|
724
772
|
this._boxedVars = prevBoxed;
|
|
@@ -726,45 +774,74 @@ export class CodeGen {
|
|
|
726
774
|
}
|
|
727
775
|
|
|
728
776
|
_withNamedReturns(decl, fn) {
|
|
777
|
+
const prevDecl = this._currentDecl;
|
|
778
|
+
this._currentDecl = decl;
|
|
729
779
|
const named = decl.returnType?._namedReturns;
|
|
730
780
|
const prev = this.namedReturnVars;
|
|
731
781
|
if (named) {
|
|
732
782
|
// Emit zero-value declarations for named return vars
|
|
733
|
-
for (
|
|
734
|
-
|
|
735
|
-
|
|
736
|
-
|
|
737
|
-
}
|
|
783
|
+
for (let i = 0; i < named.length; i++) {
|
|
784
|
+
const { name, type } = named[i];
|
|
785
|
+
const varName = !name || name === "_" ? `__ret_blank$${i}` : name;
|
|
786
|
+
this._markOwnership(varName, true);
|
|
787
|
+
this.line(`let ${varName} = ${this.zeroValueForTypeNode(type)};`);
|
|
738
788
|
}
|
|
739
|
-
this.namedReturnVars = named.map((r) =>
|
|
789
|
+
this.namedReturnVars = named.map((r, i) =>
|
|
790
|
+
!r.name || r.name === "_" ? `__ret_blank$${i}` : r.name,
|
|
791
|
+
);
|
|
740
792
|
} else {
|
|
741
793
|
this.namedReturnVars = null;
|
|
742
794
|
}
|
|
743
795
|
fn();
|
|
744
796
|
this.namedReturnVars = prev;
|
|
797
|
+
this._currentDecl = prevDecl;
|
|
745
798
|
}
|
|
746
799
|
|
|
747
800
|
// Emit a function body, wrapping in try/catch/finally for defer if needed.
|
|
748
|
-
|
|
801
|
+
// `fnNode` is the enclosing FuncDecl/MethodDecl/FuncLit; it decides whether
|
|
802
|
+
// the recover-arming prologue is needed (see HELPER_PANIC).
|
|
803
|
+
_genBody(body, fnNode = null) {
|
|
804
|
+
const prevRecoverOk = this._recoverOkInScope;
|
|
805
|
+
this._recoverOkInScope = false;
|
|
806
|
+
const isTarget = Boolean(fnNode?._isDeferTarget);
|
|
807
|
+
const forwards = isTarget && Boolean(fnNode._deferForward);
|
|
808
|
+
if (!forwards && (isTarget || hasDirectRecover(body))) {
|
|
809
|
+
this.useHelper("panicRt");
|
|
810
|
+
this.line(
|
|
811
|
+
"const __recoverOk = __gopanic.armed; __gopanic.armed = false;",
|
|
812
|
+
);
|
|
813
|
+
this._recoverOkInScope = true;
|
|
814
|
+
}
|
|
749
815
|
if (!body._hasDefer) {
|
|
750
816
|
this.genBlock(body);
|
|
817
|
+
this._recoverOkInScope = prevRecoverOk;
|
|
751
818
|
return;
|
|
752
819
|
}
|
|
820
|
+
this.useHelper("panicRt");
|
|
753
821
|
this.line("const __defers = [];");
|
|
754
|
-
this.line("
|
|
822
|
+
this.line("const __frame = { pn: null };");
|
|
755
823
|
this.line("try {");
|
|
756
824
|
this.indented(() => this.genBlock(body));
|
|
757
825
|
this.line("} catch (__err) {");
|
|
758
|
-
this.indented(() =>
|
|
826
|
+
this.indented(() => {
|
|
827
|
+
this.line("__frame.pn = { err: __err, recovered: false };");
|
|
828
|
+
this.line("__gopanic.stack.push(__frame.pn);");
|
|
829
|
+
});
|
|
759
830
|
this.line("} finally {");
|
|
760
831
|
this.indented(() => {
|
|
761
|
-
|
|
762
|
-
|
|
763
|
-
)
|
|
764
|
-
|
|
832
|
+
// Runs defers LIFO and rethrows an unrecovered panic.
|
|
833
|
+
this.line("__runDefers(__defers, __frame);");
|
|
834
|
+
if (this.namedReturnVars?.length > 0) {
|
|
835
|
+
const vars = this.namedReturnVars;
|
|
836
|
+
this.line(
|
|
837
|
+
vars.length === 1
|
|
838
|
+
? `return ${vars[0]};`
|
|
839
|
+
: `return [${vars.join(", ")}];`,
|
|
840
|
+
);
|
|
841
|
+
}
|
|
765
842
|
});
|
|
766
843
|
this.line("}");
|
|
767
|
-
// If a recover() cleared
|
|
844
|
+
// If a recover() cleared the panic, execution reaches here.
|
|
768
845
|
// Return named return vars so deferred mutations are visible to the caller.
|
|
769
846
|
if (this.namedReturnVars?.length > 0) {
|
|
770
847
|
const vars = this.namedReturnVars;
|
|
@@ -773,7 +850,12 @@ export class CodeGen {
|
|
|
773
850
|
? `return ${vars[0]};`
|
|
774
851
|
: `return [${vars.join(", ")}];`,
|
|
775
852
|
);
|
|
853
|
+
} else if (this._currentDecl?.returnType) {
|
|
854
|
+
this.line(
|
|
855
|
+
`return ${this.zeroValueForTypeNode(this._currentDecl.returnType)};`,
|
|
856
|
+
);
|
|
776
857
|
}
|
|
858
|
+
this._recoverOkInScope = prevRecoverOk;
|
|
777
859
|
}
|
|
778
860
|
|
|
779
861
|
// Scan AST node for _addressTaken idents on scalars and populate _boxedVars.
|