gofront 1.7.0 → 1.9.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 +14 -14
- package/package.json +10 -38
- package/src/backend/js/expressions.js +2060 -389
- package/src/backend/js/index.js +586 -174
- package/src/backend/js/natives.js +383 -0
- package/src/backend/js/runtime.js +936 -1644
- package/src/backend/js/statements.js +1349 -132
- package/src/backend/js/stdlib/index.js +51 -94
- package/src/backend/js/templ.js +67 -118
- package/src/backend/js/type-info.js +436 -0
- package/src/backend/shared/fixed-float.js +20 -0
- package/src/backend/shared/fmt-types.js +80 -0
- package/src/backend/shared/host-unicode.js +36 -0
- package/src/backend/wasm/boundary.js +753 -872
- package/src/backend/wasm/emit-builtins.js +914 -237
- package/src/backend/wasm/emit-exprs.js +1456 -195
- package/src/backend/wasm/emit-maps.js +78 -380
- package/src/backend/wasm/emit-stmts.js +1659 -214
- package/src/backend/wasm/emit.js +614 -88
- package/src/backend/wasm/encode.js +43 -13
- package/src/backend/wasm/globals.js +491 -0
- package/src/backend/wasm/glue.js +2 -4
- package/src/backend/wasm/index.js +406 -3195
- package/src/backend/wasm/method-expr.js +392 -0
- package/src/backend/wasm/module-emitter.js +1615 -0
- package/src/backend/wasm/monomorph.js +164 -9
- package/src/backend/wasm/natives.js +596 -0
- package/src/backend/wasm/prescan.js +249 -0
- package/src/backend/wasm/prune-funcs.js +89 -0
- package/src/backend/wasm/stdlib/index.js +2 -37
- package/src/backend/wasm/stdlib/simd.js +293 -28
- package/src/backend/wasm/types.js +260 -27
- 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} +241 -11
- package/src/{test-runner.js → cli/test-runner.js} +188 -122
- package/src/{vendor.js → cli/vendor.js} +3 -4
- package/src/compiler.js +202 -386
- package/src/index.js +15 -169
- package/src/{lexer.js → lexer/lexer.js} +203 -62
- package/src/{templ-lexer.js → lexer/templ-lexer.js} +61 -18
- package/src/{tokens.js → lexer/tokens.js} +2 -0
- package/src/link/sourcemap.js +97 -0
- package/src/link/stdlib.js +737 -0
- package/src/link/type-names.js +148 -0
- package/src/link/wasm.js +318 -0
- package/src/lower/bounds.js +547 -0
- package/src/lower/boxing.js +1 -1
- package/src/lower/captures.js +267 -64
- package/src/lower/embedding.js +32 -3
- package/src/lower/errors-as.js +196 -0
- package/src/lower/fmt-formatters.js +905 -0
- package/src/lower/functions.js +2 -0
- package/src/lower/gen-types.js +274 -0
- package/src/lower/index.js +33 -19
- package/src/lower/json-codecs.js +1379 -0
- package/src/lower/ownership.js +47 -8
- package/src/lower/range.js +86 -1
- package/src/lower/reachability.js +150 -0
- package/src/lower/walk.js +12 -0
- package/src/parser/declarations.js +83 -15
- package/src/parser/expressions.js +110 -18
- package/src/parser/index.js +2 -1
- package/src/parser/statements.js +38 -22
- package/src/{templ-parser.js → parser/templ.js} +179 -17
- package/src/parser/types.js +70 -9
- package/src/resolver.js +21 -1
- package/src/typechecker/assignability.js +291 -19
- package/src/typechecker/const-fold.js +399 -0
- package/src/typechecker/constants.js +282 -0
- package/src/typechecker/expressions.js +1220 -183
- package/src/typechecker/index.js +659 -92
- package/src/typechecker/init-order.js +426 -0
- package/src/typechecker/operand-text.js +40 -0
- package/src/typechecker/resolve.js +613 -62
- package/src/typechecker/statements.js +212 -20
- package/src/typechecker/stdlib/excluded.js +902 -0
- package/src/typechecker/stdlib/index.js +38 -0
- package/src/typechecker/stdlib/simd.js +65 -15
- package/src/typechecker/termination.js +11 -2
- package/src/typechecker/types.js +268 -514
- package/stdlib/bytes/buffer.go +479 -0
- package/stdlib/bytes/bytes.go +1010 -0
- package/stdlib/bytes/reader.go +161 -0
- package/stdlib/cmp/cmp.go +65 -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/errors.go +31 -0
- package/stdlib/encoding/json/indent.go +71 -0
- package/stdlib/encoding/json/json.go +62 -0
- package/stdlib/encoding/json/number.go +12 -0
- package/stdlib/encoding/json/stream.go +173 -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/hash/hash.go +53 -0
- package/stdlib/html/html.go +251 -0
- package/stdlib/internal/fmtrt/fmtrt.go +163 -0
- package/stdlib/internal/jsonrt/dec.go +871 -0
- package/stdlib/internal/jsonrt/enc.go +516 -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 +658 -0
- package/stdlib/io/io.go +502 -0
- package/stdlib/iter/iter.go +18 -0
- package/stdlib/maps/maps.go +131 -0
- package/stdlib/math/bits/bits.go +507 -0
- package/stdlib/math/extra.go +272 -0
- 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 +500 -0
- 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 +526 -0
- 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 +250 -0
- package/stdlib/unicode/utf8/utf8.go +464 -0
- 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 -46
- package/src/backend/js/stdlib/builder.js +0 -63
- package/src/backend/js/stdlib/bytes.js +0 -122
- package/src/backend/js/stdlib/errors.js +0 -44
- package/src/backend/js/stdlib/fmt.js +0 -178
- 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 -972
- package/src/backend/js/stdlib/maps.js +0 -45
- package/src/backend/js/stdlib/math.js +0 -69
- 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 -24
- package/src/backend/js/stdlib/slices.js +0 -77
- package/src/backend/js/stdlib/sort.js +0 -30
- package/src/backend/js/stdlib/strconv.js +0 -74
- package/src/backend/js/stdlib/strings.js +0 -222
- package/src/backend/js/stdlib/sync.js +0 -13
- package/src/backend/js/stdlib/testing.js +0 -34
- package/src/backend/js/stdlib/time.js +0 -128
- package/src/backend/js/stdlib/unicode.js +0 -25
- package/src/backend/js/stdlib/utf8.js +0 -26
- package/src/backend/wasm/const-fold.js +0 -205
- package/src/backend/wasm/emit-stdlib.js +0 -13
- package/src/backend/wasm/stdlib/bytes.js +0 -5039
- package/src/backend/wasm/stdlib/core.js +0 -8903
- package/src/backend/wasm/stdlib/io.js +0 -2161
- package/src/backend/wasm/stdlib/packages.js +0 -2400
- package/src/backend/wasm/stdlib/pure.js +0 -720
- package/src/backend/wasm/stdlib/time.js +0 -1200
- package/src/typechecker/stdlib/core.js +0 -801
- package/src/typechecker/stdlib/extended.js +0 -914
- package/src/typechecker/stdlib.js +0 -22
- /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/compiler.js
CHANGED
|
@@ -19,26 +19,42 @@
|
|
|
19
19
|
|
|
20
20
|
import { readdirSync, readFileSync, statSync } from "node:fs";
|
|
21
21
|
import { basename, dirname, join, relative, resolve, sep } from "node:path";
|
|
22
|
-
import {
|
|
23
|
-
buildSourceMap,
|
|
24
|
-
buildWasmSourceMap,
|
|
25
|
-
CodeGen,
|
|
26
|
-
} from "./backend/js/index.js";
|
|
22
|
+
import { CodeGen } from "./backend/js/index.js";
|
|
27
23
|
import { compileWasmModule, optimizeWasm } from "./backend/wasm/index.js";
|
|
28
|
-
import { log } from "./colors.js";
|
|
24
|
+
import { log } from "./cli/colors.js";
|
|
29
25
|
import { parseDts } from "./dts-parser.js";
|
|
30
|
-
import { Lexer } from "./lexer.js";
|
|
31
|
-
import {
|
|
26
|
+
import { Lexer } from "./lexer/lexer.js";
|
|
27
|
+
import { TemplLexer } from "./lexer/templ-lexer.js";
|
|
28
|
+
import {
|
|
29
|
+
attachSourceMap,
|
|
30
|
+
buildWasmMap,
|
|
31
|
+
mergeCompilationChunks,
|
|
32
|
+
WASM_MAP_URL,
|
|
33
|
+
} from "./link/sourcemap.js";
|
|
34
|
+
import {
|
|
35
|
+
checkGeneratedGo,
|
|
36
|
+
finishStdlibJs,
|
|
37
|
+
importStdlibPackages,
|
|
38
|
+
mangleCollidingTypes,
|
|
39
|
+
renameLocalTypes,
|
|
40
|
+
withOriginalTypeNames,
|
|
41
|
+
} from "./link/stdlib.js";
|
|
42
|
+
import {
|
|
43
|
+
linkIntoBundle,
|
|
44
|
+
registerPackageUnit,
|
|
45
|
+
wasmMarker,
|
|
46
|
+
} from "./link/wasm.js";
|
|
47
|
+
import { lower, takesElementAddress } from "./lower/index.js";
|
|
32
48
|
import { Parser } from "./parser/index.js";
|
|
49
|
+
import { TemplParser } from "./parser/templ.js";
|
|
33
50
|
import {
|
|
34
51
|
isBuiltinPackage,
|
|
35
52
|
isLocalPath,
|
|
36
53
|
resolveAll,
|
|
37
54
|
resolveGwDir,
|
|
55
|
+
resolveStdlibSource,
|
|
38
56
|
} from "./resolver.js";
|
|
39
|
-
import {
|
|
40
|
-
import { TemplParser } from "./templ-parser.js";
|
|
41
|
-
import { TypeCheckError, TypeChecker } from "./typechecker/index.js";
|
|
57
|
+
import { EXCLUDED_STDLIB_PACKAGES, TypeChecker } from "./typechecker/index.js";
|
|
42
58
|
import { WASM_SUPPORTED_STDLIB } from "./typechecker/types.js";
|
|
43
59
|
|
|
44
60
|
// ── Parse cache ──────────────────────────────────────────────
|
|
@@ -46,10 +62,21 @@ import { WASM_SUPPORTED_STDLIB } from "./typechecker/types.js";
|
|
|
46
62
|
// Map<filePath, { mtime: number, ast: object }>
|
|
47
63
|
const _parseCache = new Map();
|
|
48
64
|
|
|
65
|
+
// A cached AST keeps everything the build attached to it (checked types,
|
|
66
|
+
// lowered stdlib programs), so a build of a Go-source stdlib importer pins
|
|
67
|
+
// megabytes. The cache is therefore bounded; the least recently used file goes
|
|
68
|
+
// first.
|
|
69
|
+
const PARSE_CACHE_LIMIT = 16;
|
|
70
|
+
|
|
49
71
|
export function clearParseCache() {
|
|
50
72
|
_parseCache.clear();
|
|
51
73
|
}
|
|
52
74
|
|
|
75
|
+
// Drops one file, e.g. a throwaway source that was deleted after its build.
|
|
76
|
+
export function evictParseCache(filePath) {
|
|
77
|
+
_parseCache.delete(resolve(filePath));
|
|
78
|
+
}
|
|
79
|
+
|
|
53
80
|
export function parseCacheSize() {
|
|
54
81
|
return _parseCache.size;
|
|
55
82
|
}
|
|
@@ -57,9 +84,14 @@ export function parseCacheSize() {
|
|
|
57
84
|
// ── Helpers ──────────────────────────────────────────────────
|
|
58
85
|
|
|
59
86
|
function parseGoFrontFile(filePath) {
|
|
87
|
+
const key = resolve(filePath);
|
|
60
88
|
const mtime = statSync(filePath).mtimeMs;
|
|
61
|
-
const cached = _parseCache.get(
|
|
62
|
-
if (cached && cached.mtime === mtime)
|
|
89
|
+
const cached = _parseCache.get(key);
|
|
90
|
+
if (cached && cached.mtime === mtime) {
|
|
91
|
+
_parseCache.delete(key);
|
|
92
|
+
_parseCache.set(key, cached);
|
|
93
|
+
return cached.ast;
|
|
94
|
+
}
|
|
63
95
|
|
|
64
96
|
const source = readFileSync(filePath, "utf8");
|
|
65
97
|
const filename = basename(filePath);
|
|
@@ -74,7 +106,9 @@ function parseGoFrontFile(filePath) {
|
|
|
74
106
|
ast._path = resolve(filePath);
|
|
75
107
|
// compileFiles overwrites `target` with the resolved one; keep the directive.
|
|
76
108
|
ast._declaredTarget = ast.target;
|
|
77
|
-
_parseCache.set(
|
|
109
|
+
_parseCache.set(key, { mtime, ast });
|
|
110
|
+
if (_parseCache.size > PARSE_CACHE_LIMIT)
|
|
111
|
+
_parseCache.delete(_parseCache.keys().next().value);
|
|
78
112
|
return ast;
|
|
79
113
|
}
|
|
80
114
|
|
|
@@ -89,103 +123,11 @@ export function gwFilesIn(dir, { includeTests = false } = {}) {
|
|
|
89
123
|
.map((f) => join(dir, f));
|
|
90
124
|
}
|
|
91
125
|
|
|
92
|
-
function normalizeChunk(c) {
|
|
93
|
-
if (typeof c === "string") {
|
|
94
|
-
return { js: c, sourceFiles: [], sourcesContent: [], mappings: [] };
|
|
95
|
-
}
|
|
96
|
-
return c;
|
|
97
|
-
}
|
|
98
|
-
|
|
99
|
-
function appendChunkMappings(dest, mappings, localToUnifiedIdx, lineOffset) {
|
|
100
|
-
if (!mappings) return;
|
|
101
|
-
for (const m of mappings) {
|
|
102
|
-
dest.push({
|
|
103
|
-
genLine: m.genLine + lineOffset,
|
|
104
|
-
srcLine: m.srcLine,
|
|
105
|
-
srcFileIdx: localToUnifiedIdx[m.srcFileIdx ?? 0] ?? 0,
|
|
106
|
-
});
|
|
107
|
-
}
|
|
108
|
-
}
|
|
109
|
-
|
|
110
|
-
function mergeCompilationChunks(chunks) {
|
|
111
|
-
const activeChunks = chunks
|
|
112
|
-
.filter(Boolean)
|
|
113
|
-
.map(normalizeChunk)
|
|
114
|
-
.filter((c) => c.js.length > 0);
|
|
115
|
-
|
|
116
|
-
if (activeChunks.length === 0) {
|
|
117
|
-
return { js: "", sourceFiles: [], sourcesContent: [], mappings: [] };
|
|
118
|
-
}
|
|
119
|
-
|
|
120
|
-
const unifiedSources = [];
|
|
121
|
-
const unifiedSourcesContent = [];
|
|
122
|
-
const fileIdxMap = new Map();
|
|
123
|
-
|
|
124
|
-
function getOrAddFile(filePath, content) {
|
|
125
|
-
const key = resolve(filePath);
|
|
126
|
-
let idx = fileIdxMap.get(key);
|
|
127
|
-
if (idx === undefined) {
|
|
128
|
-
idx = unifiedSources.length;
|
|
129
|
-
fileIdxMap.set(key, idx);
|
|
130
|
-
unifiedSources.push(key);
|
|
131
|
-
unifiedSourcesContent.push(content);
|
|
132
|
-
}
|
|
133
|
-
return idx;
|
|
134
|
-
}
|
|
135
|
-
|
|
136
|
-
const combinedJsParts = [];
|
|
137
|
-
const mergedMappings = [];
|
|
138
|
-
let currentLineOffset = 0;
|
|
139
|
-
|
|
140
|
-
for (const chunk of activeChunks) {
|
|
141
|
-
combinedJsParts.push(chunk.js);
|
|
142
|
-
const localToUnifiedIdx = (chunk.sourceFiles ?? []).map((file, i) =>
|
|
143
|
-
getOrAddFile(file, chunk.sourcesContent?.[i] ?? ""),
|
|
144
|
-
);
|
|
145
|
-
appendChunkMappings(
|
|
146
|
-
mergedMappings,
|
|
147
|
-
chunk.mappings,
|
|
148
|
-
localToUnifiedIdx,
|
|
149
|
-
currentLineOffset,
|
|
150
|
-
);
|
|
151
|
-
currentLineOffset += chunk.js.split("\n").length;
|
|
152
|
-
}
|
|
153
|
-
|
|
154
|
-
return {
|
|
155
|
-
js: combinedJsParts.join("\n"),
|
|
156
|
-
sourceFiles: unifiedSources,
|
|
157
|
-
sourcesContent: unifiedSourcesContent,
|
|
158
|
-
mappings: mergedMappings,
|
|
159
|
-
};
|
|
160
|
-
}
|
|
161
|
-
|
|
162
|
-
function attachSourceMap(merged, outputDir) {
|
|
163
|
-
const relativeSources = merged.sourceFiles.map((f) => relative(outputDir, f));
|
|
164
|
-
const mapJson = buildSourceMap(
|
|
165
|
-
relativeSources,
|
|
166
|
-
merged.mappings,
|
|
167
|
-
merged.sourcesContent,
|
|
168
|
-
);
|
|
169
|
-
const b64 = Buffer.from(mapJson).toString("base64");
|
|
170
|
-
merged.js += `\n//# sourceMappingURL=data:application/json;base64,${b64}`;
|
|
171
|
-
}
|
|
172
|
-
|
|
173
|
-
const WASM_MAP_URL = "app.wasm.map";
|
|
174
|
-
|
|
175
|
-
// Function-level `app.wasm.map` (sources relative to the output dir).
|
|
176
|
-
function buildWasmMap(info, outputDir) {
|
|
177
|
-
if (!info || info.mappings.length === 0) return null;
|
|
178
|
-
return buildWasmSourceMap(
|
|
179
|
-
info.sources.map((f) => relative(outputDir, f)),
|
|
180
|
-
info.mappings,
|
|
181
|
-
);
|
|
182
|
-
}
|
|
183
|
-
|
|
184
126
|
// Shared tail of compileFiles / compileSingleFile: link `app.wasm`, run
|
|
185
127
|
// wasm-opt when requested and produce the wasm source map.
|
|
186
128
|
function finishWasm(options, merged, pkgTarget, outputDir) {
|
|
187
129
|
const wantMap = Boolean(options.sourceMap && !options.isDependency);
|
|
188
|
-
let { wasm, wat, sourceMapInfo } = linkIntoBundle(
|
|
130
|
+
let { wasm, wat, sourceMapInfo, stringTable } = linkIntoBundle(
|
|
189
131
|
options,
|
|
190
132
|
merged,
|
|
191
133
|
pkgTarget,
|
|
@@ -210,174 +152,19 @@ function finishWasm(options, merged, pkgTarget, outputDir) {
|
|
|
210
152
|
wasmOptInfo = opt;
|
|
211
153
|
if (opt.sourceMap) wasmSourceMap = opt.sourceMap;
|
|
212
154
|
}
|
|
213
|
-
return { wasm, wat, wasmOptInfo, wasmSourceMap };
|
|
155
|
+
return { wasm, wat, wasmOptInfo, wasmSourceMap, stringTable };
|
|
214
156
|
}
|
|
215
157
|
|
|
216
|
-
//
|
|
217
|
-
|
|
218
|
-
|
|
219
|
-
// shared `options.wasmUnits` array. The root compile links all units into a
|
|
220
|
-
// single `app.wasm` and splices the generated JS facade into the bundle where
|
|
221
|
-
// the first wasm package's JS would have been.
|
|
222
|
-
|
|
223
|
-
const WASM_MARKER_RE = /^\/\*__GOFRONT_WASM_UNIT:[^*]*\*\/$/m;
|
|
224
|
-
|
|
225
|
-
function wasmMarker(pkgName) {
|
|
226
|
-
return `/*__GOFRONT_WASM_UNIT:${pkgName}*/`;
|
|
227
|
-
}
|
|
228
|
-
|
|
229
|
-
function registerWasmUnit(options, unit) {
|
|
230
|
-
const units = options.wasmUnits;
|
|
231
|
-
if (!units) return;
|
|
232
|
-
if (units.some((u) => u.key === unit.key)) return;
|
|
233
|
-
units.push(unit);
|
|
234
|
-
}
|
|
235
|
-
|
|
236
|
-
// Registers a `wasm`/`both` package as a link unit and returns the target the
|
|
237
|
-
// package's own code is emitted for. `options.wasmTests` runs a `both`
|
|
238
|
-
// package's tests through the wasm backend (the package is then treated as
|
|
239
|
-
// `wasm` for linking so its test functions are exposed by the facade).
|
|
240
|
-
function registerPackageUnit(options, unit) {
|
|
241
|
-
const { pkgTarget, programs } = unit;
|
|
242
|
-
if (pkgTarget !== "wasm" && pkgTarget !== "both") return pkgTarget;
|
|
243
|
-
const emitTarget =
|
|
244
|
-
options.wasmTests && options.isTest && pkgTarget === "both"
|
|
245
|
-
? "wasm"
|
|
246
|
-
: pkgTarget;
|
|
247
|
-
registerWasmUnit(options, {
|
|
248
|
-
...unit,
|
|
249
|
-
target: emitTarget,
|
|
250
|
-
programs:
|
|
251
|
-
emitTarget === pkgTarget
|
|
252
|
-
? programs
|
|
253
|
-
: programs.map((p) => ({ ...p, target: emitTarget })),
|
|
254
|
-
});
|
|
255
|
-
return emitTarget;
|
|
256
|
-
}
|
|
257
|
-
|
|
258
|
-
function linkWasmUnits(
|
|
259
|
-
units,
|
|
260
|
-
{ emitWat = false, rootTarget = "js", sourceMappingURL = null } = {},
|
|
261
|
-
) {
|
|
262
|
-
if (!units.some((u) => u.target === "wasm")) return null;
|
|
263
|
-
checkLinkCollisions(units);
|
|
264
|
-
|
|
265
|
-
const types = new Map();
|
|
266
|
-
const bundledPackages = new Set();
|
|
267
|
-
const programs = [];
|
|
268
|
-
for (const u of units) {
|
|
269
|
-
for (const [k, v] of u.types) types.set(k, v);
|
|
270
|
-
for (const b of u.bundledPackages) bundledPackages.add(b);
|
|
271
|
-
programs.push(...u.programs);
|
|
272
|
-
}
|
|
273
|
-
const checker = {
|
|
274
|
-
types,
|
|
275
|
-
errors: [],
|
|
276
|
-
err(msg, node) {
|
|
277
|
-
const e = new TypeCheckError(
|
|
278
|
-
msg,
|
|
279
|
-
node,
|
|
280
|
-
this._currentFile,
|
|
281
|
-
this._currentSource,
|
|
282
|
-
);
|
|
283
|
-
this.errors.push(e);
|
|
284
|
-
return e;
|
|
285
|
-
},
|
|
286
|
-
};
|
|
287
|
-
const lowerRes = lower(programs, checker);
|
|
288
|
-
return compileWasmModule(programs, checker, lowerRes, {
|
|
289
|
-
boundary: true,
|
|
290
|
-
bundledPackages,
|
|
291
|
-
emitWat,
|
|
292
|
-
callMain: rootTarget === "wasm",
|
|
293
|
-
sourceMappingURL,
|
|
294
|
-
});
|
|
295
|
-
}
|
|
296
|
-
|
|
297
|
-
// The linked module is one flat namespace (like the JS bundle), so a top-level
|
|
298
|
-
// name declared by two different packages would silently resolve to whichever
|
|
299
|
-
// was emitted last. Reject it up front.
|
|
300
|
-
function topLevelDeclNames(decl) {
|
|
301
|
-
switch (decl.kind) {
|
|
302
|
-
case "FuncDecl":
|
|
303
|
-
return [decl.name];
|
|
304
|
-
case "MethodDecl":
|
|
305
|
-
return [`${decl.recvType?.name ?? "?"}.${decl.name}`];
|
|
306
|
-
case "TypeDecl":
|
|
307
|
-
return [decl.name];
|
|
308
|
-
case "VarDecl":
|
|
309
|
-
case "ConstDecl":
|
|
310
|
-
return (decl.decls ?? []).flatMap((spec) => spec.names ?? []);
|
|
311
|
-
default:
|
|
312
|
-
return [];
|
|
313
|
-
}
|
|
314
|
-
}
|
|
315
|
-
|
|
316
|
-
function checkLinkCollisions(units) {
|
|
317
|
-
const owner = new Map(); // name -> pkgName
|
|
318
|
-
const errors = [];
|
|
319
|
-
for (const u of units) {
|
|
320
|
-
for (const p of u.programs) {
|
|
321
|
-
for (const d of p.decls ?? []) {
|
|
322
|
-
for (const name of topLevelDeclNames(d)) {
|
|
323
|
-
if (name === "_") continue;
|
|
324
|
-
const prev = owner.get(name);
|
|
325
|
-
if (prev === undefined) owner.set(name, u.pkgName);
|
|
326
|
-
else if (prev !== u.pkgName)
|
|
327
|
-
errors.push(
|
|
328
|
-
`cannot link wasm packages: '${name}' is declared in both '${prev}' and '${u.pkgName}' (linked wasm packages share one namespace)`,
|
|
329
|
-
);
|
|
330
|
-
}
|
|
331
|
-
}
|
|
332
|
-
}
|
|
333
|
-
}
|
|
334
|
-
if (errors.length > 0) throw new Error([...new Set(errors)].join("\n"));
|
|
335
|
-
}
|
|
336
|
-
|
|
337
|
-
// Replaces the first wasm marker with the facade (dropping the others) and
|
|
338
|
-
// shifts source-map lines that follow it.
|
|
339
|
-
function spliceFacade(merged, facade) {
|
|
340
|
-
const lines = merged.js.split("\n");
|
|
341
|
-
const first = lines.findIndex((l) => WASM_MARKER_RE.test(l));
|
|
342
|
-
if (first < 0) {
|
|
343
|
-
merged.js = `${facade}\n${merged.js}`;
|
|
344
|
-
const shift = facade.split("\n").length;
|
|
345
|
-
for (const m of merged.mappings) m.genLine += shift;
|
|
346
|
-
return;
|
|
347
|
-
}
|
|
348
|
-
const facadeLines = facade.split("\n");
|
|
349
|
-
const delta = facadeLines.length - 1;
|
|
350
|
-
for (const m of merged.mappings) {
|
|
351
|
-
if (m.genLine > first) m.genLine += delta;
|
|
352
|
-
}
|
|
353
|
-
const out = [...lines.slice(0, first), ...facadeLines];
|
|
354
|
-
for (let i = first + 1; i < lines.length; i++) {
|
|
355
|
-
if (!WASM_MARKER_RE.test(lines[i])) out.push(lines[i]);
|
|
356
|
-
}
|
|
357
|
-
merged.js = out.join("\n");
|
|
358
|
-
}
|
|
359
|
-
|
|
360
|
-
// Root compiles only: link every registered unit into app.wasm and splice the
|
|
361
|
-
// facade into the merged bundle. Returns `{ wasm, wat, sourceMapInfo }`
|
|
362
|
-
// (nulls when there is nothing to link).
|
|
363
|
-
function linkIntoBundle(options, merged, pkgTarget, { sourceMappingURL } = {}) {
|
|
364
|
-
const none = { wasm: null, wat: null, sourceMapInfo: null };
|
|
365
|
-
if (options.isDependency) return none;
|
|
366
|
-
const linked = linkWasmUnits(options.wasmUnits, {
|
|
367
|
-
emitWat: options.emitWat,
|
|
368
|
-
rootTarget: pkgTarget,
|
|
369
|
-
sourceMappingURL,
|
|
370
|
-
});
|
|
371
|
-
if (!linked) return none;
|
|
372
|
-
spliceFacade(merged, linked.facade);
|
|
373
|
-
return {
|
|
374
|
-
wasm: linked.wasm,
|
|
375
|
-
wat: linked.wat ?? null,
|
|
376
|
-
sourceMapInfo: linked.sourceMapInfo ?? null,
|
|
377
|
-
};
|
|
158
|
+
// Prints non-fatal diagnostics (e.g. JS Number precision of a constant).
|
|
159
|
+
function logWarnings(warnings) {
|
|
160
|
+
for (const w of warnings) log.warn(w);
|
|
378
161
|
}
|
|
379
162
|
|
|
380
163
|
// ── Import resolution ─────────────────────────────────────────
|
|
164
|
+
|
|
165
|
+
// What link/stdlib.js needs from this module. Injected rather than imported
|
|
166
|
+
// so that link/stdlib.js does not depend on compiler.js.
|
|
167
|
+
const STDLIB_DEPS = { gwFilesIn, resolveImports, TypeChecker };
|
|
381
168
|
//
|
|
382
169
|
// Shared by compileFiles (multi-file) and the single-file path in index.js.
|
|
383
170
|
// Mutates checker, jsImports, bundledPackages, and preambles in place.
|
|
@@ -417,18 +204,17 @@ function resolveImports(
|
|
|
417
204
|
"js: imports are not allowed in wasm packages",
|
|
418
205
|
impNode,
|
|
419
206
|
);
|
|
420
|
-
} else if (path === "gom") {
|
|
421
|
-
checker.recordBlocker("gom usage", "gom");
|
|
422
|
-
checker.err(
|
|
423
|
-
"package 'gom' is not available in wasm packages",
|
|
424
|
-
impNode,
|
|
425
|
-
);
|
|
426
207
|
} else if (path === "gofront/shared" && pkgTarget === "both") {
|
|
427
208
|
checker.err(
|
|
428
209
|
"'gofront/shared' requires a wasm-only package (//gofront:target wasm): a both package has no linear memory on the JS side",
|
|
429
210
|
impNode,
|
|
430
211
|
);
|
|
431
|
-
} else if (
|
|
212
|
+
} else if (
|
|
213
|
+
!isLocalPath(path) &&
|
|
214
|
+
!EXCLUDED_STDLIB_PACKAGES.has(path) &&
|
|
215
|
+
(isBuiltinPackage(path) ||
|
|
216
|
+
!resolveStdlibSource(path, options.stdlibRoot))
|
|
217
|
+
) {
|
|
432
218
|
if (!isBuiltinPackage(path)) {
|
|
433
219
|
checker.recordBlocker("js: import", path);
|
|
434
220
|
checker.err(
|
|
@@ -469,13 +255,27 @@ function resolveImports(
|
|
|
469
255
|
...imp,
|
|
470
256
|
imports: imp.imports.filter(({ alias }) => alias !== "_"),
|
|
471
257
|
}));
|
|
472
|
-
const resolved = resolveAll(
|
|
258
|
+
const resolved = resolveAll(
|
|
259
|
+
allImportsNoSideEffect,
|
|
260
|
+
fromFile,
|
|
261
|
+
parseDts,
|
|
262
|
+
options.stdlibRoot,
|
|
263
|
+
);
|
|
473
264
|
for (const [path, info] of resolved) {
|
|
474
265
|
if (!info) continue;
|
|
475
266
|
checker.addDefinitions(info.types, info.values);
|
|
476
267
|
jsImports.set(path, [...info.values.keys()]);
|
|
477
268
|
}
|
|
478
269
|
|
|
270
|
+
importStdlibPackages(
|
|
271
|
+
programs,
|
|
272
|
+
checker,
|
|
273
|
+
preambles,
|
|
274
|
+
bundledDirs,
|
|
275
|
+
options,
|
|
276
|
+
STDLIB_DEPS,
|
|
277
|
+
);
|
|
278
|
+
|
|
479
279
|
// local GoFront packages (./subdir)
|
|
480
280
|
const seenLocalPaths = new Set();
|
|
481
281
|
for (const p of programs) {
|
|
@@ -501,6 +301,9 @@ function resolveImports(
|
|
|
501
301
|
isDependency: true,
|
|
502
302
|
});
|
|
503
303
|
if (!alreadyBundled) preambles.push(dep);
|
|
304
|
+
// A dependency that hands out `&xs[i]` makes whole-element
|
|
305
|
+
// stores in this package write in place too.
|
|
306
|
+
if (dep.elemAddrTaken) checker.depElemAddrTaken = true;
|
|
504
307
|
|
|
505
308
|
// Target import rules for local packages
|
|
506
309
|
const impNode = {
|
|
@@ -541,7 +344,10 @@ function resolveImports(
|
|
|
541
344
|
|
|
542
345
|
if (alias === "_") continue;
|
|
543
346
|
if (alias === ".") {
|
|
544
|
-
checker.addDefinitions(dep.exportedTypes, dep.exportedSymbols
|
|
347
|
+
checker.addDefinitions(dep.exportedTypes, dep.exportedSymbols, {
|
|
348
|
+
external: false,
|
|
349
|
+
consts: dep.exportedConsts,
|
|
350
|
+
});
|
|
545
351
|
continue;
|
|
546
352
|
}
|
|
547
353
|
const nameUsed = alias ?? dep.pkgName;
|
|
@@ -551,6 +357,7 @@ function resolveImports(
|
|
|
551
357
|
dep.exportedSymbols,
|
|
552
358
|
dep.exportedTypes,
|
|
553
359
|
dep.target,
|
|
360
|
+
dep.exportedConsts,
|
|
554
361
|
);
|
|
555
362
|
checker.trackImport(nameUsed, { _line }, p._filename, p._source);
|
|
556
363
|
}
|
|
@@ -584,112 +391,29 @@ export function resolvePackageTarget(declared, pkgDir, options = {}) {
|
|
|
584
391
|
}
|
|
585
392
|
|
|
586
393
|
export function compileSingleFile(inputPath, options = {}) {
|
|
587
|
-
const {
|
|
588
|
-
sourceMap = false,
|
|
589
|
-
outputFile = null,
|
|
590
|
-
dumpTokens = false,
|
|
591
|
-
dumpAst = false,
|
|
592
|
-
} = options;
|
|
593
|
-
options = { ...options, wasmUnits: options.wasmUnits ?? [] };
|
|
594
|
-
|
|
595
|
-
let source;
|
|
596
|
-
try {
|
|
597
|
-
source = readFileSync(inputPath, "utf8");
|
|
598
|
-
} catch (e) {
|
|
599
|
-
throw new Error(`cannot read '${inputPath}': ${e.message}`);
|
|
600
|
-
}
|
|
394
|
+
const { outputFile = null, dumpTokens = false, dumpAst = false } = options;
|
|
601
395
|
|
|
602
|
-
|
|
603
|
-
|
|
604
|
-
|
|
605
|
-
|
|
606
|
-
|
|
607
|
-
|
|
608
|
-
|
|
609
|
-
|
|
610
|
-
|
|
611
|
-
|
|
612
|
-
|
|
613
|
-
|
|
614
|
-
|
|
615
|
-
const jsImports = new Map();
|
|
616
|
-
const bundledPackages = new Set();
|
|
617
|
-
const preambles = [];
|
|
618
|
-
|
|
619
|
-
const pkgTarget = resolvePackageTarget(
|
|
620
|
-
ast.target ?? options.target ?? "js",
|
|
621
|
-
dirname(resolve(inputPath)),
|
|
622
|
-
options,
|
|
623
|
-
);
|
|
624
|
-
ast.target = pkgTarget;
|
|
625
|
-
checker.target = pkgTarget;
|
|
626
|
-
checker.pkgName = ast.pkg?.name ?? "main";
|
|
627
|
-
|
|
628
|
-
resolveImports(
|
|
629
|
-
[ast],
|
|
630
|
-
inputPath,
|
|
631
|
-
checker,
|
|
632
|
-
jsImports,
|
|
633
|
-
bundledPackages,
|
|
634
|
-
preambles,
|
|
635
|
-
options.bundledDirs ?? new Set(),
|
|
636
|
-
{ ...options, outputDir },
|
|
637
|
-
);
|
|
638
|
-
|
|
639
|
-
const errors = checker.check(ast);
|
|
640
|
-
checker.reportUnusedImports();
|
|
641
|
-
if (errors.length > 0) {
|
|
642
|
-
throw new Error(errors.map((e) => e.message).join("\n"));
|
|
643
|
-
}
|
|
644
|
-
for (const w of checker.warnings) log.warn(w);
|
|
645
|
-
|
|
646
|
-
if (pkgTarget === "wasm" || pkgTarget === "both") {
|
|
647
|
-
registerWasmUnit(options, {
|
|
648
|
-
key: resolve(inputPath),
|
|
649
|
-
pkgName: checker.pkgName,
|
|
650
|
-
target: pkgTarget,
|
|
651
|
-
programs: [ast],
|
|
652
|
-
types: checker.types,
|
|
653
|
-
bundledPackages,
|
|
654
|
-
});
|
|
396
|
+
if (dumpTokens || dumpAst) {
|
|
397
|
+
let source;
|
|
398
|
+
try {
|
|
399
|
+
source = readFileSync(inputPath, "utf8");
|
|
400
|
+
} catch (e) {
|
|
401
|
+
throw new Error(`cannot read '${inputPath}': ${e.message}`);
|
|
402
|
+
}
|
|
403
|
+
const tokens = new Lexer(source, basename(inputPath)).tokenize();
|
|
404
|
+
if (dumpTokens) return { tokens };
|
|
405
|
+
const ast = new Parser(tokens, basename(inputPath), source).parse();
|
|
406
|
+
ast._source = source;
|
|
407
|
+
ast._path = resolve(inputPath);
|
|
408
|
+
return { ast };
|
|
655
409
|
}
|
|
656
410
|
|
|
657
|
-
|
|
658
|
-
|
|
659
|
-
|
|
660
|
-
|
|
411
|
+
return compileFiles([resolve(inputPath)], {
|
|
412
|
+
...options,
|
|
413
|
+
outputDir:
|
|
414
|
+
options.outputDir ??
|
|
415
|
+
(outputFile ? dirname(resolve(outputFile)) : resolve(".")),
|
|
661
416
|
});
|
|
662
|
-
const mainJs =
|
|
663
|
-
pkgTarget === "wasm" ? wasmMarker(checker.pkgName) : cg.generate(ast);
|
|
664
|
-
|
|
665
|
-
const mainChunk = {
|
|
666
|
-
js: mainJs,
|
|
667
|
-
sourceFiles: [resolve(inputPath)],
|
|
668
|
-
sourcesContent: [source],
|
|
669
|
-
mappings: pkgTarget === "wasm" ? [] : cg.getMappings(),
|
|
670
|
-
};
|
|
671
|
-
|
|
672
|
-
const merged = mergeCompilationChunks([...preambles, mainChunk]);
|
|
673
|
-
const { wasm, wat, wasmOptInfo, wasmSourceMap } = finishWasm(
|
|
674
|
-
{ ...options, sourceMap },
|
|
675
|
-
merged,
|
|
676
|
-
pkgTarget,
|
|
677
|
-
outputDir,
|
|
678
|
-
);
|
|
679
|
-
|
|
680
|
-
if (sourceMap && !options.isDependency) {
|
|
681
|
-
attachSourceMap(merged, outputDir);
|
|
682
|
-
}
|
|
683
|
-
|
|
684
|
-
return {
|
|
685
|
-
js: merged.js,
|
|
686
|
-
css: cg.getCss(),
|
|
687
|
-
target: pkgTarget,
|
|
688
|
-
wasm,
|
|
689
|
-
wat,
|
|
690
|
-
wasmOptInfo,
|
|
691
|
-
wasmSourceMap,
|
|
692
|
-
};
|
|
693
417
|
}
|
|
694
418
|
|
|
695
419
|
export function compileDir(dir, options = {}) {
|
|
@@ -716,7 +440,12 @@ export function compileFiles(files, options = {}) {
|
|
|
716
440
|
options = {
|
|
717
441
|
...options,
|
|
718
442
|
wasmUnits: options.wasmUnits ?? [],
|
|
443
|
+
stdlibCache: options.stdlibCache ?? new Map(),
|
|
444
|
+
jsRootPrograms: options.jsRootPrograms ?? [],
|
|
719
445
|
rootDir: options.rootDir ?? fromDir,
|
|
446
|
+
bundledDirs: options.bundledDirs ?? new Set(),
|
|
447
|
+
typeOwners: options.typeOwners ?? new Map(),
|
|
448
|
+
jsonBuild: options.jsonBuild ?? { js: false, wasm: false },
|
|
720
449
|
};
|
|
721
450
|
const outputDir =
|
|
722
451
|
options.outputDir ??
|
|
@@ -744,6 +473,15 @@ export function compileFiles(files, options = {}) {
|
|
|
744
473
|
);
|
|
745
474
|
const pkgName = pkgNames[0];
|
|
746
475
|
|
|
476
|
+
// Local packages share one flat JS module: a type name another package
|
|
477
|
+
// already declared is renamed here (`Pt` -> `Pt$$b`).
|
|
478
|
+
const renamedTypes = mangleLocalTypes(
|
|
479
|
+
programs,
|
|
480
|
+
resolve(fromDir),
|
|
481
|
+
pkgName,
|
|
482
|
+
options.typeOwners,
|
|
483
|
+
);
|
|
484
|
+
|
|
747
485
|
// Validate target directives across files in this package
|
|
748
486
|
const declaredTargets = new Map();
|
|
749
487
|
for (const p of programs) {
|
|
@@ -770,6 +508,11 @@ export function compileFiles(files, options = {}) {
|
|
|
770
508
|
);
|
|
771
509
|
for (const p of programs) p.target = pkgTarget;
|
|
772
510
|
|
|
511
|
+
// The test runner's driver is a source that exists only in memory: it is
|
|
512
|
+
// parsed and checked with the package but never written next to it.
|
|
513
|
+
const driver = testDriverProgram(options, programs, pkgTarget, fromDir);
|
|
514
|
+
if (driver) programs.push(driver);
|
|
515
|
+
|
|
773
516
|
// ── 2. Resolve imports ────────────────────────────────────────
|
|
774
517
|
const checker = new TypeChecker();
|
|
775
518
|
checker.target = pkgTarget;
|
|
@@ -792,6 +535,13 @@ export function compileFiles(files, options = {}) {
|
|
|
792
535
|
|
|
793
536
|
// ── 3. Type-check ─────────────────────────────────────────────
|
|
794
537
|
const errors = checker.checkAll(programs);
|
|
538
|
+
const codecs = checkGeneratedGo(
|
|
539
|
+
programs,
|
|
540
|
+
checker,
|
|
541
|
+
preambles,
|
|
542
|
+
options,
|
|
543
|
+
STDLIB_DEPS,
|
|
544
|
+
);
|
|
795
545
|
checker.reportUnusedImports();
|
|
796
546
|
if (errors.length > 0) {
|
|
797
547
|
const msgs = errors.map((e) => e.message).join("\n");
|
|
@@ -804,7 +554,7 @@ export function compileFiles(files, options = {}) {
|
|
|
804
554
|
key: resolve(fromDir),
|
|
805
555
|
pkgName,
|
|
806
556
|
pkgTarget,
|
|
807
|
-
programs,
|
|
557
|
+
programs: [...programs, ...codecs],
|
|
808
558
|
types: checker.types,
|
|
809
559
|
bundledPackages,
|
|
810
560
|
});
|
|
@@ -813,13 +563,15 @@ export function compileFiles(files, options = {}) {
|
|
|
813
563
|
const codegen = new CodeGen(checker, jsImports, bundledPackages, {
|
|
814
564
|
target: pkgTarget,
|
|
815
565
|
strict: isStrict,
|
|
566
|
+
natives: options.natives,
|
|
816
567
|
});
|
|
817
568
|
const mainJs =
|
|
818
569
|
emitTarget === "wasm"
|
|
819
570
|
? wasmMarker(pkgName)
|
|
820
|
-
: codegen.generateAll(programs, {
|
|
571
|
+
: codegen.generateAll([...programs, ...codecs], {
|
|
821
572
|
isTest: options.isTest ?? false,
|
|
822
573
|
});
|
|
574
|
+
logWarnings(codegen.warnings);
|
|
823
575
|
|
|
824
576
|
const mainChunk = {
|
|
825
577
|
js: mainJs,
|
|
@@ -829,7 +581,8 @@ export function compileFiles(files, options = {}) {
|
|
|
829
581
|
};
|
|
830
582
|
|
|
831
583
|
const merged = mergeCompilationChunks([...preambles, mainChunk]);
|
|
832
|
-
|
|
584
|
+
finishStdlibJs(merged, options, [...programs, ...codecs], emitTarget);
|
|
585
|
+
const { wasm, wat, wasmOptInfo, wasmSourceMap, stringTable } = finishWasm(
|
|
833
586
|
options,
|
|
834
587
|
merged,
|
|
835
588
|
pkgTarget,
|
|
@@ -848,17 +601,80 @@ export function compileFiles(files, options = {}) {
|
|
|
848
601
|
return {
|
|
849
602
|
pkgName,
|
|
850
603
|
target: pkgTarget,
|
|
604
|
+
elemAddrTaken:
|
|
605
|
+
checker.depElemAddrTaken === true ||
|
|
606
|
+
programs.some((p) => takesElementAddress(p.decls)),
|
|
851
607
|
js: merged.js,
|
|
852
608
|
css: allCss,
|
|
853
609
|
wasm,
|
|
854
610
|
wat,
|
|
855
611
|
wasmOptInfo,
|
|
856
612
|
wasmSourceMap,
|
|
857
|
-
|
|
613
|
+
stringTable,
|
|
614
|
+
programs: driver ? programs.filter((p) => p !== driver) : programs,
|
|
858
615
|
exportedSymbols: checker.getExportedSymbols(),
|
|
859
|
-
exportedTypes:
|
|
616
|
+
exportedTypes: withOriginalTypeNames(
|
|
617
|
+
checker.getExportedTypes(),
|
|
618
|
+
renamedTypes,
|
|
619
|
+
),
|
|
620
|
+
exportedConsts: checker.getExportedConsts(),
|
|
860
621
|
sourceFiles: merged.sourceFiles,
|
|
861
622
|
sourcesContent: merged.sourcesContent,
|
|
862
623
|
mappings: merged.mappings,
|
|
863
624
|
};
|
|
864
625
|
}
|
|
626
|
+
|
|
627
|
+
// Parses the in-memory driver source `options.testDriver(programs, target)`
|
|
628
|
+
// returns (null: no driver) as a `_test.go` file of the package.
|
|
629
|
+
function testDriverProgram(options, programs, pkgTarget, fromDir) {
|
|
630
|
+
if (!options.testDriver || options.isDependency) return null;
|
|
631
|
+
const source = options.testDriver(programs, pkgTarget);
|
|
632
|
+
if (!source) return null;
|
|
633
|
+
const filename = "gofront_testmain_test.go";
|
|
634
|
+
const ast = new Parser(
|
|
635
|
+
new Lexer(source, filename).tokenize(),
|
|
636
|
+
filename,
|
|
637
|
+
source,
|
|
638
|
+
).parse();
|
|
639
|
+
ast._source = source;
|
|
640
|
+
ast._path = join(fromDir, filename);
|
|
641
|
+
ast._declaredTarget = ast.target;
|
|
642
|
+
ast.target = pkgTarget;
|
|
643
|
+
return ast;
|
|
644
|
+
}
|
|
645
|
+
|
|
646
|
+
// The renamed ASTs must not be reused from the parse cache by a later build.
|
|
647
|
+
function mangleLocalTypes(programs, pkgKey, pkgName, owners) {
|
|
648
|
+
const renamed = mangleCollidingTypes(programs, pkgKey, pkgName, owners);
|
|
649
|
+
const locals = renameLocalTypes(programs);
|
|
650
|
+
if (renamed.size > 0 || locals)
|
|
651
|
+
for (const p of programs) _parseCache.delete(p._path);
|
|
652
|
+
return renamed;
|
|
653
|
+
}
|
|
654
|
+
|
|
655
|
+
export function compileWasm(source, options = {}) {
|
|
656
|
+
const filename = options.filename ?? "main.go";
|
|
657
|
+
const tokens = new Lexer(source, filename).tokenize();
|
|
658
|
+
const ast = new Parser(tokens, filename, source).parse();
|
|
659
|
+
|
|
660
|
+
const checker = new TypeChecker();
|
|
661
|
+
checker.target = "wasm";
|
|
662
|
+
checker.pkgName = ast.pkg?.name ?? "main";
|
|
663
|
+
|
|
664
|
+
const errors = checker.check(ast);
|
|
665
|
+
if (errors.length > 0) {
|
|
666
|
+
return { wasm: null, errors };
|
|
667
|
+
}
|
|
668
|
+
|
|
669
|
+
const lowerRes = lower([ast], checker);
|
|
670
|
+
const res = compileWasmModule([ast], checker, lowerRes, {
|
|
671
|
+
...options,
|
|
672
|
+
exportAll: options.exportAll ?? true,
|
|
673
|
+
});
|
|
674
|
+
|
|
675
|
+
if (checker.errors?.length > 0) {
|
|
676
|
+
return { wasm: null, errors: checker.errors };
|
|
677
|
+
}
|
|
678
|
+
|
|
679
|
+
return { ...res, errors: [] };
|
|
680
|
+
}
|