xbintsc 0.1.3 → 0.1.8

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.
Files changed (142) hide show
  1. package/README.md +14 -13
  2. package/dist/src/ast/common.d.ts +33 -0
  3. package/dist/src/ast/common.js +7 -0
  4. package/dist/src/ast/common.js.map +1 -0
  5. package/dist/src/ast/declarations.d.ts +110 -0
  6. package/dist/src/ast/declarations.js +5 -0
  7. package/dist/src/ast/declarations.js.map +1 -0
  8. package/dist/src/ast/expressions.d.ts +219 -0
  9. package/dist/src/ast/expressions.js +6 -0
  10. package/dist/src/ast/expressions.js.map +1 -0
  11. package/dist/src/ast/kinds.d.ts +160 -0
  12. package/dist/src/ast/kinds.js +171 -0
  13. package/dist/src/ast/kinds.js.map +1 -0
  14. package/dist/src/ast/modules.d.ts +61 -0
  15. package/dist/src/ast/modules.js +5 -0
  16. package/dist/src/ast/modules.js.map +1 -0
  17. package/dist/src/ast/nodes.d.ts +11 -839
  18. package/dist/src/ast/nodes.js +11 -237
  19. package/dist/src/ast/nodes.js.map +1 -1
  20. package/dist/src/ast/operators.d.ts +71 -0
  21. package/dist/src/ast/operators.js +77 -0
  22. package/dist/src/ast/operators.js.map +1 -0
  23. package/dist/src/ast/statements.d.ts +120 -0
  24. package/dist/src/ast/statements.js +5 -0
  25. package/dist/src/ast/statements.js.map +1 -0
  26. package/dist/src/ast/types.d.ts +123 -0
  27. package/dist/src/ast/types.js +6 -0
  28. package/dist/src/ast/types.js.map +1 -0
  29. package/dist/src/codegen/generator/calls.d.ts +22 -0
  30. package/dist/src/codegen/generator/calls.js +301 -0
  31. package/dist/src/codegen/generator/calls.js.map +1 -0
  32. package/dist/src/codegen/generator/context.d.ts +45 -0
  33. package/dist/src/codegen/generator/context.js +128 -0
  34. package/dist/src/codegen/generator/context.js.map +1 -0
  35. package/dist/src/codegen/generator/expressions.d.ts +22 -0
  36. package/dist/src/codegen/generator/expressions.js +383 -0
  37. package/dist/src/codegen/generator/expressions.js.map +1 -0
  38. package/dist/src/codegen/generator/generator.d.ts +22 -0
  39. package/dist/src/codegen/generator/generator.js +21 -0
  40. package/dist/src/codegen/generator/generator.js.map +1 -0
  41. package/dist/src/codegen/generator/module.d.ts +15 -0
  42. package/dist/src/codegen/generator/module.js +114 -0
  43. package/dist/src/codegen/generator/module.js.map +1 -0
  44. package/dist/src/codegen/generator/state.d.ts +40 -0
  45. package/dist/src/codegen/generator/state.js +84 -0
  46. package/dist/src/codegen/generator/state.js.map +1 -0
  47. package/dist/src/codegen/generator/statements.d.ts +22 -0
  48. package/dist/src/codegen/generator/statements.js +425 -0
  49. package/dist/src/codegen/generator/statements.js.map +1 -0
  50. package/dist/src/codegen/generator/tables.d.ts +19 -0
  51. package/dist/src/codegen/generator/tables.js +153 -0
  52. package/dist/src/codegen/generator/tables.js.map +1 -0
  53. package/dist/src/codegen/llvm.d.ts +4 -13
  54. package/dist/src/codegen/llvm.js +4 -1159
  55. package/dist/src/codegen/llvm.js.map +1 -1
  56. package/dist/src/driver/compiler.js +13 -4
  57. package/dist/src/driver/compiler.js.map +1 -1
  58. package/dist/src/lexer/char.d.ts +78 -0
  59. package/dist/src/lexer/char.js +106 -0
  60. package/dist/src/lexer/char.js.map +1 -0
  61. package/dist/src/lexer/scanner.js +1 -98
  62. package/dist/src/lexer/scanner.js.map +1 -1
  63. package/dist/src/parser/context.d.ts +58 -0
  64. package/dist/src/parser/context.js +174 -0
  65. package/dist/src/parser/context.js.map +1 -0
  66. package/dist/src/parser/declarations.d.ts +26 -0
  67. package/dist/src/parser/declarations.js +461 -0
  68. package/dist/src/parser/declarations.js.map +1 -0
  69. package/dist/src/parser/expressions.d.ts +27 -0
  70. package/dist/src/parser/expressions.js +437 -0
  71. package/dist/src/parser/expressions.js.map +1 -0
  72. package/dist/src/parser/helpers.d.ts +7 -0
  73. package/dist/src/parser/helpers.js +36 -0
  74. package/dist/src/parser/helpers.js.map +1 -0
  75. package/dist/src/parser/literals.d.ts +16 -0
  76. package/dist/src/parser/literals.js +193 -0
  77. package/dist/src/parser/literals.js.map +1 -0
  78. package/dist/src/parser/modules.d.ts +12 -0
  79. package/dist/src/parser/modules.js +175 -0
  80. package/dist/src/parser/modules.js.map +1 -0
  81. package/dist/src/parser/operators.d.ts +12 -0
  82. package/dist/src/parser/operators.js +172 -0
  83. package/dist/src/parser/operators.js.map +1 -0
  84. package/dist/src/parser/parser.d.ts +17 -122
  85. package/dist/src/parser/parser.js +18 -2307
  86. package/dist/src/parser/parser.js.map +1 -1
  87. package/dist/src/parser/speculation.d.ts +6 -0
  88. package/dist/src/parser/speculation.js +10 -0
  89. package/dist/src/parser/speculation.js.map +1 -0
  90. package/dist/src/parser/statements.d.ts +28 -0
  91. package/dist/src/parser/statements.js +402 -0
  92. package/dist/src/parser/statements.js.map +1 -0
  93. package/dist/src/parser/types.d.ts +21 -0
  94. package/dist/src/parser/types.js +338 -0
  95. package/dist/src/parser/types.js.map +1 -0
  96. package/dist/tests/e2e/compile.test.js +122 -2
  97. package/dist/tests/e2e/compile.test.js.map +1 -1
  98. package/dist/tests/parser/parser.test.js +9 -1
  99. package/dist/tests/parser/parser.test.js.map +1 -1
  100. package/package.json +1 -1
  101. package/runtime/rt.h +32 -0
  102. package/runtime/rt_internal.h +106 -0
  103. package/runtime/xt_alloc.c +38 -0
  104. package/runtime/xt_builtins.c +192 -0
  105. package/runtime/xt_containers.c +225 -0
  106. package/runtime/xt_io.c +133 -0
  107. package/runtime/xt_stdlib.c +502 -0
  108. package/runtime/xt_values.c +291 -0
  109. package/scripts/build-runtime.mjs +8 -1
  110. package/src/ast/common.ts +210 -0
  111. package/src/ast/declarations.ts +130 -0
  112. package/src/ast/expressions.ts +275 -0
  113. package/src/ast/kinds.ts +176 -0
  114. package/src/ast/modules.ts +73 -0
  115. package/src/ast/nodes.ts +11 -1101
  116. package/src/ast/operators.ts +76 -0
  117. package/src/ast/statements.ts +148 -0
  118. package/src/ast/types.ts +173 -0
  119. package/src/codegen/generator/calls.ts +355 -0
  120. package/src/codegen/generator/context.ts +156 -0
  121. package/src/codegen/generator/expressions.ts +431 -0
  122. package/src/codegen/generator/generator.ts +35 -0
  123. package/src/codegen/generator/module.ts +139 -0
  124. package/src/codegen/generator/state.ts +126 -0
  125. package/src/codegen/generator/statements.ts +474 -0
  126. package/src/codegen/generator/tables.ts +171 -0
  127. package/src/codegen/llvm.ts +4 -1305
  128. package/src/driver/compiler.ts +17 -5
  129. package/src/lexer/char.ts +116 -0
  130. package/src/lexer/scanner.ts +9 -109
  131. package/src/parser/context.ts +196 -0
  132. package/src/parser/declarations.ts +502 -0
  133. package/src/parser/expressions.ts +465 -0
  134. package/src/parser/helpers.ts +42 -0
  135. package/src/parser/literals.ts +207 -0
  136. package/src/parser/modules.ts +194 -0
  137. package/src/parser/operators.ts +181 -0
  138. package/src/parser/parser.ts +35 -2369
  139. package/src/parser/speculation.ts +9 -0
  140. package/src/parser/statements.ts +457 -0
  141. package/src/parser/types.ts +365 -0
  142. package/runtime/xt_runtime.c +0 -682
@@ -0,0 +1,465 @@
1
+ /**
2
+ * Expression parsing: assignment/conditional/binary/unary operators, calls,
3
+ * member access, literals, arrow functions, templates and regexes.
4
+ */
5
+
6
+ import { DiagnosticCode } from "../diagnostics/diagnostic.js";
7
+ import { TokenKind } from "../lexer/token.js";
8
+ import {
9
+ BinaryOperator,
10
+ PostfixUnaryOperator,
11
+ PrefixUnaryOperator,
12
+ } from "../ast/operators.js";
13
+ import {
14
+ NodeFlags,
15
+ SyntaxKind,
16
+ type ArrowFunction,
17
+ type BinaryExpression,
18
+ type BooleanLiteral,
19
+ type CallExpression,
20
+ type ConditionalExpression,
21
+ type Expression,
22
+ type NewExpression,
23
+ type NumericLiteral,
24
+ type Parameter,
25
+ type ParenthesizedExpression,
26
+ type TypeNode,
27
+ } from "../ast/nodes.js";
28
+ import {
29
+ AS_PRECEDENCE,
30
+ assignmentOperator,
31
+ binaryOperator,
32
+ binaryPrecedence,
33
+ prefixUnaryOperator,
34
+ } from "./operators.js";
35
+ import { isAssignmentTarget } from "./helpers.js";
36
+ import { SpeculationError } from "./speculation.js";
37
+ import type { Parser } from "./parser.js";
38
+
39
+ export interface ExpressionMethods {
40
+ parseExpression(this: Parser, noIn?: boolean): Expression;
41
+ parseAssignmentExpression(this: Parser, noIn?: boolean): Expression;
42
+ tryParseArrowFunction(this: Parser): ArrowFunction | undefined;
43
+ countTypeParameterTokens(this: Parser, cursor: number): number;
44
+ findMatchingParen(this: Parser, cursor: number): number;
45
+ skipTypeTokens(this: Parser, startIndex: number): number;
46
+ parseConditionalExpression(this: Parser, noIn: boolean): Expression;
47
+ parseBinaryExpression(this: Parser, minPrecedence: number, noIn: boolean): Expression;
48
+ parseUnaryExpression(this: Parser): Expression;
49
+ parsePostfixExpression(this: Parser): Expression;
50
+ parseLeftHandSideExpression(this: Parser): Expression;
51
+ parseNewExpression(this: Parser): NewExpression;
52
+ parseMemberOnlyExpression(this: Parser): Expression;
53
+ parsePrimaryExpression(this: Parser): Expression;
54
+ parseCallAndMemberTail(this: Parser, base: Expression): Expression;
55
+ previousEnd(this: Parser, args: readonly Expression[], fallback: number): number;
56
+ parsePropertyAccess(this: Parser, expression: Expression): Expression;
57
+ parseArguments(this: Parser): Expression[];
58
+ }
59
+
60
+ export const expressionMethods: ExpressionMethods = {
61
+ parseExpression(this: Parser, noIn = false): Expression {
62
+ return this.parseAssignmentExpression(noIn);
63
+ },
64
+
65
+ parseAssignmentExpression(this: Parser, noIn = false): Expression {
66
+ const arrow = this.tryParseArrowFunction();
67
+ if (arrow) return arrow;
68
+
69
+ const start = this.token.start;
70
+ const left = this.parseConditionalExpression(noIn);
71
+ const token = this.token;
72
+ const op = assignmentOperator(token.kind);
73
+ if (op) {
74
+ if (!isAssignmentTarget(left)) {
75
+ this.error(DiagnosticCode.InvalidAssignmentTarget, "Invalid assignment target", token);
76
+ }
77
+ this.nextToken();
78
+ const right = this.parseAssignmentExpression(noIn);
79
+ const assignment = {
80
+ kind: SyntaxKind.BinaryExpression,
81
+ left,
82
+ operator: op,
83
+ right,
84
+ operatorToken: token,
85
+ start,
86
+ end: right.end,
87
+ } as unknown as BinaryExpression;
88
+ return assignment;
89
+ }
90
+ return left;
91
+ },
92
+
93
+ tryParseArrowFunction(this: Parser): ArrowFunction | undefined {
94
+ const start = this.token.start;
95
+ let flags = NodeFlags.None;
96
+ let async = false;
97
+ let cursor = 0;
98
+ if (this.at(TokenKind.AsyncKeyword) && !this.lookAhead(1).precededByLineBreak) {
99
+ const next = this.lookAhead(1);
100
+ if (next.kind === TokenKind.OpenParen || this.isIdentifierLike(next)) async = true;
101
+ }
102
+ if (async) cursor = 1;
103
+ const afterTypeParams = this.countTypeParameterTokens(cursor);
104
+ if (afterTypeParams >= 0) cursor = afterTypeParams;
105
+
106
+ const first = this.lookAhead(cursor);
107
+ if (first.kind === TokenKind.OpenParen) {
108
+ const closeIndex = this.findMatchingParen(cursor);
109
+ if (closeIndex < 0) return undefined;
110
+ let arrowIndex = closeIndex + 1;
111
+ if (this.lookAhead(arrowIndex).kind === TokenKind.Colon) {
112
+ arrowIndex = this.skipTypeTokens(arrowIndex + 1);
113
+ if (arrowIndex < 0) return undefined;
114
+ }
115
+ if (this.lookAhead(arrowIndex).kind !== TokenKind.EqualsGreaterThan) return undefined;
116
+ } else if (this.isIdentifierLike(first)) {
117
+ if (this.lookAhead(cursor + 1).kind !== TokenKind.EqualsGreaterThan) return undefined;
118
+ } else {
119
+ return undefined;
120
+ }
121
+
122
+ if (async) {
123
+ this.nextToken();
124
+ flags |= NodeFlags.Async;
125
+ }
126
+ const typeParams = this.at(TokenKind.LessThan) ? this.parseTypeParameters() : [];
127
+ let parameters: Parameter[];
128
+ if (this.at(TokenKind.OpenParen)) {
129
+ parameters = this.parseParameters();
130
+ } else {
131
+ const paramStart = this.token.start;
132
+ const name = this.parseIdentifierName();
133
+ parameters = [{ kind: SyntaxKind.Parameter, name, modifiers: [], dotDotDotToken: false, questionToken: false, start: paramStart, end: name.end }];
134
+ }
135
+ let returnType: TypeNode | undefined;
136
+ if (this.at(TokenKind.Colon)) {
137
+ this.nextToken();
138
+ returnType = this.parseReturnType();
139
+ }
140
+ this.parseExpected(TokenKind.EqualsGreaterThan);
141
+ const body: import("../ast/nodes.js").Block | Expression = this.at(TokenKind.OpenBrace) ? this.parseBlock() : this.parseAssignmentExpression();
142
+ return { kind: SyntaxKind.ArrowFunction, typeParameters: typeParams, parameters, returnType, body, flags, start, end: body.end };
143
+ },
144
+
145
+ countTypeParameterTokens(this: Parser, cursor: number): number {
146
+ if (this.lookAhead(cursor).kind !== TokenKind.LessThan) return -1;
147
+ let depth = 0;
148
+ for (let i = cursor; ; i++) {
149
+ const t = this.lookAhead(i);
150
+ if (t.kind === TokenKind.EndOfFile) return -1;
151
+ if (t.kind === TokenKind.LessThan) depth++;
152
+ else if (t.kind === TokenKind.GreaterThan) {
153
+ depth--;
154
+ if (depth === 0) return i + 1;
155
+ } else if (t.kind === TokenKind.GreaterThanGreaterThan || t.kind === TokenKind.GreaterThanGreaterThanGreaterThan) {
156
+ depth -= t.kind === TokenKind.GreaterThanGreaterThan ? 2 : 3;
157
+ if (depth <= 0) return i + 1;
158
+ } else if (t.kind === TokenKind.Semicolon) {
159
+ return -1;
160
+ }
161
+ }
162
+ },
163
+
164
+ findMatchingParen(this: Parser, cursor: number): number {
165
+ let depth = 0;
166
+ for (let i = cursor; ; i++) {
167
+ const t = this.lookAhead(i);
168
+ if (t.kind === TokenKind.EndOfFile) return -1;
169
+ if (t.kind === TokenKind.OpenParen) depth++;
170
+ else if (t.kind === TokenKind.CloseParen) {
171
+ depth--;
172
+ if (depth === 0) return i;
173
+ }
174
+ }
175
+ },
176
+
177
+ skipTypeTokens(this: Parser, startIndex: number): number {
178
+ let depth = 0;
179
+ for (let i = startIndex; ; i++) {
180
+ const t = this.lookAhead(i);
181
+ if (t.kind === TokenKind.EndOfFile) return -1;
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) depth--;
184
+ else if (t.kind === TokenKind.EqualsGreaterThan && depth === 0) return i;
185
+ else if (t.kind === TokenKind.Semicolon && depth === 0) return -1;
186
+ }
187
+ },
188
+
189
+ parseConditionalExpression(this: Parser, noIn: boolean): Expression {
190
+ const start = this.token.start;
191
+ const condition = this.parseBinaryExpression(0, noIn);
192
+ if (this.at(TokenKind.Question)) {
193
+ this.nextToken();
194
+ const whenTrue = this.parseAssignmentExpression();
195
+ this.parseExpected(TokenKind.Colon);
196
+ const whenFalse = this.parseAssignmentExpression(noIn);
197
+ const node: ConditionalExpression = { kind: SyntaxKind.ConditionalExpression, condition, whenTrue, whenFalse, start, end: whenFalse.end };
198
+ return node;
199
+ }
200
+ return condition;
201
+ },
202
+
203
+ parseBinaryExpression(this: Parser, minPrecedence: number, noIn: boolean): Expression {
204
+ let left = this.parseUnaryExpression();
205
+ for (;;) {
206
+ const token = this.token;
207
+ // `expr as Type` / `expr satisfies Type` bind at the relational level.
208
+ if (token.kind === TokenKind.AsKeyword || token.kind === TokenKind.SatisfiesKeyword) {
209
+ if (AS_PRECEDENCE < minPrecedence) break;
210
+ this.nextToken();
211
+ const type = this.parseType();
212
+ left =
213
+ token.kind === TokenKind.AsKeyword
214
+ ? { kind: SyntaxKind.AsExpression, expression: left, type, start: left.start, end: type.end }
215
+ : { kind: SyntaxKind.SatisfiesExpression, expression: left, type, start: left.start, end: type.end };
216
+ continue;
217
+ }
218
+ if (token.kind === TokenKind.InKeyword && noIn) break;
219
+ const op = binaryOperator(token.kind);
220
+ if (!op) break;
221
+ const precedence = binaryPrecedence(op);
222
+ if (precedence < minPrecedence) break;
223
+ const nextMin = op === BinaryOperator.Exponent ? precedence : precedence + 1;
224
+ this.nextToken();
225
+ const right = this.parseBinaryExpression(nextMin, noIn);
226
+ const binary: BinaryExpression = { kind: SyntaxKind.BinaryExpression, left, operator: op, right, operatorToken: token, start: left.start, end: right.end };
227
+ left = binary;
228
+ }
229
+ return left;
230
+ },
231
+
232
+ parseUnaryExpression(this: Parser): Expression {
233
+ const token = this.token;
234
+ const prefix = prefixUnaryOperator(token.kind);
235
+ if (prefix) {
236
+ this.nextToken();
237
+ if (prefix === PrefixUnaryOperator.Await) {
238
+ const expression = this.parseUnaryExpression();
239
+ return { kind: SyntaxKind.AwaitExpression, expression, start: token.start, end: expression.end };
240
+ }
241
+ if (prefix === PrefixUnaryOperator.Delete) {
242
+ const expression = this.parseUnaryExpression();
243
+ return { kind: SyntaxKind.DeleteExpression, expression, start: token.start, end: expression.end };
244
+ }
245
+ if (prefix === PrefixUnaryOperator.Void) {
246
+ const expression = this.parseUnaryExpression();
247
+ return { kind: SyntaxKind.VoidExpression, expression, start: token.start, end: expression.end };
248
+ }
249
+ if (prefix === PrefixUnaryOperator.TypeOf) {
250
+ const expression = this.parseUnaryExpression();
251
+ return { kind: SyntaxKind.TypeOfExpression, expression, start: token.start, end: expression.end };
252
+ }
253
+ const operand = this.parseUnaryExpression();
254
+ return { kind: SyntaxKind.PrefixUnaryExpression, operator: prefix, operand, start: token.start, end: operand.end };
255
+ }
256
+ if (token.kind === TokenKind.YieldKeyword) {
257
+ this.nextToken();
258
+ let delegate = false;
259
+ let expression: Expression | undefined;
260
+ if (this.at(TokenKind.Asterisk)) {
261
+ this.nextToken();
262
+ delegate = true;
263
+ }
264
+ if (!this.canInsertSemicolon() && !this.at(TokenKind.Semicolon) && !this.at(TokenKind.CloseParen)) {
265
+ expression = this.parseAssignmentExpression();
266
+ }
267
+ return { kind: SyntaxKind.YieldExpression, expression, delegate, start: token.start, end: expression?.end ?? token.end };
268
+ }
269
+ if (token.kind === TokenKind.LessThan) {
270
+ const assertion = this.tryParse<Expression>(() => {
271
+ const type = this.parseType();
272
+ const expression = this.parseUnaryExpression();
273
+ return { kind: SyntaxKind.AsExpression, expression, type, start: token.start, end: expression.end };
274
+ });
275
+ if (assertion) return assertion;
276
+ }
277
+ return this.parsePostfixExpression();
278
+ },
279
+
280
+ parsePostfixExpression(this: Parser): Expression {
281
+ const start = this.token.start;
282
+ const expression = this.parseLeftHandSideExpression();
283
+ const token = this.token;
284
+ if ((token.kind === TokenKind.PlusPlus || token.kind === TokenKind.MinusMinus) && !token.precededByLineBreak) {
285
+ this.nextToken();
286
+ const operator = token.kind === TokenKind.PlusPlus ? PostfixUnaryOperator.PlusPlus : PostfixUnaryOperator.MinusMinus;
287
+ return { kind: SyntaxKind.PostfixUnaryExpression, operator, operand: expression, start, end: token.end };
288
+ }
289
+ return expression;
290
+ },
291
+
292
+ parseLeftHandSideExpression(this: Parser): Expression {
293
+ const expression = this.at(TokenKind.NewKeyword) ? this.parseNewExpression() : this.parsePrimaryExpression();
294
+ return this.parseCallAndMemberTail(expression);
295
+ },
296
+
297
+ parseNewExpression(this: Parser): NewExpression {
298
+ const start = this.parseExpected(TokenKind.NewKeyword).start;
299
+ const callee = this.parseMemberOnlyExpression();
300
+ const typeArguments = this.at(TokenKind.LessThan) ? this.parseTypeArguments() : [];
301
+ const args = this.at(TokenKind.OpenParen) ? this.parseArguments() : [];
302
+ return { kind: SyntaxKind.NewExpression, expression: callee, typeArguments, arguments: args, start, end: args[args.length - 1]?.end ?? callee.end };
303
+ },
304
+
305
+ parseMemberOnlyExpression(this: Parser): Expression {
306
+ let expression: Expression = this.parsePrimaryExpression();
307
+ for (;;) {
308
+ if (this.at(TokenKind.Dot) || this.at(TokenKind.QuestionDot)) {
309
+ expression = this.parsePropertyAccess(expression);
310
+ } else if (this.at(TokenKind.OpenBracket)) {
311
+ this.nextToken();
312
+ const argument = this.parseExpression();
313
+ const close = this.parseExpected(TokenKind.CloseBracket);
314
+ expression = { kind: SyntaxKind.ElementAccessExpression, expression, argumentExpression: argument, optional: false, start: expression.start, end: close.end };
315
+ } else {
316
+ break;
317
+ }
318
+ }
319
+ return expression;
320
+ },
321
+
322
+ parsePrimaryExpression(this: Parser): Expression {
323
+ const token = this.token;
324
+ switch (token.kind) {
325
+ case TokenKind.NumericLiteral: {
326
+ this.nextToken();
327
+ const node: NumericLiteral = { kind: SyntaxKind.NumericLiteral, text: token.text, value: Number(token.value ?? 0), start: token.start, end: token.end };
328
+ return node;
329
+ }
330
+ case TokenKind.BigIntLiteral:
331
+ this.nextToken();
332
+ return { kind: SyntaxKind.BigIntLiteral, text: token.text, value: BigInt(token.value ?? 0n), start: token.start, end: token.end };
333
+ case TokenKind.StringLiteral:
334
+ this.nextToken();
335
+ return this.stringLiteralFromToken(token);
336
+ case TokenKind.TrueKeyword:
337
+ this.nextToken();
338
+ return { kind: SyntaxKind.TrueKeyword, value: true, start: token.start, end: token.end } satisfies BooleanLiteral;
339
+ case TokenKind.FalseKeyword:
340
+ this.nextToken();
341
+ return { kind: SyntaxKind.FalseKeyword, value: false, start: token.start, end: token.end } satisfies BooleanLiteral;
342
+ case TokenKind.NullKeyword:
343
+ this.nextToken();
344
+ return { kind: SyntaxKind.NullKeyword, start: token.start, end: token.end };
345
+ case TokenKind.UndefinedKeyword:
346
+ this.nextToken();
347
+ return { kind: SyntaxKind.UndefinedKeyword, start: token.start, end: token.end };
348
+ case TokenKind.ThisKeyword:
349
+ this.nextToken();
350
+ return { kind: SyntaxKind.ThisKeyword, start: token.start, end: token.end };
351
+ case TokenKind.OpenParen: {
352
+ this.nextToken();
353
+ const expression = this.parseExpression();
354
+ const close = this.parseExpected(TokenKind.CloseParen);
355
+ const paren: ParenthesizedExpression = { kind: SyntaxKind.ParenthesizedExpression, expression, start: token.start, end: close.end };
356
+ return paren;
357
+ }
358
+ case TokenKind.OpenBracket:
359
+ return this.parseArrayLiteral();
360
+ case TokenKind.OpenBrace:
361
+ return this.parseObjectLiteral();
362
+ case TokenKind.FunctionKeyword:
363
+ return this.parseFunctionExpression();
364
+ case TokenKind.ClassKeyword:
365
+ return this.parseClassExpression();
366
+ case TokenKind.AsyncKeyword:
367
+ if (this.atAhead(1, TokenKind.FunctionKeyword) && !this.lookAhead(1).precededByLineBreak) return this.parseFunctionExpression();
368
+ break;
369
+ case TokenKind.Backtick:
370
+ case TokenKind.TemplateHead:
371
+ case TokenKind.NoSubstitutionTemplateLiteral:
372
+ return this.parseTemplateLiteral();
373
+ case TokenKind.Slash:
374
+ return this.parseRegularExpression();
375
+ default:
376
+ break;
377
+ }
378
+ if (this.isIdentifierLike(token)) return this.parseIdentifierName();
379
+ this.error(DiagnosticCode.UnexpectedToken, `Unexpected token '${token.text || token.kind}'`);
380
+ if (token.kind !== TokenKind.EndOfFile) this.nextToken();
381
+ return { kind: SyntaxKind.Identifier, text: "<error>", start: token.start, end: token.end };
382
+ },
383
+
384
+ parseCallAndMemberTail(this: Parser, base: Expression): Expression {
385
+ let expression = base;
386
+ for (;;) {
387
+ const token = this.token;
388
+ if (token.kind === TokenKind.Dot || token.kind === TokenKind.QuestionDot) {
389
+ expression = this.parsePropertyAccess(expression);
390
+ continue;
391
+ }
392
+ if (token.kind === TokenKind.OpenBracket) {
393
+ this.nextToken();
394
+ const argument = this.parseExpression();
395
+ const close = this.parseExpected(TokenKind.CloseBracket);
396
+ expression = { kind: SyntaxKind.ElementAccessExpression, expression, argumentExpression: argument, optional: false, start: expression.start, end: close.end };
397
+ continue;
398
+ }
399
+ if (token.kind === TokenKind.OpenParen) {
400
+ const args = this.parseArguments();
401
+ const call: CallExpression = { kind: SyntaxKind.CallExpression, expression, typeArguments: [], arguments: args, optional: false, start: expression.start, end: this.previousEnd(args, expression.end) };
402
+ expression = call;
403
+ continue;
404
+ }
405
+ if (token.kind === TokenKind.LessThan) {
406
+ const call = this.tryParse<Expression>(() => {
407
+ const typeArguments = this.parseTypeArguments();
408
+ if (!this.at(TokenKind.OpenParen)) throw new SpeculationError();
409
+ const args = this.parseArguments();
410
+ return { kind: SyntaxKind.CallExpression, expression, typeArguments, arguments: args, optional: false, start: expression.start, end: this.previousEnd(args, this.token.start) };
411
+ });
412
+ if (call) {
413
+ expression = call;
414
+ continue;
415
+ }
416
+ }
417
+ if (this.at(TokenKind.Backtick) || this.at(TokenKind.TemplateHead) || this.at(TokenKind.NoSubstitutionTemplateLiteral)) {
418
+ const template = this.parseTemplateLiteral();
419
+ expression = { kind: SyntaxKind.TaggedTemplateExpression, tag: expression, template, start: expression.start, end: template.end };
420
+ continue;
421
+ }
422
+ return expression;
423
+ }
424
+ },
425
+
426
+ previousEnd(this: Parser, args: readonly Expression[], fallback: number): number {
427
+ return args[args.length - 1]?.end ?? fallback;
428
+ },
429
+
430
+ parsePropertyAccess(this: Parser, expression: Expression): Expression {
431
+ const token = this.nextToken();
432
+ const optional = token.kind === TokenKind.QuestionDot;
433
+ if (optional && this.at(TokenKind.OpenParen)) {
434
+ const args = this.parseArguments();
435
+ return { kind: SyntaxKind.CallExpression, expression, typeArguments: [], arguments: args, optional: true, start: expression.start, end: this.previousEnd(args, token.start) };
436
+ }
437
+ if (optional && this.at(TokenKind.OpenBracket)) {
438
+ this.nextToken();
439
+ const argument = this.parseExpression();
440
+ const close = this.parseExpected(TokenKind.CloseBracket);
441
+ return { kind: SyntaxKind.ElementAccessExpression, expression, argumentExpression: argument, optional: true, start: expression.start, end: close.end };
442
+ }
443
+ const name = this.parseIdentifierName();
444
+ return { kind: SyntaxKind.PropertyAccessExpression, expression, name, optional, start: expression.start, end: name.end };
445
+ },
446
+
447
+ parseArguments(this: Parser): Expression[] {
448
+ this.parseExpected(TokenKind.OpenParen);
449
+ const args: Expression[] = [];
450
+ while (!this.at(TokenKind.CloseParen) && !this.at(TokenKind.EndOfFile)) {
451
+ if (this.at(TokenKind.DotDotDot)) {
452
+ const start = this.nextToken().start;
453
+ const expression = this.parseAssignmentExpression();
454
+ args.push({ kind: SyntaxKind.SpreadElement, expression, start, end: expression.end });
455
+ } else {
456
+ args.push(this.parseAssignmentExpression());
457
+ }
458
+ if (this.at(TokenKind.Comma)) this.nextToken();
459
+ else break;
460
+ }
461
+ this.parseExpected(TokenKind.CloseParen);
462
+ return args;
463
+ },
464
+
465
+ };
@@ -0,0 +1,42 @@
1
+ /**
2
+ * Small AST-shape predicates shared by the parser's method groups.
3
+ */
4
+
5
+ import { SyntaxKind } from "../ast/kinds.js";
6
+ import type { Expression, PropertyName } from "../ast/nodes.js";
7
+
8
+ export function expressionToPropertyName(expr: Expression): PropertyName | undefined {
9
+ switch (expr.kind) {
10
+ case SyntaxKind.StringLiteral:
11
+ return expr;
12
+ case SyntaxKind.NumericLiteral:
13
+ return expr;
14
+ case SyntaxKind.Identifier:
15
+ return expr;
16
+ default:
17
+ return undefined;
18
+ }
19
+ }
20
+
21
+ export function propertyNameText(name: PropertyName): string {
22
+ switch (name.kind) {
23
+ case SyntaxKind.Identifier:
24
+ case SyntaxKind.PrivateIdentifier:
25
+ return name.text;
26
+ case SyntaxKind.StringLiteral:
27
+ return name.value;
28
+ case SyntaxKind.NumericLiteral:
29
+ return name.text;
30
+ default:
31
+ return "";
32
+ }
33
+ }
34
+
35
+ export function isAssignmentTarget(expr: Expression): boolean {
36
+ return (
37
+ expr.kind === SyntaxKind.Identifier ||
38
+ expr.kind === SyntaxKind.PropertyAccessExpression ||
39
+ expr.kind === SyntaxKind.ElementAccessExpression ||
40
+ expr.kind === SyntaxKind.ParenthesizedExpression
41
+ );
42
+ }