tree-sitter-ucode 0.6.0 → 0.7.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/markup/grammar.js CHANGED
@@ -78,7 +78,6 @@ module.exports = grammar({
78
78
 
79
79
  inline: $ => [
80
80
  $._call_signature,
81
- $._formal_parameter,
82
81
  $._expressions,
83
82
  $._semicolon,
84
83
  $._identifier,
@@ -126,7 +125,7 @@ module.exports = grammar({
126
125
  [$.primary_expression, $._for_header],
127
126
  [$.variable_declarator, $._for_header],
128
127
  [$.assignment_expression, $.pattern],
129
- [$.labeled_statement, $._property_name],
128
+ [$.primary_expression, $.delete_expression],
130
129
  ],
131
130
 
132
131
  word: $ => $.identifier,
@@ -209,18 +208,22 @@ module.exports = grammar({
209
208
  field('clause', $.export_clause),
210
209
  $._semicolon,
211
210
  ),
211
+ // `export let/const …;` already carries its own terminating semicolon.
212
212
  seq(
213
213
  'export',
214
- choice(
215
- field('declaration', $.declaration),
216
- seq(
217
- 'default',
218
- seq(
219
- field('value', $.expression),
220
- ';',
221
- ),
222
- ),
223
- ),
214
+ field('declaration', $.lexical_declaration),
215
+ ),
216
+ // `export function f() {}` requires an explicit trailing `;` in ucode.
217
+ seq(
218
+ 'export',
219
+ field('declaration', $.function_declaration),
220
+ ';',
221
+ ),
222
+ seq(
223
+ 'export',
224
+ 'default',
225
+ field('value', $.expression),
226
+ ';',
224
227
  ),
225
228
  ),
226
229
 
@@ -323,7 +326,6 @@ module.exports = grammar({
323
326
  $.continue_statement,
324
327
  $.return_statement,
325
328
  $.empty_statement,
326
- $.labeled_statement,
327
329
  ),
328
330
 
329
331
  expression_statement: $ => seq(
@@ -331,10 +333,19 @@ module.exports = grammar({
331
333
  $._semicolon,
332
334
  ),
333
335
 
334
- lexical_declaration: $ => seq(
335
- field('kind', choice('let', 'const')),
336
- commaSep1($.variable_declarator),
337
- $._semicolon,
336
+ // `let` declarators may omit the initializer; `const` requires one.
337
+ // ucode rejects `const a;` ("Expecting initializer expression").
338
+ lexical_declaration: $ => choice(
339
+ seq(
340
+ field('kind', 'let'),
341
+ commaSep1($.variable_declarator),
342
+ $._semicolon,
343
+ ),
344
+ seq(
345
+ field('kind', 'const'),
346
+ commaSep1(alias($._const_declarator, $.variable_declarator)),
347
+ $._semicolon,
348
+ ),
338
349
  ),
339
350
 
340
351
  variable_declarator: $ => seq(
@@ -342,6 +353,11 @@ module.exports = grammar({
342
353
  optional($._initializer),
343
354
  ),
344
355
 
356
+ _const_declarator: $ => seq(
357
+ field('name', $.identifier),
358
+ $._initializer,
359
+ ),
360
+
345
361
  statement_block: $ => prec.right(seq(
346
362
  '{',
347
363
  repeat($.statement),
@@ -513,17 +529,19 @@ module.exports = grammar({
513
529
  ),
514
530
  ),
515
531
 
516
- // Supports both `for (k in obj)` and `for (k, v in obj)` (ucode two-variable form)
532
+ // Supports both `for (k in obj)` and `for (k, v in obj)` (ucode two-variable form).
533
+ // The loop target must be a plain identifier: ucode rejects member/subscript
534
+ // targets (`for (a.x in o)`) and only `let` (never `const`) may declare it.
517
535
  _for_header: $ => seq(
518
536
  '(',
519
537
  choice(
520
538
  seq(
521
- field('kind', choice('let', 'const')),
539
+ field('kind', 'let'),
522
540
  field('left', $.identifier),
523
541
  optional(seq(',', field('value', $.identifier))),
524
542
  ),
525
543
  seq(
526
- field('left', $._lhs_expression),
544
+ field('left', $.identifier),
527
545
  optional(seq(',', field('value', $.identifier))),
528
546
  ),
529
547
  ),
@@ -566,15 +584,14 @@ module.exports = grammar({
566
584
  optional(field('handler', $.catch_clause)),
567
585
  ),
568
586
 
587
+ // ucode has no labeled statements, so `break`/`continue` take no label.
569
588
  break_statement: $ => seq(
570
589
  'break',
571
- field('label', optional(alias($.identifier, $.statement_identifier))),
572
590
  $._semicolon,
573
591
  ),
574
592
 
575
593
  continue_statement: $ => seq(
576
594
  'continue',
577
- field('label', optional(alias($.identifier, $.statement_identifier))),
578
595
  $._semicolon,
579
596
  ),
580
597
 
@@ -586,12 +603,6 @@ module.exports = grammar({
586
603
 
587
604
  empty_statement: _ => ';',
588
605
 
589
- labeled_statement: $ => prec.dynamic(-1, seq(
590
- field('label', alias(choice($.identifier, $._reserved_identifier), $.statement_identifier)),
591
- ':',
592
- field('body', $.statement),
593
- )),
594
-
595
606
  //
596
607
  // Statement components
597
608
  //
@@ -641,6 +652,7 @@ module.exports = grammar({
641
652
  $.assignment_expression,
642
653
  $.augmented_assignment_expression,
643
654
  $.unary_expression,
655
+ $.delete_expression,
644
656
  $.binary_expression,
645
657
  $.ternary_expression,
646
658
  $.update_expression,
@@ -667,25 +679,33 @@ module.exports = grammar({
667
679
  $.call_expression,
668
680
  ),
669
681
 
682
+ // ucode allows a trailing comma but NOT interior elision (`{a:1,,b:2}`).
670
683
  object: $ => prec('object', seq(
671
684
  '{',
672
- commaSep(optional(choice(
673
- $.pair,
674
- $.spread_element,
675
- alias(
676
- choice($.identifier, $._reserved_identifier),
677
- $.shorthand_property_identifier,
678
- ),
679
- ))),
685
+ optional(seq(
686
+ commaSep1(choice(
687
+ $.pair,
688
+ $.spread_element,
689
+ alias(
690
+ choice($.identifier, $._reserved_identifier),
691
+ $.shorthand_property_identifier,
692
+ ),
693
+ )),
694
+ optional(','),
695
+ )),
680
696
  '}',
681
697
  )),
682
698
 
699
+ // ucode allows a trailing comma but NOT interior elision (`[1,,2]`).
683
700
  array: $ => seq(
684
701
  '[',
685
- commaSep(optional(choice(
686
- $.expression,
687
- $.spread_element,
688
- ))),
702
+ optional(seq(
703
+ commaSep1(choice(
704
+ $.expression,
705
+ $.spread_element,
706
+ )),
707
+ optional(','),
708
+ )),
689
709
  ']',
690
710
  ),
691
711
 
@@ -796,10 +816,17 @@ module.exports = grammar({
796
816
  ),
797
817
 
798
818
  unary_expression: $ => prec.left('unary_void', seq(
799
- field('operator', choice('!', '~', '-', '+', 'delete')),
819
+ field('operator', choice('!', '~', '-', '+')),
800
820
  field('argument', $.expression),
801
821
  )),
802
822
 
823
+ // ucode's `delete` only accepts a property access (member or subscript)
824
+ // expression: `delete o.k` / `delete o["k"]`. `delete x` is a syntax error.
825
+ delete_expression: $ => prec.left('unary_void', seq(
826
+ field('operator', 'delete'),
827
+ field('argument', choice($.member_expression, $.subscript_expression)),
828
+ )),
829
+
803
830
  update_expression: $ => prec.left(choice(
804
831
  seq(
805
832
  field('argument', $.expression),
@@ -852,13 +879,16 @@ module.exports = grammar({
852
879
  ),
853
880
 
854
881
  _call_signature: $ => field('parameters', $.formal_parameters),
855
- _formal_parameter: $ => choice($.identifier, $.rest_element),
856
882
 
883
+ // A rest element (`...name`) must be the final parameter, and there can be
884
+ // only one. ucode rejects a rest param followed by anything — including a
885
+ // trailing comma. A trailing comma is allowed only after plain parameters.
857
886
  formal_parameters: $ => seq(
858
887
  '(',
859
- optional(seq(
860
- commaSep1($._formal_parameter),
861
- optional(','),
888
+ optional(choice(
889
+ $.rest_element,
890
+ seq(commaSep1($.identifier), ',', $.rest_element),
891
+ seq(commaSep1($.identifier), optional(',')),
862
892
  )),
863
893
  ')',
864
894
  ),
@@ -893,7 +923,8 @@ module.exports = grammar({
893
923
  unescaped_double_string_fragment: _ => token.immediate(prec(1, /[^"\\\r\n]+/)),
894
924
  unescaped_single_string_fragment: _ => token.immediate(prec(1, /[^'\\\r\n]+/)),
895
925
 
896
- // Ucode extends JS escapes with \e (ESC), \a (BEL), and octal sequences
926
+ // Ucode extends JS escapes with \e (ESC), \a (BEL), and octal sequences.
927
+ // Unlike JS, ucode supports only the 4-hex `\uXXXX` form \u2014 not `\u{...}`.
897
928
  escape_sequence: _ => token.immediate(seq(
898
929
  '\\',
899
930
  choice(
@@ -901,7 +932,6 @@ module.exports = grammar({
901
932
  /[0-7]{1,3}/,
902
933
  /x[0-9a-fA-F]{2}/,
903
934
  /u[0-9a-fA-F]{4}/,
904
- /u\{[0-9a-fA-F]+\}/,
905
935
  /\r[\n\u2028\u2029]/,
906
936
  ),
907
937
  )),
@@ -949,27 +979,30 @@ module.exports = grammar({
949
979
  // - C-style legacy octal: 0177
950
980
  // - Hex float: 0x1.8
951
981
  // - Uppercase prefixes: 0O, 0B (already in JS grammar)
982
+ //
983
+ // Unlike JS, ucode does NOT support:
984
+ // - numeric underscore separators (1_000)
985
+ // - leading-dot floats (.5) — a digit is required before the dot
952
986
  number: _ => {
953
- const hexDigits = /[\da-fA-F](_?[\da-fA-F])*/;
987
+ const hexDigits = /[\da-fA-F]+/;
954
988
  const hexLiteral = seq(choice('0x', '0X'), hexDigits);
955
989
  const hexFloat = seq(choice('0x', '0X'), hexDigits, '.', optional(hexDigits));
956
990
 
957
- const decimalDigits = /\d(_?\d)*/;
991
+ const decimalDigits = /\d+/;
958
992
  const signedInteger = seq(optional(choice('-', '+')), decimalDigits);
959
993
  const exponentPart = seq(choice('e', 'E'), signedInteger);
960
994
 
961
- const binaryLiteral = seq(choice('0b', '0B'), /[0-1](_?[0-1])*/);
962
- const octalLiteral = seq(choice('0o', '0O'), /[0-7](_?[0-7])*/);
995
+ const binaryLiteral = seq(choice('0b', '0B'), /[0-1]+/);
996
+ const octalLiteral = seq(choice('0o', '0O'), /[0-7]+/);
963
997
  const legacyOctalLiteral = seq('0', /[0-7]+/);
964
998
 
965
999
  const decimalIntegerLiteral = choice(
966
1000
  '0',
967
- seq(optional('0'), /[1-9]/, optional(seq(optional('_'), decimalDigits))),
1001
+ seq(optional('0'), /[1-9]/, optional(decimalDigits)),
968
1002
  );
969
1003
 
970
1004
  const decimalLiteral = choice(
971
1005
  seq(decimalIntegerLiteral, '.', optional(decimalDigits), optional(exponentPart)),
972
- seq('.', decimalDigits, optional(exponentPart)),
973
1006
  seq(decimalIntegerLiteral, exponentPart),
974
1007
  decimalDigits,
975
1008
  );
@@ -986,9 +1019,12 @@ module.exports = grammar({
986
1019
 
987
1020
  _identifier: $ => $.identifier,
988
1021
 
1022
+ // ucode does NOT support unicode escape sequences in identifiers (unlike JS);
1023
+ // a literal `\u...` is an "Unexpected character". Non-ASCII letters are still
1024
+ // allowed directly via the negated character class.
989
1025
  identifier: _ => {
990
- const alpha = /[^\x00-\x1F\s\p{Zs}0-9:;`"'@#.,|^&<=>+\-*/\\%?!~()\[\]{}\uFEFF\u2060\u200B\u2028\u2029]|\\u[0-9a-fA-F]{4}|\\u\{[0-9a-fA-F]+\}/;
991
- const alphanumeric = /[^\x00-\x1F\s\p{Zs}:;`"'@#.,|^&<=>+\-*/\\%?!~()\[\]{}\uFEFF\u2060\u200B\u2028\u2029]|\\u[0-9a-fA-F]{4}|\\u\{[0-9a-fA-F]+\}/;
1026
+ const alpha = /[^\x00-\x1F\s\p{Zs}0-9:;`"'@#.,|^&<=>+\-*/\\%?!~()\[\]{}\uFEFF\u2060\u200B\u2028\u2029]/;
1027
+ const alphanumeric = /[^\x00-\x1F\s\p{Zs}:;`"'@#.,|^&<=>+\-*/\\%?!~()\[\]{}\uFEFF\u2060\u200B\u2028\u2029]/;
992
1028
  return token(seq(alpha, repeat(alphanumeric)));
993
1029
  },
994
1030
 
@@ -997,9 +1033,11 @@ module.exports = grammar({
997
1033
  false: _ => 'false',
998
1034
  null: _ => 'null',
999
1035
 
1036
+ // Unlike arrays/objects, ucode call arguments allow neither interior
1037
+ // elision (`f(1,,2)`) nor a trailing comma (`f(1,2,)`).
1000
1038
  arguments: $ => seq(
1001
1039
  '(',
1002
- commaSep(optional(choice($.expression, $.spread_element))),
1040
+ commaSep(choice($.expression, $.spread_element)),
1003
1041
  ')',
1004
1042
  ),
1005
1043