xbintsc 0.2.4 → 0.2.6
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/declarations.d.ts +20 -1
- package/dist/src/ast/expressions.d.ts +6 -2
- package/dist/src/ast/kinds.d.ts +6 -1
- package/dist/src/ast/kinds.js +5 -0
- package/dist/src/ast/kinds.js.map +1 -1
- package/dist/src/ast/statements.d.ts +2 -1
- package/dist/src/binder/binder.js +73 -9
- package/dist/src/binder/binder.js.map +1 -1
- package/dist/src/cli/main.js +2 -4
- package/dist/src/cli/main.js.map +1 -1
- package/dist/src/codegen/generator/calls.d.ts +1 -1
- package/dist/src/codegen/generator/calls.js +57 -14
- 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/expressions.js +39 -3
- package/dist/src/codegen/generator/expressions.js.map +1 -1
- package/dist/src/codegen/generator/module.js +73 -7
- package/dist/src/codegen/generator/module.js.map +1 -1
- package/dist/src/codegen/generator/state.js +16 -0
- package/dist/src/codegen/generator/state.js.map +1 -1
- package/dist/src/codegen/generator/statements.d.ts +4 -1
- package/dist/src/codegen/generator/statements.js +141 -10
- package/dist/src/codegen/generator/statements.js.map +1 -1
- package/dist/src/codegen/generator/tables.d.ts +3 -0
- package/dist/src/codegen/generator/tables.js +13 -0
- package/dist/src/codegen/generator/tables.js.map +1 -1
- package/dist/src/codegen/values.d.ts +18 -11
- package/dist/src/codegen/values.js +92 -15
- package/dist/src/codegen/values.js.map +1 -1
- package/dist/src/diagnostics/source.d.ts +1 -1
- package/dist/src/diagnostics/source.js +12 -7
- package/dist/src/diagnostics/source.js.map +1 -1
- package/dist/src/driver/compiler.d.ts +5 -0
- package/dist/src/driver/compiler.js +42 -2
- package/dist/src/driver/compiler.js.map +1 -1
- package/dist/src/driver/modules.js +29 -4
- package/dist/src/driver/modules.js.map +1 -1
- package/dist/src/extensions/node/child_process/index.d.ts +7 -0
- package/dist/src/extensions/node/child_process/index.js +19 -0
- package/dist/src/extensions/node/child_process/index.js.map +1 -0
- package/dist/src/extensions/node/crypto/index.d.ts +6 -0
- package/dist/src/extensions/node/crypto/index.js +18 -0
- package/dist/src/extensions/node/crypto/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/module.d.ts +9 -1
- package/dist/src/extensions/node/module.js +14 -1
- package/dist/src/extensions/node/module.js.map +1 -1
- package/dist/src/extensions/node/url/index.d.ts +7 -0
- package/dist/src/extensions/node/url/index.js +21 -0
- package/dist/src/extensions/node/url/index.js.map +1 -0
- package/dist/src/lexer/scanner.js +4 -5
- package/dist/src/lexer/scanner.js.map +1 -1
- package/dist/src/lexer/token.d.ts +10 -0
- package/dist/src/lexer/token.js +69 -0
- package/dist/src/lexer/token.js.map +1 -1
- package/dist/src/parser/context.js +4 -16
- package/dist/src/parser/context.js.map +1 -1
- package/dist/src/parser/declarations.d.ts +2 -0
- package/dist/src/parser/declarations.js +146 -33
- package/dist/src/parser/declarations.js.map +1 -1
- package/dist/src/parser/expressions.js +20 -3
- package/dist/src/parser/expressions.js.map +1 -1
- package/dist/src/parser/helpers.js +2 -0
- package/dist/src/parser/helpers.js.map +1 -1
- package/dist/src/parser/modules.js +7 -2
- package/dist/src/parser/modules.js.map +1 -1
- package/dist/src/parser/statements.js +28 -3
- package/dist/src/parser/statements.js.map +1 -1
- package/dist/src/parser/types.js +5 -0
- package/dist/src/parser/types.js.map +1 -1
- package/dist/tests/codegen/llvm.test.js +16 -0
- package/dist/tests/codegen/llvm.test.js.map +1 -1
- package/dist/tests/driver/compiler.test.js +13 -1
- package/dist/tests/driver/compiler.test.js.map +1 -1
- package/dist/tests/e2e/compile.test.js +57 -0
- package/dist/tests/e2e/compile.test.js.map +1 -1
- package/dist/tests/parser/parser.test.js +53 -0
- package/dist/tests/parser/parser.test.js.map +1 -1
- package/package.json +1 -1
- package/runtime/ext_node/child_process/child_process.c +213 -0
- package/runtime/ext_node/crypto/crypto.c +177 -0
- package/runtime/ext_node/process/process.c +37 -3
- package/runtime/ext_node/url/url.c +85 -0
- package/runtime/rt.h +20 -0
- package/runtime/rt_internal.h +11 -0
- package/runtime/xt_builtins.c +23 -0
- package/runtime/xt_containers.c +136 -10
- package/runtime/xt_io.c +53 -0
- package/runtime/xt_regex.h +16 -6
- package/runtime/xt_stdlib.c +11 -2
- package/runtime/xt_stdlib2.c +250 -13
- package/runtime/xt_values.c +2 -1
- package/src/ast/declarations.ts +26 -1
- package/src/ast/expressions.ts +7 -2
- package/src/ast/kinds.ts +5 -0
- package/src/ast/statements.ts +2 -1
- package/src/binder/binder.ts +75 -9
- package/src/cli/main.ts +2 -3
- package/src/codegen/generator/calls.ts +59 -16
- package/src/codegen/generator/context.ts +1 -1
- package/src/codegen/generator/expressions.ts +39 -3
- package/src/codegen/generator/module.ts +79 -7
- package/src/codegen/generator/state.ts +16 -0
- package/src/codegen/generator/statements.ts +139 -11
- package/src/codegen/generator/tables.ts +14 -0
- package/src/codegen/values.ts +85 -16
- package/src/diagnostics/source.ts +12 -7
- package/src/driver/compiler.ts +44 -2
- package/src/driver/modules.ts +28 -3
- package/src/extensions/node/child_process/index.ts +24 -0
- package/src/extensions/node/crypto/index.ts +23 -0
- package/src/extensions/node/index.ts +6 -0
- package/src/extensions/node/module.ts +13 -1
- package/src/extensions/node/url/index.ts +26 -0
- package/src/lexer/scanner.ts +4 -4
- package/src/lexer/token.ts +73 -0
- package/src/parser/context.ts +4 -15
- package/src/parser/declarations.ts +140 -29
- package/src/parser/expressions.ts +20 -4
- package/src/parser/helpers.ts +2 -0
- package/src/parser/modules.ts +7 -2
- package/src/parser/statements.ts +27 -3
- package/src/parser/types.ts +5 -0
package/src/lexer/scanner.ts
CHANGED
|
@@ -240,12 +240,12 @@ export class Scanner {
|
|
|
240
240
|
const cleaned = raw.replace(/_/g, "");
|
|
241
241
|
if (isBigInt) {
|
|
242
242
|
raw = raw.slice(0, -1).replace(/_/g, "");
|
|
243
|
-
|
|
244
|
-
|
|
245
|
-
} catch {
|
|
243
|
+
const parsed = Number(raw);
|
|
244
|
+
if (parsed !== parsed) {
|
|
246
245
|
this.error(DiagnosticCode.InvalidNumber, `Invalid BigInt literal '${raw}'`, start, this.pos);
|
|
247
|
-
return this.makeToken(TokenKind.BigIntLiteral, start, this.pos, raw, precededByLineBreak,
|
|
246
|
+
return this.makeToken(TokenKind.BigIntLiteral, start, this.pos, raw, precededByLineBreak, 0);
|
|
248
247
|
}
|
|
248
|
+
return this.makeToken(TokenKind.BigIntLiteral, start, this.pos, raw, precededByLineBreak, parsed);
|
|
249
249
|
}
|
|
250
250
|
let value: number;
|
|
251
251
|
if (/^0[xX]/.test(cleaned)) value = parseInt(cleaned.slice(2), 16);
|
package/src/lexer/token.ts
CHANGED
|
@@ -264,3 +264,76 @@ export const CONTEXTUAL_KEYWORDS: ReadonlySet<TokenKind> = new Set([
|
|
|
264
264
|
export function isOfKeyword(token: Token): boolean {
|
|
265
265
|
return token.kind === TokenKind.Identifier && token.text === "of";
|
|
266
266
|
}
|
|
267
|
+
|
|
268
|
+
/** Every keyword token kind, derived from the scanner's keyword table. */
|
|
269
|
+
export const KEYWORD_KINDS: ReadonlySet<TokenKind> = new Set(KEYWORDS.values());
|
|
270
|
+
|
|
271
|
+
/**
|
|
272
|
+
* True for the hard/contextual keywords the scanner emits. Property names and
|
|
273
|
+
* member access allow any of these (`obj.default`, `{ type: 1 }`), so the
|
|
274
|
+
* parser consults this instead of maintaining a hand-written allow list.
|
|
275
|
+
*/
|
|
276
|
+
export function isKeywordKind(kind: TokenKind): boolean {
|
|
277
|
+
return KEYWORD_KINDS.has(kind);
|
|
278
|
+
}
|
|
279
|
+
|
|
280
|
+
/**
|
|
281
|
+
* Keywords that can never be used as a plain binding/identifier. Everything
|
|
282
|
+
* else the scanner recognizes is a TypeScript contextual keyword (`type`,
|
|
283
|
+
* `async`, `module`, `namespace`, `readonly`, …) and may legally name a
|
|
284
|
+
* variable, parameter or property.
|
|
285
|
+
*/
|
|
286
|
+
const RESERVED_KEYWORDS: ReadonlySet<TokenKind> = new Set([
|
|
287
|
+
TokenKind.BreakKeyword,
|
|
288
|
+
TokenKind.CaseKeyword,
|
|
289
|
+
TokenKind.CatchKeyword,
|
|
290
|
+
TokenKind.ClassKeyword,
|
|
291
|
+
TokenKind.ConstKeyword,
|
|
292
|
+
TokenKind.ContinueKeyword,
|
|
293
|
+
TokenKind.DebuggerKeyword,
|
|
294
|
+
TokenKind.DefaultKeyword,
|
|
295
|
+
TokenKind.DeleteKeyword,
|
|
296
|
+
TokenKind.DoKeyword,
|
|
297
|
+
TokenKind.ElseKeyword,
|
|
298
|
+
TokenKind.EnumKeyword,
|
|
299
|
+
TokenKind.ExportKeyword,
|
|
300
|
+
TokenKind.ExtendsKeyword,
|
|
301
|
+
TokenKind.FalseKeyword,
|
|
302
|
+
TokenKind.FinallyKeyword,
|
|
303
|
+
TokenKind.ForKeyword,
|
|
304
|
+
TokenKind.FunctionKeyword,
|
|
305
|
+
TokenKind.IfKeyword,
|
|
306
|
+
TokenKind.ImportKeyword,
|
|
307
|
+
TokenKind.InKeyword,
|
|
308
|
+
TokenKind.InstanceOfKeyword,
|
|
309
|
+
TokenKind.NewKeyword,
|
|
310
|
+
TokenKind.NullKeyword,
|
|
311
|
+
TokenKind.ReturnKeyword,
|
|
312
|
+
TokenKind.SuperKeyword,
|
|
313
|
+
TokenKind.SwitchKeyword,
|
|
314
|
+
TokenKind.ThisKeyword,
|
|
315
|
+
TokenKind.ThrowKeyword,
|
|
316
|
+
TokenKind.TrueKeyword,
|
|
317
|
+
TokenKind.TryKeyword,
|
|
318
|
+
TokenKind.TypeOfKeyword,
|
|
319
|
+
TokenKind.VarKeyword,
|
|
320
|
+
TokenKind.VoidKeyword,
|
|
321
|
+
TokenKind.WhileKeyword,
|
|
322
|
+
TokenKind.WithKeyword,
|
|
323
|
+
// Strict-mode / module reserved words.
|
|
324
|
+
TokenKind.LetKeyword,
|
|
325
|
+
TokenKind.StaticKeyword,
|
|
326
|
+
TokenKind.YieldKeyword,
|
|
327
|
+
TokenKind.AwaitKeyword,
|
|
328
|
+
TokenKind.ImplementsKeyword,
|
|
329
|
+
TokenKind.InterfaceKeyword,
|
|
330
|
+
TokenKind.PackageKeyword,
|
|
331
|
+
TokenKind.PrivateKeyword,
|
|
332
|
+
TokenKind.ProtectedKeyword,
|
|
333
|
+
TokenKind.PublicKeyword,
|
|
334
|
+
]);
|
|
335
|
+
|
|
336
|
+
/** True when the scanner token may be used as an identifier/binding name. */
|
|
337
|
+
export function isIdentifierNameToken(kind: TokenKind): boolean {
|
|
338
|
+
return kind === TokenKind.Identifier || (isKeywordKind(kind) && !RESERVED_KEYWORDS.has(kind));
|
|
339
|
+
}
|
package/src/parser/context.ts
CHANGED
|
@@ -10,7 +10,7 @@
|
|
|
10
10
|
import { DiagnosticBag, DiagnosticCode } from "../diagnostics/diagnostic.js";
|
|
11
11
|
import type { SourceFile } from "../diagnostics/source.js";
|
|
12
12
|
import { Scanner } from "../lexer/scanner.js";
|
|
13
|
-
import { Token, TokenKind } from "../lexer/token.js";
|
|
13
|
+
import { isIdentifierNameToken, isKeywordKind, Token, TokenKind } from "../lexer/token.js";
|
|
14
14
|
import { SyntaxKind } from "../ast/kinds.js";
|
|
15
15
|
import type { Identifier, StringLiteral } from "../ast/nodes.js";
|
|
16
16
|
import { SpeculationError } from "./speculation.js";
|
|
@@ -121,24 +121,13 @@ export class ParserContext {
|
|
|
121
121
|
}
|
|
122
122
|
|
|
123
123
|
isIdentifierLike(token: Token): boolean {
|
|
124
|
-
|
|
125
|
-
switch (token.kind) {
|
|
126
|
-
case TokenKind.AsKeyword:
|
|
127
|
-
case TokenKind.SatisfiesKeyword:
|
|
128
|
-
case TokenKind.FromKeyword:
|
|
129
|
-
case TokenKind.TypeKeyword:
|
|
130
|
-
case TokenKind.GetKeyword:
|
|
131
|
-
case TokenKind.SetKeyword:
|
|
132
|
-
case TokenKind.AsyncKeyword:
|
|
133
|
-
return true;
|
|
134
|
-
default:
|
|
135
|
-
return false;
|
|
136
|
-
}
|
|
124
|
+
return isIdentifierNameToken(token.kind);
|
|
137
125
|
}
|
|
138
126
|
|
|
139
127
|
parseIdentifier(allowKeywords = false): Identifier {
|
|
140
128
|
const token = this.token;
|
|
141
|
-
|
|
129
|
+
const ok = allowKeywords ? isKeywordKind(token.kind) : isIdentifierNameToken(token.kind);
|
|
130
|
+
if (token.kind === TokenKind.Identifier || ok) {
|
|
142
131
|
this.nextToken();
|
|
143
132
|
return { kind: SyntaxKind.Identifier, text: token.text, start: token.start, end: token.end };
|
|
144
133
|
}
|
|
@@ -37,6 +37,7 @@ import {
|
|
|
37
37
|
type TypeParameterDeclaration,
|
|
38
38
|
} from "../ast/nodes.js";
|
|
39
39
|
import { expressionToPropertyName } from "./helpers.js";
|
|
40
|
+
import { SpeculationError } from "./speculation.js";
|
|
40
41
|
import type { Parser } from "./parser.js";
|
|
41
42
|
|
|
42
43
|
export interface DeclarationMethods {
|
|
@@ -44,6 +45,8 @@ export interface DeclarationMethods {
|
|
|
44
45
|
parseTypeParameters(this: Parser): TypeParameterDeclaration[];
|
|
45
46
|
parseGreaterThan(this: Parser): void;
|
|
46
47
|
parseParameters(this: Parser): Parameter[];
|
|
48
|
+
parseBindingName(this: Parser): import("../ast/declarations.js").BindingName;
|
|
49
|
+
parseBindingElement(this: Parser, allowPropertyName: boolean): import("../ast/declarations.js").BindingElement;
|
|
47
50
|
parseReturnType(this: Parser): TypeNode;
|
|
48
51
|
parseClassDeclaration(this: Parser, modifiers: Modifier[]): ClassDeclaration;
|
|
49
52
|
parseHeritageClauses(this: Parser): HeritageClause[];
|
|
@@ -153,7 +156,15 @@ export const declarationMethods: DeclarationMethods = {
|
|
|
153
156
|
this.nextToken();
|
|
154
157
|
dotDotDotToken = true;
|
|
155
158
|
}
|
|
156
|
-
|
|
159
|
+
let name: import("../ast/declarations.js").BindingName;
|
|
160
|
+
let isThisParameter = false;
|
|
161
|
+
if (this.at(TokenKind.ThisKeyword)) {
|
|
162
|
+
const thisToken = this.nextToken();
|
|
163
|
+
name = { kind: SyntaxKind.Identifier, text: "this", start: thisToken.start, end: thisToken.end };
|
|
164
|
+
isThisParameter = true;
|
|
165
|
+
} else {
|
|
166
|
+
name = this.parseBindingName();
|
|
167
|
+
}
|
|
157
168
|
let questionToken = false;
|
|
158
169
|
if (this.at(TokenKind.Question)) {
|
|
159
170
|
this.nextToken();
|
|
@@ -169,7 +180,11 @@ export const declarationMethods: DeclarationMethods = {
|
|
|
169
180
|
this.nextToken();
|
|
170
181
|
initializer = this.parseAssignmentExpression();
|
|
171
182
|
}
|
|
172
|
-
|
|
183
|
+
// A `this` parameter is a type-level annotation only and is never a
|
|
184
|
+
// runtime argument, so it must not occupy an `argv` slot.
|
|
185
|
+
if (!isThisParameter) {
|
|
186
|
+
params.push({ kind: SyntaxKind.Parameter, name, modifiers, dotDotDotToken, questionToken, type, initializer, start, end: initializer?.end ?? type?.end ?? name.end });
|
|
187
|
+
}
|
|
173
188
|
if (this.at(TokenKind.Comma)) this.nextToken();
|
|
174
189
|
else break;
|
|
175
190
|
}
|
|
@@ -177,6 +192,76 @@ export const declarationMethods: DeclarationMethods = {
|
|
|
177
192
|
return params;
|
|
178
193
|
},
|
|
179
194
|
|
|
195
|
+
parseBindingName(this: Parser): import("../ast/declarations.js").BindingName {
|
|
196
|
+
if (this.at(TokenKind.OpenBracket)) {
|
|
197
|
+
const open = this.nextToken();
|
|
198
|
+
const elements: (import("../ast/declarations.js").BindingElement | undefined)[] = [];
|
|
199
|
+
while (!this.at(TokenKind.CloseBracket) && !this.at(TokenKind.EndOfFile)) {
|
|
200
|
+
if (this.at(TokenKind.Comma)) {
|
|
201
|
+
elements.push(undefined);
|
|
202
|
+
this.nextToken();
|
|
203
|
+
continue;
|
|
204
|
+
}
|
|
205
|
+
elements.push(this.parseBindingElement(false));
|
|
206
|
+
if (this.at(TokenKind.Comma)) this.nextToken();
|
|
207
|
+
else break;
|
|
208
|
+
}
|
|
209
|
+
const close = this.parseExpected(TokenKind.CloseBracket);
|
|
210
|
+
return { kind: SyntaxKind.ArrayBindingPattern, elements, start: open.start, end: close.end };
|
|
211
|
+
}
|
|
212
|
+
if (this.at(TokenKind.OpenBrace)) {
|
|
213
|
+
const open = this.nextToken();
|
|
214
|
+
const elements: import("../ast/declarations.js").BindingElement[] = [];
|
|
215
|
+
while (!this.at(TokenKind.CloseBrace) && !this.at(TokenKind.EndOfFile)) {
|
|
216
|
+
elements.push(this.parseBindingElement(true));
|
|
217
|
+
if (this.at(TokenKind.Comma)) this.nextToken();
|
|
218
|
+
else break;
|
|
219
|
+
}
|
|
220
|
+
const close = this.parseExpected(TokenKind.CloseBrace);
|
|
221
|
+
return { kind: SyntaxKind.ObjectBindingPattern, elements, start: open.start, end: close.end };
|
|
222
|
+
}
|
|
223
|
+
return this.parseIdentifier();
|
|
224
|
+
},
|
|
225
|
+
|
|
226
|
+
parseBindingElement(this: Parser, allowPropertyName: boolean): import("../ast/declarations.js").BindingElement {
|
|
227
|
+
const start = this.token.start;
|
|
228
|
+
let dotDotDotToken = false;
|
|
229
|
+
if (this.at(TokenKind.DotDotDot)) {
|
|
230
|
+
this.nextToken();
|
|
231
|
+
dotDotDotToken = true;
|
|
232
|
+
}
|
|
233
|
+
let propertyName: PropertyName | undefined;
|
|
234
|
+
let name: import("../ast/declarations.js").BindingName;
|
|
235
|
+
if (allowPropertyName && this.at(TokenKind.OpenBracket)) {
|
|
236
|
+
// Computed property key: `{ [expr]: target }`.
|
|
237
|
+
this.nextToken();
|
|
238
|
+
const expr = this.parseAssignmentExpression();
|
|
239
|
+
this.parseExpected(TokenKind.CloseBracket);
|
|
240
|
+
propertyName = expressionToPropertyName(expr) ?? { kind: SyntaxKind.Identifier, text: "<computed>", start: expr.start, end: expr.end };
|
|
241
|
+
this.parseExpected(TokenKind.Colon);
|
|
242
|
+
name = this.parseBindingName();
|
|
243
|
+
} else if (allowPropertyName && !this.at(TokenKind.OpenBrace) && !this.at(TokenKind.OpenBracket)) {
|
|
244
|
+
const first = this.parseIdentifierName();
|
|
245
|
+
if (this.at(TokenKind.Colon)) {
|
|
246
|
+
this.nextToken();
|
|
247
|
+
propertyName = first;
|
|
248
|
+
name = this.parseBindingName();
|
|
249
|
+
} else {
|
|
250
|
+
name = first;
|
|
251
|
+
}
|
|
252
|
+
} else {
|
|
253
|
+
// Array element, or a nested pattern used as an object value.
|
|
254
|
+
name = this.parseBindingName();
|
|
255
|
+
}
|
|
256
|
+
let initializer: Expression | undefined;
|
|
257
|
+
if (this.at(TokenKind.Equals)) {
|
|
258
|
+
this.nextToken();
|
|
259
|
+
initializer = this.parseAssignmentExpression();
|
|
260
|
+
}
|
|
261
|
+
const end = initializer?.end ?? (name.kind === SyntaxKind.Identifier ? name.end : name.end);
|
|
262
|
+
return { kind: SyntaxKind.BindingElement, name, propertyName, dotDotDotToken, initializer, start, end };
|
|
263
|
+
},
|
|
264
|
+
|
|
180
265
|
parseReturnType(this: Parser): TypeNode {
|
|
181
266
|
if (this.at(TokenKind.AssertsKeyword)) {
|
|
182
267
|
const start = this.nextToken().start;
|
|
@@ -249,6 +334,42 @@ export const declarationMethods: DeclarationMethods = {
|
|
|
249
334
|
this.nextToken();
|
|
250
335
|
return undefined;
|
|
251
336
|
}
|
|
337
|
+
if (
|
|
338
|
+
(this.at(TokenKind.GetKeyword) || this.at(TokenKind.SetKeyword)) &&
|
|
339
|
+
!this.atAhead(1, TokenKind.OpenParen) &&
|
|
340
|
+
!this.atAhead(1, TokenKind.Colon) &&
|
|
341
|
+
!this.atAhead(1, TokenKind.Equals) &&
|
|
342
|
+
!this.atAhead(1, TokenKind.Question) &&
|
|
343
|
+
!this.atAhead(1, TokenKind.LessThan) &&
|
|
344
|
+
!this.atAhead(1, TokenKind.Semicolon)
|
|
345
|
+
) {
|
|
346
|
+
const accessorToken = this.nextToken();
|
|
347
|
+
const name = this.parsePropertyName();
|
|
348
|
+
const parameters = this.parseParameters();
|
|
349
|
+
let returnType: TypeNode | undefined;
|
|
350
|
+
if (this.at(TokenKind.Colon)) {
|
|
351
|
+
this.nextToken();
|
|
352
|
+
returnType = this.parseReturnType();
|
|
353
|
+
}
|
|
354
|
+
let body: Block | undefined;
|
|
355
|
+
if (this.at(TokenKind.OpenBrace)) body = this.parseBlock();
|
|
356
|
+
else this.parseSemicolon();
|
|
357
|
+
const accessor: MethodDeclaration = {
|
|
358
|
+
kind: SyntaxKind.MethodDeclaration,
|
|
359
|
+
name,
|
|
360
|
+
modifiers,
|
|
361
|
+
typeParameters: [],
|
|
362
|
+
parameters,
|
|
363
|
+
returnType,
|
|
364
|
+
body,
|
|
365
|
+
flags: NodeFlags.None,
|
|
366
|
+
optional: false,
|
|
367
|
+
accessor: accessorToken.kind === TokenKind.GetKeyword ? "get" : "set",
|
|
368
|
+
start,
|
|
369
|
+
end: body?.end ?? returnType?.end ?? name.end,
|
|
370
|
+
};
|
|
371
|
+
return accessor;
|
|
372
|
+
}
|
|
252
373
|
if (this.at(TokenKind.ConstructorKeyword)) {
|
|
253
374
|
const name = this.nextToken();
|
|
254
375
|
const parameters = this.parseParameters();
|
|
@@ -337,13 +458,10 @@ export const declarationMethods: DeclarationMethods = {
|
|
|
337
458
|
return { kind: SyntaxKind.NumericLiteral, text: token.text, value: Number(token.value ?? 0), start: token.start, end: token.end };
|
|
338
459
|
}
|
|
339
460
|
if (token.kind === TokenKind.OpenBracket) {
|
|
340
|
-
this.nextToken();
|
|
461
|
+
const start = this.nextToken().start;
|
|
341
462
|
const expr = this.parseAssignmentExpression();
|
|
342
|
-
this.parseExpected(TokenKind.CloseBracket);
|
|
343
|
-
|
|
344
|
-
if (name) return name;
|
|
345
|
-
this.error(DiagnosticCode.InvalidTypeSyntax, "Computed property names are not supported by xbintsc");
|
|
346
|
-
return { kind: SyntaxKind.Identifier, text: "<computed>", start: expr.start, end: expr.end };
|
|
463
|
+
const close = this.parseExpected(TokenKind.CloseBracket);
|
|
464
|
+
return { kind: SyntaxKind.ComputedPropertyName, expression: expr, start, end: close.end };
|
|
347
465
|
}
|
|
348
466
|
return this.parseIdentifierName();
|
|
349
467
|
},
|
|
@@ -439,34 +557,27 @@ export const declarationMethods: DeclarationMethods = {
|
|
|
439
557
|
const name: Identifier = { kind: SyntaxKind.Identifier, text: "__call", start, end: start };
|
|
440
558
|
return { kind: SyntaxKind.MethodSignature, name, questionToken: false, typeParameters, parameters, returnType, start, end: returnType?.end ?? start };
|
|
441
559
|
}
|
|
442
|
-
if (this.at(TokenKind.OpenBracket)
|
|
443
|
-
const
|
|
444
|
-
|
|
445
|
-
|
|
446
|
-
this.nextToken();
|
|
447
|
-
const parameters: Parameter[] = [];
|
|
448
|
-
let ok = true;
|
|
449
|
-
try {
|
|
560
|
+
if (this.at(TokenKind.OpenBracket)) {
|
|
561
|
+
const indexSignature = this.tryParse<TypeElement>(() => {
|
|
562
|
+
const open = this.nextToken();
|
|
563
|
+
const parameters: Parameter[] = [];
|
|
450
564
|
const paramName = this.parseIdentifier();
|
|
451
|
-
let
|
|
565
|
+
let paramType: TypeNode | undefined;
|
|
452
566
|
if (this.at(TokenKind.Colon)) {
|
|
453
567
|
this.nextToken();
|
|
454
|
-
|
|
455
|
-
} else
|
|
568
|
+
paramType = this.parseType();
|
|
569
|
+
} else {
|
|
570
|
+
throw new SpeculationError();
|
|
571
|
+
}
|
|
456
572
|
this.parseExpected(TokenKind.CloseBracket);
|
|
457
|
-
|
|
458
|
-
} catch {
|
|
459
|
-
ok = false;
|
|
460
|
-
}
|
|
461
|
-
if (ok && this.at(TokenKind.Colon)) {
|
|
573
|
+
if (!this.at(TokenKind.Colon)) throw new SpeculationError();
|
|
462
574
|
this.nextToken();
|
|
463
575
|
const type = this.parseType();
|
|
464
576
|
this.parseSemicolonOrComma();
|
|
465
|
-
|
|
466
|
-
|
|
467
|
-
|
|
468
|
-
|
|
469
|
-
this.scanner.seek(savePos);
|
|
577
|
+
parameters.push({ kind: SyntaxKind.Parameter, name: paramName, modifiers: [], dotDotDotToken: false, questionToken: false, type: paramType, start: paramName.start, end: paramType?.end ?? paramName.end });
|
|
578
|
+
return { kind: SyntaxKind.IndexSignature, parameters, type, start: open.start, end: type.end };
|
|
579
|
+
});
|
|
580
|
+
if (indexSignature) return indexSignature;
|
|
470
581
|
}
|
|
471
582
|
const name = this.parsePropertyName();
|
|
472
583
|
let questionToken = false;
|
|
@@ -180,9 +180,11 @@ export const expressionMethods: ExpressionMethods = {
|
|
|
180
180
|
const t = this.lookAhead(i);
|
|
181
181
|
if (t.kind === TokenKind.EndOfFile) return -1;
|
|
182
182
|
if (t.kind === TokenKind.OpenParen || t.kind === TokenKind.OpenBracket || t.kind === TokenKind.OpenBrace) depth++;
|
|
183
|
-
else if (t.kind === TokenKind.CloseParen || t.kind === TokenKind.CloseBracket || t.kind === TokenKind.CloseBrace)
|
|
184
|
-
|
|
185
|
-
|
|
183
|
+
else if (t.kind === TokenKind.CloseParen || t.kind === TokenKind.CloseBracket || t.kind === TokenKind.CloseBrace) {
|
|
184
|
+
if (depth === 0) return -1;
|
|
185
|
+
depth--;
|
|
186
|
+
} else if (t.kind === TokenKind.EqualsGreaterThan && depth === 0) return i;
|
|
187
|
+
else if (depth === 0 && (t.kind === TokenKind.Semicolon || t.kind === TokenKind.Comma)) return -1;
|
|
186
188
|
}
|
|
187
189
|
},
|
|
188
190
|
|
|
@@ -329,7 +331,7 @@ export const expressionMethods: ExpressionMethods = {
|
|
|
329
331
|
}
|
|
330
332
|
case TokenKind.BigIntLiteral:
|
|
331
333
|
this.nextToken();
|
|
332
|
-
return { kind: SyntaxKind.BigIntLiteral, text: token.text, value:
|
|
334
|
+
return { kind: SyntaxKind.BigIntLiteral, text: token.text, value: Number(token.value ?? 0), start: token.start, end: token.end };
|
|
333
335
|
case TokenKind.StringLiteral:
|
|
334
336
|
this.nextToken();
|
|
335
337
|
return this.stringLiteralFromToken(token);
|
|
@@ -374,7 +376,16 @@ export const expressionMethods: ExpressionMethods = {
|
|
|
374
376
|
case TokenKind.NoSubstitutionTemplateLiteral:
|
|
375
377
|
return this.parseTemplateLiteral();
|
|
376
378
|
case TokenKind.Slash:
|
|
379
|
+
case TokenKind.RegularExpressionLiteral:
|
|
377
380
|
return this.parseRegularExpression();
|
|
381
|
+
case TokenKind.ImportKeyword:
|
|
382
|
+
if (this.atAhead(1, TokenKind.Dot)) {
|
|
383
|
+
const importToken = this.nextToken();
|
|
384
|
+
this.nextToken();
|
|
385
|
+
const metaName = this.parseIdentifierName();
|
|
386
|
+
return { kind: SyntaxKind.Identifier, text: "import.meta", start: importToken.start, end: metaName.end };
|
|
387
|
+
}
|
|
388
|
+
break;
|
|
378
389
|
default:
|
|
379
390
|
break;
|
|
380
391
|
}
|
|
@@ -422,6 +433,11 @@ export const expressionMethods: ExpressionMethods = {
|
|
|
422
433
|
expression = { kind: SyntaxKind.TaggedTemplateExpression, tag: expression, template, start: expression.start, end: template.end };
|
|
423
434
|
continue;
|
|
424
435
|
}
|
|
436
|
+
if (token.kind === TokenKind.Exclamation && !token.precededByLineBreak) {
|
|
437
|
+
this.nextToken();
|
|
438
|
+
expression = { kind: SyntaxKind.NonNullExpression, expression, start: expression.start, end: token.end };
|
|
439
|
+
continue;
|
|
440
|
+
}
|
|
425
441
|
return expression;
|
|
426
442
|
}
|
|
427
443
|
},
|
package/src/parser/helpers.ts
CHANGED
package/src/parser/modules.ts
CHANGED
|
@@ -126,6 +126,11 @@ export const moduleMethods: ModuleMethods = {
|
|
|
126
126
|
const assignment: ExportAssignment = { kind: SyntaxKind.ExportAssignment, isExportEquals: false, expression, start, end: expression.end };
|
|
127
127
|
return assignment;
|
|
128
128
|
}
|
|
129
|
+
let isTypeOnly = false;
|
|
130
|
+
if (this.at(TokenKind.TypeKeyword) && (this.atAhead(1, TokenKind.OpenBrace) || this.atAhead(1, TokenKind.Asterisk))) {
|
|
131
|
+
isTypeOnly = true;
|
|
132
|
+
this.nextToken();
|
|
133
|
+
}
|
|
129
134
|
if (this.at(TokenKind.Asterisk)) {
|
|
130
135
|
this.nextToken();
|
|
131
136
|
let nsName: Identifier | undefined;
|
|
@@ -144,7 +149,7 @@ export const moduleMethods: ModuleMethods = {
|
|
|
144
149
|
modifiers: [],
|
|
145
150
|
exportClause: nsName ? { kind: SyntaxKind.NamespaceImport, name: nsName, start: nsName.start, end: nsName.end } : undefined,
|
|
146
151
|
moduleSpecifier,
|
|
147
|
-
isTypeOnly
|
|
152
|
+
isTypeOnly,
|
|
148
153
|
start,
|
|
149
154
|
end: moduleSpecifier?.end ?? nsName?.end ?? start,
|
|
150
155
|
};
|
|
@@ -158,7 +163,7 @@ export const moduleMethods: ModuleMethods = {
|
|
|
158
163
|
if (this.at(TokenKind.StringLiteral)) moduleSpecifier = this.stringLiteralFromToken(this.nextToken());
|
|
159
164
|
}
|
|
160
165
|
this.parseSemicolon();
|
|
161
|
-
const decl: ExportDeclaration = { kind: SyntaxKind.ExportDeclaration, modifiers: [], exportClause: namedExports, moduleSpecifier, isTypeOnly
|
|
166
|
+
const decl: ExportDeclaration = { kind: SyntaxKind.ExportDeclaration, modifiers: [], exportClause: namedExports, moduleSpecifier, isTypeOnly, start, end: moduleSpecifier?.end ?? namedExports.end };
|
|
162
167
|
return decl;
|
|
163
168
|
}
|
|
164
169
|
const modifiers = this.tryParseModifiers();
|
package/src/parser/statements.ts
CHANGED
|
@@ -4,7 +4,7 @@
|
|
|
4
4
|
*/
|
|
5
5
|
|
|
6
6
|
import { DiagnosticCode } from "../diagnostics/diagnostic.js";
|
|
7
|
-
import { isOfKeyword, TokenKind } from "../lexer/token.js";
|
|
7
|
+
import { isIdentifierNameToken, isKeywordKind, isOfKeyword, TokenKind } from "../lexer/token.js";
|
|
8
8
|
import {
|
|
9
9
|
ModifierKind,
|
|
10
10
|
SyntaxKind,
|
|
@@ -58,6 +58,15 @@ export const statementMethods: StatementMethods = {
|
|
|
58
58
|
const modifiers: Modifier[] = [];
|
|
59
59
|
for (;;) {
|
|
60
60
|
const kind = this.token.kind;
|
|
61
|
+
const nextKind = this.lookAhead(1).kind;
|
|
62
|
+
const nextStartsName =
|
|
63
|
+
isIdentifierNameToken(nextKind) ||
|
|
64
|
+
isKeywordKind(nextKind) ||
|
|
65
|
+
nextKind === TokenKind.OpenBracket ||
|
|
66
|
+
nextKind === TokenKind.StringLiteral ||
|
|
67
|
+
nextKind === TokenKind.NumericLiteral ||
|
|
68
|
+
nextKind === TokenKind.Asterisk ||
|
|
69
|
+
nextKind === TokenKind.OpenBrace;
|
|
61
70
|
let modifierKind: ModifierKind | undefined;
|
|
62
71
|
switch (kind) {
|
|
63
72
|
case TokenKind.ExportKeyword:
|
|
@@ -89,6 +98,9 @@ export const statementMethods: StatementMethods = {
|
|
|
89
98
|
case TokenKind.ReadonlyKeyword:
|
|
90
99
|
modifierKind = ModifierKind.Readonly;
|
|
91
100
|
break;
|
|
101
|
+
case TokenKind.ConstKeyword:
|
|
102
|
+
if (this.atAhead(1, TokenKind.EnumKeyword)) modifierKind = ModifierKind.Const;
|
|
103
|
+
break;
|
|
92
104
|
case TokenKind.AsyncKeyword:
|
|
93
105
|
if (!this.lookAhead(1).precededByLineBreak) modifierKind = ModifierKind.Async;
|
|
94
106
|
break;
|
|
@@ -96,6 +108,10 @@ export const statementMethods: StatementMethods = {
|
|
|
96
108
|
break;
|
|
97
109
|
}
|
|
98
110
|
if (!modifierKind) break;
|
|
111
|
+
// Contextual modifiers (`declare`, `readonly`, `static`, …) are only
|
|
112
|
+
// modifiers when a member/declaration name follows; otherwise they are
|
|
113
|
+
// names themselves (`private declare(...)`, `readonly()`).
|
|
114
|
+
if (modifierKind !== ModifierKind.Export && modifierKind !== ModifierKind.Default && !nextStartsName) break;
|
|
99
115
|
const token = this.nextToken();
|
|
100
116
|
modifiers.push({ kind: SyntaxKind.Unknown, modifierKind, start: token.start, end: token.end });
|
|
101
117
|
}
|
|
@@ -120,6 +136,10 @@ export const statementMethods: StatementMethods = {
|
|
|
120
136
|
case TokenKind.VarKeyword:
|
|
121
137
|
case TokenKind.LetKeyword:
|
|
122
138
|
case TokenKind.ConstKeyword:
|
|
139
|
+
if (this.at(TokenKind.ConstKeyword) && this.atAhead(1, TokenKind.EnumKeyword)) {
|
|
140
|
+
const constToken = this.nextToken();
|
|
141
|
+
return this.parseEnumDeclaration([{ kind: SyntaxKind.Unknown, modifierKind: ModifierKind.Const, start: constToken.start, end: constToken.end }]);
|
|
142
|
+
}
|
|
123
143
|
return this.parseVariableStatement([]);
|
|
124
144
|
case TokenKind.FunctionKeyword:
|
|
125
145
|
return this.parseFunctionDeclaration([]);
|
|
@@ -186,6 +206,10 @@ export const statementMethods: StatementMethods = {
|
|
|
186
206
|
case TokenKind.VarKeyword:
|
|
187
207
|
case TokenKind.LetKeyword:
|
|
188
208
|
case TokenKind.ConstKeyword:
|
|
209
|
+
if (this.at(TokenKind.ConstKeyword) && this.atAhead(1, TokenKind.EnumKeyword)) {
|
|
210
|
+
const constToken = this.nextToken();
|
|
211
|
+
return this.parseEnumDeclaration([...modifiers, { kind: SyntaxKind.Unknown, modifierKind: ModifierKind.Const, start: constToken.start, end: constToken.end }]);
|
|
212
|
+
}
|
|
189
213
|
return this.parseVariableStatement(modifiers);
|
|
190
214
|
case TokenKind.FunctionKeyword:
|
|
191
215
|
return this.parseFunctionDeclaration(modifiers);
|
|
@@ -244,9 +268,9 @@ export const statementMethods: StatementMethods = {
|
|
|
244
268
|
},
|
|
245
269
|
|
|
246
270
|
parseVariableDeclaration(this: Parser): VariableDeclaration {
|
|
247
|
-
const name = this.
|
|
271
|
+
const name = this.parseBindingName();
|
|
248
272
|
let exclamation = false;
|
|
249
|
-
if (this.at(TokenKind.Exclamation)) {
|
|
273
|
+
if (name.kind === SyntaxKind.Identifier && this.at(TokenKind.Exclamation)) {
|
|
250
274
|
this.nextToken();
|
|
251
275
|
exclamation = true;
|
|
252
276
|
}
|
package/src/parser/types.ts
CHANGED
|
@@ -243,6 +243,11 @@ export const typeMethods: TypeMethods = {
|
|
|
243
243
|
const literal: NumericLiteral = { kind: SyntaxKind.NumericLiteral, text: `-${num.text}`, value: -Number(num.value ?? 0), start, end: num.end };
|
|
244
244
|
return { kind: SyntaxKind.LiteralType, literal, start, end: num.end };
|
|
245
245
|
}
|
|
246
|
+
case TokenKind.ConstKeyword: {
|
|
247
|
+
// `as const` const assertion: erased like any other type.
|
|
248
|
+
this.nextToken();
|
|
249
|
+
return { kind: SyntaxKind.AnyKeywordType, start, end: token.end };
|
|
250
|
+
}
|
|
246
251
|
case TokenKind.ImportKeyword: {
|
|
247
252
|
// import("...").T - parse loosely and degrade to `any`.
|
|
248
253
|
this.nextToken();
|