tree-sitter-batch 0.8.0 → 0.10.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.
package/README.md CHANGED
@@ -6,10 +6,11 @@ Parses `.bat` and `.cmd` files into a concrete syntax tree for syntax highlighti
6
6
 
7
7
  ## Features
8
8
 
9
- - **Control flow** — `IF`/`ELSE` (EXIST, DEFINED, ERRORLEVEL, comparison with NOT), `FOR` (/D /R /L /F), `GOTO`, `CALL`
10
- - **Variables** — `SET` (plain, `/A` arithmetic, `/P` prompt), `%VAR%`, `!VAR!`, `%%i`, `%~dp0`, `%VAR:old=new%`
11
- - **Operators** — pipes `|`, redirects `>` `>>` `2>` `2>&1`, conditional `&&` `||`
12
- - **Structure** — labels `:name`, comments `REM` `::`, parenthesized blocks, `@ECHO OFF`
9
+ - **Control flow** — `IF`/`ELSE` (EXIST, DEFINED, ERRORLEVEL, comparison with NOT), `FOR` (/D /R /L /F), `GOTO`, `CALL`, `EXIT /B`
10
+ - **Variables** — `SET` (plain, `/A` arithmetic, `/P` prompt), `%VAR%`, `!VAR!`, `%%i`, `%~dp0`, `%VAR:old=new%`, escaped forms `%%VAR%%` `%%%%i`
11
+ - **Echo** — free-form text with literal `(` `)` `!` `%`, inline strings, and variable references
12
+ - **Operators** — pipes `|`, redirects `>` `>>` `2>` `2>&1`, conditional `&&` `||`, separator `&`
13
+ - **Structure** — labels `:name`, comments `REM` `::`, parenthesized blocks, `@ECHO OFF`, macro invocations
13
14
  - **Scope** — `SETLOCAL`/`ENDLOCAL` with `ENABLEDELAYEDEXPANSION`
14
15
  - **Case-insensitive** — all keywords match regardless of casing
15
16
 
@@ -51,20 +52,20 @@ Parsed tree:
51
52
  (variable_assignment
52
53
  (set_keyword) (variable_name) (assignment_value))
53
54
  (variable_assignment
54
- (set_keyword) (set_option) (variable_name) (assignment_value))
55
+ (set_keyword) (arithmetic_assignment (set_option) (arithmetic_expression)))
55
56
  (if_stmt
56
57
  (string)
57
58
  (parenthesized
58
59
  (cmd (command_name) (argument_list (argument_value)))))
59
60
  (for_stmt
60
61
  (for_variable)
61
- (for_set)
62
+ (for_set (for_set_literal))
62
63
  (parenthesized
63
64
  (cmd (command_name) (argument_list (string) (string)))))
64
65
  (if_stmt
65
66
  (variable_reference)
66
67
  (comparison_op)
67
- (integer)
68
+ (argument_value)
68
69
  (parenthesized
69
70
  (cmd (command_name) (argument_list (argument_value) (argument_value))))
70
71
  (else_clause
package/grammar.js CHANGED
@@ -1,5 +1,23 @@
1
1
  const ci = (word) => new RegExp(word.split('').map((c) => /[a-zA-Z]/.test(c) ? `[${c.toLowerCase()}${c.toUpperCase()}]` : c).join(''));
2
2
  const kw = (word) => token(prec(10, ci(word)));
3
+ const varRefChoice = () => choice(
4
+ seq('%%', /[$@a-zA-Z_][$@a-zA-Z0-9_.#()\[\]]*/, '%%'),
5
+ seq('%', /[$@a-zA-Z_][$@a-zA-Z0-9_.#()\[\]]*/, '%'),
6
+ seq('%~', /[a-zA-Z]*/, /[0-9]/),
7
+ seq('%', /[0-9]/),
8
+ '%*',
9
+ seq('%%%%%%', optional('~'), /[a-zA-Z0-9]/),
10
+ seq('%%%%', optional('~'), /[a-zA-Z0-9]/),
11
+ seq('%%', optional('~'), /[a-zA-Z]/),
12
+ seq('%%', /[0-9]/),
13
+ seq('!', /[$%a-zA-Z_][$a-zA-Z0-9_.#]*/, '!'),
14
+ seq('%', /[$@a-zA-Z_][$@a-zA-Z0-9_.#()\[\]]*/, ':', /[^%\r\n]+/, '%'),
15
+ seq('%', /[^%=\s\r\n]/, '%'),
16
+ seq('!', /[%$a-zA-Z_][%$a-zA-Z0-9_.#()\[\]]*/, /:[^!\r\n]+/, '!'),
17
+ seq('%', /[<>\/]+[@a-zA-Z_0-9.]*/, '%'),
18
+ seq('%', /\\[@a-zA-Z_0-9.]+/, '%'),
19
+ seq('%', /"[^"%\r\n]+"/, '%'),
20
+ );
3
21
  const operand = ($) => [
4
22
  $.cond_exec, $.pipe_stmt, $.redirect_stmt, $.call_stmt, $.cmd, $.parenthesized,
5
23
  $.variable_assignment, $.goto_stmt, $.exit_stmt, $.setlocal_stmt, $.endlocal_stmt,
@@ -93,11 +111,11 @@ export default grammar({
93
111
  ))),
94
112
  if_stmt: ($) => prec.right(8, seq(
95
113
  optional('@'), kw('if'),
96
- optional(alias(ci('/i'), $.if_option)),
114
+ optional(alias(token(prec(2, ci('/i'))), $.if_option)),
97
115
  optional(kw('not')),
98
116
  choice(
99
- seq(kw('exist'), choice($.string, $.variable_reference, $.argument_value)),
100
- seq(kw('defined'), choice(/[$a-zA-Z_][$a-zA-Z0-9_.]*/, $.string, $.variable_reference)),
117
+ seq(kw('exist'), $._if_operand),
118
+ seq(kw('defined'), choice(/[$a-zA-Z_][$a-zA-Z0-9_.]*/, $._if_operand)),
101
119
  seq(kw('errorlevel'), $.integer),
102
120
  seq(
103
121
  $._if_operand,
@@ -122,10 +140,17 @@ export default grammar({
122
140
  $.redirect_stmt, $.pipe_stmt, $.comment,
123
141
  ),
124
142
  _if_operand: ($) => choice(
125
- $.string, $.variable_reference, $.integer, $.bracketed_value,
126
- alias($._if_word, $.argument_value),
143
+ $.string, $.bracketed_value, $.paren_expression,
144
+ prec.right(seq(
145
+ choice($.variable_reference, alias($._if_word, $.argument_value), $.integer),
146
+ repeat(choice(
147
+ alias($._variable_reference_immediate, $.variable_reference),
148
+ alias($._if_word_rest, $.argument_value),
149
+ )),
150
+ )),
127
151
  ),
128
- _if_word: () => token(prec(-1, /[^=<>\s\[\]"|&()][^=<>\s"|&()]*/)),
152
+ _if_word: () => token(prec(1, /[^=<>\s\[\]"|&()%!][^=<>\s"|&()%!]*/)),
153
+ _if_word_rest: () => token.immediate(/[^=<>\s\[\]"|&()%!][^=<>\s"|&()%!]*/),
129
154
  comparison_op: () => token(prec(10, choice('==', ci('equ'), ci('neq'), ci('lss'), ci('leq'), ci('gtr'), ci('geq')))),
130
155
  goto_stmt: ($) => prec(8, seq(
131
156
  optional('@'), kw('goto'),
@@ -202,23 +227,20 @@ export default grammar({
202
227
  '&',
203
228
  choice(...operand($), $.comment),
204
229
  )),
205
- variable_reference: () => token(choice(
206
- seq('%', /[$@a-zA-Z_][$@a-zA-Z0-9_.#()\[\]]*/, '%'),
207
- seq('%~', /[a-zA-Z]*/, /[0-9]/),
208
- seq('%', /[0-9]/),
209
- '%*',
210
- seq('%%', optional('~'), /[a-zA-Z]/),
211
- seq('!', /[$%a-zA-Z_][$a-zA-Z0-9_.#]*/, '!'),
212
- seq('%', /[$@a-zA-Z_][$@a-zA-Z0-9_.#()\[\]]*/, ':', /[^%\r\n]+/, '%'),
213
- seq('%', /[^%=\s\r\n]/, '%'),
214
- seq('!', /[%$a-zA-Z_][%$a-zA-Z0-9_.#()\[\]]*/, /:[^!\r\n]+/, '!'),
215
- seq('%', /[<>\/]+[@a-zA-Z_0-9.]*/, '%'),
216
- seq('%', /\\[@a-zA-Z_0-9.]+/, '%'),
217
- seq('%', /"[^"%\r\n]+"/, '%'),
218
- )),
230
+ variable_reference: () => token(varRefChoice()),
231
+ _variable_reference_immediate: () => token.immediate(varRefChoice()),
219
232
  string: () => token(seq('"', /[^"\r\n]*/, '"')),
220
233
  bracketed_value: ($) => seq('[', repeat(choice($.variable_reference, alias(token(/[^%!\[\]\r\n]+/), $.bracketed_literal))), ']'),
221
- cmd: ($) => prec.right(5, seq(optional('@'), choice($.command_name, $.variable_reference), optional($.argument_list))),
234
+ cmd: ($) => prec.right(5, choice(
235
+ seq(optional('@'), alias(kw('echo'), $.command_name), optional(alias($._echo_text, $.argument_list))),
236
+ seq(optional('@'), choice($.command_name, $.variable_reference), optional($.argument_list)),
237
+ )),
238
+ _echo_text: ($) => prec.right(repeat1(choice(
239
+ $.variable_reference,
240
+ $.string,
241
+ alias($._echo_literal, $.argument_value),
242
+ ))),
243
+ _echo_literal: () => token(/(?:\^[&|<>^()]|[^\s|&><"\r\n%!()])+|[()!%]/),
222
244
  macro_invocation: ($) => prec.right(6, seq($.variable_reference, $.parenthesized, optional($.else_clause))),
223
245
  command_name: () => /[$a-zA-Z_][$a-zA-Z0-9_.#-]*/,
224
246
  argument_list: ($) => prec.right(repeat1($._arg)),
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "tree-sitter-batch",
3
- "version": "0.8.0",
3
+ "version": "0.10.1",
4
4
  "description": "A Windows Batch/CMD grammar for tree-sitter",
5
5
  "type": "module",
6
6
  "repository": {
@@ -34,12 +34,16 @@
34
34
  "node-gyp-build": "^4.8.4"
35
35
  },
36
36
  "devDependencies": {
37
- "eslint": "^9.15.0",
37
+ "eslint": "^10.2.0",
38
38
  "eslint-config-treesitter": "^1.0.2",
39
+ "globals": "^17.5.0",
39
40
  "prebuildify": "^6.0.1",
40
- "tree-sitter-cli": "0.24.7",
41
+ "tree-sitter-cli": "0.26.8",
41
42
  "tree-sitter-go-types": "^0.1.0"
42
43
  },
44
+ "overrides": {
45
+ "eslint-plugin-jsdoc": "^62.9.0"
46
+ },
43
47
  "peerDependencies": {
44
48
  "tree-sitter": ">=0.25.0"
45
49
  },
@@ -52,7 +56,7 @@
52
56
  "install": "node-gyp-build",
53
57
  "prestart": "tree-sitter build --wasm",
54
58
  "start": "tree-sitter playground",
55
- "generate": "tree-sitter generate && tree-sitter-go-types",
59
+ "generate": "tree-sitter generate --abi 14 && tree-sitter-go-types",
56
60
  "lint": "eslint grammar.js",
57
61
  "test": "node --test bindings/node/*_test.js"
58
62
  }