tree-sitter-ktav 0.2.1 → 0.3.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.
package/grammar.js CHANGED
@@ -55,13 +55,35 @@ module.exports = grammar({
55
55
  word: $ => $._key_segment,
56
56
 
57
57
  rules: {
58
+ // The top-level document is a sequence of lines. Per spec § 5.0.1
59
+ // (added in spec 0.1.1) the root may be either an Object (the
60
+ // historical default — every content line is a pair) or an Array
61
+ // (every content line is an array item). Tree-sitter is a generic
62
+ // parser of trees: rather than encode the spec's "first content
63
+ // line decides" rule structurally, we accept either kind of line
64
+ // anywhere at the top level. The reference parser performs the
65
+ // semantic § 5.0.1 dispatch and rejects mixed roots; the grammar's
66
+ // job here is only to produce a clean syntax tree for both shapes
67
+ // (and for editors / LSPs) without spurious ERROR nodes on bare
68
+ // top-level scalars or `:i`/`:f`/`::` lines.
58
69
  source_file: $ => repeat($._line),
59
70
 
60
71
  // ---- Top-level lines ----
72
+ //
73
+ // `top_array_item` covers the top-level Array case (§ 5.0.1): a
74
+ // bare scalar, a typed-marker item (`:: …`, `:i …`, `:f …`), a
75
+ // lone `{` / `[` opener, or a `(` / `((` multi-line opener. It
76
+ // is structurally identical to `array_item` (used inside `[ ]`)
77
+ // but is kept as a distinct rule so we can apply a lexer-level
78
+ // disambiguation: a line that classifies as a pair (§ 5.3) must
79
+ // remain a pair at the top level (spec § 5.0.1 step 2), so
80
+ // `top_array_item`'s plain bare-scalar branch is given lower
81
+ // precedence than `object_pair` via `prec.dynamic`.
61
82
  _line: $ => choice(
62
83
  $.comment,
63
84
  $.blank_line,
64
85
  $.object_pair,
86
+ $.top_array_item,
65
87
  ),
66
88
 
67
89
  blank_line: $ => $._newline,
@@ -69,11 +91,13 @@ module.exports = grammar({
69
91
  _newline: $ => /\r?\n/,
70
92
 
71
93
  // ---- Comment ----
72
- comment: $ => seq(
73
- '#',
74
- optional(/[^\r\n]*/),
75
- $._newline,
76
- ),
94
+ //
95
+ // Captured as a single whole-line token so it is the
96
+ // unambiguous longest match at line start when the line
97
+ // begins with `#`. Without this, `_top_scalar_text` (also a
98
+ // whole-line token) would tie or beat a structurally-defined
99
+ // comment that's split into `'#'` + tail + newline pieces.
100
+ comment: $ => token(prec(1, /#[^\r\n]*\r?\n/)),
77
101
 
78
102
  // ---- Object pair ----
79
103
  //
@@ -210,6 +234,77 @@ module.exports = grammar({
210
234
  field('value', $._value_line),
211
235
  ),
212
236
 
237
+ // Top-level array item (§ 5.0.1, added in spec 0.1.1).
238
+ //
239
+ // Structurally a sibling of `array_item` (used inside `[ ]`),
240
+ // but with two differences that realise spec § 5.0.1 step 2:
241
+ //
242
+ // * The plain bare-scalar branch uses `_top_scalar_text`, a
243
+ // token that disallows `:` anywhere in the line. This makes
244
+ // any line containing a `:` (i.e. any pair-shaped line)
245
+ // parseable ONLY as `object_pair`, never as a top-level
246
+ // bare-scalar — which is what § 5.0.1 step 2 requires.
247
+ // Per spec note: to force a colon-bearing scalar at the root
248
+ // to be an Array item, use the raw marker (`:: foo: bar`).
249
+ //
250
+ // * Compound openers (`{`, `[`, `(`, `((`) and the empty-inline
251
+ // compound forms (`{}` / `[]` / `()` / `(())`) and the
252
+ // keywords are still allowed unchanged — they are
253
+ // unambiguous lines that cannot be confused with a pair.
254
+ top_array_item: $ => choice(
255
+ seq(
256
+ field('marker', $.sep_raw),
257
+ $._marker_ws,
258
+ field('value', choice($.empty_value, $.scalar)),
259
+ ),
260
+ seq(
261
+ field('marker', $.sep_int),
262
+ $._marker_ws,
263
+ field('value', choice($.empty_value, $.scalar)),
264
+ ),
265
+ seq(
266
+ field('marker', $.sep_float),
267
+ $._marker_ws,
268
+ field('value', choice($.empty_value, $.scalar)),
269
+ ),
270
+ field('value', $.compound_object),
271
+ field('value', $.compound_array),
272
+ field('value', $.multiline_stripped),
273
+ field('value', $.multiline_verbatim),
274
+ field('value', $.empty_object),
275
+ field('value', $.empty_array),
276
+ field('value', $.empty_paren),
277
+ field('value', $.empty_double_paren),
278
+ field('value', $.keyword),
279
+ // Bare-scalar branch — the line is captured as a `scalar`
280
+ // node whose text comes from the `_top_scalar_text` token
281
+ // (no `:` allowed). Wrapping in `top_scalar` keeps the AST
282
+ // tidy: tools see exactly the same `(scalar)` shape as
283
+ // elsewhere, with the only difference being which lexer
284
+ // rule produced the inner token.
285
+ field('value', $.top_scalar),
286
+ ),
287
+
288
+ // `top_scalar` is a one-token whole-line scalar used at the
289
+ // document root for spec § 5.0.1's bare-scalar Array-item
290
+ // case. The token swallows the trailing newline, which makes
291
+ // it strictly longer than the `_key_segment` token a pair
292
+ // would emit (`_key_segment` stops at the first `:` / `\n` /
293
+ // structural byte). Two consequences:
294
+ //
295
+ // 1. On a colon-free line such as `foo\n`, the whole-line
296
+ // `_top_scalar_text` token (length 4) wins the lexer's
297
+ // longest-match against `_key_segment` (length 3) — so
298
+ // the parser commits to the top-level Array-item path,
299
+ // not the always-ERROR pair-without-separator path.
300
+ // 2. On a pair-shaped line such as `name: Russia\n`, the
301
+ // `_top_scalar_text` regex CANNOT match (it forbids
302
+ // `:`), so `_key_segment` is the only viable token at
303
+ // line-start and the parser correctly enters
304
+ // `object_pair` (spec § 5.0.1 step 2).
305
+ top_scalar: $ => $._top_scalar_text,
306
+ _top_scalar_text: $ => token(/[^\s:\r\n][^:\r\n]*\r?\n/),
307
+
213
308
  // ---- Multi-line strings ----
214
309
  multiline_stripped: $ => seq(
215
310
  $.open_paren,
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "tree-sitter-ktav",
3
- "version": "0.2.1",
3
+ "version": "0.3.0",
4
4
  "description": "Tree-sitter grammar for Ktav (כְּתָב) — the Written Configuration Format",
5
5
  "keywords": [
6
6
  "parser",
package/src/grammar.json CHANGED
@@ -24,6 +24,10 @@
24
24
  {
25
25
  "type": "SYMBOL",
26
26
  "name": "object_pair"
27
+ },
28
+ {
29
+ "type": "SYMBOL",
30
+ "name": "top_array_item"
27
31
  }
28
32
  ]
29
33
  },
@@ -36,29 +40,15 @@
36
40
  "value": "\\r?\\n"
37
41
  },
38
42
  "comment": {
39
- "type": "SEQ",
40
- "members": [
41
- {
42
- "type": "STRING",
43
- "value": "#"
44
- },
45
- {
46
- "type": "CHOICE",
47
- "members": [
48
- {
49
- "type": "PATTERN",
50
- "value": "[^\\r\\n]*"
51
- },
52
- {
53
- "type": "BLANK"
54
- }
55
- ]
56
- },
57
- {
58
- "type": "SYMBOL",
59
- "name": "_newline"
43
+ "type": "TOKEN",
44
+ "content": {
45
+ "type": "PREC",
46
+ "value": 1,
47
+ "content": {
48
+ "type": "PATTERN",
49
+ "value": "#[^\\r\\n]*\\r?\\n"
60
50
  }
61
- ]
51
+ }
62
52
  },
63
53
  "object_pair": {
64
54
  "type": "CHOICE",
@@ -658,6 +648,204 @@
658
648
  }
659
649
  ]
660
650
  },
651
+ "top_array_item": {
652
+ "type": "CHOICE",
653
+ "members": [
654
+ {
655
+ "type": "SEQ",
656
+ "members": [
657
+ {
658
+ "type": "FIELD",
659
+ "name": "marker",
660
+ "content": {
661
+ "type": "SYMBOL",
662
+ "name": "sep_raw"
663
+ }
664
+ },
665
+ {
666
+ "type": "SYMBOL",
667
+ "name": "_marker_ws"
668
+ },
669
+ {
670
+ "type": "FIELD",
671
+ "name": "value",
672
+ "content": {
673
+ "type": "CHOICE",
674
+ "members": [
675
+ {
676
+ "type": "SYMBOL",
677
+ "name": "empty_value"
678
+ },
679
+ {
680
+ "type": "SYMBOL",
681
+ "name": "scalar"
682
+ }
683
+ ]
684
+ }
685
+ }
686
+ ]
687
+ },
688
+ {
689
+ "type": "SEQ",
690
+ "members": [
691
+ {
692
+ "type": "FIELD",
693
+ "name": "marker",
694
+ "content": {
695
+ "type": "SYMBOL",
696
+ "name": "sep_int"
697
+ }
698
+ },
699
+ {
700
+ "type": "SYMBOL",
701
+ "name": "_marker_ws"
702
+ },
703
+ {
704
+ "type": "FIELD",
705
+ "name": "value",
706
+ "content": {
707
+ "type": "CHOICE",
708
+ "members": [
709
+ {
710
+ "type": "SYMBOL",
711
+ "name": "empty_value"
712
+ },
713
+ {
714
+ "type": "SYMBOL",
715
+ "name": "scalar"
716
+ }
717
+ ]
718
+ }
719
+ }
720
+ ]
721
+ },
722
+ {
723
+ "type": "SEQ",
724
+ "members": [
725
+ {
726
+ "type": "FIELD",
727
+ "name": "marker",
728
+ "content": {
729
+ "type": "SYMBOL",
730
+ "name": "sep_float"
731
+ }
732
+ },
733
+ {
734
+ "type": "SYMBOL",
735
+ "name": "_marker_ws"
736
+ },
737
+ {
738
+ "type": "FIELD",
739
+ "name": "value",
740
+ "content": {
741
+ "type": "CHOICE",
742
+ "members": [
743
+ {
744
+ "type": "SYMBOL",
745
+ "name": "empty_value"
746
+ },
747
+ {
748
+ "type": "SYMBOL",
749
+ "name": "scalar"
750
+ }
751
+ ]
752
+ }
753
+ }
754
+ ]
755
+ },
756
+ {
757
+ "type": "FIELD",
758
+ "name": "value",
759
+ "content": {
760
+ "type": "SYMBOL",
761
+ "name": "compound_object"
762
+ }
763
+ },
764
+ {
765
+ "type": "FIELD",
766
+ "name": "value",
767
+ "content": {
768
+ "type": "SYMBOL",
769
+ "name": "compound_array"
770
+ }
771
+ },
772
+ {
773
+ "type": "FIELD",
774
+ "name": "value",
775
+ "content": {
776
+ "type": "SYMBOL",
777
+ "name": "multiline_stripped"
778
+ }
779
+ },
780
+ {
781
+ "type": "FIELD",
782
+ "name": "value",
783
+ "content": {
784
+ "type": "SYMBOL",
785
+ "name": "multiline_verbatim"
786
+ }
787
+ },
788
+ {
789
+ "type": "FIELD",
790
+ "name": "value",
791
+ "content": {
792
+ "type": "SYMBOL",
793
+ "name": "empty_object"
794
+ }
795
+ },
796
+ {
797
+ "type": "FIELD",
798
+ "name": "value",
799
+ "content": {
800
+ "type": "SYMBOL",
801
+ "name": "empty_array"
802
+ }
803
+ },
804
+ {
805
+ "type": "FIELD",
806
+ "name": "value",
807
+ "content": {
808
+ "type": "SYMBOL",
809
+ "name": "empty_paren"
810
+ }
811
+ },
812
+ {
813
+ "type": "FIELD",
814
+ "name": "value",
815
+ "content": {
816
+ "type": "SYMBOL",
817
+ "name": "empty_double_paren"
818
+ }
819
+ },
820
+ {
821
+ "type": "FIELD",
822
+ "name": "value",
823
+ "content": {
824
+ "type": "SYMBOL",
825
+ "name": "keyword"
826
+ }
827
+ },
828
+ {
829
+ "type": "FIELD",
830
+ "name": "value",
831
+ "content": {
832
+ "type": "SYMBOL",
833
+ "name": "top_scalar"
834
+ }
835
+ }
836
+ ]
837
+ },
838
+ "top_scalar": {
839
+ "type": "SYMBOL",
840
+ "name": "_top_scalar_text"
841
+ },
842
+ "_top_scalar_text": {
843
+ "type": "TOKEN",
844
+ "content": {
845
+ "type": "PATTERN",
846
+ "value": "[^\\s:\\r\\n][^:\\r\\n]*\\r?\\n"
847
+ }
848
+ },
661
849
  "multiline_stripped": {
662
850
  "type": "SEQ",
663
851
  "members": [
@@ -98,11 +98,6 @@
98
98
  "named": true,
99
99
  "fields": {}
100
100
  },
101
- {
102
- "type": "comment",
103
- "named": true,
104
- "fields": {}
105
- },
106
101
  {
107
102
  "type": "compound_array",
108
103
  "named": true,
@@ -392,13 +387,96 @@
392
387
  {
393
388
  "type": "object_pair",
394
389
  "named": true
390
+ },
391
+ {
392
+ "type": "top_array_item",
393
+ "named": true
395
394
  }
396
395
  ]
397
396
  }
398
397
  },
399
398
  {
400
- "type": "#",
401
- "named": false
399
+ "type": "top_array_item",
400
+ "named": true,
401
+ "fields": {
402
+ "marker": {
403
+ "multiple": false,
404
+ "required": false,
405
+ "types": [
406
+ {
407
+ "type": "sep_float",
408
+ "named": true
409
+ },
410
+ {
411
+ "type": "sep_int",
412
+ "named": true
413
+ },
414
+ {
415
+ "type": "sep_raw",
416
+ "named": true
417
+ }
418
+ ]
419
+ },
420
+ "value": {
421
+ "multiple": false,
422
+ "required": true,
423
+ "types": [
424
+ {
425
+ "type": "compound_array",
426
+ "named": true
427
+ },
428
+ {
429
+ "type": "compound_object",
430
+ "named": true
431
+ },
432
+ {
433
+ "type": "empty_array",
434
+ "named": true
435
+ },
436
+ {
437
+ "type": "empty_double_paren",
438
+ "named": true
439
+ },
440
+ {
441
+ "type": "empty_object",
442
+ "named": true
443
+ },
444
+ {
445
+ "type": "empty_paren",
446
+ "named": true
447
+ },
448
+ {
449
+ "type": "empty_value",
450
+ "named": true
451
+ },
452
+ {
453
+ "type": "keyword",
454
+ "named": true
455
+ },
456
+ {
457
+ "type": "multiline_stripped",
458
+ "named": true
459
+ },
460
+ {
461
+ "type": "multiline_verbatim",
462
+ "named": true
463
+ },
464
+ {
465
+ "type": "scalar",
466
+ "named": true
467
+ },
468
+ {
469
+ "type": "top_scalar",
470
+ "named": true
471
+ }
472
+ ]
473
+ }
474
+ }
475
+ },
476
+ {
477
+ "type": "top_scalar",
478
+ "named": true,
479
+ "fields": {}
402
480
  },
403
481
  {
404
482
  "type": "(())",
@@ -420,6 +498,10 @@
420
498
  "type": "]",
421
499
  "named": false
422
500
  },
501
+ {
502
+ "type": "comment",
503
+ "named": true
504
+ },
423
505
  {
424
506
  "type": "kw_false",
425
507
  "named": true