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
|
@@ -8,10 +8,9 @@
|
|
|
8
8
|
// (a constant may name one declared later).
|
|
9
9
|
//
|
|
10
10
|
// The checker reports cycles; both backends emit initialisers in this order.
|
|
11
|
-
// Shadowing
|
|
12
|
-
//
|
|
13
|
-
//
|
|
14
|
-
// invents a cycle.
|
|
11
|
+
// Shadowing follows Go's block scoping: a name declared by a parameter, result,
|
|
12
|
+
// receiver or statement hides the package-level one from the next statement to
|
|
13
|
+
// the end of its block, and not outside it.
|
|
15
14
|
|
|
16
15
|
function forEachChildNode(node, fn) {
|
|
17
16
|
for (const key of Object.keys(node)) {
|
|
@@ -21,34 +20,35 @@ function forEachChildNode(node, fn) {
|
|
|
21
20
|
}
|
|
22
21
|
}
|
|
23
22
|
|
|
24
|
-
//
|
|
25
|
-
|
|
26
|
-
|
|
27
|
-
|
|
28
|
-
|
|
29
|
-
return out;
|
|
23
|
+
// A lexical scope of locally declared names.
|
|
24
|
+
class Shadow {
|
|
25
|
+
constructor(parent = null) {
|
|
26
|
+
this.parent = parent;
|
|
27
|
+
this.names = new Set();
|
|
30
28
|
}
|
|
31
|
-
|
|
32
|
-
|
|
33
|
-
|
|
34
|
-
|
|
35
|
-
} else if (node.kind === "RangeStmt" || node.kind === "ForRangeStmt") {
|
|
36
|
-
for (const k of [node.key, node.value, node.keyVar, node.valueVar])
|
|
37
|
-
if (k?.kind === "Ident") out.add(k.name);
|
|
38
|
-
if (typeof node.key === "string") out.add(node.key);
|
|
39
|
-
if (typeof node.value === "string") out.add(node.value);
|
|
40
|
-
} else if (node.kind === "TypeSwitchStmt" && node.assign) {
|
|
41
|
-
out.add(node.assign);
|
|
29
|
+
|
|
30
|
+
has(name) {
|
|
31
|
+
for (let s = this; s; s = s.parent) if (s.names.has(name)) return true;
|
|
32
|
+
return false;
|
|
42
33
|
}
|
|
43
|
-
|
|
44
|
-
|
|
45
|
-
|
|
46
|
-
|
|
47
|
-
|
|
48
|
-
|
|
34
|
+
|
|
35
|
+
add(...names) {
|
|
36
|
+
for (const n of names) if (n) this.names.add(n);
|
|
37
|
+
}
|
|
38
|
+
}
|
|
39
|
+
|
|
40
|
+
// Names a function-like node declares for its body: receiver, parameters and
|
|
41
|
+
// named results.
|
|
42
|
+
function signatureNames(node) {
|
|
43
|
+
const out = [];
|
|
44
|
+
if (node.recvName) out.push(node.recvName);
|
|
45
|
+
for (const p of node.params ?? []) if (p?.name) out.push(p.name);
|
|
46
|
+
for (const r of node.returnType?._namedReturns ?? []) out.push(r.name);
|
|
49
47
|
return out;
|
|
50
48
|
}
|
|
51
49
|
|
|
50
|
+
const lhsName = (l) => (typeof l === "string" ? l : l?.name);
|
|
51
|
+
|
|
52
52
|
// The `Type.method` key of the declaration `name` selects on a value of type
|
|
53
53
|
// `t`, found the way the checker finds it: on the type itself, else on an
|
|
54
54
|
// embedded type (through pointers too). Interface methods have no body to
|
|
@@ -83,6 +83,60 @@ function litHasExprKeys(lit) {
|
|
|
83
83
|
return ["MapType", "SliceType", "ArrayType"].includes(lit.typeExpr?.kind);
|
|
84
84
|
}
|
|
85
85
|
|
|
86
|
+
// Statements that open a scope and declare names as they run. Each handler
|
|
87
|
+
// walks the node's children in order, adding declarations to `shadow` after
|
|
88
|
+
// the expressions that cannot see them.
|
|
89
|
+
const SCOPED = {
|
|
90
|
+
FuncDecl: walkFunc,
|
|
91
|
+
MethodDecl: walkFunc,
|
|
92
|
+
FuncLit: walkFunc,
|
|
93
|
+
Block: (node, shadow, ctx, out) =>
|
|
94
|
+
walkRefs(node.stmts, new Shadow(shadow), ctx, out),
|
|
95
|
+
DefineStmt: (node, shadow, ctx, out) => {
|
|
96
|
+
walkRefs(node.rhs, shadow, ctx, out);
|
|
97
|
+
shadow.add(...[node.lhs].flat().map(lhsName));
|
|
98
|
+
},
|
|
99
|
+
VarDecl: walkDeclSpecs,
|
|
100
|
+
ConstDecl: walkDeclSpecs,
|
|
101
|
+
IfStmt: (node, shadow, ctx, out) => {
|
|
102
|
+
const inner = new Shadow(shadow);
|
|
103
|
+
for (const c of [node.init, node.cond, node.body, node.elseBody])
|
|
104
|
+
walkRefs(c, inner, ctx, out);
|
|
105
|
+
},
|
|
106
|
+
ForStmt: (node, shadow, ctx, out) => {
|
|
107
|
+
const inner = new Shadow(shadow);
|
|
108
|
+
for (const c of [node.init, node.cond, node.post, node.body])
|
|
109
|
+
walkRefs(c, inner, ctx, out);
|
|
110
|
+
},
|
|
111
|
+
SwitchStmt: walkSwitch,
|
|
112
|
+
TypeSwitchStmt: walkSwitch,
|
|
113
|
+
};
|
|
114
|
+
|
|
115
|
+
function walkFunc(node, shadow, ctx, out) {
|
|
116
|
+
const inner = new Shadow(shadow);
|
|
117
|
+
inner.add(...signatureNames(node));
|
|
118
|
+
walkRefs(node.body, inner, ctx, out);
|
|
119
|
+
}
|
|
120
|
+
|
|
121
|
+
function walkDeclSpecs(node, shadow, ctx, out) {
|
|
122
|
+
for (const spec of node.decls ?? []) {
|
|
123
|
+
walkRefs(spec.value, shadow, ctx, out);
|
|
124
|
+
shadow.add(...(spec.names ?? []));
|
|
125
|
+
}
|
|
126
|
+
}
|
|
127
|
+
|
|
128
|
+
function walkSwitch(node, shadow, ctx, out) {
|
|
129
|
+
const inner = new Shadow(shadow);
|
|
130
|
+
walkRefs(node.init, inner, ctx, out);
|
|
131
|
+
walkRefs(node.tag ?? node.expr, inner, ctx, out);
|
|
132
|
+
for (const c of node.cases ?? []) {
|
|
133
|
+
const clause = new Shadow(inner);
|
|
134
|
+
if (node.assign) clause.add(node.assign);
|
|
135
|
+
walkRefs(c.list, clause, ctx, out);
|
|
136
|
+
walkRefs(c.stmts, clause, ctx, out);
|
|
137
|
+
}
|
|
138
|
+
}
|
|
139
|
+
|
|
86
140
|
function walkRefs(node, shadow, ctx, out) {
|
|
87
141
|
if (!node || typeof node !== "object") return;
|
|
88
142
|
if (Array.isArray(node)) {
|
|
@@ -90,10 +144,17 @@ function walkRefs(node, shadow, ctx, out) {
|
|
|
90
144
|
return;
|
|
91
145
|
}
|
|
92
146
|
if (node.kind === "Ident") {
|
|
93
|
-
|
|
147
|
+
// The blank identifier names nothing, whatever `var _` the package has.
|
|
148
|
+
if (
|
|
149
|
+
node.name !== "_" &&
|
|
150
|
+
ctx.pkgNames.has(node.name) &&
|
|
151
|
+
!shadow.has(node.name)
|
|
152
|
+
)
|
|
94
153
|
out.names.add(node.name);
|
|
95
154
|
return;
|
|
96
155
|
}
|
|
156
|
+
const scoped = SCOPED[node.kind];
|
|
157
|
+
if (scoped) return scoped(node, shadow, ctx, out);
|
|
97
158
|
if (node.kind === "SelectorExpr") {
|
|
98
159
|
const key = methodKeyOf(node.expr?._type, node.field, ctx.funcs);
|
|
99
160
|
if (key) out.methods.add(key);
|
|
@@ -118,11 +179,10 @@ function walkRefs(node, shadow, ctx, out) {
|
|
|
118
179
|
/**
|
|
119
180
|
* Collects what `root` (an initialiser expression or a function declaration)
|
|
120
181
|
* refers to: package-level names (`names`) and declarations selected as methods
|
|
121
|
-
* (`methods`, keyed `Type.method`)
|
|
122
|
-
* a name declared anywhere inside `root` never counts as the package-level one.
|
|
182
|
+
* (`methods`, keyed `Type.method`), honouring block-scoped shadowing.
|
|
123
183
|
*/
|
|
124
184
|
function collectRefs(root, ctx, out) {
|
|
125
|
-
walkRefs(root,
|
|
185
|
+
walkRefs(root, new Shadow(), ctx, out);
|
|
126
186
|
}
|
|
127
187
|
|
|
128
188
|
const emptyRefs = () => ({ names: new Set(), methods: new Set() });
|
|
@@ -261,24 +321,52 @@ function orderVars(varEntries, depsOf) {
|
|
|
261
321
|
return { vars, cycles: [] };
|
|
262
322
|
}
|
|
263
323
|
|
|
264
|
-
// Constants depend on other constants only
|
|
324
|
+
// Constants depend on other constants only; a constant that reaches itself is
|
|
325
|
+
// a cycle (reported once, at the constant where the walk closed it).
|
|
265
326
|
function orderConsts(constEntries) {
|
|
266
327
|
const constNames = new Set(constEntries.flatMap((e) => e.names));
|
|
267
328
|
const ctx = { pkgNames: constNames, funcs: new Map() };
|
|
268
329
|
const owner = new Map();
|
|
269
330
|
for (const e of constEntries) for (const n of e.names) owner.set(n, e);
|
|
270
331
|
const consts = [];
|
|
271
|
-
const
|
|
332
|
+
const cycles = [];
|
|
333
|
+
const state = new Map(); // entry -> 1 while on the walk's path, 2 when done
|
|
334
|
+
const path = [];
|
|
272
335
|
const visit = (e) => {
|
|
273
|
-
|
|
274
|
-
|
|
336
|
+
state.set(e, 1);
|
|
337
|
+
path.push(e);
|
|
275
338
|
const refs = emptyRefs();
|
|
276
339
|
for (const v of e.spec.value ?? []) collectRefs(v, ctx, refs);
|
|
277
|
-
for (const n of refs.names)
|
|
340
|
+
for (const n of refs.names) {
|
|
341
|
+
const dep = owner.get(n);
|
|
342
|
+
if (!dep) continue;
|
|
343
|
+
if (state.get(dep) === 1) {
|
|
344
|
+
const names = path.slice(path.indexOf(dep)).map((p) => p.names[0]);
|
|
345
|
+
const chain = names.length === 1 ? names : [...names, names[0]];
|
|
346
|
+
cycles.push({ spec: dep.spec, message: cycleMessage(dep, chain) });
|
|
347
|
+
} else if (!state.has(dep)) visit(dep);
|
|
348
|
+
}
|
|
349
|
+
path.pop();
|
|
350
|
+
state.set(e, 2);
|
|
278
351
|
consts.push(e);
|
|
279
352
|
};
|
|
280
|
-
for (const e of constEntries) visit(e);
|
|
281
|
-
return consts;
|
|
353
|
+
for (const e of constEntries) if (!state.has(e)) visit(e);
|
|
354
|
+
return { consts, cycles };
|
|
355
|
+
}
|
|
356
|
+
|
|
357
|
+
// A literal initialiser (or none: the zero value) reads nothing and has no
|
|
358
|
+
// effect, and gc initialises it statically, so a function that runs during
|
|
359
|
+
// another variable's initialiser sees it set even when it is declared later
|
|
360
|
+
// (an interface method call adds no dependency in the spec).
|
|
361
|
+
const isStaticValue = (v) =>
|
|
362
|
+
v?.kind === "BasicLit" ||
|
|
363
|
+
(v?.kind === "UnaryExpr" &&
|
|
364
|
+
["-", "+"].includes(v.op) &&
|
|
365
|
+
isStaticValue(v.operand));
|
|
366
|
+
|
|
367
|
+
function staticInitsFirst(vars) {
|
|
368
|
+
const isStatic = (e) => (e.spec.value ?? []).every(isStaticValue);
|
|
369
|
+
return [...vars.filter(isStatic), ...vars.filter((e) => !isStatic(e))];
|
|
282
370
|
}
|
|
283
371
|
|
|
284
372
|
/**
|
|
@@ -290,8 +378,16 @@ function orderConsts(constEntries) {
|
|
|
290
378
|
export function orderPackageInits(programs) {
|
|
291
379
|
const decls = collectDecls(programs);
|
|
292
380
|
const depsOf = buildVarDeps(decls);
|
|
293
|
-
const
|
|
294
|
-
|
|
381
|
+
const ordered = orderVars(decls.varEntries, depsOf);
|
|
382
|
+
const { cycles } = ordered;
|
|
383
|
+
const vars =
|
|
384
|
+
cycles.length === 0 ? staticInitsFirst(ordered.vars) : ordered.vars;
|
|
385
|
+
const constOrder = orderConsts(decls.constEntries);
|
|
386
|
+
return {
|
|
387
|
+
consts: constOrder.consts,
|
|
388
|
+
vars,
|
|
389
|
+
cycles: [...constOrder.cycles, ...cycles],
|
|
390
|
+
};
|
|
295
391
|
}
|
|
296
392
|
|
|
297
393
|
/**
|
|
@@ -0,0 +1,41 @@
|
|
|
1
|
+
// Source-like text of an expression for diagnostics ("cannot use y (variable
|
|
2
|
+
// of type float64) as int value"). Only the common shapes are printed in full;
|
|
3
|
+
// anything else falls back to "expression".
|
|
4
|
+
|
|
5
|
+
function litText(node) {
|
|
6
|
+
switch (node.litKind) {
|
|
7
|
+
case "STRING":
|
|
8
|
+
return JSON.stringify(node.value);
|
|
9
|
+
case "NIL":
|
|
10
|
+
return "nil";
|
|
11
|
+
default:
|
|
12
|
+
return String(node.value);
|
|
13
|
+
}
|
|
14
|
+
}
|
|
15
|
+
|
|
16
|
+
const PRINTERS = {
|
|
17
|
+
Ident: (n) => n.name,
|
|
18
|
+
BasicLit: litText,
|
|
19
|
+
ImagLit: (n) => `${n.value}i`,
|
|
20
|
+
ParenExpr: (n) => `(${exprText(n.expr)})`,
|
|
21
|
+
SelectorExpr: (n) => `${exprText(n.expr)}.${n.field}`,
|
|
22
|
+
UnaryExpr: (n) => `${n.op}${exprText(n.operand)}`,
|
|
23
|
+
BinaryExpr: (n) => `${exprText(n.left)} ${n.op} ${exprText(n.right)}`,
|
|
24
|
+
CallExpr: (n) =>
|
|
25
|
+
`${exprText(n.func)}(${(n.args ?? []).map(exprText).join(", ")})`,
|
|
26
|
+
IndexExpr: (n) => `${exprText(n.expr)}[${exprText(n.index)}]`,
|
|
27
|
+
};
|
|
28
|
+
|
|
29
|
+
export function exprText(node) {
|
|
30
|
+
const print = node && PRINTERS[node.kind];
|
|
31
|
+
return print ? print(node) : "expression";
|
|
32
|
+
}
|
|
33
|
+
|
|
34
|
+
// "variable of type float64", "untyped int constant", "value of type float64".
|
|
35
|
+
export function operandKind(node, typeName, isUntypedConst) {
|
|
36
|
+
if (isUntypedConst)
|
|
37
|
+
return `untyped ${typeName === "float64" ? "float" : typeName} constant`;
|
|
38
|
+
return node?.kind === "Ident"
|
|
39
|
+
? `variable of type ${typeName}`
|
|
40
|
+
: `value of type ${typeName}`;
|
|
41
|
+
}
|