@atomic-ehr/fhirpath 0.0.1-canary.0c6931e.20250727185306

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 (85) hide show
  1. package/README.md +473 -0
  2. package/dist/index.d.ts +462 -0
  3. package/dist/index.js +10307 -0
  4. package/dist/index.js.map +1 -0
  5. package/package.json +58 -0
  6. package/src/analyzer/analyzer.ts +499 -0
  7. package/src/analyzer/model-provider.ts +244 -0
  8. package/src/analyzer/schemas/index.ts +2 -0
  9. package/src/analyzer/schemas/types.ts +40 -0
  10. package/src/analyzer/types.ts +142 -0
  11. package/src/api/builder.ts +157 -0
  12. package/src/api/errors.ts +145 -0
  13. package/src/api/expression.ts +156 -0
  14. package/src/api/index.ts +122 -0
  15. package/src/api/inspect.ts +99 -0
  16. package/src/api/registry.ts +128 -0
  17. package/src/api/types.ts +210 -0
  18. package/src/compiler/compiler.ts +546 -0
  19. package/src/compiler/index.ts +2 -0
  20. package/src/compiler/prototype-context-adapter.ts +99 -0
  21. package/src/compiler/types.ts +24 -0
  22. package/src/index.ts +107 -0
  23. package/src/interpreter/README.md +78 -0
  24. package/src/interpreter/interpreter.ts +475 -0
  25. package/src/interpreter/types.ts +108 -0
  26. package/src/lexer/char-tables.ts +37 -0
  27. package/src/lexer/errors.ts +31 -0
  28. package/src/lexer/index.ts +5 -0
  29. package/src/lexer/lexer.ts +745 -0
  30. package/src/lexer/token.ts +104 -0
  31. package/src/lexer2/index.md +232 -0
  32. package/src/lexer2/index.perf.test.ts +68 -0
  33. package/src/lexer2/index.test.ts +549 -0
  34. package/src/lexer2/index.ts +1251 -0
  35. package/src/lexer2/notes.md +173 -0
  36. package/src/lexer2/optimization-summary.md +718 -0
  37. package/src/parser/ast-factory.ts +220 -0
  38. package/src/parser/ast.ts +144 -0
  39. package/src/parser/collection-parser.ts +89 -0
  40. package/src/parser/diagnostic-messages.ts +216 -0
  41. package/src/parser/diagnostics.ts +85 -0
  42. package/src/parser/error-reporter.ts +230 -0
  43. package/src/parser/index.ts +3 -0
  44. package/src/parser/literal-parser.ts +103 -0
  45. package/src/parser/parse-error.ts +16 -0
  46. package/src/parser/parser-error-factory.ts +141 -0
  47. package/src/parser/parser-state.ts +134 -0
  48. package/src/parser/parser.ts +1272 -0
  49. package/src/parser/pprint.ts +169 -0
  50. package/src/parser/precedence-manager.ts +64 -0
  51. package/src/parser/source-mapper.ts +248 -0
  52. package/src/parser/special-constructs.ts +142 -0
  53. package/src/parser/token-navigator.ts +110 -0
  54. package/src/parser/types.ts +60 -0
  55. package/src/parser2/index.md +177 -0
  56. package/src/parser2/index.perf.test.ts +184 -0
  57. package/src/parser2/index.test.ts +305 -0
  58. package/src/parser2/index.ts +578 -0
  59. package/src/parser2/optimization-summary.md +176 -0
  60. package/src/registry/default-analyzers.ts +257 -0
  61. package/src/registry/default-compilers.ts +31 -0
  62. package/src/registry/index.ts +96 -0
  63. package/src/registry/operations/arithmetic.ts +506 -0
  64. package/src/registry/operations/collection.ts +425 -0
  65. package/src/registry/operations/comparison.ts +432 -0
  66. package/src/registry/operations/existence.ts +703 -0
  67. package/src/registry/operations/filtering.ts +358 -0
  68. package/src/registry/operations/literals.ts +341 -0
  69. package/src/registry/operations/logical.ts +439 -0
  70. package/src/registry/operations/math.ts +128 -0
  71. package/src/registry/operations/membership.ts +132 -0
  72. package/src/registry/operations/navigation.ts +52 -0
  73. package/src/registry/operations/string.ts +507 -0
  74. package/src/registry/operations/subsetting.ts +174 -0
  75. package/src/registry/operations/type-checking.ts +162 -0
  76. package/src/registry/operations/type-conversion.ts +404 -0
  77. package/src/registry/operations/type-operators.ts +308 -0
  78. package/src/registry/operations/utility.ts +644 -0
  79. package/src/registry/registry.ts +146 -0
  80. package/src/registry/types.ts +161 -0
  81. package/src/registry/utils/evaluation-helpers.ts +93 -0
  82. package/src/registry/utils/index.ts +3 -0
  83. package/src/registry/utils/type-system.ts +173 -0
  84. package/src/runtime/context.ts +158 -0
  85. package/src/runtime/debug-context.ts +135 -0
@@ -0,0 +1,578 @@
1
+ import { Lexer, TokenType } from '../lexer2';
2
+ import type { Token } from '../lexer2';
3
+
4
+ // AST Types
5
+ export interface Position {
6
+ line: number;
7
+ column: number;
8
+ offset: number;
9
+ }
10
+
11
+ export enum NodeType {
12
+ // Navigation
13
+ Identifier,
14
+ TypeOrIdentifier,
15
+
16
+ // Operators
17
+ Binary,
18
+ Unary,
19
+ Union,
20
+
21
+ // Functions
22
+ Function,
23
+
24
+ // Literals
25
+ Literal,
26
+ Variable,
27
+ Collection,
28
+
29
+ // Type operations
30
+ MembershipTest,
31
+ TypeCast,
32
+ TypeReference,
33
+
34
+ // Special
35
+ Index,
36
+ }
37
+
38
+ export interface ASTNode {
39
+ type: NodeType;
40
+ position: Position;
41
+ }
42
+
43
+ export interface IdentifierNode extends ASTNode {
44
+ type: NodeType.Identifier;
45
+ name: string;
46
+ }
47
+
48
+ export interface TypeOrIdentifierNode extends ASTNode {
49
+ type: NodeType.TypeOrIdentifier;
50
+ name: string;
51
+ }
52
+
53
+ export interface LiteralNode extends ASTNode {
54
+ type: NodeType.Literal;
55
+ value: any;
56
+ valueType: 'string' | 'number' | 'boolean' | 'date' | 'time' | 'datetime' | 'null';
57
+ }
58
+
59
+ export interface BinaryNode extends ASTNode {
60
+ type: NodeType.Binary;
61
+ operator: TokenType;
62
+ left: ASTNode;
63
+ right: ASTNode;
64
+ }
65
+
66
+ export interface UnaryNode extends ASTNode {
67
+ type: NodeType.Unary;
68
+ operator: TokenType;
69
+ operand: ASTNode;
70
+ }
71
+
72
+ export interface FunctionNode extends ASTNode {
73
+ type: NodeType.Function;
74
+ name: ASTNode;
75
+ arguments: ASTNode[];
76
+ }
77
+
78
+ export interface VariableNode extends ASTNode {
79
+ type: NodeType.Variable;
80
+ name: string;
81
+ }
82
+
83
+ export interface IndexNode extends ASTNode {
84
+ type: NodeType.Index;
85
+ expression: ASTNode;
86
+ index: ASTNode;
87
+ }
88
+
89
+ export interface UnionNode extends ASTNode {
90
+ type: NodeType.Union;
91
+ operands: ASTNode[];
92
+ }
93
+
94
+ export interface MembershipTestNode extends ASTNode {
95
+ type: NodeType.MembershipTest;
96
+ expression: ASTNode;
97
+ targetType: string;
98
+ }
99
+
100
+ export interface TypeCastNode extends ASTNode {
101
+ type: NodeType.TypeCast;
102
+ expression: ASTNode;
103
+ targetType: string;
104
+ }
105
+
106
+ export interface CollectionNode extends ASTNode {
107
+ type: NodeType.Collection;
108
+ elements: ASTNode[];
109
+ }
110
+
111
+ export interface TypeReferenceNode extends ASTNode {
112
+ type: NodeType.TypeReference;
113
+ typeName: string;
114
+ }
115
+
116
+ export class Parser {
117
+ private lexer: Lexer;
118
+ private tokens: Token[] = [];
119
+ private current = 0;
120
+
121
+ constructor(input: string) {
122
+ this.lexer = new Lexer(input);
123
+ this.tokens = this.lexer.tokenize();
124
+ }
125
+
126
+ parse(): ASTNode {
127
+ const expr = this.expression();
128
+ if (!this.isAtEnd()) {
129
+ throw new Error(`Unexpected token: ${this.lexer.getTokenValue(this.peek())}`);
130
+ }
131
+ return expr;
132
+ }
133
+
134
+ private expression(): ASTNode {
135
+ return this.parseExpressionWithPrecedence(0);
136
+ }
137
+
138
+ private parseExpressionWithPrecedence(minPrecedence: number): ASTNode {
139
+ let left = this.parsePrimary();
140
+
141
+ // Inline isAtEnd() and peek() for hot path
142
+ while (this.current < this.tokens.length) {
143
+ const token = this.tokens[this.current];
144
+ if (!token || token.type === TokenType.EOF) break;
145
+
146
+ const precedence = this.getPrecedence(token.type);
147
+
148
+ if (precedence < minPrecedence) break;
149
+
150
+ if (token.type === TokenType.DOT) {
151
+ this.current++; // inline advance()
152
+ const right = this.parseInvocation();
153
+ left = this.createBinaryNode(token, left, right);
154
+ } else if (this.isBinaryOperator(token.type)) {
155
+ this.current++; // inline advance()
156
+ const associativity = this.getAssociativity(token.type);
157
+ const nextMinPrecedence = associativity === 'left' ? precedence + 1 : precedence;
158
+ const right = this.parseExpressionWithPrecedence(nextMinPrecedence);
159
+
160
+ if (token.type === TokenType.PIPE && left.type === NodeType.Union) {
161
+ (left as UnionNode).operands.push(right);
162
+ } else if (token.type === TokenType.PIPE) {
163
+ left = this.createUnionNode([left, right], this.getPosition(token));
164
+ } else {
165
+ left = this.createBinaryNode(token, left, right);
166
+ }
167
+ } else if (token.type === TokenType.IS) {
168
+ this.current++; // inline advance()
169
+ const typeName = this.parseTypeName();
170
+ left = this.createMembershipTestNode(left, typeName, this.getPosition(token));
171
+ } else if (token.type === TokenType.AS) {
172
+ this.current++; // inline advance()
173
+ const typeName = this.parseTypeName();
174
+ left = this.createTypeCastNode(left, typeName, this.getPosition(token));
175
+ } else if (token.type === TokenType.LBRACKET) {
176
+ this.current++; // inline advance()
177
+ const index = this.expression();
178
+ this.consume(TokenType.RBRACKET, "Expected ']'");
179
+ left = this.createIndexNode(left, index, this.getPosition(token));
180
+ } else if (token.type === TokenType.LPAREN && this.isFunctionCall(left)) {
181
+ const parenToken = token;
182
+ this.current++; // inline advance()
183
+ const args = this.parseArgumentList();
184
+ this.consume(TokenType.RPAREN, "Expected ')'");
185
+ left = this.createFunctionNode(left, args, left.position);
186
+ } else {
187
+ break;
188
+ }
189
+ }
190
+
191
+ return left;
192
+ }
193
+
194
+ private parsePrimary(): ASTNode {
195
+ // Inline peek() for hot path
196
+ const token = this.current < this.tokens.length ? this.tokens[this.current] : { type: TokenType.EOF, start: 0, end: 0, line: 1, column: 1 };
197
+
198
+ if (token.type === TokenType.NUMBER) {
199
+ this.current++; // inline advance()
200
+ return this.createLiteralNode(parseFloat(this.lexer.getTokenValue(token)), 'number', token);
201
+ }
202
+
203
+ if (token.type === TokenType.STRING) {
204
+ this.current++; // inline advance()
205
+ const value = this.parseStringValue(this.lexer.getTokenValue(token));
206
+ return this.createLiteralNode(value, 'string', token);
207
+ }
208
+
209
+ if (token.type === TokenType.TRUE || token.type === TokenType.FALSE) {
210
+ this.advance();
211
+ return this.createLiteralNode(token.type === TokenType.TRUE, 'boolean', token);
212
+ }
213
+
214
+ if (token.type === TokenType.NULL || (token.type === TokenType.IDENTIFIER && this.lexer.getTokenValue(token) === 'null')) {
215
+ this.advance();
216
+ return this.createLiteralNode(null, 'null', token);
217
+ }
218
+
219
+ if (token.type === TokenType.DATETIME) {
220
+ this.advance();
221
+ const value = this.lexer.getTokenValue(token).substring(1); // Remove @
222
+ return this.createLiteralNode(value, 'datetime', token);
223
+ }
224
+
225
+ if (token.type === TokenType.TIME) {
226
+ this.advance();
227
+ const value = this.lexer.getTokenValue(token).substring(1); // Remove @
228
+ return this.createLiteralNode(value, 'time', token);
229
+ }
230
+
231
+ if (token.type === TokenType.THIS || token.type === TokenType.INDEX || token.type === TokenType.TOTAL) {
232
+ this.advance();
233
+ return this.createVariableNode(this.lexer.getTokenValue(token), token);
234
+ }
235
+
236
+ if (token.type === TokenType.ENV_VAR) {
237
+ this.advance();
238
+ const value = this.lexer.getTokenValue(token);
239
+ return this.createVariableNode(value, token);
240
+ }
241
+
242
+ if (token.type === TokenType.IDENTIFIER ||
243
+ token.type === TokenType.DELIMITED_IDENTIFIER ||
244
+ this.isKeywordAllowedAsIdentifier(token.type)) {
245
+ this.advance();
246
+ const name = this.parseIdentifierValue(this.lexer.getTokenValue(token));
247
+ return this.createIdentifierNode(name, token);
248
+ }
249
+
250
+ if (token.type === TokenType.LPAREN) {
251
+ this.advance();
252
+ const expr = this.expression();
253
+ this.consume(TokenType.RPAREN, "Expected ')'");
254
+ return expr;
255
+ }
256
+
257
+ if (token.type === TokenType.LBRACE) {
258
+ this.advance();
259
+ const elements = this.parseCollectionElements();
260
+ this.consume(TokenType.RBRACE, "Expected '}'");
261
+ return this.createCollectionNode(elements, this.getPosition(token));
262
+ }
263
+
264
+ if (token.type === TokenType.PLUS || token.type === TokenType.MINUS) {
265
+ this.advance();
266
+ const operand = this.parseExpressionWithPrecedence(this.getPrecedence(TokenType.MULTIPLY));
267
+ return this.createUnaryNode(token, operand);
268
+ }
269
+
270
+ throw new Error(`Unexpected token: ${this.lexer.getTokenValue(token)}`);
271
+ }
272
+
273
+ private parseInvocation(): ASTNode {
274
+ const token = this.peek();
275
+
276
+ // Allow identifiers and keywords that can be used as member names
277
+ if (token.type === TokenType.IDENTIFIER ||
278
+ token.type === TokenType.DELIMITED_IDENTIFIER ||
279
+ this.isKeywordAllowedAsMember(token.type)) {
280
+ this.advance();
281
+ const name = this.parseIdentifierValue(this.lexer.getTokenValue(token));
282
+ const node = this.createIdentifierNode(name, token);
283
+
284
+ // Check if this is a function call
285
+ if (this.check(TokenType.LPAREN)) {
286
+ this.advance();
287
+ const args = this.parseArgumentList();
288
+ this.consume(TokenType.RPAREN, "Expected ')'");
289
+ return this.createFunctionNode(node, args, node.position);
290
+ }
291
+
292
+ return node;
293
+ }
294
+
295
+ // Allow environment variables after dot (like .%resource)
296
+ if (token.type === TokenType.ENV_VAR) {
297
+ this.advance();
298
+ const value = this.lexer.getTokenValue(token);
299
+ return this.createVariableNode(value, token);
300
+ }
301
+
302
+ throw new Error(`Expected identifier after '.', got: ${this.lexer.getTokenValue(token)}`);
303
+ }
304
+
305
+ private isKeywordAllowedAsMember(type: TokenType): boolean {
306
+ // Keywords that can be used as member names
307
+ return [
308
+ TokenType.CONTAINS,
309
+ TokenType.AND,
310
+ TokenType.OR,
311
+ TokenType.XOR,
312
+ TokenType.IMPLIES,
313
+ TokenType.AS,
314
+ TokenType.IS,
315
+ TokenType.DIV,
316
+ TokenType.MOD,
317
+ TokenType.IN,
318
+ TokenType.TRUE,
319
+ TokenType.FALSE
320
+ ].includes(type);
321
+ }
322
+
323
+ private isKeywordAllowedAsIdentifier(type: TokenType): boolean {
324
+ // Keywords that can be used as identifiers in certain contexts
325
+ return this.isKeywordAllowedAsMember(type);
326
+ }
327
+
328
+ private parseArgumentList(): ASTNode[] {
329
+ const args: ASTNode[] = [];
330
+
331
+ if (this.peek().type === TokenType.RPAREN) {
332
+ return args;
333
+ }
334
+
335
+ args.push(this.expression());
336
+
337
+ while (this.match(TokenType.COMMA)) {
338
+ args.push(this.expression());
339
+ }
340
+
341
+ return args;
342
+ }
343
+
344
+ private parseCollectionElements(): ASTNode[] {
345
+ const elements: ASTNode[] = [];
346
+
347
+ if (this.peek().type === TokenType.RBRACE) {
348
+ return elements;
349
+ }
350
+
351
+ elements.push(this.expression());
352
+
353
+ while (this.match(TokenType.COMMA)) {
354
+ elements.push(this.expression());
355
+ }
356
+
357
+ return elements;
358
+ }
359
+
360
+ private parseTypeName(): string {
361
+ const token = this.advance();
362
+ if (token.type !== TokenType.IDENTIFIER && token.type !== TokenType.DELIMITED_IDENTIFIER) {
363
+ throw new Error(`Expected type name, got: ${this.lexer.getTokenValue(token)}`);
364
+ }
365
+ return this.parseIdentifierValue(this.lexer.getTokenValue(token));
366
+ }
367
+
368
+ private parseStringValue(raw: string): string {
369
+ // Remove quotes and handle escape sequences
370
+ const content = raw.slice(1, -1);
371
+ return content.replace(/\\(.)/g, (_, char) => {
372
+ switch (char) {
373
+ case 'n': return '\n';
374
+ case 'r': return '\r';
375
+ case 't': return '\t';
376
+ case 'f': return '\f';
377
+ case '\\': return '\\';
378
+ case "'": return "'";
379
+ case '"': return '"';
380
+ case '`': return '`';
381
+ case '/': return '/';
382
+ default: return char;
383
+ }
384
+ });
385
+ }
386
+
387
+ private parseIdentifierValue(raw: string): string {
388
+ if (raw.startsWith('`')) {
389
+ // Delimited identifier - remove backticks and handle escapes
390
+ return raw.slice(1, -1).replace(/\\(.)/g, '$1');
391
+ }
392
+ return raw;
393
+ }
394
+
395
+ private isFunctionCall(node: ASTNode): boolean {
396
+ return node.type === NodeType.Identifier || node.type === NodeType.TypeOrIdentifier;
397
+ }
398
+
399
+ private isBinaryOperator(type: TokenType): boolean {
400
+ return [
401
+ TokenType.PLUS, TokenType.MINUS, TokenType.MULTIPLY, TokenType.DIVIDE,
402
+ TokenType.DIV, TokenType.MOD, TokenType.AMPERSAND, TokenType.PIPE,
403
+ TokenType.LT, TokenType.GT, TokenType.LTE, TokenType.GTE,
404
+ TokenType.EQ, TokenType.NEQ, TokenType.SIMILAR, TokenType.NOT_SIMILAR,
405
+ TokenType.AND, TokenType.OR, TokenType.XOR, TokenType.IMPLIES,
406
+ TokenType.IN, TokenType.CONTAINS
407
+ ].includes(type);
408
+ }
409
+
410
+ private getPrecedence(type: TokenType): number {
411
+ // Extract precedence from high byte using bit shift
412
+ return type >>> 8;
413
+ }
414
+
415
+ private getAssociativity(type: TokenType): 'left' | 'right' {
416
+ // Most operators are left associative
417
+ // Only implies is right associative
418
+ return type === TokenType.IMPLIES ? 'right' : 'left';
419
+ }
420
+
421
+ private getPosition(token: Token): Position {
422
+ return {
423
+ line: token.line,
424
+ column: token.column,
425
+ offset: token.start
426
+ };
427
+ }
428
+
429
+ private createIdentifierNode(name: string, token: Token): ASTNode {
430
+ const position = this.getPosition(token);
431
+
432
+ // Check if it's a type (starts with uppercase)
433
+ if (name[0] && name[0] >= 'A' && name[0] <= 'Z') {
434
+ return {
435
+ type: NodeType.TypeOrIdentifier,
436
+ name,
437
+ position
438
+ } as TypeOrIdentifierNode;
439
+ }
440
+
441
+ return {
442
+ type: NodeType.Identifier,
443
+ name,
444
+ position
445
+ } as IdentifierNode;
446
+ }
447
+
448
+ private createLiteralNode(value: any, valueType: LiteralNode['valueType'], token: Token): LiteralNode {
449
+ return {
450
+ type: NodeType.Literal,
451
+ value,
452
+ valueType,
453
+ position: this.getPosition(token)
454
+ };
455
+ }
456
+
457
+ private createBinaryNode(token: Token, left: ASTNode, right: ASTNode): BinaryNode {
458
+ return {
459
+ type: NodeType.Binary,
460
+ operator: token.type,
461
+ left,
462
+ right,
463
+ position: this.getPosition(token)
464
+ };
465
+ }
466
+
467
+ private createUnaryNode(token: Token, operand: ASTNode): UnaryNode {
468
+ return {
469
+ type: NodeType.Unary,
470
+ operator: token.type,
471
+ operand,
472
+ position: this.getPosition(token)
473
+ };
474
+ }
475
+
476
+ private createFunctionNode(name: ASTNode, args: ASTNode[], position: Position): FunctionNode {
477
+ return {
478
+ type: NodeType.Function,
479
+ name,
480
+ arguments: args,
481
+ position
482
+ };
483
+ }
484
+
485
+ private createVariableNode(name: string, token: Token): VariableNode {
486
+ return {
487
+ type: NodeType.Variable,
488
+ name,
489
+ position: this.getPosition(token)
490
+ };
491
+ }
492
+
493
+ private createIndexNode(expression: ASTNode, index: ASTNode, position: Position): IndexNode {
494
+ return {
495
+ type: NodeType.Index,
496
+ expression,
497
+ index,
498
+ position
499
+ };
500
+ }
501
+
502
+ private createUnionNode(operands: ASTNode[], position: Position): UnionNode {
503
+ return {
504
+ type: NodeType.Union,
505
+ operands,
506
+ position
507
+ };
508
+ }
509
+
510
+ private createMembershipTestNode(expression: ASTNode, targetType: string, position: Position): MembershipTestNode {
511
+ return {
512
+ type: NodeType.MembershipTest,
513
+ expression,
514
+ targetType,
515
+ position
516
+ };
517
+ }
518
+
519
+ private createTypeCastNode(expression: ASTNode, targetType: string, position: Position): TypeCastNode {
520
+ return {
521
+ type: NodeType.TypeCast,
522
+ expression,
523
+ targetType,
524
+ position
525
+ };
526
+ }
527
+
528
+ private createCollectionNode(elements: ASTNode[], position: Position): CollectionNode {
529
+ return {
530
+ type: NodeType.Collection,
531
+ elements,
532
+ position
533
+ };
534
+ }
535
+
536
+ // Helper methods
537
+ private peek(): Token {
538
+ return this.tokens[this.current] || { type: TokenType.EOF, start: 0, end: 0, line: 1, column: 1 };
539
+ }
540
+
541
+ private previous(): Token {
542
+ return this.tokens[this.current - 1] || { type: TokenType.EOF, start: 0, end: 0, line: 1, column: 1 };
543
+ }
544
+
545
+ private isAtEnd(): boolean {
546
+ return this.current >= this.tokens.length || this.peek().type === TokenType.EOF;
547
+ }
548
+
549
+ private advance(): Token {
550
+ if (!this.isAtEnd()) this.current++;
551
+ return this.previous();
552
+ }
553
+
554
+ private check(type: TokenType): boolean {
555
+ if (this.isAtEnd()) return false;
556
+ return this.peek().type === type;
557
+ }
558
+
559
+ private match(...types: TokenType[]): boolean {
560
+ for (const type of types) {
561
+ if (this.check(type)) {
562
+ this.advance();
563
+ return true;
564
+ }
565
+ }
566
+ return false;
567
+ }
568
+
569
+ private consume(type: TokenType, message: string): Token {
570
+ if (this.check(type)) return this.advance();
571
+ throw new Error(message + ` at token: ${this.lexer.getTokenValue(this.peek())}`);
572
+ }
573
+ }
574
+
575
+ export function parse(input: string): ASTNode {
576
+ const parser = new Parser(input);
577
+ return parser.parse();
578
+ }