gofront 1.8.0 → 1.9.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 +3 -3
- package/package.json +6 -5
- package/src/backend/js/expressions.js +1157 -408
- package/src/backend/js/index.js +327 -153
- package/src/backend/js/natives.js +383 -0
- package/src/backend/js/runtime.js +559 -2552
- package/src/backend/js/statements.js +670 -158
- package/src/backend/js/stdlib/index.js +45 -93
- package/src/backend/js/templ.js +32 -45
- package/src/backend/js/type-info.js +298 -19
- package/src/backend/shared/fixed-float.js +20 -0
- package/src/backend/shared/fmt-types.js +91 -170
- package/src/backend/shared/host-unicode.js +36 -0
- package/src/backend/wasm/boundary.js +490 -965
- package/src/backend/wasm/emit-builtins.js +884 -256
- package/src/backend/wasm/emit-exprs.js +185 -77
- package/src/backend/wasm/emit-maps.js +17 -367
- package/src/backend/wasm/emit-shared.js +4 -1
- package/src/backend/wasm/emit-stmts.js +524 -240
- package/src/backend/wasm/emit.js +176 -38
- package/src/backend/wasm/globals.js +48 -8
- package/src/backend/wasm/glue.js +2 -4
- package/src/backend/wasm/index.js +44 -530
- package/src/backend/wasm/method-expr.js +12 -1
- package/src/backend/wasm/module-emitter.js +299 -770
- package/src/backend/wasm/monomorph.js +139 -8
- package/src/backend/wasm/natives.js +600 -0
- package/src/backend/wasm/prescan.js +5 -153
- package/src/backend/wasm/prune-funcs.js +89 -0
- package/src/backend/wasm/stdlib/index.js +2 -32
- package/src/backend/wasm/types.js +97 -20
- package/src/backend/wasm/variadic.js +9 -4
- package/src/cli/cli-core.js +5 -1
- package/src/cli/test-runner.js +115 -342
- package/src/compiler.js +113 -130
- package/src/lexer/lexer.js +106 -11
- package/src/lexer/templ-lexer.js +61 -18
- package/src/lexer/tokens.js +1 -0
- package/src/link/stdlib.js +355 -132
- package/src/link/type-names.js +204 -0
- package/src/link/wasm.js +30 -6
- package/src/lower/bounds.js +153 -0
- package/src/lower/captures.js +92 -33
- package/src/lower/embedding.js +62 -5
- package/src/lower/errors-as.js +196 -0
- package/src/lower/fmt-formatters.js +929 -0
- package/src/lower/functions.js +225 -7
- package/src/lower/gen-types.js +293 -0
- package/src/lower/index.js +14 -2
- package/src/lower/json-codecs.js +334 -245
- package/src/lower/ownership.js +25 -7
- package/src/lower/reachability.js +69 -51
- package/src/lower/walk.js +12 -0
- package/src/parser/declarations.js +30 -5
- package/src/parser/expressions.js +111 -57
- package/src/parser/statements.js +108 -0
- package/src/parser/templ.js +44 -5
- package/src/parser/types.js +12 -0
- package/src/resolver.js +1 -2
- package/src/typechecker/assignability.js +214 -19
- package/src/typechecker/const-fold.js +70 -27
- package/src/typechecker/constants.js +156 -8
- package/src/typechecker/expressions.js +490 -108
- package/src/typechecker/index.js +346 -42
- package/src/typechecker/init-order.js +136 -40
- package/src/typechecker/operand-text.js +41 -0
- package/src/typechecker/resolve.js +490 -65
- package/src/typechecker/statements.js +288 -27
- package/src/typechecker/stdlib/excluded.js +9 -5
- package/src/typechecker/stdlib/index.js +25 -9
- package/src/typechecker/termination.js +10 -1
- package/src/typechecker/types.js +287 -575
- package/stdlib/bytes/buffer.go +479 -0
- package/stdlib/bytes/bytes.go +1010 -0
- package/stdlib/bytes/reader.go +161 -0
- package/stdlib/context/context.go +115 -0
- package/stdlib/crypto/rand/rand.go +34 -0
- package/stdlib/crypto/sha256/sha256.go +249 -0
- package/stdlib/encoding/base64/base64.go +331 -0
- package/stdlib/encoding/binary/binary.go +332 -0
- package/stdlib/encoding/hex/hex.go +140 -0
- package/stdlib/encoding/json/json.go +62 -0
- package/stdlib/errors/errors.go +174 -0
- package/stdlib/fmt/errors.go +110 -0
- package/stdlib/fmt/format.go +732 -0
- package/stdlib/fmt/print.go +1232 -0
- package/stdlib/gom/gom.go +293 -0
- package/stdlib/html/html.go +251 -0
- package/stdlib/internal/fmtrt/fmtrt.go +163 -0
- package/stdlib/internal/jsonrt/dec.go +171 -38
- package/stdlib/internal/jsonrt/enc.go +186 -36
- package/stdlib/internal/jsonrt/scanner.go +17 -8
- package/stdlib/io/io.go +157 -1
- package/stdlib/maps/maps.go +131 -0
- package/stdlib/math/bits/bits.go +507 -0
- package/stdlib/math/extra.go +16 -14
- package/stdlib/math/math.go +439 -0
- package/stdlib/math/rand/rand.go +297 -0
- package/stdlib/os/os.go +93 -0
- package/stdlib/path/filepath/filepath.go +47 -0
- package/stdlib/path/path.go +394 -0
- package/stdlib/regexp/regexp.go +231 -0
- package/stdlib/slices/slices.go +526 -0
- package/stdlib/slices/sort.go +209 -0
- package/stdlib/slices/zsort_cmp.go +480 -0
- package/stdlib/slices/zsort_ordered.go +482 -0
- package/stdlib/sort/sort.go +391 -452
- package/stdlib/sort/zsort_func.go +480 -0
- package/stdlib/sort/zsort_iface.go +480 -0
- package/stdlib/strconv/float.go +1699 -0
- package/stdlib/strconv/isprint.go +752 -0
- package/stdlib/strconv/quote.go +235 -50
- package/stdlib/strconv/strconv.go +616 -0
- package/stdlib/strings/builder.go +95 -0
- package/stdlib/strings/reader.go +163 -0
- package/stdlib/strings/replacer.go +102 -0
- package/stdlib/strings/strings.go +807 -0
- package/stdlib/sync/sync.go +268 -0
- package/stdlib/testing/async_js.go +61 -0
- package/stdlib/testing/benchmark.go +297 -0
- package/stdlib/testing/testing.go +523 -0
- package/stdlib/time/duration.go +233 -0
- package/stdlib/time/format.go +745 -0
- package/stdlib/time/parse.go +790 -0
- package/stdlib/time/sleep_js.go +63 -0
- package/stdlib/time/time.go +834 -0
- package/stdlib/unicode/unicode.go +141 -3
- package/stdlib/unicode/utf8/utf8.go +464 -0
- package/src/backend/js/fmt-runtime.js +0 -573
- package/src/backend/js/stdlib/base64.js +0 -12
- package/src/backend/js/stdlib/binary.js +0 -102
- package/src/backend/js/stdlib/bits.js +0 -119
- package/src/backend/js/stdlib/builder.js +0 -98
- package/src/backend/js/stdlib/bytes.js +0 -368
- package/src/backend/js/stdlib/errors.js +0 -45
- package/src/backend/js/stdlib/fmt.js +0 -517
- package/src/backend/js/stdlib/gom.js +0 -155
- package/src/backend/js/stdlib/hex.js +0 -17
- package/src/backend/js/stdlib/html.js +0 -20
- package/src/backend/js/stdlib/io.js +0 -137
- package/src/backend/js/stdlib/json.js +0 -1167
- package/src/backend/js/stdlib/maps.js +0 -37
- package/src/backend/js/stdlib/math.js +0 -85
- package/src/backend/js/stdlib/os.js +0 -13
- package/src/backend/js/stdlib/path.js +0 -48
- package/src/backend/js/stdlib/rand.js +0 -32
- package/src/backend/js/stdlib/regexp.js +0 -54
- package/src/backend/js/stdlib/sha256.js +0 -12
- package/src/backend/js/stdlib/shared.js +0 -17
- package/src/backend/js/stdlib/simd.js +0 -34
- package/src/backend/js/stdlib/slices.js +0 -107
- package/src/backend/js/stdlib/sort.js +0 -30
- package/src/backend/js/stdlib/strconv.js +0 -79
- package/src/backend/js/stdlib/strings.js +0 -301
- package/src/backend/js/stdlib/sync.js +0 -13
- package/src/backend/js/stdlib/testing.js +0 -41
- package/src/backend/js/stdlib/time.js +0 -152
- package/src/backend/js/stdlib/unicode.js +0 -25
- package/src/backend/js/stdlib/utf8.js +0 -26
- package/src/backend/wasm/stdlib/bytes.js +0 -6716
- package/src/backend/wasm/stdlib/core.js +0 -10278
- package/src/backend/wasm/stdlib/io.js +0 -3578
- package/src/backend/wasm/stdlib/packages.js +0 -2402
- package/src/backend/wasm/stdlib/pure.js +0 -720
- package/src/backend/wasm/stdlib/time.js +0 -2229
- package/src/typechecker/stdlib/core.js +0 -1079
- package/src/typechecker/stdlib/extended.js +0 -1210
- package/stdlib/bytes/iter.go +0 -192
- package/stdlib/bytes/search.go +0 -240
- package/stdlib/bytes/split.go +0 -218
- package/stdlib/errors/overlay.go +0 -12
- package/stdlib/maps/iter.go +0 -65
- package/stdlib/slices/extra.go +0 -73
- package/stdlib/slices/iter.go +0 -113
- package/stdlib/strings/extra.go +0 -35
- package/stdlib/strings/iter.go +0 -122
- package/stdlib/sync/extra.go +0 -105
- package/stdlib/unicode/utf8/bytes.go +0 -239
package/src/backend/js/index.js
CHANGED
|
@@ -20,67 +20,63 @@
|
|
|
20
20
|
import {
|
|
21
21
|
computeEmbeddedStubs,
|
|
22
22
|
hasDirectRecover,
|
|
23
|
-
isReferenceType,
|
|
24
23
|
markInBoundsIndexes,
|
|
24
|
+
markRedundantNilChecks,
|
|
25
25
|
normalizeDefers,
|
|
26
26
|
scanAddressTaken,
|
|
27
|
+
splitForwardedTuples,
|
|
28
|
+
takesElementAddress,
|
|
27
29
|
} from "../../lower/index.js";
|
|
28
30
|
import { orderPackageInits } from "../../typechecker/init-order.js";
|
|
29
31
|
import {
|
|
30
32
|
BROWSER_GLOBALS,
|
|
31
33
|
isComplex,
|
|
34
|
+
isMethodPromotedOverField,
|
|
32
35
|
isNumeric,
|
|
33
36
|
} from "../../typechecker/types.js";
|
|
34
|
-
import {
|
|
37
|
+
import { goTypeName } from "../shared/fmt-types.js";
|
|
38
|
+
import {
|
|
39
|
+
unicodeIsJs,
|
|
40
|
+
unicodeToLowerJs,
|
|
41
|
+
unicodeToUpperJs,
|
|
42
|
+
} from "../shared/host-unicode.js";
|
|
43
|
+
import {
|
|
44
|
+
comparesToNil,
|
|
45
|
+
derefsReceiverFirst,
|
|
46
|
+
expressionGenMethods,
|
|
47
|
+
} from "./expressions.js";
|
|
35
48
|
import {
|
|
36
49
|
HELPER_APPEND,
|
|
37
|
-
HELPER_BASE64,
|
|
38
|
-
HELPER_BINARY,
|
|
39
50
|
HELPER_BOUNDS,
|
|
40
51
|
HELPER_CDIV,
|
|
41
52
|
HELPER_CMUL,
|
|
42
|
-
HELPER_CRYPTO_RAND,
|
|
43
|
-
HELPER_DURATION,
|
|
44
53
|
HELPER_EQUAL,
|
|
45
54
|
HELPER_ERROR,
|
|
46
|
-
HELPER_ERROR_AS,
|
|
47
|
-
HELPER_ERROR_IS,
|
|
48
|
-
HELPER_ERROR_JOIN,
|
|
49
55
|
HELPER_GENERICS,
|
|
50
56
|
HELPER_GEQ,
|
|
51
|
-
HELPER_HEX,
|
|
52
57
|
HELPER_IFACE_BOX,
|
|
53
|
-
HELPER_IFD,
|
|
54
58
|
HELPER_IFEQ,
|
|
55
59
|
HELPER_INJECT_STYLES,
|
|
56
|
-
|
|
57
|
-
HELPER_JSON,
|
|
60
|
+
HELPER_JSONRT,
|
|
58
61
|
HELPER_LEN,
|
|
62
|
+
HELPER_MKLEN,
|
|
59
63
|
HELPER_NIL_CALL,
|
|
60
64
|
HELPER_NIL_MAP,
|
|
61
65
|
HELPER_NM,
|
|
62
|
-
HELPER_OS,
|
|
63
66
|
HELPER_PANIC,
|
|
64
|
-
HELPER_PATH_CLEAN,
|
|
65
|
-
HELPER_PATH_ERROR,
|
|
66
67
|
HELPER_PTREQ,
|
|
68
|
+
HELPER_PUSHS,
|
|
69
|
+
HELPER_RUNESTR,
|
|
67
70
|
HELPER_S,
|
|
68
71
|
HELPER_SCLONE,
|
|
69
|
-
HELPER_SHA256,
|
|
70
72
|
HELPER_SHIFT,
|
|
71
73
|
HELPER_SIMD,
|
|
72
74
|
HELPER_SLICE,
|
|
73
|
-
HELPER_SORT_SLICE,
|
|
74
|
-
HELPER_SPRINT,
|
|
75
|
-
HELPER_SPRINTF,
|
|
76
|
-
HELPER_STRCONV,
|
|
77
|
-
HELPER_STRCONV_ERROR,
|
|
78
75
|
HELPER_STRUCT_KEY,
|
|
79
76
|
HELPER_SV,
|
|
80
|
-
|
|
81
|
-
|
|
82
|
-
|
|
83
|
-
HELPER_TIME_PARSE,
|
|
77
|
+
HELPER_TO64,
|
|
78
|
+
HELPER_U8DEC,
|
|
79
|
+
HELPER_U8ENC,
|
|
84
80
|
HELPER_VA,
|
|
85
81
|
HELPER_VCLONE,
|
|
86
82
|
} from "./runtime.js";
|
|
@@ -142,15 +138,19 @@ const jsBindingName = (n) =>
|
|
|
142
138
|
// `this.useHelper(name)`; `_prependHelpers` emits every marked entry.
|
|
143
139
|
const HELPER_MAP = [
|
|
144
140
|
["len", HELPER_LEN],
|
|
141
|
+
["u8enc", HELPER_U8ENC],
|
|
142
|
+
["u8dec", HELPER_U8DEC],
|
|
145
143
|
["sv", HELPER_SV],
|
|
146
144
|
["slice", HELPER_SLICE],
|
|
145
|
+
["mklen", HELPER_MKLEN],
|
|
146
|
+
["runestr", HELPER_RUNESTR],
|
|
147
147
|
["append", HELPER_APPEND],
|
|
148
148
|
["sliceGuard", HELPER_S],
|
|
149
|
+
["pushs", HELPER_PUSHS],
|
|
149
150
|
["sclone", HELPER_SCLONE],
|
|
150
151
|
["va", HELPER_VA],
|
|
151
152
|
["vclone", HELPER_VCLONE],
|
|
152
153
|
["ifaceBox", HELPER_IFACE_BOX],
|
|
153
|
-
["ifd", HELPER_IFD],
|
|
154
154
|
["equal", HELPER_EQUAL],
|
|
155
155
|
["geq", HELPER_GEQ],
|
|
156
156
|
["ptreq", HELPER_PTREQ],
|
|
@@ -159,42 +159,87 @@ const HELPER_MAP = [
|
|
|
159
159
|
["cdiv", HELPER_CDIV],
|
|
160
160
|
["panicRt", HELPER_PANIC],
|
|
161
161
|
["shift", HELPER_SHIFT],
|
|
162
|
+
["to64", HELPER_TO64],
|
|
162
163
|
["nilCall", HELPER_NIL_CALL],
|
|
163
164
|
["bounds", HELPER_BOUNDS],
|
|
164
165
|
["nilMap", HELPER_NIL_MAP],
|
|
165
166
|
["nm", HELPER_NM],
|
|
166
167
|
["structKey", HELPER_STRUCT_KEY],
|
|
167
168
|
["generics", HELPER_GENERICS],
|
|
168
|
-
["sprintf", HELPER_SPRINTF],
|
|
169
|
-
["sprint", HELPER_SPRINT],
|
|
170
169
|
["error", HELPER_ERROR],
|
|
171
|
-
["
|
|
172
|
-
["errorAs", HELPER_ERROR_AS],
|
|
173
|
-
["errorJoin", HELPER_ERROR_JOIN],
|
|
174
|
-
["strconvError", HELPER_STRCONV_ERROR],
|
|
175
|
-
["pathError", HELPER_PATH_ERROR],
|
|
176
|
-
["ioEOF", HELPER_IO_EOF],
|
|
177
|
-
["os", HELPER_OS],
|
|
178
|
-
["strconv", HELPER_STRCONV],
|
|
179
|
-
["pathClean", HELPER_PATH_CLEAN],
|
|
180
|
-
["sortSlice", HELPER_SORT_SLICE],
|
|
181
|
-
["timeFmt", HELPER_TIME_FMT],
|
|
182
|
-
["timeParse", HELPER_TIME_PARSE],
|
|
183
|
-
["duration", HELPER_DURATION],
|
|
184
|
-
["testing", HELPER_TESTING],
|
|
185
|
-
["sync", HELPER_SYNC],
|
|
186
|
-
["cryptoRand", HELPER_CRYPTO_RAND],
|
|
187
|
-
["sha256", HELPER_SHA256],
|
|
188
|
-
["binary", HELPER_BINARY],
|
|
189
|
-
["hex", HELPER_HEX],
|
|
190
|
-
["base64", HELPER_BASE64],
|
|
191
|
-
["json", HELPER_JSON],
|
|
170
|
+
["jsonrt", HELPER_JSONRT],
|
|
192
171
|
["simd", HELPER_SIMD],
|
|
193
172
|
];
|
|
194
173
|
|
|
195
174
|
// JS bodies of `//gofront:intrinsic` functions (names: INTRINSICS in
|
|
196
175
|
// typechecker/types.js). The WASM backend keeps their empty body.
|
|
197
|
-
const JS_INTRINSICS = {
|
|
176
|
+
const JS_INTRINSICS = {
|
|
177
|
+
rand_source: () => "return Math.random();",
|
|
178
|
+
time_now: () =>
|
|
179
|
+
'return BigInt(Math.floor(typeof globalThis.__GOFRONT_CLOCK === "function" ? globalThis.__GOFRONT_CLOCK() : Date.now())) * 1000000n;',
|
|
180
|
+
time_sleep: ([ns]) =>
|
|
181
|
+
`await new Promise((r) => setTimeout(r, Number(${ns}) / 1000000));`,
|
|
182
|
+
time_zone_offset: ([unix]) =>
|
|
183
|
+
`return (-new Date(Number(${unix}) * 1000).getTimezoneOffset() * 60) | 0;`,
|
|
184
|
+
// os: node writes straight to the stream; other hosts print whole lines
|
|
185
|
+
// (console.log adds the newline), buffering the partial line.
|
|
186
|
+
os_write: ([fd, s]) =>
|
|
187
|
+
`if (typeof process !== "undefined" && process?.stdout?.write) { (${fd} === 2 && process.stderr?.write ? process.stderr : process.stdout).write(${s}); return; } let b = (globalThis.__os_buf ?? "") + ${s}; const nl = b.lastIndexOf("\\n"); if (nl >= 0) { (${fd} === 2 && typeof console.error === "function" ? console.error : console.log)(b.slice(0, nl)); b = b.slice(nl + 1); } globalThis.__os_buf = b;`,
|
|
188
|
+
os_exit: ([code]) =>
|
|
189
|
+
`if (typeof process !== "undefined" && process?.exit) process.exit(${code}); throw new Error("os.Exit(" + ${code} + ")");`,
|
|
190
|
+
os_getenv: ([key]) =>
|
|
191
|
+
`return (typeof process !== "undefined" && process?.env ? process.env : (globalThis.__os_env ??= {}))[${key}] ?? "";`,
|
|
192
|
+
os_setenv: ([key, value]) =>
|
|
193
|
+
`(typeof process !== "undefined" && process?.env ? process.env : (globalThis.__os_env ??= {}))[${key}] = ${value};`,
|
|
194
|
+
unicode_is: ([r, class_]) => unicodeIsJs(r, class_),
|
|
195
|
+
unicode_to_upper: ([r]) => unicodeToUpperJs(r),
|
|
196
|
+
unicode_to_lower: ([r]) => unicodeToLowerJs(r),
|
|
197
|
+
crypto_rand_u32: () =>
|
|
198
|
+
'const c = typeof crypto !== "undefined" ? crypto : globalThis.crypto; if (c?.getRandomValues) return c.getRandomValues(new Uint32Array(1))[0]; return Math.floor(Math.random() * 4294967296);',
|
|
199
|
+
// A number per object for the whole run, from 1 (pointers print as 0x<id>).
|
|
200
|
+
testing_nanotime: () => "return BigInt(Math.round(performance.now() * 1e6));",
|
|
201
|
+
testing_match: ([pattern, s]) =>
|
|
202
|
+
`const c = (globalThis.__testRe ??= new Map()); let re = c.get(${pattern}); if (!re) { re = new RegExp(${pattern}); c.set(${pattern}, re); } return re.test(${s});`,
|
|
203
|
+
testing_call: ([f, t]) =>
|
|
204
|
+
`const r = ${f}(${t}); return r && typeof r.then === "function" ? r : null;`,
|
|
205
|
+
fmt_ptr_id: ([v]) =>
|
|
206
|
+
`if (${v} === null || ${v} === undefined || (typeof ${v} !== "object" && typeof ${v} !== "function")) return 0n; const t = (globalThis.__fmtptr ??= { m: new WeakMap(), n: 1 }); let id = t.m.get(${v}); if (!id) { id = t.n++; t.m.set(${v}, id); } return BigInt(id);`,
|
|
207
|
+
math_float64bits: ([f]) =>
|
|
208
|
+
`const $b = new ArrayBuffer(8); new Float64Array($b)[0] = ${f}; return new BigUint64Array($b)[0];`,
|
|
209
|
+
math_float64frombits: ([u]) =>
|
|
210
|
+
`const $b = new ArrayBuffer(8); new BigUint64Array($b)[0] = BigInt(${u}); return new Float64Array($b)[0];`,
|
|
211
|
+
math_float32bits: ([f]) =>
|
|
212
|
+
`const $b = new ArrayBuffer(4); new Float32Array($b)[0] = ${f}; return new Uint32Array($b)[0];`,
|
|
213
|
+
math_float32frombits: ([u]) =>
|
|
214
|
+
`const $b = new ArrayBuffer(4); new Uint32Array($b)[0] = ${u} >>> 0; return new Float32Array($b)[0];`,
|
|
215
|
+
math_mod: ([x, y]) => `return ${x} % ${y};`,
|
|
216
|
+
...Object.fromEntries(
|
|
217
|
+
[
|
|
218
|
+
"sin",
|
|
219
|
+
"cos",
|
|
220
|
+
"tan",
|
|
221
|
+
"asin",
|
|
222
|
+
"acos",
|
|
223
|
+
"atan",
|
|
224
|
+
"sinh",
|
|
225
|
+
"cosh",
|
|
226
|
+
"tanh",
|
|
227
|
+
"exp",
|
|
228
|
+
"expm1",
|
|
229
|
+
"log",
|
|
230
|
+
"log1p",
|
|
231
|
+
"log2",
|
|
232
|
+
"log10",
|
|
233
|
+
"cbrt",
|
|
234
|
+
].map((f) => [`math_${f}`, ([x]) => `return Math.${f}(${x});`]),
|
|
235
|
+
),
|
|
236
|
+
...Object.fromEntries(
|
|
237
|
+
["atan2", "pow", "hypot"].map((f) => [
|
|
238
|
+
`math_${f}`,
|
|
239
|
+
([x, y]) => `return Math.${f}(${x}, ${y});`,
|
|
240
|
+
]),
|
|
241
|
+
),
|
|
242
|
+
};
|
|
198
243
|
|
|
199
244
|
export class CodeGen {
|
|
200
245
|
// jsImports: Map<importPath, string[]> — npm package imports to emit at top of file
|
|
@@ -209,6 +254,7 @@ export class CodeGen {
|
|
|
209
254
|
this.checker = checker;
|
|
210
255
|
this.target = options.target ?? "js";
|
|
211
256
|
this.strict = Boolean(options.strict || this.target === "both");
|
|
257
|
+
this.natives = options.natives !== false; // replace native calls with host code
|
|
212
258
|
this.out = [];
|
|
213
259
|
this.indent = 0;
|
|
214
260
|
this.structNames = new Set();
|
|
@@ -224,9 +270,9 @@ export class CodeGen {
|
|
|
224
270
|
this._srcMappings = []; // { genLine, srcLine, srcFileIdx } for source map
|
|
225
271
|
this._currentSrcFileIdx = 0; // updated as each top-level decl is generated
|
|
226
272
|
this._boxedVars = new Set(); // address-taken scalar variables that need boxing
|
|
227
|
-
this.
|
|
228
|
-
this.
|
|
229
|
-
this.
|
|
273
|
+
this._hoistedLocals = new Set(); // function-local classes the json codecs name
|
|
274
|
+
this._hasJsonCodecs = false;
|
|
275
|
+
this._jsonCodecFileIdx = -1;
|
|
230
276
|
// Runtime helper usage tracking — only emit helpers that are actually used
|
|
231
277
|
this._helpers = new Set();
|
|
232
278
|
// Per-function context for Go value semantics (see _withFnCtx)
|
|
@@ -328,10 +374,15 @@ export class CodeGen {
|
|
|
328
374
|
this._precisionWarned = new Set();
|
|
329
375
|
// Defer lowering (argument/receiver hoisting, recover-target marking) is
|
|
330
376
|
// idempotent and owned by the backends: the wasm path runs it via
|
|
331
|
-
// `lower()`, the JS path here.
|
|
377
|
+
// `lower()`, the JS path here. So is splitting multi-value calls
|
|
378
|
+
// forwarded into interfaces into temps.
|
|
379
|
+
splitForwardedTuples(program);
|
|
332
380
|
normalizeDefers(program);
|
|
333
381
|
// Strict mode: index checks the loop shape proves unnecessary are elided.
|
|
334
|
-
if (this.strict)
|
|
382
|
+
if (this.strict) {
|
|
383
|
+
markInBoundsIndexes(program);
|
|
384
|
+
markRedundantNilChecks(program, (d) => comparesToNil(d.body, d.recvName));
|
|
385
|
+
}
|
|
335
386
|
if (program._filename) this._srcFileNames = [program._filename];
|
|
336
387
|
// Ensure _pkgName is set on all decls (generateAll sets it for
|
|
337
388
|
// multi-file; for single-file compiles we derive it from the AST).
|
|
@@ -343,16 +394,22 @@ export class CodeGen {
|
|
|
343
394
|
}
|
|
344
395
|
}
|
|
345
396
|
this._renameReservedIdents(program.decls);
|
|
397
|
+
this._elemAddrTaken =
|
|
398
|
+
takesElementAddress(program.decls) ||
|
|
399
|
+
this.checker?.depElemAddrTaken === true;
|
|
346
400
|
this._boxedGlobals = this._collectBoxedGlobals(program);
|
|
347
401
|
this._boxedVars = new Set(this._boxedGlobals);
|
|
348
402
|
this._collectResliceNames(program);
|
|
349
|
-
this._jsonAnyUsed = this._usesJsonAnyMarshal(program.decls);
|
|
350
403
|
const methods = this._collectDecls(program);
|
|
351
404
|
this._emitJsImports();
|
|
352
405
|
this._emitTypeDecls(program, methods);
|
|
406
|
+
// Package variable initialisers may call functions that declare local
|
|
407
|
+
// structs, so the hoisted classes are declared before them.
|
|
408
|
+
const hoistedAt = this.out.length;
|
|
409
|
+
if (this._hasJsonCodecs) this.line("");
|
|
353
410
|
this._emitVarConstDecls(program);
|
|
354
411
|
const initNames = this._emitFuncDecls(program);
|
|
355
|
-
this.
|
|
412
|
+
this._emitHoistedLocals(hoistedAt);
|
|
356
413
|
this._callInitAndMain(initNames, program, isTest);
|
|
357
414
|
const prependedLines = this._prependHelpers(isTest);
|
|
358
415
|
return this._finalizeOutput(prependedLines);
|
|
@@ -467,6 +524,7 @@ export class CodeGen {
|
|
|
467
524
|
FuncLit: "_renameSignature",
|
|
468
525
|
TemplDecl: "_renameSignature",
|
|
469
526
|
TemplExpr: "_renameTemplExprNode",
|
|
527
|
+
TemplChildren: "_renameTemplExprNode",
|
|
470
528
|
TemplComponent: "_renameTemplExprNode",
|
|
471
529
|
TemplIf: "_renameTemplExprNode",
|
|
472
530
|
TemplSwitch: "_renameTemplExprNode",
|
|
@@ -535,13 +593,35 @@ export class CodeGen {
|
|
|
535
593
|
const name = d.recvType.name;
|
|
536
594
|
if (!methods.has(name)) methods.set(name, []);
|
|
537
595
|
methods.get(name).push(d);
|
|
538
|
-
if (d.recvPointer && comparesToNil(d.body, d.recvName))
|
|
539
|
-
this.nilSafeMethods.add(`${name}.${d.name}`);
|
|
540
596
|
}
|
|
541
597
|
}
|
|
598
|
+
this._markNilSafeMethods(methods);
|
|
542
599
|
return methods;
|
|
543
600
|
}
|
|
544
601
|
|
|
602
|
+
// Pointer-receiver methods that can run with a nil receiver: they compare
|
|
603
|
+
// it with nil, or do not read through it before anything could skip the
|
|
604
|
+
// read (a method that does panics on nil either way, so it keeps the
|
|
605
|
+
// faster direct call). Calls to these go through the prototype (see
|
|
606
|
+
// _nilSafeMethodClass).
|
|
607
|
+
_markNilSafeMethods(methods) {
|
|
608
|
+
for (const [name, decls] of methods) {
|
|
609
|
+
const safe = new Set();
|
|
610
|
+
const ptr = decls.filter((d) => d.recvPointer);
|
|
611
|
+
for (const d of ptr) safe.add(d.name);
|
|
612
|
+
for (let changed = true; changed; ) {
|
|
613
|
+
changed = false;
|
|
614
|
+
for (const d of ptr) {
|
|
615
|
+
if (!safe.has(d.name) || comparesToNil(d.body, d.recvName)) continue;
|
|
616
|
+
if (!derefsReceiverFirst(d.body?.stmts, d.recvName, safe)) continue;
|
|
617
|
+
safe.delete(d.name);
|
|
618
|
+
changed = true;
|
|
619
|
+
}
|
|
620
|
+
}
|
|
621
|
+
for (const m of safe) this.nilSafeMethods.add(`${name}.${m}`);
|
|
622
|
+
}
|
|
623
|
+
}
|
|
624
|
+
|
|
545
625
|
_collectNamedWrappers(program, methods) {
|
|
546
626
|
for (const d of program.decls) {
|
|
547
627
|
if (
|
|
@@ -567,37 +647,15 @@ export class CodeGen {
|
|
|
567
647
|
this._helpers.add(name);
|
|
568
648
|
if (name === "ifeq" || name === "geq") this._helpers.add("equal");
|
|
569
649
|
if (name === "geq") this._helpers.add("ifeq");
|
|
570
|
-
if (
|
|
571
|
-
name === "strconvError" ||
|
|
572
|
-
name === "pathError" ||
|
|
573
|
-
name === "ioEOF" ||
|
|
574
|
-
name === "base64" ||
|
|
575
|
-
name === "hex" ||
|
|
576
|
-
name === "json"
|
|
577
|
-
) {
|
|
578
|
-
this._helpers.add("error");
|
|
579
|
-
}
|
|
580
650
|
if (name === "json") {
|
|
581
|
-
this.useHelper("base64");
|
|
582
|
-
}
|
|
583
|
-
if (name === "os") {
|
|
584
|
-
this.useHelper("ioEOF");
|
|
585
651
|
this._helpers.add("error");
|
|
586
652
|
}
|
|
653
|
+
if (name === "panicRt") this._helpers.add("error");
|
|
587
654
|
if (name === "append") this.useHelper("slice");
|
|
588
|
-
if (name === "sprint") this._helpers.add("sprintf");
|
|
589
655
|
if (name === "slice") this._helpers.add("sv");
|
|
590
|
-
if (name === "binary") {
|
|
591
|
-
this.useHelper("ioEOF");
|
|
592
|
-
this._helpers.add("error");
|
|
593
|
-
}
|
|
594
656
|
}
|
|
595
657
|
|
|
596
|
-
_prependHelpers(
|
|
597
|
-
if (isTest || this._helpers.has("testing")) {
|
|
598
|
-
this.useHelper("sprintf");
|
|
599
|
-
this.useHelper("testing");
|
|
600
|
-
}
|
|
658
|
+
_prependHelpers(_isTest = false) {
|
|
601
659
|
const helpers = [];
|
|
602
660
|
if (this.collectedCss.length > 0) helpers.push(HELPER_INJECT_STYLES);
|
|
603
661
|
for (const [name, src] of HELPER_MAP) {
|
|
@@ -616,6 +674,8 @@ export class CodeGen {
|
|
|
616
674
|
// Annotates each decl with its source file index before merging.
|
|
617
675
|
generateAll(programs, options = {}) {
|
|
618
676
|
this._srcFileNames = programs.map((p) => p._filename ?? null);
|
|
677
|
+
this._jsonCodecFileIdx = programs.findIndex((p) => p._generated);
|
|
678
|
+
this._hasJsonCodecs = this._jsonCodecFileIdx >= 0;
|
|
619
679
|
for (let i = 0; i < programs.length; i++) {
|
|
620
680
|
for (const decl of programs[i].decls) {
|
|
621
681
|
decl._srcFileIdx = i;
|
|
@@ -632,8 +692,13 @@ export class CodeGen {
|
|
|
632
692
|
// Records a non-fatal diagnostic at `node` ("main.go at line 3:5: msg").
|
|
633
693
|
_warn(msg, node) {
|
|
634
694
|
const file = this._srcFileNames[this._currentSrcFileIdx ?? 0];
|
|
635
|
-
|
|
636
|
-
|
|
695
|
+
// Binary and unary expressions carry no position of their own: use the
|
|
696
|
+
// leftmost operand that does.
|
|
697
|
+
let pos = node;
|
|
698
|
+
while (pos && !(pos.line ?? pos._line))
|
|
699
|
+
pos = pos.left ?? pos.operand ?? pos.expr;
|
|
700
|
+
const line = pos?.line ?? pos?._line;
|
|
701
|
+
const at = line ? `at line ${line}:${pos.col ?? pos._col ?? 1}` : "";
|
|
637
702
|
const loc = [file, at].filter(Boolean).join(" ");
|
|
638
703
|
this.warnings.push(loc ? `${loc}: ${msg}` : msg);
|
|
639
704
|
}
|
|
@@ -646,14 +711,6 @@ export class CodeGen {
|
|
|
646
711
|
return this._srcMappings;
|
|
647
712
|
}
|
|
648
713
|
|
|
649
|
-
// Returns a source map JSON string for the last generate() call.
|
|
650
|
-
// sources: string[] of source filenames (relative to the output file).
|
|
651
|
-
// sourcesContent: string[] of original file contents (embedded for DevTools breakpoints).
|
|
652
|
-
getSourceMap(sources, sourcesContent) {
|
|
653
|
-
const srcArray = Array.isArray(sources) ? sources : [sources];
|
|
654
|
-
return buildSourceMap(srcArray, this._srcMappings, sourcesContent);
|
|
655
|
-
}
|
|
656
|
-
|
|
657
714
|
// ── Type declarations ────────────────────────────────────────
|
|
658
715
|
|
|
659
716
|
// `type S Base` with Base a struct declared in this package: the struct
|
|
@@ -665,15 +722,42 @@ export class CodeGen {
|
|
|
665
722
|
let t = decl.type;
|
|
666
723
|
for (let depth = 0; depth < 16 && t; depth++) {
|
|
667
724
|
if (t.kind === "StructType") return t;
|
|
725
|
+
// `type S Base[int]`: the fields come from the checked type.
|
|
726
|
+
if (t.kind === "GenericTypeName" || t.kind === "InstantiationExpr")
|
|
727
|
+
return { kind: "StructType", fields: [] };
|
|
668
728
|
if (t.kind !== "TypeName" && t.kind !== "Ident") return null;
|
|
669
729
|
const next = this._typeDeclsByName?.get(t.name);
|
|
670
|
-
if (!next
|
|
730
|
+
if (!next) return null;
|
|
671
731
|
t = next.type;
|
|
672
732
|
}
|
|
673
733
|
return null;
|
|
674
734
|
}
|
|
675
735
|
|
|
676
736
|
genTypeDeclWithMethods(decl, methodDecls) {
|
|
737
|
+
this._genTypeDeclBody(decl, methodDecls);
|
|
738
|
+
this._genUnhashableMark(decl.name);
|
|
739
|
+
}
|
|
740
|
+
|
|
741
|
+
// Marks a defined type Go cannot hash so `__ik` can name it in the panic
|
|
742
|
+
// of an interface-keyed map insert: a struct class carries `__uh`, a
|
|
743
|
+
// defined slice or map type registers its interface tag.
|
|
744
|
+
_genUnhashableMark(name) {
|
|
745
|
+
const t = this.checker?.types.get(name);
|
|
746
|
+
if (t?.kind !== "named" || t.typeParams?.length || t.typeArgs?.length)
|
|
747
|
+
return;
|
|
748
|
+
if (!this._isUnhashableType(t)) return;
|
|
749
|
+
const goName = JSON.stringify(goTypeName(t));
|
|
750
|
+
if (this.structNames.has(name)) {
|
|
751
|
+
this.line(
|
|
752
|
+
`Object.defineProperty(${name}, "__uh", { value: ${goName} });`,
|
|
753
|
+
);
|
|
754
|
+
} else if (this._isNamedComposite(t)) {
|
|
755
|
+
this.useHelper("structKey");
|
|
756
|
+
this.line(`__uht.set(${JSON.stringify(name)}, ${goName});`);
|
|
757
|
+
}
|
|
758
|
+
}
|
|
759
|
+
|
|
760
|
+
_genTypeDeclBody(decl, methodDecls) {
|
|
677
761
|
const definedStruct =
|
|
678
762
|
decl.type.kind === "StructType" ? null : this._definedStructAst(decl);
|
|
679
763
|
if (decl.type.kind === "StructType") {
|
|
@@ -715,6 +799,7 @@ export class CodeGen {
|
|
|
715
799
|
);
|
|
716
800
|
}
|
|
717
801
|
}
|
|
802
|
+
this._tagMultiUnwrap(methodDecls);
|
|
718
803
|
});
|
|
719
804
|
this.line("}");
|
|
720
805
|
// Box for *T in an interface. It also proxies `.value` to the pointer, so
|
|
@@ -732,10 +817,20 @@ export class CodeGen {
|
|
|
732
817
|
`${m.name}(...__a) { return ${name}.$${m.name}(${recv}, ...__a); }`,
|
|
733
818
|
);
|
|
734
819
|
}
|
|
820
|
+
this._tagMultiUnwrap(methodDecls);
|
|
735
821
|
});
|
|
736
822
|
this.line("}");
|
|
737
823
|
}
|
|
738
824
|
|
|
825
|
+
// `Unwrap() []error` on a box class is told apart from `Unwrap() error`
|
|
826
|
+
// in type tests, as on struct classes.
|
|
827
|
+
_tagMultiUnwrap(methodDecls) {
|
|
828
|
+
const unwrap = methodDecls.find(
|
|
829
|
+
(m) => m.name === "Unwrap" && m.returnType?.kind === "SliceType",
|
|
830
|
+
);
|
|
831
|
+
if (unwrap) this.line("static { this.prototype.Unwrap.__multi = true; }");
|
|
832
|
+
}
|
|
833
|
+
|
|
739
834
|
_namedBoxField(underlying) {
|
|
740
835
|
if (underlying?.kind === "func") return "_fn";
|
|
741
836
|
if (underlying?.kind === "map") return "_map";
|
|
@@ -776,8 +871,11 @@ export class CodeGen {
|
|
|
776
871
|
if (this.checker) {
|
|
777
872
|
const resolved = this.checker.types.get(name)?.underlying;
|
|
778
873
|
if (resolved?.kind === "struct") {
|
|
779
|
-
for (const [fName, fType] of resolved.fields.entries())
|
|
874
|
+
for (const [fName, fType] of resolved.fields.entries()) {
|
|
875
|
+
// A method promoted shallower shadows the deeper field.
|
|
876
|
+
if (isMethodPromotedOverField(resolved, fName)) continue;
|
|
780
877
|
fields.push({ name: fName, zero: this.zeroValueForType(fType) });
|
|
878
|
+
}
|
|
781
879
|
}
|
|
782
880
|
} else {
|
|
783
881
|
for (const f of structTypeAst.fields) {
|
|
@@ -797,8 +895,10 @@ export class CodeGen {
|
|
|
797
895
|
const fields = [];
|
|
798
896
|
// Cached per type name, so never bound to the current generic body.
|
|
799
897
|
this._withTypeParamZeros(null, () => {
|
|
800
|
-
for (const [name, type] of resolved.fields.entries())
|
|
898
|
+
for (const [name, type] of resolved.fields.entries()) {
|
|
899
|
+
if (isMethodPromotedOverField(resolved, name)) continue;
|
|
801
900
|
fields.push({ name, zero: this.zeroValueForType(type) });
|
|
901
|
+
}
|
|
802
902
|
});
|
|
803
903
|
this.structFields.set(typeName, fields);
|
|
804
904
|
return fields;
|
|
@@ -948,46 +1048,102 @@ export class CodeGen {
|
|
|
948
1048
|
`Object.defineProperty(${name}.prototype, "value", { get() { return this; }, set(v) { Object.assign(this, v); }, configurable: true });`,
|
|
949
1049
|
);
|
|
950
1050
|
}
|
|
951
|
-
this.
|
|
1051
|
+
this._genValueMethodMeta(name, methodDecls);
|
|
952
1052
|
}
|
|
953
1053
|
|
|
954
|
-
|
|
955
|
-
|
|
956
|
-
|
|
957
|
-
|
|
958
|
-
|
|
959
|
-
this.
|
|
960
|
-
|
|
1054
|
+
// Names of the value-receiver methods: a typed nil pointer in an interface
|
|
1055
|
+
// panics when one is called (see __mknil).
|
|
1056
|
+
_genValueMethodMeta(name, methodDecls) {
|
|
1057
|
+
const vm = methodDecls.filter((m) => !m.recvPointer).map((m) => m.name);
|
|
1058
|
+
if (vm.length > 0)
|
|
1059
|
+
this.line(
|
|
1060
|
+
`Object.defineProperty(${name}, "__vm", { value: ${JSON.stringify(vm)} });`,
|
|
1061
|
+
);
|
|
1062
|
+
// Pointer-receiver methods are outside the method set of a struct value
|
|
1063
|
+
// held in an interface (see _ifaceMethodCheck).
|
|
1064
|
+
const pm = methodDecls.filter((m) => m.recvPointer).map((m) => m.name);
|
|
1065
|
+
// ...and so are those promoted from an embedded struct value.
|
|
1066
|
+
for (const stub of computeEmbeddedStubs(name, methodDecls, this.checker))
|
|
1067
|
+
if (stub.ptrOnly) pm.push(stub.methodName);
|
|
1068
|
+
if (pm.length > 0)
|
|
1069
|
+
this.line(
|
|
1070
|
+
`Object.defineProperty(${name}, "__pm", { value: ${JSON.stringify(pm)} });`,
|
|
1071
|
+
);
|
|
1072
|
+
}
|
|
1073
|
+
|
|
1074
|
+
// The generated json codecs live at package level and name function-local
|
|
1075
|
+
// struct classes: those are declared once at module level and assigned
|
|
1076
|
+
// where the Go source declares them.
|
|
1077
|
+
_hoistLocalClass(stmt, start) {
|
|
1078
|
+
if (!this._hasJsonCodecs || stmt.type.kind !== "StructType") return;
|
|
1079
|
+
const open = this.out.findIndex(
|
|
1080
|
+
(l, i) => i >= start && l.trimStart().startsWith(`class ${stmt.name} `),
|
|
1081
|
+
);
|
|
1082
|
+
if (open < 0) return;
|
|
1083
|
+
const indent = this.out[open].match(/^\s*/)[0];
|
|
1084
|
+
const close = this.out.findIndex((l, i) => i > open && l === `${indent}}`);
|
|
1085
|
+
if (close < 0) return;
|
|
1086
|
+
this.out[open] =
|
|
1087
|
+
`${indent}${stmt.name} = ${stmt.name}.__ph ? ${this.out[open].trimStart()}`;
|
|
1088
|
+
this.out[close] = `${indent}} : ${stmt.name};`;
|
|
1089
|
+
this._hoistedLocals.add(stmt.name);
|
|
1090
|
+
}
|
|
1091
|
+
|
|
1092
|
+
_emitHoistedLocals(at) {
|
|
1093
|
+
if (this._hoistedLocals.size > 0 && this._hasJsonCodecs)
|
|
1094
|
+
this.out[at] =
|
|
1095
|
+
`var ${[...this._hoistedLocals].map((n) => `${n} = class { static __ph = true; }`).join(", ")};`;
|
|
961
1096
|
}
|
|
962
1097
|
|
|
963
1098
|
// A promoted method runs on the embedded value (`this.In`), so it and the
|
|
964
1099
|
// outer struct's promoted-field accesses see the same storage. Embedded
|
|
965
1100
|
// types that are not compiled Go structs keep the borrowed-`this` form.
|
|
966
|
-
_embedStub(
|
|
967
|
-
|
|
968
|
-
|
|
969
|
-
|
|
1101
|
+
_embedStub(
|
|
1102
|
+
method,
|
|
1103
|
+
embedName,
|
|
1104
|
+
valueEmbed = false,
|
|
1105
|
+
fieldName = null,
|
|
1106
|
+
nilPtrRecv = false,
|
|
1107
|
+
ifaceEmbed = false,
|
|
1108
|
+
) {
|
|
1109
|
+
// An embedded interface forwards to the interface value in its field.
|
|
1110
|
+
if (ifaceEmbed)
|
|
1111
|
+
return `${method}(...__a) { return this.${fieldName}.${method}(...__a); }`;
|
|
1112
|
+
// The field is named after the type without its package suffix
|
|
1113
|
+
// (`Mutex$$sync` is the field `Mutex`), or after the alias it embeds.
|
|
1114
|
+
const field = fieldName || embedName.replace(/\$\$.*$/, "");
|
|
1115
|
+
// A named non-struct type is boxed: its methods are static, taking
|
|
1116
|
+
// the value as the receiver.
|
|
1117
|
+
if (valueEmbed)
|
|
1118
|
+
return `${method}(...__a) { return ${embedName}.$${method}(this.${field}, ...__a); }`;
|
|
1119
|
+
const call = this._embedStubCall(method, embedName, field, nilPtrRecv);
|
|
970
1120
|
return `${method}(...__a) { return ${call}; }`;
|
|
971
1121
|
}
|
|
972
1122
|
|
|
973
|
-
|
|
974
|
-
|
|
975
|
-
|
|
976
|
-
|
|
977
|
-
|
|
978
|
-
|
|
979
|
-
|
|
980
|
-
|
|
981
|
-
this.line(this._embedStub(mName, embedName));
|
|
982
|
-
}
|
|
983
|
-
}
|
|
1123
|
+
_embedStubCall(method, embedName, field, nilPtrRecv) {
|
|
1124
|
+
if (!this.structNames.has(embedName))
|
|
1125
|
+
return `${embedName}.prototype.${method}.call(this, ...__a)`;
|
|
1126
|
+
// A nil embedded pointer still reaches a pointer-receiver method, as in
|
|
1127
|
+
// Go: call it through the prototype instead of reading it off null.
|
|
1128
|
+
return nilPtrRecv
|
|
1129
|
+
? `${embedName}.prototype.${method}.call(this.${field}, ...__a)`
|
|
1130
|
+
: `this.${field}.${method}(...__a)`;
|
|
984
1131
|
}
|
|
985
1132
|
|
|
986
1133
|
_genEmbeddedMethodStubs(name, methodDecls) {
|
|
987
1134
|
const stubs = computeEmbeddedStubs(name, methodDecls, this.checker);
|
|
988
1135
|
for (const stub of stubs) {
|
|
989
1136
|
this.blank();
|
|
990
|
-
this.line(
|
|
1137
|
+
this.line(
|
|
1138
|
+
this._embedStub(
|
|
1139
|
+
stub.methodName,
|
|
1140
|
+
stub.embedName,
|
|
1141
|
+
stub.valueEmbed,
|
|
1142
|
+
stub.fieldName,
|
|
1143
|
+
stub.nilPtrRecv,
|
|
1144
|
+
stub.ifaceEmbed,
|
|
1145
|
+
),
|
|
1146
|
+
);
|
|
991
1147
|
}
|
|
992
1148
|
}
|
|
993
1149
|
|
|
@@ -1252,47 +1408,65 @@ export class CodeGen {
|
|
|
1252
1408
|
return Boolean(info?.methods.get(method)?._ptrRecv);
|
|
1253
1409
|
}
|
|
1254
1410
|
|
|
1255
|
-
_isReferenceType(t) {
|
|
1256
|
-
return isReferenceType(t);
|
|
1257
|
-
}
|
|
1258
|
-
|
|
1259
1411
|
// ── Variable / const declarations ────────────────────────────
|
|
1260
1412
|
|
|
1261
1413
|
genVarDecl(decl) {
|
|
1262
1414
|
for (const spec of decl.decls) {
|
|
1263
|
-
if (spec.
|
|
1264
|
-
|
|
1265
|
-
|
|
1266
|
-
|
|
1267
|
-
|
|
1268
|
-
|
|
1269
|
-
|
|
1270
|
-
|
|
1271
|
-
|
|
1272
|
-
|
|
1273
|
-
|
|
1274
|
-
|
|
1275
|
-
|
|
1276
|
-
|
|
1277
|
-
|
|
1278
|
-
|
|
1279
|
-
|
|
1280
|
-
|
|
1281
|
-
|
|
1282
|
-
|
|
1283
|
-
|
|
1284
|
-
}
|
|
1285
|
-
|
|
1286
|
-
|
|
1287
|
-
|
|
1288
|
-
|
|
1289
|
-
|
|
1290
|
-
|
|
1415
|
+
if (spec._commaOk) this._genDefineStmt(this._varSpecAsDefine(spec));
|
|
1416
|
+
else if (spec.value) this._genVarSpecValues(spec);
|
|
1417
|
+
else this._genVarSpecZero(spec);
|
|
1418
|
+
}
|
|
1419
|
+
}
|
|
1420
|
+
|
|
1421
|
+
_genVarSpecValues(spec) {
|
|
1422
|
+
const paired = spec.value.length === spec.names.length;
|
|
1423
|
+
const vals = spec.value.map((v, i) => {
|
|
1424
|
+
const js = paired
|
|
1425
|
+
? this._genDeclValue(spec.names[i], v)
|
|
1426
|
+
: this.genExpr(v);
|
|
1427
|
+
// Wrap numeric values assigned to complex-typed vars
|
|
1428
|
+
if (spec.type?.name === "complex128" || spec.type?.name === "complex64") {
|
|
1429
|
+
if (
|
|
1430
|
+
!isComplex(v._type) &&
|
|
1431
|
+
!v._asComplex &&
|
|
1432
|
+
(isNumeric(v._type) || v._type?.kind === "untyped")
|
|
1433
|
+
) {
|
|
1434
|
+
return `{ re: ${js}, im: 0 }`;
|
|
1435
|
+
}
|
|
1436
|
+
}
|
|
1437
|
+
if (spec.type?.name === "int64" || spec.type?.name === "uint64") {
|
|
1438
|
+
if (
|
|
1439
|
+
v._type?.kind === "untyped" &&
|
|
1440
|
+
!js.endsWith("n") &&
|
|
1441
|
+
/^-?\d+$/.test(js)
|
|
1442
|
+
) {
|
|
1443
|
+
return `${js}n`;
|
|
1291
1444
|
}
|
|
1292
1445
|
}
|
|
1446
|
+
return js;
|
|
1447
|
+
});
|
|
1448
|
+
this._emitVarBindings(spec.names, vals, paired);
|
|
1449
|
+
}
|
|
1450
|
+
|
|
1451
|
+
_genVarSpecZero(spec) {
|
|
1452
|
+
const zero = spec.type ? this.zeroValueForTypeNode(spec.type) : "null";
|
|
1453
|
+
for (const name of spec.names) {
|
|
1454
|
+
if (name === "_") continue;
|
|
1455
|
+
this._markOwnership(name, true);
|
|
1456
|
+
const val = this._boxedVars.has(name) ? `{ value: ${zero} }` : zero;
|
|
1457
|
+
this.line(`let ${name} = ${val};`);
|
|
1293
1458
|
}
|
|
1294
1459
|
}
|
|
1295
1460
|
|
|
1461
|
+
// `var v, ok = m[k]` generates like `v, ok := m[k]`.
|
|
1462
|
+
_varSpecAsDefine(spec) {
|
|
1463
|
+
return {
|
|
1464
|
+
kind: "DefineStmt",
|
|
1465
|
+
lhs: spec.names.map((name) => ({ kind: "Ident", name })),
|
|
1466
|
+
rhs: spec.value,
|
|
1467
|
+
};
|
|
1468
|
+
}
|
|
1469
|
+
|
|
1296
1470
|
// `var a = v` / `var a, b = v1, v2` / `var a, b = f()`, boxing address-taken names.
|
|
1297
1471
|
_emitVarBindings(names, vals, paired) {
|
|
1298
1472
|
if (names.length === 1 && names[0] === "_") {
|