xbintsc 0.3.79 → 0.3.87
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 +13 -5
- package/README.zh-CN.md +13 -6
- package/dist/src/ast/common.d.ts +23 -0
- package/dist/src/cli/main.js +68 -24
- package/dist/src/cli/main.js.map +1 -1
- package/dist/src/codegen/generator/calls/invocation.js +5 -1
- package/dist/src/codegen/generator/calls/invocation.js.map +1 -1
- package/dist/src/codegen/generator/context.d.ts +50 -0
- package/dist/src/codegen/generator/context.js +124 -13
- package/dist/src/codegen/generator/context.js.map +1 -1
- package/dist/src/codegen/generator/debug.d.ts +33 -0
- package/dist/src/codegen/generator/debug.js +97 -0
- package/dist/src/codegen/generator/debug.js.map +1 -0
- package/dist/src/codegen/generator/expressions/assignment.js +9 -5
- package/dist/src/codegen/generator/expressions/assignment.js.map +1 -1
- package/dist/src/codegen/generator/expressions/operators.js +35 -9
- package/dist/src/codegen/generator/expressions/operators.js.map +1 -1
- package/dist/src/codegen/generator/expressions/primary.js +5 -2
- package/dist/src/codegen/generator/expressions/primary.js.map +1 -1
- package/dist/src/codegen/generator/generator.d.ts +3 -1
- package/dist/src/codegen/generator/generator.js +3 -1
- package/dist/src/codegen/generator/generator.js.map +1 -1
- package/dist/src/codegen/generator/module.d.ts +1 -0
- package/dist/src/codegen/generator/module.js +76 -6
- package/dist/src/codegen/generator/module.js.map +1 -1
- package/dist/src/codegen/generator/numeric.d.ts +26 -0
- package/dist/src/codegen/generator/numeric.js +127 -0
- package/dist/src/codegen/generator/numeric.js.map +1 -0
- package/dist/src/codegen/generator/state.d.ts +17 -0
- package/dist/src/codegen/generator/state.js +5 -0
- package/dist/src/codegen/generator/state.js.map +1 -1
- package/dist/src/codegen/generator/statements/control-flow.js +1 -1
- package/dist/src/codegen/generator/statements/control-flow.js.map +1 -1
- package/dist/src/codegen/generator/statements/dispatch.js +3 -0
- package/dist/src/codegen/generator/statements/dispatch.js.map +1 -1
- package/dist/src/codegen/generator/statements/variables.js +8 -2
- package/dist/src/codegen/generator/statements/variables.js.map +1 -1
- package/dist/src/codegen/generator/tables.d.ts +7 -0
- package/dist/src/codegen/generator/tables.js +25 -0
- package/dist/src/codegen/generator/tables.js.map +1 -1
- package/dist/src/driver/bundler/merge.js +41 -5
- package/dist/src/driver/bundler/merge.js.map +1 -1
- package/dist/src/driver/compiler.d.ts +22 -3
- package/dist/src/driver/compiler.js +49 -58
- package/dist/src/driver/compiler.js.map +1 -1
- package/dist/src/driver/fingerprint.d.ts +27 -0
- package/dist/src/driver/fingerprint.js +88 -0
- package/dist/src/driver/fingerprint.js.map +1 -0
- package/dist/src/driver/toolchain-provider.d.ts +9 -2
- package/dist/src/driver/toolchain-provider.js +15 -15
- package/dist/src/driver/toolchain-provider.js.map +1 -1
- package/dist/src/driver/toolchain.d.ts +58 -1
- package/dist/src/driver/toolchain.js +169 -22
- package/dist/src/driver/toolchain.js.map +1 -1
- package/dist/src/extensions/gui/index.js +10 -2
- package/dist/src/extensions/gui/index.js.map +1 -1
- package/dist/src/parser/expressions.js +20 -1
- package/dist/src/parser/expressions.js.map +1 -1
- package/dist/tests/cli/main.test.js +41 -1
- package/dist/tests/cli/main.test.js.map +1 -1
- package/dist/tests/codegen/expressions.test.js +14 -3
- package/dist/tests/codegen/expressions.test.js.map +1 -1
- package/dist/tests/codegen/llvm.test.js +23 -0
- package/dist/tests/codegen/llvm.test.js.map +1 -1
- package/dist/tests/driver/toolchain-provider.test.js +49 -2
- package/dist/tests/driver/toolchain-provider.test.js.map +1 -1
- package/dist/tests/driver/toolchain.test.js +62 -3
- package/dist/tests/driver/toolchain.test.js.map +1 -1
- package/dist/tests/e2e/child-process.test.d.ts +10 -0
- package/dist/tests/e2e/child-process.test.js +59 -0
- package/dist/tests/e2e/child-process.test.js.map +1 -0
- package/dist/tests/e2e/compile-objects-classes.test.js +47 -0
- package/dist/tests/e2e/compile-objects-classes.test.js.map +1 -1
- package/dist/tests/e2e/error-stack.test.d.ts +9 -0
- package/dist/tests/e2e/error-stack.test.js +94 -0
- package/dist/tests/e2e/error-stack.test.js.map +1 -0
- package/dist/tests/e2e/gui-example-svg.test.d.ts +21 -0
- package/dist/tests/e2e/gui-example-svg.test.js +105 -0
- package/dist/tests/e2e/gui-example-svg.test.js.map +1 -0
- package/dist/tests/e2e/gui-transform.test.d.ts +7 -0
- package/dist/tests/e2e/gui-transform.test.js +198 -0
- package/dist/tests/e2e/gui-transform.test.js.map +1 -0
- package/dist/tests/e2e/string-concat.test.d.ts +9 -0
- package/dist/tests/e2e/string-concat.test.js +102 -0
- package/dist/tests/e2e/string-concat.test.js.map +1 -0
- package/dist/tests/helpers.d.ts +9 -0
- package/dist/tests/helpers.js +26 -3
- package/dist/tests/helpers.js.map +1 -1
- package/dist/tests/parser/expressions.test.js +7 -0
- package/dist/tests/parser/expressions.test.js.map +1 -1
- package/dist/tests/version.test.d.ts +1 -0
- package/dist/tests/version.test.js +24 -0
- package/dist/tests/version.test.js.map +1 -0
- package/doc/DESIGN.md +20 -12
- package/doc/ai/cli.md +7 -0
- package/doc/ai/contributing.md +7 -1
- package/doc/ai/extensions.md +5 -1
- package/doc/ai/language-support.md +4 -4
- package/doc/ai/troubleshooting.md +39 -2
- package/doc/ai/zh-CN/cli.md +2 -0
- package/doc/ai/zh-CN/contributing.md +6 -2
- package/doc/ai/zh-CN/extensions.md +5 -1
- package/doc/ai/zh-CN/language-support.md +4 -4
- package/doc/ai/zh-CN/troubleshooting.md +35 -2
- package/doc/gui/animation.md +53 -2
- package/doc/gui/api.md +1 -1
- package/doc/gui/dom.md +6 -1
- package/doc/gui/input.md +4 -1
- package/doc/gui/known-issues.md +16 -4
- package/doc/gui/layout.md +36 -0
- package/doc/gui/rendering.md +15 -0
- package/doc/gui.md +32 -3
- package/doc/implemented.md +4 -4
- package/doc/requirements.md +13 -4
- package/doc/unimplemented.md +11 -10
- package/doc/zh-CN/DESIGN.md +15 -9
- package/doc/zh-CN/gui/animation.md +49 -2
- package/doc/zh-CN/gui/api.md +1 -1
- package/doc/zh-CN/gui/dom.md +6 -1
- package/doc/zh-CN/gui/input.md +2 -0
- package/doc/zh-CN/gui/known-issues.md +12 -2
- package/doc/zh-CN/gui/layout.md +31 -0
- package/doc/zh-CN/gui/rendering.md +11 -0
- package/doc/zh-CN/gui.md +28 -3
- package/doc/zh-CN/implemented.md +4 -4
- package/doc/zh-CN/requirements.md +12 -3
- package/doc/zh-CN/unimplemented.md +10 -9
- package/package.json +3 -1
- package/runtime/ext_gui/document.cpp +21 -3
- package/runtime/ext_gui/document.h +4 -1
- package/runtime/ext_gui/dom_api_node.cpp +6 -4
- package/runtime/ext_gui/layout.cpp +78 -1
- package/runtime/ext_gui/layout.h +21 -0
- package/runtime/ext_gui/paint.cpp +48 -15
- package/runtime/ext_gui/paint.h +8 -2
- package/runtime/ext_gui/renderer.cpp +4 -2
- package/runtime/ext_gui/renderer_image.cpp +2 -1
- package/runtime/ext_gui/renderer_internal.h +6 -1
- package/runtime/ext_gui/renderer_text.cpp +37 -15
- package/runtime/ext_gui/style.h +10 -0
- package/runtime/ext_gui/style_print.cpp +6 -0
- package/runtime/ext_gui/style_values.cpp +43 -0
- package/runtime/ext_gui/transform.cpp +412 -0
- package/runtime/ext_gui/transform.h +112 -0
- package/runtime/ext_gui/window.cpp +6 -4
- package/runtime/ext_node/buffer/parts/construction.inc +2 -2
- package/runtime/ext_node/buffer/parts/methods.inc +1 -1
- package/runtime/ext_node/buffer/parts/search.inc +1 -1
- package/runtime/ext_node/child_process/child_process.c +25 -0
- package/runtime/ext_node/fs/fd_ops.c +1 -1
- package/runtime/rt.h +17 -1
- package/runtime/rt_internal.h +47 -4
- package/runtime/xt_alloc.c +14 -2
- package/runtime/xt_bigint/conversions.inc +1 -1
- package/runtime/xt_builtins.c +136 -14
- package/runtime/xt_containers/access.inc +17 -16
- package/runtime/xt_containers/objects.inc +4 -3
- package/runtime/xt_io/exception.inc +171 -2
- package/runtime/xt_io/inspect.inc +15 -13
- package/runtime/xt_io.c +5 -0
- package/runtime/xt_stdlib/arrays.inc +2 -2
- package/runtime/xt_stdlib/dispatch.inc +2 -2
- package/runtime/xt_stdlib/strings.inc +33 -21
- package/runtime/xt_stdlib2/array-statics.inc +2 -1
- package/runtime/xt_stdlib2/arrays.inc +1 -1
- package/runtime/xt_stdlib2/error.inc +22 -6
- package/runtime/xt_stdlib2/json.inc +3 -2
- package/runtime/xt_stdlib2/number-string-statics.inc +3 -1
- package/runtime/xt_stdlib2/regexp-match.inc +48 -33
- package/runtime/xt_stdlib2/strings.inc +23 -14
- package/runtime/xt_symbol.c +1 -1
- package/runtime/xt_values/comparison.inc +2 -2
- package/runtime/xt_values/constructors.inc +10 -5
- package/runtime/xt_values/conversions.inc +4 -3
- package/runtime/xt_values/strings.inc +78 -4
- package/scripts/bench.ts +172 -0
- package/scripts/build-runtime.ts +2 -1
- package/scripts/check-version.ts +53 -0
- package/src/ast/common.ts +23 -0
- package/src/cli/main.ts +68 -26
- package/src/codegen/generator/calls/invocation.ts +5 -0
- package/src/codegen/generator/context.ts +129 -18
- package/src/codegen/generator/debug.ts +132 -0
- package/src/codegen/generator/expressions/assignment.ts +9 -5
- package/src/codegen/generator/expressions/operators.ts +47 -8
- package/src/codegen/generator/expressions/primary.ts +5 -2
- package/src/codegen/generator/generator.ts +18 -2
- package/src/codegen/generator/module.ts +78 -6
- package/src/codegen/generator/numeric.ts +158 -0
- package/src/codegen/generator/state.ts +22 -0
- package/src/codegen/generator/statements/control-flow.ts +1 -1
- package/src/codegen/generator/statements/dispatch.ts +3 -0
- package/src/codegen/generator/statements/variables.ts +8 -2
- package/src/codegen/generator/tables.ts +26 -0
- package/src/driver/bundler/merge.ts +39 -5
- package/src/driver/compiler.ts +68 -56
- package/src/driver/fingerprint.ts +85 -0
- package/src/driver/toolchain-provider.ts +17 -16
- package/src/driver/toolchain.ts +210 -21
- package/src/extensions/gui/index.ts +10 -2
- package/src/parser/expressions.ts +20 -1
package/src/driver/toolchain.ts
CHANGED
|
@@ -6,6 +6,8 @@
|
|
|
6
6
|
*/
|
|
7
7
|
|
|
8
8
|
import { spawnSync, type SpawnSyncOptions } from "node:child_process";
|
|
9
|
+
import { existsSync } from "node:fs";
|
|
10
|
+
import { join } from "node:path";
|
|
9
11
|
|
|
10
12
|
export interface CommandResult {
|
|
11
13
|
readonly status: number;
|
|
@@ -53,26 +55,176 @@ export class ToolchainError extends Error {
|
|
|
53
55
|
}
|
|
54
56
|
}
|
|
55
57
|
|
|
56
|
-
/**
|
|
57
|
-
|
|
58
|
-
|
|
59
|
-
|
|
60
|
-
|
|
61
|
-
|
|
62
|
-
|
|
63
|
-
|
|
64
|
-
|
|
65
|
-
|
|
66
|
-
|
|
67
|
-
|
|
68
|
-
|
|
69
|
-
|
|
70
|
-
|
|
71
|
-
|
|
58
|
+
/**
|
|
59
|
+
* The oldest clang/LLVM the emitted IR is known to compile with. LLVM 16 made
|
|
60
|
+
* opaque pointers the only pointer representation, and the IR emitted by
|
|
61
|
+
* `src/codegen` relies on that; clang 15 and older reject it with
|
|
62
|
+
* "'@.str.0' defined with type '[6 x i8]*' but expected 'i8*'".
|
|
63
|
+
*/
|
|
64
|
+
export const MINIMUM_CLANG_MAJOR = 16;
|
|
65
|
+
|
|
66
|
+
export interface ClangVersion {
|
|
67
|
+
readonly major: number;
|
|
68
|
+
readonly minor: number;
|
|
69
|
+
readonly patch: number;
|
|
70
|
+
}
|
|
71
|
+
|
|
72
|
+
/** Result of probing one candidate with `--version`. */
|
|
73
|
+
export interface ClangProbe {
|
|
74
|
+
readonly command: string;
|
|
75
|
+
/** True when the command ran and exited 0. */
|
|
76
|
+
readonly responds: boolean;
|
|
77
|
+
readonly version?: ClangVersion;
|
|
78
|
+
/** First line of the version output, for diagnostics. */
|
|
79
|
+
readonly summary: string;
|
|
80
|
+
}
|
|
81
|
+
|
|
82
|
+
export interface ClangLocation {
|
|
83
|
+
readonly command: string;
|
|
84
|
+
readonly source: "env" | "system";
|
|
85
|
+
/** Absent when an explicit wrapper does not print a parseable version. */
|
|
86
|
+
readonly version?: ClangVersion;
|
|
87
|
+
}
|
|
88
|
+
|
|
89
|
+
/**
|
|
90
|
+
* Extract the LLVM version from a `--version` line. Accepts "clang version
|
|
91
|
+
* 19.1.5", "Apple clang version 15.0.0" and distribution prefixes such as
|
|
92
|
+
* "Ubuntu clang version 18.1.3"; returns `undefined` for anything else (notably
|
|
93
|
+
* gcc, which `cc` may resolve to).
|
|
94
|
+
*/
|
|
95
|
+
export function parseClangVersion(output: string): ClangVersion | undefined {
|
|
96
|
+
const match = /clang version (\d+)\.(\d+)\.(\d+)/i.exec(output);
|
|
97
|
+
if (!match) return undefined;
|
|
98
|
+
return { major: Number(match[1]), minor: Number(match[2]), patch: Number(match[3]) };
|
|
99
|
+
}
|
|
100
|
+
|
|
101
|
+
function firstLineOf(text: string): string {
|
|
102
|
+
const end = text.indexOf("\n");
|
|
103
|
+
return (end === -1 ? text : text.slice(0, end)).trim();
|
|
104
|
+
}
|
|
105
|
+
|
|
106
|
+
/** Run `<command> --version` and classify the result. Never throws. */
|
|
107
|
+
export function probeClang(
|
|
108
|
+
runner: Runner,
|
|
109
|
+
command: string,
|
|
110
|
+
env?: Record<string, string>,
|
|
111
|
+
): ClangProbe {
|
|
112
|
+
try {
|
|
113
|
+
const result = runner.run(command, ["--version"], env ? { env } : undefined);
|
|
114
|
+
const output = `${result.stdout}\n${result.stderr}`;
|
|
115
|
+
const version = parseClangVersion(output);
|
|
116
|
+
return {
|
|
117
|
+
command,
|
|
118
|
+
responds: result.status === 0,
|
|
119
|
+
...(version ? { version } : {}),
|
|
120
|
+
summary: firstLineOf(result.stdout) || firstLineOf(result.stderr),
|
|
121
|
+
};
|
|
122
|
+
} catch {
|
|
123
|
+
return { command, responds: false, summary: "" };
|
|
124
|
+
}
|
|
125
|
+
}
|
|
126
|
+
|
|
127
|
+
/**
|
|
128
|
+
* Visual Studio ships its own LLVM build (`VC\Tools\Llvm\x64\bin\clang.exe`).
|
|
129
|
+
* It is a perfectly good driver but is not on `PATH` in a plain shell, so probe
|
|
130
|
+
* the well-known install locations too. Only candidates that exist are
|
|
131
|
+
* returned, and only on Windows.
|
|
132
|
+
*/
|
|
133
|
+
function visualStudioClangCandidates(): string[] {
|
|
134
|
+
if (process.platform !== "win32") return [];
|
|
135
|
+
const roots = [process.env.ProgramFiles, process.env["ProgramFiles(x86)"], process.env.ProgramW6432]
|
|
136
|
+
.filter((root): root is string => Boolean(root));
|
|
137
|
+
const arch = process.arch === "arm64" ? "ARM64" : "x64";
|
|
138
|
+
const candidates: string[] = [];
|
|
139
|
+
for (const root of roots) {
|
|
140
|
+
for (const year of ["2022", "2019"]) {
|
|
141
|
+
for (const edition of ["Community", "Professional", "Enterprise", "BuildTools"]) {
|
|
142
|
+
const llvm = join(root, "Microsoft Visual Studio", year, edition, "VC", "Tools", "Llvm");
|
|
143
|
+
candidates.push(join(llvm, arch, "bin", "clang.exe"));
|
|
144
|
+
candidates.push(join(llvm, "bin", "clang.exe"));
|
|
145
|
+
}
|
|
72
146
|
}
|
|
73
|
-
|
|
147
|
+
candidates.push(join(root, "LLVM", "bin", "clang.exe"));
|
|
74
148
|
}
|
|
75
|
-
|
|
149
|
+
return [...new Set(candidates)].filter((candidate) => existsSync(candidate));
|
|
150
|
+
}
|
|
151
|
+
|
|
152
|
+
/** Commands probed for a system compiler, in preference order. */
|
|
153
|
+
export function systemClangCandidates(): string[] {
|
|
154
|
+
const candidates = ["clang"];
|
|
155
|
+
for (let major = 20; major >= MINIMUM_CLANG_MAJOR; major--) candidates.push(`clang-${major}`);
|
|
156
|
+
candidates.push("cc");
|
|
157
|
+
candidates.push(...visualStudioClangCandidates());
|
|
158
|
+
return [...new Set(candidates)];
|
|
159
|
+
}
|
|
160
|
+
|
|
161
|
+
function tooOldError(probe: ClangProbe): ToolchainError {
|
|
162
|
+
const version = probe.version!;
|
|
163
|
+
const found = `clang ${version.major}.${version.minor}.${version.patch}`;
|
|
164
|
+
return new ToolchainError(
|
|
165
|
+
"clang --version",
|
|
166
|
+
1,
|
|
167
|
+
`${probe.command} reports ${found}, but xbintsc requires clang ${MINIMUM_CLANG_MAJOR} or newer ` +
|
|
168
|
+
"(the emitted LLVM IR uses opaque pointers).\n" +
|
|
169
|
+
"Install a newer LLVM/clang (on Windows, the one bundled with Visual Studio works) or set " +
|
|
170
|
+
`xbintsc_CLANG to a clang ${MINIMUM_CLANG_MAJOR}+ binary.`,
|
|
171
|
+
);
|
|
172
|
+
}
|
|
173
|
+
|
|
174
|
+
function noCompilerError(tried: readonly ClangProbe[]): ToolchainError {
|
|
175
|
+
const responded = tried.filter((probe) => probe.responds);
|
|
176
|
+
const details = responded.map((probe) => {
|
|
177
|
+
const version = probe.version
|
|
178
|
+
? `clang ${probe.version.major}.${probe.version.minor}.${probe.version.patch}`
|
|
179
|
+
: probe.summary || "unknown version";
|
|
180
|
+
return ` ${probe.command}: ${version}`;
|
|
181
|
+
});
|
|
182
|
+
const tooOld = responded.some((probe) => probe.version !== undefined && probe.version.major < MINIMUM_CLANG_MAJOR);
|
|
183
|
+
const reason = tooOld
|
|
184
|
+
? `Only clang older than ${MINIMUM_CLANG_MAJOR} was found; xbintsc requires clang ${MINIMUM_CLANG_MAJOR}+ ` +
|
|
185
|
+
"(the emitted LLVM IR uses opaque pointers)."
|
|
186
|
+
: `No clang ${MINIMUM_CLANG_MAJOR}+ was found.`;
|
|
187
|
+
return new ToolchainError(
|
|
188
|
+
"clang --version",
|
|
189
|
+
1,
|
|
190
|
+
[reason, ...(details.length > 0 ? ["Tested:", ...details] : []), "Set xbintsc_CLANG to a clang binary."].join("\n"),
|
|
191
|
+
);
|
|
192
|
+
}
|
|
193
|
+
|
|
194
|
+
/**
|
|
195
|
+
* Resolve the compiler to use, version-checked.
|
|
196
|
+
*
|
|
197
|
+
* An explicit `xbintsc_CLANG` / `xbintsc_TOOLCHAIN` wins even when it is older
|
|
198
|
+
* than the minimum: the user asked for it, so the clear "too old" error is more
|
|
199
|
+
* helpful than silently using another compiler. A broken explicit path falls
|
|
200
|
+
* back to the system search. System candidates are probed in order and the
|
|
201
|
+
* first one reporting clang >= {@link MINIMUM_CLANG_MAJOR} wins, so a modern
|
|
202
|
+
* clang installed next to an old `/usr/bin/clang` is still found.
|
|
203
|
+
*/
|
|
204
|
+
export function locateClang(runner: Runner = realRunner): ClangLocation {
|
|
205
|
+
const explicit = process.env.xbintsc_CLANG ?? process.env.xbintsc_TOOLCHAIN;
|
|
206
|
+
const tried: ClangProbe[] = [];
|
|
207
|
+
if (explicit) {
|
|
208
|
+
const probe = probeClang(runner, explicit);
|
|
209
|
+
if (probe.responds) {
|
|
210
|
+
if (probe.version && probe.version.major < MINIMUM_CLANG_MAJOR) throw tooOldError(probe);
|
|
211
|
+
return { command: explicit, source: "env", ...(probe.version ? { version: probe.version } : {}) };
|
|
212
|
+
}
|
|
213
|
+
tried.push(probe);
|
|
214
|
+
}
|
|
215
|
+
for (const command of systemClangCandidates()) {
|
|
216
|
+
const probe = probeClang(runner, command);
|
|
217
|
+
tried.push(probe);
|
|
218
|
+
if (!probe.responds || !probe.version) continue;
|
|
219
|
+
if (probe.version.major < MINIMUM_CLANG_MAJOR) continue;
|
|
220
|
+
return { command, source: "system", version: probe.version };
|
|
221
|
+
}
|
|
222
|
+
throw noCompilerError(tried);
|
|
223
|
+
}
|
|
224
|
+
|
|
225
|
+
/** Locate a supported clang-compatible C compiler, or throw a clear error. */
|
|
226
|
+
export function findClang(runner: Runner = realRunner): string {
|
|
227
|
+
return locateClang(runner).command;
|
|
76
228
|
}
|
|
77
229
|
|
|
78
230
|
export interface CompileIrOptions {
|
|
@@ -81,13 +233,23 @@ export interface CompileIrOptions {
|
|
|
81
233
|
readonly objectPath: string;
|
|
82
234
|
readonly optimize: string;
|
|
83
235
|
readonly env?: Record<string, string>;
|
|
236
|
+
/** Emit debug info (`-g`) and keep frame pointers for crash backtraces. */
|
|
237
|
+
readonly debug?: boolean;
|
|
84
238
|
}
|
|
85
239
|
|
|
240
|
+
/**
|
|
241
|
+
* One function/data item per section so the linker can drop everything a
|
|
242
|
+
* program never references. This is what `--gc-sections` / `-dead_strip` need;
|
|
243
|
+
* the runtime is a set of translation units with many unused entry points.
|
|
244
|
+
*/
|
|
245
|
+
const SECTION_FLAGS = ["-ffunction-sections", "-fdata-sections"];
|
|
246
|
+
|
|
86
247
|
/** Compile an LLVM IR file to a native object file. */
|
|
87
248
|
export function compileIr(runner: Runner, options: CompileIrOptions): void {
|
|
249
|
+
const debugFlags = options.debug ? ["-g", "-fno-omit-frame-pointer"] : [];
|
|
88
250
|
const result = runner.run(
|
|
89
251
|
options.clang,
|
|
90
|
-
[`-O${options.optimize}`, "-c", options.irPath, "-o", options.objectPath],
|
|
252
|
+
[`-O${options.optimize}`, ...SECTION_FLAGS, ...debugFlags, "-c", options.irPath, "-o", options.objectPath],
|
|
91
253
|
{ env: options.env },
|
|
92
254
|
);
|
|
93
255
|
if (result.status !== 0) throw new ToolchainError(`${options.clang} ${options.irPath}`, result.status, result.stderr);
|
|
@@ -102,12 +264,39 @@ export interface LinkOptions {
|
|
|
102
264
|
readonly env?: Record<string, string>;
|
|
103
265
|
}
|
|
104
266
|
|
|
267
|
+
/** Platform flag that drops unreferenced sections (paired with {@link SECTION_FLAGS}). */
|
|
268
|
+
function deadStripFlag(): string[] {
|
|
269
|
+
if (process.platform === "win32") return []; // link.exe /OPT:REF is on by default
|
|
270
|
+
if (process.platform === "darwin") return ["-Wl,-dead_strip"];
|
|
271
|
+
return ["-Wl,--gc-sections"];
|
|
272
|
+
}
|
|
273
|
+
|
|
105
274
|
export function link(runner: Runner, options: LinkOptions): void {
|
|
106
|
-
const args = [
|
|
275
|
+
const args = [
|
|
276
|
+
`-O${options.optimize}`,
|
|
277
|
+
...options.objectPaths,
|
|
278
|
+
"-o",
|
|
279
|
+
options.outputPath,
|
|
280
|
+
...deadStripFlag(),
|
|
281
|
+
...options.linkerFlags,
|
|
282
|
+
];
|
|
107
283
|
const result = runner.run(options.clang, args, { env: options.env });
|
|
108
284
|
if (result.status !== 0) throw new ToolchainError(`${options.clang} link`, result.status, result.stderr);
|
|
109
285
|
}
|
|
110
286
|
|
|
287
|
+
/**
|
|
288
|
+
* Flags shared by every runtime/extension C compile. Exported so the object
|
|
289
|
+
* cache key can change when they do: the cache is keyed by source content, and
|
|
290
|
+
* a flag change is a different object.
|
|
291
|
+
*/
|
|
292
|
+
export const RUNTIME_CFLAGS = [
|
|
293
|
+
"-O2",
|
|
294
|
+
"-Wall",
|
|
295
|
+
"-Wextra",
|
|
296
|
+
"-D_CRT_SECURE_NO_WARNINGS",
|
|
297
|
+
...SECTION_FLAGS,
|
|
298
|
+
] as const;
|
|
299
|
+
|
|
111
300
|
/** Compile a C source to an object file (used for the runtime and extensions). */
|
|
112
301
|
export function compileC(
|
|
113
302
|
runner: Runner,
|
|
@@ -119,7 +308,7 @@ export function compileC(
|
|
|
119
308
|
): void {
|
|
120
309
|
const result = runner.run(
|
|
121
310
|
clang,
|
|
122
|
-
[
|
|
311
|
+
[...RUNTIME_CFLAGS, "-c", sourcePath, "-o", objectPath, `-I${includeDir}`],
|
|
123
312
|
{ env },
|
|
124
313
|
);
|
|
125
314
|
if (result.status !== 0) throw new ToolchainError(`${clang} ${sourcePath}`, result.status, result.stderr);
|
|
@@ -98,8 +98,16 @@ export const guiExtension: Extension = {
|
|
|
98
98
|
"-luser32", "-lgdi32", "-lshell32",
|
|
99
99
|
"-lole32", "-loleaut32", "-luuid", "-ladvapi32",
|
|
100
100
|
"-lwinmm", "-limm32", "-lversion", "-lsetupapi",
|
|
101
|
-
/* The engine is C
|
|
102
|
-
|
|
101
|
+
/* The engine is C++, but `msvcprt` (the DLL C++ runtime) must not be
|
|
102
|
+
* named here: `gui.lib` is built with `CMAKE_MSVC_RUNTIME_LIBRARY=
|
|
103
|
+
* MultiThreaded` and every engine object records `libcpmt` (the static
|
|
104
|
+
* C++ runtime) as a dependent library — see `scripts/build-gui.ts`.
|
|
105
|
+
* The two runtimes define the same symbols, so requesting the DLL one
|
|
106
|
+
* as well fails the link with `LNK2038: mismatch detected for
|
|
107
|
+
* 'RuntimeLibrary'` plus a wall of `LNK2005: already defined` errors
|
|
108
|
+
* (surfacing as `clang: linker command failed with exit code 1169`).
|
|
109
|
+
* clang links the static `libcpmt` by default, which is the CRT the
|
|
110
|
+
* archive and the xbintsc runtime objects were both built against. */
|
|
103
111
|
];
|
|
104
112
|
}
|
|
105
113
|
return ["-lX11", "-lwayland-client", "-lEGL", "-lGL", "-ldl", "-lpthread", "-lstdc++"];
|
|
@@ -299,7 +299,26 @@ export const expressionMethods: ExpressionMethods = {
|
|
|
299
299
|
},
|
|
300
300
|
|
|
301
301
|
parseNewExpression(this: Parser): NewExpression {
|
|
302
|
-
const
|
|
302
|
+
const newToken = this.parseExpected(TokenKind.NewKeyword);
|
|
303
|
+
const start = newToken.start;
|
|
304
|
+
/* `new.target` is not part of the supported subset. Parsing it as a member
|
|
305
|
+
* access produced "Unexpected token '.'" pointing at the dot; report what
|
|
306
|
+
* is actually unsupported instead. */
|
|
307
|
+
if (this.at(TokenKind.Dot) && this.atAhead(1, TokenKind.Identifier) && this.lookAhead(1).text === "target") {
|
|
308
|
+
this.nextToken(); // .
|
|
309
|
+
const target = this.nextToken(); // target
|
|
310
|
+
this.error(DiagnosticCode.UnsupportedFeature, "xbintsc does not yet support new.target", {
|
|
311
|
+
...newToken,
|
|
312
|
+
end: target.end,
|
|
313
|
+
});
|
|
314
|
+
const placeholder: Expression = {
|
|
315
|
+
kind: SyntaxKind.Identifier,
|
|
316
|
+
text: "undefined",
|
|
317
|
+
start: target.start,
|
|
318
|
+
end: target.end,
|
|
319
|
+
};
|
|
320
|
+
return { kind: SyntaxKind.NewExpression, expression: placeholder, typeArguments: [], arguments: [], start, end: target.end };
|
|
321
|
+
}
|
|
303
322
|
const callee = this.parseMemberOnlyExpression();
|
|
304
323
|
const typeArguments = this.at(TokenKind.LessThan) ? this.parseTypeArguments() : [];
|
|
305
324
|
const args = this.at(TokenKind.OpenParen) ? this.parseArguments() : [];
|