tree-sitter-ucode 0.1.2 → 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/README.md CHANGED
@@ -7,7 +7,12 @@ Two grammars are provided:
7
7
  | Grammar | Scope | File types |
8
8
  |---------|-------|------------|
9
9
  | `ucode` | `source.uc` | `.uc` |
10
- | `ucode_tmpl` | `source.uc.tmpl` | `.uc.tmpl`, `.utpl` |
10
+ | `ucode_tmpl` | `source.uc.tmpl` | `.uc` (template files — detected by content) |
11
+
12
+ Both grammars use the `.uc` extension. Template files are distinguished from plain
13
+ code files by content: any `.uc` file whose first tag opener (`{%`, `{{`, or `{#`)
14
+ appears at the start of a line is automatically parsed by `ucode_tmpl`. Plain code
15
+ files fall back to `ucode`. See [File-type detection](#file-type-detection) below.
11
16
 
12
17
  ## Ucode vs JavaScript
13
18
 
@@ -17,13 +22,12 @@ Ucode is an ECMAScript subset with OpenWrt-specific extensions. Key differences:
17
22
  |---------|-------|------------|
18
23
  | Alternative block syntax | `if/elif/else/endif`, `for/endfor`, `while/endwhile`, `function/endfunction` | Not supported |
19
24
  | Two-variable for-in | `for (k, v in obj)` | Single variable only |
20
- | Forward declaration | `function foo;` | Not supported |
21
- | Removed keywords | `var`, `new`, `typeof`, `void`, `class`, `instanceof`, `do`, `async`, `await`, `yield` | All supported |
22
- | Removed features | Destructuring, `for...of`, `do-while`, generators | All supported |
25
+ | Removed keywords | `var`, `new`, `throw`, `typeof`, `void`, `class`, `instanceof`, `do`, `async`, `await`, `yield` | All supported |
26
+ | Removed features | Destructuring, `for...of`, `do-while`, generators, forward declarations, dynamic `import()` | All supported |
23
27
  | Added number literals | `0177` (C octal), `0x1.8` (hex float), `0B`/`0O` prefixes | Standard only |
24
28
  | Added escape sequences | `\e` (ESC), `\a` (BEL), octal `\177` | Standard only |
25
29
  | Regex flags | `g`, `i`, `s` only | Full set |
26
- | Module system | Static `import`/`export`, dynamic `import(path)`; no `from` on re-exports | Full ES modules |
30
+ | Module system | Static `import`/`export` only; no `from` on re-exports | Full ES modules |
27
31
 
28
32
  ## Requirements
29
33
 
@@ -56,10 +60,18 @@ npm test # runs tree-sitter test for ucode and ucode_tmpl
56
60
  To filter by corpus file name:
57
61
 
58
62
  ```sh
59
- npx tree-sitter test --file-name control_flow
63
+ npx tree-sitter test --lib-path ucode.so --lang-name ucode --file-name control_flow
60
64
  npx tree-sitter test -p tmpl --file-name template
61
65
  ```
62
66
 
67
+ ## File-type detection
68
+
69
+ Both grammars claim the `.uc` extension. Tools that respect `content-regex` in
70
+ `tree-sitter.json` (including the tree-sitter CLI ≥ 0.24) automatically route
71
+ template files to `ucode_tmpl` when a tag opener appears at the start of a line.
72
+ Editors that manage their own filetype dispatch (Neovim, Helix) need an explicit
73
+ rule — see the editor sections below.
74
+
63
75
  ## Use in Neovim (nvim-treesitter)
64
76
 
65
77
  Add to your nvim-treesitter config (e.g. `~/.config/nvim/lua/plugins/treesitter.lua`):
@@ -86,15 +98,26 @@ parser_config.ucode_tmpl = {
86
98
  }
87
99
  ```
88
100
 
89
- Associate `.uc` and `.uc.tmpl` files with the right filetypes:
101
+ Associate `.uc` files with the right filetype. Since nvim-treesitter does not
102
+ use `content-regex`, the mapping must be done with a `BufRead` autocmd or a
103
+ filetype function that inspects the file content:
90
104
 
91
105
  ```lua
92
106
  vim.filetype.add({
93
107
  extension = {
94
- uc = "ucode",
95
- utpl = "ucode_tmpl",
108
+ uc = function(path)
109
+ -- Files whose first tag opener is at the start of a line are templates
110
+ local f = io.open(path, "r")
111
+ if f then
112
+ local content = f:read("*a")
113
+ f:close()
114
+ if content:find("^%s*{[%%{#]", 1, false) or content:find("\n%s*{[%%{#]") then
115
+ return "ucode_tmpl"
116
+ end
117
+ end
118
+ return "ucode"
119
+ end,
96
120
  },
97
- pattern = { [".*%.uc%.tmpl"] = "ucode_tmpl" },
98
121
  })
99
122
  ```
100
123
 
@@ -104,32 +127,38 @@ Add to `~/.config/helix/languages.toml`:
104
127
 
105
128
  ```toml
106
129
  [[language]]
107
- name = "ucode"
108
- scope = "source.uc"
109
- file-types = ["uc"]
130
+ name = "ucode"
131
+ scope = "source.uc"
132
+ file-types = [{ glob = "*.uc" }]
110
133
  comment-token = "//"
111
- indent = { tab-width = 2, unit = " " }
112
- grammar = "ucode"
134
+ indent = { tab-width = 2, unit = " " }
135
+ grammar = "ucode"
113
136
 
114
137
  [[language]]
115
- name = "ucode-tmpl"
116
- scope = "source.uc.tmpl"
117
- file-types = ["uc.tmpl", "utpl"]
118
- grammar = "ucode_tmpl"
138
+ name = "ucode-tmpl"
139
+ scope = "source.uc.tmpl"
140
+ comment-token = "{#"
141
+ indent = { tab-width = 2, unit = " " }
142
+ grammar = "ucode_tmpl"
119
143
 
120
144
  [[grammar]]
121
145
  name = "ucode"
122
- source = { git = "https://github.com/m00qek/tree-sitter-ucode", rev = "main" }
146
+ source = { git = "https://github.com/m00qek/tree-sitter-ucode", rev = "v0.3.0" }
123
147
 
124
148
  [[grammar]]
125
149
  name = "ucode_tmpl"
126
- source = { git = "https://github.com/m00qek/tree-sitter-ucode", rev = "main", subpath = "tmpl" }
150
+ source = { git = "https://github.com/m00qek/tree-sitter-ucode", rev = "v0.3.0", subpath = "tmpl" }
127
151
  ```
128
152
 
129
- ## Template files (.uc.tmpl / .utpl)
153
+ Helix does not support content-based filetype detection. To open a `.uc`
154
+ template file as `ucode-tmpl`, use `:set-language ucode-tmpl` in command mode,
155
+ or configure a file-specific override via a `.helix/languages.toml` in your
156
+ project.
157
+
158
+ ## Template files
130
159
 
131
- Template files mix raw text with code tags. The `ucode_tmpl` grammar produces
132
- a document tree; editors use language injection to apply ucode highlighting
160
+ Template files mix raw text with code tags. The `ucode_tmpl` grammar produces a
161
+ `document` tree; editors use language injection to apply ucode highlighting
133
162
  inside the code and expression tags.
134
163
 
135
164
  | Tag | Purpose |
@@ -142,7 +171,17 @@ inside the code and expression tags.
142
171
  | `{%+ ... %}` | Statement block — suppress `lstrip_blocks` stripping |
143
172
  | `{#- ... -#}` | Comment — strip whitespace on both sides |
144
173
 
145
- Opener and closer markers are independent: any opener variant may be combined with any closer variant. `{%-` / `{{-` / `{#-` strip the preceding raw text; `-%}` / `-}}` / `-#}` strip the following raw text. `{%+` suppresses `lstrip_blocks` stripping and may be combined with `-%}` (e.g. `{%+ ... -%}`).
174
+ Opener and closer markers are independent: any opener variant may be combined
175
+ with any closer variant. `{%-` / `{{-` / `{#-` strip the preceding raw text;
176
+ `-%}` / `-}}` / `-#}` strip the following raw text. `{%+` suppresses
177
+ `lstrip_blocks` stripping and may be combined with `-%}`.
178
+
179
+ **EOF-implicit close**: a `{%` statement tag that reaches end-of-file without
180
+ an explicit `%}` is treated as implicitly closed. This supports the common
181
+ OpenWrt pattern of a file that opens one `{%` block at the top and contains
182
+ only ucode code, with no closing `%}`. The parse tree shows an `(eof_close)`
183
+ node in the `close` field. Expression (`{{`) and comment (`{#`) tags still
184
+ require explicit closers.
146
185
 
147
186
  Example:
148
187
 
package/grammar.js CHANGED
@@ -46,6 +46,7 @@ module.exports = grammar({
46
46
  'if',
47
47
  'import',
48
48
  'in',
49
+ 'let',
49
50
  'null',
50
51
  'return',
51
52
  'switch',
@@ -99,7 +100,6 @@ module.exports = grammar({
99
100
  ['member', 'call', $.expression],
100
101
  ['declaration', 'literal'],
101
102
  [$.primary_expression, $.statement_block, 'object'],
102
- [$.import_statement, $.import],
103
103
  [$.export_statement, $.primary_expression],
104
104
  [$.lexical_declaration, $.primary_expression],
105
105
  ],
@@ -143,7 +143,7 @@ module.exports = grammar({
143
143
  'default',
144
144
  seq(
145
145
  field('value', $.expression),
146
- $._semicolon,
146
+ ';',
147
147
  ),
148
148
  ),
149
149
  ),
@@ -173,18 +173,14 @@ module.exports = grammar({
173
173
 
174
174
  declaration: $ => choice(
175
175
  $.function_declaration,
176
- $.function_forward_declaration,
177
176
  $.lexical_declaration,
178
177
  ),
179
178
 
180
179
  //
181
180
  // Import declarations
182
181
  // Ucode keeps full ES module static import syntax.
183
- // Also adds dynamic `import(path)` as a unary expression (see import_expression).
184
182
  //
185
183
 
186
- import: _ => token('import'),
187
-
188
184
  import_statement: $ => seq(
189
185
  'import',
190
186
  choice(
@@ -461,7 +457,6 @@ module.exports = grammar({
461
457
  $.binary_expression,
462
458
  $.ternary_expression,
463
459
  $.update_expression,
464
- $.import_expression,
465
460
  ),
466
461
 
467
462
  primary_expression: $ => choice(
@@ -485,14 +480,6 @@ module.exports = grammar({
485
480
  $.call_expression,
486
481
  ),
487
482
 
488
- // Dynamic import expression: `let m = import("./mod.uc")`
489
- import_expression: $ => prec('call', seq(
490
- $.import,
491
- '(',
492
- field('source', $.expression),
493
- ')',
494
- )),
495
-
496
483
  object: $ => prec('object', seq(
497
484
  '{',
498
485
  commaSep(optional(choice(
@@ -662,13 +649,6 @@ module.exports = grammar({
662
649
  optional($._automatic_semicolon),
663
650
  )),
664
651
 
665
- // Forward declaration: `function name;`
666
- function_forward_declaration: $ => seq(
667
- 'function',
668
- field('name', $.identifier),
669
- ';',
670
- ),
671
-
672
652
  arrow_function: $ => seq(
673
653
  choice(
674
654
  field('parameter', choice(
@@ -857,7 +837,6 @@ module.exports = grammar({
857
837
  _reserved_identifier: _ => choice(
858
838
  'get',
859
839
  'set',
860
- 'let',
861
840
  ),
862
841
 
863
842
  _semicolon: $ => choice($._automatic_semicolon, ';'),
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "tree-sitter-ucode",
3
- "version": "0.1.2",
3
+ "version": "0.3.0",
4
4
  "description": "Ucode grammar for tree-sitter",
5
5
  "repository": {
6
6
  "type": "git",
@@ -35,7 +35,7 @@
35
35
  },
36
36
  "devDependencies": {
37
37
  "prebuildify": "^6.0.1",
38
- "tree-sitter-cli": "^0.26.0"
38
+ "tree-sitter-cli": "0.26.9"
39
39
  },
40
40
  "peerDependencies": {
41
41
  "tree-sitter": "^0.22.0"
@@ -48,7 +48,7 @@
48
48
  "scripts": {
49
49
  "install": "node-gyp-build",
50
50
  "build": "tree-sitter generate && tree-sitter generate tmpl/grammar.js --output tmpl/src && node-gyp-build && tree-sitter build --output ucode.so . && tree-sitter build --output ucode_tmpl.so ./tmpl",
51
- "test": "tree-sitter test && tree-sitter test -p tmpl",
51
+ "test": "node scripts/run-tests.js",
52
52
  "prestart": "tree-sitter build --wasm",
53
53
  "start": "tree-sitter playground"
54
54
  }
@@ -0,0 +1,38 @@
1
+ ; Fold queries for ucode.
2
+ ; Each captured node becomes a collapsible fold region.
3
+
4
+ ; -------------------------------------------------------------------------
5
+ ; Brace-delimited blocks
6
+ ;
7
+ ; statement_block covers brace-body function_declaration, function_expression,
8
+ ; and arrow_function bodies — the signature line stays visible because the
9
+ ; fold starts at '{', not at the 'function' keyword.
10
+ ; -------------------------------------------------------------------------
11
+
12
+ [
13
+ (statement_block)
14
+ (switch_body)
15
+ (object)
16
+ (array)
17
+ ] @fold
18
+
19
+ ; -------------------------------------------------------------------------
20
+ ; Alternative (colon/endif) syntax — fold the entire construct
21
+ ; -------------------------------------------------------------------------
22
+
23
+ [
24
+ (if_alt_statement)
25
+ (for_alt_statement)
26
+ (for_in_alt_statement)
27
+ (while_alt_statement)
28
+ ] @fold
29
+
30
+ ; -------------------------------------------------------------------------
31
+ ; Colon-body function declaration (function f(): ... endfunction)
32
+ ;
33
+ ; Brace-body function declarations are folded via (statement_block) above.
34
+ ; The colon form has no statement_block, so we fold the whole declaration.
35
+ ; We filter on "endfunction" so this pattern only matches the colon form.
36
+ ; -------------------------------------------------------------------------
37
+
38
+ (function_declaration "endfunction") @fold
@@ -53,9 +53,6 @@
53
53
  (function_declaration
54
54
  name: (identifier) @function)
55
55
 
56
- (function_forward_declaration
57
- name: (identifier) @function)
58
-
59
56
  (function_expression
60
57
  name: (identifier) @function)
61
58
 
@@ -121,8 +118,12 @@
121
118
 
122
119
  ["import" "export"] @keyword.import
123
120
  ["as" "from"] @keyword.import
124
- ; Dynamic import() uses a named node, not an anonymous string
125
- (import_expression (import) @keyword.import)
121
+
122
+ ; 'default' in export context is a module keyword, not a conditional.
123
+ ; These patterns are more specific than the generic ["switch" "case" "default"]
124
+ ; below, so they take priority for 'default' tokens inside export constructs.
125
+ (export_statement "default" @keyword.import)
126
+ (export_specifier "default" @keyword.import)
126
127
 
127
128
  ; -------------------------------------------------------------------------
128
129
  ; Keywords — storage / operators
@@ -0,0 +1,63 @@
1
+ ; Indentation queries for ucode.
2
+ ; Capture names follow the nvim-treesitter standard.
3
+
4
+ ; -------------------------------------------------------------------------
5
+ ; Brace-delimited constructs — increase indent inside
6
+ ; -------------------------------------------------------------------------
7
+
8
+ [
9
+ (statement_block)
10
+ (switch_body)
11
+ (object)
12
+ (array)
13
+ (arguments)
14
+ (formal_parameters)
15
+ ] @indent.begin
16
+
17
+ ; Closing delimiters — decrease indent
18
+ [
19
+ "}"
20
+ "]"
21
+ ")"
22
+ ] @indent.end
23
+
24
+ ; -------------------------------------------------------------------------
25
+ ; Alternative (colon/endif) syntax
26
+ ; -------------------------------------------------------------------------
27
+
28
+ ; The ':' after the condition opens the body
29
+ (if_alt_statement ":" @indent.begin)
30
+ (elif_clause ":" @indent.begin)
31
+ (for_alt_statement ":" @indent.begin)
32
+ (for_in_alt_statement ":" @indent.begin)
33
+ (while_alt_statement ":" @indent.begin)
34
+ (function_declaration ":" @indent.begin)
35
+
36
+ ; Closing keywords close the body
37
+ [
38
+ "endif"
39
+ "endfor"
40
+ "endwhile"
41
+ "endfunction"
42
+ ] @indent.end
43
+
44
+ ; -------------------------------------------------------------------------
45
+ ; Branch keywords (else/elif) — dedent keyword, indent following body
46
+ ; -------------------------------------------------------------------------
47
+
48
+ (else_clause "else") @indent.branch
49
+ (else_alt_clause "else") @indent.branch
50
+ (elif_clause "elif") @indent.branch
51
+
52
+ ; else_alt_clause has no ':' delimiter (grammar: 'else' repeat(statement)),
53
+ ; so @indent.branch alone only dedents the 'else' keyword — it does not
54
+ ; open an indent scope for the body. Add @indent.begin on the whole node
55
+ ; so the body statements are indented one level relative to 'else'.
56
+ (else_alt_clause) @indent.begin
57
+
58
+ ; -------------------------------------------------------------------------
59
+ ; Switch
60
+ ; -------------------------------------------------------------------------
61
+
62
+ (switch_case "case") @indent.branch
63
+ (switch_default "default") @indent.branch
@@ -6,7 +6,6 @@
6
6
  ; -------------------------------------------------------------------------
7
7
 
8
8
  (function_declaration) @local.scope
9
- ; function_forward_declaration has no body — it is a definition, not a scope
10
9
  (function_expression) @local.scope
11
10
  (arrow_function) @local.scope
12
11
  ; statement_block provides block scoping for let/const
@@ -23,16 +22,12 @@
23
22
  ; Definitions — functions
24
23
  ; -------------------------------------------------------------------------
25
24
 
26
- ; Declaration and forward-declaration names belong to the *enclosing* scope
27
- ; so that callers outside the function body can resolve them.
25
+ ; Function declaration names belong to the enclosing scope so that
26
+ ; callers outside the function body can resolve them.
28
27
  (function_declaration
29
28
  name: (identifier) @local.definition.function
30
29
  (#set! definition.function.scope parent))
31
30
 
32
- (function_forward_declaration
33
- name: (identifier) @local.definition.function
34
- (#set! definition.function.scope parent))
35
-
36
31
  ; Named function expressions (let f = function foo() {}) keep their name
37
32
  ; *inside* the expression scope — foo is only visible for self-recursion,
38
33
  ; not to the surrounding block. No (#set! parent) here.
package/queries/tags.scm CHANGED
@@ -14,19 +14,6 @@
14
14
  (#select-adjacent! @doc @definition.function)
15
15
  )
16
16
 
17
- ; -------------------------------------------------------------------------
18
- ; Function definitions — forward declarations: `function name;`
19
- ; -------------------------------------------------------------------------
20
-
21
- (
22
- (comment)* @doc
23
- .
24
- (function_forward_declaration
25
- name: (identifier) @name) @definition.function
26
- (#strip! @doc "^[\\s\\*/]+|^[\\s\\*/]$")
27
- (#select-adjacent! @doc @definition.function)
28
- )
29
-
30
17
  ; -------------------------------------------------------------------------
31
18
  ; Function definitions — named function expressions
32
19
  ; -------------------------------------------------------------------------
@@ -0,0 +1,84 @@
1
+ ; Text-object queries for nvim-treesitter-textobjects.
2
+ ; Provides @function, @parameter, @conditional, @loop, @call, and @block
3
+ ; text objects for ucode source files.
4
+
5
+ ; -------------------------------------------------------------------------
6
+ ; Functions
7
+ ; -------------------------------------------------------------------------
8
+
9
+ ; Brace-body function declaration
10
+ (function_declaration
11
+ body: (statement_block) @function.inner) @function.outer
12
+
13
+ ; Colon-body function declaration — outer only; no block node to target for inner
14
+ (function_declaration "endfunction") @function.outer
15
+
16
+ (function_expression
17
+ body: (statement_block) @function.inner) @function.outer
18
+
19
+ (arrow_function
20
+ body: (statement_block) @function.inner) @function.outer
21
+
22
+ ; Arrow function with expression body (no braces).
23
+ ; Uses the 'expression' supertype so all expression forms are matched
24
+ ; without an explicit enumeration — including update_expression (x => x++),
25
+ ; assignment_expression (x => y = 1), and any type added to the grammar later.
26
+ (arrow_function
27
+ body: (expression) @function.inner) @function.outer
28
+
29
+ ; -------------------------------------------------------------------------
30
+ ; Parameters
31
+ ;
32
+ ; @parameter.inner — the parameter node itself
33
+ ; @parameter.outer — same node; nvim-treesitter-textobjects extends the
34
+ ; selection to absorb adjacent ',' delimiters automatically when the
35
+ ; capture name ends in .outer
36
+ ; -------------------------------------------------------------------------
37
+
38
+ (formal_parameters (_) @parameter.inner)
39
+ (formal_parameters (_) @parameter.outer)
40
+
41
+ ; -------------------------------------------------------------------------
42
+ ; Conditionals
43
+ ; -------------------------------------------------------------------------
44
+
45
+ (if_statement
46
+ consequence: (statement_block) @conditional.inner) @conditional.outer
47
+
48
+ (if_alt_statement) @conditional.outer
49
+
50
+ ; -------------------------------------------------------------------------
51
+ ; Loops
52
+ ; -------------------------------------------------------------------------
53
+
54
+ (for_statement
55
+ body: (statement_block) @loop.inner) @loop.outer
56
+
57
+ (for_in_statement
58
+ body: (statement_block) @loop.inner) @loop.outer
59
+
60
+ (while_statement
61
+ body: (statement_block) @loop.inner) @loop.outer
62
+
63
+ (for_alt_statement) @loop.outer
64
+ (for_in_alt_statement) @loop.outer
65
+ (while_alt_statement) @loop.outer
66
+
67
+ ; -------------------------------------------------------------------------
68
+ ; Calls
69
+ ; -------------------------------------------------------------------------
70
+
71
+ (call_expression
72
+ arguments: (arguments) @call.inner) @call.outer
73
+
74
+ ; -------------------------------------------------------------------------
75
+ ; Blocks
76
+ ;
77
+ ; @block.outer — the full statement_block including braces
78
+ ; @block.inner — named children only; nvim-treesitter-textobjects selects
79
+ ; from the first to the last captured child, covering the block interior
80
+ ; without needing the deprecated #make-range! predicate
81
+ ; -------------------------------------------------------------------------
82
+
83
+ (statement_block) @block.outer
84
+ (statement_block (_) @block.inner)
package/src/grammar.json CHANGED
@@ -88,8 +88,8 @@
88
88
  }
89
89
  },
90
90
  {
91
- "type": "SYMBOL",
92
- "name": "_semicolon"
91
+ "type": "STRING",
92
+ "value": ";"
93
93
  }
94
94
  ]
95
95
  }
@@ -221,23 +221,12 @@
221
221
  "type": "SYMBOL",
222
222
  "name": "function_declaration"
223
223
  },
224
- {
225
- "type": "SYMBOL",
226
- "name": "function_forward_declaration"
227
- },
228
224
  {
229
225
  "type": "SYMBOL",
230
226
  "name": "lexical_declaration"
231
227
  }
232
228
  ]
233
229
  },
234
- "import": {
235
- "type": "TOKEN",
236
- "content": {
237
- "type": "STRING",
238
- "value": "import"
239
- }
240
- },
241
230
  "import_statement": {
242
231
  "type": "SEQ",
243
232
  "members": [
@@ -1690,10 +1679,6 @@
1690
1679
  {
1691
1680
  "type": "SYMBOL",
1692
1681
  "name": "update_expression"
1693
- },
1694
- {
1695
- "type": "SYMBOL",
1696
- "name": "import_expression"
1697
1682
  }
1698
1683
  ]
1699
1684
  },
@@ -1779,35 +1764,6 @@
1779
1764
  }
1780
1765
  ]
1781
1766
  },
1782
- "import_expression": {
1783
- "type": "PREC",
1784
- "value": "call",
1785
- "content": {
1786
- "type": "SEQ",
1787
- "members": [
1788
- {
1789
- "type": "SYMBOL",
1790
- "name": "import"
1791
- },
1792
- {
1793
- "type": "STRING",
1794
- "value": "("
1795
- },
1796
- {
1797
- "type": "FIELD",
1798
- "name": "source",
1799
- "content": {
1800
- "type": "SYMBOL",
1801
- "name": "expression"
1802
- }
1803
- },
1804
- {
1805
- "type": "STRING",
1806
- "value": ")"
1807
- }
1808
- ]
1809
- }
1810
- },
1811
1767
  "object": {
1812
1768
  "type": "PREC",
1813
1769
  "value": "object",
@@ -3472,27 +3428,6 @@
3472
3428
  ]
3473
3429
  }
3474
3430
  },
3475
- "function_forward_declaration": {
3476
- "type": "SEQ",
3477
- "members": [
3478
- {
3479
- "type": "STRING",
3480
- "value": "function"
3481
- },
3482
- {
3483
- "type": "FIELD",
3484
- "name": "name",
3485
- "content": {
3486
- "type": "SYMBOL",
3487
- "name": "identifier"
3488
- }
3489
- },
3490
- {
3491
- "type": "STRING",
3492
- "value": ";"
3493
- }
3494
- ]
3495
- },
3496
3431
  "arrow_function": {
3497
3432
  "type": "SEQ",
3498
3433
  "members": [
@@ -4666,10 +4601,6 @@
4666
4601
  {
4667
4602
  "type": "STRING",
4668
4603
  "value": "set"
4669
- },
4670
- {
4671
- "type": "STRING",
4672
- "value": "let"
4673
4604
  }
4674
4605
  ]
4675
4606
  },
@@ -4842,16 +4773,6 @@
4842
4773
  "value": "object"
4843
4774
  }
4844
4775
  ],
4845
- [
4846
- {
4847
- "type": "SYMBOL",
4848
- "name": "import_statement"
4849
- },
4850
- {
4851
- "type": "SYMBOL",
4852
- "name": "import"
4853
- }
4854
- ],
4855
4776
  [
4856
4777
  {
4857
4778
  "type": "SYMBOL",
@@ -4984,6 +4905,10 @@
4984
4905
  "type": "STRING",
4985
4906
  "value": "in"
4986
4907
  },
4908
+ {
4909
+ "type": "STRING",
4910
+ "value": "let"
4911
+ },
4987
4912
  {
4988
4913
  "type": "STRING",
4989
4914
  "value": "null"