skir-internal 0.0.1

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 (132) hide show
  1. package/README.md +2 -0
  2. package/dist/casing.d.ts +8 -0
  3. package/dist/casing.d.ts.map +1 -0
  4. package/dist/casing.js +43 -0
  5. package/dist/casing.js.map +1 -0
  6. package/dist/casing.test.d.ts.map +1 -0
  7. package/dist/casing.test.js +136 -0
  8. package/dist/casing.test.js.map +1 -0
  9. package/dist/command_line_parser.d.ts +33 -0
  10. package/dist/command_line_parser.d.ts.map +1 -0
  11. package/dist/command_line_parser.js +168 -0
  12. package/dist/command_line_parser.js.map +1 -0
  13. package/dist/command_line_parser.test.d.ts +2 -0
  14. package/dist/command_line_parser.test.d.ts.map +1 -0
  15. package/dist/command_line_parser.test.js +297 -0
  16. package/dist/command_line_parser.test.js.map +1 -0
  17. package/dist/compatibility_checker.d.ts +74 -0
  18. package/dist/compatibility_checker.d.ts.map +1 -0
  19. package/dist/compatibility_checker.js +341 -0
  20. package/dist/compatibility_checker.js.map +1 -0
  21. package/dist/compatibility_checker.test.d.ts +2 -0
  22. package/dist/compatibility_checker.test.d.ts.map +1 -0
  23. package/dist/compatibility_checker.test.js +582 -0
  24. package/dist/compatibility_checker.test.js.map +1 -0
  25. package/dist/compiler.d.ts.map +1 -0
  26. package/dist/compiler.js +375 -0
  27. package/dist/compiler.js.map +1 -0
  28. package/dist/config.d.ts +47 -0
  29. package/dist/config.d.ts.map +1 -0
  30. package/dist/config.js +23 -0
  31. package/dist/config.js.map +1 -0
  32. package/dist/definition_finder.d.ts +12 -0
  33. package/dist/definition_finder.d.ts.map +1 -0
  34. package/dist/definition_finder.js +180 -0
  35. package/dist/definition_finder.js.map +1 -0
  36. package/dist/definition_finder.test.d.ts +2 -0
  37. package/dist/definition_finder.test.d.ts.map +1 -0
  38. package/dist/definition_finder.test.js +164 -0
  39. package/dist/definition_finder.test.js.map +1 -0
  40. package/dist/doc_comment_parser.d.ts +3 -0
  41. package/dist/doc_comment_parser.d.ts.map +1 -0
  42. package/dist/doc_comment_parser.js +219 -0
  43. package/dist/doc_comment_parser.js.map +1 -0
  44. package/dist/doc_comment_parser.test.d.ts +2 -0
  45. package/dist/doc_comment_parser.test.d.ts.map +1 -0
  46. package/dist/doc_comment_parser.test.js +494 -0
  47. package/dist/doc_comment_parser.test.js.map +1 -0
  48. package/dist/encoding.d.ts +2 -0
  49. package/dist/encoding.d.ts.map +1 -0
  50. package/dist/encoding.js +38 -0
  51. package/dist/encoding.js.map +1 -0
  52. package/dist/encoding.test.d.ts +2 -0
  53. package/dist/encoding.test.d.ts.map +1 -0
  54. package/dist/encoding.test.js +23 -0
  55. package/dist/encoding.test.js.map +1 -0
  56. package/dist/error_renderer.d.ts +10 -0
  57. package/dist/error_renderer.d.ts.map +1 -0
  58. package/dist/error_renderer.js +266 -0
  59. package/dist/error_renderer.js.map +1 -0
  60. package/dist/formatter.d.ts +16 -0
  61. package/dist/formatter.d.ts.map +1 -0
  62. package/dist/formatter.js +220 -0
  63. package/dist/formatter.js.map +1 -0
  64. package/dist/formatter.test.d.ts +2 -0
  65. package/dist/formatter.test.d.ts.map +1 -0
  66. package/dist/formatter.test.js +390 -0
  67. package/dist/formatter.test.js.map +1 -0
  68. package/dist/formatter2.d.ts +3 -0
  69. package/dist/formatter2.d.ts.map +1 -0
  70. package/dist/formatter2.js +67 -0
  71. package/dist/formatter2.js.map +1 -0
  72. package/dist/index.d.ts +6 -0
  73. package/dist/index.d.ts.map +1 -0
  74. package/dist/index.js +5 -0
  75. package/dist/index.js.map +1 -0
  76. package/dist/index.test.d.ts.map +1 -0
  77. package/dist/index.test.js +14 -0
  78. package/dist/index.test.js.map +1 -0
  79. package/dist/io.d.ts.map +1 -0
  80. package/dist/io.js +22 -0
  81. package/dist/io.js.map +1 -0
  82. package/dist/language_server.d.ts +15 -0
  83. package/dist/language_server.d.ts.map +1 -0
  84. package/dist/language_server.js +248 -0
  85. package/dist/language_server.js.map +1 -0
  86. package/dist/literals.d.ts +13 -0
  87. package/dist/literals.d.ts.map +1 -0
  88. package/dist/literals.js +100 -0
  89. package/dist/literals.js.map +1 -0
  90. package/dist/literals.test.d.ts.map +1 -0
  91. package/dist/literals.test.js +149 -0
  92. package/dist/literals.test.js.map +1 -0
  93. package/dist/module_collector.d.ts +3 -0
  94. package/dist/module_collector.d.ts.map +1 -0
  95. package/dist/module_collector.js +22 -0
  96. package/dist/module_collector.js.map +1 -0
  97. package/dist/module_set.d.ts +40 -0
  98. package/dist/module_set.d.ts.map +1 -0
  99. package/dist/module_set.js +1178 -0
  100. package/dist/module_set.js.map +1 -0
  101. package/dist/module_set.test.d.ts.map +1 -0
  102. package/dist/module_set.test.js +1897 -0
  103. package/dist/module_set.test.js.map +1 -0
  104. package/dist/parser.d.ts +7 -0
  105. package/dist/parser.d.ts.map +1 -0
  106. package/dist/parser.js +1075 -0
  107. package/dist/parser.js.map +1 -0
  108. package/dist/parser.test.d.ts.map +1 -0
  109. package/dist/parser.test.js +1594 -0
  110. package/dist/parser.test.js.map +1 -0
  111. package/dist/project_initializer.d.ts +2 -0
  112. package/dist/project_initializer.d.ts.map +1 -0
  113. package/dist/project_initializer.js +30 -0
  114. package/dist/project_initializer.js.map +1 -0
  115. package/dist/snapshotter.d.ts +9 -0
  116. package/dist/snapshotter.d.ts.map +1 -0
  117. package/dist/snapshotter.js +144 -0
  118. package/dist/snapshotter.js.map +1 -0
  119. package/dist/tokenizer.d.ts +10 -0
  120. package/dist/tokenizer.d.ts.map +1 -0
  121. package/dist/tokenizer.js +198 -0
  122. package/dist/tokenizer.js.map +1 -0
  123. package/dist/tokenizer.test.d.ts.map +1 -0
  124. package/dist/tokenizer.test.js +441 -0
  125. package/dist/tokenizer.test.js.map +1 -0
  126. package/dist/types.d.ts +439 -0
  127. package/dist/types.d.ts.map +1 -0
  128. package/dist/types.js +2 -0
  129. package/dist/types.js.map +1 -0
  130. package/package.json +58 -0
  131. package/src/casing.ts +53 -0
  132. package/src/types.ts +585 -0
@@ -0,0 +1,1594 @@
1
+ import { expect } from "buckwheat";
2
+ import { describe, it } from "mocha";
3
+ import { parseModule } from "./parser.js";
4
+ import { tokenizeModule } from "./tokenizer.js";
5
+ function parse(content) {
6
+ const pathToModule = "path/to/module";
7
+ const tokenizerResult = tokenizeModule(content, pathToModule);
8
+ return parseModule(tokenizerResult.result);
9
+ }
10
+ describe("module parser", () => {
11
+ it("simple struct", () => {
12
+ const actualModule = parse(`
13
+ struct Point {
14
+ x: float32;
15
+ y: float32;
16
+ removed;
17
+ }`);
18
+ expect(actualModule).toMatch({
19
+ result: {
20
+ kind: "module",
21
+ path: "path/to/module",
22
+ nameToDeclaration: {
23
+ Point: {
24
+ kind: "record",
25
+ name: {
26
+ text: "Point",
27
+ },
28
+ recordType: "struct",
29
+ nameToDeclaration: {
30
+ x: {
31
+ kind: "field",
32
+ name: {
33
+ text: "x",
34
+ },
35
+ number: 0,
36
+ unresolvedType: {
37
+ kind: "primitive",
38
+ primitive: "float32",
39
+ },
40
+ isRecursive: false,
41
+ },
42
+ y: {
43
+ kind: "field",
44
+ name: {
45
+ text: "y",
46
+ },
47
+ number: 1,
48
+ unresolvedType: {
49
+ kind: "primitive",
50
+ primitive: "float32",
51
+ },
52
+ isRecursive: false,
53
+ },
54
+ },
55
+ fields: [
56
+ {
57
+ name: {
58
+ text: "x",
59
+ },
60
+ },
61
+ {
62
+ name: {
63
+ text: "y",
64
+ },
65
+ },
66
+ ],
67
+ nestedRecords: [],
68
+ removedNumbers: [2],
69
+ numSlots: 2,
70
+ numSlotsInclRemovedNumbers: 3,
71
+ },
72
+ },
73
+ },
74
+ errors: [],
75
+ });
76
+ });
77
+ it("struct with explicit numbering", () => {
78
+ const actualModule = parse(`
79
+ struct Point {
80
+ x: float32 = 1;
81
+ y: float32 = 0;
82
+ }`);
83
+ expect(actualModule).toMatch({
84
+ result: {
85
+ nameToDeclaration: {
86
+ Point: {
87
+ nameToDeclaration: {
88
+ x: {
89
+ number: 1,
90
+ },
91
+ y: {
92
+ number: 0,
93
+ },
94
+ },
95
+ },
96
+ },
97
+ },
98
+ errors: [],
99
+ });
100
+ });
101
+ it("struct with inline records", () => {
102
+ const actualModule = parse(`
103
+ struct Foo {
104
+ bar: struct {
105
+ x: float32;
106
+ y: float32;
107
+ };
108
+ }`);
109
+ expect(actualModule).toMatch({
110
+ result: {
111
+ nameToDeclaration: {
112
+ Foo: {
113
+ nameToDeclaration: {
114
+ bar: {
115
+ number: 0,
116
+ unresolvedType: {
117
+ nameParts: [
118
+ {
119
+ text: "Bar",
120
+ },
121
+ ],
122
+ },
123
+ },
124
+ Bar: {
125
+ name: {
126
+ text: "Bar",
127
+ },
128
+ nameToDeclaration: {
129
+ x: {
130
+ number: 0,
131
+ },
132
+ y: {
133
+ number: 1,
134
+ },
135
+ },
136
+ },
137
+ },
138
+ },
139
+ },
140
+ },
141
+ errors: [],
142
+ });
143
+ });
144
+ it("struct with doc comments", () => {
145
+ const actualModule = parse(`
146
+ /// Doc comment
147
+ /// for Foo
148
+ struct Foo {
149
+ /// Doc comment for x
150
+ x: int32;
151
+ /// Doc comment for y
152
+ y: int32;
153
+ }`);
154
+ expect(actualModule).toMatch({
155
+ result: {
156
+ nameToDeclaration: {
157
+ Foo: {
158
+ doc: {},
159
+ nameToDeclaration: {
160
+ x: {
161
+ doc: {},
162
+ },
163
+ y: {
164
+ doc: {},
165
+ },
166
+ },
167
+ },
168
+ },
169
+ },
170
+ errors: [],
171
+ });
172
+ });
173
+ it("struct inline record conflicts with nested record", () => {
174
+ const actualModule = parse(`
175
+ struct Foo {
176
+ bar: struct {
177
+ x: float32;
178
+ y: float32;
179
+ };
180
+ struct Bar {}
181
+ }`);
182
+ expect(actualModule).toMatch({
183
+ result: {
184
+ nameToDeclaration: {
185
+ Foo: {
186
+ nameToDeclaration: {
187
+ bar: {
188
+ number: 0,
189
+ },
190
+ Bar: {
191
+ nameToDeclaration: {
192
+ x: {
193
+ number: 0,
194
+ },
195
+ y: {
196
+ number: 1,
197
+ },
198
+ },
199
+ },
200
+ },
201
+ },
202
+ },
203
+ },
204
+ errors: [
205
+ {
206
+ token: {
207
+ text: "Bar",
208
+ },
209
+ message: "Duplicate identifier 'Bar'",
210
+ },
211
+ ],
212
+ });
213
+ });
214
+ it("simple enum", () => {
215
+ const actualModule = parse(`
216
+ enum Enum {
217
+ CONSTANT;
218
+ removed;
219
+ /// Doc comment
220
+ value_field: bool;
221
+ }`);
222
+ expect(actualModule).toMatch({
223
+ result: {
224
+ nameToDeclaration: {
225
+ Enum: {
226
+ kind: "record",
227
+ name: {
228
+ text: "Enum",
229
+ },
230
+ recordType: "enum",
231
+ nameToDeclaration: {
232
+ CONSTANT: {
233
+ kind: "field",
234
+ name: {
235
+ text: "CONSTANT",
236
+ },
237
+ number: 1,
238
+ },
239
+ value_field: {
240
+ kind: "field",
241
+ name: {
242
+ text: "value_field",
243
+ },
244
+ number: 3,
245
+ doc: {},
246
+ unresolvedType: {
247
+ kind: "primitive",
248
+ },
249
+ isRecursive: false,
250
+ },
251
+ },
252
+ fields: [
253
+ {
254
+ kind: "field",
255
+ name: {
256
+ text: "CONSTANT",
257
+ },
258
+ },
259
+ {
260
+ kind: "field",
261
+ name: {
262
+ text: "value_field",
263
+ },
264
+ },
265
+ ],
266
+ numSlots: 0,
267
+ numSlotsInclRemovedNumbers: 0,
268
+ },
269
+ },
270
+ },
271
+ errors: [],
272
+ });
273
+ });
274
+ it("record with stable id", () => {
275
+ const actualModule = parse(`
276
+ struct Foo(4294967295) {}
277
+ enum Zoo(0) {}`);
278
+ expect(actualModule).toMatch({
279
+ result: {
280
+ kind: "module",
281
+ path: "path/to/module",
282
+ nameToDeclaration: {
283
+ Foo: {
284
+ kind: "record",
285
+ recordNumber: 4294967295,
286
+ },
287
+ Zoo: {
288
+ kind: "record",
289
+ recordNumber: 0,
290
+ },
291
+ },
292
+ },
293
+ errors: [],
294
+ });
295
+ });
296
+ it("nested struct", () => {
297
+ const actualModule = parse(`
298
+ struct Foo {
299
+ struct Bar {}
300
+ }`);
301
+ expect(actualModule).toMatch({
302
+ result: {
303
+ kind: "module",
304
+ path: "path/to/module",
305
+ nameToDeclaration: {
306
+ Foo: {
307
+ kind: "record",
308
+ name: {
309
+ text: "Foo",
310
+ },
311
+ recordType: "struct",
312
+ nameToDeclaration: {
313
+ Bar: {
314
+ kind: "record",
315
+ name: {
316
+ text: "Bar",
317
+ },
318
+ recordType: "struct",
319
+ },
320
+ },
321
+ nestedRecords: [
322
+ {
323
+ kind: "record",
324
+ name: {
325
+ text: "Bar",
326
+ },
327
+ recordType: "struct",
328
+ },
329
+ ],
330
+ },
331
+ },
332
+ },
333
+ errors: [],
334
+ });
335
+ });
336
+ it("struct with all possible types", () => {
337
+ const actualModule = parse(`
338
+ struct AllTypes {
339
+ bool: bool;
340
+ int32: int32;
341
+ int64: int64;
342
+ uint64: uint64;
343
+ float32: float32;
344
+ float64: float64;
345
+ timestamp: timestamp;
346
+ string: string;
347
+ bytes: bytes;
348
+ strings: [string?];
349
+ foos: [Foo|x.y];
350
+ }`);
351
+ expect(actualModule).toMatch({
352
+ result: {
353
+ nameToDeclaration: {
354
+ AllTypes: {
355
+ nameToDeclaration: {
356
+ bool: {
357
+ unresolvedType: {
358
+ kind: "primitive",
359
+ primitive: "bool",
360
+ },
361
+ },
362
+ int32: {
363
+ unresolvedType: {
364
+ kind: "primitive",
365
+ primitive: "int32",
366
+ },
367
+ },
368
+ int64: {
369
+ unresolvedType: {
370
+ kind: "primitive",
371
+ primitive: "int64",
372
+ },
373
+ },
374
+ uint64: {
375
+ unresolvedType: {
376
+ kind: "primitive",
377
+ primitive: "uint64",
378
+ },
379
+ },
380
+ float32: {
381
+ unresolvedType: {
382
+ kind: "primitive",
383
+ primitive: "float32",
384
+ },
385
+ },
386
+ float64: {
387
+ unresolvedType: {
388
+ kind: "primitive",
389
+ primitive: "float64",
390
+ },
391
+ },
392
+ timestamp: {
393
+ unresolvedType: {
394
+ kind: "primitive",
395
+ primitive: "timestamp",
396
+ },
397
+ },
398
+ string: {
399
+ unresolvedType: {
400
+ kind: "primitive",
401
+ primitive: "string",
402
+ },
403
+ },
404
+ bytes: {
405
+ unresolvedType: {
406
+ kind: "primitive",
407
+ primitive: "bytes",
408
+ },
409
+ },
410
+ strings: {
411
+ unresolvedType: {
412
+ kind: "array",
413
+ item: {
414
+ kind: "optional",
415
+ other: {
416
+ kind: "primitive",
417
+ primitive: "string",
418
+ },
419
+ },
420
+ },
421
+ },
422
+ foos: {
423
+ unresolvedType: {
424
+ kind: "array",
425
+ item: {
426
+ kind: "record",
427
+ nameParts: [
428
+ {
429
+ text: "Foo",
430
+ position: 284,
431
+ line: {
432
+ lineNumber: 12,
433
+ line: " foos: [Foo|x.y];",
434
+ position: 269,
435
+ modulePath: "path/to/module",
436
+ },
437
+ colNumber: 15,
438
+ },
439
+ ],
440
+ absolute: false,
441
+ },
442
+ key: {
443
+ pipeToken: {
444
+ text: "|",
445
+ position: 287,
446
+ line: {
447
+ lineNumber: 12,
448
+ line: " foos: [Foo|x.y];",
449
+ position: 269,
450
+ modulePath: "path/to/module",
451
+ },
452
+ colNumber: 18,
453
+ },
454
+ path: [
455
+ {
456
+ name: {
457
+ text: "x",
458
+ position: 288,
459
+ line: {
460
+ lineNumber: 12,
461
+ line: " foos: [Foo|x.y];",
462
+ position: 269,
463
+ modulePath: "path/to/module",
464
+ },
465
+ colNumber: 19,
466
+ },
467
+ },
468
+ {
469
+ name: {
470
+ text: "y",
471
+ position: 290,
472
+ line: {
473
+ lineNumber: 12,
474
+ line: " foos: [Foo|x.y];",
475
+ position: 269,
476
+ modulePath: "path/to/module",
477
+ },
478
+ colNumber: 21,
479
+ },
480
+ declaration: undefined,
481
+ },
482
+ ],
483
+ keyType: {
484
+ kind: "primitive",
485
+ primitive: "bool",
486
+ },
487
+ },
488
+ },
489
+ },
490
+ },
491
+ },
492
+ },
493
+ },
494
+ errors: [],
495
+ });
496
+ });
497
+ it("module with imports", () => {
498
+ const actualModule = parse(`
499
+ import foo from './path/😊/foo';
500
+ import * as bar from "path/to/bar";`);
501
+ expect(actualModule).toMatch({
502
+ result: {
503
+ nameToDeclaration: {
504
+ foo: {
505
+ kind: "import",
506
+ importedNames: [
507
+ {
508
+ text: "foo",
509
+ },
510
+ ],
511
+ modulePath: {
512
+ text: "'./path/😊/foo'",
513
+ },
514
+ },
515
+ bar: {
516
+ kind: "import-alias",
517
+ name: {
518
+ text: "bar",
519
+ },
520
+ modulePath: {
521
+ text: '"path/to/bar"',
522
+ },
523
+ },
524
+ },
525
+ },
526
+ errors: [],
527
+ });
528
+ });
529
+ it("module with duplicate identifier", () => {
530
+ const actualModule = parse(`
531
+ struct A {}
532
+ struct A {}`);
533
+ expect(actualModule).toMatch({
534
+ errors: [
535
+ {
536
+ token: {
537
+ text: "A",
538
+ line: {
539
+ lineNumber: 2,
540
+ },
541
+ },
542
+ message: "Duplicate identifier 'A'",
543
+ },
544
+ ],
545
+ });
546
+ });
547
+ it("enum with sparse numbers", () => {
548
+ const actualModule = parse(`
549
+ enum Enum {
550
+ CONSTANT = 2;
551
+ removed 10, 11;
552
+ removed 12..14;
553
+ removed 30..32, 50, 60..62;
554
+ value_field: bool = 4;
555
+ }`);
556
+ expect(actualModule).toMatch({
557
+ result: {
558
+ nameToDeclaration: {
559
+ Enum: {
560
+ kind: "record",
561
+ name: {
562
+ text: "Enum",
563
+ },
564
+ recordType: "enum",
565
+ nameToDeclaration: {
566
+ CONSTANT: {
567
+ kind: "field",
568
+ name: {
569
+ text: "CONSTANT",
570
+ },
571
+ number: 2,
572
+ },
573
+ value_field: {
574
+ kind: "field",
575
+ name: {
576
+ text: "value_field",
577
+ },
578
+ number: 4,
579
+ },
580
+ },
581
+ removedNumbers: [10, 11, 12, 13, 14, 30, 31, 32, 50, 60, 61, 62],
582
+ },
583
+ },
584
+ },
585
+ errors: [],
586
+ });
587
+ });
588
+ it("struct with duplicate identifier", () => {
589
+ const actualModule = parse(`
590
+ struct A {
591
+ a: bool;
592
+ a: bool;
593
+ }`);
594
+ expect(actualModule).toMatch({
595
+ errors: [
596
+ {
597
+ token: {
598
+ text: "a",
599
+ line: {
600
+ lineNumber: 3,
601
+ },
602
+ },
603
+ message: "Duplicate identifier 'a'",
604
+ },
605
+ ],
606
+ });
607
+ });
608
+ it("struct with invalid casing", () => {
609
+ const actualModule = parse(`
610
+ struct a {
611
+ A: bool;
612
+ }`);
613
+ expect(actualModule).toMatch({
614
+ errors: [
615
+ {
616
+ token: {
617
+ text: "a",
618
+ },
619
+ expected: "UpperCamel",
620
+ },
621
+ {
622
+ token: {
623
+ text: "A",
624
+ },
625
+ expected: "lower_underscore",
626
+ },
627
+ ],
628
+ });
629
+ });
630
+ it("struct with mixed numbering", () => {
631
+ const actualModule = parse(`
632
+ struct A {
633
+ a: bool;
634
+ b: bool = 1;
635
+ }`);
636
+ expect(actualModule).toMatch({
637
+ errors: [
638
+ {
639
+ token: {
640
+ text: "b",
641
+ },
642
+ message: "Cannot mix implicit and explicit numbering",
643
+ },
644
+ ],
645
+ });
646
+ });
647
+ it("struct with removed fields and mixed numbering", () => {
648
+ const actualModule = parse(`
649
+ struct A {
650
+ removed;
651
+ b: bool = 1;
652
+ }`);
653
+ expect(actualModule).toMatch({
654
+ errors: [
655
+ {
656
+ token: {
657
+ text: "b",
658
+ },
659
+ message: "Cannot mix implicit and explicit numbering",
660
+ },
661
+ ],
662
+ });
663
+ });
664
+ it("struct with duplicate number", () => {
665
+ const actualModule = parse(`
666
+ struct A {
667
+ a: bool = 0;
668
+ b: bool = 0;
669
+ }`);
670
+ expect(actualModule).toMatch({
671
+ errors: [
672
+ {
673
+ token: {
674
+ text: "b",
675
+ },
676
+ message: "Duplicate field number 0",
677
+ },
678
+ ],
679
+ });
680
+ });
681
+ it("struct with duplicate number in removed declaration", () => {
682
+ const actualModule = parse(`
683
+ struct A {
684
+ removed 0, 1, 2, 5, 2, 3, 4;
685
+ }`);
686
+ expect(actualModule).toMatch({
687
+ errors: [
688
+ {
689
+ token: {
690
+ text: "removed",
691
+ },
692
+ message: "Duplicate field number 2",
693
+ },
694
+ ],
695
+ });
696
+ });
697
+ it("struct with duplicate number in removed range declaration", () => {
698
+ const actualModule = parse(`
699
+ struct A {
700
+ removed 0, 1, 2, 5, 2..4;
701
+ }`);
702
+ expect(actualModule).toMatch({
703
+ errors: [
704
+ {
705
+ token: {
706
+ text: "removed",
707
+ },
708
+ message: "Duplicate field number 2",
709
+ },
710
+ ],
711
+ });
712
+ });
713
+ it("struct with invalid range in removed declaration", () => {
714
+ const actualModule = parse(`
715
+ struct A {
716
+ removed 0..0;
717
+ }`);
718
+ expect(actualModule).toMatch({
719
+ errors: [
720
+ {
721
+ token: {
722
+ text: "removed",
723
+ },
724
+ message: "Upper bound must be greater than lower bound",
725
+ },
726
+ ],
727
+ });
728
+ });
729
+ it("struct with removed fields and duplicate number", () => {
730
+ const actualModule = parse(`
731
+ struct A {
732
+ a: bool = 0;
733
+ removed 0;
734
+ }`);
735
+ expect(actualModule).toMatch({
736
+ errors: [
737
+ {
738
+ token: {
739
+ text: "removed",
740
+ },
741
+ message: "Duplicate field number 0",
742
+ },
743
+ ],
744
+ });
745
+ });
746
+ it("struct with missing number", () => {
747
+ const actualModule = parse(`
748
+ struct A {
749
+ a: bool = 2;
750
+ b: bool = 0;
751
+ }`);
752
+ expect(actualModule).toMatch({
753
+ errors: [
754
+ {
755
+ token: {
756
+ text: "A",
757
+ },
758
+ message: "Missing field number 1",
759
+ },
760
+ ],
761
+ });
762
+ });
763
+ it("struct with stable id out of bounds", () => {
764
+ const actualModule = parse(`
765
+ struct A(4294967296) {}`);
766
+ expect(actualModule).toMatch({
767
+ errors: [
768
+ {
769
+ token: {
770
+ text: "4294967296",
771
+ },
772
+ message: "Value out of uint32 range",
773
+ },
774
+ ],
775
+ });
776
+ });
777
+ it("enum with invalid casing", () => {
778
+ const actualModule = parse(`
779
+ enum a {
780
+ foo = 1;
781
+ BAR: string = 100;
782
+ }`);
783
+ expect(actualModule).toMatch({
784
+ errors: [
785
+ {
786
+ token: {
787
+ text: "a",
788
+ },
789
+ expected: "UpperCamel",
790
+ },
791
+ {
792
+ token: {
793
+ text: "foo",
794
+ },
795
+ expected: "UPPER_UNDERSCORE",
796
+ },
797
+ {
798
+ token: {
799
+ text: "BAR",
800
+ },
801
+ expected: "lower_underscore",
802
+ },
803
+ ],
804
+ });
805
+ });
806
+ it("struct with removed fields", () => {
807
+ const actualModule = parse(`
808
+ struct Point {
809
+ removed;
810
+ a: bool;
811
+ removed;
812
+ }`);
813
+ expect(actualModule).toMatch({
814
+ result: {
815
+ kind: "module",
816
+ path: "path/to/module",
817
+ nameToDeclaration: {
818
+ Point: {
819
+ removedNumbers: [0, 2],
820
+ },
821
+ },
822
+ pathToImportedNames: {},
823
+ records: [{}],
824
+ },
825
+ errors: [],
826
+ });
827
+ });
828
+ it("struct with removed fields and explicit numbering", () => {
829
+ const actualModule = parse(`
830
+ struct Point {
831
+ removed 3, 4, 5, 6;
832
+ removed 0, 1, 2;
833
+ }`);
834
+ expect(actualModule).toMatch({
835
+ result: {
836
+ kind: "module",
837
+ path: "path/to/module",
838
+ nameToDeclaration: {
839
+ Point: {
840
+ removedNumbers: [0, 1, 2, 3, 4, 5, 6],
841
+ },
842
+ },
843
+ pathToImportedNames: {},
844
+ records: [{}],
845
+ },
846
+ errors: [],
847
+ });
848
+ });
849
+ it("empty struct", () => {
850
+ const actualModule = parse(`
851
+ struct Point {}`);
852
+ expect(actualModule).toMatch({
853
+ result: {
854
+ kind: "module",
855
+ path: "path/to/module",
856
+ nameToDeclaration: {
857
+ Point: {
858
+ kind: "record",
859
+ name: {
860
+ text: "Point",
861
+ },
862
+ recordType: "struct",
863
+ },
864
+ },
865
+ },
866
+ errors: [],
867
+ });
868
+ });
869
+ it("empty enum", () => {
870
+ const actualModule = parse(`
871
+ enum Enum {
872
+ removed;
873
+ }`);
874
+ expect(actualModule).toMatch({
875
+ result: {
876
+ kind: "module",
877
+ path: "path/to/module",
878
+ nameToDeclaration: {
879
+ Enum: {
880
+ kind: "record",
881
+ recordType: "enum",
882
+ name: {
883
+ text: "Enum",
884
+ },
885
+ },
886
+ },
887
+ },
888
+ errors: [],
889
+ });
890
+ });
891
+ it("enum with field named UNKNOWN", () => {
892
+ const actualModule = parse(`
893
+ enum Enum {
894
+ UNKNOWN = 1;
895
+ }`);
896
+ expect(actualModule).toMatch({
897
+ errors: [
898
+ {
899
+ token: {
900
+ text: "UNKNOWN",
901
+ },
902
+ message: "Cannot name field of enum: UNKNOWN",
903
+ },
904
+ ],
905
+ });
906
+ });
907
+ it("enum with field number set to zero", () => {
908
+ const actualModule = parse(`
909
+ enum Enum {
910
+ A = 0;
911
+ }`);
912
+ expect(actualModule).toMatch({
913
+ errors: [
914
+ {
915
+ token: {
916
+ text: "A",
917
+ },
918
+ message: "Number 0 is reserved for UNKNOWN field",
919
+ },
920
+ ],
921
+ });
922
+ });
923
+ it("enum with zero field number removed", () => {
924
+ const actualModule = parse(`
925
+ enum Enum {
926
+ removed 0;
927
+ }`);
928
+ expect(actualModule).toMatch({
929
+ errors: [
930
+ {
931
+ token: {
932
+ text: "removed",
933
+ },
934
+ message: "Number 0 is reserved for UNKNOWN field",
935
+ },
936
+ ],
937
+ });
938
+ });
939
+ it("method", () => {
940
+ const actualModule = parse(`
941
+ /// Doc comment for Search
942
+ method Search(req):resp;`);
943
+ expect(actualModule).toMatch({
944
+ result: {
945
+ kind: "module",
946
+ path: "path/to/module",
947
+ nameToDeclaration: {
948
+ Search: {
949
+ kind: "method",
950
+ name: {
951
+ text: "Search",
952
+ },
953
+ doc: {},
954
+ unresolvedRequestType: {
955
+ kind: "record",
956
+ nameParts: [
957
+ {
958
+ text: "req",
959
+ },
960
+ ],
961
+ },
962
+ unresolvedResponseType: {
963
+ kind: "record",
964
+ nameParts: [
965
+ {
966
+ text: "resp",
967
+ },
968
+ ],
969
+ },
970
+ number: 2446226092,
971
+ hasExplicitNumber: false,
972
+ },
973
+ },
974
+ methods: [
975
+ {
976
+ kind: "method",
977
+ name: {
978
+ text: "Search",
979
+ },
980
+ number: 2446226092,
981
+ hasExplicitNumber: false,
982
+ },
983
+ ],
984
+ },
985
+ errors: [],
986
+ });
987
+ });
988
+ it("method with inline records", () => {
989
+ const actualModule = parse(`
990
+ method Search(
991
+ struct {
992
+ x: int32;
993
+ }
994
+ ): struct {
995
+ y: int32;
996
+ };`);
997
+ expect(actualModule).toMatch({
998
+ result: {
999
+ kind: "module",
1000
+ path: "path/to/module",
1001
+ nameToDeclaration: {
1002
+ Search: {
1003
+ kind: "method",
1004
+ name: {
1005
+ text: "Search",
1006
+ },
1007
+ unresolvedRequestType: {
1008
+ kind: "record",
1009
+ nameParts: [
1010
+ {
1011
+ text: "SearchRequest",
1012
+ },
1013
+ ],
1014
+ },
1015
+ unresolvedResponseType: {
1016
+ kind: "record",
1017
+ nameParts: [
1018
+ {
1019
+ text: "SearchResponse",
1020
+ },
1021
+ ],
1022
+ },
1023
+ number: 2446226092,
1024
+ hasExplicitNumber: false,
1025
+ },
1026
+ SearchRequest: {
1027
+ name: {
1028
+ text: "SearchRequest",
1029
+ originalText: "Search",
1030
+ },
1031
+ nameToDeclaration: {
1032
+ x: {},
1033
+ },
1034
+ },
1035
+ SearchResponse: {
1036
+ name: {
1037
+ text: "SearchResponse",
1038
+ },
1039
+ nameToDeclaration: {
1040
+ y: {},
1041
+ },
1042
+ },
1043
+ },
1044
+ methods: [
1045
+ {
1046
+ kind: "method",
1047
+ name: {
1048
+ text: "Search",
1049
+ },
1050
+ },
1051
+ ],
1052
+ },
1053
+ errors: [],
1054
+ });
1055
+ });
1056
+ it("method inline record conflicts with top-level declaration", () => {
1057
+ const actualModule = parse(`
1058
+ method Search(
1059
+ struct {
1060
+ x: int32;
1061
+ }
1062
+ ): string;
1063
+
1064
+ struct SearchRequest {}`);
1065
+ expect(actualModule).toMatch({
1066
+ result: {
1067
+ kind: "module",
1068
+ path: "path/to/module",
1069
+ nameToDeclaration: {
1070
+ Search: {
1071
+ kind: "method",
1072
+ },
1073
+ SearchRequest: {},
1074
+ },
1075
+ },
1076
+ errors: [
1077
+ {
1078
+ message: "Duplicate identifier 'SearchRequest'",
1079
+ },
1080
+ ],
1081
+ });
1082
+ });
1083
+ it("method with explicit number", () => {
1084
+ const actualModule = parse(`
1085
+ method Search(req):resp = 200;`);
1086
+ expect(actualModule).toMatch({
1087
+ result: {
1088
+ kind: "module",
1089
+ path: "path/to/module",
1090
+ nameToDeclaration: {
1091
+ Search: {
1092
+ kind: "method",
1093
+ name: {
1094
+ text: "Search",
1095
+ },
1096
+ unresolvedRequestType: {
1097
+ kind: "record",
1098
+ nameParts: [
1099
+ {
1100
+ text: "req",
1101
+ },
1102
+ ],
1103
+ },
1104
+ unresolvedResponseType: {
1105
+ kind: "record",
1106
+ nameParts: [
1107
+ {
1108
+ text: "resp",
1109
+ },
1110
+ ],
1111
+ },
1112
+ number: 200,
1113
+ },
1114
+ },
1115
+ methods: [
1116
+ {
1117
+ kind: "method",
1118
+ name: {
1119
+ text: "Search",
1120
+ },
1121
+ number: 200,
1122
+ hasExplicitNumber: true,
1123
+ },
1124
+ ],
1125
+ },
1126
+ errors: [],
1127
+ });
1128
+ });
1129
+ it("string constant", () => {
1130
+ const actualModule = parse(`
1131
+ /// Doc comment for FOO
1132
+ const FOO: string = "Foo";`);
1133
+ expect(actualModule).toMatch({
1134
+ result: {
1135
+ kind: "module",
1136
+ path: "path/to/module",
1137
+ nameToDeclaration: {
1138
+ FOO: {
1139
+ kind: "constant",
1140
+ name: {
1141
+ text: "FOO",
1142
+ },
1143
+ doc: {},
1144
+ unresolvedType: {
1145
+ kind: "primitive",
1146
+ primitive: "string",
1147
+ },
1148
+ value: {
1149
+ kind: "literal",
1150
+ token: {
1151
+ text: '"Foo"',
1152
+ },
1153
+ },
1154
+ },
1155
+ },
1156
+ constants: [
1157
+ {
1158
+ kind: "constant",
1159
+ name: {
1160
+ text: "FOO",
1161
+ },
1162
+ },
1163
+ ],
1164
+ },
1165
+ errors: [],
1166
+ });
1167
+ });
1168
+ it("constant with invalid casing", () => {
1169
+ const actualModule = parse(`
1170
+ const foo: string = "Foo";`);
1171
+ expect(actualModule).toMatch({
1172
+ errors: [
1173
+ {
1174
+ token: {
1175
+ text: "foo",
1176
+ },
1177
+ expected: "UPPER_UNDERSCORE",
1178
+ },
1179
+ ],
1180
+ });
1181
+ });
1182
+ it("doc comment not on declaration", () => {
1183
+ const actualModule = parse(`
1184
+ const FOO: [string] = [
1185
+ /// Doc comment
1186
+ "bar",
1187
+ ];`);
1188
+ expect(actualModule).toMatch({
1189
+ errors: [
1190
+ {
1191
+ token: {
1192
+ text: "/// Doc comment",
1193
+ },
1194
+ message: "Doc comments can only precede declarations",
1195
+ },
1196
+ ],
1197
+ });
1198
+ });
1199
+ it("complex constant", () => {
1200
+ const actualModule = parse(`
1201
+ const FOO: [Foo] = {
1202
+ foo: true,
1203
+ x: [
1204
+ {foo: true},
1205
+ {bar: false,},
1206
+ "hey",
1207
+ 3.14,
1208
+ -3.14,
1209
+ ],
1210
+ empty_array: [],
1211
+ empty_object: {},
1212
+ };`);
1213
+ expect(actualModule).toMatch({
1214
+ result: {
1215
+ kind: "module",
1216
+ path: "path/to/module",
1217
+ nameToDeclaration: {
1218
+ FOO: {
1219
+ kind: "constant",
1220
+ name: {
1221
+ text: "FOO",
1222
+ },
1223
+ unresolvedType: {
1224
+ kind: "array",
1225
+ item: {
1226
+ kind: "record",
1227
+ },
1228
+ },
1229
+ value: {
1230
+ kind: "object",
1231
+ token: {
1232
+ text: "{",
1233
+ },
1234
+ entries: {
1235
+ foo: {
1236
+ value: {
1237
+ kind: "literal",
1238
+ token: {
1239
+ text: "true",
1240
+ },
1241
+ },
1242
+ },
1243
+ x: {
1244
+ value: {
1245
+ kind: "array",
1246
+ items: [
1247
+ {
1248
+ kind: "object",
1249
+ entries: {
1250
+ foo: {
1251
+ value: {
1252
+ kind: "literal",
1253
+ token: {
1254
+ text: "true",
1255
+ },
1256
+ },
1257
+ },
1258
+ },
1259
+ },
1260
+ {
1261
+ kind: "object",
1262
+ entries: {
1263
+ bar: {
1264
+ value: {
1265
+ kind: "literal",
1266
+ token: {
1267
+ text: "false",
1268
+ },
1269
+ },
1270
+ },
1271
+ },
1272
+ },
1273
+ {
1274
+ kind: "literal",
1275
+ token: {
1276
+ text: '"hey"',
1277
+ },
1278
+ },
1279
+ {
1280
+ kind: "literal",
1281
+ token: {
1282
+ text: "3.14",
1283
+ },
1284
+ },
1285
+ {
1286
+ kind: "literal",
1287
+ token: {
1288
+ text: "-3.14",
1289
+ },
1290
+ },
1291
+ ],
1292
+ },
1293
+ },
1294
+ empty_array: {
1295
+ value: {
1296
+ kind: "array",
1297
+ items: [],
1298
+ },
1299
+ },
1300
+ empty_object: {
1301
+ value: {
1302
+ kind: "object",
1303
+ },
1304
+ },
1305
+ },
1306
+ partial: false,
1307
+ },
1308
+ },
1309
+ },
1310
+ constants: [
1311
+ {
1312
+ kind: "constant",
1313
+ name: {
1314
+ text: "FOO",
1315
+ },
1316
+ },
1317
+ ],
1318
+ },
1319
+ errors: [],
1320
+ });
1321
+ });
1322
+ it("partial constant", () => {
1323
+ const actualModule = parse(`
1324
+ const FOO: [Foo] = {|
1325
+ foo: true,
1326
+ |};`);
1327
+ expect(actualModule).toMatch({
1328
+ result: {
1329
+ kind: "module",
1330
+ path: "path/to/module",
1331
+ nameToDeclaration: {
1332
+ FOO: {
1333
+ kind: "constant",
1334
+ name: {
1335
+ text: "FOO",
1336
+ },
1337
+ unresolvedType: {
1338
+ kind: "array",
1339
+ item: {
1340
+ kind: "record",
1341
+ },
1342
+ },
1343
+ value: {
1344
+ kind: "object",
1345
+ token: {
1346
+ text: "{|",
1347
+ },
1348
+ entries: {
1349
+ foo: {
1350
+ value: {
1351
+ kind: "literal",
1352
+ token: {
1353
+ text: "true",
1354
+ },
1355
+ },
1356
+ },
1357
+ },
1358
+ partial: true,
1359
+ },
1360
+ },
1361
+ },
1362
+ constants: [
1363
+ {
1364
+ kind: "constant",
1365
+ name: {
1366
+ text: "FOO",
1367
+ },
1368
+ },
1369
+ ],
1370
+ },
1371
+ errors: [],
1372
+ });
1373
+ });
1374
+ it("partial empty constant", () => {
1375
+ const actualModule = parse(`
1376
+ const FOO: [Foo] = {||};`);
1377
+ expect(actualModule).toMatch({
1378
+ result: {
1379
+ kind: "module",
1380
+ path: "path/to/module",
1381
+ nameToDeclaration: {
1382
+ FOO: {
1383
+ kind: "constant",
1384
+ name: {
1385
+ text: "FOO",
1386
+ },
1387
+ unresolvedType: {
1388
+ kind: "array",
1389
+ item: {
1390
+ kind: "record",
1391
+ },
1392
+ },
1393
+ value: {
1394
+ kind: "object",
1395
+ token: {
1396
+ text: "{|",
1397
+ },
1398
+ entries: {},
1399
+ partial: true,
1400
+ },
1401
+ },
1402
+ },
1403
+ constants: [
1404
+ {
1405
+ kind: "constant",
1406
+ name: {
1407
+ text: "FOO",
1408
+ },
1409
+ },
1410
+ ],
1411
+ },
1412
+ errors: [],
1413
+ });
1414
+ });
1415
+ describe("handle and recover from bad statements", () => {
1416
+ it("#0", () => {
1417
+ const actualModule = parse(`
1418
+ const FOO: string = "";
1419
+ a b c;
1420
+ struct Foo {}`);
1421
+ expect(actualModule).toMatch({
1422
+ result: {
1423
+ nameToDeclaration: {
1424
+ FOO: {},
1425
+ Foo: {},
1426
+ },
1427
+ },
1428
+ errors: [
1429
+ {
1430
+ token: {
1431
+ text: "a",
1432
+ },
1433
+ expected: "one of: 'struct', 'enum', 'import', 'method', 'const'",
1434
+ },
1435
+ ],
1436
+ });
1437
+ });
1438
+ it("#1", () => {
1439
+ const actualModule = parse(`
1440
+ const FOO: string = "";
1441
+ a;
1442
+ struct Foo {}`);
1443
+ expect(actualModule).toMatch({
1444
+ result: {
1445
+ nameToDeclaration: {
1446
+ FOO: {},
1447
+ Foo: {},
1448
+ },
1449
+ },
1450
+ errors: [
1451
+ {
1452
+ token: {
1453
+ text: "a",
1454
+ },
1455
+ expected: "one of: 'struct', 'enum', 'import', 'method', 'const'",
1456
+ },
1457
+ ],
1458
+ });
1459
+ });
1460
+ it("#2", () => {
1461
+ const actualModule = parse(`
1462
+ const FOO: string = "";
1463
+ ;;;
1464
+ struct Foo {}`);
1465
+ expect(actualModule).toMatch({
1466
+ result: {
1467
+ nameToDeclaration: {
1468
+ FOO: {},
1469
+ Foo: {},
1470
+ },
1471
+ },
1472
+ errors: [
1473
+ {
1474
+ expected: "one of: 'struct', 'enum', 'import', 'method', 'const'",
1475
+ },
1476
+ {
1477
+ expected: "one of: 'struct', 'enum', 'import', 'method', 'const'",
1478
+ },
1479
+ {
1480
+ expected: "one of: 'struct', 'enum', 'import', 'method', 'const'",
1481
+ },
1482
+ ],
1483
+ });
1484
+ });
1485
+ it("#3", () => {
1486
+ const actualModule = parse(`
1487
+ const FOO: string = "";;`);
1488
+ expect(actualModule).toMatch({
1489
+ result: {
1490
+ nameToDeclaration: {
1491
+ FOO: {},
1492
+ },
1493
+ },
1494
+ errors: [
1495
+ {
1496
+ expected: "one of: 'struct', 'enum', 'import', 'method', 'const'",
1497
+ },
1498
+ ],
1499
+ });
1500
+ });
1501
+ it("#4", () => {
1502
+ const actualModule = parse(`
1503
+ struct Foo { struct Bar {}`);
1504
+ expect(actualModule).toMatch({
1505
+ result: {
1506
+ nameToDeclaration: {
1507
+ Foo: {
1508
+ nameToDeclaration: {
1509
+ Bar: {},
1510
+ },
1511
+ },
1512
+ },
1513
+ },
1514
+ errors: [
1515
+ {
1516
+ expected: "'}'",
1517
+ },
1518
+ ],
1519
+ });
1520
+ });
1521
+ it("#5", () => {
1522
+ const actualModule = parse(`
1523
+ struct Foo { a { a; {} } b: string; }`);
1524
+ expect(actualModule).toMatch({
1525
+ result: {
1526
+ nameToDeclaration: {
1527
+ Foo: {
1528
+ nameToDeclaration: {
1529
+ b: {},
1530
+ },
1531
+ },
1532
+ },
1533
+ },
1534
+ errors: [
1535
+ {
1536
+ expected: "':'",
1537
+ },
1538
+ ],
1539
+ });
1540
+ });
1541
+ it("#6", () => {
1542
+ const actualModule = parse(`
1543
+ struct Foo { }} struct Bar { }`);
1544
+ expect(actualModule).toMatch({
1545
+ result: {
1546
+ nameToDeclaration: {
1547
+ Foo: {},
1548
+ Bar: {},
1549
+ },
1550
+ },
1551
+ errors: [
1552
+ {
1553
+ expected: "one of: 'struct', 'enum', 'import', 'method', 'const'",
1554
+ },
1555
+ ],
1556
+ });
1557
+ });
1558
+ });
1559
+ describe("grammar errors", () => {
1560
+ it("expected: record name", () => {
1561
+ const actualModule = parse(`struct {}`);
1562
+ expect(actualModule).toMatch({
1563
+ errors: [
1564
+ {
1565
+ token: {
1566
+ text: "{",
1567
+ line: {
1568
+ lineNumber: 0,
1569
+ },
1570
+ },
1571
+ expected: "identifier",
1572
+ },
1573
+ ],
1574
+ });
1575
+ });
1576
+ it("expected: positive integer", () => {
1577
+ const actualModule = parse(`struct A { n: int32 = bool; }`);
1578
+ expect(actualModule).toMatch({
1579
+ errors: [
1580
+ {
1581
+ token: {
1582
+ text: "bool",
1583
+ line: {
1584
+ lineNumber: 0,
1585
+ },
1586
+ },
1587
+ expected: "positive integer",
1588
+ },
1589
+ ],
1590
+ });
1591
+ });
1592
+ });
1593
+ });
1594
+ //# sourceMappingURL=parser.test.js.map