air-dml 1.2.9 → 2.1.0

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.
@@ -0,0 +1,776 @@
1
+ import { TokenType } from './tokens';
2
+ export class ParseError extends Error {
3
+ constructor(message, position, code) {
4
+ super(`[${position.line}:${position.column}] ${message}`);
5
+ this.position = position;
6
+ this.code = code;
7
+ this.name = 'ParseError';
8
+ }
9
+ }
10
+ export class Parser {
11
+ constructor(tokens) {
12
+ this.pos = 0;
13
+ this.errors = [];
14
+ this.pendingComments = [];
15
+ this.tokens = tokens;
16
+ }
17
+ parse() {
18
+ this.pos = 0;
19
+ this.errors = [];
20
+ this.pendingComments = [];
21
+ const ast = this.parseProgram();
22
+ return { ast, errors: this.errors };
23
+ }
24
+ parseProgram() {
25
+ const start = this.currentPosition();
26
+ let project;
27
+ const tables = [];
28
+ const refs = [];
29
+ const areas = [];
30
+ while (!this.isAtEnd()) {
31
+ this.collectComments();
32
+ if (this.isAtEnd())
33
+ break;
34
+ try {
35
+ const leadingComments = this.consumePendingComments();
36
+ if (this.check(TokenType.PROJECT)) {
37
+ project = this.parseProject();
38
+ if (leadingComments.length > 0) {
39
+ project.leadingComments = leadingComments;
40
+ }
41
+ }
42
+ else if (this.check(TokenType.TABLE)) {
43
+ const table = this.parseTable();
44
+ if (leadingComments.length > 0) {
45
+ table.leadingComments = leadingComments;
46
+ }
47
+ tables.push(table);
48
+ }
49
+ else if (this.check(TokenType.REF)) {
50
+ const ref = this.parseRef();
51
+ if (leadingComments.length > 0) {
52
+ ref.leadingComments = leadingComments;
53
+ }
54
+ refs.push(ref);
55
+ }
56
+ else if (this.check(TokenType.AREA)) {
57
+ const area = this.parseArea();
58
+ if (leadingComments.length > 0) {
59
+ area.leadingComments = leadingComments;
60
+ }
61
+ areas.push(area);
62
+ }
63
+ else if (this.check(TokenType.EOF)) {
64
+ break;
65
+ }
66
+ else {
67
+ const token = this.peek();
68
+ this.error(`予期しないトークンです: '${token.value}'`, 'UNEXPECTED_TOKEN');
69
+ this.advance();
70
+ }
71
+ }
72
+ catch (e) {
73
+ if (e instanceof ParseError) {
74
+ this.errors.push(e);
75
+ this.synchronize();
76
+ }
77
+ else {
78
+ throw e;
79
+ }
80
+ }
81
+ }
82
+ return {
83
+ kind: 'Program',
84
+ range: { start, end: this.currentPosition() },
85
+ project,
86
+ tables,
87
+ refs,
88
+ areas,
89
+ };
90
+ }
91
+ parseProject() {
92
+ const start = this.currentPosition();
93
+ this.expect(TokenType.PROJECT);
94
+ const name = this.parseNameOrString();
95
+ const settings = this.parseProjectBody();
96
+ return {
97
+ kind: 'Project',
98
+ range: { start, end: this.currentPosition() },
99
+ name,
100
+ settings,
101
+ };
102
+ }
103
+ parseProjectBody() {
104
+ const settings = {};
105
+ if (!this.check(TokenType.LBRACE)) {
106
+ return settings;
107
+ }
108
+ this.advance();
109
+ while (!this.check(TokenType.RBRACE) && !this.isAtEnd()) {
110
+ this.collectComments();
111
+ if (this.check(TokenType.RBRACE))
112
+ break;
113
+ if (this.check(TokenType.DATABASE_TYPE)) {
114
+ this.advance();
115
+ this.expect(TokenType.COLON);
116
+ settings.databaseType = this.parseStringValue();
117
+ }
118
+ else if (this.check(TokenType.NOTE)) {
119
+ this.advance();
120
+ this.expect(TokenType.COLON);
121
+ settings.note = this.parseStringValue();
122
+ }
123
+ else {
124
+ this.advance();
125
+ }
126
+ }
127
+ this.expect(TokenType.RBRACE);
128
+ return settings;
129
+ }
130
+ parseTable() {
131
+ const start = this.currentPosition();
132
+ this.expect(TokenType.TABLE);
133
+ const name = this.parseIdentifier();
134
+ const settings = this.parseTableSettings();
135
+ const { columns, indexes, note } = this.parseTableBody();
136
+ return {
137
+ kind: 'Table',
138
+ range: { start, end: this.currentPosition() },
139
+ name,
140
+ columns,
141
+ indexes: indexes.length > 0 ? indexes : undefined,
142
+ settings,
143
+ note,
144
+ };
145
+ }
146
+ parseTableSettings() {
147
+ const settings = {};
148
+ if (!this.check(TokenType.LBRACKET)) {
149
+ return settings;
150
+ }
151
+ this.advance();
152
+ while (!this.check(TokenType.RBRACKET) && !this.isAtEnd()) {
153
+ if (this.check(TokenType.ALIAS)) {
154
+ this.advance();
155
+ this.expect(TokenType.COLON);
156
+ settings.alias = this.parseStringValue();
157
+ }
158
+ else if (this.check(TokenType.POS_X)) {
159
+ this.advance();
160
+ this.expect(TokenType.COLON);
161
+ settings.posX = this.parseNumberValue();
162
+ }
163
+ else if (this.check(TokenType.POS_Y)) {
164
+ this.advance();
165
+ this.expect(TokenType.COLON);
166
+ settings.posY = this.parseNumberValue();
167
+ }
168
+ else if (this.check(TokenType.COLOR)) {
169
+ this.advance();
170
+ this.expect(TokenType.COLON);
171
+ settings.color = this.parseStringValue();
172
+ }
173
+ else if (this.check(TokenType.COMMA)) {
174
+ this.advance();
175
+ }
176
+ else {
177
+ this.advance();
178
+ }
179
+ }
180
+ this.expect(TokenType.RBRACKET);
181
+ return settings;
182
+ }
183
+ parseTableBody() {
184
+ const columns = [];
185
+ const indexes = [];
186
+ let note;
187
+ this.expect(TokenType.LBRACE);
188
+ while (!this.check(TokenType.RBRACE) && !this.isAtEnd()) {
189
+ this.collectComments();
190
+ if (this.check(TokenType.RBRACE))
191
+ break;
192
+ if (this.isTopLevelKeyword()) {
193
+ this.error('テーブル定義が閉じられていません。"}" が必要です', 'UNCLOSED_TABLE');
194
+ break;
195
+ }
196
+ if (this.check(TokenType.INDEXES)) {
197
+ const parsedIndexes = this.parseIndexes();
198
+ indexes.push(...parsedIndexes);
199
+ }
200
+ else if (this.check(TokenType.NOTE)) {
201
+ note = this.parseInlineNote();
202
+ }
203
+ else if (this.isColumnIdentifier()) {
204
+ const leadingComments = this.consumePendingComments();
205
+ const column = this.parseColumn();
206
+ if (leadingComments.length > 0) {
207
+ column.leadingComments = leadingComments;
208
+ }
209
+ columns.push(column);
210
+ }
211
+ else {
212
+ this.advance();
213
+ }
214
+ }
215
+ if (this.check(TokenType.RBRACE)) {
216
+ this.advance();
217
+ }
218
+ return { columns, indexes, note };
219
+ }
220
+ isTopLevelKeyword() {
221
+ const type = this.peek().type;
222
+ return (type === TokenType.PROJECT ||
223
+ type === TokenType.TABLE ||
224
+ type === TokenType.REF ||
225
+ type === TokenType.AREA);
226
+ }
227
+ isColumnIdentifier() {
228
+ const token = this.peek();
229
+ if (token.type === TokenType.IDENTIFIER || token.type === TokenType.STRING) {
230
+ return true;
231
+ }
232
+ if (this.isKeyword(token.type) && !this.isTopLevelKeyword()) {
233
+ return true;
234
+ }
235
+ return false;
236
+ }
237
+ parseColumn() {
238
+ const start = this.currentPosition();
239
+ const name = this.parseIdentifier();
240
+ const { type, typeParams } = this.parseColumnType();
241
+ const constraints = this.parseColumnConstraints();
242
+ return {
243
+ kind: 'Column',
244
+ range: { start, end: this.currentPosition() },
245
+ name,
246
+ type,
247
+ typeParams,
248
+ constraints,
249
+ };
250
+ }
251
+ parseColumnType() {
252
+ const type = this.parseIdentifier();
253
+ if (this.check(TokenType.LPAREN)) {
254
+ this.advance();
255
+ let params = '';
256
+ while (!this.check(TokenType.RPAREN) && !this.isAtEnd()) {
257
+ const token = this.advance();
258
+ params += token.value;
259
+ }
260
+ this.expect(TokenType.RPAREN);
261
+ return { type, typeParams: params };
262
+ }
263
+ return { type };
264
+ }
265
+ parseColumnConstraints() {
266
+ const constraints = {};
267
+ if (!this.check(TokenType.LBRACKET)) {
268
+ return constraints;
269
+ }
270
+ this.advance();
271
+ while (!this.check(TokenType.RBRACKET) && !this.isAtEnd()) {
272
+ if (this.check(TokenType.PK)) {
273
+ this.advance();
274
+ constraints.pk = true;
275
+ }
276
+ else if (this.check(TokenType.FK)) {
277
+ this.advance();
278
+ constraints.fk = true;
279
+ }
280
+ else if (this.check(TokenType.UNIQUE)) {
281
+ this.advance();
282
+ constraints.unique = true;
283
+ }
284
+ else if (this.check(TokenType.NOT)) {
285
+ this.advance();
286
+ if (this.check(TokenType.NULL)) {
287
+ this.advance();
288
+ }
289
+ constraints.notNull = true;
290
+ }
291
+ else if (this.check(TokenType.NULL)) {
292
+ this.advance();
293
+ }
294
+ else if (this.check(TokenType.INCREMENT)) {
295
+ this.advance();
296
+ constraints.increment = true;
297
+ }
298
+ else if (this.check(TokenType.ALIAS)) {
299
+ this.advance();
300
+ this.expect(TokenType.COLON);
301
+ constraints.alias = this.parseStringValue();
302
+ }
303
+ else if (this.check(TokenType.NOTE)) {
304
+ this.advance();
305
+ this.expect(TokenType.COLON);
306
+ constraints.note = this.parseStringValue();
307
+ }
308
+ else if (this.check(TokenType.COMMA)) {
309
+ this.advance();
310
+ }
311
+ else {
312
+ this.advance();
313
+ }
314
+ }
315
+ this.expect(TokenType.RBRACKET);
316
+ return constraints;
317
+ }
318
+ parseRef() {
319
+ const start = this.currentPosition();
320
+ this.expect(TokenType.REF);
321
+ let name;
322
+ if (this.check(TokenType.IDENTIFIER) && this.peekNext()?.type === TokenType.COLON) {
323
+ name = this.parseIdentifier();
324
+ }
325
+ this.expect(TokenType.COLON);
326
+ const from = this.parseRefEndpoint();
327
+ const relationType = this.parseRelationType();
328
+ const to = this.parseRefEndpoint();
329
+ const settings = this.parseRefSettings();
330
+ return {
331
+ kind: 'Ref',
332
+ range: { start, end: this.currentPosition() },
333
+ name,
334
+ from,
335
+ to,
336
+ relationType,
337
+ settings,
338
+ };
339
+ }
340
+ parseRefEndpoint() {
341
+ const table = this.parseIdentifier();
342
+ this.expect(TokenType.DOT);
343
+ const column = this.parseIdentifier();
344
+ return { table, column };
345
+ }
346
+ parseRelationType() {
347
+ if (this.check(TokenType.REF_GT)) {
348
+ this.advance();
349
+ return '>';
350
+ }
351
+ if (this.check(TokenType.REF_LT)) {
352
+ this.advance();
353
+ return '<';
354
+ }
355
+ if (this.check(TokenType.REF_LTGT)) {
356
+ this.advance();
357
+ return '<>';
358
+ }
359
+ if (this.check(TokenType.REF_DASH)) {
360
+ this.advance();
361
+ return '-';
362
+ }
363
+ if (this.check(TokenType.REF_TILDE)) {
364
+ this.advance();
365
+ return '~';
366
+ }
367
+ this.error('リレーション演算子が必要です(>, <, -, <>, ~)', 'EXPECTED_REF_OPERATOR');
368
+ return '>';
369
+ }
370
+ parseRefSettings() {
371
+ const settings = {};
372
+ if (!this.check(TokenType.LBRACKET)) {
373
+ return settings;
374
+ }
375
+ this.advance();
376
+ while (!this.check(TokenType.RBRACKET) && !this.isAtEnd()) {
377
+ if (this.check(TokenType.SWAP_EDGE)) {
378
+ this.advance();
379
+ this.expect(TokenType.COLON);
380
+ settings.swapEdge = this.parseBooleanValue();
381
+ }
382
+ else if (this.check(TokenType.NOTE)) {
383
+ this.advance();
384
+ this.expect(TokenType.COLON);
385
+ settings.note = this.parseStringValue();
386
+ }
387
+ else if (this.check(TokenType.COMMA)) {
388
+ this.advance();
389
+ }
390
+ else {
391
+ this.advance();
392
+ }
393
+ }
394
+ this.expect(TokenType.RBRACKET);
395
+ return settings;
396
+ }
397
+ parseArea() {
398
+ const start = this.currentPosition();
399
+ this.expect(TokenType.AREA);
400
+ const name = this.parseStringValue();
401
+ const settings = this.parseAreaSettings();
402
+ const { tables, commonColumns, note } = this.parseAreaBody();
403
+ return {
404
+ kind: 'Area',
405
+ range: { start, end: this.currentPosition() },
406
+ name,
407
+ tables,
408
+ settings,
409
+ commonColumns: commonColumns.length > 0 ? commonColumns : undefined,
410
+ note,
411
+ };
412
+ }
413
+ parseAreaSettings() {
414
+ const settings = {};
415
+ if (!this.check(TokenType.LBRACKET)) {
416
+ return settings;
417
+ }
418
+ this.advance();
419
+ while (!this.check(TokenType.RBRACKET) && !this.isAtEnd()) {
420
+ if (this.check(TokenType.POS_X)) {
421
+ this.advance();
422
+ this.expect(TokenType.COLON);
423
+ settings.posX = this.parseNumberValue();
424
+ }
425
+ else if (this.check(TokenType.POS_Y)) {
426
+ this.advance();
427
+ this.expect(TokenType.COLON);
428
+ settings.posY = this.parseNumberValue();
429
+ }
430
+ else if (this.check(TokenType.WIDTH)) {
431
+ this.advance();
432
+ this.expect(TokenType.COLON);
433
+ settings.width = this.parseNumberValue();
434
+ }
435
+ else if (this.check(TokenType.HEIGHT)) {
436
+ this.advance();
437
+ this.expect(TokenType.COLON);
438
+ settings.height = this.parseNumberValue();
439
+ }
440
+ else if (this.check(TokenType.COLOR)) {
441
+ this.advance();
442
+ this.expect(TokenType.COLON);
443
+ settings.color = this.parseStringValue();
444
+ }
445
+ else if (this.check(TokenType.DATABASE_TYPE)) {
446
+ this.advance();
447
+ this.expect(TokenType.COLON);
448
+ settings.databaseType = this.parseStringValue();
449
+ }
450
+ else if (this.check(TokenType.LABEL_HORIZONTAL)) {
451
+ this.advance();
452
+ this.expect(TokenType.COLON);
453
+ const val = this.parseStringValue();
454
+ if (val === 'left' || val === 'center' || val === 'right') {
455
+ settings.labelHorizontal = val;
456
+ }
457
+ }
458
+ else if (this.check(TokenType.LABEL_VERTICAL)) {
459
+ this.advance();
460
+ this.expect(TokenType.COLON);
461
+ const val = this.parseStringValue();
462
+ if (val === 'top' || val === 'center' || val === 'bottom') {
463
+ settings.labelVertical = val;
464
+ }
465
+ }
466
+ else if (this.check(TokenType.COMMA)) {
467
+ this.advance();
468
+ }
469
+ else {
470
+ this.advance();
471
+ }
472
+ }
473
+ this.expect(TokenType.RBRACKET);
474
+ return settings;
475
+ }
476
+ parseAreaBody() {
477
+ const tables = [];
478
+ const commonColumns = [];
479
+ let note;
480
+ this.expect(TokenType.LBRACE);
481
+ while (!this.check(TokenType.RBRACE) && !this.isAtEnd()) {
482
+ this.collectComments();
483
+ if (this.check(TokenType.RBRACE))
484
+ break;
485
+ if (this.check(TokenType.COMMON_COLUMNS)) {
486
+ const cols = this.parseCommonColumns();
487
+ commonColumns.push(...cols);
488
+ }
489
+ else if (this.check(TokenType.NOTE)) {
490
+ note = this.parseInlineNote();
491
+ }
492
+ else if (this.isIdentifierLike()) {
493
+ tables.push(this.parseIdentifier());
494
+ }
495
+ else {
496
+ this.advance();
497
+ }
498
+ }
499
+ this.expect(TokenType.RBRACE);
500
+ return { tables, commonColumns, note };
501
+ }
502
+ parseCommonColumns() {
503
+ const columns = [];
504
+ this.expect(TokenType.COMMON_COLUMNS);
505
+ this.expect(TokenType.COLON);
506
+ this.expect(TokenType.LBRACKET);
507
+ while (!this.check(TokenType.RBRACKET) && !this.isAtEnd()) {
508
+ this.collectComments();
509
+ if (this.check(TokenType.RBRACKET))
510
+ break;
511
+ if (this.isIdentifierLike()) {
512
+ const column = this.parseColumn();
513
+ this.attachComments(column);
514
+ columns.push(column);
515
+ }
516
+ else {
517
+ this.advance();
518
+ }
519
+ }
520
+ this.expect(TokenType.RBRACKET);
521
+ return columns;
522
+ }
523
+ parseIndexes() {
524
+ const indexes = [];
525
+ this.expect(TokenType.INDEXES);
526
+ this.expect(TokenType.LBRACE);
527
+ while (!this.check(TokenType.RBRACE) && !this.isAtEnd()) {
528
+ this.collectComments();
529
+ if (this.check(TokenType.RBRACE))
530
+ break;
531
+ if (this.check(TokenType.LPAREN) || this.isIdentifierLike()) {
532
+ const index = this.parseIndex();
533
+ this.attachComments(index);
534
+ indexes.push(index);
535
+ }
536
+ else {
537
+ this.advance();
538
+ }
539
+ }
540
+ this.expect(TokenType.RBRACE);
541
+ return indexes;
542
+ }
543
+ parseIndex() {
544
+ const start = this.currentPosition();
545
+ const columns = [];
546
+ if (this.check(TokenType.LPAREN)) {
547
+ this.advance();
548
+ while (!this.check(TokenType.RPAREN) && !this.isAtEnd()) {
549
+ if (this.isIdentifierLike()) {
550
+ columns.push(this.parseIdentifier());
551
+ }
552
+ if (this.check(TokenType.COMMA)) {
553
+ this.advance();
554
+ }
555
+ }
556
+ this.expect(TokenType.RPAREN);
557
+ }
558
+ else {
559
+ columns.push(this.parseIdentifier());
560
+ }
561
+ const settings = this.parseIndexSettings();
562
+ return {
563
+ kind: 'Index',
564
+ range: { start, end: this.currentPosition() },
565
+ columns,
566
+ settings,
567
+ };
568
+ }
569
+ parseIndexSettings() {
570
+ const settings = {};
571
+ if (!this.check(TokenType.LBRACKET)) {
572
+ return settings;
573
+ }
574
+ this.advance();
575
+ while (!this.check(TokenType.RBRACKET) && !this.isAtEnd()) {
576
+ if (this.check(TokenType.UNIQUE)) {
577
+ this.advance();
578
+ settings.unique = true;
579
+ }
580
+ else if (this.check(TokenType.PK)) {
581
+ this.advance();
582
+ settings.pk = true;
583
+ }
584
+ else if (this.check(TokenType.NAME)) {
585
+ this.advance();
586
+ this.expect(TokenType.COLON);
587
+ settings.name = this.parseStringValue();
588
+ }
589
+ else if (this.check(TokenType.COMMA)) {
590
+ this.advance();
591
+ }
592
+ else {
593
+ this.advance();
594
+ }
595
+ }
596
+ this.expect(TokenType.RBRACKET);
597
+ return settings;
598
+ }
599
+ parseInlineNote() {
600
+ this.expect(TokenType.NOTE);
601
+ this.expect(TokenType.COLON);
602
+ return this.parseStringValue();
603
+ }
604
+ parseIdentifier() {
605
+ const token = this.peek();
606
+ if (token.type === TokenType.IDENTIFIER) {
607
+ this.advance();
608
+ return token.value;
609
+ }
610
+ if (token.type === TokenType.STRING) {
611
+ this.advance();
612
+ return token.value;
613
+ }
614
+ if (this.isKeyword(token.type)) {
615
+ this.advance();
616
+ return token.value;
617
+ }
618
+ this.error('識別子が必要です', 'EXPECTED_IDENTIFIER');
619
+ return '';
620
+ }
621
+ parseNameOrString() {
622
+ const token = this.peek();
623
+ if (token.type === TokenType.STRING) {
624
+ this.advance();
625
+ return token.value;
626
+ }
627
+ if (token.type === TokenType.IDENTIFIER) {
628
+ this.advance();
629
+ return token.value;
630
+ }
631
+ this.error('名前または文字列が必要です', 'EXPECTED_NAME');
632
+ return '';
633
+ }
634
+ parseStringValue() {
635
+ const token = this.peek();
636
+ if (token.type === TokenType.STRING ||
637
+ token.type === TokenType.SINGLE_STRING ||
638
+ token.type === TokenType.BACKTICK_STRING) {
639
+ this.advance();
640
+ return token.value;
641
+ }
642
+ if (token.type === TokenType.IDENTIFIER) {
643
+ this.advance();
644
+ return token.value;
645
+ }
646
+ this.error('文字列が必要です', 'EXPECTED_STRING');
647
+ return '';
648
+ }
649
+ parseNumberValue() {
650
+ const token = this.peek();
651
+ if (token.type === TokenType.NUMBER) {
652
+ this.advance();
653
+ return parseFloat(token.value);
654
+ }
655
+ this.error('数値が必要です', 'EXPECTED_NUMBER');
656
+ return 0;
657
+ }
658
+ parseBooleanValue() {
659
+ const token = this.peek();
660
+ if (token.type === TokenType.IDENTIFIER) {
661
+ this.advance();
662
+ return token.value.toLowerCase() === 'true';
663
+ }
664
+ if (token.type === TokenType.NUMBER) {
665
+ this.advance();
666
+ return token.value !== '0';
667
+ }
668
+ this.advance();
669
+ return false;
670
+ }
671
+ isIdentifierLike() {
672
+ const token = this.peek();
673
+ return (token.type === TokenType.IDENTIFIER ||
674
+ token.type === TokenType.STRING ||
675
+ this.isKeyword(token.type));
676
+ }
677
+ isKeyword(type) {
678
+ return [
679
+ TokenType.PROJECT,
680
+ TokenType.TABLE,
681
+ TokenType.AREA,
682
+ TokenType.REF,
683
+ TokenType.NOTE,
684
+ TokenType.INDEXES,
685
+ TokenType.PK,
686
+ TokenType.FK,
687
+ TokenType.UNIQUE,
688
+ TokenType.NOT,
689
+ TokenType.NULL,
690
+ TokenType.INCREMENT,
691
+ TokenType.ALIAS,
692
+ TokenType.NAME,
693
+ ].includes(type);
694
+ }
695
+ peek() {
696
+ return this.tokens[this.pos];
697
+ }
698
+ peekNext() {
699
+ return this.tokens[this.pos + 1];
700
+ }
701
+ advance() {
702
+ const token = this.tokens[this.pos];
703
+ if (!this.isAtEnd()) {
704
+ this.pos++;
705
+ }
706
+ return token;
707
+ }
708
+ check(type) {
709
+ return this.peek().type === type;
710
+ }
711
+ expect(type) {
712
+ if (this.check(type)) {
713
+ return this.advance();
714
+ }
715
+ const token = this.peek();
716
+ const expected = this.tokenTypeName(type);
717
+ this.error(`'${expected}' が必要ですが、'${token.value}' が見つかりました`, 'UNEXPECTED_TOKEN');
718
+ return token;
719
+ }
720
+ isAtEnd() {
721
+ return this.peek().type === TokenType.EOF;
722
+ }
723
+ currentPosition() {
724
+ return this.peek().start;
725
+ }
726
+ collectComments() {
727
+ while (this.check(TokenType.LINE_COMMENT)) {
728
+ this.pendingComments.push(this.advance().value);
729
+ }
730
+ }
731
+ consumePendingComments() {
732
+ const comments = [...this.pendingComments];
733
+ this.pendingComments = [];
734
+ return comments;
735
+ }
736
+ attachComments(node) {
737
+ if (this.pendingComments.length > 0) {
738
+ node.leadingComments = [...this.pendingComments];
739
+ this.pendingComments = [];
740
+ }
741
+ }
742
+ error(message, code) {
743
+ throw new ParseError(message, this.currentPosition(), code);
744
+ }
745
+ synchronize() {
746
+ while (!this.isAtEnd()) {
747
+ const type = this.peek().type;
748
+ if (type === TokenType.RBRACE) {
749
+ this.advance();
750
+ return;
751
+ }
752
+ if (type === TokenType.PROJECT ||
753
+ type === TokenType.TABLE ||
754
+ type === TokenType.REF ||
755
+ type === TokenType.AREA) {
756
+ return;
757
+ }
758
+ this.advance();
759
+ }
760
+ }
761
+ tokenTypeName(type) {
762
+ const names = {
763
+ [TokenType.LBRACE]: '{',
764
+ [TokenType.RBRACE]: '}',
765
+ [TokenType.LBRACKET]: '[',
766
+ [TokenType.RBRACKET]: ']',
767
+ [TokenType.LPAREN]: '(',
768
+ [TokenType.RPAREN]: ')',
769
+ [TokenType.COLON]: ':',
770
+ [TokenType.COMMA]: ',',
771
+ [TokenType.DOT]: '.',
772
+ };
773
+ return names[type] ?? type;
774
+ }
775
+ }
776
+ //# sourceMappingURL=parser.js.map