gofront 1.7.0 → 1.8.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 +13 -13
- package/package.json +8 -37
- package/src/backend/js/expressions.js +1341 -148
- package/src/backend/js/fmt-runtime.js +573 -0
- package/src/backend/js/index.js +375 -57
- package/src/backend/js/runtime.js +1460 -133
- package/src/backend/js/statements.js +900 -86
- package/src/backend/js/stdlib/bits.js +87 -14
- package/src/backend/js/stdlib/builder.js +41 -6
- package/src/backend/js/stdlib/bytes.js +253 -7
- package/src/backend/js/stdlib/errors.js +2 -1
- package/src/backend/js/stdlib/fmt.js +349 -10
- package/src/backend/js/stdlib/index.js +8 -3
- package/src/backend/js/stdlib/json.js +247 -52
- package/src/backend/js/stdlib/maps.js +0 -8
- package/src/backend/js/stdlib/math.js +17 -1
- package/src/backend/js/stdlib/simd.js +10 -0
- package/src/backend/js/stdlib/slices.js +36 -6
- package/src/backend/js/stdlib/strconv.js +10 -5
- package/src/backend/js/stdlib/strings.js +83 -4
- package/src/backend/js/stdlib/testing.js +7 -0
- package/src/backend/js/stdlib/time.js +79 -55
- package/src/backend/js/stdlib/unicode.js +1 -1
- package/src/backend/js/stdlib/utf8.js +1 -1
- package/src/backend/js/templ.js +38 -76
- package/src/backend/js/type-info.js +272 -0
- package/src/backend/shared/fmt-types.js +188 -0
- package/src/backend/wasm/boundary.js +436 -80
- package/src/backend/wasm/emit-builtins.js +303 -13
- package/src/backend/wasm/emit-exprs.js +1397 -203
- package/src/backend/wasm/emit-maps.js +61 -13
- package/src/backend/wasm/emit-stmts.js +1359 -164
- package/src/backend/wasm/emit.js +512 -77
- package/src/backend/wasm/encode.js +43 -13
- package/src/backend/wasm/globals.js +452 -0
- package/src/backend/wasm/index.js +194 -2489
- package/src/backend/wasm/method-expr.js +381 -0
- package/src/backend/wasm/module-emitter.js +2240 -0
- package/src/backend/wasm/monomorph.js +62 -4
- package/src/backend/wasm/prescan.js +397 -0
- package/src/backend/wasm/stdlib/bytes.js +1804 -127
- package/src/backend/wasm/stdlib/core.js +1574 -199
- package/src/backend/wasm/stdlib/index.js +0 -5
- package/src/backend/wasm/stdlib/io.js +1567 -150
- package/src/backend/wasm/stdlib/packages.js +2 -0
- package/src/backend/wasm/stdlib/simd.js +293 -28
- package/src/backend/wasm/stdlib/time.js +1041 -12
- package/src/backend/wasm/types.js +200 -15
- package/src/backend/wasm/variadic.js +93 -0
- package/src/backend/wasm/wat.js +47 -20
- package/src/{cli-core.js → cli/cli-core.js} +236 -10
- package/src/{test-runner.js → cli/test-runner.js} +332 -39
- package/src/{vendor.js → cli/vendor.js} +3 -4
- package/src/compiler.js +107 -269
- package/src/index.js +15 -169
- package/src/{lexer.js → lexer/lexer.js} +102 -55
- package/src/{tokens.js → lexer/tokens.js} +1 -0
- package/src/link/sourcemap.js +97 -0
- package/src/link/stdlib.js +515 -0
- package/src/link/wasm.js +294 -0
- package/src/lower/bounds.js +394 -0
- package/src/lower/boxing.js +1 -1
- package/src/lower/captures.js +176 -32
- package/src/lower/index.js +26 -18
- package/src/lower/json-codecs.js +1398 -0
- package/src/lower/ownership.js +22 -1
- package/src/lower/range.js +86 -1
- package/src/lower/reachability.js +132 -0
- package/src/parser/declarations.js +58 -13
- package/src/parser/expressions.js +29 -7
- package/src/parser/index.js +2 -1
- package/src/parser/statements.js +37 -22
- package/src/{templ-parser.js → parser/templ.js} +138 -15
- package/src/parser/types.js +69 -9
- package/src/resolver.js +22 -1
- package/src/typechecker/assignability.js +176 -17
- package/src/typechecker/const-fold.js +356 -0
- package/src/typechecker/constants.js +256 -0
- package/src/typechecker/expressions.js +931 -122
- package/src/typechecker/index.js +459 -67
- package/src/typechecker/init-order.js +330 -0
- package/src/typechecker/resolve.js +451 -56
- package/src/typechecker/statements.js +90 -9
- package/src/typechecker/stdlib/core.js +333 -55
- package/src/typechecker/stdlib/excluded.js +898 -0
- package/src/typechecker/stdlib/extended.js +322 -26
- package/src/typechecker/{stdlib.js → stdlib/index.js} +5 -5
- package/src/typechecker/stdlib/simd.js +65 -15
- package/src/typechecker/termination.js +1 -1
- package/src/typechecker/types.js +149 -25
- package/stdlib/bytes/iter.go +192 -0
- package/stdlib/bytes/search.go +240 -0
- package/stdlib/bytes/split.go +218 -0
- package/stdlib/cmp/cmp.go +65 -0
- package/stdlib/encoding/json/errors.go +31 -0
- package/stdlib/encoding/json/indent.go +71 -0
- package/stdlib/encoding/json/number.go +12 -0
- package/stdlib/encoding/json/stream.go +173 -0
- package/stdlib/errors/overlay.go +12 -0
- package/stdlib/hash/hash.go +53 -0
- package/stdlib/internal/jsonrt/dec.go +738 -0
- package/stdlib/internal/jsonrt/enc.go +366 -0
- package/stdlib/internal/jsonrt/indent.go +135 -0
- package/stdlib/internal/jsonrt/number.go +27 -0
- package/stdlib/internal/jsonrt/reader.go +73 -0
- package/stdlib/internal/jsonrt/scanner.go +649 -0
- package/stdlib/io/io.go +346 -0
- package/stdlib/iter/iter.go +18 -0
- package/stdlib/maps/iter.go +65 -0
- package/stdlib/math/extra.go +270 -0
- package/stdlib/slices/extra.go +73 -0
- package/stdlib/slices/iter.go +113 -0
- package/stdlib/sort/sort.go +561 -0
- package/stdlib/strconv/quote.go +341 -0
- package/stdlib/strings/extra.go +35 -0
- package/stdlib/strings/iter.go +122 -0
- package/stdlib/sync/extra.go +105 -0
- package/stdlib/unicode/unicode.go +112 -0
- package/stdlib/unicode/utf8/bytes.go +239 -0
- package/src/backend/wasm/const-fold.js +0 -205
- package/src/backend/wasm/emit-stdlib.js +0 -13
- /package/src/{asset-manager.js → cli/asset-manager.js} +0 -0
- /package/src/{colors.js → cli/colors.js} +0 -0
- /package/src/{dev-server.js → cli/dev-server.js} +0 -0
- /package/src/{minifier.js → cli/minifier.js} +0 -0
- /package/src/{project-config.js → cli/project-config.js} +0 -0
- /package/src/{pwa.js → cli/pwa.js} +0 -0
- /package/src/{templ-lexer.js → lexer/templ-lexer.js} +0 -0
|
@@ -0,0 +1,256 @@
|
|
|
1
|
+
// TypeChecker constant evaluation — installed as a mixin on TypeChecker.prototype.
|
|
2
|
+
//
|
|
3
|
+
// Every constant expression gets its exact value from the shared folder
|
|
4
|
+
// (src/typechecker/const-fold.js) and carries it on the AST node as `_const`, so
|
|
5
|
+
// both backends emit the same value. Typed constant overflow and constant
|
|
6
|
+
// division by zero are reported here.
|
|
7
|
+
|
|
8
|
+
import {
|
|
9
|
+
constFromLit,
|
|
10
|
+
constIntValue,
|
|
11
|
+
convertConst,
|
|
12
|
+
foldBinary,
|
|
13
|
+
foldMinMax,
|
|
14
|
+
foldUnary,
|
|
15
|
+
INT_RANGES,
|
|
16
|
+
intConst,
|
|
17
|
+
MATH_INT_CONSTS,
|
|
18
|
+
} from "./const-fold.js";
|
|
19
|
+
import { defaultType, isAny, typeStr, VOID } from "./types.js";
|
|
20
|
+
|
|
21
|
+
// Basic type names usable as conversion functions (`int32(x)`).
|
|
22
|
+
const BASIC_CONVERSIONS = new Set([
|
|
23
|
+
...Object.keys(INT_RANGES),
|
|
24
|
+
"float32",
|
|
25
|
+
"float64",
|
|
26
|
+
"string",
|
|
27
|
+
"bool",
|
|
28
|
+
]);
|
|
29
|
+
|
|
30
|
+
// Node kinds that can be constant expressions.
|
|
31
|
+
const CONST_KINDS = new Set([
|
|
32
|
+
"BasicLit",
|
|
33
|
+
"Ident",
|
|
34
|
+
"ParenExpr",
|
|
35
|
+
"UnaryExpr",
|
|
36
|
+
"BinaryExpr",
|
|
37
|
+
"CallExpr",
|
|
38
|
+
"TypeConversion",
|
|
39
|
+
"SelectorExpr",
|
|
40
|
+
]);
|
|
41
|
+
|
|
42
|
+
const NEGATIVE_SHIFT_ERROR = "invalid shift count: negative shift count";
|
|
43
|
+
|
|
44
|
+
/** @type {ThisType<import('./index.js').TypeChecker>} */
|
|
45
|
+
export const constantCheckMethods = {
|
|
46
|
+
// The value of a constant expression, or null when `expr` is not one (or
|
|
47
|
+
// is an overflowing or erroneous one).
|
|
48
|
+
_constValue(expr, scope = null) {
|
|
49
|
+
const raw = this._constRaw(expr, scope ?? this.globals);
|
|
50
|
+
return raw && !raw.overflow && !raw.error ? raw : null;
|
|
51
|
+
},
|
|
52
|
+
|
|
53
|
+
// Integer value of an integer (or untyped integral float) constant as a
|
|
54
|
+
// Number, or null.
|
|
55
|
+
_constIntValue(expr, scope = null) {
|
|
56
|
+
const v = this._constValue(expr, scope);
|
|
57
|
+
if (!v || (v.k === "FLOAT" && v.t)) return null;
|
|
58
|
+
const i = constIntValue(v);
|
|
59
|
+
return i === null ? null : Number(i);
|
|
60
|
+
},
|
|
61
|
+
|
|
62
|
+
// Raw evaluation result, memoized on checked nodes: a value, a value with
|
|
63
|
+
// `overflow`, `{ error }`, or null.
|
|
64
|
+
_constRaw(expr, scope) {
|
|
65
|
+
if (!expr || typeof expr !== "object" || !CONST_KINDS.has(expr.kind))
|
|
66
|
+
return null;
|
|
67
|
+
if (expr._constRaw !== undefined) return expr._constRaw;
|
|
68
|
+
if (expr._constBusy) return null; // cyclic constant
|
|
69
|
+
expr._constBusy = true;
|
|
70
|
+
let raw;
|
|
71
|
+
try {
|
|
72
|
+
raw = this._evalConst(expr, scope);
|
|
73
|
+
} catch (err) {
|
|
74
|
+
raw = { error: err.message };
|
|
75
|
+
} finally {
|
|
76
|
+
expr._constBusy = false;
|
|
77
|
+
}
|
|
78
|
+
// Conversions are only resolved once the node has been checked.
|
|
79
|
+
if (expr._type !== undefined) expr._constRaw = raw;
|
|
80
|
+
return raw;
|
|
81
|
+
},
|
|
82
|
+
|
|
83
|
+
// Called by checkExpr after typing `expr`: attaches `_const` and reports
|
|
84
|
+
// overflow / division by zero once per node.
|
|
85
|
+
_noteConst(expr, scope) {
|
|
86
|
+
if (!CONST_KINDS.has(expr.kind)) return;
|
|
87
|
+
const raw = this._constRaw(expr, scope);
|
|
88
|
+
expr._const = raw && !raw.overflow && !raw.error ? raw : null;
|
|
89
|
+
if (!raw || expr._constReported) return;
|
|
90
|
+
if (raw.error) {
|
|
91
|
+
expr._constReported = true;
|
|
92
|
+
// checkShiftCount already reports a negative count at its operand.
|
|
93
|
+
if (raw.error === NEGATIVE_SHIFT_ERROR) return;
|
|
94
|
+
this.err(raw.error, expr);
|
|
95
|
+
} else if (raw.overflow) {
|
|
96
|
+
expr._constReported = true;
|
|
97
|
+
this.err(`constant ${raw.v} overflows ${raw.typeName ?? raw.t}`, expr);
|
|
98
|
+
}
|
|
99
|
+
},
|
|
100
|
+
|
|
101
|
+
_evalConst(expr, scope) {
|
|
102
|
+
switch (expr.kind) {
|
|
103
|
+
case "BasicLit":
|
|
104
|
+
return constFromLit(expr);
|
|
105
|
+
case "ParenExpr":
|
|
106
|
+
return this._constValue(expr.expr, scope);
|
|
107
|
+
case "UnaryExpr": {
|
|
108
|
+
const x = this._constValue(expr.operand, scope);
|
|
109
|
+
return x ? foldUnary(expr.op, x) : null;
|
|
110
|
+
}
|
|
111
|
+
case "BinaryExpr": {
|
|
112
|
+
const a = this._constValue(expr.left, scope);
|
|
113
|
+
const b = a ? this._constValue(expr.right, scope) : null;
|
|
114
|
+
return a && b ? foldBinary(expr.op, a, b) : null;
|
|
115
|
+
}
|
|
116
|
+
case "Ident":
|
|
117
|
+
return this._evalConstIdent(expr, scope);
|
|
118
|
+
case "SelectorExpr":
|
|
119
|
+
return this._evalConstSelector(expr, scope);
|
|
120
|
+
case "TypeConversion": {
|
|
121
|
+
const v = this._constValue(expr.expr, scope);
|
|
122
|
+
const target = v ? this.resolveTypeNode(expr.targetType, scope) : null;
|
|
123
|
+
return target ? this._convertConstTo(v, target) : null;
|
|
124
|
+
}
|
|
125
|
+
default:
|
|
126
|
+
return this._evalConstCall(expr, scope);
|
|
127
|
+
}
|
|
128
|
+
},
|
|
129
|
+
|
|
130
|
+
_evalConstIdent(expr, scope) {
|
|
131
|
+
const owner = scope.lookupScope(expr.name);
|
|
132
|
+
if (!owner?._consts.has(expr.name)) return null;
|
|
133
|
+
const init = owner.lookupConstExpr(expr.name);
|
|
134
|
+
const v = init
|
|
135
|
+
? this._constValue(init, owner)
|
|
136
|
+
: (this._importedConsts?.get(expr.name) ?? null);
|
|
137
|
+
if (!v) return null;
|
|
138
|
+
const declared = owner.symbols.get(expr.name);
|
|
139
|
+
if (!declared || declared.kind === "untyped" || declared.kind === "any")
|
|
140
|
+
return v;
|
|
141
|
+
const typed = this._convertConstTo(v, declared);
|
|
142
|
+
return typed?.overflow ? null : typed;
|
|
143
|
+
},
|
|
144
|
+
|
|
145
|
+
// `pkg.K` (an imported GoFront package) and the integer `math` constants.
|
|
146
|
+
_evalConstSelector(expr, scope) {
|
|
147
|
+
if (expr.expr?.kind !== "Ident") return null;
|
|
148
|
+
const ns = scope.lookup(expr.expr.name);
|
|
149
|
+
if (ns?.kind !== "namespace") return null;
|
|
150
|
+
if (ns._gofront) return ns._consts?.get(expr.field) ?? null;
|
|
151
|
+
const m = ns.name === "math" ? MATH_INT_CONSTS[expr.field] : undefined;
|
|
152
|
+
return m === undefined ? null : intConst(m);
|
|
153
|
+
},
|
|
154
|
+
|
|
155
|
+
// Conversions, `len` of a constant string, and `min`/`max` of constants.
|
|
156
|
+
_evalConstCall(expr, scope) {
|
|
157
|
+
const target = this._constConversionTarget(expr, scope);
|
|
158
|
+
if (target) {
|
|
159
|
+
const v = this._constValue(expr.args[0], scope);
|
|
160
|
+
return v ? this._convertConstTo(v, target) : null;
|
|
161
|
+
}
|
|
162
|
+
const fn = expr.func;
|
|
163
|
+
if (fn?.kind !== "Ident" || scope.lookup(fn.name)?.kind !== "builtin")
|
|
164
|
+
return null;
|
|
165
|
+
const vals = (expr.args ?? []).map((a) => this._constValue(a, scope));
|
|
166
|
+
if (vals.length === 0 || vals.some((v) => !v)) return null;
|
|
167
|
+
if (fn.name === "min" || fn.name === "max")
|
|
168
|
+
return foldMinMax(fn.name === "min", vals);
|
|
169
|
+
// GoFront strings use UTF-16 code units on both backends.
|
|
170
|
+
const isLen = fn.name === "len" && vals[0].k === "STRING";
|
|
171
|
+
return isLen ? intConst(BigInt(vals[0].v.length)) : null;
|
|
172
|
+
},
|
|
173
|
+
|
|
174
|
+
// Target type of a conversion call (`MyInt(x)`, `int32(x)`), or null.
|
|
175
|
+
_constConversionTarget(expr, scope) {
|
|
176
|
+
if (expr.args?.length !== 1) return null;
|
|
177
|
+
if (expr._isTypeConversion) return expr._conversionTargetType ?? null;
|
|
178
|
+
const fn = expr.func;
|
|
179
|
+
if (fn?.kind !== "Ident" || !BASIC_CONVERSIONS.has(fn.name)) return null;
|
|
180
|
+
const owner = scope.lookupScope(fn.name);
|
|
181
|
+
return !owner || owner === this.universe
|
|
182
|
+
? { kind: "basic", name: fn.name }
|
|
183
|
+
: null;
|
|
184
|
+
},
|
|
185
|
+
|
|
186
|
+
// Converts a constant to Go type `t` (basic or named over a basic type).
|
|
187
|
+
_convertConstTo(v, t) {
|
|
188
|
+
const u = this.resolveType(t?.kind === "named" ? t.underlying : t);
|
|
189
|
+
if (u?.kind !== "basic") return null;
|
|
190
|
+
const r = convertConst(v, u.name);
|
|
191
|
+
return r?.overflow ? { ...r, typeName: typeStr(t) } : r;
|
|
192
|
+
},
|
|
193
|
+
|
|
194
|
+
// `var x int8 = 200`: an untyped integer constant must fit the target. An
|
|
195
|
+
// interface target takes the constant's default type (`var v any = 1 << 64`).
|
|
196
|
+
// A null `ctx` reports an operand converted to the other operand's type.
|
|
197
|
+
_checkConstOverflow(target, source, node, ctx) {
|
|
198
|
+
if (source?.kind !== "untyped" || !node?._const) return false;
|
|
199
|
+
const base = this.resolveType(
|
|
200
|
+
target?.kind === "named" ? target.underlying : target,
|
|
201
|
+
);
|
|
202
|
+
if (base?.kind === "interface" || isAny(base)) target = defaultType(source);
|
|
203
|
+
const i = constIntValue(node._const);
|
|
204
|
+
const range = i === null ? null : this._intRange(target);
|
|
205
|
+
if (!range) return false;
|
|
206
|
+
if (i >= range[0] && i <= range[1]) {
|
|
207
|
+
node._intConst = true; // the JS backend's precision warning reads this
|
|
208
|
+
return false;
|
|
209
|
+
}
|
|
210
|
+
const isInt = node._const.k === "INT";
|
|
211
|
+
const text = isInt ? String(i) : String(node._const.v);
|
|
212
|
+
const what = `untyped ${isInt ? "int" : "float"} constant`;
|
|
213
|
+
const shown =
|
|
214
|
+
node.kind === "BasicLit"
|
|
215
|
+
? `${node.value} (${what})`
|
|
216
|
+
: `${text} (${what} ${text})`;
|
|
217
|
+
this.err(
|
|
218
|
+
ctx
|
|
219
|
+
? `cannot use ${shown} as ${typeStr(target)} value in ${ctx} (overflows)`
|
|
220
|
+
: `${shown} overflows ${typeStr(target)}`,
|
|
221
|
+
node,
|
|
222
|
+
);
|
|
223
|
+
return true;
|
|
224
|
+
},
|
|
225
|
+
|
|
226
|
+
// `x := 1 << 63`, `println(1 << 64)`: the constant takes its default type.
|
|
227
|
+
_checkConstDefault(source, node, ctx) {
|
|
228
|
+
return this._checkConstOverflow(defaultType(source), source, node, ctx);
|
|
229
|
+
},
|
|
230
|
+
|
|
231
|
+
// print/println arguments take their default type.
|
|
232
|
+
_checkPrintArgs(name, expr, argTypes) {
|
|
233
|
+
for (let i = 0; i < expr.args.length; i++)
|
|
234
|
+
this._checkConstDefault(
|
|
235
|
+
argTypes[i],
|
|
236
|
+
expr.args[i],
|
|
237
|
+
`argument to built-in ${name}`,
|
|
238
|
+
);
|
|
239
|
+
return VOID;
|
|
240
|
+
},
|
|
241
|
+
|
|
242
|
+
// `x + 300` with `x int8`: the untyped operand is converted to the other
|
|
243
|
+
// operand's type.
|
|
244
|
+
_checkConstOperands(op, lt, rt, expr) {
|
|
245
|
+
if (op === "<<" || op === ">>" || op === "&&" || op === "||") return;
|
|
246
|
+
if (rt?.kind === "untyped" && lt?.kind !== "untyped")
|
|
247
|
+
this._checkConstOverflow(lt, rt, expr.right, null);
|
|
248
|
+
else if (lt?.kind === "untyped" && rt?.kind !== "untyped")
|
|
249
|
+
this._checkConstOverflow(rt, lt, expr.left, null);
|
|
250
|
+
},
|
|
251
|
+
|
|
252
|
+
_intRange(t) {
|
|
253
|
+
const u = this.resolveType(t?.kind === "named" ? t.underlying : t);
|
|
254
|
+
return u?.kind === "basic" ? (INT_RANGES[u.name] ?? null) : null;
|
|
255
|
+
},
|
|
256
|
+
};
|