xbintsc 0.1.6 → 0.1.9
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 +7 -4
- package/dist/src/ast/common.d.ts +33 -0
- package/dist/src/ast/common.js +7 -0
- package/dist/src/ast/common.js.map +1 -0
- package/dist/src/ast/declarations.d.ts +110 -0
- package/dist/src/ast/declarations.js +5 -0
- package/dist/src/ast/declarations.js.map +1 -0
- package/dist/src/ast/expressions.d.ts +219 -0
- package/dist/src/ast/expressions.js +6 -0
- package/dist/src/ast/expressions.js.map +1 -0
- package/dist/src/ast/kinds.d.ts +160 -0
- package/dist/src/ast/kinds.js +171 -0
- package/dist/src/ast/kinds.js.map +1 -0
- package/dist/src/ast/modules.d.ts +61 -0
- package/dist/src/ast/modules.js +5 -0
- package/dist/src/ast/modules.js.map +1 -0
- package/dist/src/ast/nodes.d.ts +11 -839
- package/dist/src/ast/nodes.js +11 -237
- package/dist/src/ast/nodes.js.map +1 -1
- package/dist/src/ast/operators.d.ts +71 -0
- package/dist/src/ast/operators.js +77 -0
- package/dist/src/ast/operators.js.map +1 -0
- package/dist/src/ast/statements.d.ts +120 -0
- package/dist/src/ast/statements.js +5 -0
- package/dist/src/ast/statements.js.map +1 -0
- package/dist/src/ast/types.d.ts +123 -0
- package/dist/src/ast/types.js +6 -0
- package/dist/src/ast/types.js.map +1 -0
- package/dist/src/binder/binder.d.ts +35 -1
- package/dist/src/binder/binder.js +138 -0
- package/dist/src/binder/binder.js.map +1 -1
- package/dist/src/codegen/generator/calls.d.ts +26 -0
- package/dist/src/codegen/generator/calls.js +373 -0
- package/dist/src/codegen/generator/calls.js.map +1 -0
- package/dist/src/codegen/generator/context.d.ts +47 -0
- package/dist/src/codegen/generator/context.js +164 -0
- package/dist/src/codegen/generator/context.js.map +1 -0
- package/dist/src/codegen/generator/expressions.d.ts +25 -0
- package/dist/src/codegen/generator/expressions.js +454 -0
- package/dist/src/codegen/generator/expressions.js.map +1 -0
- package/dist/src/codegen/generator/generator.d.ts +22 -0
- package/dist/src/codegen/generator/generator.js +21 -0
- package/dist/src/codegen/generator/generator.js.map +1 -0
- package/dist/src/codegen/generator/module.d.ts +19 -0
- package/dist/src/codegen/generator/module.js +214 -0
- package/dist/src/codegen/generator/module.js.map +1 -0
- package/dist/src/codegen/generator/state.d.ts +42 -0
- package/dist/src/codegen/generator/state.js +125 -0
- package/dist/src/codegen/generator/state.js.map +1 -0
- package/dist/src/codegen/generator/statements.d.ts +22 -0
- package/dist/src/codegen/generator/statements.js +433 -0
- package/dist/src/codegen/generator/statements.js.map +1 -0
- package/dist/src/codegen/generator/tables.d.ts +23 -0
- package/dist/src/codegen/generator/tables.js +186 -0
- package/dist/src/codegen/generator/tables.js.map +1 -0
- package/dist/src/codegen/llvm.d.ts +4 -13
- package/dist/src/codegen/llvm.js +4 -1537
- package/dist/src/codegen/llvm.js.map +1 -1
- package/dist/src/driver/compiler.js +36 -11
- package/dist/src/driver/compiler.js.map +1 -1
- package/dist/src/driver/modules.d.ts +24 -0
- package/dist/src/driver/modules.js +347 -0
- package/dist/src/driver/modules.js.map +1 -0
- package/dist/src/lexer/char.d.ts +78 -0
- package/dist/src/lexer/char.js +106 -0
- package/dist/src/lexer/char.js.map +1 -0
- package/dist/src/lexer/scanner.js +1 -98
- package/dist/src/lexer/scanner.js.map +1 -1
- package/dist/src/parser/context.d.ts +58 -0
- package/dist/src/parser/context.js +174 -0
- package/dist/src/parser/context.js.map +1 -0
- package/dist/src/parser/declarations.d.ts +26 -0
- package/dist/src/parser/declarations.js +461 -0
- package/dist/src/parser/declarations.js.map +1 -0
- package/dist/src/parser/expressions.d.ts +27 -0
- package/dist/src/parser/expressions.js +440 -0
- package/dist/src/parser/expressions.js.map +1 -0
- package/dist/src/parser/helpers.d.ts +7 -0
- package/dist/src/parser/helpers.js +36 -0
- package/dist/src/parser/helpers.js.map +1 -0
- package/dist/src/parser/literals.d.ts +16 -0
- package/dist/src/parser/literals.js +193 -0
- package/dist/src/parser/literals.js.map +1 -0
- package/dist/src/parser/modules.d.ts +12 -0
- package/dist/src/parser/modules.js +175 -0
- package/dist/src/parser/modules.js.map +1 -0
- package/dist/src/parser/operators.d.ts +12 -0
- package/dist/src/parser/operators.js +172 -0
- package/dist/src/parser/operators.js.map +1 -0
- package/dist/src/parser/parser.d.ts +17 -122
- package/dist/src/parser/parser.js +18 -2311
- package/dist/src/parser/parser.js.map +1 -1
- package/dist/src/parser/speculation.d.ts +6 -0
- package/dist/src/parser/speculation.js +10 -0
- package/dist/src/parser/speculation.js.map +1 -0
- package/dist/src/parser/statements.d.ts +28 -0
- package/dist/src/parser/statements.js +402 -0
- package/dist/src/parser/statements.js.map +1 -0
- package/dist/src/parser/types.d.ts +21 -0
- package/dist/src/parser/types.js +338 -0
- package/dist/src/parser/types.js.map +1 -0
- package/dist/tests/codegen/llvm.test.js +1 -1
- package/dist/tests/codegen/llvm.test.js.map +1 -1
- package/dist/tests/e2e/compile.test.js +86 -0
- package/dist/tests/e2e/compile.test.js.map +1 -1
- package/package.json +1 -1
- package/runtime/rt.h +55 -4
- package/runtime/rt_internal.h +169 -0
- package/runtime/xt_alloc.c +38 -0
- package/runtime/xt_builtins.c +238 -0
- package/runtime/xt_containers.c +312 -0
- package/runtime/xt_io.c +246 -0
- package/runtime/xt_promise.c +292 -0
- package/runtime/xt_stdlib.c +556 -0
- package/runtime/xt_stdlib2.c +1043 -0
- package/runtime/xt_values.c +291 -0
- package/scripts/build-runtime.mjs +8 -1
- package/src/ast/common.ts +210 -0
- package/src/ast/declarations.ts +130 -0
- package/src/ast/expressions.ts +275 -0
- package/src/ast/kinds.ts +176 -0
- package/src/ast/modules.ts +73 -0
- package/src/ast/nodes.ts +11 -1101
- package/src/ast/operators.ts +76 -0
- package/src/ast/statements.ts +148 -0
- package/src/ast/types.ts +173 -0
- package/src/binder/binder.ts +196 -0
- package/src/codegen/generator/calls.ts +433 -0
- package/src/codegen/generator/context.ts +190 -0
- package/src/codegen/generator/expressions.ts +508 -0
- package/src/codegen/generator/generator.ts +35 -0
- package/src/codegen/generator/module.ts +244 -0
- package/src/codegen/generator/state.ts +169 -0
- package/src/codegen/generator/statements.ts +480 -0
- package/src/codegen/generator/tables.ts +206 -0
- package/src/codegen/llvm.ts +4 -1720
- package/src/driver/compiler.ts +45 -12
- package/src/driver/modules.ts +377 -0
- package/src/lexer/char.ts +116 -0
- package/src/lexer/scanner.ts +9 -109
- package/src/parser/context.ts +196 -0
- package/src/parser/declarations.ts +502 -0
- package/src/parser/expressions.ts +468 -0
- package/src/parser/helpers.ts +42 -0
- package/src/parser/literals.ts +207 -0
- package/src/parser/modules.ts +194 -0
- package/src/parser/operators.ts +181 -0
- package/src/parser/parser.ts +35 -2373
- package/src/parser/speculation.ts +9 -0
- package/src/parser/statements.ts +457 -0
- package/src/parser/types.ts +365 -0
- package/runtime/xt_runtime.c +0 -1372
|
@@ -0,0 +1,207 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Literal and "primary aggregate" expression parsing: array/object literals,
|
|
3
|
+
* function/class expressions, template literals and regular expression
|
|
4
|
+
* literals.
|
|
5
|
+
*/
|
|
6
|
+
|
|
7
|
+
import { DiagnosticCode } from "../diagnostics/diagnostic.js";
|
|
8
|
+
import { TokenKind } from "../lexer/token.js";
|
|
9
|
+
import {
|
|
10
|
+
NodeFlags,
|
|
11
|
+
SyntaxKind,
|
|
12
|
+
type ArrayLiteralExpression,
|
|
13
|
+
type ClassExpression,
|
|
14
|
+
type Expression,
|
|
15
|
+
type FunctionExpression,
|
|
16
|
+
type Identifier,
|
|
17
|
+
type ObjectLiteralElementLike,
|
|
18
|
+
type ObjectLiteralExpression,
|
|
19
|
+
type RegularExpressionLiteral,
|
|
20
|
+
type ShorthandPropertyAssignment,
|
|
21
|
+
type TemplateLiteral,
|
|
22
|
+
type TemplateSpan,
|
|
23
|
+
type TypeNode,
|
|
24
|
+
} from "../ast/nodes.js";
|
|
25
|
+
import type { Parser } from "./parser.js";
|
|
26
|
+
|
|
27
|
+
export interface LiteralMethods {
|
|
28
|
+
parseArrayLiteral(this: Parser): ArrayLiteralExpression;
|
|
29
|
+
parseObjectLiteral(this: Parser): ObjectLiteralExpression;
|
|
30
|
+
parseFunctionExpression(this: Parser): FunctionExpression;
|
|
31
|
+
parseClassExpression(this: Parser): ClassExpression;
|
|
32
|
+
parseTemplateLiteral(this: Parser): TemplateLiteral;
|
|
33
|
+
parseRegularExpression(this: Parser): RegularExpressionLiteral;
|
|
34
|
+
}
|
|
35
|
+
|
|
36
|
+
export const literalMethods: LiteralMethods = {
|
|
37
|
+
parseArrayLiteral(this: Parser): ArrayLiteralExpression {
|
|
38
|
+
const open = this.parseExpected(TokenKind.OpenBracket);
|
|
39
|
+
const elements: Expression[] = [];
|
|
40
|
+
while (!this.at(TokenKind.CloseBracket) && !this.at(TokenKind.EndOfFile)) {
|
|
41
|
+
if (this.at(TokenKind.Comma)) {
|
|
42
|
+
// Elision: represent as an undefined literal hole.
|
|
43
|
+
elements.push({ kind: SyntaxKind.UndefinedKeyword, start: this.token.start, end: this.token.start });
|
|
44
|
+
this.nextToken();
|
|
45
|
+
continue;
|
|
46
|
+
}
|
|
47
|
+
if (this.at(TokenKind.DotDotDot)) {
|
|
48
|
+
const start = this.nextToken().start;
|
|
49
|
+
const expression = this.parseAssignmentExpression();
|
|
50
|
+
elements.push({ kind: SyntaxKind.SpreadElement, expression, start, end: expression.end });
|
|
51
|
+
} else {
|
|
52
|
+
elements.push(this.parseAssignmentExpression());
|
|
53
|
+
}
|
|
54
|
+
if (this.at(TokenKind.Comma)) this.nextToken();
|
|
55
|
+
else break;
|
|
56
|
+
}
|
|
57
|
+
const close = this.parseExpected(TokenKind.CloseBracket);
|
|
58
|
+
return { kind: SyntaxKind.ArrayLiteralExpression, elements, start: open.start, end: close.end };
|
|
59
|
+
},
|
|
60
|
+
|
|
61
|
+
parseObjectLiteral(this: Parser): ObjectLiteralExpression {
|
|
62
|
+
const open = this.parseExpected(TokenKind.OpenBrace);
|
|
63
|
+
const properties: ObjectLiteralElementLike[] = [];
|
|
64
|
+
while (!this.at(TokenKind.CloseBrace) && !this.at(TokenKind.EndOfFile)) {
|
|
65
|
+
if (this.at(TokenKind.DotDotDot)) {
|
|
66
|
+
const start = this.nextToken().start;
|
|
67
|
+
const expression = this.parseAssignmentExpression();
|
|
68
|
+
properties.push({ kind: SyntaxKind.SpreadElement, expression, start, end: expression.end });
|
|
69
|
+
} else {
|
|
70
|
+
const start = this.token.start;
|
|
71
|
+
const name = this.parsePropertyName();
|
|
72
|
+
if (this.at(TokenKind.Colon)) {
|
|
73
|
+
this.nextToken();
|
|
74
|
+
const initializer = this.parseAssignmentExpression();
|
|
75
|
+
properties.push({ kind: SyntaxKind.PropertyAssignment, name, initializer, start, end: initializer.end });
|
|
76
|
+
} else if (this.at(TokenKind.OpenParen) || this.at(TokenKind.LessThan)) {
|
|
77
|
+
const typeParameters = this.at(TokenKind.LessThan) ? this.parseTypeParameters() : [];
|
|
78
|
+
const parameters = this.parseParameters();
|
|
79
|
+
let returnType: TypeNode | undefined;
|
|
80
|
+
if (this.at(TokenKind.Colon)) {
|
|
81
|
+
this.nextToken();
|
|
82
|
+
returnType = this.parseReturnType();
|
|
83
|
+
}
|
|
84
|
+
const body = this.parseBlock();
|
|
85
|
+
const fn: FunctionExpression = { kind: SyntaxKind.FunctionExpression, typeParameters, parameters, returnType, body, flags: NodeFlags.None, start, end: body.end };
|
|
86
|
+
properties.push({ kind: SyntaxKind.PropertyAssignment, name, initializer: fn, start, end: body.end });
|
|
87
|
+
} else if (name.kind === SyntaxKind.Identifier) {
|
|
88
|
+
const shorthand: ShorthandPropertyAssignment = { kind: SyntaxKind.ShorthandPropertyAssignment, name, start, end: name.end };
|
|
89
|
+
properties.push(shorthand);
|
|
90
|
+
} else {
|
|
91
|
+
this.error(DiagnosticCode.UnexpectedToken, "Invalid object literal member");
|
|
92
|
+
this.nextToken();
|
|
93
|
+
}
|
|
94
|
+
}
|
|
95
|
+
if (this.at(TokenKind.Comma)) this.nextToken();
|
|
96
|
+
else break;
|
|
97
|
+
}
|
|
98
|
+
const close = this.parseExpected(TokenKind.CloseBrace);
|
|
99
|
+
return { kind: SyntaxKind.ObjectLiteralExpression, properties, start: open.start, end: close.end };
|
|
100
|
+
},
|
|
101
|
+
|
|
102
|
+
parseFunctionExpression(this: Parser): FunctionExpression {
|
|
103
|
+
const start = this.parseExpected(TokenKind.FunctionKeyword).start;
|
|
104
|
+
let flags = NodeFlags.None;
|
|
105
|
+
if (this.at(TokenKind.Asterisk)) {
|
|
106
|
+
this.nextToken();
|
|
107
|
+
flags |= NodeFlags.Generator;
|
|
108
|
+
}
|
|
109
|
+
let name: Identifier | undefined;
|
|
110
|
+
if (this.at(TokenKind.Identifier)) name = this.parseIdentifier();
|
|
111
|
+
const typeParameters = this.parseTypeParameters();
|
|
112
|
+
const parameters = this.parseParameters();
|
|
113
|
+
let returnType: TypeNode | undefined;
|
|
114
|
+
if (this.at(TokenKind.Colon)) {
|
|
115
|
+
this.nextToken();
|
|
116
|
+
returnType = this.parseReturnType();
|
|
117
|
+
}
|
|
118
|
+
const body = this.parseBlock();
|
|
119
|
+
return { kind: SyntaxKind.FunctionExpression, name, typeParameters, parameters, returnType, body, flags, start, end: body.end };
|
|
120
|
+
},
|
|
121
|
+
|
|
122
|
+
parseClassExpression(this: Parser): ClassExpression {
|
|
123
|
+
const start = this.parseExpected(TokenKind.ClassKeyword).start;
|
|
124
|
+
let name: Identifier | undefined;
|
|
125
|
+
if (this.at(TokenKind.Identifier)) name = this.parseIdentifier();
|
|
126
|
+
const typeParameters = this.parseTypeParameters();
|
|
127
|
+
const heritage = this.parseHeritageClauses();
|
|
128
|
+
const members = this.parseClassMembers();
|
|
129
|
+
return { kind: SyntaxKind.ClassExpression, name, typeParameters, heritage, members, start, end: members[members.length - 1]?.end ?? start };
|
|
130
|
+
},
|
|
131
|
+
|
|
132
|
+
parseTemplateLiteral(this: Parser): TemplateLiteral {
|
|
133
|
+
const startToken = this.token;
|
|
134
|
+
if (startToken.kind === TokenKind.NoSubstitutionTemplateLiteral) {
|
|
135
|
+
this.nextToken();
|
|
136
|
+
return { kind: SyntaxKind.NoSubstitutionTemplateLiteral, text: startToken.text, value: String(startToken.value ?? ""), start: startToken.start, end: startToken.end } as unknown as TemplateLiteral;
|
|
137
|
+
}
|
|
138
|
+
if (startToken.kind === TokenKind.Backtick) {
|
|
139
|
+
// Re-scan from the backtick so the scanner produces a TemplateHead.
|
|
140
|
+
this.scanner.seek(startToken.start);
|
|
141
|
+
this.tokens = [this.scanner.nextToken()];
|
|
142
|
+
this.index = 0;
|
|
143
|
+
return this.parseTemplateLiteral();
|
|
144
|
+
} const head = String(startToken.value ?? "");
|
|
145
|
+
this.nextToken();
|
|
146
|
+
const spans: TemplateSpan[] = [];
|
|
147
|
+
for (;;) {
|
|
148
|
+
const expression = this.parseExpression();
|
|
149
|
+
if (!this.at(TokenKind.CloseBrace)) {
|
|
150
|
+
this.error(DiagnosticCode.UnterminatedTemplate, "Expected '}' to close template substitution");
|
|
151
|
+
return { kind: SyntaxKind.TemplateLiteral, head, spans, start: startToken.start, end: this.token.end };
|
|
152
|
+
}
|
|
153
|
+
// The `}` terminates a substitution; re-read it as template text without
|
|
154
|
+
// first scanning the following (template) characters as normal tokens.
|
|
155
|
+
const closeStart = this.token.start;
|
|
156
|
+
this.tokens = [this.scanner.continueTemplate(closeStart)];
|
|
157
|
+
this.index = 0;
|
|
158
|
+
const literalToken = this.token;
|
|
159
|
+
if (literalToken.kind === TokenKind.NoSubstitutionTemplateLiteral) {
|
|
160
|
+
this.nextToken();
|
|
161
|
+
spans.push({ kind: SyntaxKind.TemplateSpan, expression, literal: String(literalToken.value ?? ""), isTail: true, start: expression.start, end: literalToken.end });
|
|
162
|
+
return { kind: SyntaxKind.TemplateLiteral, head, spans, start: startToken.start, end: literalToken.end };
|
|
163
|
+
}
|
|
164
|
+
if (literalToken.kind === TokenKind.TemplateHead) {
|
|
165
|
+
this.nextToken();
|
|
166
|
+
spans.push({ kind: SyntaxKind.TemplateSpan, expression, literal: String(literalToken.value ?? ""), isTail: false, start: expression.start, end: literalToken.end });
|
|
167
|
+
continue;
|
|
168
|
+
}
|
|
169
|
+
this.error(DiagnosticCode.UnterminatedTemplate, "Unterminated template literal", literalToken);
|
|
170
|
+
return { kind: SyntaxKind.TemplateLiteral, head, spans, start: startToken.start, end: literalToken.end };
|
|
171
|
+
}
|
|
172
|
+
},
|
|
173
|
+
|
|
174
|
+
parseRegularExpression(this: Parser): RegularExpressionLiteral {
|
|
175
|
+
const token = this.token;
|
|
176
|
+
const text = this.source.text;
|
|
177
|
+
let i = token.start + 1;
|
|
178
|
+
let inClass = false;
|
|
179
|
+
let pattern = "";
|
|
180
|
+
for (; i < text.length; i++) {
|
|
181
|
+
const ch = text[i]!;
|
|
182
|
+
if (ch === "\\") {
|
|
183
|
+
pattern += ch + (text[i + 1] ?? "");
|
|
184
|
+
i++;
|
|
185
|
+
continue;
|
|
186
|
+
}
|
|
187
|
+
if (ch === "[") inClass = true;
|
|
188
|
+
else if (ch === "]") inClass = false;
|
|
189
|
+
else if (ch === "/" && !inClass) break;
|
|
190
|
+
else if (ch === "\n") break;
|
|
191
|
+
pattern += ch;
|
|
192
|
+
}
|
|
193
|
+
if (text[i] !== "/") {
|
|
194
|
+
this.error(DiagnosticCode.InvalidCharacter, "Unterminated regular expression");
|
|
195
|
+
this.nextToken();
|
|
196
|
+
return { kind: SyntaxKind.RegularExpressionLiteral, text: token.text, pattern: "", flags: "", start: token.start, end: token.end };
|
|
197
|
+
}
|
|
198
|
+
i++;
|
|
199
|
+
const flagsStart = i;
|
|
200
|
+
while (i < text.length && /[a-z]/i.test(text[i]!)) i++;
|
|
201
|
+
const flags = text.slice(flagsStart, i);
|
|
202
|
+
this.scanner.seek(i);
|
|
203
|
+
this.tokens = [this.scanner.nextToken()];
|
|
204
|
+
this.index = 0;
|
|
205
|
+
return { kind: SyntaxKind.RegularExpressionLiteral, text: text.slice(token.start, i), pattern, flags, start: token.start, end: i };
|
|
206
|
+
},
|
|
207
|
+
};
|
|
@@ -0,0 +1,194 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Import and export declaration parsing.
|
|
3
|
+
*/
|
|
4
|
+
|
|
5
|
+
import { TokenKind } from "../lexer/token.js";
|
|
6
|
+
import {
|
|
7
|
+
ModifierKind,
|
|
8
|
+
SyntaxKind,
|
|
9
|
+
type ExportAssignment,
|
|
10
|
+
type ExportDeclaration,
|
|
11
|
+
type ExportSpecifier,
|
|
12
|
+
type Identifier,
|
|
13
|
+
type ImportClause,
|
|
14
|
+
type ImportDeclaration,
|
|
15
|
+
type ImportSpecifier,
|
|
16
|
+
type Modifier,
|
|
17
|
+
type NamedExports,
|
|
18
|
+
type NamedImports,
|
|
19
|
+
type NamespaceImport,
|
|
20
|
+
type Statement,
|
|
21
|
+
type StringLiteral,
|
|
22
|
+
} from "../ast/nodes.js";
|
|
23
|
+
import { propertyNameText } from "./helpers.js";
|
|
24
|
+
import type { Parser } from "./parser.js";
|
|
25
|
+
|
|
26
|
+
export interface ModuleMethods {
|
|
27
|
+
parseImportDeclaration(this: Parser): ImportDeclaration;
|
|
28
|
+
parseNamedImports(this: Parser): NamedImports;
|
|
29
|
+
parseExportDeclaration(this: Parser): Statement;
|
|
30
|
+
parseNamedExports(this: Parser): NamedExports;
|
|
31
|
+
}
|
|
32
|
+
|
|
33
|
+
export const moduleMethods: ModuleMethods = {
|
|
34
|
+
parseImportDeclaration(this: Parser): ImportDeclaration {
|
|
35
|
+
const start = this.parseExpected(TokenKind.ImportKeyword).start;
|
|
36
|
+
let importClause: ImportClause | undefined;
|
|
37
|
+
if (!this.at(TokenKind.StringLiteral)) {
|
|
38
|
+
const clauseStart = this.token.start;
|
|
39
|
+
let isTypeOnly = false;
|
|
40
|
+
if (this.at(TokenKind.TypeKeyword) && !this.lookAhead(1).precededByLineBreak) {
|
|
41
|
+
const next = this.lookAhead(1);
|
|
42
|
+
if (this.isIdentifierLike(next) || next.kind === TokenKind.OpenBrace || next.kind === TokenKind.Asterisk) {
|
|
43
|
+
this.nextToken();
|
|
44
|
+
isTypeOnly = true;
|
|
45
|
+
}
|
|
46
|
+
}
|
|
47
|
+
let name: Identifier | undefined;
|
|
48
|
+
let namedBindings: NamedImports | NamespaceImport | undefined;
|
|
49
|
+
if (this.isIdentifierLike(this.token)) {
|
|
50
|
+
name = this.parseIdentifierName();
|
|
51
|
+
if (this.at(TokenKind.Comma)) this.nextToken();
|
|
52
|
+
}
|
|
53
|
+
if (this.at(TokenKind.Asterisk)) {
|
|
54
|
+
this.nextToken();
|
|
55
|
+
this.parseExpected(TokenKind.AsKeyword);
|
|
56
|
+
const nsName = this.parseIdentifier();
|
|
57
|
+
namedBindings = { kind: SyntaxKind.NamespaceImport, name: nsName, start: nsName.start, end: nsName.end };
|
|
58
|
+
} else if (this.at(TokenKind.OpenBrace)) {
|
|
59
|
+
namedBindings = this.parseNamedImports();
|
|
60
|
+
}
|
|
61
|
+
importClause = { kind: SyntaxKind.ImportClause, name, namedBindings, isTypeOnly, start: clauseStart, end: namedBindings?.end ?? name?.end ?? clauseStart };
|
|
62
|
+
}
|
|
63
|
+
this.parseExpected(TokenKind.FromKeyword);
|
|
64
|
+
const moduleToken = this.parseExpected(TokenKind.StringLiteral);
|
|
65
|
+
const moduleSpecifier = this.stringLiteralFromToken(moduleToken);
|
|
66
|
+
const attributes: { name: string; value: string }[] = [];
|
|
67
|
+
if (this.at(TokenKind.WithKeyword) || (this.at(TokenKind.Identifier) && this.token.text === "assert")) {
|
|
68
|
+
this.nextToken();
|
|
69
|
+
this.parseExpected(TokenKind.OpenBrace);
|
|
70
|
+
while (!this.at(TokenKind.CloseBrace) && !this.at(TokenKind.EndOfFile)) {
|
|
71
|
+
const key = this.parsePropertyName();
|
|
72
|
+
this.parseExpected(TokenKind.Colon);
|
|
73
|
+
const valueToken = this.parseExpected(TokenKind.StringLiteral);
|
|
74
|
+
attributes.push({ name: propertyNameText(key), value: String(valueToken.value ?? "") });
|
|
75
|
+
if (this.at(TokenKind.Comma)) this.nextToken();
|
|
76
|
+
else break;
|
|
77
|
+
}
|
|
78
|
+
this.parseExpected(TokenKind.CloseBrace);
|
|
79
|
+
}
|
|
80
|
+
this.parseSemicolon();
|
|
81
|
+
return { kind: SyntaxKind.ImportDeclaration, importClause, moduleSpecifier, attributes, start, end: moduleSpecifier.end };
|
|
82
|
+
},
|
|
83
|
+
|
|
84
|
+
parseNamedImports(this: Parser): NamedImports {
|
|
85
|
+
const open = this.parseExpected(TokenKind.OpenBrace);
|
|
86
|
+
const elements: ImportSpecifier[] = [];
|
|
87
|
+
while (!this.at(TokenKind.CloseBrace) && !this.at(TokenKind.EndOfFile)) {
|
|
88
|
+
const specStart = this.token.start;
|
|
89
|
+
let isTypeOnly = false;
|
|
90
|
+
if (this.at(TokenKind.TypeKeyword)) {
|
|
91
|
+
this.nextToken();
|
|
92
|
+
isTypeOnly = true;
|
|
93
|
+
}
|
|
94
|
+
const first = this.parseIdentifierName();
|
|
95
|
+
let propertyName: Identifier | undefined;
|
|
96
|
+
let name = first;
|
|
97
|
+
if (this.at(TokenKind.AsKeyword)) {
|
|
98
|
+
this.nextToken();
|
|
99
|
+
propertyName = first;
|
|
100
|
+
name = this.parseIdentifierName();
|
|
101
|
+
}
|
|
102
|
+
elements.push({ kind: SyntaxKind.ImportSpecifier, propertyName, name, isTypeOnly, start: specStart, end: name.end });
|
|
103
|
+
if (this.at(TokenKind.Comma)) this.nextToken();
|
|
104
|
+
else break;
|
|
105
|
+
}
|
|
106
|
+
const close = this.parseExpected(TokenKind.CloseBrace);
|
|
107
|
+
return { kind: SyntaxKind.NamedImports, elements, start: open.start, end: close.end };
|
|
108
|
+
},
|
|
109
|
+
|
|
110
|
+
parseExportDeclaration(this: Parser): Statement {
|
|
111
|
+
const start = this.parseExpected(TokenKind.ExportKeyword).start;
|
|
112
|
+
if (this.at(TokenKind.Equals)) {
|
|
113
|
+
this.nextToken();
|
|
114
|
+
const expression = this.parseExpression();
|
|
115
|
+
this.parseSemicolon();
|
|
116
|
+
const assignment: ExportAssignment = { kind: SyntaxKind.ExportAssignment, isExportEquals: true, expression, start, end: expression.end };
|
|
117
|
+
return assignment;
|
|
118
|
+
}
|
|
119
|
+
if (this.at(TokenKind.DefaultKeyword)) {
|
|
120
|
+
this.nextToken();
|
|
121
|
+
if (this.at(TokenKind.FunctionKeyword) || this.at(TokenKind.ClassKeyword) || this.at(TokenKind.InterfaceKeyword)) {
|
|
122
|
+
return this.parseStatementWithModifiers([{ kind: SyntaxKind.Unknown, modifierKind: ModifierKind.Default, start, end: this.token.start }]);
|
|
123
|
+
}
|
|
124
|
+
const expression = this.parseAssignmentExpression();
|
|
125
|
+
this.parseSemicolon();
|
|
126
|
+
const assignment: ExportAssignment = { kind: SyntaxKind.ExportAssignment, isExportEquals: false, expression, start, end: expression.end };
|
|
127
|
+
return assignment;
|
|
128
|
+
}
|
|
129
|
+
if (this.at(TokenKind.Asterisk)) {
|
|
130
|
+
this.nextToken();
|
|
131
|
+
let nsName: Identifier | undefined;
|
|
132
|
+
if (this.at(TokenKind.AsKeyword)) {
|
|
133
|
+
this.nextToken();
|
|
134
|
+
nsName = this.parseIdentifierName();
|
|
135
|
+
}
|
|
136
|
+
let moduleSpecifier: StringLiteral | undefined;
|
|
137
|
+
if (this.at(TokenKind.FromKeyword)) {
|
|
138
|
+
this.nextToken();
|
|
139
|
+
moduleSpecifier = this.stringLiteralFromToken(this.nextToken());
|
|
140
|
+
}
|
|
141
|
+
this.parseSemicolon();
|
|
142
|
+
const decl: ExportDeclaration = {
|
|
143
|
+
kind: SyntaxKind.ExportDeclaration,
|
|
144
|
+
modifiers: [],
|
|
145
|
+
exportClause: nsName ? { kind: SyntaxKind.NamespaceImport, name: nsName, start: nsName.start, end: nsName.end } : undefined,
|
|
146
|
+
moduleSpecifier,
|
|
147
|
+
isTypeOnly: false,
|
|
148
|
+
start,
|
|
149
|
+
end: moduleSpecifier?.end ?? nsName?.end ?? start,
|
|
150
|
+
};
|
|
151
|
+
return decl;
|
|
152
|
+
}
|
|
153
|
+
if (this.at(TokenKind.OpenBrace)) {
|
|
154
|
+
const namedExports = this.parseNamedExports();
|
|
155
|
+
let moduleSpecifier: StringLiteral | undefined;
|
|
156
|
+
if (this.at(TokenKind.FromKeyword)) {
|
|
157
|
+
this.nextToken();
|
|
158
|
+
if (this.at(TokenKind.StringLiteral)) moduleSpecifier = this.stringLiteralFromToken(this.nextToken());
|
|
159
|
+
}
|
|
160
|
+
this.parseSemicolon();
|
|
161
|
+
const decl: ExportDeclaration = { kind: SyntaxKind.ExportDeclaration, modifiers: [], exportClause: namedExports, moduleSpecifier, isTypeOnly: false, start, end: moduleSpecifier?.end ?? namedExports.end };
|
|
162
|
+
return decl;
|
|
163
|
+
}
|
|
164
|
+
const modifiers = this.tryParseModifiers();
|
|
165
|
+
modifiers.push({ kind: SyntaxKind.Unknown, modifierKind: ModifierKind.Export, start, end: this.token.start });
|
|
166
|
+
return this.parseStatementWithModifiers(modifiers);
|
|
167
|
+
},
|
|
168
|
+
|
|
169
|
+
parseNamedExports(this: Parser): NamedExports {
|
|
170
|
+
const open = this.parseExpected(TokenKind.OpenBrace);
|
|
171
|
+
const elements: ExportSpecifier[] = [];
|
|
172
|
+
while (!this.at(TokenKind.CloseBrace) && !this.at(TokenKind.EndOfFile)) {
|
|
173
|
+
const specStart = this.token.start;
|
|
174
|
+
let isTypeOnly = false;
|
|
175
|
+
if (this.at(TokenKind.TypeKeyword)) {
|
|
176
|
+
this.nextToken();
|
|
177
|
+
isTypeOnly = true;
|
|
178
|
+
}
|
|
179
|
+
const first = this.parseIdentifierName();
|
|
180
|
+
let propertyName: Identifier | undefined;
|
|
181
|
+
let name = first;
|
|
182
|
+
if (this.at(TokenKind.AsKeyword)) {
|
|
183
|
+
this.nextToken();
|
|
184
|
+
propertyName = first;
|
|
185
|
+
name = this.parseIdentifierName();
|
|
186
|
+
}
|
|
187
|
+
elements.push({ kind: SyntaxKind.ExportSpecifier, propertyName, name, isTypeOnly, start: specStart, end: name.end });
|
|
188
|
+
if (this.at(TokenKind.Comma)) this.nextToken();
|
|
189
|
+
else break;
|
|
190
|
+
}
|
|
191
|
+
const close = this.parseExpected(TokenKind.CloseBrace);
|
|
192
|
+
return { kind: SyntaxKind.NamedExports, elements, start: open.start, end: close.end };
|
|
193
|
+
},
|
|
194
|
+
};
|
|
@@ -0,0 +1,181 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Maps lexer token kinds to the AST operator enums and assigns the appropriate
|
|
3
|
+
* precedence to binary operators.
|
|
4
|
+
*/
|
|
5
|
+
|
|
6
|
+
import { TokenKind } from "../lexer/token.js";
|
|
7
|
+
import {
|
|
8
|
+
AssignmentOperator,
|
|
9
|
+
BinaryOperator,
|
|
10
|
+
PrefixUnaryOperator,
|
|
11
|
+
} from "../ast/operators.js";
|
|
12
|
+
|
|
13
|
+
/** `as` / `satisfies` share the relational precedence level. */
|
|
14
|
+
export const AS_PRECEDENCE = 8;
|
|
15
|
+
|
|
16
|
+
export function assignmentOperator(kind: TokenKind): AssignmentOperator | undefined {
|
|
17
|
+
switch (kind) {
|
|
18
|
+
case TokenKind.Equals:
|
|
19
|
+
return AssignmentOperator.Assign;
|
|
20
|
+
case TokenKind.PlusEquals:
|
|
21
|
+
return AssignmentOperator.AddAssign;
|
|
22
|
+
case TokenKind.MinusEquals:
|
|
23
|
+
return AssignmentOperator.SubtractAssign;
|
|
24
|
+
case TokenKind.AsteriskEquals:
|
|
25
|
+
return AssignmentOperator.MultiplyAssign;
|
|
26
|
+
case TokenKind.SlashEquals:
|
|
27
|
+
return AssignmentOperator.DivideAssign;
|
|
28
|
+
case TokenKind.PercentEquals:
|
|
29
|
+
return AssignmentOperator.RemainderAssign;
|
|
30
|
+
case TokenKind.AsteriskAsteriskEquals:
|
|
31
|
+
return AssignmentOperator.ExponentAssign;
|
|
32
|
+
case TokenKind.LessThanLessThanEquals:
|
|
33
|
+
return AssignmentOperator.LessThanLessThanAssign;
|
|
34
|
+
case TokenKind.GreaterThanGreaterThanEquals:
|
|
35
|
+
return AssignmentOperator.GreaterThanGreaterThanAssign;
|
|
36
|
+
case TokenKind.GreaterThanGreaterThanGreaterThanEquals:
|
|
37
|
+
return AssignmentOperator.GreaterThanGreaterThanGreaterThanAssign;
|
|
38
|
+
case TokenKind.AmpersandEquals:
|
|
39
|
+
return AssignmentOperator.AmpersandAssign;
|
|
40
|
+
case TokenKind.BarEquals:
|
|
41
|
+
return AssignmentOperator.BarAssign;
|
|
42
|
+
case TokenKind.CaretEquals:
|
|
43
|
+
return AssignmentOperator.CaretAssign;
|
|
44
|
+
case TokenKind.AmpersandAmpersandEquals:
|
|
45
|
+
return AssignmentOperator.AmpersandAmpersandAssign;
|
|
46
|
+
case TokenKind.BarBarEquals:
|
|
47
|
+
return AssignmentOperator.BarBarAssign;
|
|
48
|
+
case TokenKind.QuestionQuestionEquals:
|
|
49
|
+
return AssignmentOperator.QuestionQuestionAssign;
|
|
50
|
+
default:
|
|
51
|
+
return undefined;
|
|
52
|
+
}
|
|
53
|
+
}
|
|
54
|
+
|
|
55
|
+
export function binaryOperator(kind: TokenKind): BinaryOperator | undefined {
|
|
56
|
+
switch (kind) {
|
|
57
|
+
case TokenKind.Plus:
|
|
58
|
+
return BinaryOperator.Add;
|
|
59
|
+
case TokenKind.Minus:
|
|
60
|
+
return BinaryOperator.Subtract;
|
|
61
|
+
case TokenKind.Asterisk:
|
|
62
|
+
return BinaryOperator.Multiply;
|
|
63
|
+
case TokenKind.Slash:
|
|
64
|
+
return BinaryOperator.Divide;
|
|
65
|
+
case TokenKind.Percent:
|
|
66
|
+
return BinaryOperator.Remainder;
|
|
67
|
+
case TokenKind.AsteriskAsterisk:
|
|
68
|
+
return BinaryOperator.Exponent;
|
|
69
|
+
case TokenKind.LessThan:
|
|
70
|
+
return BinaryOperator.LessThan;
|
|
71
|
+
case TokenKind.LessThanEquals:
|
|
72
|
+
return BinaryOperator.LessThanEquals;
|
|
73
|
+
case TokenKind.GreaterThan:
|
|
74
|
+
return BinaryOperator.GreaterThan;
|
|
75
|
+
case TokenKind.GreaterThanEquals:
|
|
76
|
+
return BinaryOperator.GreaterThanEquals;
|
|
77
|
+
case TokenKind.EqualsEquals:
|
|
78
|
+
return BinaryOperator.EqualsEquals;
|
|
79
|
+
case TokenKind.ExclamationEquals:
|
|
80
|
+
return BinaryOperator.ExclamationEquals;
|
|
81
|
+
case TokenKind.EqualsEqualsEquals:
|
|
82
|
+
return BinaryOperator.EqualsEqualsEquals;
|
|
83
|
+
case TokenKind.ExclamationEqualsEquals:
|
|
84
|
+
return BinaryOperator.ExclamationEqualsEquals;
|
|
85
|
+
case TokenKind.AmpersandAmpersand:
|
|
86
|
+
return BinaryOperator.AmpersandAmpersand;
|
|
87
|
+
case TokenKind.BarBar:
|
|
88
|
+
return BinaryOperator.BarBar;
|
|
89
|
+
case TokenKind.QuestionQuestion:
|
|
90
|
+
return BinaryOperator.QuestionQuestion;
|
|
91
|
+
case TokenKind.Ampersand:
|
|
92
|
+
return BinaryOperator.Ampersand;
|
|
93
|
+
case TokenKind.Bar:
|
|
94
|
+
return BinaryOperator.Bar;
|
|
95
|
+
case TokenKind.Caret:
|
|
96
|
+
return BinaryOperator.Caret;
|
|
97
|
+
case TokenKind.LessThanLessThan:
|
|
98
|
+
return BinaryOperator.LessThanLessThan;
|
|
99
|
+
case TokenKind.GreaterThanGreaterThan:
|
|
100
|
+
return BinaryOperator.GreaterThanGreaterThan;
|
|
101
|
+
case TokenKind.GreaterThanGreaterThanGreaterThan:
|
|
102
|
+
return BinaryOperator.GreaterThanGreaterThanGreaterThan;
|
|
103
|
+
case TokenKind.InKeyword:
|
|
104
|
+
return BinaryOperator.In;
|
|
105
|
+
case TokenKind.InstanceOfKeyword:
|
|
106
|
+
return BinaryOperator.InstanceOf;
|
|
107
|
+
default:
|
|
108
|
+
return undefined;
|
|
109
|
+
}
|
|
110
|
+
}
|
|
111
|
+
|
|
112
|
+
export function binaryPrecedence(op: BinaryOperator): number {
|
|
113
|
+
switch (op) {
|
|
114
|
+
case BinaryOperator.QuestionQuestion:
|
|
115
|
+
return 1;
|
|
116
|
+
case BinaryOperator.BarBar:
|
|
117
|
+
return 2;
|
|
118
|
+
case BinaryOperator.AmpersandAmpersand:
|
|
119
|
+
return 3;
|
|
120
|
+
case BinaryOperator.Bar:
|
|
121
|
+
return 4;
|
|
122
|
+
case BinaryOperator.Caret:
|
|
123
|
+
return 5;
|
|
124
|
+
case BinaryOperator.Ampersand:
|
|
125
|
+
return 6;
|
|
126
|
+
case BinaryOperator.EqualsEquals:
|
|
127
|
+
case BinaryOperator.ExclamationEquals:
|
|
128
|
+
case BinaryOperator.EqualsEqualsEquals:
|
|
129
|
+
case BinaryOperator.ExclamationEqualsEquals:
|
|
130
|
+
return 7;
|
|
131
|
+
case BinaryOperator.LessThan:
|
|
132
|
+
case BinaryOperator.LessThanEquals:
|
|
133
|
+
case BinaryOperator.GreaterThan:
|
|
134
|
+
case BinaryOperator.GreaterThanEquals:
|
|
135
|
+
case BinaryOperator.In:
|
|
136
|
+
case BinaryOperator.InstanceOf:
|
|
137
|
+
return 8;
|
|
138
|
+
case BinaryOperator.LessThanLessThan:
|
|
139
|
+
case BinaryOperator.GreaterThanGreaterThan:
|
|
140
|
+
case BinaryOperator.GreaterThanGreaterThanGreaterThan:
|
|
141
|
+
return 9;
|
|
142
|
+
case BinaryOperator.Add:
|
|
143
|
+
case BinaryOperator.Subtract:
|
|
144
|
+
return 10;
|
|
145
|
+
case BinaryOperator.Multiply:
|
|
146
|
+
case BinaryOperator.Divide:
|
|
147
|
+
case BinaryOperator.Remainder:
|
|
148
|
+
return 11;
|
|
149
|
+
case BinaryOperator.Exponent:
|
|
150
|
+
return 12;
|
|
151
|
+
default:
|
|
152
|
+
return -1;
|
|
153
|
+
}
|
|
154
|
+
}
|
|
155
|
+
|
|
156
|
+
export function prefixUnaryOperator(kind: TokenKind): PrefixUnaryOperator | undefined {
|
|
157
|
+
switch (kind) {
|
|
158
|
+
case TokenKind.Plus:
|
|
159
|
+
return PrefixUnaryOperator.Plus;
|
|
160
|
+
case TokenKind.Minus:
|
|
161
|
+
return PrefixUnaryOperator.Minus;
|
|
162
|
+
case TokenKind.Tilde:
|
|
163
|
+
return PrefixUnaryOperator.Tilde;
|
|
164
|
+
case TokenKind.Exclamation:
|
|
165
|
+
return PrefixUnaryOperator.Exclamation;
|
|
166
|
+
case TokenKind.TypeOfKeyword:
|
|
167
|
+
return PrefixUnaryOperator.TypeOf;
|
|
168
|
+
case TokenKind.VoidKeyword:
|
|
169
|
+
return PrefixUnaryOperator.Void;
|
|
170
|
+
case TokenKind.DeleteKeyword:
|
|
171
|
+
return PrefixUnaryOperator.Delete;
|
|
172
|
+
case TokenKind.PlusPlus:
|
|
173
|
+
return PrefixUnaryOperator.PlusPlus;
|
|
174
|
+
case TokenKind.MinusMinus:
|
|
175
|
+
return PrefixUnaryOperator.MinusMinus;
|
|
176
|
+
case TokenKind.AwaitKeyword:
|
|
177
|
+
return PrefixUnaryOperator.Await;
|
|
178
|
+
default:
|
|
179
|
+
return undefined;
|
|
180
|
+
}
|
|
181
|
+
}
|