xbintsc 0.2.9 → 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 +78 -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 +1 -0
- 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,226 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Assignment lowering: compound/logical assignment and destructuring targets.
|
|
3
|
+
*/
|
|
4
|
+
|
|
5
|
+
import {
|
|
6
|
+
SyntaxKind,
|
|
7
|
+
AssignmentOperator,
|
|
8
|
+
type ArrayLiteralExpression,
|
|
9
|
+
type BinaryExpression,
|
|
10
|
+
type ElementAccessExpression,
|
|
11
|
+
type Expression,
|
|
12
|
+
type Identifier,
|
|
13
|
+
type ObjectLiteralExpression,
|
|
14
|
+
type PropertyAccessExpression,
|
|
15
|
+
type PropertyAssignment,
|
|
16
|
+
type ShorthandPropertyAssignment,
|
|
17
|
+
type SpreadElement,
|
|
18
|
+
} from "../../../ast/nodes.js";
|
|
19
|
+
import { SymbolKind } from "../../../binder/binder.js";
|
|
20
|
+
import { DiagnosticCode } from "../../../diagnostics/diagnostic.js";
|
|
21
|
+
import { i64, numberLiteral, XT_UNDEFINED } from "../../values.js";
|
|
22
|
+
import { BINARY_RUNTIME, compoundToBinary, propertyNameText } from "../tables.js";
|
|
23
|
+
import type { Generator } from "../generator.js";
|
|
24
|
+
|
|
25
|
+
export interface AssignmentExpressionMethods {
|
|
26
|
+
emitAssignment(this: Generator, node: BinaryExpression): string;
|
|
27
|
+
emitLogicalAssignment(this: Generator, node: BinaryExpression): string;
|
|
28
|
+
emitAssignmentTarget(this: Generator, target: Expression, value: string): void;
|
|
29
|
+
emitArrayAssignmentTarget(this: Generator, pattern: ArrayLiteralExpression, value: string): void;
|
|
30
|
+
emitObjectAssignmentTarget(this: Generator, pattern: ObjectLiteralExpression, value: string): void;
|
|
31
|
+
}
|
|
32
|
+
|
|
33
|
+
/** True for `target = default` (only the plain assignment operator). */
|
|
34
|
+
function isPlainAssignment(node: Expression): boolean {
|
|
35
|
+
if (node.kind !== SyntaxKind.BinaryExpression) return false;
|
|
36
|
+
return ((node as BinaryExpression).operator as unknown as AssignmentOperator) === AssignmentOperator.Assign;
|
|
37
|
+
}
|
|
38
|
+
|
|
39
|
+
export const assignmentExpressionMethods: AssignmentExpressionMethods = {
|
|
40
|
+
emitAssignment(node: BinaryExpression): string {
|
|
41
|
+
const operator = node.operator as unknown as AssignmentOperator;
|
|
42
|
+
const target = node.left;
|
|
43
|
+
let value: string;
|
|
44
|
+
if (operator === AssignmentOperator.Assign) {
|
|
45
|
+
value = this.emitExpression(node.right);
|
|
46
|
+
} else if (
|
|
47
|
+
operator === AssignmentOperator.AmpersandAmpersandAssign ||
|
|
48
|
+
operator === AssignmentOperator.BarBarAssign ||
|
|
49
|
+
operator === AssignmentOperator.QuestionQuestionAssign
|
|
50
|
+
) {
|
|
51
|
+
value = this.emitLogicalAssignment(node);
|
|
52
|
+
} else {
|
|
53
|
+
const current = this.emitExpression(target);
|
|
54
|
+
const right = this.emitExpression(node.right);
|
|
55
|
+
const binaryOperator = compoundToBinary(operator);
|
|
56
|
+
const runtime = BINARY_RUNTIME[binaryOperator];
|
|
57
|
+
if (!runtime) {
|
|
58
|
+
this.unsupported(node, `assignment operator '${operator}'`);
|
|
59
|
+
return i64(XT_UNDEFINED);
|
|
60
|
+
}
|
|
61
|
+
const result = this.reg();
|
|
62
|
+
this.emit(` ${result} = call i64 @${runtime}(i64 ${current}, i64 ${right})`);
|
|
63
|
+
value = result;
|
|
64
|
+
}
|
|
65
|
+
this.emitAssignmentTarget(target, value);
|
|
66
|
+
return value;
|
|
67
|
+
},
|
|
68
|
+
|
|
69
|
+
emitLogicalAssignment(node: BinaryExpression): string {
|
|
70
|
+
const operator = node.operator as unknown as AssignmentOperator;
|
|
71
|
+
const target = node.left;
|
|
72
|
+
const current = this.emitExpression(target);
|
|
73
|
+
const result = this.alloca();
|
|
74
|
+
this.emit(` store i64 ${current}, i64* ${result}`);
|
|
75
|
+
const rightLabel = this.label("assign.right");
|
|
76
|
+
const endLabel = this.label("assign.end");
|
|
77
|
+
let condition: string;
|
|
78
|
+
if (operator === AssignmentOperator.AmpersandAmpersandAssign) {
|
|
79
|
+
const truthy = this.reg();
|
|
80
|
+
this.emit(` ${truthy} = call i32 @xt_truthy(i64 ${current})`);
|
|
81
|
+
condition = this.reg();
|
|
82
|
+
this.emit(` ${condition} = icmp ne i32 ${truthy}, 0`);
|
|
83
|
+
} else if (operator === AssignmentOperator.BarBarAssign) {
|
|
84
|
+
const truthy = this.reg();
|
|
85
|
+
this.emit(` ${truthy} = call i32 @xt_truthy(i64 ${current})`);
|
|
86
|
+
const isTruthy = this.reg();
|
|
87
|
+
this.emit(` ${isTruthy} = icmp ne i32 ${truthy}, 0`);
|
|
88
|
+
condition = this.reg();
|
|
89
|
+
this.emit(` ${condition} = xor i1 ${isTruthy}, true`);
|
|
90
|
+
} else {
|
|
91
|
+
const nullish = this.reg();
|
|
92
|
+
this.emit(` ${nullish} = call i64 @xt_is_nullish(i64 ${current})`);
|
|
93
|
+
const truthy = this.reg();
|
|
94
|
+
this.emit(` ${truthy} = call i32 @xt_truthy(i64 ${nullish})`);
|
|
95
|
+
condition = this.reg();
|
|
96
|
+
this.emit(` ${condition} = icmp ne i32 ${truthy}, 0`);
|
|
97
|
+
}
|
|
98
|
+
this.terminate(`br i1 ${condition}, label %${rightLabel}, label %${endLabel}`);
|
|
99
|
+
this.startBlock(rightLabel);
|
|
100
|
+
const right = this.emitExpression(node.right);
|
|
101
|
+
this.emit(` store i64 ${right}, i64* ${result}`);
|
|
102
|
+
this.terminate(`br label %${endLabel}`);
|
|
103
|
+
this.startBlock(endLabel);
|
|
104
|
+
const value = this.reg();
|
|
105
|
+
this.emit(` ${value} = load i64, i64* ${result}`);
|
|
106
|
+
this.emitAssignmentTarget(target, value);
|
|
107
|
+
return value;
|
|
108
|
+
},
|
|
109
|
+
|
|
110
|
+
emitAssignmentTarget(target: Expression, value: string): void {
|
|
111
|
+
switch (target.kind) {
|
|
112
|
+
case SyntaxKind.Identifier: {
|
|
113
|
+
const identifier = target as Identifier;
|
|
114
|
+
const symbol = this.binding.symbolOfIdentifier.get(identifier);
|
|
115
|
+
if (!symbol) return;
|
|
116
|
+
if (symbol.kind === SymbolKind.Const || symbol.kind === SymbolKind.Import) {
|
|
117
|
+
this.diagnostics.error(
|
|
118
|
+
DiagnosticCode.CannotAssignToConst,
|
|
119
|
+
symbol.kind === SymbolKind.Import
|
|
120
|
+
? `Cannot assign to '${symbol.name}' because it is an import.`
|
|
121
|
+
: `Cannot assign to '${symbol.name}' because it is a constant.`,
|
|
122
|
+
identifier,
|
|
123
|
+
this.sourceFile.fileName,
|
|
124
|
+
);
|
|
125
|
+
return;
|
|
126
|
+
}
|
|
127
|
+
this.writeSlot(symbol, value);
|
|
128
|
+
return;
|
|
129
|
+
}
|
|
130
|
+
case SyntaxKind.PropertyAccessExpression: {
|
|
131
|
+
const access = target as PropertyAccessExpression;
|
|
132
|
+
const object = this.emitExpression(access.expression);
|
|
133
|
+
const key = this.stringValue(access.name.text);
|
|
134
|
+
this.emit(` call i64 @xt_set(i64 ${object}, i64 ${key}, i64 ${value})`);
|
|
135
|
+
return;
|
|
136
|
+
}
|
|
137
|
+
case SyntaxKind.ElementAccessExpression: {
|
|
138
|
+
const access = target as ElementAccessExpression;
|
|
139
|
+
const object = this.emitExpression(access.expression);
|
|
140
|
+
const key = this.emitExpression(access.argumentExpression);
|
|
141
|
+
this.emit(` call i64 @xt_set(i64 ${object}, i64 ${key}, i64 ${value})`);
|
|
142
|
+
return;
|
|
143
|
+
}
|
|
144
|
+
case SyntaxKind.ParenthesizedExpression:
|
|
145
|
+
this.emitAssignmentTarget((target as { expression: Expression }).expression, value);
|
|
146
|
+
return;
|
|
147
|
+
case SyntaxKind.ArrayLiteralExpression:
|
|
148
|
+
this.emitArrayAssignmentTarget(target as ArrayLiteralExpression, value);
|
|
149
|
+
return;
|
|
150
|
+
case SyntaxKind.ObjectLiteralExpression:
|
|
151
|
+
this.emitObjectAssignmentTarget(target as ObjectLiteralExpression, value);
|
|
152
|
+
return;
|
|
153
|
+
default:
|
|
154
|
+
this.unsupported(target, "assignment target");
|
|
155
|
+
}
|
|
156
|
+
},
|
|
157
|
+
|
|
158
|
+
/** `[a, b] = value` / `for ([a, b] of xs)`: assign each element of `value`. */
|
|
159
|
+
emitArrayAssignmentTarget(pattern: ArrayLiteralExpression, value: string): void {
|
|
160
|
+
for (let index = 0; index < pattern.elements.length; index++) {
|
|
161
|
+
const element = pattern.elements[index];
|
|
162
|
+
if (!element) continue;
|
|
163
|
+
if (element.kind === SyntaxKind.UndefinedKeyword) continue; // elision hole
|
|
164
|
+
if (element.kind === SyntaxKind.SpreadElement) {
|
|
165
|
+
const spread = element as SpreadElement;
|
|
166
|
+
const startPtr = this.alloca();
|
|
167
|
+
this.emit(` store i64 ${numberLiteral(index)}, i64* ${startPtr}`);
|
|
168
|
+
const sliceName = this.stringValue("slice");
|
|
169
|
+
const rest = this.reg();
|
|
170
|
+
this.emit(` ${rest} = call i64 @xt_call_method(i64 ${value}, i64 ${sliceName}, i32 1, i64* ${startPtr})`);
|
|
171
|
+
this.emitAssignmentTarget(spread.expression, rest);
|
|
172
|
+
continue;
|
|
173
|
+
}
|
|
174
|
+
let target: Expression = element;
|
|
175
|
+
let fallback: Expression | undefined;
|
|
176
|
+
if (isPlainAssignment(element)) {
|
|
177
|
+
const binary = element as BinaryExpression;
|
|
178
|
+
target = binary.left;
|
|
179
|
+
fallback = binary.right;
|
|
180
|
+
}
|
|
181
|
+
let elementValue = this.reg();
|
|
182
|
+
this.emit(` ${elementValue} = call i64 @xt_get(i64 ${value}, i64 ${numberLiteral(index)})`);
|
|
183
|
+
if (fallback) elementValue = this.emitBindingDefault(elementValue, fallback);
|
|
184
|
+
this.emitAssignmentTarget(target, elementValue);
|
|
185
|
+
}
|
|
186
|
+
},
|
|
187
|
+
|
|
188
|
+
/** `{ a, b } = value` / `for ({ a } of xs)`: assign each property of `value`. */
|
|
189
|
+
emitObjectAssignmentTarget(pattern: ObjectLiteralExpression, value: string): void {
|
|
190
|
+
for (const property of pattern.properties) {
|
|
191
|
+
if (property.kind === SyntaxKind.SpreadElement) {
|
|
192
|
+
this.unsupported(property, "object rest destructuring");
|
|
193
|
+
continue;
|
|
194
|
+
}
|
|
195
|
+
if (property.kind === SyntaxKind.PropertyAssignment) {
|
|
196
|
+
const assignment = property as PropertyAssignment;
|
|
197
|
+
let key: string;
|
|
198
|
+
if (assignment.name.kind === SyntaxKind.ComputedPropertyName) {
|
|
199
|
+
const keyValue = this.emitExpression((assignment.name as { expression: Expression }).expression);
|
|
200
|
+
key = this.reg();
|
|
201
|
+
this.emit(` ${key} = call i64 @xt_to_string(i64 ${keyValue})`);
|
|
202
|
+
} else {
|
|
203
|
+
key = this.stringValue(propertyNameText(assignment.name));
|
|
204
|
+
}
|
|
205
|
+
let target: Expression = assignment.initializer;
|
|
206
|
+
let fallback: Expression | undefined;
|
|
207
|
+
if (isPlainAssignment(target)) {
|
|
208
|
+
const binary = target as BinaryExpression;
|
|
209
|
+
target = binary.left;
|
|
210
|
+
fallback = binary.right;
|
|
211
|
+
}
|
|
212
|
+
let elementValue = this.reg();
|
|
213
|
+
this.emit(` ${elementValue} = call i64 @xt_get(i64 ${value}, i64 ${key})`);
|
|
214
|
+
if (fallback) elementValue = this.emitBindingDefault(elementValue, fallback);
|
|
215
|
+
this.emitAssignmentTarget(target, elementValue);
|
|
216
|
+
continue;
|
|
217
|
+
}
|
|
218
|
+
const shorthand = property as ShorthandPropertyAssignment;
|
|
219
|
+
const key = this.stringValue(shorthand.name.text);
|
|
220
|
+
let elementValue = this.reg();
|
|
221
|
+
this.emit(` ${elementValue} = call i64 @xt_get(i64 ${value}, i64 ${key})`);
|
|
222
|
+
if (shorthand.initializer) elementValue = this.emitBindingDefault(elementValue, shorthand.initializer);
|
|
223
|
+
this.emitAssignmentTarget(shorthand.name, elementValue);
|
|
224
|
+
}
|
|
225
|
+
},
|
|
226
|
+
};
|
|
@@ -0,0 +1,182 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Operator lowering: binary/compound expressions, short-circuiting,
|
|
3
|
+
* conditionals and unary operators.
|
|
4
|
+
*/
|
|
5
|
+
|
|
6
|
+
import {
|
|
7
|
+
BinaryOperator,
|
|
8
|
+
PostfixUnaryOperator,
|
|
9
|
+
PrefixUnaryOperator,
|
|
10
|
+
type BinaryExpression,
|
|
11
|
+
type ConditionalExpression,
|
|
12
|
+
type PostfixUnaryExpression,
|
|
13
|
+
type PrefixUnaryExpression,
|
|
14
|
+
} from "../../../ast/nodes.js";
|
|
15
|
+
import { i64, numberLiteral, XT_UNDEFINED } from "../../values.js";
|
|
16
|
+
import { BINARY_RUNTIME, isAssignmentOperator } from "../tables.js";
|
|
17
|
+
import type { Generator } from "../generator.js";
|
|
18
|
+
|
|
19
|
+
export interface OperatorExpressionMethods {
|
|
20
|
+
emitBinaryOrAssignment(this: Generator, node: BinaryExpression): string;
|
|
21
|
+
emitShortCircuit(this: Generator, node: BinaryExpression, kind: "and" | "or" | "nullish"): string;
|
|
22
|
+
emitConditional(this: Generator, node: ConditionalExpression): string;
|
|
23
|
+
emitPrefix(this: Generator, node: PrefixUnaryExpression): string;
|
|
24
|
+
emitPostfix(this: Generator, node: PostfixUnaryExpression): string;
|
|
25
|
+
}
|
|
26
|
+
|
|
27
|
+
export const operatorExpressionMethods: OperatorExpressionMethods = {
|
|
28
|
+
emitBinaryOrAssignment(node: BinaryExpression): string {
|
|
29
|
+
const operator = node.operator as string;
|
|
30
|
+
if (isAssignmentOperator(operator)) {
|
|
31
|
+
return this.emitAssignment(node);
|
|
32
|
+
}
|
|
33
|
+
switch (operator) {
|
|
34
|
+
case BinaryOperator.AmpersandAmpersand:
|
|
35
|
+
return this.emitShortCircuit(node, "and");
|
|
36
|
+
case BinaryOperator.BarBar:
|
|
37
|
+
return this.emitShortCircuit(node, "or");
|
|
38
|
+
case BinaryOperator.QuestionQuestion:
|
|
39
|
+
return this.emitShortCircuit(node, "nullish");
|
|
40
|
+
case BinaryOperator.Comma: {
|
|
41
|
+
this.emitExpression(node.left);
|
|
42
|
+
return this.emitExpression(node.right);
|
|
43
|
+
}
|
|
44
|
+
default:
|
|
45
|
+
break;
|
|
46
|
+
}
|
|
47
|
+
const left = this.emitExpression(node.left);
|
|
48
|
+
const right = this.emitExpression(node.right);
|
|
49
|
+
const runtime = BINARY_RUNTIME[operator];
|
|
50
|
+
if (!runtime) {
|
|
51
|
+
this.unsupported(node, `operator '${operator}'`);
|
|
52
|
+
return i64(XT_UNDEFINED);
|
|
53
|
+
}
|
|
54
|
+
const result = this.reg();
|
|
55
|
+
this.emit(` ${result} = call i64 @${runtime}(i64 ${left}, i64 ${right})`);
|
|
56
|
+
return result;
|
|
57
|
+
},
|
|
58
|
+
|
|
59
|
+
emitShortCircuit(node: BinaryExpression, kind: "and" | "or" | "nullish"): string {
|
|
60
|
+
const result = this.alloca();
|
|
61
|
+
const left = this.emitExpression(node.left);
|
|
62
|
+
this.emit(` store i64 ${left}, i64* ${result}`);
|
|
63
|
+
const rightLabel = this.label("sc.right");
|
|
64
|
+
const endLabel = this.label("sc.end");
|
|
65
|
+
let condition: string;
|
|
66
|
+
if (kind === "and") {
|
|
67
|
+
const truthy = this.reg();
|
|
68
|
+
this.emit(` ${truthy} = call i32 @xt_truthy(i64 ${left})`);
|
|
69
|
+
condition = this.reg();
|
|
70
|
+
this.emit(` ${condition} = icmp ne i32 ${truthy}, 0`);
|
|
71
|
+
} else if (kind === "or") {
|
|
72
|
+
const truthy = this.reg();
|
|
73
|
+
this.emit(` ${truthy} = call i32 @xt_truthy(i64 ${left})`);
|
|
74
|
+
const isTruthy = this.reg();
|
|
75
|
+
this.emit(` ${isTruthy} = icmp ne i32 ${truthy}, 0`);
|
|
76
|
+
condition = this.reg();
|
|
77
|
+
this.emit(` ${condition} = xor i1 ${isTruthy}, true`);
|
|
78
|
+
} else {
|
|
79
|
+
const nullish = this.reg();
|
|
80
|
+
this.emit(` ${nullish} = call i64 @xt_is_nullish(i64 ${left})`);
|
|
81
|
+
const truthy = this.reg();
|
|
82
|
+
this.emit(` ${truthy} = call i32 @xt_truthy(i64 ${nullish})`);
|
|
83
|
+
condition = this.reg();
|
|
84
|
+
this.emit(` ${condition} = icmp ne i32 ${truthy}, 0`);
|
|
85
|
+
}
|
|
86
|
+
this.terminate(`br i1 ${condition}, label %${rightLabel}, label %${endLabel}`);
|
|
87
|
+
this.startBlock(rightLabel);
|
|
88
|
+
const right = this.emitExpression(node.right);
|
|
89
|
+
this.emit(` store i64 ${right}, i64* ${result}`);
|
|
90
|
+
this.terminate(`br label %${endLabel}`);
|
|
91
|
+
this.startBlock(endLabel);
|
|
92
|
+
const value = this.reg();
|
|
93
|
+
this.emit(` ${value} = load i64, i64* ${result}`);
|
|
94
|
+
return value;
|
|
95
|
+
},
|
|
96
|
+
|
|
97
|
+
emitConditional(node: ConditionalExpression): string {
|
|
98
|
+
const result = this.alloca();
|
|
99
|
+
const condition = this.emitExpression(node.condition);
|
|
100
|
+
const truthy = this.reg();
|
|
101
|
+
this.emit(` ${truthy} = call i32 @xt_truthy(i64 ${condition})`);
|
|
102
|
+
const nonzero = this.reg();
|
|
103
|
+
this.emit(` ${nonzero} = icmp ne i32 ${truthy}, 0`);
|
|
104
|
+
const trueLabel = this.label("cond.true");
|
|
105
|
+
const falseLabel = this.label("cond.false");
|
|
106
|
+
const endLabel = this.label("cond.end");
|
|
107
|
+
this.terminate(`br i1 ${nonzero}, label %${trueLabel}, label %${falseLabel}`);
|
|
108
|
+
this.startBlock(trueLabel);
|
|
109
|
+
const whenTrue = this.emitExpression(node.whenTrue);
|
|
110
|
+
this.emit(` store i64 ${whenTrue}, i64* ${result}`);
|
|
111
|
+
this.terminate(`br label %${endLabel}`);
|
|
112
|
+
this.startBlock(falseLabel);
|
|
113
|
+
const whenFalse = this.emitExpression(node.whenFalse);
|
|
114
|
+
this.emit(` store i64 ${whenFalse}, i64* ${result}`);
|
|
115
|
+
this.terminate(`br label %${endLabel}`);
|
|
116
|
+
this.startBlock(endLabel);
|
|
117
|
+
const value = this.reg();
|
|
118
|
+
this.emit(` ${value} = load i64, i64* ${result}`);
|
|
119
|
+
return value;
|
|
120
|
+
},
|
|
121
|
+
|
|
122
|
+
emitPrefix(node: PrefixUnaryExpression): string {
|
|
123
|
+
switch (node.operator) {
|
|
124
|
+
case PrefixUnaryOperator.Minus: {
|
|
125
|
+
const operand = this.emitExpression(node.operand);
|
|
126
|
+
const result = this.reg();
|
|
127
|
+
this.emit(` ${result} = call i64 @xt_neg(i64 ${operand})`);
|
|
128
|
+
return result;
|
|
129
|
+
}
|
|
130
|
+
case PrefixUnaryOperator.Plus: {
|
|
131
|
+
const operand = this.emitExpression(node.operand);
|
|
132
|
+
const result = this.reg();
|
|
133
|
+
this.emit(` ${result} = call i64 @xt_pos(i64 ${operand})`);
|
|
134
|
+
return result;
|
|
135
|
+
}
|
|
136
|
+
case PrefixUnaryOperator.Exclamation: {
|
|
137
|
+
const operand = this.emitExpression(node.operand);
|
|
138
|
+
const result = this.reg();
|
|
139
|
+
this.emit(` ${result} = call i64 @xt_not(i64 ${operand})`);
|
|
140
|
+
return result;
|
|
141
|
+
}
|
|
142
|
+
case PrefixUnaryOperator.Tilde: {
|
|
143
|
+
const operand = this.emitExpression(node.operand);
|
|
144
|
+
const result = this.reg();
|
|
145
|
+
this.emit(` ${result} = call i64 @xt_bit_not(i64 ${operand})`);
|
|
146
|
+
return result;
|
|
147
|
+
}
|
|
148
|
+
case PrefixUnaryOperator.TypeOf: {
|
|
149
|
+
const operand = this.emitExpression(node.operand);
|
|
150
|
+
const result = this.reg();
|
|
151
|
+
this.emit(` ${result} = call i64 @xt_typeof(i64 ${operand})`);
|
|
152
|
+
return result;
|
|
153
|
+
}
|
|
154
|
+
case PrefixUnaryOperator.Void:
|
|
155
|
+
if (node.operand) this.emitExpression(node.operand);
|
|
156
|
+
return i64(XT_UNDEFINED);
|
|
157
|
+
case PrefixUnaryOperator.PlusPlus:
|
|
158
|
+
case PrefixUnaryOperator.MinusMinus: {
|
|
159
|
+
const one = numberLiteral(1);
|
|
160
|
+
const current = this.emitExpression(node.operand);
|
|
161
|
+
const fn = node.operator === PrefixUnaryOperator.PlusPlus ? "xt_add" : "xt_sub";
|
|
162
|
+
const next = this.reg();
|
|
163
|
+
this.emit(` ${next} = call i64 @${fn}(i64 ${current}, i64 ${one})`);
|
|
164
|
+
this.emitAssignmentTarget(node.operand, next);
|
|
165
|
+
return next;
|
|
166
|
+
}
|
|
167
|
+
default:
|
|
168
|
+
this.unsupported(node, `unary operator '${node.operator}'`);
|
|
169
|
+
return i64(XT_UNDEFINED);
|
|
170
|
+
}
|
|
171
|
+
},
|
|
172
|
+
|
|
173
|
+
emitPostfix(node: PostfixUnaryExpression): string {
|
|
174
|
+
const one = numberLiteral(1);
|
|
175
|
+
const current = this.emitExpression(node.operand);
|
|
176
|
+
const fn = node.operator === PostfixUnaryOperator.PlusPlus ? "xt_add" : "xt_sub";
|
|
177
|
+
const next = this.reg();
|
|
178
|
+
this.emit(` ${next} = call i64 @${fn}(i64 ${current}, i64 ${one})`);
|
|
179
|
+
this.emitAssignmentTarget(node.operand, next);
|
|
180
|
+
return current;
|
|
181
|
+
},
|
|
182
|
+
};
|