xbintsc 0.3.25 → 0.3.46
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 +39 -3
- package/dist/src/cli/main.js +124 -30
- package/dist/src/cli/main.js.map +1 -1
- package/dist/src/codegen/generator/calls/access.js +8 -1
- package/dist/src/codegen/generator/calls/access.js.map +1 -1
- package/dist/src/codegen/generator/module.js +10 -0
- package/dist/src/codegen/generator/module.js.map +1 -1
- package/dist/src/codegen/generator/state.js +24 -0
- package/dist/src/codegen/generator/state.js.map +1 -1
- package/dist/src/codegen/generator/tables.d.ts +6 -0
- package/dist/src/codegen/generator/tables.js +38 -0
- package/dist/src/codegen/generator/tables.js.map +1 -1
- package/dist/src/driver/bundler/commonjs.d.ts +52 -0
- package/dist/src/driver/bundler/commonjs.js +493 -0
- package/dist/src/driver/bundler/commonjs.js.map +1 -0
- package/dist/src/driver/bundler/graph.js +14 -0
- package/dist/src/driver/bundler/graph.js.map +1 -1
- package/dist/src/driver/bundler/merge.js +14 -0
- package/dist/src/driver/bundler/merge.js.map +1 -1
- package/dist/src/driver/bundler/types.d.ts +8 -0
- package/dist/src/driver/compiler.d.ts +8 -1
- package/dist/src/driver/compiler.js +73 -5
- package/dist/src/driver/compiler.js.map +1 -1
- package/dist/src/driver/config.d.ts +53 -0
- package/dist/src/driver/config.js +141 -0
- package/dist/src/driver/config.js.map +1 -0
- package/dist/src/driver/icon.d.ts +62 -0
- package/dist/src/driver/icon.js +151 -0
- package/dist/src/driver/icon.js.map +1 -0
- package/dist/src/driver/index.d.ts +4 -0
- package/dist/src/driver/index.js +4 -0
- package/dist/src/driver/index.js.map +1 -1
- package/dist/src/driver/mac-bundle.d.ts +41 -0
- package/dist/src/driver/mac-bundle.js +123 -0
- package/dist/src/driver/mac-bundle.js.map +1 -0
- package/dist/src/driver/win-icon.d.ts +27 -0
- package/dist/src/driver/win-icon.js +80 -0
- package/dist/src/driver/win-icon.js.map +1 -0
- package/dist/src/parser/statements.js +17 -4
- package/dist/src/parser/statements.js.map +1 -1
- package/dist/tests/cli/main.test.js +46 -1
- package/dist/tests/cli/main.test.js.map +1 -1
- package/dist/tests/driver/config.test.d.ts +1 -0
- package/dist/tests/driver/config.test.js +124 -0
- package/dist/tests/driver/config.test.js.map +1 -0
- package/dist/tests/driver/icon.test.d.ts +1 -0
- package/dist/tests/driver/icon.test.js +421 -0
- package/dist/tests/driver/icon.test.js.map +1 -0
- package/dist/tests/driver/modules.test.js +109 -0
- package/dist/tests/driver/modules.test.js.map +1 -1
- package/dist/tests/e2e/fetch.test.d.ts +12 -0
- package/dist/tests/e2e/fetch.test.js +272 -0
- package/dist/tests/e2e/fetch.test.js.map +1 -0
- package/dist/tests/e2e/gc.test.d.ts +1 -0
- package/dist/tests/e2e/gc.test.js +168 -0
- package/dist/tests/e2e/gc.test.js.map +1 -0
- package/dist/tests/e2e/gui-dom.test.d.ts +5 -0
- package/dist/tests/e2e/gui-dom.test.js +102 -0
- package/dist/tests/e2e/gui-dom.test.js.map +1 -0
- package/dist/tests/e2e/gui-events.test.d.ts +5 -0
- package/dist/tests/e2e/gui-events.test.js +60 -0
- package/dist/tests/e2e/gui-events.test.js.map +1 -0
- package/dist/tests/e2e/gui-helpers.d.ts +31 -0
- package/dist/tests/e2e/gui-helpers.js +74 -0
- package/dist/tests/e2e/gui-helpers.js.map +1 -0
- package/dist/tests/e2e/gui-layout.test.d.ts +4 -0
- package/dist/tests/e2e/gui-layout.test.js +88 -0
- package/dist/tests/e2e/gui-layout.test.js.map +1 -0
- package/dist/tests/e2e/gui-lifecycle.test.d.ts +5 -0
- package/dist/tests/e2e/gui-lifecycle.test.js +58 -0
- package/dist/tests/e2e/gui-lifecycle.test.js.map +1 -0
- package/dist/tests/e2e/gui-paint.test.d.ts +5 -0
- package/dist/tests/e2e/gui-paint.test.js +111 -0
- package/dist/tests/e2e/gui-paint.test.js.map +1 -0
- package/dist/tests/e2e/gui-script.test.d.ts +5 -0
- package/dist/tests/e2e/gui-script.test.js +78 -0
- package/dist/tests/e2e/gui-script.test.js.map +1 -0
- package/dist/tests/e2e/gui-style.test.d.ts +5 -0
- package/dist/tests/e2e/gui-style.test.js +175 -0
- package/dist/tests/e2e/gui-style.test.js.map +1 -0
- package/dist/tests/e2e/harness.d.ts +2 -0
- package/dist/tests/e2e/harness.js +1 -0
- package/dist/tests/e2e/harness.js.map +1 -1
- package/dist/tests/e2e/icon.test.d.ts +7 -0
- package/dist/tests/e2e/icon.test.js +80 -0
- package/dist/tests/e2e/icon.test.js.map +1 -0
- package/dist/tests/e2e/npm-modules.test.d.ts +4 -1
- package/dist/tests/e2e/npm-modules.test.js +47 -1
- package/dist/tests/e2e/npm-modules.test.js.map +1 -1
- package/dist/tests/e2e/runtime-coverage-typed-array.test.d.ts +9 -0
- package/dist/tests/e2e/runtime-coverage-typed-array.test.js +140 -0
- package/dist/tests/e2e/runtime-coverage-typed-array.test.js.map +1 -0
- package/dist/tests/parser/statements.test.js +11 -0
- package/dist/tests/parser/statements.test.js.map +1 -1
- package/package.json +3 -2
- package/runtime/ext_gui/css.cpp +4 -517
- package/runtime/ext_gui/css_internal.h +27 -0
- package/runtime/ext_gui/css_match.cpp +195 -0
- package/runtime/ext_gui/css_selector.cpp +207 -0
- package/runtime/ext_gui/css_sheet.cpp +129 -0
- package/runtime/ext_gui/dom.cpp +7 -403
- package/runtime/ext_gui/dom_api.cpp +63 -1146
- package/runtime/ext_gui/dom_api_document.cpp +96 -0
- package/runtime/ext_gui/dom_api_events.cpp +123 -0
- package/runtime/ext_gui/dom_api_internal.h +135 -0
- package/runtime/ext_gui/dom_api_node.cpp +329 -0
- package/runtime/ext_gui/dom_api_node_read.cpp +294 -0
- package/runtime/ext_gui/dom_api_proto.cpp +135 -0
- package/runtime/ext_gui/dom_api_style.cpp +192 -0
- package/runtime/ext_gui/dom_internal.h +39 -0
- package/runtime/ext_gui/dom_parse.cpp +348 -0
- package/runtime/ext_gui/dom_serialize.cpp +54 -0
- package/runtime/ext_gui/gui.cpp +56 -286
- package/runtime/ext_gui/gui_events.cpp +294 -0
- package/runtime/ext_gui/gui_internal.h +29 -0
- package/runtime/ext_gui/layout.cpp +6 -597
- package/runtime/ext_gui/layout_flex.cpp +200 -0
- package/runtime/ext_gui/layout_flow.cpp +191 -0
- package/runtime/ext_gui/layout_flow_internal.h +149 -0
- package/runtime/ext_gui/layout_inline.cpp +181 -0
- package/runtime/ext_gui/layout_internal.h +20 -0
- package/runtime/ext_gui/renderer.cpp +15 -679
- package/runtime/ext_gui/renderer_image.cpp +233 -0
- package/runtime/ext_gui/renderer_internal.h +112 -0
- package/runtime/ext_gui/renderer_shaders.h +108 -0
- package/runtime/ext_gui/renderer_text.cpp +342 -0
- package/runtime/ext_gui/style.cpp +12 -660
- package/runtime/ext_gui/style_internal.h +33 -0
- package/runtime/ext_gui/style_print.cpp +113 -0
- package/runtime/ext_gui/style_ua.cpp +98 -0
- package/runtime/ext_gui/style_values.cpp +468 -0
- package/runtime/ext_gui/window.cpp +1 -0
- package/runtime/ext_node/buffer/parts/prototype.inc +1 -0
- package/runtime/ext_node/dgram/dgram.c +1 -0
- package/runtime/ext_node/events/events.c +1 -0
- package/runtime/ext_node/fs/fs_ops.c +10 -25
- package/runtime/ext_node/fs/glob.c +13 -30
- package/runtime/ext_node/fs/promises.c +1 -0
- package/runtime/ext_node/http/parts/prototypes.inc +5 -0
- package/runtime/ext_node/net/parts/prototypes.inc +2 -0
- package/runtime/ext_node/process/process.c +9 -7
- package/runtime/ext_node/stream/stream.c +1 -0
- package/runtime/ext_node/util/util.c +6 -6
- package/runtime/rt.h +16 -0
- package/runtime/rt_internal.h +67 -2
- package/runtime/xt_alloc.c +442 -5
- package/runtime/xt_builtins.c +1 -0
- package/runtime/xt_containers/access.inc +32 -1
- package/runtime/xt_fetch/buffer.inc +64 -0
- package/runtime/xt_fetch/headers.inc +312 -0
- package/runtime/xt_fetch/request.inc +386 -0
- package/runtime/xt_fetch/response.inc +107 -0
- package/runtime/xt_fetch/socket.inc +72 -0
- package/runtime/xt_fetch/url.inc +108 -0
- package/runtime/xt_fetch.c +39 -0
- package/runtime/xt_generator.c +95 -1
- package/runtime/xt_loop.c +35 -1
- package/runtime/xt_promise.c +46 -0
- package/runtime/xt_stdlib2/error.inc +1 -0
- package/runtime/xt_stdlib2/regexp-match.inc +8 -7
- package/runtime/xt_stdlib2/set.inc +1 -1
- package/runtime/xt_symbol.c +2 -0
- package/runtime/xt_typed_array/construction.inc +142 -0
- package/runtime/xt_typed_array/elements.inc +92 -0
- package/runtime/xt_typed_array/methods.inc +329 -0
- package/runtime/xt_typed_array.c +72 -0
- package/runtime/xt_values/number-format.inc +26 -0
- package/scripts/check-file-length.ts +85 -0
- package/src/cli/main.ts +137 -29
- package/src/codegen/generator/calls/access.ts +9 -1
- package/src/codegen/generator/module.ts +10 -0
- package/src/codegen/generator/state.ts +24 -0
- package/src/codegen/generator/tables.ts +40 -0
- package/src/driver/bundler/commonjs.ts +553 -0
- package/src/driver/bundler/graph.ts +14 -0
- package/src/driver/bundler/merge.ts +15 -0
- package/src/driver/bundler/types.ts +8 -0
- package/src/driver/compiler.ts +83 -5
- package/src/driver/config.ts +173 -0
- package/src/driver/icon.ts +184 -0
- package/src/driver/index.ts +30 -0
- package/src/driver/mac-bundle.ts +156 -0
- package/src/driver/win-icon.ts +96 -0
- package/src/parser/statements.ts +17 -4
- package/dist/tests/e2e/gui.test.d.ts +0 -12
- package/dist/tests/e2e/gui.test.js +0 -702
- package/dist/tests/e2e/gui.test.js.map +0 -1
|
@@ -0,0 +1,85 @@
|
|
|
1
|
+
#!/usr/bin/env node
|
|
2
|
+
/**
|
|
3
|
+
* Enforce the per-file line budget for code ESLint cannot parse.
|
|
4
|
+
*
|
|
5
|
+
* ESLint's `max-lines` rule already caps the TypeScript/JavaScript sources at
|
|
6
|
+
* 600 lines (see `eslint.config.js`). This script applies the same budget to
|
|
7
|
+
* the runtime's C, C++, Rust and `#include`d `.inc` fragments plus shell
|
|
8
|
+
* scripts, so *every* code file stays focused and small.
|
|
9
|
+
*
|
|
10
|
+
* Vendored third-party sources that must ship verbatim (notably the
|
|
11
|
+
* single-header `stb_image.h`) are exempt: they are not ours to split.
|
|
12
|
+
*
|
|
13
|
+
* Run via `npm run lint` (or `tsx scripts/check-file-length.ts`).
|
|
14
|
+
*/
|
|
15
|
+
|
|
16
|
+
import { readdirSync, readFileSync } from "node:fs";
|
|
17
|
+
import { join, relative, resolve } from "node:path";
|
|
18
|
+
import { fileURLToPath } from "node:url";
|
|
19
|
+
|
|
20
|
+
const root = resolve(fileURLToPath(new URL(".", import.meta.url)), "..");
|
|
21
|
+
|
|
22
|
+
/** Maximum number of lines allowed in a single code file. */
|
|
23
|
+
const MAX_LINES = 600;
|
|
24
|
+
|
|
25
|
+
const CODE_EXTENSIONS = new Set([".c", ".h", ".cc", ".cpp", ".hpp", ".rs", ".inc", ".sh"]);
|
|
26
|
+
|
|
27
|
+
const IGNORED_DIRECTORIES = new Set([
|
|
28
|
+
".git",
|
|
29
|
+
"build",
|
|
30
|
+
"coverage",
|
|
31
|
+
"dist",
|
|
32
|
+
"node_modules",
|
|
33
|
+
"scratch",
|
|
34
|
+
"target",
|
|
35
|
+
"vendor",
|
|
36
|
+
]);
|
|
37
|
+
|
|
38
|
+
/** Vendored third-party sources that ship verbatim and are not ours to split. */
|
|
39
|
+
const VENDORED_FILES = new Set([join("runtime", "ext_gui", "stb_image.h")]);
|
|
40
|
+
|
|
41
|
+
interface Offense {
|
|
42
|
+
file: string;
|
|
43
|
+
lines: number;
|
|
44
|
+
}
|
|
45
|
+
|
|
46
|
+
function countLines(path: string): number {
|
|
47
|
+
const content = readFileSync(path, "utf8");
|
|
48
|
+
if (content.length === 0) return 0;
|
|
49
|
+
// A trailing newline terminates the last line instead of starting a new one.
|
|
50
|
+
const lines = content.split("\n");
|
|
51
|
+
return content.endsWith("\n") ? lines.length - 1 : lines.length;
|
|
52
|
+
}
|
|
53
|
+
|
|
54
|
+
function collect(dir: string, offenses: Offense[]): void {
|
|
55
|
+
for (const entry of readdirSync(dir, { withFileTypes: true }).sort((a, b) => a.name.localeCompare(b.name))) {
|
|
56
|
+
const full = join(dir, entry.name);
|
|
57
|
+
if (entry.isDirectory()) {
|
|
58
|
+
if (IGNORED_DIRECTORIES.has(entry.name)) continue;
|
|
59
|
+
// `runtime/lib` holds prebuilt archives, never sources.
|
|
60
|
+
if (relative(root, full) === join("runtime", "lib")) continue;
|
|
61
|
+
collect(full, offenses);
|
|
62
|
+
continue;
|
|
63
|
+
}
|
|
64
|
+
if (!entry.isFile()) continue;
|
|
65
|
+
const dot = entry.name.lastIndexOf(".");
|
|
66
|
+
if (dot < 0 || !CODE_EXTENSIONS.has(entry.name.slice(dot))) continue;
|
|
67
|
+
const file = relative(root, full);
|
|
68
|
+
if (VENDORED_FILES.has(file)) continue;
|
|
69
|
+
const lines = countLines(full);
|
|
70
|
+
if (lines > MAX_LINES) offenses.push({ file, lines });
|
|
71
|
+
}
|
|
72
|
+
}
|
|
73
|
+
|
|
74
|
+
const offenses: Offense[] = [];
|
|
75
|
+
collect(root, offenses);
|
|
76
|
+
|
|
77
|
+
if (offenses.length > 0) {
|
|
78
|
+
console.error(`xbintsc: code files must stay under ${MAX_LINES} lines - split them by responsibility:`);
|
|
79
|
+
for (const offense of offenses.sort((a, b) => b.lines - a.lines)) {
|
|
80
|
+
console.error(` ${offense.file}: ${offense.lines} lines`);
|
|
81
|
+
}
|
|
82
|
+
process.exit(1);
|
|
83
|
+
}
|
|
84
|
+
|
|
85
|
+
console.log(`xbintsc: all code files are within ${MAX_LINES} lines`);
|
package/src/cli/main.ts
CHANGED
|
@@ -14,6 +14,7 @@
|
|
|
14
14
|
|
|
15
15
|
import { spawnSync } from "node:child_process";
|
|
16
16
|
import { readFileSync } from "node:fs";
|
|
17
|
+
import { dirname, resolve } from "node:path";
|
|
17
18
|
import { pathToFileURL } from "node:url";
|
|
18
19
|
import { formatDiagnostic, type Diagnostic } from "../diagnostics/diagnostic.js";
|
|
19
20
|
import { SourceFile } from "../diagnostics/source.js";
|
|
@@ -25,6 +26,15 @@ import { realRunner } from "../driver/toolchain.js";
|
|
|
25
26
|
import { createDefaultRegistry, type ExtensionRegistry } from "../extensions/registry.js";
|
|
26
27
|
import { bundledExtensions } from "../extensions/catalog.js";
|
|
27
28
|
import { nativeExtensionFromManifest } from "../extensions/native.js";
|
|
29
|
+
import { resolveResourceCompiler } from "../driver/win-icon.js";
|
|
30
|
+
import {
|
|
31
|
+
CONFIG_FILE_NAME,
|
|
32
|
+
findProjectConfig,
|
|
33
|
+
loadProjectConfig,
|
|
34
|
+
resolveConfigPaths,
|
|
35
|
+
type AppConfig,
|
|
36
|
+
type ProjectConfig,
|
|
37
|
+
} from "../driver/config.js";
|
|
28
38
|
|
|
29
39
|
export interface CliIo {
|
|
30
40
|
readonly stdout: (text: string) => void;
|
|
@@ -43,7 +53,18 @@ interface ParsedArgs {
|
|
|
43
53
|
readonly passthrough: string[];
|
|
44
54
|
}
|
|
45
55
|
|
|
46
|
-
const VALUE_FLAGS = new Set([
|
|
56
|
+
const VALUE_FLAGS = new Set([
|
|
57
|
+
"output",
|
|
58
|
+
"out",
|
|
59
|
+
"emit",
|
|
60
|
+
"optimize",
|
|
61
|
+
"ext",
|
|
62
|
+
"ext-native",
|
|
63
|
+
"config",
|
|
64
|
+
"icon",
|
|
65
|
+
"app-id",
|
|
66
|
+
"app-name",
|
|
67
|
+
]);
|
|
47
68
|
|
|
48
69
|
function parseArgs(argv: readonly string[]): ParsedArgs {
|
|
49
70
|
const positionals: string[] = [];
|
|
@@ -95,29 +116,22 @@ function parseArgs(argv: readonly string[]): ParsedArgs {
|
|
|
95
116
|
return { command: positionals.shift(), positionals, flags, passthrough };
|
|
96
117
|
}
|
|
97
118
|
|
|
98
|
-
function buildRegistry(
|
|
119
|
+
function buildRegistry(extNames: readonly string[], nativeManifests: readonly string[]): ExtensionRegistry {
|
|
99
120
|
const registry = createDefaultRegistry();
|
|
100
|
-
const
|
|
101
|
-
|
|
102
|
-
const
|
|
103
|
-
|
|
104
|
-
|
|
105
|
-
if (!extension) throw new Error(`Unknown extension '${name}'`);
|
|
106
|
-
registry.register(extension);
|
|
107
|
-
}
|
|
121
|
+
const bundled = bundledExtensions();
|
|
122
|
+
for (const name of extNames) {
|
|
123
|
+
const extension = bundled.find((candidate) => candidate.name === name);
|
|
124
|
+
if (!extension) throw new Error(`Unknown extension '${name}'`);
|
|
125
|
+
registry.register(extension);
|
|
108
126
|
}
|
|
109
|
-
// Each
|
|
110
|
-
|
|
111
|
-
|
|
112
|
-
if (typeof native === "string") {
|
|
113
|
-
for (const manifest of native.split(",").map((n) => n.trim()).filter(Boolean)) {
|
|
114
|
-
registry.register(nativeExtensionFromManifest(manifest));
|
|
115
|
-
}
|
|
127
|
+
// Each manifest describes a pre-built C++ or Rust library.
|
|
128
|
+
for (const manifest of nativeManifests) {
|
|
129
|
+
registry.register(nativeExtensionFromManifest(manifest));
|
|
116
130
|
}
|
|
117
131
|
// Hint the extensions that ship with xbintsc but were not enabled, so a
|
|
118
132
|
// missing `import` of a known module points at the flag that enables it
|
|
119
133
|
// (`pass --ext node`) instead of failing later with a confusing error.
|
|
120
|
-
for (const extension of
|
|
134
|
+
for (const extension of bundled) {
|
|
121
135
|
if (!registry.has(extension.name)) registry.hintExtension(extension);
|
|
122
136
|
}
|
|
123
137
|
return registry;
|
|
@@ -131,6 +145,11 @@ function printDiagnostics(diagnostics: readonly Diagnostic[], fileName: string,
|
|
|
131
145
|
source = undefined;
|
|
132
146
|
}
|
|
133
147
|
for (const diagnostic of diagnostics) {
|
|
148
|
+
// Driver-level diagnostics (icon, config, …) have no source location.
|
|
149
|
+
if (diagnostic.fileName === undefined && diagnostic.start === undefined) {
|
|
150
|
+
io.stderr(`error TS${diagnostic.code}: ${diagnostic.message}\n`);
|
|
151
|
+
continue;
|
|
152
|
+
}
|
|
134
153
|
io.stderr(formatDiagnostic(diagnostic, source) + "\n");
|
|
135
154
|
}
|
|
136
155
|
}
|
|
@@ -153,6 +172,13 @@ Options:
|
|
|
153
172
|
--ext <names> Comma separated extensions (e.g. node)
|
|
154
173
|
--ext-native <m> Register a C++/Rust extension from a JSON manifest
|
|
155
174
|
(comma separated for several)
|
|
175
|
+
--config <path> Use a project config (default: auto-detect
|
|
176
|
+
${CONFIG_FILE_NAME})
|
|
177
|
+
--no-config Do not read any project config
|
|
178
|
+
--icon <path> Embed an application icon (PNG/ICO/ICNS)
|
|
179
|
+
--bundle macOS: also produce a .app bundle
|
|
180
|
+
--app-name <name> Bundle / display name
|
|
181
|
+
--app-id <id> macOS bundle identifier (e.g. com.example.demo)
|
|
156
182
|
--force Ignore the incremental cache
|
|
157
183
|
--verbose Print progress information
|
|
158
184
|
`;
|
|
@@ -190,9 +216,70 @@ function doctor(io: CliIo): number {
|
|
|
190
216
|
} catch {
|
|
191
217
|
io.stdout("runtime lib: unavailable\n");
|
|
192
218
|
}
|
|
219
|
+
|
|
220
|
+
try {
|
|
221
|
+
const toolchain = resolveToolchain();
|
|
222
|
+
const resource = resolveResourceCompiler(realRunner, toolchain.clang);
|
|
223
|
+
io.stdout(`icon res : ${resource ? `${resource.tool} (${resource.kind})` : "none (.exe icon disabled)"}\n`);
|
|
224
|
+
} catch {
|
|
225
|
+
io.stdout("icon res : unknown\n");
|
|
226
|
+
}
|
|
193
227
|
return 0;
|
|
194
228
|
}
|
|
195
229
|
|
|
230
|
+
type ConfigResolution =
|
|
231
|
+
| { readonly ok: true; readonly config: ProjectConfig }
|
|
232
|
+
| { readonly ok: false; readonly error: string };
|
|
233
|
+
|
|
234
|
+
/**
|
|
235
|
+
* Resolve the project config for a command: `--config <path>` selects one
|
|
236
|
+
* explicitly, `--no-config` disables discovery, otherwise we walk up from the
|
|
237
|
+
* entry file (or the cwd) looking for {@link CONFIG_FILE_NAME}.
|
|
238
|
+
*/
|
|
239
|
+
function resolveProjectConfig(
|
|
240
|
+
flags: Map<string, string | boolean>,
|
|
241
|
+
cliEntry: string | undefined,
|
|
242
|
+
): ConfigResolution {
|
|
243
|
+
try {
|
|
244
|
+
const explicit = flags.get("config");
|
|
245
|
+
if (typeof explicit === "string") {
|
|
246
|
+
return { ok: true, config: resolveConfigPaths(loadProjectConfig(explicit)) };
|
|
247
|
+
}
|
|
248
|
+
if (flags.has("no-config")) return { ok: true, config: {} };
|
|
249
|
+
const startDir = cliEntry ? dirname(resolve(cliEntry)) : process.cwd();
|
|
250
|
+
const found = findProjectConfig(startDir);
|
|
251
|
+
if (!found) return { ok: true, config: {} };
|
|
252
|
+
return { ok: true, config: resolveConfigPaths(loadProjectConfig(found)) };
|
|
253
|
+
} catch (error) {
|
|
254
|
+
return { ok: false, error: (error as Error).message };
|
|
255
|
+
}
|
|
256
|
+
}
|
|
257
|
+
|
|
258
|
+
/** Merge `app.*` config with the CLI overrides (`--icon`, `--bundle`, …). */
|
|
259
|
+
function mergeAppConfig(flags: Map<string, string | boolean>, config: ProjectConfig): AppConfig {
|
|
260
|
+
const base = config.app ?? {};
|
|
261
|
+
const name = typeof flags.get("app-name") === "string" ? (flags.get("app-name") as string) : base.name;
|
|
262
|
+
const bundleId = typeof flags.get("app-id") === "string" ? (flags.get("app-id") as string) : base.bundleId;
|
|
263
|
+
const bundle = flags.has("bundle") ? true : base.bundle;
|
|
264
|
+
const icon = typeof flags.get("icon") === "string" ? (flags.get("icon") as string) : base.icon;
|
|
265
|
+
return {
|
|
266
|
+
...(name !== undefined ? { name } : {}),
|
|
267
|
+
...(bundleId !== undefined ? { bundleId } : {}),
|
|
268
|
+
...(bundle !== undefined ? { bundle } : {}),
|
|
269
|
+
...(icon !== undefined ? { icon } : {}),
|
|
270
|
+
};
|
|
271
|
+
}
|
|
272
|
+
|
|
273
|
+
/** Split a comma-separated CLI flag into a trimmed, non-empty list. */
|
|
274
|
+
function listFlag(flags: Map<string, string | boolean>, name: string): string[] | undefined {
|
|
275
|
+
const value = flags.get(name);
|
|
276
|
+
if (typeof value !== "string") return undefined;
|
|
277
|
+
return value
|
|
278
|
+
.split(",")
|
|
279
|
+
.map((entry) => entry.trim())
|
|
280
|
+
.filter(Boolean);
|
|
281
|
+
}
|
|
282
|
+
|
|
196
283
|
export function run(argv: readonly string[], io: CliIo = defaultIo): number {
|
|
197
284
|
const args = parseArgs(argv);
|
|
198
285
|
const command = args.command;
|
|
@@ -212,12 +299,20 @@ export function run(argv: readonly string[], io: CliIo = defaultIo): number {
|
|
|
212
299
|
}
|
|
213
300
|
|
|
214
301
|
if (command === "emit") {
|
|
215
|
-
const
|
|
302
|
+
const cliEntry = args.positionals[0];
|
|
303
|
+
const resolved = resolveProjectConfig(args.flags, cliEntry);
|
|
304
|
+
if (!resolved.ok) {
|
|
305
|
+
io.stderr(`xbintsc: ${resolved.error}\n`);
|
|
306
|
+
return 1;
|
|
307
|
+
}
|
|
308
|
+
const entry = cliEntry ?? resolved.config.entry;
|
|
216
309
|
if (!entry) {
|
|
217
|
-
io.stderr(
|
|
310
|
+
io.stderr(`xbintsc: emit requires a source file (or 'entry' in ${CONFIG_FILE_NAME})\n`);
|
|
218
311
|
return 1;
|
|
219
312
|
}
|
|
220
|
-
const
|
|
313
|
+
const extNames = listFlag(args.flags, "ext") ?? resolved.config.extensions ?? [];
|
|
314
|
+
const nativeManifests = listFlag(args.flags, "ext-native") ?? resolved.config.extNative ?? [];
|
|
315
|
+
const registry = buildRegistry(extNames, nativeManifests);
|
|
221
316
|
const { ir, diagnostics } = compileEntry(entry, registry);
|
|
222
317
|
if (diagnostics.some((d) => d.category === "error")) {
|
|
223
318
|
printDiagnostics(diagnostics, entry, io);
|
|
@@ -228,21 +323,33 @@ export function run(argv: readonly string[], io: CliIo = defaultIo): number {
|
|
|
228
323
|
}
|
|
229
324
|
|
|
230
325
|
if (command === "build" || command === "run") {
|
|
231
|
-
const
|
|
326
|
+
const cliEntry = args.positionals[0];
|
|
327
|
+
const resolved = resolveProjectConfig(args.flags, cliEntry);
|
|
328
|
+
if (!resolved.ok) {
|
|
329
|
+
io.stderr(`xbintsc: ${resolved.error}\n`);
|
|
330
|
+
return 1;
|
|
331
|
+
}
|
|
332
|
+
const config = resolved.config;
|
|
333
|
+
const entry = cliEntry ?? config.entry;
|
|
232
334
|
if (!entry) {
|
|
233
|
-
io.stderr(`xbintsc: ${command} requires a source file\n`);
|
|
335
|
+
io.stderr(`xbintsc: ${command} requires a source file (or 'entry' in ${CONFIG_FILE_NAME})\n`);
|
|
234
336
|
return 1;
|
|
235
337
|
}
|
|
236
338
|
const emit = (args.flags.get("emit") as EmitKind | undefined) ?? "exe";
|
|
237
|
-
const optimize = (args.flags.get("optimize") as string | undefined) ?? "2";
|
|
339
|
+
const optimize = (args.flags.get("optimize") as string | undefined) ?? config.optimize ?? "2";
|
|
340
|
+
const extNames = listFlag(args.flags, "ext") ?? config.extensions ?? [];
|
|
341
|
+
const nativeManifests = listFlag(args.flags, "ext-native") ?? config.extNative ?? [];
|
|
342
|
+
const registry = buildRegistry(extNames, nativeManifests);
|
|
343
|
+
|
|
238
344
|
const result = build(entry, {
|
|
239
|
-
output: typeof args.flags.get("output") === "string" ? (args.flags.get("output") as string) :
|
|
240
|
-
outDir: typeof args.flags.get("out") === "string" ? (args.flags.get("out") as string) :
|
|
345
|
+
output: typeof args.flags.get("output") === "string" ? (args.flags.get("output") as string) : config.output,
|
|
346
|
+
outDir: typeof args.flags.get("out") === "string" ? (args.flags.get("out") as string) : config.outDir,
|
|
241
347
|
emit,
|
|
242
348
|
optimize: optimize as "0" | "1" | "2" | "3",
|
|
243
|
-
force: Boolean(args.flags.get("force")),
|
|
349
|
+
force: Boolean(args.flags.get("force")) || config.force === true,
|
|
244
350
|
verbose: Boolean(args.flags.get("verbose")),
|
|
245
|
-
extensions:
|
|
351
|
+
extensions: registry,
|
|
352
|
+
app: mergeAppConfig(args.flags, config),
|
|
246
353
|
});
|
|
247
354
|
|
|
248
355
|
if (result.diagnostics.some((d) => d.category === "error")) {
|
|
@@ -251,7 +358,8 @@ export function run(argv: readonly string[], io: CliIo = defaultIo): number {
|
|
|
251
358
|
}
|
|
252
359
|
|
|
253
360
|
if (command === "build") {
|
|
254
|
-
|
|
361
|
+
const bundle = result.bundlePath ? ` (bundle: ${result.bundlePath})` : "";
|
|
362
|
+
io.stdout(`xbintsc: wrote ${result.outputPath}${result.cached ? " (cached)" : ""}${bundle}\n`);
|
|
255
363
|
return 0;
|
|
256
364
|
}
|
|
257
365
|
|
|
@@ -13,7 +13,7 @@ import {
|
|
|
13
13
|
type PropertyAccessExpression,
|
|
14
14
|
} from "../../../ast/nodes.js";
|
|
15
15
|
import { i64, numberLiteral, XT_TRUE, XT_UNDEFINED } from "../../values.js";
|
|
16
|
-
import { MATH_CONSTANTS, NAMESPACE_PROPERTIES, NUMBER_CONSTANTS } from "../tables.js";
|
|
16
|
+
import { MATH_CONSTANTS, NAMESPACE_PROPERTIES, NUMBER_CONSTANTS, TYPED_ARRAYS } from "../tables.js";
|
|
17
17
|
import type { Generator } from "../generator.js";
|
|
18
18
|
|
|
19
19
|
export interface AccessCallMethods {
|
|
@@ -121,6 +121,14 @@ export const accessCallMethods: AccessCallMethods = {
|
|
|
121
121
|
return result;
|
|
122
122
|
}
|
|
123
123
|
}
|
|
124
|
+
if (
|
|
125
|
+
node.expression.kind === SyntaxKind.Identifier &&
|
|
126
|
+
!this.binding.symbolOfIdentifier.get(node.expression as Identifier) &&
|
|
127
|
+
node.name.text === "BYTES_PER_ELEMENT"
|
|
128
|
+
) {
|
|
129
|
+
const typed = TYPED_ARRAYS[(node.expression as Identifier).text];
|
|
130
|
+
if (typed) return numberLiteral(typed.bytes);
|
|
131
|
+
}
|
|
124
132
|
const object = this.emitExpression(node.expression);
|
|
125
133
|
return this.emitPropertyGet(object, node.name.text);
|
|
126
134
|
},
|
|
@@ -227,9 +227,19 @@ export const moduleMethods: ModuleMethods = {
|
|
|
227
227
|
|
|
228
228
|
emitMain(): void {
|
|
229
229
|
const moduleName = this.functionName(this.binding.moduleFunction);
|
|
230
|
+
// Module bindings and class constructors live in globals; register them as
|
|
231
|
+
// GC roots before the module body runs so a collection cannot free them.
|
|
232
|
+
const roots = [...this.classGlobals.values(), ...this.moduleGlobals.values()];
|
|
233
|
+
const rootLines = roots.map((name) => ` call void @xt_gc_add_root(i64* ${name})`);
|
|
230
234
|
this.functions.push(
|
|
231
235
|
[
|
|
232
236
|
"define i32 @main(i32 %argc, i8** %argv) {",
|
|
237
|
+
" %stackbase = alloca i64",
|
|
238
|
+
" %stackbase.ptr = bitcast i64* %stackbase to i8*",
|
|
239
|
+
" call void @xt_gc_set_stack_base(i8* %stackbase.ptr)",
|
|
240
|
+
" call void @xt_gc_init()",
|
|
241
|
+
...rootLines,
|
|
242
|
+
" call void @xt_gc_arm()",
|
|
233
243
|
" call void @xt_set_program_args(i32 %argc, i8** %argv)",
|
|
234
244
|
` %result = call i64 @${moduleName}(i64 ${i64(XT_UNDEFINED)}, i64 ${i64(XT_UNDEFINED)}, i32 0, i64* null)`,
|
|
235
245
|
" call void @xt_drain_microtasks()",
|
|
@@ -103,6 +103,10 @@ export const RUNTIME_DECLARATIONS: readonly string[] = [
|
|
|
103
103
|
"declare i64 @xt_await(i64)",
|
|
104
104
|
"declare void @xt_drain_microtasks()",
|
|
105
105
|
"declare void @xt_run_event_loop()",
|
|
106
|
+
"declare void @xt_gc_init()",
|
|
107
|
+
"declare void @xt_gc_set_stack_base(i8*)",
|
|
108
|
+
"declare void @xt_gc_arm()",
|
|
109
|
+
"declare void @xt_gc_add_root(i64*)",
|
|
106
110
|
"declare i64 @xt_promise_resolve(i64)",
|
|
107
111
|
"declare i64 @xt_promise_reject(i64)",
|
|
108
112
|
"declare i64 @xt_promise_ctor(i32, i64*)",
|
|
@@ -116,6 +120,24 @@ export const RUNTIME_DECLARATIONS: readonly string[] = [
|
|
|
116
120
|
"declare i64 @xt_os_static(i64, i32, i64*)",
|
|
117
121
|
"declare i64 @xt_buffer_static(i64, i32, i64*)",
|
|
118
122
|
"declare i64 @xt_buffer_ctor(i32, i64*)",
|
|
123
|
+
"declare i64 @xt_ta_u8_ctor(i32, i64*)",
|
|
124
|
+
"declare i64 @xt_ta_u8_static(i64, i32, i64*)",
|
|
125
|
+
"declare i64 @xt_ta_i8_ctor(i32, i64*)",
|
|
126
|
+
"declare i64 @xt_ta_i8_static(i64, i32, i64*)",
|
|
127
|
+
"declare i64 @xt_ta_u8c_ctor(i32, i64*)",
|
|
128
|
+
"declare i64 @xt_ta_u8c_static(i64, i32, i64*)",
|
|
129
|
+
"declare i64 @xt_ta_u16_ctor(i32, i64*)",
|
|
130
|
+
"declare i64 @xt_ta_u16_static(i64, i32, i64*)",
|
|
131
|
+
"declare i64 @xt_ta_i16_ctor(i32, i64*)",
|
|
132
|
+
"declare i64 @xt_ta_i16_static(i64, i32, i64*)",
|
|
133
|
+
"declare i64 @xt_ta_u32_ctor(i32, i64*)",
|
|
134
|
+
"declare i64 @xt_ta_u32_static(i64, i32, i64*)",
|
|
135
|
+
"declare i64 @xt_ta_i32_ctor(i32, i64*)",
|
|
136
|
+
"declare i64 @xt_ta_i32_static(i64, i32, i64*)",
|
|
137
|
+
"declare i64 @xt_ta_f32_ctor(i32, i64*)",
|
|
138
|
+
"declare i64 @xt_ta_f32_static(i64, i32, i64*)",
|
|
139
|
+
"declare i64 @xt_ta_f64_ctor(i32, i64*)",
|
|
140
|
+
"declare i64 @xt_ta_f64_static(i64, i32, i64*)",
|
|
119
141
|
"declare i64 @xt_stream_static(i64, i32, i64*)",
|
|
120
142
|
"declare i64 @xt_readable_ctor(i32, i64*)",
|
|
121
143
|
"declare i64 @xt_writable_ctor(i32, i64*)",
|
|
@@ -219,6 +241,7 @@ export const RUNTIME_DECLARATIONS: readonly string[] = [
|
|
|
219
241
|
"declare i64 @xt_clear_timeout(i32, i64*)",
|
|
220
242
|
"declare i64 @xt_set_interval(i32, i64*)",
|
|
221
243
|
"declare i64 @xt_clear_interval(i32, i64*)",
|
|
244
|
+
"declare i64 @xt_fetch(i32, i64*)",
|
|
222
245
|
"declare i64 @xt_number_ctor(i32, i64*)",
|
|
223
246
|
"declare i64 @xt_bigint_ctor(i32, i64*)",
|
|
224
247
|
"declare i64 @xt_bigint_static(i64, i32, i64*)",
|
|
@@ -254,6 +277,7 @@ export const RUNTIME_DECLARATIONS: readonly string[] = [
|
|
|
254
277
|
"declare i64 @xt_builtin_value_clearTimeout(i64, i64, i32, i64*)",
|
|
255
278
|
"declare i64 @xt_builtin_value_setInterval(i64, i64, i32, i64*)",
|
|
256
279
|
"declare i64 @xt_builtin_value_clearInterval(i64, i64, i32, i64*)",
|
|
280
|
+
"declare i64 @xt_builtin_value_fetch(i64, i64, i32, i64*)",
|
|
257
281
|
"declare i64 @xt_builtin_value_number(i64, i64, i32, i64*)",
|
|
258
282
|
"declare i64 @xt_builtin_value_string(i64, i64, i32, i64*)",
|
|
259
283
|
"declare i64 @xt_builtin_value_boolean(i64, i64, i32, i64*)",
|
|
@@ -127,6 +127,7 @@ export const GLOBAL_FUNCTIONS: Record<string, string> = {
|
|
|
127
127
|
clearTimeout: "xt_clear_timeout",
|
|
128
128
|
setInterval: "xt_set_interval",
|
|
129
129
|
clearInterval: "xt_clear_interval",
|
|
130
|
+
fetch: "xt_fetch",
|
|
130
131
|
Number: "xt_number_ctor",
|
|
131
132
|
String: "xt_string_ctor",
|
|
132
133
|
Boolean: "xt_boolean_ctor",
|
|
@@ -150,6 +151,7 @@ export const BUILTIN_FUNCTION_VALUES: Record<string, string> = {
|
|
|
150
151
|
clearTimeout: "xt_builtin_value_clearTimeout",
|
|
151
152
|
setInterval: "xt_builtin_value_setInterval",
|
|
152
153
|
clearInterval: "xt_builtin_value_clearInterval",
|
|
154
|
+
fetch: "xt_builtin_value_fetch",
|
|
153
155
|
Number: "xt_builtin_value_number",
|
|
154
156
|
String: "xt_builtin_value_string",
|
|
155
157
|
Boolean: "xt_builtin_value_boolean",
|
|
@@ -157,6 +159,42 @@ export const BUILTIN_FUNCTION_VALUES: Record<string, string> = {
|
|
|
157
159
|
Symbol: "xt_builtin_value_symbol",
|
|
158
160
|
};
|
|
159
161
|
|
|
162
|
+
/** Typed-array globals: constructor, static dispatcher and element width. */
|
|
163
|
+
export const TYPED_ARRAYS: Record<string, { ctor: string; static: string; bytes: number }> = {
|
|
164
|
+
Uint8Array: { ctor: "xt_ta_u8_ctor", static: "xt_ta_u8_static", bytes: 1 },
|
|
165
|
+
Int8Array: { ctor: "xt_ta_i8_ctor", static: "xt_ta_i8_static", bytes: 1 },
|
|
166
|
+
Uint8ClampedArray: { ctor: "xt_ta_u8c_ctor", static: "xt_ta_u8c_static", bytes: 1 },
|
|
167
|
+
Uint16Array: { ctor: "xt_ta_u16_ctor", static: "xt_ta_u16_static", bytes: 2 },
|
|
168
|
+
Int16Array: { ctor: "xt_ta_i16_ctor", static: "xt_ta_i16_static", bytes: 2 },
|
|
169
|
+
Uint32Array: { ctor: "xt_ta_u32_ctor", static: "xt_ta_u32_static", bytes: 4 },
|
|
170
|
+
Int32Array: { ctor: "xt_ta_i32_ctor", static: "xt_ta_i32_static", bytes: 4 },
|
|
171
|
+
Float32Array: { ctor: "xt_ta_f32_ctor", static: "xt_ta_f32_static", bytes: 4 },
|
|
172
|
+
Float64Array: { ctor: "xt_ta_f64_ctor", static: "xt_ta_f64_static", bytes: 8 },
|
|
173
|
+
};
|
|
174
|
+
|
|
175
|
+
const TYPED_ARRAY_CTORS: Record<string, string> = {
|
|
176
|
+
Uint8Array: "xt_ta_u8_ctor",
|
|
177
|
+
Int8Array: "xt_ta_i8_ctor",
|
|
178
|
+
Uint8ClampedArray: "xt_ta_u8c_ctor",
|
|
179
|
+
Uint16Array: "xt_ta_u16_ctor",
|
|
180
|
+
Int16Array: "xt_ta_i16_ctor",
|
|
181
|
+
Uint32Array: "xt_ta_u32_ctor",
|
|
182
|
+
Int32Array: "xt_ta_i32_ctor",
|
|
183
|
+
Float32Array: "xt_ta_f32_ctor",
|
|
184
|
+
Float64Array: "xt_ta_f64_ctor",
|
|
185
|
+
};
|
|
186
|
+
const TYPED_ARRAY_STATICS: Record<string, string> = {
|
|
187
|
+
Uint8Array: "xt_ta_u8_static",
|
|
188
|
+
Int8Array: "xt_ta_i8_static",
|
|
189
|
+
Uint8ClampedArray: "xt_ta_u8c_static",
|
|
190
|
+
Uint16Array: "xt_ta_u16_static",
|
|
191
|
+
Int16Array: "xt_ta_i16_static",
|
|
192
|
+
Uint32Array: "xt_ta_u32_static",
|
|
193
|
+
Int32Array: "xt_ta_i32_static",
|
|
194
|
+
Float32Array: "xt_ta_f32_static",
|
|
195
|
+
Float64Array: "xt_ta_f64_static",
|
|
196
|
+
};
|
|
197
|
+
|
|
160
198
|
/** Global namespaces whose static methods map to runtime dispatchers. */
|
|
161
199
|
export const NAMESPACE_STATICS: Record<string, string> = {
|
|
162
200
|
Math: "xt_math_call",
|
|
@@ -186,6 +224,7 @@ export const NAMESPACE_STATICS: Record<string, string> = {
|
|
|
186
224
|
util: "xt_util_static",
|
|
187
225
|
querystring: "xt_querystring_static",
|
|
188
226
|
assert: "xt_assert_static",
|
|
227
|
+
...TYPED_ARRAY_STATICS,
|
|
189
228
|
};
|
|
190
229
|
|
|
191
230
|
/** Namespace identifiers whose property access maps to a runtime getter. */
|
|
@@ -213,6 +252,7 @@ export const CTOR_FUNCTIONS: Record<string, string> = {
|
|
|
213
252
|
Server: "xt_net_server_ctor",
|
|
214
253
|
EventEmitter: "xt_event_emitter_ctor",
|
|
215
254
|
...ERROR_CONSTRUCTORS,
|
|
255
|
+
...TYPED_ARRAY_CTORS,
|
|
216
256
|
};
|
|
217
257
|
|
|
218
258
|
export const BUILTIN_METHODS = new Set<string>([
|