xbintsc 0.3.13 → 0.3.15
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 +22 -22
- package/README.zh-CN.md +20 -19
- package/bin/xbintsc.js +1 -2
- package/dist/src/cli/main.js +4 -1
- package/dist/src/cli/main.js.map +1 -1
- package/dist/src/codegen/generator/calls/access.js +13 -0
- package/dist/src/codegen/generator/calls/access.js.map +1 -1
- package/dist/src/codegen/generator/calls/invocation.js +8 -2
- package/dist/src/codegen/generator/calls/invocation.js.map +1 -1
- package/dist/src/codegen/generator/context.d.ts +6 -0
- package/dist/src/codegen/generator/context.js +24 -2
- package/dist/src/codegen/generator/context.js.map +1 -1
- package/dist/src/codegen/generator/expressions/primary.js +5 -0
- package/dist/src/codegen/generator/expressions/primary.js.map +1 -1
- package/dist/src/codegen/generator/tables.d.ts +5 -6
- package/dist/src/codegen/generator/tables.js +5 -6
- package/dist/src/codegen/generator/tables.js.map +1 -1
- package/dist/src/driver/compiler.js +15 -3
- package/dist/src/driver/compiler.js.map +1 -1
- package/dist/src/driver/index.d.ts +1 -2
- package/dist/src/driver/index.js +1 -2
- package/dist/src/driver/index.js.map +1 -1
- package/dist/src/driver/modules.d.ts +1 -1
- package/dist/src/driver/modules.js +235 -25
- package/dist/src/driver/modules.js.map +1 -1
- package/dist/src/driver/paths.d.ts +0 -9
- package/dist/src/driver/paths.js +0 -31
- package/dist/src/driver/paths.js.map +1 -1
- package/dist/src/driver/toolchain-provider.d.ts +10 -10
- package/dist/src/driver/toolchain-provider.js +9 -38
- package/dist/src/driver/toolchain-provider.js.map +1 -1
- package/dist/src/driver/toolchain.js +8 -2
- package/dist/src/driver/toolchain.js.map +1 -1
- package/dist/src/extensions/native.d.ts +2 -3
- package/dist/src/extensions/native.js +2 -3
- package/dist/src/extensions/native.js.map +1 -1
- package/dist/src/extensions/node/fs/fs-ops.d.ts +5 -2
- package/dist/src/extensions/node/fs/fs-ops.js +45 -6
- package/dist/src/extensions/node/fs/fs-ops.js.map +1 -1
- package/dist/src/extensions/node/fs/index.d.ts +6 -2
- package/dist/src/extensions/node/fs/index.js +22 -3
- package/dist/src/extensions/node/fs/index.js.map +1 -1
- package/dist/src/extensions/node/fs-promises/index.d.ts +4 -3
- package/dist/src/extensions/node/fs-promises/index.js +31 -3
- package/dist/src/extensions/node/fs-promises/index.js.map +1 -1
- package/dist/tests/cli/main.test.js +8 -0
- package/dist/tests/cli/main.test.js.map +1 -1
- package/dist/tests/driver/compiler.test.js +28 -1
- package/dist/tests/driver/compiler.test.js.map +1 -1
- package/dist/tests/driver/modules.test.js +91 -4
- package/dist/tests/driver/modules.test.js.map +1 -1
- package/dist/tests/driver/paths.test.js +1 -9
- package/dist/tests/driver/paths.test.js.map +1 -1
- package/dist/tests/driver/toolchain-provider.test.js +12 -79
- package/dist/tests/driver/toolchain-provider.test.js.map +1 -1
- package/dist/tests/e2e/compile-node.test.js +240 -0
- package/dist/tests/e2e/compile-node.test.js.map +1 -1
- package/dist/tests/e2e/compile.test.js +12 -0
- package/dist/tests/e2e/compile.test.js.map +1 -1
- package/dist/tests/e2e/harness.js +11 -8
- package/dist/tests/e2e/harness.js.map +1 -1
- package/dist/tests/e2e/native-extensions.test.d.ts +4 -5
- package/dist/tests/e2e/native-extensions.test.js +6 -7
- package/dist/tests/e2e/native-extensions.test.js.map +1 -1
- package/dist/tests/e2e/node-modules.test.js +1 -1
- package/dist/tests/e2e/node-modules.test.js.map +1 -1
- package/dist/tests/e2e/npm-modules.test.d.ts +9 -0
- package/dist/tests/e2e/npm-modules.test.js +55 -0
- package/dist/tests/e2e/npm-modules.test.js.map +1 -0
- package/dist/tests/e2e/runtime-coverage.test.d.ts +11 -0
- package/dist/tests/e2e/runtime-coverage.test.js +646 -0
- package/dist/tests/e2e/runtime-coverage.test.js.map +1 -0
- package/package.json +1 -2
- package/runtime/ext_node/buffer/parts/prototype.inc +7 -0
- package/runtime/ext_node/buffer/parts/search.inc +8 -4
- package/runtime/ext_node/child_process/child_process.c +5 -0
- package/runtime/ext_node/fs/constants.c +113 -0
- package/runtime/ext_node/fs/copy_ops.c +145 -0
- package/runtime/ext_node/fs/dir.c +101 -0
- package/runtime/ext_node/fs/fd_ops.c +405 -0
- package/runtime/ext_node/fs/fs_common.h +388 -5
- package/runtime/ext_node/fs/fs_ops.c +100 -139
- package/runtime/ext_node/fs/glob.c +232 -0
- package/runtime/ext_node/fs/link_ops.c +91 -0
- package/runtime/ext_node/fs/meta_ops.c +403 -0
- package/runtime/ext_node/fs/promises.c +275 -60
- package/runtime/ext_node/fs/read_file.c +8 -4
- package/runtime/ext_node/fs/watch.c +52 -0
- package/runtime/ext_node/fs/write_file.c +20 -11
- package/runtime/ext_node/stream/stream.c +19 -2
- package/runtime/rt.h +8 -0
- package/runtime/rt_internal.h +10 -23
- package/runtime/xt_ext.h +0 -1
- package/runtime/xt_io.c +24 -3
- package/runtime/xt_stdlib2/helpers.inc +2 -4
- package/scripts/build-runtime.ts +7 -8
- package/scripts/coverage-runtime.ts +4 -4
- package/scripts/package-release.ts +12 -84
- package/src/cli/main.ts +4 -1
- package/src/codegen/generator/calls/access.ts +15 -0
- package/src/codegen/generator/calls/invocation.ts +8 -2
- package/src/codegen/generator/context.ts +30 -2
- package/src/codegen/generator/expressions/primary.ts +5 -0
- package/src/codegen/generator/tables.ts +5 -6
- package/src/driver/compiler.ts +16 -3
- package/src/driver/index.ts +1 -9
- package/src/driver/modules.ts +251 -26
- package/src/driver/paths.ts +0 -31
- package/src/driver/toolchain-provider.ts +12 -45
- package/src/driver/toolchain.ts +7 -2
- package/src/extensions/native.ts +2 -3
- package/src/extensions/node/fs/fs-ops.ts +48 -6
- package/src/extensions/node/fs/index.ts +25 -3
- package/src/extensions/node/fs-promises/index.ts +33 -4
- package/dist/src/driver/toolchain-download.d.ts +0 -50
- package/dist/src/driver/toolchain-download.js +0 -102
- package/dist/src/driver/toolchain-download.js.map +0 -1
- package/dist/tests/driver/toolchain-download.test.d.ts +0 -1
- package/dist/tests/driver/toolchain-download.test.js +0 -53
- package/dist/tests/driver/toolchain-download.test.js.map +0 -1
- package/scripts/fetch-toolchain.ts +0 -101
- package/src/driver/toolchain-download.ts +0 -135
package/scripts/build-runtime.ts
CHANGED
|
@@ -29,16 +29,15 @@ const outDir = join(runtimeDir, "lib", platformSlug());
|
|
|
29
29
|
const objDir = join(root, "build", "runtime-obj");
|
|
30
30
|
|
|
31
31
|
if (process.platform === "win32") {
|
|
32
|
-
// The
|
|
33
|
-
//
|
|
34
|
-
//
|
|
35
|
-
//
|
|
36
|
-
console.log("xbintsc:
|
|
32
|
+
// The driver links with the MSVC ABI on Windows, where the prebuilt archives
|
|
33
|
+
// are unnecessary: `build` compiles the runtime C sources on demand with the
|
|
34
|
+
// user's clang. (Producing MSVC-compatible COFF `.lib` archives is possible
|
|
35
|
+
// but not worth the extra step.)
|
|
36
|
+
console.log("xbintsc: skipping runtime archives on Windows; the driver compiles the C sources on demand");
|
|
37
37
|
process.exit(0);
|
|
38
38
|
}
|
|
39
39
|
|
|
40
|
-
// Use the same toolchain the driver will
|
|
41
|
-
// `LD_LIBRARY_PATH` (the legacy `libtinfo.so.5` on Linux) threaded through.
|
|
40
|
+
// Use the same toolchain the driver will.
|
|
42
41
|
const toolchain = resolveToolchain();
|
|
43
42
|
const clang = toolchain.clang;
|
|
44
43
|
const childEnv = Object.assign({}, process.env, toolchain.env);
|
|
@@ -54,7 +53,7 @@ function findArchiver(clangPath: string): string {
|
|
|
54
53
|
const exe = process.platform === "win32" ? ".exe" : "";
|
|
55
54
|
const candidates = [
|
|
56
55
|
process.env.xbintsc_AR,
|
|
57
|
-
// A
|
|
56
|
+
// A clang install usually ships `llvm-ar` next to the driver.
|
|
58
57
|
dir === "." ? undefined : join(dir, `llvm-ar${exe}`),
|
|
59
58
|
"llvm-ar",
|
|
60
59
|
"ar",
|
|
@@ -160,9 +160,9 @@ function runs(command: string): boolean {
|
|
|
160
160
|
|
|
161
161
|
/**
|
|
162
162
|
* Locate the LLVM tool `name` (`llvm-profdata`/`llvm-cov`) that matches the
|
|
163
|
-
* clang the driver resolved.
|
|
164
|
-
*
|
|
165
|
-
*
|
|
163
|
+
* clang the driver resolved. Prefer the tool next to clang, then the
|
|
164
|
+
* version-suffixed system installs: mixing versions makes `llvm-profdata`
|
|
165
|
+
* reject the profile format.
|
|
166
166
|
*/
|
|
167
167
|
function findTool(clang: string, name: string): string | undefined {
|
|
168
168
|
const exe = process.platform === "win32" ? ".exe" : "";
|
|
@@ -282,7 +282,7 @@ function main(): void {
|
|
|
282
282
|
profdataTool ? undefined : "llvm-profdata",
|
|
283
283
|
covTool ? undefined : "llvm-cov",
|
|
284
284
|
].filter(Boolean).join(", ");
|
|
285
|
-
skip(`${missing} not found for ${clang}; install LLVM
|
|
285
|
+
skip(`${missing} not found for ${clang}; install the LLVM tools (llvm-profdata, llvm-cov)`, options.strict);
|
|
286
286
|
}
|
|
287
287
|
|
|
288
288
|
if (!options.reportOnly) runTests(options);
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
#!/usr/bin/env node
|
|
2
2
|
/**
|
|
3
|
-
* Assemble a
|
|
3
|
+
* Assemble a release archive for the current platform:
|
|
4
4
|
*
|
|
5
5
|
* dist/release/xbintsc-<version>-<os>-<arch>.tar.gz (or .tar.zst)
|
|
6
6
|
* dist/release/xbintsc-<version>-<os>-<arch>.tar.gz.sha256
|
|
@@ -10,23 +10,24 @@
|
|
|
10
10
|
*
|
|
11
11
|
* The unpacked staging tree is built under `build/release-stage/`, never under
|
|
12
12
|
* `dist/release/`, so an upload glob over `dist/release/*` cannot accidentally
|
|
13
|
-
* ship the (
|
|
13
|
+
* ship the (large) tree alongside the archive.
|
|
14
|
+
*
|
|
15
|
+
* xbintsc does not bundle a compiler: the archive holds only the self-hosted
|
|
16
|
+
* binary and the C runtime sources plus prebuilt archives. Users provide the
|
|
17
|
+
* toolchain themselves (see `doc/requirements.md`).
|
|
14
18
|
*
|
|
15
19
|
* Layout inside the archive:
|
|
16
20
|
*
|
|
17
21
|
* xbintsc-<os>-<arch>/
|
|
18
22
|
* bin/xbintsc[.exe] the self-hosted compiler
|
|
19
23
|
* runtime/ C runtime sources + prebuilt runtime/lib/<slug>
|
|
20
|
-
* vendor/<slug>/ the bundled clang+lld toolchain (Linux/Windows)
|
|
21
24
|
* README.md
|
|
22
25
|
*
|
|
23
|
-
* The compiler locates `runtime/`
|
|
24
|
-
*
|
|
25
|
-
* toolchain installed.
|
|
26
|
+
* The compiler locates `runtime/` relative to its own executable (see
|
|
27
|
+
* `findRuntimeDir`), so this tree runs without any bundled toolchain.
|
|
26
28
|
*
|
|
27
29
|
* Inputs:
|
|
28
30
|
* - the self-hosted binary staged at `dist/xbintsc[.exe]` (CI copies it there)
|
|
29
|
-
* - `vendor/<slug>/`, fetched by `scripts/fetch-toolchain.ts`
|
|
30
31
|
* - `runtime/lib/<slug>/`, built by `scripts/build-runtime.ts`
|
|
31
32
|
*/
|
|
32
33
|
|
|
@@ -37,9 +38,7 @@ import {
|
|
|
37
38
|
chmodSync,
|
|
38
39
|
existsSync,
|
|
39
40
|
mkdirSync,
|
|
40
|
-
readdirSync,
|
|
41
41
|
readFileSync,
|
|
42
|
-
realpathSync,
|
|
43
42
|
rmSync,
|
|
44
43
|
statSync,
|
|
45
44
|
writeFileSync,
|
|
@@ -49,14 +48,12 @@ import { basename, dirname, join, resolve } from "node:path";
|
|
|
49
48
|
import { fileURLToPath } from "node:url";
|
|
50
49
|
import {
|
|
51
50
|
findRuntimeDir,
|
|
52
|
-
platformSlug,
|
|
53
51
|
releaseArchiveBase,
|
|
54
52
|
releaseArchiveExtension,
|
|
55
53
|
releaseArchiveFileName,
|
|
56
54
|
} from "../src/driver/paths.js";
|
|
57
55
|
|
|
58
56
|
const root = resolve(dirname(fileURLToPath(import.meta.url)), "..");
|
|
59
|
-
const slug = platformSlug();
|
|
60
57
|
const base = releaseArchiveBase();
|
|
61
58
|
const version = (
|
|
62
59
|
JSON.parse(readFileSync(join(root, "package.json"), "utf8")) as { version: string }
|
|
@@ -77,55 +74,6 @@ function firstExisting(candidates: readonly string[]): string | undefined {
|
|
|
77
74
|
return undefined;
|
|
78
75
|
}
|
|
79
76
|
|
|
80
|
-
/**
|
|
81
|
-
* Copy only the parts of the fetched toolchain that xbintsc actually runs.
|
|
82
|
-
*
|
|
83
|
-
* The official LLVM release unpacks to ~7 GB: every MLIR/Flang/lldb tool, the
|
|
84
|
-
* static archives and the full C++ headers. The compiler only shells out to the
|
|
85
|
-
* clang driver, the lld linker and llvm-ar, and clang additionally needs its own
|
|
86
|
-
* resource directory (`lib/clang/<version>`, the builtin headers and
|
|
87
|
-
* compiler-rt). Copying just those keeps the archive ~100x smaller.
|
|
88
|
-
*/
|
|
89
|
-
function stageToolchain(vendor: string, dest: string): void {
|
|
90
|
-
const exe = process.platform === "win32" ? ".exe" : "";
|
|
91
|
-
mkdirSync(join(dest, "bin"), { recursive: true });
|
|
92
|
-
|
|
93
|
-
const real = (...candidates: readonly string[]): string | undefined => {
|
|
94
|
-
const found = firstExisting(candidates.map((candidate) => join(vendor, candidate)));
|
|
95
|
-
return found ? realpathSync(found) : undefined;
|
|
96
|
-
};
|
|
97
|
-
const copyAs = (source: string | undefined, name: string): void => {
|
|
98
|
-
if (!source) return;
|
|
99
|
-
const target = join(dest, "bin", name);
|
|
100
|
-
copyFileSync(source, target);
|
|
101
|
-
if (process.platform !== "win32") chmodSync(target, 0o755);
|
|
102
|
-
};
|
|
103
|
-
|
|
104
|
-
// In the official release `clang`/`ld.lld` are symlinks into the bin/ dir;
|
|
105
|
-
// copy the resolved targets under the names the toolchain provider (and
|
|
106
|
-
// clang's `-fuse-ld=lld`) expect next to `bin/clang`.
|
|
107
|
-
copyAs(real(`bin/clang${exe}`, `bin/clang-18${exe}`), `clang${exe}`);
|
|
108
|
-
copyAs(real(`bin/ld.lld${exe}`, `bin/lld${exe}`), `ld.lld${exe}`);
|
|
109
|
-
copyAs(real(`bin/llvm-ar${exe}`, "bin/llvm-ar"), `llvm-ar${exe}`);
|
|
110
|
-
|
|
111
|
-
// clang's resource directory: builtin headers + compiler-rt archives.
|
|
112
|
-
const resourceDir = join(vendor, "lib", "clang");
|
|
113
|
-
if (existsSync(resourceDir)) {
|
|
114
|
-
cpSync(resourceDir, join(dest, "lib", "clang"), { recursive: true });
|
|
115
|
-
}
|
|
116
|
-
|
|
117
|
-
// Shared libraries the fetch placed next to the toolchain (on Linux that is
|
|
118
|
-
// the legacy `libtinfo.so.5` the official build still links).
|
|
119
|
-
const libDir = join(vendor, "lib");
|
|
120
|
-
if (existsSync(libDir)) {
|
|
121
|
-
for (const entry of readdirSync(libDir, { withFileTypes: true })) {
|
|
122
|
-
if (/^(.*\.so(\.\d+)*|.*\.dylib|.*\.dll)$/.test(entry.name)) {
|
|
123
|
-
cpSync(join(libDir, entry.name), join(dest, "lib", entry.name), { recursive: true });
|
|
124
|
-
}
|
|
125
|
-
}
|
|
126
|
-
}
|
|
127
|
-
}
|
|
128
|
-
|
|
129
77
|
const distDir = join(root, "dist");
|
|
130
78
|
const binary = firstExisting([
|
|
131
79
|
join(distDir, `xbintsc${exeSuffix}`),
|
|
@@ -138,7 +86,7 @@ if (!binary) {
|
|
|
138
86
|
|
|
139
87
|
// Archives go to `dist/release/`; the unpacked staging tree goes to
|
|
140
88
|
// `build/release-stage/` so the upload glob over `dist/release/*` cannot pick up
|
|
141
|
-
// the raw tree
|
|
89
|
+
// the raw tree.
|
|
142
90
|
const releaseRoot = join(distDir, "release");
|
|
143
91
|
const stageRoot = join(root, "build", "release-stage");
|
|
144
92
|
const stage = join(stageRoot, base);
|
|
@@ -156,33 +104,13 @@ console.log(`xbintsc: packaged binary ${basename(binary)} (${statSync(binary).si
|
|
|
156
104
|
cpSync(findRuntimeDir(), join(stage, "runtime"), { recursive: true });
|
|
157
105
|
console.log("xbintsc: packaged runtime/");
|
|
158
106
|
|
|
159
|
-
// 3.
|
|
160
|
-
const vendor = join(root, "vendor", slug);
|
|
161
|
-
if (existsSync(join(vendor, "bin"))) {
|
|
162
|
-
if (process.platform === "win32") {
|
|
163
|
-
// llvm-mingw spreads its MinGW-w64 CRT/import libraries across the tree, so
|
|
164
|
-
// bundling it whole is the safe default there for now.
|
|
165
|
-
cpSync(vendor, join(stage, "vendor", slug), { recursive: true });
|
|
166
|
-
} else {
|
|
167
|
-
stageToolchain(vendor, join(stage, "vendor", slug));
|
|
168
|
-
}
|
|
169
|
-
console.log(`xbintsc: packaged vendor/${slug}/`);
|
|
170
|
-
} else if (process.platform === "linux" || process.platform === "win32") {
|
|
171
|
-
console.warn(
|
|
172
|
-
`xbintsc: warning: no vendor/${slug}/ found; the release will rely on a system toolchain. ` +
|
|
173
|
-
"Run `npm run fetch-toolchain` first for a self-contained archive.",
|
|
174
|
-
);
|
|
175
|
-
} else {
|
|
176
|
-
console.log(`xbintsc: no bundled toolchain for ${slug}; relying on the system SDK (macOS)`);
|
|
177
|
-
}
|
|
178
|
-
|
|
179
|
-
// 4. Human-facing notes.
|
|
107
|
+
// 3. Human-facing notes.
|
|
180
108
|
for (const name of ["README.md", "LICENSE"]) {
|
|
181
109
|
const source = join(root, name);
|
|
182
110
|
if (existsSync(source)) copyFileSync(source, join(stage, name));
|
|
183
111
|
}
|
|
184
112
|
|
|
185
|
-
//
|
|
113
|
+
// 4. Archive it. Prefer zstd when available, otherwise gzip.
|
|
186
114
|
const hasZstd = !spawnSync("zstd", ["--version"], { stdio: "ignore" }).error;
|
|
187
115
|
const extension = releaseArchiveExtension(hasZstd);
|
|
188
116
|
const archive = join(releaseRoot, `${archiveBase}${extension}`);
|
|
@@ -192,7 +120,7 @@ const tar = spawnSync("tar", tarArgs, { stdio: "inherit" });
|
|
|
192
120
|
if (tar.error) fail(`failed to run tar: ${tar.error.message}`);
|
|
193
121
|
if (tar.status !== 0) fail(`tar exited with ${tar.status}`);
|
|
194
122
|
|
|
195
|
-
//
|
|
123
|
+
// 5. Checksum, so users can verify the download.
|
|
196
124
|
const digest = createHash("sha256").update(readFileSync(archive)).digest("hex");
|
|
197
125
|
writeFileSync(`${archive}.sha256`, `${digest} ${basename(archive)}\n`);
|
|
198
126
|
|
package/src/cli/main.ts
CHANGED
|
@@ -172,7 +172,10 @@ function doctor(io: CliIo): number {
|
|
|
172
172
|
io.stdout(`toolchain : ${toolchain.clang} (${toolchain.source})\n`);
|
|
173
173
|
io.stdout(`compiler : ${firstLine(version) || "unknown"}\n`);
|
|
174
174
|
} catch {
|
|
175
|
-
io.stdout("toolchain : not found
|
|
175
|
+
io.stdout("toolchain : not found\n");
|
|
176
|
+
io.stdout(" install one of: Xcode Command Line Tools (`xcode-select --install`) on macOS,\n");
|
|
177
|
+
io.stdout(" clang+lld (apt/dnf/pacman) on Linux, or LLVM + Visual Studio C++ build tools on Windows,\n");
|
|
178
|
+
io.stdout(" then re-run; or set xbintsc_CLANG to a clang binary. See doc/requirements.md.\n");
|
|
176
179
|
}
|
|
177
180
|
|
|
178
181
|
try {
|
|
@@ -106,6 +106,21 @@ export const accessCallMethods: AccessCallMethods = {
|
|
|
106
106
|
}
|
|
107
107
|
}
|
|
108
108
|
}
|
|
109
|
+
// Modules with no namespace dispatcher (`fs`, ...) can still expose value
|
|
110
|
+
// getters (`fs.constants`, `fs.promises`). Lower `fs.constants` the same
|
|
111
|
+
// way a named `import { constants } from "fs"` is lowered.
|
|
112
|
+
if (node.expression.kind === SyntaxKind.Identifier) {
|
|
113
|
+
const moduleExports = this.moduleExportsOfSymbol(
|
|
114
|
+
this.binding.symbolOfIdentifier.get(node.expression as Identifier),
|
|
115
|
+
);
|
|
116
|
+
const exported = moduleExports?.[node.name.text];
|
|
117
|
+
if (exported?.valueSymbol) {
|
|
118
|
+
this.extraDeclarations.add(`declare i64 @${exported.valueSymbol}(i32, i64*)`);
|
|
119
|
+
const result = this.reg();
|
|
120
|
+
this.emit(` ${result} = call i64 @${exported.valueSymbol}(i32 0, i64* null)`);
|
|
121
|
+
return result;
|
|
122
|
+
}
|
|
123
|
+
}
|
|
109
124
|
const object = this.emitExpression(node.expression);
|
|
110
125
|
return this.emitPropertyGet(object, node.name.text);
|
|
111
126
|
},
|
|
@@ -91,8 +91,14 @@ export const invocationCallMethods: InvocationCallMethods = {
|
|
|
91
91
|
return result;
|
|
92
92
|
}
|
|
93
93
|
if (callee.kind === SyntaxKind.Identifier) {
|
|
94
|
-
|
|
95
|
-
|
|
94
|
+
const identifier = callee as Identifier;
|
|
95
|
+
if (identifier.text === "super") return this.emitSuperConstructor(node);
|
|
96
|
+
const symbol = this.binding.symbolOfIdentifier.get(identifier);
|
|
97
|
+
// `require("x")` is CommonJS; the ESM form is the only supported import.
|
|
98
|
+
if (!symbol && identifier.text === "require") {
|
|
99
|
+
this.reportRequireUse(node);
|
|
100
|
+
return i64(XT_UNDEFINED);
|
|
101
|
+
}
|
|
96
102
|
if (symbol && symbol.kind === SymbolKind.Import) {
|
|
97
103
|
const exported = this.importExports.get(symbol.id);
|
|
98
104
|
if (exported) return this.emitModuleExport(node, exported);
|
|
@@ -162,8 +162,8 @@ export class GeneratorContext {
|
|
|
162
162
|
if (!symbols.some((symbol) => this.usedAsValue(symbol))) return;
|
|
163
163
|
this.diagnostics.error(
|
|
164
164
|
DiagnosticCode.ModuleNotFound,
|
|
165
|
-
`module '${specifier}' is not supported: xbintsc can
|
|
166
|
-
"relative '.ts' files
|
|
165
|
+
`module '${specifier}' is not supported: xbintsc can import built-in platform modules, ` +
|
|
166
|
+
"relative '.ts' files and ESM packages under node_modules; CommonJS packages are not supported",
|
|
167
167
|
declaration.moduleSpecifier,
|
|
168
168
|
this.sourceFile.fileName,
|
|
169
169
|
);
|
|
@@ -414,6 +414,34 @@ export class GeneratorContext {
|
|
|
414
414
|
this.sourceFile.fileName,
|
|
415
415
|
);
|
|
416
416
|
}
|
|
417
|
+
|
|
418
|
+
/**
|
|
419
|
+
* Report a CommonJS `require(...)` use. xbintsc has no CommonJS module
|
|
420
|
+
* runtime, so point the user at the ESM `import` form (with the requested
|
|
421
|
+
* module in the hint when it is a string literal).
|
|
422
|
+
*/
|
|
423
|
+
reportRequireUse(node: Node): void {
|
|
424
|
+
const specifier = requireSpecifier(node);
|
|
425
|
+
const replacement = specifier
|
|
426
|
+
? `use an ESM import instead, e.g. \`import value from ${JSON.stringify(specifier)}\``
|
|
427
|
+
: "use an ESM `import` statement instead";
|
|
428
|
+
this.diagnostics.error(
|
|
429
|
+
DiagnosticCode.UnsupportedFeature,
|
|
430
|
+
`CommonJS \`require()\` is not supported; ${replacement}`,
|
|
431
|
+
node,
|
|
432
|
+
this.sourceFile.fileName,
|
|
433
|
+
);
|
|
434
|
+
}
|
|
435
|
+
}
|
|
436
|
+
|
|
437
|
+
/** The string literal passed to `require("...")`, when there is one. */
|
|
438
|
+
function requireSpecifier(node: Node): string | undefined {
|
|
439
|
+
if (node.kind !== SyntaxKind.CallExpression) return undefined;
|
|
440
|
+
const first = (node as { arguments?: readonly Node[] }).arguments?.[0];
|
|
441
|
+
if (first && first.kind === SyntaxKind.StringLiteral) {
|
|
442
|
+
return (first as unknown as { value: string }).value;
|
|
443
|
+
}
|
|
444
|
+
return undefined;
|
|
417
445
|
}
|
|
418
446
|
|
|
419
447
|
/** A bare module specifier (`fs`, `node:fs`, `@scope/pkg`), not a file path. */
|
|
@@ -235,6 +235,11 @@ export const primaryExpressionMethods: PrimaryExpressionMethods = {
|
|
|
235
235
|
const nameValue = this.stringValue(identifier.text);
|
|
236
236
|
return this.runtimeCall("xt_error_constructor", [nameValue]);
|
|
237
237
|
}
|
|
238
|
+
// A bare `require` reference is CommonJS; steer the user to `import`.
|
|
239
|
+
if (identifier.text === "require") {
|
|
240
|
+
this.reportRequireUse(identifier);
|
|
241
|
+
return i64(XT_UNDEFINED);
|
|
242
|
+
}
|
|
238
243
|
this.diagnostics.error(
|
|
239
244
|
DiagnosticCode.CannotFindName,
|
|
240
245
|
`Cannot find name '${identifier.text}'`,
|
|
@@ -12,12 +12,11 @@ import {
|
|
|
12
12
|
/**
|
|
13
13
|
* True when a `try` frame must be saved with `_setjmpex` rather than `_setjmp`.
|
|
14
14
|
*
|
|
15
|
-
* 64-bit Windows on ARM has no `_setjmp`:
|
|
16
|
-
* `
|
|
17
|
-
*
|
|
18
|
-
*
|
|
19
|
-
*
|
|
20
|
-
* its own host.
|
|
15
|
+
* 64-bit Windows on ARM has no `_setjmp`: the UCRT declares `setjmp` as
|
|
16
|
+
* `_setjmpex(buf, sponentry)` there, so the linker expects `_setjmpex` (with the
|
|
17
|
+
* caller's stack pointer at entry, `llvm.sponentry`, instead of its frame
|
|
18
|
+
* pointer). clang lowers a C `setjmp` on this target to exactly that pair.
|
|
19
|
+
* Checked at code-generation time because xbintsc builds for its own host.
|
|
21
20
|
*/
|
|
22
21
|
export function requiresSetjmpex(platform: string, arch: string): boolean {
|
|
23
22
|
return platform === "win32" && arch === "arm64";
|
package/src/driver/compiler.ts
CHANGED
|
@@ -77,6 +77,19 @@ export function compileString(source: string, fileName = "input.ts", extensions?
|
|
|
77
77
|
return { ir, diagnostics: diagnostics.diagnostics };
|
|
78
78
|
}
|
|
79
79
|
|
|
80
|
+
/**
|
|
81
|
+
* Every module specifier the registry can resolve at code generation time (the
|
|
82
|
+
* registered platform modules plus the hints for known-but-disabled
|
|
83
|
+
* extensions). Bare imports outside this set are looked up in `node_modules`
|
|
84
|
+
* and bundled as source.
|
|
85
|
+
*/
|
|
86
|
+
function externalModuleSpecifiers(registry: ExtensionRegistry): Set<string> {
|
|
87
|
+
return new Set([
|
|
88
|
+
...Object.keys(registry.modules()),
|
|
89
|
+
...Object.keys(registry.moduleHints()),
|
|
90
|
+
]);
|
|
91
|
+
}
|
|
92
|
+
|
|
80
93
|
/**
|
|
81
94
|
* Compile a file to LLVM IR, bundling every reachable relative module first so
|
|
82
95
|
* that imports from other TypeScript sources resolve exactly like `build`.
|
|
@@ -88,6 +101,7 @@ export function compileEntry(entryPath: string, extensions?: ExtensionRegistry):
|
|
|
88
101
|
const diagnostics = new DiagnosticBag();
|
|
89
102
|
const parser = new Parser(file, diagnostics);
|
|
90
103
|
let sourceFile = parser.parseSourceFile();
|
|
104
|
+
const registry = extensions ?? createDefaultRegistry();
|
|
91
105
|
const isModule = sourceFile.statements.some(
|
|
92
106
|
(statement) =>
|
|
93
107
|
statement.kind === SyntaxKind.ImportDeclaration ||
|
|
@@ -95,10 +109,9 @@ export function compileEntry(entryPath: string, extensions?: ExtensionRegistry):
|
|
|
95
109
|
statement.kind === SyntaxKind.ExportAssignment,
|
|
96
110
|
);
|
|
97
111
|
if (isModule) {
|
|
98
|
-
const bundled = bundleModules(absoluteEntry, diagnostics);
|
|
112
|
+
const bundled = bundleModules(absoluteEntry, diagnostics, externalModuleSpecifiers(registry));
|
|
99
113
|
if (bundled) sourceFile = bundled.sourceFile;
|
|
100
114
|
}
|
|
101
|
-
const registry = extensions ?? createDefaultRegistry();
|
|
102
115
|
const { ir } = generate(sourceFile, diagnostics, {
|
|
103
116
|
builtins: registry.builtins(),
|
|
104
117
|
modules: registry.modules(),
|
|
@@ -172,7 +185,7 @@ export function build(entryPath: string, options: BuildOptions = {}): BuildResul
|
|
|
172
185
|
);
|
|
173
186
|
let cacheText = sourceText;
|
|
174
187
|
if (isModule) {
|
|
175
|
-
const bundled = bundleModules(absoluteEntry, diagnostics);
|
|
188
|
+
const bundled = bundleModules(absoluteEntry, diagnostics, externalModuleSpecifiers(registry));
|
|
176
189
|
if (bundled) {
|
|
177
190
|
sourceFile = bundled.sourceFile;
|
|
178
191
|
cacheText = bundled.text;
|
package/src/driver/index.ts
CHANGED
|
@@ -1,14 +1,6 @@
|
|
|
1
1
|
export { build, compileString, COMPILER_VERSION, type BuildOptions, type BuildResult, type EmitKind } from "./compiler.js";
|
|
2
2
|
export { BuildCache, hashParts, hashString } from "./cache.js";
|
|
3
|
-
export { findRuntimeDir,
|
|
4
|
-
export {
|
|
5
|
-
toolchainDownload,
|
|
6
|
-
toolchainSupportLibraries,
|
|
7
|
-
LLVM_VERSION,
|
|
8
|
-
LLVM_MINGW_VERSION,
|
|
9
|
-
type ToolchainDownload,
|
|
10
|
-
type SupportLibrary,
|
|
11
|
-
} from "./toolchain-download.js";
|
|
3
|
+
export { findRuntimeDir, platformSlug, releaseArchiveBase, releaseArchiveFileName, releaseArchiveExtension } from "./paths.js";
|
|
12
4
|
export { findRuntimeLibrary, runtimeLibDir } from "./runtime-lib.js";
|
|
13
5
|
export {
|
|
14
6
|
findClang,
|