xbintsc 0.1.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.
Files changed (124) hide show
  1. package/LICENSE +21 -0
  2. package/README.md +191 -0
  3. package/bin/xbintsc.js +26 -0
  4. package/dist/src/ast/factory.d.ts +11 -0
  5. package/dist/src/ast/factory.js +36 -0
  6. package/dist/src/ast/factory.js.map +1 -0
  7. package/dist/src/ast/nodes.d.ts +848 -0
  8. package/dist/src/ast/nodes.js +247 -0
  9. package/dist/src/ast/nodes.js.map +1 -0
  10. package/dist/src/ast/visitor.d.ts +18 -0
  11. package/dist/src/ast/visitor.js +52 -0
  12. package/dist/src/ast/visitor.js.map +1 -0
  13. package/dist/src/binder/binder.d.ts +82 -0
  14. package/dist/src/binder/binder.js +443 -0
  15. package/dist/src/binder/binder.js.map +1 -0
  16. package/dist/src/cli/main.d.ts +16 -0
  17. package/dist/src/cli/main.js +191 -0
  18. package/dist/src/cli/main.js.map +1 -0
  19. package/dist/src/codegen/llvm.d.ts +31 -0
  20. package/dist/src/codegen/llvm.js +1178 -0
  21. package/dist/src/codegen/llvm.js.map +1 -0
  22. package/dist/src/codegen/values.d.ts +23 -0
  23. package/dist/src/codegen/values.js +32 -0
  24. package/dist/src/codegen/values.js.map +1 -0
  25. package/dist/src/diagnostics/diagnostic.d.ts +69 -0
  26. package/dist/src/diagnostics/diagnostic.js +104 -0
  27. package/dist/src/diagnostics/diagnostic.js.map +1 -0
  28. package/dist/src/diagnostics/source.d.ts +43 -0
  29. package/dist/src/diagnostics/source.js +73 -0
  30. package/dist/src/diagnostics/source.js.map +1 -0
  31. package/dist/src/driver/cache.d.ts +37 -0
  32. package/dist/src/driver/cache.js +82 -0
  33. package/dist/src/driver/cache.js.map +1 -0
  34. package/dist/src/driver/compiler.d.ts +41 -0
  35. package/dist/src/driver/compiler.js +128 -0
  36. package/dist/src/driver/compiler.js.map +1 -0
  37. package/dist/src/driver/index.d.ts +4 -0
  38. package/dist/src/driver/index.js +5 -0
  39. package/dist/src/driver/index.js.map +1 -0
  40. package/dist/src/driver/paths.d.ts +4 -0
  41. package/dist/src/driver/paths.js +22 -0
  42. package/dist/src/driver/paths.js.map +1 -0
  43. package/dist/src/driver/toolchain.d.ts +43 -0
  44. package/dist/src/driver/toolchain.js +76 -0
  45. package/dist/src/driver/toolchain.js.map +1 -0
  46. package/dist/src/extensions/node.d.ts +9 -0
  47. package/dist/src/extensions/node.js +20 -0
  48. package/dist/src/extensions/node.js.map +1 -0
  49. package/dist/src/extensions/registry.d.ts +45 -0
  50. package/dist/src/extensions/registry.js +76 -0
  51. package/dist/src/extensions/registry.js.map +1 -0
  52. package/dist/src/index.d.ts +18 -0
  53. package/dist/src/index.js +19 -0
  54. package/dist/src/index.js.map +1 -0
  55. package/dist/src/lexer/scanner.d.ts +48 -0
  56. package/dist/src/lexer/scanner.js +650 -0
  57. package/dist/src/lexer/scanner.js.map +1 -0
  58. package/dist/src/lexer/token.d.ts +170 -0
  59. package/dist/src/lexer/token.js +250 -0
  60. package/dist/src/lexer/token.js.map +1 -0
  61. package/dist/src/parser/parser.d.ts +127 -0
  62. package/dist/src/parser/parser.js +2334 -0
  63. package/dist/src/parser/parser.js.map +1 -0
  64. package/dist/tests/binder/binder.test.d.ts +1 -0
  65. package/dist/tests/binder/binder.test.js +89 -0
  66. package/dist/tests/binder/binder.test.js.map +1 -0
  67. package/dist/tests/cli/main.test.d.ts +1 -0
  68. package/dist/tests/cli/main.test.js +68 -0
  69. package/dist/tests/cli/main.test.js.map +1 -0
  70. package/dist/tests/cli/process.test.d.ts +9 -0
  71. package/dist/tests/cli/process.test.js +57 -0
  72. package/dist/tests/cli/process.test.js.map +1 -0
  73. package/dist/tests/codegen/llvm.test.d.ts +1 -0
  74. package/dist/tests/codegen/llvm.test.js +93 -0
  75. package/dist/tests/codegen/llvm.test.js.map +1 -0
  76. package/dist/tests/driver/cache.test.d.ts +1 -0
  77. package/dist/tests/driver/cache.test.js +66 -0
  78. package/dist/tests/driver/cache.test.js.map +1 -0
  79. package/dist/tests/driver/compiler.test.d.ts +1 -0
  80. package/dist/tests/driver/compiler.test.js +80 -0
  81. package/dist/tests/driver/compiler.test.js.map +1 -0
  82. package/dist/tests/driver/toolchain.test.d.ts +1 -0
  83. package/dist/tests/driver/toolchain.test.js +60 -0
  84. package/dist/tests/driver/toolchain.test.js.map +1 -0
  85. package/dist/tests/e2e/compile.test.d.ts +5 -0
  86. package/dist/tests/e2e/compile.test.js +93 -0
  87. package/dist/tests/e2e/compile.test.js.map +1 -0
  88. package/dist/tests/extensions/registry.test.d.ts +1 -0
  89. package/dist/tests/extensions/registry.test.js +47 -0
  90. package/dist/tests/extensions/registry.test.js.map +1 -0
  91. package/dist/tests/helpers.d.ts +23 -0
  92. package/dist/tests/helpers.js +41 -0
  93. package/dist/tests/helpers.js.map +1 -0
  94. package/dist/tests/lexer/scanner.test.d.ts +1 -0
  95. package/dist/tests/lexer/scanner.test.js +95 -0
  96. package/dist/tests/lexer/scanner.test.js.map +1 -0
  97. package/dist/tests/parser/parser.test.d.ts +1 -0
  98. package/dist/tests/parser/parser.test.js +137 -0
  99. package/dist/tests/parser/parser.test.js.map +1 -0
  100. package/package.json +49 -0
  101. package/runtime/ext_node.c +42 -0
  102. package/runtime/rt.h +177 -0
  103. package/runtime/xt_runtime.c +682 -0
  104. package/scripts/build-runtime.mjs +34 -0
  105. package/src/ast/factory.ts +37 -0
  106. package/src/ast/nodes.ts +1111 -0
  107. package/src/ast/visitor.ts +60 -0
  108. package/src/binder/binder.ts +549 -0
  109. package/src/cli/main.ts +210 -0
  110. package/src/codegen/llvm.ts +1324 -0
  111. package/src/codegen/values.ts +36 -0
  112. package/src/diagnostics/diagnostic.ts +132 -0
  113. package/src/diagnostics/source.ts +97 -0
  114. package/src/driver/cache.ts +96 -0
  115. package/src/driver/compiler.ts +197 -0
  116. package/src/driver/index.ts +4 -0
  117. package/src/driver/paths.ts +24 -0
  118. package/src/driver/toolchain.ts +103 -0
  119. package/src/extensions/node.ts +23 -0
  120. package/src/extensions/registry.ts +101 -0
  121. package/src/index.ts +33 -0
  122. package/src/lexer/scanner.ts +650 -0
  123. package/src/lexer/token.ts +266 -0
  124. package/src/parser/parser.ts +2396 -0
package/LICENSE ADDED
@@ -0,0 +1,21 @@
1
+ MIT License
2
+
3
+ Copyright (c) 2026 Zy
4
+
5
+ Permission is hereby granted, free of charge, to any person obtaining a copy
6
+ of this software and associated documentation files (the "Software"), to deal
7
+ in the Software without restriction, including without limitation the rights
8
+ to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
9
+ copies of the Software, and to permit persons to whom the Software is
10
+ furnished to do so, subject to the following conditions:
11
+
12
+ The above copyright notice and this permission notice shall be included in all
13
+ copies or substantial portions of the Software.
14
+
15
+ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
16
+ IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
17
+ FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
18
+ AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
19
+ LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
20
+ OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
21
+ SOFTWARE.
package/README.md ADDED
@@ -0,0 +1,191 @@
1
+ # xbintsc
2
+
3
+ `xbintsc` compiles a practical subset of **TypeScript directly to native binaries**.
4
+ It parses TypeScript itself, binds names, lowers the program to **LLVM IR text**,
5
+ and hands the IR to **clang**, which produces a standalone executable linked
6
+ against a small C runtime.
7
+
8
+ The design goals are:
9
+
10
+ 1. **Incremental compilation** — builds are content-addressed and skipped when nothing changed.
11
+ 2. **Well-factored modules** — lexer, parser, binder, codegen, driver, extensions each live in their own directory with their own tests.
12
+ 3. **Extensive tests** — per-module unit tests plus end-to-end tests that compile and run real binaries.
13
+ 4. **Pluggable extensions** — Node `fs`, Bun APIs, … are optional compile modules, not core code.
14
+ 5. **Self-hosting ready** — the compiler is written in TypeScript and emits IR text, so a TypeScript rewrite can eventually compile itself.
15
+ 6. **Multi-platform** — macOS, Linux and Windows on multiple CPUs, validated by GitHub Actions.
16
+
17
+ ## How it works
18
+
19
+ ```
20
+ source.ts
21
+ │ lexer src/lexer
22
+
23
+ tokens
24
+ │ parser src/parser → AST (src/ast)
25
+
26
+ AST
27
+ │ binder src/binder → scopes, symbols, closures
28
+
29
+ bound AST
30
+ │ codegen src/codegen → LLVM IR text (src/codegen/llvm.ts)
31
+
32
+ module.ll ──clang──► module.o ──link──► executable
33
+
34
+ runtime/ (C runtime, NaN-boxed values)
35
+ ```
36
+
37
+ ### Value model
38
+
39
+ JavaScript values are a single 64-bit word (`xt_value`). Doubles are stored
40
+ unboxed; everything else is a tagged pointer: a 16-bit tag in the high bits
41
+ plus a 48-bit payload. The representation is defined once in
42
+ `src/codegen/values.ts` and `runtime/rt.h`.
43
+
44
+ ### Calling convention
45
+
46
+ Every compiled function uses the same ABI:
47
+
48
+ ```c
49
+ xt_value fn(xt_value env, int32_t argc, xt_value *argv);
50
+ ```
51
+
52
+ `env` threads captured variables (by reference, through boxes), so direct calls
53
+ and closure calls share one code path. JavaScript semantics that are awkward to
54
+ inline (`+` coercion, relational comparison, property access, inspection) are
55
+ delegated to `@xt_*` runtime calls.
56
+
57
+ ### Runtime
58
+
59
+ `runtime/xt_runtime.c` implements strings, objects, arrays, closures, arithmetic,
60
+ comparison, exceptions and Node-like `console.log` inspection. It uses a bump
61
+ arena and never frees — garbage collection is deliberately deferred and isolated
62
+ behind `xt_alloc`, so it can be replaced without touching the compiler.
63
+
64
+ ## Usage
65
+
66
+ There are two ways to invoke the CLI:
67
+
68
+ - **As a user** — the package is installed and the `xbintsc` command is available
69
+ (via the `bin` entry `./bin/xbintsc.js`).
70
+ - **As a developer** — running directly from a source checkout, before building.
71
+
72
+ ### As a user
73
+
74
+ ```bash
75
+ # Install globally
76
+ npm install -g xbintsc
77
+
78
+ # ...or use it on demand without installing
79
+ npx xbintsc version
80
+
81
+ # Compile and run a program
82
+ xbintsc run examples/hello.ts
83
+
84
+ # Produce a native binary
85
+ xbintsc build examples/hello.ts --out build/examples
86
+ ./build/examples/hello
87
+
88
+ # Inspect the generated LLVM IR
89
+ xbintsc emit examples/hello.ts | head
90
+
91
+ # Use an optional extension (here, Node's readFileSync)
92
+ xbintsc run examples/read-file.ts --ext node
93
+ ```
94
+
95
+ ### As a developer (from source)
96
+
97
+ In a source checkout, run the TypeScript sources directly through `tsx` (or use
98
+ `npm run xbintsc`). The `bin` launcher also works here: without a `dist/` build it
99
+ falls back to `tsx` automatically.
100
+
101
+ ```bash
102
+ # Install dependencies
103
+ npm install
104
+
105
+ # Compile and run a program
106
+ npm run xbintsc -- run examples/hello.ts
107
+ # equivalently
108
+ npx tsx src/cli/main.ts run examples/hello.ts
109
+
110
+ # Produce a native binary
111
+ npx tsx src/cli/main.ts build examples/hello.ts --out build/examples
112
+ ./build/examples/hello
113
+
114
+ # Inspect the generated LLVM IR
115
+ npx tsx src/cli/main.ts emit examples/hello.ts | head
116
+
117
+ # Use an optional extension (here, Node's readFileSync)
118
+ npx tsx src/cli/main.ts run examples/read-file.ts --ext node
119
+ ```
120
+
121
+ CLI options:
122
+
123
+ ```
124
+ -o, --output <path> Output path
125
+ --out <dir> Output directory (default: build/)
126
+ --emit <kind> exe | obj | ir (default: exe)
127
+ -O0..-O3 Optimization level (default: -O2)
128
+ --ext <names> Comma separated extensions (e.g. node)
129
+ --force Ignore the incremental cache
130
+ --verbose Print progress information
131
+ ```
132
+
133
+ ### Programmatic API
134
+
135
+ ```ts
136
+ import { build, compileString } from "xbintsc";
137
+
138
+ const { ir } = compileString("console.log(1 + 1);");
139
+ const result = build("program.ts", { emit: "exe", outDir: "build" });
140
+ ```
141
+
142
+ ## Incremental compilation
143
+
144
+ The driver keys each build on the entry source hash, compiler version, options,
145
+ platform and the active extension set (`src/driver/cache.ts`). If every recorded
146
+ output still exists, the build returns immediately. The C runtime and extension
147
+ sources are compiled once and cached on the same principle.
148
+
149
+ ## Extensions
150
+
151
+ An extension is a plain object (`src/extensions/registry.ts`):
152
+
153
+ ```ts
154
+ export const nodeExtension: Extension = {
155
+ name: "node",
156
+ runtimeSources: () => ["runtime/ext_node.c"],
157
+ builtins: () => ({ readFileSync: { symbol: "xt_node_read_text_file" } }),
158
+ };
159
+ ```
160
+
161
+ Registering it links the extra C source and makes `readFileSync(...)` resolve to
162
+ the C symbol with the uniform `(argc, argv)` calling convention. Builtins can be
163
+ added without changing the core compiler.
164
+
165
+ ## Tests
166
+
167
+ ```bash
168
+ npm run typecheck # tsc --noEmit
169
+ npm test # unit + end-to-end (runs real binaries when clang is present)
170
+ npm run test:e2e # only the compile-and-run tests
171
+ ```
172
+
173
+ Tests are organised by module under `tests/` (`lexer`, `parser`, `binder`,
174
+ `codegen`, `driver`, `extensions`, `cli`, `e2e`).
175
+
176
+ ## Requirements
177
+
178
+ - Node.js 20+
179
+ - A `clang`-compatible C compiler on `PATH` (override with `xbintsc_CLANG`)
180
+
181
+ ## Language subset
182
+
183
+ Implemented today: functions, arrow functions and closures, `let`/`const`/`var`,
184
+ all common operators, `if`/`while`/`do`/`for`/`for…of`/`for…in`, `break`/
185
+ `continue`/`return`/`throw`, objects, arrays, member/element access, assignments,
186
+ template literals, `console.log`, extension builtins, and the TypeScript type
187
+ syntax is parsed and ignored (types are erased).
188
+
189
+ Not yet implemented: classes, enums, `switch`, `try`/`catch`, `new`, `this`,
190
+ object spread, `async`/generators, and most standard library methods (`Array`
191
+ methods other than `push`, `Math`, etc.).
package/bin/xbintsc.js ADDED
@@ -0,0 +1,26 @@
1
+ #!/usr/bin/env node
2
+ /**
3
+ * xbintsc launcher.
4
+ *
5
+ * Prefers the compiled CLI in `dist/` (production installs run `npm run build`
6
+ * first). In a checkout, falls back to running the TypeScript sources through
7
+ * `tsx` so `npx xbintsc` works without a build step.
8
+ */
9
+
10
+ import { existsSync } from "node:fs";
11
+ import { dirname, join, resolve } from "node:path";
12
+ import { fileURLToPath, pathToFileURL } from "node:url";
13
+ import { spawnSync } from "node:child_process";
14
+
15
+ const root = resolve(dirname(fileURLToPath(import.meta.url)), "..");
16
+ const compiled = join(root, "dist", "src", "cli", "main.js");
17
+
18
+ if (existsSync(compiled)) {
19
+ const { run } = await import(pathToFileURL(compiled).href);
20
+ process.exit(run(process.argv.slice(2)));
21
+ } else {
22
+ const tsx = join(root, "node_modules", ".bin", process.platform === "win32" ? "tsx.cmd" : "tsx");
23
+ const entry = join(root, "src", "cli", "main.ts");
24
+ const result = spawnSync(tsx, [entry, ...process.argv.slice(2)], { stdio: "inherit" });
25
+ process.exit(result.status ?? 1);
26
+ }
@@ -0,0 +1,11 @@
1
+ import { type Node, type Range } from "./nodes.js";
2
+ /**
3
+ * Small helpers used by the parser and by the code generators to build AST
4
+ * nodes. Keeping construction in one place means the shape of every node is
5
+ * defined exactly once and is easy to evolve.
6
+ */
7
+ export declare function node<T extends Node>(value: T): T;
8
+ export declare function range(start: number, end: number): Range;
9
+ /** Concatenate the ranges of several nodes into one span. */
10
+ export declare function span(...nodes: (Node | Range | number | undefined)[]): Range;
11
+ export declare function isIdentifier(node: Node): node is import("./nodes.js").Identifier;
@@ -0,0 +1,36 @@
1
+ import { SyntaxKind } from "./nodes.js";
2
+ /**
3
+ * Small helpers used by the parser and by the code generators to build AST
4
+ * nodes. Keeping construction in one place means the shape of every node is
5
+ * defined exactly once and is easy to evolve.
6
+ */
7
+ export function node(value) {
8
+ return value;
9
+ }
10
+ export function range(start, end) {
11
+ return { start, end };
12
+ }
13
+ /** Concatenate the ranges of several nodes into one span. */
14
+ export function span(...nodes) {
15
+ let start = Number.POSITIVE_INFINITY;
16
+ let end = Number.NEGATIVE_INFINITY;
17
+ for (const item of nodes) {
18
+ if (item === undefined)
19
+ continue;
20
+ if (typeof item === "number") {
21
+ start = Math.min(start, item);
22
+ end = Math.max(end, item);
23
+ }
24
+ else {
25
+ start = Math.min(start, item.start);
26
+ end = Math.max(end, item.end);
27
+ }
28
+ }
29
+ if (!Number.isFinite(start))
30
+ return { start: 0, end: 0 };
31
+ return { start, end };
32
+ }
33
+ export function isIdentifier(node) {
34
+ return node.kind === SyntaxKind.Identifier;
35
+ }
36
+ //# sourceMappingURL=factory.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"factory.js","sourceRoot":"","sources":["../../../src/ast/factory.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,UAAU,EAAyB,MAAM,YAAY,CAAC;AAE/D;;;;GAIG;AAEH,MAAM,UAAU,IAAI,CAAiB,KAAQ;IAC3C,OAAO,KAAK,CAAC;AACf,CAAC;AAED,MAAM,UAAU,KAAK,CAAC,KAAa,EAAE,GAAW;IAC9C,OAAO,EAAE,KAAK,EAAE,GAAG,EAAE,CAAC;AACxB,CAAC;AAED,6DAA6D;AAC7D,MAAM,UAAU,IAAI,CAAC,GAAG,KAA4C;IAClE,IAAI,KAAK,GAAG,MAAM,CAAC,iBAAiB,CAAC;IACrC,IAAI,GAAG,GAAG,MAAM,CAAC,iBAAiB,CAAC;IACnC,KAAK,MAAM,IAAI,IAAI,KAAK,EAAE,CAAC;QACzB,IAAI,IAAI,KAAK,SAAS;YAAE,SAAS;QACjC,IAAI,OAAO,IAAI,KAAK,QAAQ,EAAE,CAAC;YAC7B,KAAK,GAAG,IAAI,CAAC,GAAG,CAAC,KAAK,EAAE,IAAI,CAAC,CAAC;YAC9B,GAAG,GAAG,IAAI,CAAC,GAAG,CAAC,GAAG,EAAE,IAAI,CAAC,CAAC;QAC5B,CAAC;aAAM,CAAC;YACN,KAAK,GAAG,IAAI,CAAC,GAAG,CAAC,KAAK,EAAE,IAAI,CAAC,KAAK,CAAC,CAAC;YACpC,GAAG,GAAG,IAAI,CAAC,GAAG,CAAC,GAAG,EAAE,IAAI,CAAC,GAAG,CAAC,CAAC;QAChC,CAAC;IACH,CAAC;IACD,IAAI,CAAC,MAAM,CAAC,QAAQ,CAAC,KAAK,CAAC;QAAE,OAAO,EAAE,KAAK,EAAE,CAAC,EAAE,GAAG,EAAE,CAAC,EAAE,CAAC;IACzD,OAAO,EAAE,KAAK,EAAE,GAAG,EAAE,CAAC;AACxB,CAAC;AAED,MAAM,UAAU,YAAY,CAAC,IAAU;IACrC,OAAO,IAAI,CAAC,IAAI,KAAK,UAAU,CAAC,UAAU,CAAC;AAC7C,CAAC"}