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
package/src/driver/toolchain.ts
CHANGED
|
@@ -13,8 +13,14 @@ export interface CommandResult {
|
|
|
13
13
|
readonly stderr: string;
|
|
14
14
|
}
|
|
15
15
|
|
|
16
|
+
export interface RunOptions {
|
|
17
|
+
readonly cwd?: string;
|
|
18
|
+
/** Extra environment variables, merged over `process.env`. */
|
|
19
|
+
readonly env?: Record<string, string>;
|
|
20
|
+
}
|
|
21
|
+
|
|
16
22
|
export interface Runner {
|
|
17
|
-
run(command: string, args: readonly string[], options?:
|
|
23
|
+
run(command: string, args: readonly string[], options?: RunOptions): CommandResult;
|
|
18
24
|
}
|
|
19
25
|
|
|
20
26
|
export const realRunner: Runner = {
|
|
@@ -24,6 +30,7 @@ export const realRunner: Runner = {
|
|
|
24
30
|
encoding: "utf8",
|
|
25
31
|
maxBuffer: 64 * 1024 * 1024,
|
|
26
32
|
};
|
|
33
|
+
if (options.env) spawnOptions.env = Object.assign({}, process.env, options.env);
|
|
27
34
|
const result = spawnSync(command, [...args], spawnOptions);
|
|
28
35
|
return {
|
|
29
36
|
status: result.status ?? (result.error ? 1 : 0),
|
|
@@ -68,17 +75,16 @@ export interface CompileIrOptions {
|
|
|
68
75
|
readonly irPath: string;
|
|
69
76
|
readonly objectPath: string;
|
|
70
77
|
readonly optimize: string;
|
|
78
|
+
readonly env?: Record<string, string>;
|
|
71
79
|
}
|
|
72
80
|
|
|
73
81
|
/** Compile an LLVM IR file to a native object file. */
|
|
74
82
|
export function compileIr(runner: Runner, options: CompileIrOptions): void {
|
|
75
|
-
const result = runner.run(
|
|
76
|
-
|
|
77
|
-
"-c",
|
|
78
|
-
options.
|
|
79
|
-
|
|
80
|
-
options.objectPath,
|
|
81
|
-
]);
|
|
83
|
+
const result = runner.run(
|
|
84
|
+
options.clang,
|
|
85
|
+
[`-O${options.optimize}`, "-c", options.irPath, "-o", options.objectPath],
|
|
86
|
+
{ env: options.env },
|
|
87
|
+
);
|
|
82
88
|
if (result.status !== 0) throw new ToolchainError(`${options.clang} ${options.irPath}`, result.status, result.stderr);
|
|
83
89
|
}
|
|
84
90
|
|
|
@@ -88,16 +94,28 @@ export interface LinkOptions {
|
|
|
88
94
|
readonly outputPath: string;
|
|
89
95
|
readonly linkerFlags: readonly string[];
|
|
90
96
|
readonly optimize: string;
|
|
97
|
+
readonly env?: Record<string, string>;
|
|
91
98
|
}
|
|
92
99
|
|
|
93
100
|
export function link(runner: Runner, options: LinkOptions): void {
|
|
94
101
|
const args = [`-O${options.optimize}`, ...options.objectPaths, "-o", options.outputPath, ...options.linkerFlags];
|
|
95
|
-
const result = runner.run(options.clang, args);
|
|
102
|
+
const result = runner.run(options.clang, args, { env: options.env });
|
|
96
103
|
if (result.status !== 0) throw new ToolchainError(`${options.clang} link`, result.status, result.stderr);
|
|
97
104
|
}
|
|
98
105
|
|
|
99
106
|
/** Compile a C source to an object file (used for the runtime and extensions). */
|
|
100
|
-
export function compileC(
|
|
101
|
-
|
|
107
|
+
export function compileC(
|
|
108
|
+
runner: Runner,
|
|
109
|
+
clang: string,
|
|
110
|
+
sourcePath: string,
|
|
111
|
+
objectPath: string,
|
|
112
|
+
includeDir: string,
|
|
113
|
+
env?: Record<string, string>,
|
|
114
|
+
): void {
|
|
115
|
+
const result = runner.run(
|
|
116
|
+
clang,
|
|
117
|
+
["-O2", "-D_CRT_SECURE_NO_WARNINGS", "-c", sourcePath, "-o", objectPath, `-I${includeDir}`],
|
|
118
|
+
{ env },
|
|
119
|
+
);
|
|
102
120
|
if (result.status !== 0) throw new ToolchainError(`${clang} ${sourcePath}`, result.status, result.stderr);
|
|
103
121
|
}
|
|
@@ -1,7 +1,9 @@
|
|
|
1
1
|
/**
|
|
2
2
|
* Node's `child_process` module: `spawnSync(command, args, options)`, backed by
|
|
3
|
-
* `runtime/ext_node/child_process`. Captures stdout/stderr as UTF-8 strings
|
|
4
|
-
* honours `options.cwd`,
|
|
3
|
+
* `runtime/ext_node/child_process`. Captures stdout/stderr as UTF-8 strings,
|
|
4
|
+
* honours `options.cwd`, and supports `options.stdio: "inherit"` (hand the
|
|
5
|
+
* child the parent's stdout/stderr) — which is all the compiler's toolchain
|
|
6
|
+
* wrapper and `xbintsc run` need.
|
|
5
7
|
*/
|
|
6
8
|
|
|
7
9
|
import type { NodeModule } from "../module.js";
|
|
@@ -0,0 +1,27 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Node's `events` module.
|
|
3
|
+
*
|
|
4
|
+
* Exposes the standalone `EventEmitter` class plus its statics. `EventEmitter`
|
|
5
|
+
* is provided both as a global constructor and as a named export, so
|
|
6
|
+
* `new EventEmitter()` and `import { EventEmitter } from "events"` both work.
|
|
7
|
+
* The implementation lives in `runtime/ext_node/events/events.c`.
|
|
8
|
+
*/
|
|
9
|
+
|
|
10
|
+
import type { NodeModule } from "../module.js";
|
|
11
|
+
import { resolveFrom } from "../module.js";
|
|
12
|
+
import type { ModuleExports } from "../../registry.js";
|
|
13
|
+
|
|
14
|
+
const methods = ["listenerCount", "getEventListeners", "getMaxListeners", "setMaxListeners", "once"] as const;
|
|
15
|
+
|
|
16
|
+
const exports: ModuleExports = {
|
|
17
|
+
EventEmitter: { symbol: "xt_event_emitter_ctor", isConstructor: true },
|
|
18
|
+
...Object.fromEntries(methods.map((method) => [method, { namespace: "events", method }])),
|
|
19
|
+
};
|
|
20
|
+
|
|
21
|
+
export const eventsModule: NodeModule = {
|
|
22
|
+
name: "events",
|
|
23
|
+
namespace: "events",
|
|
24
|
+
runtimeSources: () => [resolveFrom(import.meta.url, "../../../../runtime/ext_node/events/events.c")],
|
|
25
|
+
builtins: () => ({}),
|
|
26
|
+
exports: () => exports,
|
|
27
|
+
};
|
|
@@ -25,6 +25,9 @@ import { httpModule } from "./http/index.js";
|
|
|
25
25
|
import { urlModule } from "./url/index.js";
|
|
26
26
|
import { cryptoModule } from "./crypto/index.js";
|
|
27
27
|
import { childProcessModule } from "./child_process/index.js";
|
|
28
|
+
import { eventsModule } from "./events/index.js";
|
|
29
|
+
import { utilModule } from "./util/index.js";
|
|
30
|
+
import { querystringModule } from "./querystring/index.js";
|
|
28
31
|
|
|
29
32
|
/** Every Node module the extension currently provides. */
|
|
30
33
|
const modules: readonly NodeModule[] = [
|
|
@@ -41,6 +44,9 @@ const modules: readonly NodeModule[] = [
|
|
|
41
44
|
urlModule,
|
|
42
45
|
cryptoModule,
|
|
43
46
|
childProcessModule,
|
|
47
|
+
eventsModule,
|
|
48
|
+
utilModule,
|
|
49
|
+
querystringModule,
|
|
44
50
|
];
|
|
45
51
|
|
|
46
52
|
export const nodeExtension: Extension = {
|
|
@@ -0,0 +1,29 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Node's `querystring` module.
|
|
3
|
+
*
|
|
4
|
+
* `parse` / `decode` and `stringify` / `encode` are the same functions under
|
|
5
|
+
* two names, alongside `escape` / `unescape`. Both named imports and namespace
|
|
6
|
+
* calls (`import qs from "querystring"`) are supported; the implementation
|
|
7
|
+
* lives in `runtime/ext_node/querystring/querystring.c`.
|
|
8
|
+
*/
|
|
9
|
+
|
|
10
|
+
import type { NodeModule } from "../module.js";
|
|
11
|
+
import { resolveFrom } from "../module.js";
|
|
12
|
+
import type { ModuleExports } from "../../registry.js";
|
|
13
|
+
|
|
14
|
+
const exports: ModuleExports = {
|
|
15
|
+
parse: { symbol: "xt_querystring_parse" },
|
|
16
|
+
decode: { symbol: "xt_querystring_parse" },
|
|
17
|
+
stringify: { symbol: "xt_querystring_stringify" },
|
|
18
|
+
encode: { symbol: "xt_querystring_stringify" },
|
|
19
|
+
escape: { symbol: "xt_querystring_escape" },
|
|
20
|
+
unescape: { symbol: "xt_querystring_unescape" },
|
|
21
|
+
};
|
|
22
|
+
|
|
23
|
+
export const querystringModule: NodeModule = {
|
|
24
|
+
name: "querystring",
|
|
25
|
+
namespace: "querystring",
|
|
26
|
+
runtimeSources: () => [resolveFrom(import.meta.url, "../../../../runtime/ext_node/querystring/querystring.c")],
|
|
27
|
+
builtins: () => ({}),
|
|
28
|
+
exports: () => exports,
|
|
29
|
+
};
|
|
@@ -0,0 +1,48 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Node's `util` module.
|
|
3
|
+
*
|
|
4
|
+
* Exposes the commonly used helpers (`format`, `inspect`, `isDeepStrictEqual`,
|
|
5
|
+
* `inherits`, `deprecate`, `promisify`) and the `isX` type predicates. Both
|
|
6
|
+
* `import { format } from "util"` and `import util from "util"` (namespace
|
|
7
|
+
* calls) are supported; the implementation lives in
|
|
8
|
+
* `runtime/ext_node/util/util.c`.
|
|
9
|
+
*/
|
|
10
|
+
|
|
11
|
+
import type { NodeModule } from "../module.js";
|
|
12
|
+
import { resolveFrom } from "../module.js";
|
|
13
|
+
import type { ModuleExports } from "../../registry.js";
|
|
14
|
+
|
|
15
|
+
const symbols: Record<string, string> = {
|
|
16
|
+
format: "xt_util_format",
|
|
17
|
+
formatWithOptions: "xt_util_format_with_options",
|
|
18
|
+
inspect: "xt_util_inspect",
|
|
19
|
+
isDeepStrictEqual: "xt_util_is_deep_strict_equal",
|
|
20
|
+
inherits: "xt_util_inherits",
|
|
21
|
+
deprecate: "xt_util_deprecate",
|
|
22
|
+
promisify: "xt_util_promisify",
|
|
23
|
+
isString: "xt_util_is_string",
|
|
24
|
+
isNumber: "xt_util_is_number",
|
|
25
|
+
isBoolean: "xt_util_is_boolean",
|
|
26
|
+
isUndefined: "xt_util_is_undefined",
|
|
27
|
+
isNull: "xt_util_is_null",
|
|
28
|
+
isFunction: "xt_util_is_function",
|
|
29
|
+
isArray: "xt_util_is_array",
|
|
30
|
+
isObject: "xt_util_is_object",
|
|
31
|
+
isBuffer: "xt_util_is_buffer",
|
|
32
|
+
isDate: "xt_util_is_date",
|
|
33
|
+
isRegExp: "xt_util_is_regexp",
|
|
34
|
+
isPromise: "xt_util_is_promise",
|
|
35
|
+
isError: "xt_util_is_error",
|
|
36
|
+
};
|
|
37
|
+
|
|
38
|
+
const exports: ModuleExports = Object.fromEntries(
|
|
39
|
+
Object.entries(symbols).map(([name, symbol]) => [name, { symbol }]),
|
|
40
|
+
);
|
|
41
|
+
|
|
42
|
+
export const utilModule: NodeModule = {
|
|
43
|
+
name: "util",
|
|
44
|
+
namespace: "util",
|
|
45
|
+
runtimeSources: () => [resolveFrom(import.meta.url, "../../../../runtime/ext_node/util/util.c")],
|
|
46
|
+
builtins: () => ({}),
|
|
47
|
+
exports: () => exports,
|
|
48
|
+
};
|
|
@@ -28,6 +28,12 @@ export interface ModuleExport {
|
|
|
28
28
|
readonly returnVoid?: boolean;
|
|
29
29
|
readonly namespace?: string;
|
|
30
30
|
readonly method?: string;
|
|
31
|
+
/**
|
|
32
|
+
* Marks a runtime symbol as a constructor callable with `new` (it has the
|
|
33
|
+
* `(i32, i64*)` signature). Lets `import { EventEmitter } from "events"` be
|
|
34
|
+
* used as `new EventEmitter()`.
|
|
35
|
+
*/
|
|
36
|
+
readonly isConstructor?: boolean;
|
|
31
37
|
}
|
|
32
38
|
|
|
33
39
|
export type ModuleExports = Readonly<Record<string, ModuleExport>>;
|
package/src/index.ts
CHANGED
|
@@ -0,0 +1,37 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Identifier scanning (identifiers, keywords and private `#name`s).
|
|
3
|
+
*/
|
|
4
|
+
|
|
5
|
+
import { DiagnosticCode } from "../../diagnostics/diagnostic.js";
|
|
6
|
+
import { KEYWORDS, Token, TokenKind } from "../token.js";
|
|
7
|
+
import { Char, isIdentifierPart } from "../char.js";
|
|
8
|
+
import type { Scanner } from "../scanner.js";
|
|
9
|
+
|
|
10
|
+
export interface IdentifierMethods {
|
|
11
|
+
scanIdentifier(this: Scanner, start: number, precededByLineBreak: boolean): Token;
|
|
12
|
+
}
|
|
13
|
+
|
|
14
|
+
export const identifierMethods: IdentifierMethods = {
|
|
15
|
+
scanIdentifier(this: Scanner, start: number, precededByLineBreak: boolean): Token {
|
|
16
|
+
this.pos++;
|
|
17
|
+
while (this.pos < this.text.length) {
|
|
18
|
+
const ch = this.text.charCodeAt(this.pos);
|
|
19
|
+
if (isIdentifierPart(ch)) {
|
|
20
|
+
this.pos++;
|
|
21
|
+
} else if (ch === Char.Backslash && this.text.charCodeAt(this.pos + 1) === Char.LowerU) {
|
|
22
|
+
this.pos += 2;
|
|
23
|
+
const hex = this.text.slice(this.pos, this.pos + 4);
|
|
24
|
+
this.pos += 4;
|
|
25
|
+
if (!/^[0-9a-fA-F]{4}$/.test(hex)) {
|
|
26
|
+
this.error(DiagnosticCode.InvalidEscape, "Invalid unicode escape in identifier", this.pos - 4, this.pos);
|
|
27
|
+
}
|
|
28
|
+
} else {
|
|
29
|
+
break;
|
|
30
|
+
}
|
|
31
|
+
}
|
|
32
|
+
const text = this.text.slice(start, this.pos);
|
|
33
|
+
const keyword = KEYWORDS.get(text);
|
|
34
|
+
const kind = keyword ?? TokenKind.Identifier;
|
|
35
|
+
return this.makeToken(kind, start, this.pos, text, precededByLineBreak);
|
|
36
|
+
},
|
|
37
|
+
};
|
|
@@ -0,0 +1,84 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Numeric literal scanning: decimals, radix prefixes, exponents and BigInt.
|
|
3
|
+
*/
|
|
4
|
+
|
|
5
|
+
import { DiagnosticCode } from "../../diagnostics/diagnostic.js";
|
|
6
|
+
import { Token, TokenKind } from "../token.js";
|
|
7
|
+
import { Char, isDigit, isHexDigit } from "../char.js";
|
|
8
|
+
import type { Scanner } from "../scanner.js";
|
|
9
|
+
|
|
10
|
+
export interface NumberMethods {
|
|
11
|
+
scanNumber(this: Scanner, start: number, precededByLineBreak: boolean): Token;
|
|
12
|
+
finishNumber(this: Scanner, start: number, precededByLineBreak: boolean, isBigInt: boolean): Token;
|
|
13
|
+
}
|
|
14
|
+
|
|
15
|
+
export const numberMethods: NumberMethods = {
|
|
16
|
+
scanNumber(this: Scanner, start: number, precededByLineBreak: boolean): Token {
|
|
17
|
+
const text = this.text;
|
|
18
|
+
let isBigInt = false;
|
|
19
|
+
// Radix prefixes.
|
|
20
|
+
if (text.charCodeAt(this.pos) === Char.Zero) {
|
|
21
|
+
const next = text.charCodeAt(this.pos + 1);
|
|
22
|
+
if (next === Char.LowerX || next === Char.UpperX) {
|
|
23
|
+
this.pos += 2;
|
|
24
|
+
while (isHexDigit(text.charCodeAt(this.pos)) || text.charCodeAt(this.pos) === Char.Underscore) this.pos++;
|
|
25
|
+
isBigInt = text.charCodeAt(this.pos) === Char.LowerN;
|
|
26
|
+
if (isBigInt) this.pos++;
|
|
27
|
+
return this.finishNumber(start, precededByLineBreak, isBigInt);
|
|
28
|
+
}
|
|
29
|
+
if (next === Char.LowerO || next === Char.UpperO || next === Char.LowerB || next === Char.UpperB) {
|
|
30
|
+
this.pos += 2;
|
|
31
|
+
while (isDigit(text.charCodeAt(this.pos)) || text.charCodeAt(this.pos) === Char.Underscore) this.pos++;
|
|
32
|
+
isBigInt = text.charCodeAt(this.pos) === Char.LowerN;
|
|
33
|
+
if (isBigInt) this.pos++;
|
|
34
|
+
return this.finishNumber(start, precededByLineBreak, isBigInt);
|
|
35
|
+
}
|
|
36
|
+
}
|
|
37
|
+
|
|
38
|
+
while (isDigit(text.charCodeAt(this.pos)) || text.charCodeAt(this.pos) === Char.Underscore) this.pos++;
|
|
39
|
+
if (text.charCodeAt(this.pos) === Char.Dot) {
|
|
40
|
+
this.pos++;
|
|
41
|
+
while (isDigit(text.charCodeAt(this.pos)) || text.charCodeAt(this.pos) === Char.Underscore) this.pos++;
|
|
42
|
+
}
|
|
43
|
+
const e = text.charCodeAt(this.pos);
|
|
44
|
+
if (e === Char.LowerE || e === Char.UpperE) {
|
|
45
|
+
const save = this.pos;
|
|
46
|
+
this.pos++;
|
|
47
|
+
const sign = text.charCodeAt(this.pos);
|
|
48
|
+
if (sign === Char.Plus || sign === Char.Minus) this.pos++;
|
|
49
|
+
if (isDigit(text.charCodeAt(this.pos))) {
|
|
50
|
+
while (isDigit(text.charCodeAt(this.pos)) || text.charCodeAt(this.pos) === Char.Underscore) this.pos++;
|
|
51
|
+
} else {
|
|
52
|
+
// Not an exponent, roll back.
|
|
53
|
+
this.pos = save;
|
|
54
|
+
}
|
|
55
|
+
}
|
|
56
|
+
isBigInt = text.charCodeAt(this.pos) === Char.LowerN;
|
|
57
|
+
if (isBigInt) this.pos++;
|
|
58
|
+
return this.finishNumber(start, precededByLineBreak, isBigInt);
|
|
59
|
+
},
|
|
60
|
+
|
|
61
|
+
finishNumber(this: Scanner, start: number, precededByLineBreak: boolean, isBigInt: boolean): Token {
|
|
62
|
+
let raw = this.text.slice(start, this.pos);
|
|
63
|
+
const cleaned = raw.replace(/_/g, "");
|
|
64
|
+
if (isBigInt) {
|
|
65
|
+
raw = raw.slice(0, -1).replace(/_/g, "");
|
|
66
|
+
const parsed = Number(raw);
|
|
67
|
+
if (parsed !== parsed) {
|
|
68
|
+
this.error(DiagnosticCode.InvalidNumber, `Invalid BigInt literal '${raw}'`, start, this.pos);
|
|
69
|
+
return this.makeToken(TokenKind.BigIntLiteral, start, this.pos, raw, precededByLineBreak, 0);
|
|
70
|
+
}
|
|
71
|
+
return this.makeToken(TokenKind.BigIntLiteral, start, this.pos, raw, precededByLineBreak, parsed);
|
|
72
|
+
}
|
|
73
|
+
let value: number;
|
|
74
|
+
if (/^0[xX]/.test(cleaned)) value = parseInt(cleaned.slice(2), 16);
|
|
75
|
+
else if (/^0[oO]/.test(cleaned)) value = parseInt(cleaned.slice(2), 8);
|
|
76
|
+
else if (/^0[bB]/.test(cleaned)) value = parseInt(cleaned.slice(2), 2);
|
|
77
|
+
else value = Number(cleaned);
|
|
78
|
+
if (Number.isNaN(value)) {
|
|
79
|
+
this.error(DiagnosticCode.InvalidNumber, `Invalid numeric literal '${raw}'`, start, this.pos);
|
|
80
|
+
value = 0;
|
|
81
|
+
}
|
|
82
|
+
return this.makeToken(TokenKind.NumericLiteral, start, this.pos, raw, precededByLineBreak, value);
|
|
83
|
+
},
|
|
84
|
+
};
|
|
@@ -0,0 +1,132 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Punctuation and operator scanning (the operator dispatch table).
|
|
3
|
+
*/
|
|
4
|
+
|
|
5
|
+
import { DiagnosticCode } from "../../diagnostics/diagnostic.js";
|
|
6
|
+
import { Token, TokenKind } from "../token.js";
|
|
7
|
+
import { Char, isDigit } from "../char.js";
|
|
8
|
+
import type { Scanner } from "../scanner.js";
|
|
9
|
+
|
|
10
|
+
export interface PunctuationMethods {
|
|
11
|
+
scanPunctuation(this: Scanner, start: number, precededByLineBreak: boolean): Token;
|
|
12
|
+
}
|
|
13
|
+
|
|
14
|
+
export const punctuationMethods: PunctuationMethods = {
|
|
15
|
+
scanPunctuation(this: Scanner, start: number, precededByLineBreak: boolean): Token {
|
|
16
|
+
const text = this.text;
|
|
17
|
+
const ch = text.charCodeAt(this.pos);
|
|
18
|
+
const next = text.charCodeAt(this.pos + 1);
|
|
19
|
+
const third = text.charCodeAt(this.pos + 2);
|
|
20
|
+
const fourth = text.charCodeAt(this.pos + 3);
|
|
21
|
+
|
|
22
|
+
const emit = (kind: TokenKind, length: number): Token => {
|
|
23
|
+
this.pos += length;
|
|
24
|
+
return this.makeToken(kind, start, this.pos, text.slice(start, this.pos), precededByLineBreak);
|
|
25
|
+
};
|
|
26
|
+
|
|
27
|
+
switch (ch) {
|
|
28
|
+
case Char.OpenBrace:
|
|
29
|
+
return emit(TokenKind.OpenBrace, 1);
|
|
30
|
+
case Char.CloseBrace:
|
|
31
|
+
return emit(TokenKind.CloseBrace, 1);
|
|
32
|
+
case Char.OpenParen:
|
|
33
|
+
return emit(TokenKind.OpenParen, 1);
|
|
34
|
+
case Char.CloseParen:
|
|
35
|
+
return emit(TokenKind.CloseParen, 1);
|
|
36
|
+
case Char.OpenBracket:
|
|
37
|
+
return emit(TokenKind.OpenBracket, 1);
|
|
38
|
+
case Char.CloseBracket:
|
|
39
|
+
return emit(TokenKind.CloseBracket, 1);
|
|
40
|
+
case Char.Semicolon:
|
|
41
|
+
return emit(TokenKind.Semicolon, 1);
|
|
42
|
+
case Char.Comma:
|
|
43
|
+
return emit(TokenKind.Comma, 1);
|
|
44
|
+
case Char.At:
|
|
45
|
+
return emit(TokenKind.At, 1);
|
|
46
|
+
case Char.Tilde:
|
|
47
|
+
return emit(TokenKind.Tilde, 1);
|
|
48
|
+
case Char.Colon:
|
|
49
|
+
return emit(TokenKind.Colon, 1);
|
|
50
|
+
case Char.Dot:
|
|
51
|
+
if (next === Char.Dot && third === Char.Dot) return emit(TokenKind.DotDotDot, 3);
|
|
52
|
+
return emit(TokenKind.Dot, 1);
|
|
53
|
+
case Char.Question:
|
|
54
|
+
if (next === Char.Question) {
|
|
55
|
+
if (third === Char.Equals) return emit(TokenKind.QuestionQuestionEquals, 3);
|
|
56
|
+
return emit(TokenKind.QuestionQuestion, 2);
|
|
57
|
+
}
|
|
58
|
+
if (next === Char.Dot && !isDigit(third)) return emit(TokenKind.QuestionDot, 2);
|
|
59
|
+
return emit(TokenKind.Question, 1);
|
|
60
|
+
case Char.Equals:
|
|
61
|
+
if (next === Char.Equals && third === Char.Equals) return emit(TokenKind.EqualsEqualsEquals, 3);
|
|
62
|
+
if (next === Char.Equals) return emit(TokenKind.EqualsEquals, 2);
|
|
63
|
+
if (next === Char.GreaterThan) return emit(TokenKind.EqualsGreaterThan, 2);
|
|
64
|
+
return emit(TokenKind.Equals, 1);
|
|
65
|
+
case Char.Exclamation:
|
|
66
|
+
if (next === Char.Equals && third === Char.Equals) return emit(TokenKind.ExclamationEqualsEquals, 3);
|
|
67
|
+
if (next === Char.Equals) return emit(TokenKind.ExclamationEquals, 2);
|
|
68
|
+
return emit(TokenKind.Exclamation, 1);
|
|
69
|
+
case Char.Plus:
|
|
70
|
+
if (next === Char.Plus) return emit(TokenKind.PlusPlus, 2);
|
|
71
|
+
if (next === Char.Equals) return emit(TokenKind.PlusEquals, 2);
|
|
72
|
+
return emit(TokenKind.Plus, 1);
|
|
73
|
+
case Char.Minus:
|
|
74
|
+
if (next === Char.Minus) return emit(TokenKind.MinusMinus, 2);
|
|
75
|
+
if (next === Char.Equals) return emit(TokenKind.MinusEquals, 2);
|
|
76
|
+
return emit(TokenKind.Minus, 1);
|
|
77
|
+
case Char.Asterisk:
|
|
78
|
+
if (next === Char.Asterisk) {
|
|
79
|
+
if (third === Char.Equals) return emit(TokenKind.AsteriskAsteriskEquals, 3);
|
|
80
|
+
return emit(TokenKind.AsteriskAsterisk, 2);
|
|
81
|
+
}
|
|
82
|
+
if (next === Char.Equals) return emit(TokenKind.AsteriskEquals, 2);
|
|
83
|
+
return emit(TokenKind.Asterisk, 1);
|
|
84
|
+
case Char.Slash:
|
|
85
|
+
if (next === Char.Equals) return emit(TokenKind.SlashEquals, 2);
|
|
86
|
+
if (this.regexAllowed()) return this.scanRegex(start, precededByLineBreak);
|
|
87
|
+
return emit(TokenKind.Slash, 1);
|
|
88
|
+
case Char.Percent:
|
|
89
|
+
if (next === Char.Equals) return emit(TokenKind.PercentEquals, 2);
|
|
90
|
+
return emit(TokenKind.Percent, 1);
|
|
91
|
+
case Char.LessThan:
|
|
92
|
+
if (next === Char.LessThan) {
|
|
93
|
+
if (third === Char.Equals) return emit(TokenKind.LessThanLessThanEquals, 3);
|
|
94
|
+
return emit(TokenKind.LessThanLessThan, 2);
|
|
95
|
+
}
|
|
96
|
+
if (next === Char.Equals) return emit(TokenKind.LessThanEquals, 2);
|
|
97
|
+
return emit(TokenKind.LessThan, 1);
|
|
98
|
+
case Char.GreaterThan:
|
|
99
|
+
if (next === Char.GreaterThan) {
|
|
100
|
+
if (third === Char.GreaterThan) {
|
|
101
|
+
if (fourth === Char.Equals) return emit(TokenKind.GreaterThanGreaterThanGreaterThanEquals, 4);
|
|
102
|
+
return emit(TokenKind.GreaterThanGreaterThanGreaterThan, 3);
|
|
103
|
+
}
|
|
104
|
+
if (third === Char.Equals) return emit(TokenKind.GreaterThanGreaterThanEquals, 3);
|
|
105
|
+
return emit(TokenKind.GreaterThanGreaterThan, 2);
|
|
106
|
+
}
|
|
107
|
+
if (next === Char.Equals) return emit(TokenKind.GreaterThanEquals, 2);
|
|
108
|
+
return emit(TokenKind.GreaterThan, 1);
|
|
109
|
+
case Char.Ampersand:
|
|
110
|
+
if (next === Char.Ampersand) {
|
|
111
|
+
if (third === Char.Equals) return emit(TokenKind.AmpersandAmpersandEquals, 3);
|
|
112
|
+
return emit(TokenKind.AmpersandAmpersand, 2);
|
|
113
|
+
}
|
|
114
|
+
if (next === Char.Equals) return emit(TokenKind.AmpersandEquals, 2);
|
|
115
|
+
return emit(TokenKind.Ampersand, 1);
|
|
116
|
+
case Char.Bar:
|
|
117
|
+
if (next === Char.Bar) {
|
|
118
|
+
if (third === Char.Equals) return emit(TokenKind.BarBarEquals, 3);
|
|
119
|
+
return emit(TokenKind.BarBar, 2);
|
|
120
|
+
}
|
|
121
|
+
if (next === Char.Equals) return emit(TokenKind.BarEquals, 2);
|
|
122
|
+
return emit(TokenKind.Bar, 1);
|
|
123
|
+
case Char.Caret:
|
|
124
|
+
if (next === Char.Equals) return emit(TokenKind.CaretEquals, 2);
|
|
125
|
+
return emit(TokenKind.Caret, 1);
|
|
126
|
+
default:
|
|
127
|
+
this.pos++;
|
|
128
|
+
this.error(DiagnosticCode.InvalidCharacter, `Invalid character '${text[start]}'`, start, this.pos);
|
|
129
|
+
return this.makeToken(TokenKind.Identifier, start, this.pos, text[start] ?? "", precededByLineBreak);
|
|
130
|
+
}
|
|
131
|
+
},
|
|
132
|
+
};
|
|
@@ -0,0 +1,79 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Regular expression literal scanning and the disambiguation rule that decides
|
|
3
|
+
* whether a `/` is a regex or a division operator.
|
|
4
|
+
*/
|
|
5
|
+
|
|
6
|
+
import { DiagnosticCode } from "../../diagnostics/diagnostic.js";
|
|
7
|
+
import { Token, TokenKind } from "../token.js";
|
|
8
|
+
import { Char, isIdentifierPart } from "../char.js";
|
|
9
|
+
import type { Scanner } from "../scanner.js";
|
|
10
|
+
|
|
11
|
+
export interface RegexMethods {
|
|
12
|
+
regexAllowed(this: Scanner): boolean;
|
|
13
|
+
scanRegex(this: Scanner, start: number, precededByLineBreak: boolean): Token;
|
|
14
|
+
}
|
|
15
|
+
|
|
16
|
+
export const regexMethods: RegexMethods = {
|
|
17
|
+
/**
|
|
18
|
+
* True when a `/` in this position starts a regular expression rather than a
|
|
19
|
+
* division. The decision is made from the previous significant token.
|
|
20
|
+
*/
|
|
21
|
+
regexAllowed(this: Scanner): boolean {
|
|
22
|
+
switch (this._token.kind) {
|
|
23
|
+
case TokenKind.Identifier:
|
|
24
|
+
case TokenKind.PrivateIdentifier:
|
|
25
|
+
case TokenKind.NumericLiteral:
|
|
26
|
+
case TokenKind.BigIntLiteral:
|
|
27
|
+
case TokenKind.StringLiteral:
|
|
28
|
+
case TokenKind.NoSubstitutionTemplateLiteral:
|
|
29
|
+
case TokenKind.TemplateTail:
|
|
30
|
+
case TokenKind.RegularExpressionLiteral:
|
|
31
|
+
case TokenKind.CloseParen:
|
|
32
|
+
case TokenKind.CloseBracket:
|
|
33
|
+
case TokenKind.TrueKeyword:
|
|
34
|
+
case TokenKind.FalseKeyword:
|
|
35
|
+
case TokenKind.NullKeyword:
|
|
36
|
+
case TokenKind.UndefinedKeyword:
|
|
37
|
+
case TokenKind.ThisKeyword:
|
|
38
|
+
case TokenKind.PlusPlus:
|
|
39
|
+
case TokenKind.MinusMinus:
|
|
40
|
+
return false;
|
|
41
|
+
default:
|
|
42
|
+
return true;
|
|
43
|
+
}
|
|
44
|
+
},
|
|
45
|
+
|
|
46
|
+
/** Scan a `/pattern/flags` literal, starting at the leading slash. */
|
|
47
|
+
scanRegex(this: Scanner, start: number, precededByLineBreak: boolean): Token {
|
|
48
|
+
this.pos++; // opening slash
|
|
49
|
+
let inClass = false;
|
|
50
|
+
for (;;) {
|
|
51
|
+
if (this.pos >= this.text.length) {
|
|
52
|
+
this.error(DiagnosticCode.InvalidCharacter, "Unterminated regular expression", start);
|
|
53
|
+
break;
|
|
54
|
+
}
|
|
55
|
+
const ch = this.text.charCodeAt(this.pos);
|
|
56
|
+
if (ch === Char.Backslash) {
|
|
57
|
+
this.pos += 2;
|
|
58
|
+
continue;
|
|
59
|
+
}
|
|
60
|
+
if (ch === Char.LineFeed || ch === Char.CarriageReturn) break;
|
|
61
|
+
if (ch === 91 /* [ */) inClass = true;
|
|
62
|
+
else if (ch === 93 /* ] */) inClass = false;
|
|
63
|
+
else if (ch === Char.Slash && !inClass) {
|
|
64
|
+
this.pos++;
|
|
65
|
+
break;
|
|
66
|
+
}
|
|
67
|
+
this.pos++;
|
|
68
|
+
}
|
|
69
|
+
// Flags.
|
|
70
|
+
while (this.pos < this.text.length && isIdentifierPart(this.text.charCodeAt(this.pos))) this.pos++;
|
|
71
|
+
return this.makeToken(
|
|
72
|
+
TokenKind.RegularExpressionLiteral,
|
|
73
|
+
start,
|
|
74
|
+
this.pos,
|
|
75
|
+
this.text.slice(start, this.pos),
|
|
76
|
+
precededByLineBreak,
|
|
77
|
+
);
|
|
78
|
+
},
|
|
79
|
+
};
|