gofront 1.3.12 → 1.5.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 +90 -20
- package/package.json +2 -1
- package/src/{codegen → backend/js}/expressions.js +217 -60
- package/src/{codegen → backend/js}/index.js +47 -36
- package/src/{codegen → backend/js}/runtime.js +11 -0
- package/src/{codegen → backend/js}/statements.js +43 -48
- package/src/backend/js/stdlib/bits.js +32 -0
- package/src/{codegen → backend/js}/stdlib/index.js +3 -0
- package/src/{codegen → backend/js}/templ.js +31 -2
- package/src/backend/wasm/boundary.js +1345 -0
- package/src/backend/wasm/emit.js +5779 -0
- package/src/backend/wasm/encode.js +789 -0
- package/src/backend/wasm/glue.js +130 -0
- package/src/backend/wasm/index.js +1413 -0
- package/src/backend/wasm/types.js +420 -0
- package/src/backend/wasm/wat.js +255 -0
- package/src/cli-core.js +52 -7
- package/src/compiler.js +328 -12
- package/src/dev-server.js +56 -15
- package/src/index.js +17 -9
- package/src/lexer.js +18 -0
- package/src/lower/boxing.js +36 -0
- package/src/lower/captures.js +179 -0
- package/src/lower/embedding.js +30 -0
- package/src/lower/escape.js +169 -0
- package/src/lower/functions.js +30 -0
- package/src/lower/globals.js +324 -0
- package/src/lower/index.js +115 -0
- package/src/lower/ownership.js +142 -0
- package/src/lower/range.js +70 -0
- package/src/minifier.js +2 -0
- package/src/parser/index.js +8 -3
- package/src/resolver.js +4 -1
- package/src/templ-lexer.js +107 -3
- package/src/templ-parser.js +29 -0
- package/src/test-runner.js +74 -20
- package/src/typechecker/expressions.js +40 -1
- package/src/typechecker/index.js +301 -6
- package/src/typechecker/statements.js +7 -0
- package/src/typechecker/stdlib/core.js +17 -0
- package/src/typechecker/types.js +56 -2
- /package/src/{codegen → backend/js}/source-map.js +0 -0
- /package/src/{codegen → backend/js}/stdlib/builder.js +0 -0
- /package/src/{codegen → backend/js}/stdlib/bytes.js +0 -0
- /package/src/{codegen → backend/js}/stdlib/errors.js +0 -0
- /package/src/{codegen → backend/js}/stdlib/fmt.js +0 -0
- /package/src/{codegen → backend/js}/stdlib/gom.js +0 -0
- /package/src/{codegen → backend/js}/stdlib/html.js +0 -0
- /package/src/{codegen → backend/js}/stdlib/io.js +0 -0
- /package/src/{codegen → backend/js}/stdlib/maps.js +0 -0
- /package/src/{codegen → backend/js}/stdlib/math.js +0 -0
- /package/src/{codegen → backend/js}/stdlib/os.js +0 -0
- /package/src/{codegen → backend/js}/stdlib/path.js +0 -0
- /package/src/{codegen → backend/js}/stdlib/rand.js +0 -0
- /package/src/{codegen → backend/js}/stdlib/regexp.js +0 -0
- /package/src/{codegen → backend/js}/stdlib/slices.js +0 -0
- /package/src/{codegen → backend/js}/stdlib/sort.js +0 -0
- /package/src/{codegen → backend/js}/stdlib/strconv.js +0 -0
- /package/src/{codegen → backend/js}/stdlib/strings.js +0 -0
- /package/src/{codegen → backend/js}/stdlib/testing.js +0 -0
- /package/src/{codegen → backend/js}/stdlib/time.js +0 -0
- /package/src/{codegen → backend/js}/stdlib/unicode.js +0 -0
- /package/src/{codegen → backend/js}/stdlib/utf8.js +0 -0
package/src/parser/index.js
CHANGED
|
@@ -114,6 +114,8 @@ export class Parser {
|
|
|
114
114
|
pkg,
|
|
115
115
|
imports,
|
|
116
116
|
decls,
|
|
117
|
+
target: this.tokens?.target ?? null,
|
|
118
|
+
_targetDirective: this.tokens?.targetDirective ?? null,
|
|
117
119
|
_filename: this.filename,
|
|
118
120
|
_source: this.source,
|
|
119
121
|
};
|
|
@@ -130,7 +132,9 @@ export class Parser {
|
|
|
130
132
|
this.expect(T.IMPORT);
|
|
131
133
|
const imports = [];
|
|
132
134
|
const parseOne = () => {
|
|
133
|
-
const
|
|
135
|
+
const tok = this.peek();
|
|
136
|
+
const _line = tok.line;
|
|
137
|
+
const _col = tok.col;
|
|
134
138
|
let alias = null;
|
|
135
139
|
if (this.check(T.IDENT)) {
|
|
136
140
|
alias = this.advance().value;
|
|
@@ -138,8 +142,9 @@ export class Parser {
|
|
|
138
142
|
alias = ".";
|
|
139
143
|
this.advance();
|
|
140
144
|
}
|
|
141
|
-
const
|
|
142
|
-
|
|
145
|
+
const pathTok = this.expect(T.STRING);
|
|
146
|
+
const path = pathTok.value;
|
|
147
|
+
return { path, alias, _line, _col, line: pathTok.line, col: pathTok.col };
|
|
143
148
|
};
|
|
144
149
|
if (this.match(T.LPAREN)) {
|
|
145
150
|
while (!this.check(T.RPAREN) && !this.check(T.EOF)) {
|
package/src/resolver.js
CHANGED
|
@@ -33,6 +33,7 @@ const BUILTIN_PACKAGES = new Set([
|
|
|
33
33
|
"strconv",
|
|
34
34
|
"sort",
|
|
35
35
|
"math",
|
|
36
|
+
"math/bits",
|
|
36
37
|
"math/rand",
|
|
37
38
|
"errors",
|
|
38
39
|
"time",
|
|
@@ -65,7 +66,9 @@ export function resolveGwDir(importPath, fromFile) {
|
|
|
65
66
|
const fromDir = dirname(resolve(fromFile));
|
|
66
67
|
const dir = resolve(fromDir, importPath);
|
|
67
68
|
if (!existsSync(dir)) return null;
|
|
68
|
-
const gwFiles = readdirSync(dir).filter(
|
|
69
|
+
const gwFiles = readdirSync(dir).filter(
|
|
70
|
+
(f) => f.endsWith(".go") || f.endsWith(".templ"),
|
|
71
|
+
);
|
|
69
72
|
return gwFiles.length > 0 ? dir : null;
|
|
70
73
|
}
|
|
71
74
|
|
package/src/templ-lexer.js
CHANGED
|
@@ -35,6 +35,8 @@ export const TT = {
|
|
|
35
35
|
TEMPL_CASE: "TEMPL_CASE", // case expr:
|
|
36
36
|
TEMPL_DEFAULT: "TEMPL_DEFAULT", // default:
|
|
37
37
|
TEMPL_END: "TEMPL_END", // closing } of if/for/switch/templ body
|
|
38
|
+
CSS_KW: "css",
|
|
39
|
+
CSS_BODY: "CSS_BODY",
|
|
38
40
|
};
|
|
39
41
|
|
|
40
42
|
// Describes a parsed HTML attribute
|
|
@@ -123,6 +125,13 @@ export class TemplLexer {
|
|
|
123
125
|
continue;
|
|
124
126
|
}
|
|
125
127
|
|
|
128
|
+
// Detect `css` keyword at identifier boundaries
|
|
129
|
+
if (this._matchKeyword("css")) {
|
|
130
|
+
this.tokens.push(new Token(TT.CSS_KW, "css", this.line, this.col));
|
|
131
|
+
this._lexCssDecl();
|
|
132
|
+
continue;
|
|
133
|
+
}
|
|
134
|
+
|
|
126
135
|
// Everything else: scan to end of top-level declaration using the
|
|
127
136
|
// raw Go lexer, accumulating tokens until the next `templ` keyword
|
|
128
137
|
// or EOF.
|
|
@@ -135,7 +144,7 @@ export class TemplLexer {
|
|
|
135
144
|
|
|
136
145
|
// ── Go chunk lexing ──────────────────────────────────────────
|
|
137
146
|
|
|
138
|
-
// Scan ahead to find the next `templ ` keyword at top level (not inside
|
|
147
|
+
// Scan ahead to find the next `templ ` or `css ` keyword at top level (not inside
|
|
139
148
|
// braces/parens/strings/comments). Collect all source text up to that
|
|
140
149
|
// point, lex it as normal Go, and append the tokens.
|
|
141
150
|
_lexGoChunk() {
|
|
@@ -143,8 +152,12 @@ export class TemplLexer {
|
|
|
143
152
|
let depth = 0; // brace depth
|
|
144
153
|
|
|
145
154
|
while (!this.eof()) {
|
|
146
|
-
// Check for `templ` keyword at top level (depth === 0)
|
|
147
|
-
if (
|
|
155
|
+
// Check for `templ` or `css` keyword at top level (depth === 0)
|
|
156
|
+
if (
|
|
157
|
+
depth === 0 &&
|
|
158
|
+
(this._peekKeyword("templ") || this._peekKeyword("css"))
|
|
159
|
+
)
|
|
160
|
+
break;
|
|
148
161
|
|
|
149
162
|
const ch = this.peek();
|
|
150
163
|
|
|
@@ -222,6 +235,97 @@ export class TemplLexer {
|
|
|
222
235
|
this._lexHtmlBody(1);
|
|
223
236
|
}
|
|
224
237
|
|
|
238
|
+
// ── CSS declaration lexing ───────────────────────────────────
|
|
239
|
+
|
|
240
|
+
_lexCssDecl() {
|
|
241
|
+
this.skipWhitespace();
|
|
242
|
+
|
|
243
|
+
// Name (identifier)
|
|
244
|
+
const nameStart = this.pos;
|
|
245
|
+
while (!this.eof() && /\w/.test(this.peek())) this.advance();
|
|
246
|
+
const name = this.src.slice(nameStart, this.pos);
|
|
247
|
+
if (!name) this.err("expected name after 'css'");
|
|
248
|
+
this.tokens.push(new Token(T.IDENT, name, this.line, this.col));
|
|
249
|
+
|
|
250
|
+
this.skipWhitespace();
|
|
251
|
+
|
|
252
|
+
// Parameter list (balanced parens)
|
|
253
|
+
if (this.peek() !== "(") this.err("expected '(' after css name");
|
|
254
|
+
const paramStart = this.pos;
|
|
255
|
+
this._skipBalanced("(", ")");
|
|
256
|
+
const paramSrc = this.src.slice(paramStart, this.pos);
|
|
257
|
+
for (const t of this._goTokens(paramSrc)) this.tokens.push(t);
|
|
258
|
+
|
|
259
|
+
this.skipWhitespace();
|
|
260
|
+
|
|
261
|
+
// Opening { of body
|
|
262
|
+
if (this.peek() !== "{") this.err("expected '{' after css params");
|
|
263
|
+
this.advance(); // consume {
|
|
264
|
+
this.tokens.push(new Token(T.LBRACE, "{", this.line, this.col));
|
|
265
|
+
|
|
266
|
+
this._lexCssBody();
|
|
267
|
+
}
|
|
268
|
+
|
|
269
|
+
_skipCssString(quote) {
|
|
270
|
+
this.advance(); // consume opening quote
|
|
271
|
+
while (!this.eof()) {
|
|
272
|
+
const ch = this.peek();
|
|
273
|
+
if (ch === "\\") {
|
|
274
|
+
this.advance();
|
|
275
|
+
if (!this.eof()) this.advance();
|
|
276
|
+
continue;
|
|
277
|
+
}
|
|
278
|
+
if (ch === quote) {
|
|
279
|
+
this.advance();
|
|
280
|
+
return;
|
|
281
|
+
}
|
|
282
|
+
if (ch === "\n") {
|
|
283
|
+
this.err("unterminated string in css block");
|
|
284
|
+
}
|
|
285
|
+
this.advance();
|
|
286
|
+
}
|
|
287
|
+
this.err("unterminated string in css block");
|
|
288
|
+
}
|
|
289
|
+
|
|
290
|
+
_lexCssBody() {
|
|
291
|
+
const start = this.pos;
|
|
292
|
+
let depth = 1;
|
|
293
|
+
while (!this.eof()) {
|
|
294
|
+
const ch = this.peek();
|
|
295
|
+
// Skip CSS comments /* ... */
|
|
296
|
+
if (ch === "/" && this.peek(1) === "*") {
|
|
297
|
+
this.advance();
|
|
298
|
+
this.advance();
|
|
299
|
+
this.skipBlockComment();
|
|
300
|
+
continue;
|
|
301
|
+
}
|
|
302
|
+
// Skip strings
|
|
303
|
+
if (ch === '"' || ch === "'") {
|
|
304
|
+
this._skipCssString(ch);
|
|
305
|
+
continue;
|
|
306
|
+
}
|
|
307
|
+
if (ch === "{") {
|
|
308
|
+
depth++;
|
|
309
|
+
this.advance();
|
|
310
|
+
} else if (ch === "}") {
|
|
311
|
+
depth--;
|
|
312
|
+
if (depth === 0) {
|
|
313
|
+
const cssText = this.src.slice(start, this.pos);
|
|
314
|
+
this.tokens.push(
|
|
315
|
+
new Token(TT.CSS_BODY, cssText, this.line, this.col),
|
|
316
|
+
);
|
|
317
|
+
this.advance(); // consume closing }
|
|
318
|
+
this.tokens.push(new Token(T.RBRACE, "}", this.line, this.col));
|
|
319
|
+
return;
|
|
320
|
+
}
|
|
321
|
+
this.advance();
|
|
322
|
+
} else {
|
|
323
|
+
this.advance();
|
|
324
|
+
}
|
|
325
|
+
}
|
|
326
|
+
this.err("unclosed css block");
|
|
327
|
+
}
|
|
328
|
+
|
|
225
329
|
// Lex the HTML body of a templ declaration.
|
|
226
330
|
// depth: current brace depth (starts at 1 for the opening { of templ)
|
|
227
331
|
_lexHtmlBody(depth) {
|
package/src/templ-parser.js
CHANGED
|
@@ -42,9 +42,38 @@ export class TemplParser extends Parser {
|
|
|
42
42
|
|
|
43
43
|
parseTopDecl() {
|
|
44
44
|
if (this.check(TT.TEMPL_KW)) return this.parseTemplDecl();
|
|
45
|
+
if (this.check(TT.CSS_KW)) return this.parseCssDecl();
|
|
45
46
|
return super.parseTopDecl();
|
|
46
47
|
}
|
|
47
48
|
|
|
49
|
+
// ── CssDecl ───────────────────────────────────────────────────
|
|
50
|
+
|
|
51
|
+
parseCssDecl() {
|
|
52
|
+
const _line = this.peek().line;
|
|
53
|
+
this.advance(); // consume CSS_KW
|
|
54
|
+
|
|
55
|
+
const name = this.expect(T.IDENT).value;
|
|
56
|
+
|
|
57
|
+
// Parse parameter list (standard Go params: LPAREN...RPAREN)
|
|
58
|
+
const params = this.parseParamList();
|
|
59
|
+
|
|
60
|
+
// Optional semicolon between ) and {
|
|
61
|
+
this.semi();
|
|
62
|
+
|
|
63
|
+
// Consume opening {
|
|
64
|
+
this.expect(T.LBRACE);
|
|
65
|
+
|
|
66
|
+
// Consume CSS_BODY
|
|
67
|
+
const bodyToken = this.expect(TT.CSS_BODY);
|
|
68
|
+
const cssText = bodyToken.value;
|
|
69
|
+
|
|
70
|
+
// Consume closing }
|
|
71
|
+
this.expect(T.RBRACE);
|
|
72
|
+
this.semi();
|
|
73
|
+
|
|
74
|
+
return { kind: "CssDecl", name, params, cssText, _line };
|
|
75
|
+
}
|
|
76
|
+
|
|
48
77
|
// ── TemplDecl ─────────────────────────────────────────────────
|
|
49
78
|
|
|
50
79
|
parseTemplDecl() {
|
package/src/test-runner.js
CHANGED
|
@@ -6,8 +6,13 @@ import { statSync } from "node:fs";
|
|
|
6
6
|
import { createRequire } from "node:module";
|
|
7
7
|
import { basename, dirname, join, resolve } from "node:path";
|
|
8
8
|
import { pathToFileURL } from "node:url";
|
|
9
|
+
import { HELPER_SPRINTF, HELPER_TESTING } from "./backend/js/runtime.js";
|
|
9
10
|
import { colorEnabled, createColors, formatDiagnostic } from "./colors.js";
|
|
10
|
-
import {
|
|
11
|
+
import {
|
|
12
|
+
compilePackageTests,
|
|
13
|
+
compilePackageTestsWasm,
|
|
14
|
+
gwFilesIn,
|
|
15
|
+
} from "./compiler.js";
|
|
11
16
|
|
|
12
17
|
export function isTestFunc(decl) {
|
|
13
18
|
if (decl.kind !== "FuncDecl") return false;
|
|
@@ -78,7 +83,16 @@ globalThis.document = globalThis.document ?? null;
|
|
|
78
83
|
`
|
|
79
84
|
}
|
|
80
85
|
globalThis.__gofront_verbose = ${verbose};
|
|
81
|
-
|
|
86
|
+
${
|
|
87
|
+
options.wasmBytes
|
|
88
|
+
? `
|
|
89
|
+
// ── WASM module (tests run inside app.wasm; *testing.T stays in JS) ──
|
|
90
|
+
${HELPER_SPRINTF}
|
|
91
|
+
${HELPER_TESTING}
|
|
92
|
+
globalThis.__GOFRONT_WASM_BYTES = Uint8Array.from(atob(${JSON.stringify(Buffer.from(options.wasmBytes).toString("base64"))}), (c) => c.charCodeAt(0));
|
|
93
|
+
`
|
|
94
|
+
: ""
|
|
95
|
+
}
|
|
82
96
|
// ── Compiled Package Bundle ──
|
|
83
97
|
${bundleJs}
|
|
84
98
|
// ─────────────────────────────
|
|
@@ -281,6 +295,44 @@ function spawnTestRunner(resolvedDir, harnessJs, testCount, options) {
|
|
|
281
295
|
});
|
|
282
296
|
}
|
|
283
297
|
|
|
298
|
+
function reportBuildFailure(err, resolvedDir, options) {
|
|
299
|
+
const msg = err?.message ?? String(err);
|
|
300
|
+
if (options.captureOutput) {
|
|
301
|
+
const out = `FAIL\t${basename(resolvedDir)} [build failed]\n${msg}\n`;
|
|
302
|
+
return { exitCode: 1, stdout: "", stderr: out };
|
|
303
|
+
}
|
|
304
|
+
const dest = options.stderr ?? process.stderr;
|
|
305
|
+
const c = colorsFor(options, dest);
|
|
306
|
+
dest.write(
|
|
307
|
+
`${c.bold(c.red("FAIL"))}\t${basename(resolvedDir)} ${c.red("[build failed]")}\n${formatDiagnostic(msg, c)}\n`,
|
|
308
|
+
);
|
|
309
|
+
return { exitCode: 1 };
|
|
310
|
+
}
|
|
311
|
+
|
|
312
|
+
// `both` packages run twice (JS and wasm) so the two backends are kept in
|
|
313
|
+
// agreement; output of both runs is concatenated.
|
|
314
|
+
async function runDualTarget(compiled, resolvedDir, runHarness, options) {
|
|
315
|
+
let wasmCompiled;
|
|
316
|
+
try {
|
|
317
|
+
wasmCompiled = compilePackageTestsWasm(resolvedDir, options);
|
|
318
|
+
} catch (err) {
|
|
319
|
+
return reportBuildFailure(err, resolvedDir, options);
|
|
320
|
+
}
|
|
321
|
+
const label = compiled.pkgName;
|
|
322
|
+
const jsRun = await runHarness(compiled.js, `${label} [js]`, null);
|
|
323
|
+
const wasmRun = await runHarness(
|
|
324
|
+
wasmCompiled.js,
|
|
325
|
+
`${label} [wasm]`,
|
|
326
|
+
wasmCompiled.wasm,
|
|
327
|
+
);
|
|
328
|
+
return {
|
|
329
|
+
exitCode: jsRun.exitCode !== 0 ? jsRun.exitCode : wasmRun.exitCode,
|
|
330
|
+
stdout: jsRun.stdout + wasmRun.stdout,
|
|
331
|
+
stderr: jsRun.stderr + wasmRun.stderr,
|
|
332
|
+
testCount: jsRun.testCount + wasmRun.testCount,
|
|
333
|
+
};
|
|
334
|
+
}
|
|
335
|
+
|
|
284
336
|
export async function runTests(targetDir, options = {}) {
|
|
285
337
|
let resolvedDir = resolve(targetDir);
|
|
286
338
|
try {
|
|
@@ -304,17 +356,7 @@ export async function runTests(targetDir, options = {}) {
|
|
|
304
356
|
try {
|
|
305
357
|
compiled = compilePackageTests(resolvedDir, options);
|
|
306
358
|
} catch (err) {
|
|
307
|
-
|
|
308
|
-
if (options.captureOutput) {
|
|
309
|
-
const out = `FAIL\t${basename(resolvedDir)} [build failed]\n${msg}\n`;
|
|
310
|
-
return { exitCode: 1, stdout: "", stderr: out };
|
|
311
|
-
}
|
|
312
|
-
const dest = options.stderr ?? process.stderr;
|
|
313
|
-
const c = colorsFor(options, dest);
|
|
314
|
-
dest.write(
|
|
315
|
-
`${c.bold(c.red("FAIL"))}\t${basename(resolvedDir)} ${c.red("[build failed]")}\n${formatDiagnostic(msg, c)}\n`,
|
|
316
|
-
);
|
|
317
|
-
return { exitCode: 1 };
|
|
359
|
+
return reportBuildFailure(err, resolvedDir, options);
|
|
318
360
|
}
|
|
319
361
|
|
|
320
362
|
const { pkgName, js, programs } = compiled;
|
|
@@ -324,12 +366,24 @@ export async function runTests(targetDir, options = {}) {
|
|
|
324
366
|
return reportEmptyTests(pkgName, "no tests to run", options);
|
|
325
367
|
}
|
|
326
368
|
|
|
327
|
-
const
|
|
328
|
-
|
|
329
|
-
|
|
330
|
-
|
|
331
|
-
|
|
332
|
-
|
|
369
|
+
const runHarness = (bundleJs, label, wasmBytes) =>
|
|
370
|
+
spawnTestRunner(
|
|
371
|
+
resolvedDir,
|
|
372
|
+
generateTestHarness(bundleJs, testNames, {
|
|
373
|
+
...options,
|
|
374
|
+
pkgName: label,
|
|
375
|
+
jsdomPath,
|
|
376
|
+
wasmBytes,
|
|
377
|
+
color: colorsFor(options, options.stdout ?? process.stdout).enabled,
|
|
378
|
+
}),
|
|
379
|
+
testNames.length,
|
|
380
|
+
options,
|
|
381
|
+
);
|
|
333
382
|
|
|
334
|
-
|
|
383
|
+
// `wasm` packages run inside the linked app.wasm; `js` packages that import
|
|
384
|
+
// wasm packages need the linked module too (hybrid packages).
|
|
385
|
+
if (compiled.target === "both") {
|
|
386
|
+
return runDualTarget(compiled, resolvedDir, runHarness, options);
|
|
387
|
+
}
|
|
388
|
+
return runHarness(js, pkgName, compiled.wasm ?? null);
|
|
335
389
|
}
|
|
@@ -3,6 +3,7 @@
|
|
|
3
3
|
import {
|
|
4
4
|
ANY,
|
|
5
5
|
BOOL,
|
|
6
|
+
BROWSER_GLOBALS,
|
|
6
7
|
COMPLEX128,
|
|
7
8
|
ERROR,
|
|
8
9
|
FLOAT64,
|
|
@@ -126,6 +127,26 @@ export const expressionCheckMethods = {
|
|
|
126
127
|
const t = scope.lookup(expr.name);
|
|
127
128
|
if (!t) return this.err(`Undefined: '${expr.name}'`, expr);
|
|
128
129
|
if (this.types.has(expr.name)) expr._isTypeRef = true;
|
|
130
|
+
if (
|
|
131
|
+
(this.target === "wasm" || this.target === "both") &&
|
|
132
|
+
BROWSER_GLOBALS.has(expr.name) &&
|
|
133
|
+
scope.lookup(expr.name) === this.globals.lookup(expr.name)
|
|
134
|
+
) {
|
|
135
|
+
this.recordBlocker("browser global", expr.name);
|
|
136
|
+
this.err(
|
|
137
|
+
`'${expr.name}' is not available in wasm packages`,
|
|
138
|
+
expr,
|
|
139
|
+
`(package '${this.pkgName}' is //gofront:target ${this.target} — browser globals are only available in js packages)`,
|
|
140
|
+
);
|
|
141
|
+
}
|
|
142
|
+
if (
|
|
143
|
+
(this.target === "wasm" || this.target === "both") &&
|
|
144
|
+
expr.name === "gom" &&
|
|
145
|
+
scope.lookup(expr.name) === this.globals.lookup(expr.name)
|
|
146
|
+
) {
|
|
147
|
+
this.recordBlocker("gom usage", "gom");
|
|
148
|
+
this.err("package 'gom' is not available in wasm packages", expr);
|
|
149
|
+
}
|
|
129
150
|
return t;
|
|
130
151
|
}
|
|
131
152
|
case "BinaryExpr": {
|
|
@@ -136,8 +157,16 @@ export const expressionCheckMethods = {
|
|
|
136
157
|
return this.binaryResultType(expr.op, ANY, ANY, expr);
|
|
137
158
|
return this.binaryResultType(expr.op, lt, rt, expr);
|
|
138
159
|
}
|
|
139
|
-
case "AwaitExpr":
|
|
160
|
+
case "AwaitExpr": {
|
|
161
|
+
if (this.target === "wasm" || this.target === "both") {
|
|
162
|
+
this.recordBlocker("async function");
|
|
163
|
+
this.err(
|
|
164
|
+
"async functions are not supported in wasm packages; keep async code in a js package",
|
|
165
|
+
expr,
|
|
166
|
+
);
|
|
167
|
+
}
|
|
140
168
|
return this.checkExpr(expr.expr, scope);
|
|
169
|
+
}
|
|
141
170
|
case "InstantiationExpr":
|
|
142
171
|
return this._checkInstantiationExpr(expr, scope);
|
|
143
172
|
default: {
|
|
@@ -280,6 +309,16 @@ export const expressionCheckMethods = {
|
|
|
280
309
|
},
|
|
281
310
|
|
|
282
311
|
_checkFuncLit(expr, scope) {
|
|
312
|
+
if (
|
|
313
|
+
(this.target === "wasm" || this.target === "both") &&
|
|
314
|
+
(expr.async || expr.isAsync)
|
|
315
|
+
) {
|
|
316
|
+
this.recordBlocker("async function");
|
|
317
|
+
this.err(
|
|
318
|
+
"async functions are not supported in wasm packages; keep async code in a js package",
|
|
319
|
+
expr,
|
|
320
|
+
);
|
|
321
|
+
}
|
|
283
322
|
const inner = new Scope(scope);
|
|
284
323
|
for (const p of expr.params)
|
|
285
324
|
inner.define(p.name, p.type ? this.resolveTypeNode(p.type, scope) : ANY);
|