xbintsc 0.2.8 → 0.3.1
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 +17 -2
- package/README.zh-CN.md +16 -2
- package/bin/xbintsc.js +49 -10
- package/dist/src/ast/expressions.d.ts +2 -0
- package/dist/src/binder/binder.d.ts +24 -98
- package/dist/src/binder/binder.js +13 -559
- package/dist/src/binder/binder.js.map +1 -1
- package/dist/src/binder/declarations.d.ts +16 -0
- package/dist/src/binder/declarations.js +168 -0
- package/dist/src/binder/declarations.js.map +1 -0
- package/dist/src/binder/helpers.d.ts +11 -0
- package/dist/src/binder/helpers.js +46 -0
- package/dist/src/binder/helpers.js.map +1 -0
- package/dist/src/binder/references.d.ts +21 -0
- package/dist/src/binder/references.js +349 -0
- package/dist/src/binder/references.js.map +1 -0
- package/dist/src/binder/types.d.ts +114 -0
- package/dist/src/binder/types.js +27 -0
- package/dist/src/binder/types.js.map +1 -0
- package/dist/src/cli/main.d.ts +1 -0
- package/dist/src/cli/main.js +40 -0
- package/dist/src/cli/main.js.map +1 -1
- package/dist/src/codegen/generator/calls/access.d.ts +13 -0
- package/dist/src/codegen/generator/calls/access.js +115 -0
- package/dist/src/codegen/generator/calls/access.js.map +1 -0
- package/dist/src/codegen/generator/calls/closures.d.ts +11 -0
- package/dist/src/codegen/generator/calls/closures.js +50 -0
- package/dist/src/codegen/generator/calls/closures.js.map +1 -0
- package/dist/src/codegen/generator/calls/invocation.d.ts +18 -0
- package/dist/src/codegen/generator/calls/invocation.js +242 -0
- package/dist/src/codegen/generator/calls/invocation.js.map +1 -0
- package/dist/src/codegen/generator/calls/literals.d.ts +10 -0
- package/dist/src/codegen/generator/calls/literals.js +69 -0
- package/dist/src/codegen/generator/calls/literals.js.map +1 -0
- package/dist/src/codegen/generator/calls/super.d.ts +10 -0
- package/dist/src/codegen/generator/calls/super.js +47 -0
- package/dist/src/codegen/generator/calls/super.js.map +1 -0
- package/dist/src/codegen/generator/calls.d.ts +15 -24
- package/dist/src/codegen/generator/calls.js +15 -482
- package/dist/src/codegen/generator/calls.js.map +1 -1
- package/dist/src/codegen/generator/context.d.ts +1 -1
- package/dist/src/codegen/generator/context.js +2 -2
- package/dist/src/codegen/generator/context.js.map +1 -1
- package/dist/src/codegen/generator/expressions/assignment.d.ts +13 -0
- package/dist/src/codegen/generator/expressions/assignment.js +203 -0
- package/dist/src/codegen/generator/expressions/assignment.js.map +1 -0
- package/dist/src/codegen/generator/expressions/operators.d.ts +14 -0
- package/dist/src/codegen/generator/expressions/operators.js +163 -0
- package/dist/src/codegen/generator/expressions/operators.js.map +1 -0
- package/dist/src/codegen/generator/expressions/primary.d.ts +17 -0
- package/dist/src/codegen/generator/expressions/primary.js +260 -0
- package/dist/src/codegen/generator/expressions/primary.js.map +1 -0
- package/dist/src/codegen/generator/expressions.d.ts +11 -21
- package/dist/src/codegen/generator/expressions.js +11 -494
- package/dist/src/codegen/generator/expressions.js.map +1 -1
- package/dist/src/codegen/generator/module.js +16 -4
- package/dist/src/codegen/generator/module.js.map +1 -1
- package/dist/src/codegen/generator/state.js +8 -0
- package/dist/src/codegen/generator/state.js.map +1 -1
- package/dist/src/codegen/generator/statements/control-flow.d.ts +14 -0
- package/dist/src/codegen/generator/statements/control-flow.js +199 -0
- package/dist/src/codegen/generator/statements/control-flow.js.map +1 -0
- package/dist/src/codegen/generator/statements/dispatch.d.ts +12 -0
- package/dist/src/codegen/generator/statements/dispatch.js +100 -0
- package/dist/src/codegen/generator/statements/dispatch.js.map +1 -0
- package/dist/src/codegen/generator/statements/loops.d.ts +13 -0
- package/dist/src/codegen/generator/statements/loops.js +152 -0
- package/dist/src/codegen/generator/statements/loops.js.map +1 -0
- package/dist/src/codegen/generator/statements/variables.d.ts +13 -0
- package/dist/src/codegen/generator/statements/variables.js +146 -0
- package/dist/src/codegen/generator/statements/variables.js.map +1 -0
- package/dist/src/codegen/generator/statements.d.ts +13 -21
- package/dist/src/codegen/generator/statements.js +13 -568
- package/dist/src/codegen/generator/statements.js.map +1 -1
- package/dist/src/codegen/generator/tables.js +7 -0
- package/dist/src/codegen/generator/tables.js.map +1 -1
- package/dist/src/codegen/values.d.ts +17 -17
- package/dist/src/codegen/values.js +21 -57
- package/dist/src/codegen/values.js.map +1 -1
- package/dist/src/diagnostics/diagnostic.d.ts +1 -0
- package/dist/src/diagnostics/diagnostic.js +1 -0
- package/dist/src/diagnostics/diagnostic.js.map +1 -1
- package/dist/src/diagnostics/source.d.ts +1 -1
- package/dist/src/diagnostics/source.js +7 -12
- package/dist/src/diagnostics/source.js.map +1 -1
- package/dist/src/driver/compiler.d.ts +4 -0
- package/dist/src/driver/compiler.js +51 -16
- package/dist/src/driver/compiler.js.map +1 -1
- package/dist/src/driver/index.d.ts +5 -2
- package/dist/src/driver/index.js +5 -2
- package/dist/src/driver/index.js.map +1 -1
- package/dist/src/driver/paths.d.ts +20 -0
- package/dist/src/driver/paths.js +49 -0
- package/dist/src/driver/paths.js.map +1 -1
- package/dist/src/driver/runtime-lib.d.ts +18 -0
- package/dist/src/driver/runtime-lib.js +31 -0
- package/dist/src/driver/runtime-lib.js.map +1 -0
- package/dist/src/driver/toolchain-download.d.ts +50 -0
- package/dist/src/driver/toolchain-download.js +76 -0
- package/dist/src/driver/toolchain-download.js.map +1 -0
- package/dist/src/driver/toolchain-provider.d.ts +33 -0
- package/dist/src/driver/toolchain-provider.js +71 -0
- package/dist/src/driver/toolchain-provider.js.map +1 -0
- package/dist/src/driver/toolchain.d.ts +9 -4
- package/dist/src/driver/toolchain.js +6 -10
- package/dist/src/driver/toolchain.js.map +1 -1
- package/dist/src/extensions/node/child_process/index.d.ts +4 -2
- package/dist/src/extensions/node/child_process/index.js +4 -2
- package/dist/src/extensions/node/child_process/index.js.map +1 -1
- package/dist/src/extensions/node/events/index.d.ts +10 -0
- package/dist/src/extensions/node/events/index.js +22 -0
- package/dist/src/extensions/node/events/index.js.map +1 -0
- package/dist/src/extensions/node/index.js +6 -0
- package/dist/src/extensions/node/index.js.map +1 -1
- package/dist/src/extensions/node/querystring/index.d.ts +10 -0
- package/dist/src/extensions/node/querystring/index.js +25 -0
- package/dist/src/extensions/node/querystring/index.js.map +1 -0
- package/dist/src/extensions/node/util/index.d.ts +11 -0
- package/dist/src/extensions/node/util/index.js +41 -0
- package/dist/src/extensions/node/util/index.js.map +1 -0
- package/dist/src/extensions/registry.d.ts +6 -0
- package/dist/src/extensions/registry.js.map +1 -1
- package/dist/src/index.d.ts +1 -1
- package/dist/src/index.js +1 -1
- package/dist/src/index.js.map +1 -1
- package/dist/src/lexer/scanner/identifiers.d.ts +9 -0
- package/dist/src/lexer/scanner/identifiers.js +33 -0
- package/dist/src/lexer/scanner/identifiers.js.map +1 -0
- package/dist/src/lexer/scanner/numbers.d.ts +10 -0
- package/dist/src/lexer/scanner/numbers.js +89 -0
- package/dist/src/lexer/scanner/numbers.js.map +1 -0
- package/dist/src/lexer/scanner/punctuation.d.ts +9 -0
- package/dist/src/lexer/scanner/punctuation.js +151 -0
- package/dist/src/lexer/scanner/punctuation.js.map +1 -0
- package/dist/src/lexer/scanner/regex.d.ts +11 -0
- package/dist/src/lexer/scanner/regex.js +69 -0
- package/dist/src/lexer/scanner/regex.js.map +1 -0
- package/dist/src/lexer/scanner/strings.d.ts +13 -0
- package/dist/src/lexer/scanner/strings.js +118 -0
- package/dist/src/lexer/scanner/strings.js.map +1 -0
- package/dist/src/lexer/scanner.d.ts +20 -27
- package/dist/src/lexer/scanner.js +11 -415
- package/dist/src/lexer/scanner.js.map +1 -1
- package/dist/src/parser/declarations/classes.d.ts +14 -0
- package/dist/src/parser/declarations/classes.js +191 -0
- package/dist/src/parser/declarations/classes.js.map +1 -0
- package/dist/src/parser/declarations/functions.d.ts +17 -0
- package/dist/src/parser/declarations/functions.js +241 -0
- package/dist/src/parser/declarations/functions.js.map +1 -0
- package/dist/src/parser/declarations/type-members.d.ts +16 -0
- package/dist/src/parser/declarations/type-members.js +156 -0
- package/dist/src/parser/declarations/type-members.js.map +1 -0
- package/dist/src/parser/declarations.d.ts +13 -24
- package/dist/src/parser/declarations.js +13 -571
- package/dist/src/parser/declarations.js.map +1 -1
- package/dist/src/parser/helpers.js +13 -4
- package/dist/src/parser/helpers.js.map +1 -1
- package/dist/src/parser/literals.js +10 -1
- package/dist/src/parser/literals.js.map +1 -1
- package/dist/tests/codegen/llvm.test.js +24 -0
- package/dist/tests/codegen/llvm.test.js.map +1 -1
- package/dist/tests/driver/compiler.test.js +3 -0
- package/dist/tests/driver/compiler.test.js.map +1 -1
- package/dist/tests/driver/paths.test.d.ts +1 -0
- package/dist/tests/driver/paths.test.js +26 -0
- package/dist/tests/driver/paths.test.js.map +1 -0
- package/dist/tests/driver/toolchain-download.test.d.ts +1 -0
- package/dist/tests/driver/toolchain-download.test.js +38 -0
- package/dist/tests/driver/toolchain-download.test.js.map +1 -0
- package/dist/tests/driver/toolchain-provider.test.d.ts +1 -0
- package/dist/tests/driver/toolchain-provider.test.js +37 -0
- package/dist/tests/driver/toolchain-provider.test.js.map +1 -0
- package/dist/tests/e2e/compile-node.test.d.ts +7 -0
- package/dist/tests/e2e/compile-node.test.js +123 -0
- package/dist/tests/e2e/compile-node.test.js.map +1 -0
- package/dist/tests/e2e/compile.test.d.ts +4 -1
- package/dist/tests/e2e/compile.test.js +90 -130
- package/dist/tests/e2e/compile.test.js.map +1 -1
- package/dist/tests/e2e/harness.d.ts +36 -0
- package/dist/tests/e2e/harness.js +64 -0
- package/dist/tests/e2e/harness.js.map +1 -0
- package/dist/tests/e2e/node-modules.test.js +60 -0
- package/dist/tests/e2e/node-modules.test.js.map +1 -1
- package/dist/tests/extensions/registry.test.js +4 -0
- package/dist/tests/extensions/registry.test.js.map +1 -1
- package/package.json +5 -3
- package/runtime/ext_node/buffer/buffer.c +12 -552
- package/runtime/ext_node/buffer/parts/byte-access.inc +35 -0
- package/runtime/ext_node/buffer/parts/construction.inc +60 -0
- package/runtime/ext_node/buffer/parts/integer-io.inc +119 -0
- package/runtime/ext_node/buffer/parts/methods.inc +135 -0
- package/runtime/ext_node/buffer/parts/prototype.inc +54 -0
- package/runtime/ext_node/buffer/parts/search.inc +86 -0
- package/runtime/ext_node/buffer/parts/static-api.inc +58 -0
- package/runtime/ext_node/child_process/child_process.c +37 -3
- package/runtime/ext_node/events/events.c +285 -0
- package/runtime/ext_node/http/http.c +11 -736
- package/runtime/ext_node/http/parts/client.inc +290 -0
- package/runtime/ext_node/http/parts/helpers.inc +45 -0
- package/runtime/ext_node/http/parts/prototypes.inc +57 -0
- package/runtime/ext_node/http/parts/response.inc +149 -0
- package/runtime/ext_node/http/parts/server.inc +133 -0
- package/runtime/ext_node/http/parts/string-builder.inc +58 -0
- package/runtime/ext_node/net/net.c +12 -504
- package/runtime/ext_node/net/parts/construction.inc +22 -0
- package/runtime/ext_node/net/parts/platform.inc +60 -0
- package/runtime/ext_node/net/parts/prototypes.inc +35 -0
- package/runtime/ext_node/net/parts/read-loop.inc +58 -0
- package/runtime/ext_node/net/parts/server.inc +131 -0
- package/runtime/ext_node/net/parts/socket-methods.inc +100 -0
- package/runtime/ext_node/net/parts/static-api.inc +93 -0
- package/runtime/ext_node/querystring/querystring.c +251 -0
- package/runtime/ext_node/util/util.c +456 -0
- package/runtime/rt.h +8 -2
- package/runtime/rt_internal.h +34 -0
- package/runtime/xt_bigint/arithmetic.inc +135 -0
- package/runtime/xt_bigint/bits.inc +98 -0
- package/runtime/xt_bigint/bitwise.inc +103 -0
- package/runtime/xt_bigint/compare.inc +30 -0
- package/runtime/xt_bigint/conversions.inc +51 -0
- package/runtime/xt_bigint/division.inc +85 -0
- package/runtime/xt_bigint/format.inc +145 -0
- package/runtime/xt_bigint/helpers.inc +92 -0
- package/runtime/xt_bigint/magnitude.inc +88 -0
- package/runtime/xt_bigint/public.inc +59 -0
- package/runtime/xt_bigint/small-arithmetic.inc +58 -0
- package/runtime/xt_bigint.c +42 -0
- package/runtime/xt_builtins.c +40 -5
- package/runtime/xt_io.c +7 -0
- package/runtime/xt_stdlib/arrays.inc +161 -0
- package/runtime/xt_stdlib/dispatch.inc +116 -0
- package/runtime/xt_stdlib/helpers.inc +23 -0
- package/runtime/xt_stdlib/math.inc +72 -0
- package/runtime/xt_stdlib/strings.inc +178 -0
- package/runtime/xt_stdlib.c +10 -549
- package/runtime/xt_stdlib2/array-statics.inc +37 -0
- package/runtime/xt_stdlib2/arrays.inc +189 -0
- package/runtime/xt_stdlib2/container.inc +23 -0
- package/runtime/xt_stdlib2/date.inc +72 -0
- package/runtime/xt_stdlib2/error.inc +22 -0
- package/runtime/xt_stdlib2/helpers.inc +43 -0
- package/runtime/xt_stdlib2/json.inc +213 -0
- package/runtime/xt_stdlib2/map.inc +95 -0
- package/runtime/xt_stdlib2/number-string-statics.inc +73 -0
- package/runtime/xt_stdlib2/numbers.inc +38 -0
- package/runtime/xt_stdlib2/objects.inc +41 -0
- package/runtime/xt_stdlib2/regexp-match.inc +204 -0
- package/runtime/xt_stdlib2/regexp.inc +20 -0
- package/runtime/xt_stdlib2/set.inc +105 -0
- package/runtime/xt_stdlib2/strings.inc +94 -0
- package/runtime/xt_stdlib2.c +19 -1278
- package/runtime/xt_values.c +155 -12
- package/scripts/build-runtime.ts +109 -0
- package/scripts/fetch-toolchain.ts +101 -0
- package/scripts/package-release.ts +192 -0
- package/src/ast/expressions.ts +2 -0
- package/src/binder/binder.ts +40 -725
- package/src/binder/declarations.ts +203 -0
- package/src/binder/helpers.ts +47 -0
- package/src/binder/references.ts +410 -0
- package/src/binder/types.ts +134 -0
- package/src/cli/main.ts +43 -0
- package/src/codegen/generator/calls/access.ts +139 -0
- package/src/codegen/generator/calls/closures.ts +60 -0
- package/src/codegen/generator/calls/invocation.ts +282 -0
- package/src/codegen/generator/calls/literals.ts +77 -0
- package/src/codegen/generator/calls/super.ts +61 -0
- package/src/codegen/generator/calls.ts +30 -552
- package/src/codegen/generator/context.ts +2 -2
- package/src/codegen/generator/expressions/assignment.ts +226 -0
- package/src/codegen/generator/expressions/operators.ts +182 -0
- package/src/codegen/generator/expressions/primary.ts +304 -0
- package/src/codegen/generator/expressions.ts +22 -553
- package/src/codegen/generator/module.ts +14 -4
- package/src/codegen/generator/state.ts +8 -0
- package/src/codegen/generator/statements/control-flow.ts +225 -0
- package/src/codegen/generator/statements/dispatch.ts +122 -0
- package/src/codegen/generator/statements/loops.ts +173 -0
- package/src/codegen/generator/statements/variables.ts +152 -0
- package/src/codegen/generator/statements.ts +26 -612
- package/src/codegen/generator/tables.ts +7 -0
- package/src/codegen/values.ts +22 -57
- package/src/diagnostics/diagnostic.ts +1 -0
- package/src/diagnostics/source.ts +7 -12
- package/src/driver/compiler.ts +61 -18
- package/src/driver/index.ts +17 -2
- package/src/driver/paths.ts +54 -0
- package/src/driver/runtime-lib.ts +32 -0
- package/src/driver/toolchain-download.ts +108 -0
- package/src/driver/toolchain-provider.ts +91 -0
- package/src/driver/toolchain.ts +29 -11
- package/src/extensions/node/child_process/index.ts +4 -2
- package/src/extensions/node/events/index.ts +27 -0
- package/src/extensions/node/index.ts +6 -0
- package/src/extensions/node/querystring/index.ts +29 -0
- package/src/extensions/node/util/index.ts +48 -0
- package/src/extensions/registry.ts +6 -0
- package/src/index.ts +1 -0
- package/src/lexer/scanner/identifiers.ts +37 -0
- package/src/lexer/scanner/numbers.ts +84 -0
- package/src/lexer/scanner/punctuation.ts +132 -0
- package/src/lexer/scanner/regex.ts +79 -0
- package/src/lexer/scanner/strings.ts +128 -0
- package/src/lexer/scanner.ts +35 -401
- package/src/parser/declarations/classes.ts +215 -0
- package/src/parser/declarations/functions.ts +254 -0
- package/src/parser/declarations/type-members.ts +181 -0
- package/src/parser/declarations.ts +32 -609
- package/src/parser/helpers.ts +13 -6
- package/src/parser/literals.ts +10 -1
- package/scripts/build-runtime.mjs +0 -55
|
@@ -0,0 +1,134 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Binder data model: the plain-data symbols, scopes and per-function records
|
|
3
|
+
* that the binder produces and the checker/codegen consume.
|
|
4
|
+
*/
|
|
5
|
+
|
|
6
|
+
import type {
|
|
7
|
+
ArrowFunction,
|
|
8
|
+
Expression,
|
|
9
|
+
FunctionDeclaration,
|
|
10
|
+
FunctionExpression,
|
|
11
|
+
Identifier,
|
|
12
|
+
Node,
|
|
13
|
+
SourceFileNode,
|
|
14
|
+
} from "../ast/nodes.js";
|
|
15
|
+
|
|
16
|
+
export enum SymbolKind {
|
|
17
|
+
Var = "var",
|
|
18
|
+
Let = "let",
|
|
19
|
+
Const = "const",
|
|
20
|
+
Function = "function",
|
|
21
|
+
Parameter = "parameter",
|
|
22
|
+
Class = "class",
|
|
23
|
+
Interface = "interface",
|
|
24
|
+
TypeAlias = "type",
|
|
25
|
+
Enum = "enum",
|
|
26
|
+
Import = "import",
|
|
27
|
+
Namespace = "namespace",
|
|
28
|
+
}
|
|
29
|
+
|
|
30
|
+
export interface SymbolInfo {
|
|
31
|
+
readonly id: number;
|
|
32
|
+
readonly name: string;
|
|
33
|
+
readonly kind: SymbolKind;
|
|
34
|
+
/** False for `const` bindings and imports. */
|
|
35
|
+
readonly mutable: boolean;
|
|
36
|
+
/** The function this symbol belongs to. */
|
|
37
|
+
readonly fn: FunctionInfo;
|
|
38
|
+
readonly declarations: Node[];
|
|
39
|
+
readonly references: Identifier[];
|
|
40
|
+
/** Set when referenced from a nested function. */
|
|
41
|
+
captured: boolean;
|
|
42
|
+
/** Assigned after construction once we know it is captured. */
|
|
43
|
+
boxed: boolean;
|
|
44
|
+
}
|
|
45
|
+
|
|
46
|
+
export type FunctionNode = SourceFileNode | FunctionDeclaration | FunctionExpression | ArrowFunction;
|
|
47
|
+
|
|
48
|
+
export interface FunctionInfo {
|
|
49
|
+
readonly id: number;
|
|
50
|
+
readonly name: string;
|
|
51
|
+
readonly node: FunctionNode;
|
|
52
|
+
readonly parent?: FunctionInfo;
|
|
53
|
+
readonly scope: Scope;
|
|
54
|
+
readonly params: SymbolInfo[];
|
|
55
|
+
/** Every binding declared directly in this function (params + locals). */
|
|
56
|
+
readonly locals: SymbolInfo[];
|
|
57
|
+
/** Outer bindings referenced by this function or any descendant. */
|
|
58
|
+
readonly captures: SymbolInfo[];
|
|
59
|
+
readonly captureIndex: Map<number, number>;
|
|
60
|
+
readonly isModule: boolean;
|
|
61
|
+
readonly isArrow: boolean;
|
|
62
|
+
/** True when the function was declared `async`. */
|
|
63
|
+
readonly isAsync: boolean;
|
|
64
|
+
/** True when this function's body mentions `this` directly. */
|
|
65
|
+
usesThis: boolean;
|
|
66
|
+
/** True when an arrow function must receive `this` from its enclosing scope. */
|
|
67
|
+
capturesThis: boolean;
|
|
68
|
+
/** Set for class methods/constructors; carries the owning class. */
|
|
69
|
+
classInfo?: ClassInfo;
|
|
70
|
+
/** True for `static` class members. */
|
|
71
|
+
isStatic?: boolean;
|
|
72
|
+
/** True for an explicit `constructor`. */
|
|
73
|
+
isConstructor?: boolean;
|
|
74
|
+
}
|
|
75
|
+
|
|
76
|
+
export interface ClassInfo {
|
|
77
|
+
readonly id: number;
|
|
78
|
+
readonly name: string;
|
|
79
|
+
readonly node: Node;
|
|
80
|
+
readonly scope: Scope;
|
|
81
|
+
readonly parent?: ClassInfo;
|
|
82
|
+
readonly parentExpression?: Expression;
|
|
83
|
+
/** `this`-bearing fields declared on the class. */
|
|
84
|
+
readonly fields: ClassFieldInfo[];
|
|
85
|
+
readonly methods: FunctionInfo[];
|
|
86
|
+
readonly statics: FunctionInfo[];
|
|
87
|
+
ctor?: FunctionInfo;
|
|
88
|
+
/** The symbol the class name binds to, when there is one. */
|
|
89
|
+
}
|
|
90
|
+
|
|
91
|
+
export interface ClassFieldInfo {
|
|
92
|
+
readonly name: string;
|
|
93
|
+
readonly initializer: Expression | undefined;
|
|
94
|
+
readonly fn: FunctionInfo;
|
|
95
|
+
readonly isStatic: boolean;
|
|
96
|
+
}
|
|
97
|
+
|
|
98
|
+
export enum ScopeKind {
|
|
99
|
+
Module = "module",
|
|
100
|
+
Function = "function",
|
|
101
|
+
Block = "block",
|
|
102
|
+
For = "for",
|
|
103
|
+
Catch = "catch",
|
|
104
|
+
}
|
|
105
|
+
|
|
106
|
+
export interface Scope {
|
|
107
|
+
readonly kind: ScopeKind;
|
|
108
|
+
readonly parent?: Scope;
|
|
109
|
+
readonly fn: FunctionInfo;
|
|
110
|
+
readonly symbols: Map<string, SymbolInfo>;
|
|
111
|
+
/** The syntax node that introduced the scope, when there is one. */
|
|
112
|
+
readonly node?: Node;
|
|
113
|
+
}
|
|
114
|
+
|
|
115
|
+
export interface BindResult {
|
|
116
|
+
readonly moduleFunction: FunctionInfo;
|
|
117
|
+
readonly functions: FunctionInfo[];
|
|
118
|
+
readonly classes: ClassInfo[];
|
|
119
|
+
/** Maps a class-like AST node to the ClassInfo the binder built. */
|
|
120
|
+
readonly classOfNode: Map<Node, ClassInfo>;
|
|
121
|
+
/** Maps a function-like AST node to the FunctionInfo the binder built for it. */
|
|
122
|
+
readonly functionOfNode: Map<Node, FunctionInfo>;
|
|
123
|
+
readonly symbolOfDeclaration: Map<Node, SymbolInfo>;
|
|
124
|
+
readonly symbolOfIdentifier: Map<Identifier, SymbolInfo>;
|
|
125
|
+
readonly scopes: Map<Node, Scope>;
|
|
126
|
+
/** Identifier references that could not be resolved in user code. */
|
|
127
|
+
readonly unresolved: Identifier[];
|
|
128
|
+
}
|
|
129
|
+
|
|
130
|
+
export interface MutableFunction extends FunctionInfo {
|
|
131
|
+
locals: SymbolInfo[];
|
|
132
|
+
captures: SymbolInfo[];
|
|
133
|
+
captureIndex: Map<number, number>;
|
|
134
|
+
}
|
package/src/cli/main.ts
CHANGED
|
@@ -7,6 +7,7 @@
|
|
|
7
7
|
* xbintsc build <file> [-o out] [--emit ir|obj|exe] [-O0..3] [--ext node]
|
|
8
8
|
* xbintsc run <file> [-- args...]
|
|
9
9
|
* xbintsc emit <file> # print LLVM IR to stdout
|
|
10
|
+
* xbintsc doctor # report the resolved toolchain
|
|
10
11
|
* xbintsc version
|
|
11
12
|
*/
|
|
12
13
|
|
|
@@ -17,6 +18,10 @@ import { pathToFileURL } from "node:url";
|
|
|
17
18
|
import { DiagnosticBag, formatDiagnostic, type Diagnostic } from "../diagnostics/diagnostic.js";
|
|
18
19
|
import { SourceFile } from "../diagnostics/source.js";
|
|
19
20
|
import { build, compileEntry, COMPILER_VERSION, type EmitKind } from "../driver/compiler.js";
|
|
21
|
+
import { findRuntimeDir, platformSlug } from "../driver/paths.js";
|
|
22
|
+
import { runtimeLibDir } from "../driver/runtime-lib.js";
|
|
23
|
+
import { resolveToolchain } from "../driver/toolchain-provider.js";
|
|
24
|
+
import { realRunner } from "../driver/toolchain.js";
|
|
20
25
|
import { createDefaultRegistry, type ExtensionRegistry } from "../extensions/registry.js";
|
|
21
26
|
import { nodeExtension } from "../extensions/node/index.js";
|
|
22
27
|
|
|
@@ -119,6 +124,7 @@ Usage:
|
|
|
119
124
|
xbintsc build <file.ts> [options] Compile to a native binary
|
|
120
125
|
xbintsc run <file.ts> [-- args] Compile and execute
|
|
121
126
|
xbintsc emit <file.ts> Print LLVM IR
|
|
127
|
+
xbintsc doctor Report the resolved toolchain
|
|
122
128
|
xbintsc version Print the version
|
|
123
129
|
xbintsc help Show this message
|
|
124
130
|
|
|
@@ -132,6 +138,39 @@ Options:
|
|
|
132
138
|
--verbose Print progress information
|
|
133
139
|
`;
|
|
134
140
|
|
|
141
|
+
function firstLine(text: string): string {
|
|
142
|
+
const index = text.indexOf("\n");
|
|
143
|
+
return (index === -1 ? text : text.slice(0, index)).trim();
|
|
144
|
+
}
|
|
145
|
+
|
|
146
|
+
/** Report the resolved toolchain and runtime locations. */
|
|
147
|
+
function doctor(io: CliIo): number {
|
|
148
|
+
io.stdout(`xbintsc ${COMPILER_VERSION}\n`);
|
|
149
|
+
io.stdout(`platform : ${platformSlug()}\n`);
|
|
150
|
+
|
|
151
|
+
try {
|
|
152
|
+
const toolchain = resolveToolchain();
|
|
153
|
+
const version = realRunner.run(toolchain.clang, ["--version"], { env: toolchain.env }).stdout;
|
|
154
|
+
io.stdout(`toolchain : ${toolchain.clang} (${toolchain.source})\n`);
|
|
155
|
+
io.stdout(`compiler : ${firstLine(version) || "unknown"}\n`);
|
|
156
|
+
} catch {
|
|
157
|
+
io.stdout("toolchain : not found (install the Xcode Command Line Tools or set xbintsc_CLANG)\n");
|
|
158
|
+
}
|
|
159
|
+
|
|
160
|
+
try {
|
|
161
|
+
io.stdout(`runtime : ${findRuntimeDir()}\n`);
|
|
162
|
+
} catch {
|
|
163
|
+
io.stdout("runtime : not found (cannot locate runtime/rt.h)\n");
|
|
164
|
+
}
|
|
165
|
+
|
|
166
|
+
try {
|
|
167
|
+
io.stdout(`runtime lib: ${runtimeLibDir()}\n`);
|
|
168
|
+
} catch {
|
|
169
|
+
io.stdout("runtime lib: unavailable\n");
|
|
170
|
+
}
|
|
171
|
+
return 0;
|
|
172
|
+
}
|
|
173
|
+
|
|
135
174
|
export function run(argv: readonly string[], io: CliIo = defaultIo): number {
|
|
136
175
|
const args = parseArgs(argv);
|
|
137
176
|
const command = args.command;
|
|
@@ -141,6 +180,10 @@ export function run(argv: readonly string[], io: CliIo = defaultIo): number {
|
|
|
141
180
|
return 0;
|
|
142
181
|
}
|
|
143
182
|
|
|
183
|
+
if (command === "doctor") {
|
|
184
|
+
return doctor(io);
|
|
185
|
+
}
|
|
186
|
+
|
|
144
187
|
if (command === "version" || args.flags.has("version")) {
|
|
145
188
|
io.stdout(`xbintsc ${COMPILER_VERSION}\n`);
|
|
146
189
|
return 0;
|
|
@@ -0,0 +1,139 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Member access lowering: property/element reads, `delete` and optional
|
|
3
|
+
* chaining guards.
|
|
4
|
+
*/
|
|
5
|
+
|
|
6
|
+
import {
|
|
7
|
+
SyntaxKind,
|
|
8
|
+
type DeleteExpression,
|
|
9
|
+
type ElementAccessExpression,
|
|
10
|
+
type Identifier,
|
|
11
|
+
type PropertyAccessExpression,
|
|
12
|
+
} from "../../../ast/nodes.js";
|
|
13
|
+
import { i64, numberLiteral, XT_TRUE, XT_UNDEFINED } from "../../values.js";
|
|
14
|
+
import { MATH_CONSTANTS, NAMESPACE_PROPERTIES } from "../tables.js";
|
|
15
|
+
import type { Generator } from "../generator.js";
|
|
16
|
+
|
|
17
|
+
export interface AccessCallMethods {
|
|
18
|
+
emitDelete(this: Generator, node: DeleteExpression): string;
|
|
19
|
+
emitPropertyAccess(this: Generator, node: PropertyAccessExpression): string;
|
|
20
|
+
emitElementAccess(this: Generator, node: ElementAccessExpression): string;
|
|
21
|
+
emitOptional(this: Generator, objectValue: string, compute: () => string): string;
|
|
22
|
+
}
|
|
23
|
+
|
|
24
|
+
export const accessCallMethods: AccessCallMethods = {
|
|
25
|
+
emitDelete(node: DeleteExpression): string {
|
|
26
|
+
const target = node.expression;
|
|
27
|
+
if (target.kind === SyntaxKind.PropertyAccessExpression) {
|
|
28
|
+
const access = target as PropertyAccessExpression;
|
|
29
|
+
const object = this.emitExpression(access.expression);
|
|
30
|
+
const key = this.stringValue(access.name.text);
|
|
31
|
+
return this.runtimeCall("xt_delete", [object, key]);
|
|
32
|
+
}
|
|
33
|
+
if (target.kind === SyntaxKind.ElementAccessExpression) {
|
|
34
|
+
const access = target as ElementAccessExpression;
|
|
35
|
+
const object = this.emitExpression(access.expression);
|
|
36
|
+
const key = this.emitExpression(access.argumentExpression);
|
|
37
|
+
return this.runtimeCall("xt_delete", [object, key]);
|
|
38
|
+
}
|
|
39
|
+
return i64(XT_TRUE);
|
|
40
|
+
},
|
|
41
|
+
|
|
42
|
+
emitPropertyAccess(node: PropertyAccessExpression): string {
|
|
43
|
+
if (node.expression.kind === SyntaxKind.Identifier && (node.expression as Identifier).text === "super") {
|
|
44
|
+
const thisValue = this.emitThis();
|
|
45
|
+
const proto = this.reg();
|
|
46
|
+
this.emit(` ${proto} = call i64 @xt_object_get_prototype(i64 ${thisValue})`);
|
|
47
|
+
const parentProto = this.reg();
|
|
48
|
+
this.emit(` ${parentProto} = call i64 @xt_object_get_prototype(i64 ${proto})`);
|
|
49
|
+
const key = this.stringValue(node.name.text);
|
|
50
|
+
const value = this.reg();
|
|
51
|
+
this.emit(` ${value} = call i64 @xt_get(i64 ${parentProto}, i64 ${key})`);
|
|
52
|
+
return value;
|
|
53
|
+
}
|
|
54
|
+
if (
|
|
55
|
+
node.name.text in MATH_CONSTANTS &&
|
|
56
|
+
node.expression.kind === SyntaxKind.Identifier &&
|
|
57
|
+
(node.expression as Identifier).text === "Math" &&
|
|
58
|
+
!this.binding.symbolOfIdentifier.get(node.expression as Identifier)
|
|
59
|
+
) {
|
|
60
|
+
return numberLiteral(MATH_CONSTANTS[node.name.text]!);
|
|
61
|
+
}
|
|
62
|
+
if (
|
|
63
|
+
node.expression.kind === SyntaxKind.Identifier &&
|
|
64
|
+
!this.binding.symbolOfIdentifier.get(node.expression as Identifier)
|
|
65
|
+
) {
|
|
66
|
+
const getter = NAMESPACE_PROPERTIES[(node.expression as Identifier).text];
|
|
67
|
+
if (getter) {
|
|
68
|
+
const key = this.stringValue(node.name.text);
|
|
69
|
+
const result = this.reg();
|
|
70
|
+
this.emit(` ${result} = call i64 @${getter}(i64 ${key})`);
|
|
71
|
+
return result;
|
|
72
|
+
}
|
|
73
|
+
}
|
|
74
|
+
if (node.expression.kind === SyntaxKind.Identifier) {
|
|
75
|
+
const namespace = this.namespaceOfSymbol(
|
|
76
|
+
this.binding.symbolOfIdentifier.get(node.expression as Identifier),
|
|
77
|
+
);
|
|
78
|
+
if (namespace) {
|
|
79
|
+
const getter = NAMESPACE_PROPERTIES[namespace];
|
|
80
|
+
if (getter) {
|
|
81
|
+
const key = this.stringValue(node.name.text);
|
|
82
|
+
const result = this.reg();
|
|
83
|
+
this.emit(` ${result} = call i64 @${getter}(i64 ${key})`);
|
|
84
|
+
return result;
|
|
85
|
+
}
|
|
86
|
+
}
|
|
87
|
+
}
|
|
88
|
+
const object = this.emitExpression(node.expression);
|
|
89
|
+
const access = (): string => {
|
|
90
|
+
if (node.name.text === "length") {
|
|
91
|
+
const result = this.reg();
|
|
92
|
+
this.emit(` ${result} = call i64 @xt_array_length(i64 ${object})`);
|
|
93
|
+
return result;
|
|
94
|
+
}
|
|
95
|
+
const key = this.stringValue(node.name.text);
|
|
96
|
+
const result = this.reg();
|
|
97
|
+
this.emit(` ${result} = call i64 @xt_get(i64 ${object}, i64 ${key})`);
|
|
98
|
+
return result;
|
|
99
|
+
};
|
|
100
|
+
return node.optional ? this.emitOptional(object, access) : access();
|
|
101
|
+
},
|
|
102
|
+
|
|
103
|
+
emitElementAccess(node: ElementAccessExpression): string {
|
|
104
|
+
const object = this.emitExpression(node.expression);
|
|
105
|
+
const access = (): string => {
|
|
106
|
+
const key = this.emitExpression(node.argumentExpression);
|
|
107
|
+
const result = this.reg();
|
|
108
|
+
this.emit(` ${result} = call i64 @xt_get(i64 ${object}, i64 ${key})`);
|
|
109
|
+
return result;
|
|
110
|
+
};
|
|
111
|
+
return node.optional ? this.emitOptional(object, access) : access();
|
|
112
|
+
},
|
|
113
|
+
|
|
114
|
+
/**
|
|
115
|
+
* Evaluate `object` once and, when it is neither `null` nor `undefined`, run
|
|
116
|
+
* `compute` to produce the value; otherwise short-circuit to `undefined`.
|
|
117
|
+
*/
|
|
118
|
+
emitOptional(objectValue: string, compute: () => string): string {
|
|
119
|
+
const result = this.alloca();
|
|
120
|
+
this.emit(` store i64 ${i64(XT_UNDEFINED)}, i64* ${result}`);
|
|
121
|
+
const nullish = this.reg();
|
|
122
|
+
this.emit(` ${nullish} = call i64 @xt_is_nullish(i64 ${objectValue})`);
|
|
123
|
+
const truthy = this.reg();
|
|
124
|
+
this.emit(` ${truthy} = call i32 @xt_truthy(i64 ${nullish})`);
|
|
125
|
+
const condition = this.reg();
|
|
126
|
+
this.emit(` ${condition} = icmp ne i32 ${truthy}, 0`);
|
|
127
|
+
const someLabel = this.label("opt.some");
|
|
128
|
+
const endLabel = this.label("opt.end");
|
|
129
|
+
this.terminate(`br i1 ${condition}, label %${endLabel}, label %${someLabel}`);
|
|
130
|
+
this.startBlock(someLabel);
|
|
131
|
+
const value = compute();
|
|
132
|
+
this.emit(` store i64 ${value}, i64* ${result}`);
|
|
133
|
+
this.terminate(`br label %${endLabel}`);
|
|
134
|
+
this.startBlock(endLabel);
|
|
135
|
+
const merged = this.reg();
|
|
136
|
+
this.emit(` ${merged} = load i64, i64* ${result}`);
|
|
137
|
+
return merged;
|
|
138
|
+
},
|
|
139
|
+
};
|
|
@@ -0,0 +1,60 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Closure lowering: arrow/function expressions and their captured environments.
|
|
3
|
+
*/
|
|
4
|
+
|
|
5
|
+
import type { ArrowFunction, FunctionExpression } from "../../../ast/nodes.js";
|
|
6
|
+
import type { FunctionInfo } from "../../../binder/binder.js";
|
|
7
|
+
import { i64, XT_UNDEFINED } from "../../values.js";
|
|
8
|
+
import type { Generator } from "../generator.js";
|
|
9
|
+
|
|
10
|
+
export interface ClosureCallMethods {
|
|
11
|
+
emitClosure(this: Generator, node: ArrowFunction | FunctionExpression): string;
|
|
12
|
+
emitClosureValue(this: Generator, fn: FunctionInfo): string;
|
|
13
|
+
}
|
|
14
|
+
|
|
15
|
+
export const closureCallMethods: ClosureCallMethods = {
|
|
16
|
+
emitClosure(node: ArrowFunction | FunctionExpression): string {
|
|
17
|
+
const fn = this.binding.functionOfNode.get(node);
|
|
18
|
+
if (!fn) {
|
|
19
|
+
this.unsupported(node, "closure");
|
|
20
|
+
return i64(XT_UNDEFINED);
|
|
21
|
+
}
|
|
22
|
+
return this.emitClosureValue(fn);
|
|
23
|
+
},
|
|
24
|
+
|
|
25
|
+
emitClosureValue(fn: FunctionInfo): string {
|
|
26
|
+
const count = fn.captures.length + (fn.capturesThis ? 1 : 0);
|
|
27
|
+
let envPtr = "null";
|
|
28
|
+
if (count > 0) {
|
|
29
|
+
envPtr = `%env${this.current.allocas.length}`;
|
|
30
|
+
this.current.allocas.push(`${envPtr} = alloca i64, i32 ${count}`);
|
|
31
|
+
for (let index = 0; index < fn.captures.length; index++) {
|
|
32
|
+
const symbol = fn.captures[index]!;
|
|
33
|
+
const slot = this.current.slots.get(symbol.id);
|
|
34
|
+
let raw = i64(XT_UNDEFINED);
|
|
35
|
+
if (slot) {
|
|
36
|
+
raw = this.reg();
|
|
37
|
+
this.emit(` ${raw} = load i64, i64* ${slot.ptr}`);
|
|
38
|
+
}
|
|
39
|
+
const target = this.reg();
|
|
40
|
+
this.emit(` ${target} = getelementptr i64, i64* ${envPtr}, i32 ${index}`);
|
|
41
|
+
this.emit(` store i64 ${raw}, i64* ${target}`);
|
|
42
|
+
}
|
|
43
|
+
if (fn.capturesThis) {
|
|
44
|
+
let thisValue = i64(XT_UNDEFINED);
|
|
45
|
+
if (this.current.thisPtr) {
|
|
46
|
+
thisValue = this.reg();
|
|
47
|
+
this.emit(` ${thisValue} = load i64, i64* ${this.current.thisPtr}`);
|
|
48
|
+
}
|
|
49
|
+
const target = this.reg();
|
|
50
|
+
this.emit(` ${target} = getelementptr i64, i64* ${envPtr}, i32 ${fn.captures.length}`);
|
|
51
|
+
this.emit(` store i64 ${thisValue}, i64* ${target}`);
|
|
52
|
+
}
|
|
53
|
+
}
|
|
54
|
+
const cast = this.reg();
|
|
55
|
+
this.emit(` ${cast} = bitcast i64 (i64, i64, i32, i64*)* @${this.functionName(fn)} to i8*`);
|
|
56
|
+
const closure = this.reg();
|
|
57
|
+
this.emit(` ${closure} = call i64 @xt_closure_new(i8* ${cast}, i32 ${count}, i64* ${envPtr})`);
|
|
58
|
+
return closure;
|
|
59
|
+
},
|
|
60
|
+
};
|
|
@@ -0,0 +1,282 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Call invocation: direct calls, built-in/namespace dispatch, imported
|
|
3
|
+
* bindings, argument marshalling and generic runtime calls.
|
|
4
|
+
*/
|
|
5
|
+
|
|
6
|
+
import {
|
|
7
|
+
SyntaxKind,
|
|
8
|
+
type CallExpression,
|
|
9
|
+
type ElementAccessExpression,
|
|
10
|
+
type Expression,
|
|
11
|
+
type Identifier,
|
|
12
|
+
type PropertyAccessExpression,
|
|
13
|
+
type SpreadElement,
|
|
14
|
+
} from "../../../ast/nodes.js";
|
|
15
|
+
import { SymbolKind } from "../../../binder/binder.js";
|
|
16
|
+
import type { ModuleExport } from "../../../extensions/registry.js";
|
|
17
|
+
import { i64, XT_UNDEFINED } from "../../values.js";
|
|
18
|
+
import {
|
|
19
|
+
BUILTIN_METHODS,
|
|
20
|
+
CONSOLE_METHODS,
|
|
21
|
+
CTOR_FUNCTIONS,
|
|
22
|
+
GLOBAL_FUNCTIONS,
|
|
23
|
+
MATH_FUNCTIONS,
|
|
24
|
+
NAMESPACE_STATICS,
|
|
25
|
+
} from "../tables.js";
|
|
26
|
+
import type { Generator } from "../generator.js";
|
|
27
|
+
|
|
28
|
+
export interface InvocationCallMethods {
|
|
29
|
+
emitCall(this: Generator, node: CallExpression): string;
|
|
30
|
+
tryEmitBuiltinCall(this: Generator, node: CallExpression, callee: PropertyAccessExpression): string | undefined;
|
|
31
|
+
emitModuleExport(this: Generator, node: CallExpression, exported: ModuleExport): string;
|
|
32
|
+
runtimeCall(this: Generator, name: string, args: readonly string[]): string;
|
|
33
|
+
emitArguments(this: Generator, args: readonly Expression[]): { argc: string; ptr: string };
|
|
34
|
+
}
|
|
35
|
+
|
|
36
|
+
export const invocationCallMethods: InvocationCallMethods = {
|
|
37
|
+
emitCall(node: CallExpression): string {
|
|
38
|
+
const callee = node.expression;
|
|
39
|
+
if (node.optional) {
|
|
40
|
+
const calleeValue = this.emitExpression(callee);
|
|
41
|
+
return this.emitOptional(calleeValue, () => {
|
|
42
|
+
const args = this.emitArguments(node.arguments);
|
|
43
|
+
const result = this.reg();
|
|
44
|
+
this.emit(` ${result} = call i64 @xt_closure_call(i64 ${calleeValue}, i32 ${args.argc}, i64* ${args.ptr})`);
|
|
45
|
+
return result;
|
|
46
|
+
});
|
|
47
|
+
}
|
|
48
|
+
if (
|
|
49
|
+
(callee.kind === SyntaxKind.PropertyAccessExpression || callee.kind === SyntaxKind.ElementAccessExpression) &&
|
|
50
|
+
(callee as PropertyAccessExpression | ElementAccessExpression).optional
|
|
51
|
+
) {
|
|
52
|
+
// `obj?.method(args)` / `obj?.[key](args)`: guard the receiver, then
|
|
53
|
+
// dispatch through the runtime, which understands object methods as well
|
|
54
|
+
// as the built-in array/string methods.
|
|
55
|
+
const access = callee as PropertyAccessExpression | ElementAccessExpression;
|
|
56
|
+
const object = this.emitExpression(access.expression);
|
|
57
|
+
return this.emitOptional(object, () => {
|
|
58
|
+
const name =
|
|
59
|
+
access.kind === SyntaxKind.PropertyAccessExpression
|
|
60
|
+
? this.stringValue((access as PropertyAccessExpression).name.text)
|
|
61
|
+
: this.emitExpression((access as ElementAccessExpression).argumentExpression);
|
|
62
|
+
const args = this.emitArguments(node.arguments);
|
|
63
|
+
const result = this.reg();
|
|
64
|
+
this.emit(
|
|
65
|
+
` ${result} = call i64 @xt_call_method(i64 ${object}, i64 ${name}, i32 ${args.argc}, i64* ${args.ptr})`,
|
|
66
|
+
);
|
|
67
|
+
return result;
|
|
68
|
+
});
|
|
69
|
+
}
|
|
70
|
+
if (callee.kind === SyntaxKind.PropertyAccessExpression) {
|
|
71
|
+
const access = callee as PropertyAccessExpression;
|
|
72
|
+
const special = this.tryEmitBuiltinCall(node, access);
|
|
73
|
+
if (special) return special;
|
|
74
|
+
if (access.expression.kind === SyntaxKind.Identifier && (access.expression as Identifier).text === "super") {
|
|
75
|
+
return this.emitSuperCall(node, access);
|
|
76
|
+
}
|
|
77
|
+
const object = this.emitExpression(access.expression);
|
|
78
|
+
const name = this.stringValue(access.name.text);
|
|
79
|
+
const args = this.emitArguments(node.arguments);
|
|
80
|
+
const result = this.reg();
|
|
81
|
+
this.emit(` ${result} = call i64 @xt_call_method(i64 ${object}, i64 ${name}, i32 ${args.argc}, i64* ${args.ptr})`);
|
|
82
|
+
return result;
|
|
83
|
+
}
|
|
84
|
+
if (callee.kind === SyntaxKind.ElementAccessExpression) {
|
|
85
|
+
const access = callee as ElementAccessExpression;
|
|
86
|
+
const object = this.emitExpression(access.expression);
|
|
87
|
+
const name = this.emitExpression(access.argumentExpression);
|
|
88
|
+
const args = this.emitArguments(node.arguments);
|
|
89
|
+
const result = this.reg();
|
|
90
|
+
this.emit(` ${result} = call i64 @xt_call_method(i64 ${object}, i64 ${name}, i32 ${args.argc}, i64* ${args.ptr})`);
|
|
91
|
+
return result;
|
|
92
|
+
}
|
|
93
|
+
if (callee.kind === SyntaxKind.Identifier) {
|
|
94
|
+
if ((callee as Identifier).text === "super") return this.emitSuperConstructor(node);
|
|
95
|
+
const symbol = this.binding.symbolOfIdentifier.get(callee as Identifier);
|
|
96
|
+
if (symbol && symbol.kind === SymbolKind.Import) {
|
|
97
|
+
const exported = this.importExports.get(symbol.id);
|
|
98
|
+
if (exported) return this.emitModuleExport(node, exported);
|
|
99
|
+
}
|
|
100
|
+
if (symbol && symbol.kind === SymbolKind.Function) {
|
|
101
|
+
const declaration = symbol.declarations[0];
|
|
102
|
+
const fn = declaration ? this.binding.functionOfNode.get(declaration) : undefined;
|
|
103
|
+
if (fn) {
|
|
104
|
+
const args = this.emitArguments(node.arguments);
|
|
105
|
+
const result = this.reg();
|
|
106
|
+
this.emit(
|
|
107
|
+
` ${result} = call i64 @${this.functionName(fn)}(i64 ${i64(XT_UNDEFINED)}, i64 ${i64(XT_UNDEFINED)}, i32 ${args.argc}, i64* ${args.ptr})`,
|
|
108
|
+
);
|
|
109
|
+
return result;
|
|
110
|
+
}
|
|
111
|
+
}
|
|
112
|
+
const globalFunction = !symbol ? GLOBAL_FUNCTIONS[(callee as Identifier).text] : undefined;
|
|
113
|
+
if (globalFunction) {
|
|
114
|
+
const args = this.emitArguments(node.arguments);
|
|
115
|
+
const result = this.reg();
|
|
116
|
+
this.emit(` ${result} = call i64 @${globalFunction}(i32 ${args.argc}, i64* ${args.ptr})`);
|
|
117
|
+
return result;
|
|
118
|
+
}
|
|
119
|
+
const builtin = this.builtins[(callee as Identifier).text];
|
|
120
|
+
if (!symbol && builtin) {
|
|
121
|
+
this.extraDeclarations.add(
|
|
122
|
+
builtin.returnVoid ? `declare void @${builtin.symbol}(i32, i64*)` : `declare i64 @${builtin.symbol}(i32, i64*)`,
|
|
123
|
+
);
|
|
124
|
+
const args = this.emitArguments(node.arguments);
|
|
125
|
+
if (builtin.returnVoid) {
|
|
126
|
+
this.emit(` call void @${builtin.symbol}(i32 ${args.argc}, i64* ${args.ptr})`);
|
|
127
|
+
return i64(XT_UNDEFINED);
|
|
128
|
+
}
|
|
129
|
+
const result = this.reg();
|
|
130
|
+
this.emit(` ${result} = call i64 @${builtin.symbol}(i32 ${args.argc}, i64* ${args.ptr})`);
|
|
131
|
+
return result;
|
|
132
|
+
}
|
|
133
|
+
const ctor = !symbol ? CTOR_FUNCTIONS[(callee as Identifier).text] : undefined;
|
|
134
|
+
if (ctor) {
|
|
135
|
+
const args = this.emitArguments(node.arguments);
|
|
136
|
+
const result = this.reg();
|
|
137
|
+
this.emit(` ${result} = call i64 @${ctor}(i32 ${args.argc}, i64* ${args.ptr})`);
|
|
138
|
+
return result;
|
|
139
|
+
}
|
|
140
|
+
}
|
|
141
|
+
const calleeValue = this.emitExpression(callee);
|
|
142
|
+
const args = this.emitArguments(node.arguments);
|
|
143
|
+
const result = this.reg();
|
|
144
|
+
this.emit(` ${result} = call i64 @xt_closure_call(i64 ${calleeValue}, i32 ${args.argc}, i64* ${args.ptr})`);
|
|
145
|
+
return result;
|
|
146
|
+
},
|
|
147
|
+
|
|
148
|
+
tryEmitBuiltinCall(node: CallExpression, callee: PropertyAccessExpression): string | undefined {
|
|
149
|
+
const target = callee.expression;
|
|
150
|
+
const method = callee.name.text;
|
|
151
|
+
const targetIdentifier = target.kind === SyntaxKind.Identifier ? (target as Identifier) : undefined;
|
|
152
|
+
const targetSymbol = targetIdentifier ? this.binding.symbolOfIdentifier.get(targetIdentifier) : undefined;
|
|
153
|
+
|
|
154
|
+
if (targetIdentifier && targetIdentifier.text === "console" && !targetSymbol) {
|
|
155
|
+
const consoleFn = CONSOLE_METHODS[method];
|
|
156
|
+
if (consoleFn) {
|
|
157
|
+
const args = this.emitArguments(node.arguments);
|
|
158
|
+
this.emit(` call void @${consoleFn}(i32 ${args.argc}, i64* ${args.ptr})`);
|
|
159
|
+
return i64(XT_UNDEFINED);
|
|
160
|
+
}
|
|
161
|
+
return undefined;
|
|
162
|
+
}
|
|
163
|
+
|
|
164
|
+
if (targetIdentifier && targetIdentifier.text === "Math" && !targetSymbol) {
|
|
165
|
+
if (!MATH_FUNCTIONS.has(method)) return undefined;
|
|
166
|
+
const name = this.stringValue(method);
|
|
167
|
+
const args = this.emitArguments(node.arguments);
|
|
168
|
+
const result = this.reg();
|
|
169
|
+
this.emit(` ${result} = call i64 @xt_math_call(i64 ${name}, i32 ${args.argc}, i64* ${args.ptr})`);
|
|
170
|
+
return result;
|
|
171
|
+
}
|
|
172
|
+
|
|
173
|
+
if (targetIdentifier && targetIdentifier.text === "JSON" && !targetSymbol) {
|
|
174
|
+
const fn = method === "parse" ? "xt_json_parse" : method === "stringify" ? "xt_json_stringify" : undefined;
|
|
175
|
+
if (!fn) return undefined;
|
|
176
|
+
const args = this.emitArguments(node.arguments);
|
|
177
|
+
const result = this.reg();
|
|
178
|
+
this.emit(` ${result} = call i64 @${fn}(i32 ${args.argc}, i64* ${args.ptr})`);
|
|
179
|
+
return result;
|
|
180
|
+
}
|
|
181
|
+
|
|
182
|
+
if (targetIdentifier && !targetSymbol) {
|
|
183
|
+
const dispatcher = NAMESPACE_STATICS[targetIdentifier.text];
|
|
184
|
+
if (dispatcher && targetIdentifier.text !== "Math" && targetIdentifier.text !== "JSON") {
|
|
185
|
+
const name = this.stringValue(method);
|
|
186
|
+
const args = this.emitArguments(node.arguments);
|
|
187
|
+
const result = this.reg();
|
|
188
|
+
this.emit(` ${result} = call i64 @${dispatcher}(i64 ${name}, i32 ${args.argc}, i64* ${args.ptr})`);
|
|
189
|
+
return result;
|
|
190
|
+
}
|
|
191
|
+
}
|
|
192
|
+
|
|
193
|
+
// `import * as ns from "path"` (or a default import) aliases a runtime
|
|
194
|
+
// namespace: `ns.join(...)` lowers to the same dispatcher as `path.join`.
|
|
195
|
+
if (targetIdentifier) {
|
|
196
|
+
const namespace = this.namespaceOfSymbol(targetSymbol);
|
|
197
|
+
if (namespace) {
|
|
198
|
+
const dispatcher = NAMESPACE_STATICS[namespace];
|
|
199
|
+
if (dispatcher) {
|
|
200
|
+
const name = this.stringValue(method);
|
|
201
|
+
const args = this.emitArguments(node.arguments);
|
|
202
|
+
const result = this.reg();
|
|
203
|
+
this.emit(` ${result} = call i64 @${dispatcher}(i64 ${name}, i32 ${args.argc}, i64* ${args.ptr})`);
|
|
204
|
+
return result;
|
|
205
|
+
}
|
|
206
|
+
}
|
|
207
|
+
}
|
|
208
|
+
|
|
209
|
+
void BUILTIN_METHODS;
|
|
210
|
+
return undefined;
|
|
211
|
+
},
|
|
212
|
+
|
|
213
|
+
/** Lower a call to an imported module binding to its runtime symbol. */
|
|
214
|
+
emitModuleExport(node: CallExpression, exported: ModuleExport): string {
|
|
215
|
+
const args = this.emitArguments(node.arguments);
|
|
216
|
+
if (exported.symbol) {
|
|
217
|
+
this.extraDeclarations.add(
|
|
218
|
+
exported.returnVoid
|
|
219
|
+
? `declare void @${exported.symbol}(i32, i64*)`
|
|
220
|
+
: `declare i64 @${exported.symbol}(i32, i64*)`,
|
|
221
|
+
);
|
|
222
|
+
if (exported.returnVoid) {
|
|
223
|
+
this.emit(` call void @${exported.symbol}(i32 ${args.argc}, i64* ${args.ptr})`);
|
|
224
|
+
return i64(XT_UNDEFINED);
|
|
225
|
+
}
|
|
226
|
+
const result = this.reg();
|
|
227
|
+
this.emit(` ${result} = call i64 @${exported.symbol}(i32 ${args.argc}, i64* ${args.ptr})`);
|
|
228
|
+
return result;
|
|
229
|
+
}
|
|
230
|
+
if (exported.namespace && exported.method) {
|
|
231
|
+
const dispatcher = NAMESPACE_STATICS[exported.namespace];
|
|
232
|
+
if (dispatcher) {
|
|
233
|
+
const name = this.stringValue(exported.method);
|
|
234
|
+
const result = this.reg();
|
|
235
|
+
this.emit(` ${result} = call i64 @${dispatcher}(i64 ${name}, i32 ${args.argc}, i64* ${args.ptr})`);
|
|
236
|
+
return result;
|
|
237
|
+
}
|
|
238
|
+
}
|
|
239
|
+
this.unsupported(node, "imported function");
|
|
240
|
+
return i64(XT_UNDEFINED);
|
|
241
|
+
},
|
|
242
|
+
|
|
243
|
+
runtimeCall(name: string, args: readonly string[]): string {
|
|
244
|
+
const result = this.reg();
|
|
245
|
+
this.emit(` ${result} = call i64 @${name}(${args.map((a) => `i64 ${a}`).join(", ")})`);
|
|
246
|
+
return result;
|
|
247
|
+
},
|
|
248
|
+
|
|
249
|
+
emitArguments(args: readonly Expression[]): { argc: string; ptr: string } {
|
|
250
|
+
if (args.length === 0) return { argc: "0", ptr: "null" };
|
|
251
|
+
const hasSpread = args.some((element) => element.kind === SyntaxKind.SpreadElement);
|
|
252
|
+
if (!hasSpread) {
|
|
253
|
+
const ptr = `%args${this.current.allocas.length}`;
|
|
254
|
+
this.current.allocas.push(`${ptr} = alloca i64, i32 ${args.length}`);
|
|
255
|
+
for (let index = 0; index < args.length; index++) {
|
|
256
|
+
const value = this.emitExpression(args[index]!);
|
|
257
|
+
const slot = this.reg();
|
|
258
|
+
this.emit(` ${slot} = getelementptr i64, i64* ${ptr}, i32 ${index}`);
|
|
259
|
+
this.emit(` store i64 ${value}, i64* ${slot}`);
|
|
260
|
+
}
|
|
261
|
+
return { argc: String(args.length), ptr };
|
|
262
|
+
}
|
|
263
|
+
// At least one `...spread`: accumulate the argument list in a runtime
|
|
264
|
+
// array, which grows to whatever length the spread produces.
|
|
265
|
+
const array = this.reg();
|
|
266
|
+
this.emit(` ${array} = call i64 @xt_array_new(i32 0, i64* null)`);
|
|
267
|
+
for (const element of args) {
|
|
268
|
+
if (element.kind === SyntaxKind.SpreadElement) {
|
|
269
|
+
const value = this.emitExpression((element as SpreadElement).expression);
|
|
270
|
+
this.emit(` call i64 @xt_array_spread(i64 ${array}, i64 ${value})`);
|
|
271
|
+
} else {
|
|
272
|
+
const value = this.emitExpression(element);
|
|
273
|
+
this.emit(` call i64 @xt_array_push(i64 ${array}, i64 ${value})`);
|
|
274
|
+
}
|
|
275
|
+
}
|
|
276
|
+
const argc = this.reg();
|
|
277
|
+
this.emit(` ${argc} = call i32 @xt_array_size(i64 ${array})`);
|
|
278
|
+
const ptr = this.reg();
|
|
279
|
+
this.emit(` ${ptr} = call i64* @xt_array_items(i64 ${array})`);
|
|
280
|
+
return { argc, ptr };
|
|
281
|
+
},
|
|
282
|
+
};
|