xbintsc 0.3.3 → 0.3.5
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/dist/src/ast/expressions.d.ts +8 -0
- package/dist/src/binder/binder.js +1 -0
- package/dist/src/binder/binder.js.map +1 -1
- package/dist/src/binder/references.d.ts +1 -1
- package/dist/src/binder/references.js +34 -5
- package/dist/src/binder/references.js.map +1 -1
- package/dist/src/binder/types.d.ts +4 -0
- package/dist/src/binder/types.js.map +1 -1
- package/dist/src/cli/main.js.map +1 -1
- package/dist/src/codegen/generator/calls/access.d.ts +9 -1
- package/dist/src/codegen/generator/calls/access.js +146 -13
- package/dist/src/codegen/generator/calls/access.js.map +1 -1
- package/dist/src/codegen/generator/calls/closures.d.ts +1 -0
- package/dist/src/codegen/generator/calls/closures.js +25 -0
- package/dist/src/codegen/generator/calls/closures.js.map +1 -1
- package/dist/src/codegen/generator/calls/invocation.js +12 -1
- package/dist/src/codegen/generator/calls/invocation.js.map +1 -1
- package/dist/src/codegen/generator/calls/literals.js +12 -4
- package/dist/src/codegen/generator/calls/literals.js.map +1 -1
- package/dist/src/codegen/generator/calls/super.js +4 -7
- package/dist/src/codegen/generator/calls/super.js.map +1 -1
- package/dist/src/codegen/generator/context.d.ts +21 -2
- package/dist/src/codegen/generator/context.js +42 -5
- package/dist/src/codegen/generator/context.js.map +1 -1
- package/dist/src/codegen/generator/expressions/assignment.js +1 -3
- package/dist/src/codegen/generator/expressions/assignment.js.map +1 -1
- package/dist/src/codegen/generator/expressions/primary.d.ts +3 -1
- package/dist/src/codegen/generator/expressions/primary.js +99 -1
- package/dist/src/codegen/generator/expressions/primary.js.map +1 -1
- package/dist/src/codegen/generator/generator.js.map +1 -1
- package/dist/src/codegen/generator/module.js +25 -15
- package/dist/src/codegen/generator/module.js.map +1 -1
- package/dist/src/codegen/generator/state.d.ts +15 -0
- package/dist/src/codegen/generator/state.js +28 -1
- package/dist/src/codegen/generator/state.js.map +1 -1
- package/dist/src/codegen/generator/statements/control-flow.d.ts +3 -1
- package/dist/src/codegen/generator/statements/control-flow.js +85 -0
- package/dist/src/codegen/generator/statements/control-flow.js.map +1 -1
- package/dist/src/codegen/generator/statements/dispatch.js +15 -6
- package/dist/src/codegen/generator/statements/dispatch.js.map +1 -1
- package/dist/src/codegen/generator/statements/loops.d.ts +3 -0
- package/dist/src/codegen/generator/statements/loops.js +25 -11
- package/dist/src/codegen/generator/statements/loops.js.map +1 -1
- package/dist/src/codegen/generator/tables.d.ts +7 -0
- package/dist/src/codegen/generator/tables.js +41 -1
- package/dist/src/codegen/generator/tables.js.map +1 -1
- package/dist/src/driver/compiler.d.ts +1 -1
- package/dist/src/driver/compiler.js +33 -1
- package/dist/src/driver/compiler.js.map +1 -1
- package/dist/src/driver/modules.d.ts +4 -3
- package/dist/src/driver/modules.js +61 -4
- package/dist/src/driver/modules.js.map +1 -1
- package/dist/src/driver/toolchain.js +1 -1
- package/dist/src/driver/toolchain.js.map +1 -1
- package/dist/src/lexer/scanner.js.map +1 -1
- package/dist/src/parser/declarations/classes.js +4 -0
- package/dist/src/parser/declarations/classes.js.map +1 -1
- package/dist/src/parser/declarations/type-members.js.map +1 -1
- package/dist/src/parser/expressions.d.ts +2 -1
- package/dist/src/parser/expressions.js +10 -1
- package/dist/src/parser/expressions.js.map +1 -1
- package/dist/src/parser/helpers.js +2 -2
- package/dist/src/parser/helpers.js.map +1 -1
- package/dist/src/parser/literals.js +79 -6
- package/dist/src/parser/literals.js.map +1 -1
- package/dist/src/parser/modules.js.map +1 -1
- package/dist/src/parser/parser.js +0 -1
- package/dist/src/parser/parser.js.map +1 -1
- package/dist/src/parser/statements.d.ts +1 -0
- package/dist/src/parser/statements.js +13 -1
- package/dist/src/parser/statements.js.map +1 -1
- package/dist/src/parser/types.js +2 -2
- package/dist/src/parser/types.js.map +1 -1
- package/dist/tests/ast/factory.test.d.ts +1 -0
- package/dist/tests/ast/factory.test.js +35 -0
- package/dist/tests/ast/factory.test.js.map +1 -0
- package/dist/tests/ast/visitor.test.d.ts +1 -0
- package/dist/tests/ast/visitor.test.js +53 -0
- package/dist/tests/ast/visitor.test.js.map +1 -0
- package/dist/tests/cli/main.test.js +109 -9
- package/dist/tests/cli/main.test.js.map +1 -1
- package/dist/tests/codegen/closures.test.d.ts +1 -0
- package/dist/tests/codegen/closures.test.js +32 -0
- package/dist/tests/codegen/closures.test.js.map +1 -0
- package/dist/tests/codegen/expressions.test.d.ts +1 -0
- package/dist/tests/codegen/expressions.test.js +149 -0
- package/dist/tests/codegen/expressions.test.js.map +1 -0
- package/dist/tests/codegen/llvm.test.js +14 -0
- package/dist/tests/codegen/llvm.test.js.map +1 -1
- package/dist/tests/codegen/values.test.d.ts +1 -0
- package/dist/tests/codegen/values.test.js +48 -0
- package/dist/tests/codegen/values.test.js.map +1 -0
- package/dist/tests/diagnostics/diagnostic.test.d.ts +1 -0
- package/dist/tests/diagnostics/diagnostic.test.js +117 -0
- package/dist/tests/diagnostics/diagnostic.test.js.map +1 -0
- package/dist/tests/diagnostics/source.test.d.ts +1 -0
- package/dist/tests/diagnostics/source.test.js +58 -0
- package/dist/tests/diagnostics/source.test.js.map +1 -0
- package/dist/tests/driver/modules.test.d.ts +1 -0
- package/dist/tests/driver/modules.test.js +140 -0
- package/dist/tests/driver/modules.test.js.map +1 -0
- package/dist/tests/driver/paths.test.js +17 -1
- package/dist/tests/driver/paths.test.js.map +1 -1
- package/dist/tests/driver/runtime-lib.test.d.ts +1 -0
- package/dist/tests/driver/runtime-lib.test.js +19 -0
- package/dist/tests/driver/runtime-lib.test.js.map +1 -0
- package/dist/tests/driver/toolchain-provider.test.js +91 -0
- package/dist/tests/driver/toolchain-provider.test.js.map +1 -1
- package/dist/tests/driver/toolchain.test.js +11 -1
- package/dist/tests/driver/toolchain.test.js.map +1 -1
- package/dist/tests/e2e/compile-node.test.js +14 -1
- package/dist/tests/e2e/compile-node.test.js.map +1 -1
- package/dist/tests/e2e/compile.test.js +465 -2
- package/dist/tests/e2e/compile.test.js.map +1 -1
- package/dist/tests/e2e/differential.test.d.ts +7 -0
- package/dist/tests/e2e/differential.test.js +581 -0
- package/dist/tests/e2e/differential.test.js.map +1 -0
- package/dist/tests/e2e/harness.d.ts +21 -0
- package/dist/tests/e2e/harness.js +26 -0
- package/dist/tests/e2e/harness.js.map +1 -1
- package/dist/tests/extensions/node.test.d.ts +1 -0
- package/dist/tests/extensions/node.test.js +32 -0
- package/dist/tests/extensions/node.test.js.map +1 -0
- package/dist/tests/lexer/identifiers.test.d.ts +1 -0
- package/dist/tests/lexer/identifiers.test.js +13 -0
- package/dist/tests/lexer/identifiers.test.js.map +1 -0
- package/dist/tests/lexer/numbers.test.d.ts +1 -0
- package/dist/tests/lexer/numbers.test.js +23 -0
- package/dist/tests/lexer/numbers.test.js.map +1 -0
- package/dist/tests/lexer/strings.test.d.ts +1 -0
- package/dist/tests/lexer/strings.test.js +72 -0
- package/dist/tests/lexer/strings.test.js.map +1 -0
- package/dist/tests/parser/declarations.test.d.ts +1 -0
- package/dist/tests/parser/declarations.test.js +70 -0
- package/dist/tests/parser/declarations.test.js.map +1 -0
- package/dist/tests/parser/expressions.test.d.ts +1 -0
- package/dist/tests/parser/expressions.test.js +47 -0
- package/dist/tests/parser/expressions.test.js.map +1 -0
- package/dist/tests/parser/helpers.test.d.ts +1 -0
- package/dist/tests/parser/helpers.test.js +58 -0
- package/dist/tests/parser/helpers.test.js.map +1 -0
- package/dist/tests/parser/literals.test.d.ts +1 -0
- package/dist/tests/parser/literals.test.js +70 -0
- package/dist/tests/parser/literals.test.js.map +1 -0
- package/dist/tests/parser/module-syntax.test.d.ts +1 -0
- package/dist/tests/parser/module-syntax.test.js +91 -0
- package/dist/tests/parser/module-syntax.test.js.map +1 -0
- package/dist/tests/parser/statements.test.d.ts +1 -0
- package/dist/tests/parser/statements.test.js +85 -0
- package/dist/tests/parser/statements.test.js.map +1 -0
- package/dist/tests/parser/type-members.test.d.ts +1 -0
- package/dist/tests/parser/type-members.test.js +86 -0
- package/dist/tests/parser/type-members.test.js.map +1 -0
- package/dist/tests/parser/types.test.d.ts +1 -0
- package/dist/tests/parser/types.test.js +143 -0
- package/dist/tests/parser/types.test.js.map +1 -0
- package/package.json +6 -1
- package/runtime/ext_node/fs/fs_ops.c +36 -1
- package/runtime/rt.h +17 -0
- package/runtime/rt_internal.h +88 -2
- package/runtime/xt_builtins.c +174 -6
- package/runtime/xt_containers.c +234 -42
- package/runtime/xt_generator.c +304 -0
- package/runtime/xt_io.c +170 -30
- package/runtime/xt_promise.c +6 -1
- package/runtime/xt_regex.h +105 -35
- package/runtime/xt_stdlib/dispatch.inc +255 -4
- package/runtime/xt_stdlib/strings.inc +17 -13
- package/runtime/xt_stdlib2/arrays.inc +126 -19
- package/runtime/xt_stdlib2/date.inc +9 -2
- package/runtime/xt_stdlib2/error.inc +162 -12
- package/runtime/xt_stdlib2/helpers.inc +4 -0
- package/runtime/xt_stdlib2/json.inc +19 -6
- package/runtime/xt_stdlib2/number-string-statics.inc +1 -1
- package/runtime/xt_stdlib2/numbers.inc +4 -5
- package/runtime/xt_stdlib2/objects.inc +29 -0
- package/runtime/xt_stdlib2/regexp-match.inc +293 -51
- package/runtime/xt_stdlib2/set.inc +58 -2
- package/runtime/xt_stdlib2/strings.inc +38 -0
- package/runtime/xt_symbol.c +149 -0
- package/runtime/xt_values.c +221 -15
- package/scripts/build-runtime.ts +1 -1
- package/src/ast/expressions.ts +8 -0
- package/src/binder/binder.ts +1 -1
- package/src/binder/references.ts +47 -4
- package/src/binder/types.ts +4 -0
- package/src/cli/main.ts +1 -2
- package/src/codegen/generator/calls/access.ts +158 -13
- package/src/codegen/generator/calls/closures.ts +24 -0
- package/src/codegen/generator/calls/invocation.ts +11 -1
- package/src/codegen/generator/calls/literals.ts +10 -4
- package/src/codegen/generator/calls/super.ts +6 -9
- package/src/codegen/generator/context.ts +44 -7
- package/src/codegen/generator/expressions/assignment.ts +1 -3
- package/src/codegen/generator/expressions/primary.ts +108 -2
- package/src/codegen/generator/generator.ts +0 -1
- package/src/codegen/generator/module.ts +24 -18
- package/src/codegen/generator/state.ts +44 -1
- package/src/codegen/generator/statements/control-flow.ts +86 -0
- package/src/codegen/generator/statements/dispatch.ts +18 -6
- package/src/codegen/generator/statements/loops.ts +29 -11
- package/src/codegen/generator/tables.ts +44 -1
- package/src/driver/compiler.ts +32 -2
- package/src/driver/modules.ts +64 -4
- package/src/driver/toolchain.ts +1 -1
- package/src/lexer/scanner.ts +0 -1
- package/src/parser/declarations/classes.ts +4 -0
- package/src/parser/declarations/type-members.ts +0 -2
- package/src/parser/expressions.ts +13 -1
- package/src/parser/helpers.ts +2 -2
- package/src/parser/literals.ts +82 -7
- package/src/parser/modules.ts +0 -1
- package/src/parser/parser.ts +0 -1
- package/src/parser/statements.ts +14 -0
- package/src/parser/types.ts +2 -2
package/src/driver/modules.ts
CHANGED
|
@@ -6,9 +6,10 @@
|
|
|
6
6
|
* Each module's top-level bindings are renamed to a globally unique name and
|
|
7
7
|
* imported names are rewritten to the (renamed) exported binding.
|
|
8
8
|
*
|
|
9
|
-
* This is intentionally simple: it supports named imports/exports,
|
|
10
|
-
* default` for declarations,
|
|
11
|
-
*
|
|
9
|
+
* This is intentionally simple: it supports named imports/exports, namespace
|
|
10
|
+
* imports, `export default` for declarations, `export ... from` and `export *`.
|
|
11
|
+
* Namespace names are live bindings only at the granularity of the module's
|
|
12
|
+
* final names, and circular graphs are reported as an error.
|
|
12
13
|
*/
|
|
13
14
|
|
|
14
15
|
import { existsSync, readFileSync, statSync } from "node:fs";
|
|
@@ -21,6 +22,8 @@ import {
|
|
|
21
22
|
type Identifier,
|
|
22
23
|
type ImportDeclaration,
|
|
23
24
|
type Node,
|
|
25
|
+
type ObjectLiteralExpression,
|
|
26
|
+
type PropertyAssignment,
|
|
24
27
|
type SourceFileNode,
|
|
25
28
|
type Statement,
|
|
26
29
|
type VariableDeclaration,
|
|
@@ -284,7 +287,10 @@ export function bundleModules(entryPath: string, diagnostics: DiagnosticBag): Bu
|
|
|
284
287
|
}
|
|
285
288
|
}
|
|
286
289
|
|
|
287
|
-
// Phase 3: rewrite imported names and record re-exports.
|
|
290
|
+
// Phase 3: rewrite imported names and record re-exports. Namespace imports
|
|
291
|
+
// are lowered to a synthetic object literal holding every export, built
|
|
292
|
+
// from the dependency's (already renamed) final names.
|
|
293
|
+
const namespaceStatements = new Map<Statement, Statement>();
|
|
288
294
|
for (const record of records) {
|
|
289
295
|
const scope = moduleScope(record);
|
|
290
296
|
if (!scope) continue;
|
|
@@ -307,6 +313,11 @@ export function bundleModules(entryPath: string, diagnostics: DiagnosticBag): Bu
|
|
|
307
313
|
const local = scope.symbols.get(specifier.name.text);
|
|
308
314
|
if (target && local) renameReferences(local, target);
|
|
309
315
|
}
|
|
316
|
+
} else if (bindings && bindings.kind === SyntaxKind.NamespaceImport) {
|
|
317
|
+
const local = scope.symbols.get(bindings.name.text);
|
|
318
|
+
const finalName = `${record.prefix}${bindings.name.text}`;
|
|
319
|
+
if (local) renameReferences(local, finalName);
|
|
320
|
+
namespaceStatements.set(statement, namespaceImportToStatement(statement, finalName, dependency));
|
|
310
321
|
}
|
|
311
322
|
}
|
|
312
323
|
}
|
|
@@ -320,6 +331,9 @@ export function bundleModules(entryPath: string, diagnostics: DiagnosticBag): Bu
|
|
|
320
331
|
// External (extension) imports stay in place for code generation.
|
|
321
332
|
if (isExternalSpecifier((statement as ImportDeclaration).moduleSpecifier.value)) {
|
|
322
333
|
merged.push(statement);
|
|
334
|
+
} else {
|
|
335
|
+
const synthetic = namespaceStatements.get(statement);
|
|
336
|
+
if (synthetic) merged.push(synthetic);
|
|
323
337
|
}
|
|
324
338
|
continue;
|
|
325
339
|
}
|
|
@@ -383,6 +397,52 @@ function collectBindingIdentifiers(name: import("../ast/declarations.js").Bindin
|
|
|
383
397
|
}
|
|
384
398
|
}
|
|
385
399
|
|
|
400
|
+
/** Lower `import * as ns from "./mod"` to `const m0_ns = { ...exports }`. */
|
|
401
|
+
function namespaceImportToStatement(
|
|
402
|
+
statement: Statement,
|
|
403
|
+
finalName: string,
|
|
404
|
+
dependency: ModuleRecord,
|
|
405
|
+
): Statement {
|
|
406
|
+
const properties: PropertyAssignment[] = [];
|
|
407
|
+
for (const [exportedName, target] of dependency.exports) {
|
|
408
|
+
properties.push({
|
|
409
|
+
kind: SyntaxKind.PropertyAssignment,
|
|
410
|
+
name: { kind: SyntaxKind.Identifier, text: exportedName, start: statement.start, end: statement.start },
|
|
411
|
+
initializer: { kind: SyntaxKind.Identifier, text: target, start: statement.start, end: statement.start },
|
|
412
|
+
start: statement.start,
|
|
413
|
+
end: statement.start,
|
|
414
|
+
});
|
|
415
|
+
}
|
|
416
|
+
const initializer: ObjectLiteralExpression = {
|
|
417
|
+
kind: SyntaxKind.ObjectLiteralExpression,
|
|
418
|
+
properties,
|
|
419
|
+
start: statement.start,
|
|
420
|
+
end: statement.end,
|
|
421
|
+
};
|
|
422
|
+
const declaration: VariableDeclaration = {
|
|
423
|
+
kind: SyntaxKind.VariableDeclaration,
|
|
424
|
+
name: { kind: SyntaxKind.Identifier, text: finalName, start: statement.start, end: statement.start },
|
|
425
|
+
exclamation: false,
|
|
426
|
+
initializer,
|
|
427
|
+
start: statement.start,
|
|
428
|
+
end: statement.end,
|
|
429
|
+
};
|
|
430
|
+
const list: VariableDeclarationList = {
|
|
431
|
+
kind: SyntaxKind.VariableDeclarationList,
|
|
432
|
+
declarationKind: "const" as const,
|
|
433
|
+
declarations: [declaration],
|
|
434
|
+
start: statement.start,
|
|
435
|
+
end: statement.end,
|
|
436
|
+
};
|
|
437
|
+
return {
|
|
438
|
+
kind: SyntaxKind.VariableStatement,
|
|
439
|
+
declarationList: list,
|
|
440
|
+
modifiers: [],
|
|
441
|
+
start: statement.start,
|
|
442
|
+
end: statement.end,
|
|
443
|
+
};
|
|
444
|
+
}
|
|
445
|
+
|
|
386
446
|
/** Turn `export default expr` into a synthetic `const` declaration. */
|
|
387
447
|
function exportAssignmentToStatement(record: ModuleRecord, assignment: ExportAssignment): Statement {
|
|
388
448
|
const name: Identifier = {
|
package/src/driver/toolchain.ts
CHANGED
|
@@ -114,7 +114,7 @@ export function compileC(
|
|
|
114
114
|
): void {
|
|
115
115
|
const result = runner.run(
|
|
116
116
|
clang,
|
|
117
|
-
["-O2", "-D_CRT_SECURE_NO_WARNINGS", "-c", sourcePath, "-o", objectPath, `-I${includeDir}`],
|
|
117
|
+
["-O2", "-Wall", "-Wextra", "-D_CRT_SECURE_NO_WARNINGS", "-c", sourcePath, "-o", objectPath, `-I${includeDir}`],
|
|
118
118
|
{ env },
|
|
119
119
|
);
|
|
120
120
|
if (result.status !== 0) throw new ToolchainError(`${clang} ${sourcePath}`, result.status, result.stderr);
|
package/src/lexer/scanner.ts
CHANGED
|
@@ -196,6 +196,10 @@ export const declarationClassMethods: DeclarationClassMethods = {
|
|
|
196
196
|
|
|
197
197
|
parsePropertyName(this: Parser): PropertyName {
|
|
198
198
|
const token = this.token;
|
|
199
|
+
if (token.kind === TokenKind.PrivateIdentifier) {
|
|
200
|
+
this.nextToken();
|
|
201
|
+
return { kind: SyntaxKind.PrivateIdentifier, text: token.text, start: token.start, end: token.end };
|
|
202
|
+
}
|
|
199
203
|
if (token.kind === TokenKind.StringLiteral) {
|
|
200
204
|
this.nextToken();
|
|
201
205
|
return { kind: SyntaxKind.StringLiteral, text: token.text, raw: token.text, value: String(token.value ?? ""), start: token.start, end: token.end };
|
|
@@ -11,13 +11,11 @@ import {
|
|
|
11
11
|
type EnumMember,
|
|
12
12
|
type Expression,
|
|
13
13
|
type Identifier,
|
|
14
|
-
type IndexSignature,
|
|
15
14
|
type InterfaceDeclaration,
|
|
16
15
|
type MethodSignature,
|
|
17
16
|
type Modifier,
|
|
18
17
|
type ModuleDeclaration,
|
|
19
18
|
type Parameter,
|
|
20
|
-
type PropertyName,
|
|
21
19
|
type PropertySignature,
|
|
22
20
|
type StringLiteral,
|
|
23
21
|
type TypeAliasDeclaration,
|
|
@@ -19,6 +19,7 @@ import {
|
|
|
19
19
|
type CallExpression,
|
|
20
20
|
type ConditionalExpression,
|
|
21
21
|
type Expression,
|
|
22
|
+
type Identifier,
|
|
22
23
|
type NewExpression,
|
|
23
24
|
type NumericLiteral,
|
|
24
25
|
type Parameter,
|
|
@@ -54,6 +55,7 @@ export interface ExpressionMethods {
|
|
|
54
55
|
parseCallAndMemberTail(this: Parser, base: Expression): Expression;
|
|
55
56
|
previousEnd(this: Parser, args: readonly Expression[], fallback: number): number;
|
|
56
57
|
parsePropertyAccess(this: Parser, expression: Expression): Expression;
|
|
58
|
+
parseMemberName(this: Parser): Identifier;
|
|
57
59
|
parseArguments(this: Parser): Expression[];
|
|
58
60
|
}
|
|
59
61
|
|
|
@@ -459,10 +461,20 @@ export const expressionMethods: ExpressionMethods = {
|
|
|
459
461
|
const close = this.parseExpected(TokenKind.CloseBracket);
|
|
460
462
|
return { kind: SyntaxKind.ElementAccessExpression, expression, argumentExpression: argument, optional: true, start: expression.start, end: close.end };
|
|
461
463
|
}
|
|
462
|
-
const name = this.
|
|
464
|
+
const name = this.parseMemberName();
|
|
463
465
|
return { kind: SyntaxKind.PropertyAccessExpression, expression, name, optional, start: expression.start, end: name.end };
|
|
464
466
|
},
|
|
465
467
|
|
|
468
|
+
/** Member name after `.`: a normal identifier or a `#private` name. */
|
|
469
|
+
parseMemberName(this: Parser): Identifier {
|
|
470
|
+
const token = this.token;
|
|
471
|
+
if (token.kind === TokenKind.PrivateIdentifier) {
|
|
472
|
+
this.nextToken();
|
|
473
|
+
return { kind: SyntaxKind.Identifier, text: token.text, escaped: true, start: token.start, end: token.end };
|
|
474
|
+
}
|
|
475
|
+
return this.parseIdentifierName();
|
|
476
|
+
},
|
|
477
|
+
|
|
466
478
|
parseArguments(this: Parser): Expression[] {
|
|
467
479
|
this.parseExpected(TokenKind.OpenParen);
|
|
468
480
|
const args: Expression[] = [];
|
package/src/parser/helpers.ts
CHANGED
|
@@ -36,12 +36,12 @@ export function propertyNameText(name: PropertyName): string {
|
|
|
36
36
|
|
|
37
37
|
export function isAssignmentTarget(expr: Expression): boolean {
|
|
38
38
|
switch (expr.kind) {
|
|
39
|
+
// Array/object literals are valid on the left of `=` as destructuring
|
|
40
|
+
// patterns (`[a, b] = xs`, `({ a } = obj)`).
|
|
39
41
|
case SyntaxKind.Identifier:
|
|
40
42
|
case SyntaxKind.PropertyAccessExpression:
|
|
41
43
|
case SyntaxKind.ElementAccessExpression:
|
|
42
44
|
case SyntaxKind.ParenthesizedExpression:
|
|
43
|
-
// Array/object literals are valid on the left of `=` as destructuring
|
|
44
|
-
// patterns (`[a, b] = xs`, `({ a } = obj)`).
|
|
45
45
|
case SyntaxKind.ArrayLiteralExpression:
|
|
46
46
|
case SyntaxKind.ObjectLiteralExpression:
|
|
47
47
|
return true;
|
package/src/parser/literals.ts
CHANGED
|
@@ -33,6 +33,12 @@ export interface LiteralMethods {
|
|
|
33
33
|
parseRegularExpression(this: Parser): RegularExpressionLiteral;
|
|
34
34
|
}
|
|
35
35
|
|
|
36
|
+
/** Strip the delimiters from a scanned template chunk and normalize newlines. */
|
|
37
|
+
function rawTemplateChunk(text: string, leading: number, trailing: number): string {
|
|
38
|
+
const end = Math.max(leading, text.length - trailing);
|
|
39
|
+
return text.slice(leading, end).replace(/\r\n?/g, "\n");
|
|
40
|
+
}
|
|
41
|
+
|
|
36
42
|
export const literalMethods: LiteralMethods = {
|
|
37
43
|
parseArrayLiteral(this: Parser): ArrayLiteralExpression {
|
|
38
44
|
const open = this.parseExpected(TokenKind.OpenBracket);
|
|
@@ -66,6 +72,50 @@ export const literalMethods: LiteralMethods = {
|
|
|
66
72
|
const start = this.nextToken().start;
|
|
67
73
|
const expression = this.parseAssignmentExpression();
|
|
68
74
|
properties.push({ kind: SyntaxKind.SpreadElement, expression, start, end: expression.end });
|
|
75
|
+
} else if (
|
|
76
|
+
(this.at(TokenKind.GetKeyword) || this.at(TokenKind.SetKeyword)) &&
|
|
77
|
+
!this.atAhead(1, TokenKind.OpenParen) &&
|
|
78
|
+
!this.atAhead(1, TokenKind.Colon) &&
|
|
79
|
+
!this.atAhead(1, TokenKind.Comma) &&
|
|
80
|
+
!this.atAhead(1, TokenKind.CloseBrace) &&
|
|
81
|
+
!this.atAhead(1, TokenKind.Equals) &&
|
|
82
|
+
!this.atAhead(1, TokenKind.Question) &&
|
|
83
|
+
!this.atAhead(1, TokenKind.LessThan)
|
|
84
|
+
) {
|
|
85
|
+
// `{ get x() {} }` / `{ set x(v) {} }` object-literal accessors.
|
|
86
|
+
const start = this.token.start;
|
|
87
|
+
const accessorToken = this.nextToken();
|
|
88
|
+
const name = this.parsePropertyName();
|
|
89
|
+
const parameters = this.parseParameters();
|
|
90
|
+
let returnType: TypeNode | undefined;
|
|
91
|
+
if (this.at(TokenKind.Colon)) {
|
|
92
|
+
this.nextToken();
|
|
93
|
+
returnType = this.parseReturnType();
|
|
94
|
+
}
|
|
95
|
+
const body = this.parseBlock();
|
|
96
|
+
const fn: FunctionExpression = { kind: SyntaxKind.FunctionExpression, typeParameters: [], parameters, returnType, body, flags: NodeFlags.None, start, end: body.end };
|
|
97
|
+
properties.push({
|
|
98
|
+
kind: SyntaxKind.PropertyAssignment,
|
|
99
|
+
name,
|
|
100
|
+
initializer: fn,
|
|
101
|
+
accessor: accessorToken.kind === TokenKind.GetKeyword ? "get" : "set",
|
|
102
|
+
start,
|
|
103
|
+
end: body.end,
|
|
104
|
+
});
|
|
105
|
+
} else if (this.at(TokenKind.Asterisk)) {
|
|
106
|
+
// `{ *gen() {} }` object-literal generator method.
|
|
107
|
+
const start = this.nextToken().start;
|
|
108
|
+
const name = this.parsePropertyName();
|
|
109
|
+
const typeParameters = this.at(TokenKind.LessThan) ? this.parseTypeParameters() : [];
|
|
110
|
+
const parameters = this.parseParameters();
|
|
111
|
+
let returnType: TypeNode | undefined;
|
|
112
|
+
if (this.at(TokenKind.Colon)) {
|
|
113
|
+
this.nextToken();
|
|
114
|
+
returnType = this.parseReturnType();
|
|
115
|
+
}
|
|
116
|
+
const body = this.parseBlock();
|
|
117
|
+
const fn: FunctionExpression = { kind: SyntaxKind.FunctionExpression, typeParameters, parameters, returnType, body, flags: NodeFlags.Generator, start, end: body.end };
|
|
118
|
+
properties.push({ kind: SyntaxKind.PropertyAssignment, name, initializer: fn, start, end: body.end });
|
|
69
119
|
} else {
|
|
70
120
|
const start = this.token.start;
|
|
71
121
|
const name = this.parsePropertyName();
|
|
@@ -142,7 +192,14 @@ export const literalMethods: LiteralMethods = {
|
|
|
142
192
|
const startToken = this.token;
|
|
143
193
|
if (startToken.kind === TokenKind.NoSubstitutionTemplateLiteral) {
|
|
144
194
|
this.nextToken();
|
|
145
|
-
return {
|
|
195
|
+
return {
|
|
196
|
+
kind: SyntaxKind.NoSubstitutionTemplateLiteral,
|
|
197
|
+
text: startToken.text,
|
|
198
|
+
value: String(startToken.value ?? ""),
|
|
199
|
+
raw: rawTemplateChunk(startToken.text, 1, 1),
|
|
200
|
+
start: startToken.start,
|
|
201
|
+
end: startToken.end,
|
|
202
|
+
} as unknown as TemplateLiteral;
|
|
146
203
|
}
|
|
147
204
|
if (startToken.kind === TokenKind.Backtick) {
|
|
148
205
|
// Re-scan from the backtick so the scanner produces a TemplateHead.
|
|
@@ -150,14 +207,16 @@ export const literalMethods: LiteralMethods = {
|
|
|
150
207
|
this.tokens = [this.scanner.nextToken()];
|
|
151
208
|
this.index = 0;
|
|
152
209
|
return this.parseTemplateLiteral();
|
|
153
|
-
}
|
|
210
|
+
}
|
|
211
|
+
const head = String(startToken.value ?? "");
|
|
212
|
+
const headRaw = rawTemplateChunk(startToken.text, 1, 2);
|
|
154
213
|
this.nextToken();
|
|
155
214
|
const spans: TemplateSpan[] = [];
|
|
156
215
|
for (;;) {
|
|
157
216
|
const expression = this.parseExpression();
|
|
158
217
|
if (!this.at(TokenKind.CloseBrace)) {
|
|
159
218
|
this.error(DiagnosticCode.UnterminatedTemplate, "Expected '}' to close template substitution");
|
|
160
|
-
return { kind: SyntaxKind.TemplateLiteral, head, spans, start: startToken.start, end: this.token.end };
|
|
219
|
+
return { kind: SyntaxKind.TemplateLiteral, head, raw: headRaw, spans, start: startToken.start, end: this.token.end };
|
|
161
220
|
}
|
|
162
221
|
// The `}` terminates a substitution; re-read it as template text without
|
|
163
222
|
// first scanning the following (template) characters as normal tokens.
|
|
@@ -167,16 +226,32 @@ export const literalMethods: LiteralMethods = {
|
|
|
167
226
|
const literalToken = this.token;
|
|
168
227
|
if (literalToken.kind === TokenKind.NoSubstitutionTemplateLiteral) {
|
|
169
228
|
this.nextToken();
|
|
170
|
-
spans.push({
|
|
171
|
-
|
|
229
|
+
spans.push({
|
|
230
|
+
kind: SyntaxKind.TemplateSpan,
|
|
231
|
+
expression,
|
|
232
|
+
literal: String(literalToken.value ?? ""),
|
|
233
|
+
raw: rawTemplateChunk(literalToken.text, 0, 1),
|
|
234
|
+
isTail: true,
|
|
235
|
+
start: expression.start,
|
|
236
|
+
end: literalToken.end,
|
|
237
|
+
});
|
|
238
|
+
return { kind: SyntaxKind.TemplateLiteral, head, raw: headRaw, spans, start: startToken.start, end: literalToken.end };
|
|
172
239
|
}
|
|
173
240
|
if (literalToken.kind === TokenKind.TemplateHead) {
|
|
174
241
|
this.nextToken();
|
|
175
|
-
spans.push({
|
|
242
|
+
spans.push({
|
|
243
|
+
kind: SyntaxKind.TemplateSpan,
|
|
244
|
+
expression,
|
|
245
|
+
literal: String(literalToken.value ?? ""),
|
|
246
|
+
raw: rawTemplateChunk(literalToken.text, 0, 2),
|
|
247
|
+
isTail: false,
|
|
248
|
+
start: expression.start,
|
|
249
|
+
end: literalToken.end,
|
|
250
|
+
});
|
|
176
251
|
continue;
|
|
177
252
|
}
|
|
178
253
|
this.error(DiagnosticCode.UnterminatedTemplate, "Unterminated template literal", literalToken);
|
|
179
|
-
return { kind: SyntaxKind.TemplateLiteral, head, spans, start: startToken.start, end: literalToken.end };
|
|
254
|
+
return { kind: SyntaxKind.TemplateLiteral, head, raw: headRaw, spans, start: startToken.start, end: literalToken.end };
|
|
180
255
|
}
|
|
181
256
|
},
|
|
182
257
|
|
package/src/parser/modules.ts
CHANGED
package/src/parser/parser.ts
CHANGED
|
@@ -24,7 +24,6 @@ export class Parser extends ParserContext {
|
|
|
24
24
|
const statements: Statement[] = [];
|
|
25
25
|
while (!this.at(TokenKind.EndOfFile)) {
|
|
26
26
|
const before = this.consumed;
|
|
27
|
-
const beforePos = this.scanner.position;
|
|
28
27
|
const statement = this.parseStatement();
|
|
29
28
|
if (statement) statements.push(statement);
|
|
30
29
|
if (this.consumed === before) {
|
package/src/parser/statements.ts
CHANGED
|
@@ -43,6 +43,7 @@ export interface StatementMethods {
|
|
|
43
43
|
parseDoStatement(this: Parser): Statement;
|
|
44
44
|
parseForStatement(this: Parser): ForStatement | ForOfStatement | ForInStatement;
|
|
45
45
|
parseReturnStatement(this: Parser): Statement;
|
|
46
|
+
parseLabeledStatement(this: Parser): Statement;
|
|
46
47
|
parseBreakStatement(this: Parser): Statement;
|
|
47
48
|
parseContinueStatement(this: Parser): Statement;
|
|
48
49
|
parseThrowStatement(this: Parser): Statement;
|
|
@@ -60,6 +61,8 @@ export const statementMethods: StatementMethods = {
|
|
|
60
61
|
const kind = this.token.kind;
|
|
61
62
|
const nextKind = this.lookAhead(1).kind;
|
|
62
63
|
const nextStartsName =
|
|
64
|
+
nextKind === TokenKind.Identifier ||
|
|
65
|
+
nextKind === TokenKind.PrivateIdentifier ||
|
|
63
66
|
isIdentifierNameToken(nextKind) ||
|
|
64
67
|
isKeywordKind(nextKind) ||
|
|
65
68
|
nextKind === TokenKind.OpenBracket ||
|
|
@@ -126,6 +129,9 @@ export const statementMethods: StatementMethods = {
|
|
|
126
129
|
|
|
127
130
|
parseStatement(this: Parser): Statement | undefined {
|
|
128
131
|
const token = this.token;
|
|
132
|
+
if (this.isIdentifierLike(token) && this.atAhead(1, TokenKind.Colon)) {
|
|
133
|
+
return this.parseLabeledStatement();
|
|
134
|
+
}
|
|
129
135
|
switch (token.kind) {
|
|
130
136
|
case TokenKind.OpenBrace:
|
|
131
137
|
return this.parseBlock();
|
|
@@ -381,6 +387,14 @@ export const statementMethods: StatementMethods = {
|
|
|
381
387
|
return { kind: SyntaxKind.ReturnStatement, expression, start, end: expression?.end ?? start + 6 } as Statement;
|
|
382
388
|
},
|
|
383
389
|
|
|
390
|
+
parseLabeledStatement(this: Parser): Statement {
|
|
391
|
+
const label = this.parseIdentifier();
|
|
392
|
+
this.parseExpected(TokenKind.Colon);
|
|
393
|
+
const statement = this.parseStatement();
|
|
394
|
+
const node = statement ?? ({ kind: SyntaxKind.EmptyStatement, start: label.end, end: label.end } as Statement);
|
|
395
|
+
return { kind: SyntaxKind.LabeledStatement, label, statement: node, start: label.start, end: node.end } as Statement;
|
|
396
|
+
},
|
|
397
|
+
|
|
384
398
|
parseBreakStatement(this: Parser): Statement {
|
|
385
399
|
const start = this.parseExpected(TokenKind.BreakKeyword).start;
|
|
386
400
|
let label: Identifier | undefined;
|
package/src/parser/types.ts
CHANGED
|
@@ -330,13 +330,13 @@ export const typeMethods: TypeMethods = {
|
|
|
330
330
|
if (this.atAhead(1, TokenKind.OpenBracket)) {
|
|
331
331
|
cursor = 1;
|
|
332
332
|
if (this.atAhead(2, TokenKind.Identifier)) {
|
|
333
|
-
|
|
333
|
+
const i = 3;
|
|
334
334
|
if (this.lookAhead(i).kind === TokenKind.InKeyword) {
|
|
335
335
|
const open = this.parseExpected(TokenKind.OpenBrace);
|
|
336
336
|
this.parseExpected(TokenKind.OpenBracket);
|
|
337
337
|
const name = this.parseIdentifier();
|
|
338
338
|
this.parseExpected(TokenKind.InKeyword);
|
|
339
|
-
|
|
339
|
+
const constraint = this.parseType();
|
|
340
340
|
this.parseExpected(TokenKind.CloseBracket);
|
|
341
341
|
let questionToken: boolean | "+" | "-" = false;
|
|
342
342
|
if (this.at(TokenKind.Question)) {
|