tree-sitter-batch 0.7.2 → 0.8.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
@@ -1,11 +1,18 @@
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 operand = ($) => [$.cond_exec, $.pipe_stmt, $.redirect_stmt, $.call_stmt, $.cmd, $.parenthesized];
3
+ const operand = ($) => [
4
+ $.cond_exec, $.pipe_stmt, $.redirect_stmt, $.call_stmt, $.cmd, $.parenthesized,
5
+ $.variable_assignment, $.goto_stmt, $.exit_stmt, $.setlocal_stmt, $.endlocal_stmt,
6
+ $.if_stmt, $.for_stmt, $.macro_invocation,
7
+ ];
4
8
 
5
9
  export default grammar({
6
10
  name: 'batch',
7
11
  extras: () => [/[ \t]/],
8
12
  word: ($) => $.command_name,
13
+ conflicts: ($) => [
14
+ [$.parenthesized, $.paren_expression],
15
+ ],
9
16
  rules: {
10
17
  program: ($) => repeat(choice(seq($._stmt, /\r?\n/), /\r?\n/)),
11
18
  _stmt: ($) => choice(
@@ -13,14 +20,15 @@ export default grammar({
13
20
  $.if_stmt, $.goto_stmt, $.call_stmt, $.exit_stmt,
14
21
  $.setlocal_stmt, $.endlocal_stmt, $.for_stmt,
15
22
  $.redirect_stmt, $.pipe_stmt, $.cond_exec, $.command_sep,
16
- $.parenthesized, $.cmd,
23
+ $.parenthesized, $.macro_invocation, $.cmd,
17
24
  ),
18
25
  echo_off: () => prec(10, seq('@', kw('echo'), choice(kw('off'), kw('on')))),
19
26
  comment: () => token(prec(10, choice(
20
27
  seq(optional('@'), /[rR][eE][mM]/, optional(seq(/[ \t]/, /[^\r\n]*/))),
21
- seq('::', /[^\r\n]*/),
28
+ seq(':', /[^$a-zA-Z_\r\n]/, /[^\r\n]*/),
29
+ seq('%#', /[^\r\n]*/, '#%'),
22
30
  ))),
23
- label: () => token(seq(':', /[a-zA-Z_][a-zA-Z0-9_-]*/)),
31
+ label: () => token(seq(':', /[$a-zA-Z_][$a-zA-Z0-9_.#-]*/, optional(seq(/[ \t]/, /[^\r\n]*/)))),
24
32
  variable_assignment: ($) => prec(8, seq(
25
33
  optional('@'), alias(kw('set'), $.set_keyword),
26
34
  choice(
@@ -29,12 +37,26 @@ export default grammar({
29
37
  seq(
30
38
  /[ \t]+/,
31
39
  choice(
32
- seq('"', alias(/[a-zA-Z_][a-zA-Z0-9_()\[\]]*/, $.variable_name), '=', optional($.quoted_assignment_value), '"'),
33
- seq(alias(/[a-zA-Z_][a-zA-Z0-9_()\[\]]*/, $.variable_name), '=', optional($.assignment_value)),
40
+ seq('"', repeat1(choice($.variable_reference, alias($._quoted_var_name_pattern, $.variable_name))), '=', optional($.quoted_assignment_value), '"', optional($.argument_list)),
41
+ seq('^"', repeat1(choice($.variable_reference, alias($._quoted_var_name_pattern, $.variable_name))), '=', optional($.caret_quoted_assignment_value), optional('^"')),
42
+ seq(choice($.variable_reference, alias($._var_name_pattern, $.variable_name)), '=', optional($.assignment_value)),
34
43
  ),
35
44
  ),
36
45
  ),
37
46
  )),
47
+ caret_quoted_assignment_value: ($) => prec.right(repeat1(choice(
48
+ $.variable_reference,
49
+ alias(/[^%!\r\n^]+/, $.assignment_literal),
50
+ alias('%', $.assignment_literal),
51
+ alias('!', $.assignment_literal),
52
+ alias(token(prec(1, '^^')), $.assignment_literal),
53
+ alias('^', $.assignment_literal),
54
+ ))),
55
+ _var_name_pattern: () => token(choice(
56
+ /[$@a-zA-Z_][$@a-zA-Z0-9_.#()\[\]]*/,
57
+ /\/[@a-zA-Z_][@a-zA-Z0-9_.#()\[\]]+/,
58
+ )),
59
+ _quoted_var_name_pattern: () => token(prec(1, choice(/[^\s="%][^="%]*/, /%%[a-zA-Z]?/, /"[^="\r\n]+"/))),
38
60
  arithmetic_assignment: ($) => seq(
39
61
  optional(/[ \t]+/), alias(ci('/a'), $.set_option),
40
62
  optional(/[ \t]+/), $.arithmetic_expression,
@@ -42,7 +64,7 @@ export default grammar({
42
64
  prompt_assignment: ($) => seq(
43
65
  optional(/[ \t]+/), alias(ci('/p'), $.set_option),
44
66
  optional(/[ \t]+/),
45
- alias(/[a-zA-Z_][a-zA-Z0-9_()\[\]]*/, $.variable_name), '=', optional($.assignment_value),
67
+ alias(/[@a-zA-Z_][@a-zA-Z0-9_()\[\]]*/, $.variable_name), '=', optional($.assignment_value),
46
68
  ),
47
69
  arithmetic_expression: () => token(choice(
48
70
  seq('"', /[^"\r\n]*/, '"'),
@@ -50,10 +72,19 @@ export default grammar({
50
72
  )),
51
73
  assignment_value: ($) => prec.right(repeat1(choice(
52
74
  $.variable_reference,
53
- alias(/[^%!\r\n]+/, $.assignment_literal),
75
+ $.assignment_paren_group,
76
+ alias(/[^%!()\r\n]+/, $.assignment_literal),
54
77
  alias('%', $.assignment_literal),
55
78
  alias('!', $.assignment_literal),
56
79
  ))),
80
+ assignment_paren_group: ($) => seq('(', repeat(choice(
81
+ $.variable_reference,
82
+ $.assignment_paren_group,
83
+ alias(/[^%!()\r\n]+/, $.assignment_literal),
84
+ /\r?\n/,
85
+ alias('%', $.assignment_literal),
86
+ alias('!', $.assignment_literal),
87
+ )), ')'),
57
88
  quoted_assignment_value: ($) => prec.right(repeat1(choice(
58
89
  $.variable_reference,
59
90
  alias(/[^%!"\r\n]+/, $.assignment_literal),
@@ -62,36 +93,51 @@ export default grammar({
62
93
  ))),
63
94
  if_stmt: ($) => prec.right(8, seq(
64
95
  optional('@'), kw('if'),
96
+ optional(alias(ci('/i'), $.if_option)),
65
97
  optional(kw('not')),
66
98
  choice(
67
- seq(kw('exist'), choice($.string, $.variable_reference)),
68
- seq(kw('defined'), /[a-zA-Z_][a-zA-Z0-9_]*/),
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)),
69
101
  seq(kw('errorlevel'), $.integer),
70
102
  seq(
71
- choice($.string, $.variable_reference, $.integer),
103
+ $._if_operand,
72
104
  $.comparison_op,
73
- choice($.string, $.variable_reference, $.integer),
105
+ $._if_operand,
74
106
  ),
75
107
  ),
76
108
  choice(
77
109
  // Parenthesized form: supports else clause
78
110
  seq($.parenthesized, optional($.else_clause)),
79
111
  // Inline command form: no else (ambiguous)
80
- $.cmd,
112
+ $._body_stmt,
81
113
  ),
82
114
  )),
83
115
  else_clause: ($) => prec.right(8, seq(
84
116
  kw('else'),
85
- choice($.parenthesized, $.cmd),
117
+ choice($.parenthesized, $._body_stmt),
86
118
  )),
119
+ _body_stmt: ($) => choice(
120
+ $.cmd, $.variable_assignment, $.call_stmt, $.goto_stmt, $.exit_stmt,
121
+ $.setlocal_stmt, $.endlocal_stmt, $.if_stmt, $.for_stmt,
122
+ $.redirect_stmt, $.pipe_stmt, $.comment,
123
+ ),
124
+ _if_operand: ($) => choice(
125
+ $.string, $.variable_reference, $.integer, $.bracketed_value,
126
+ alias($._if_word, $.argument_value),
127
+ ),
128
+ _if_word: () => token(prec(-1, /[^=<>\s\[\]"|&()][^=<>\s"|&()]*/)),
87
129
  comparison_op: () => token(prec(10, choice('==', ci('equ'), ci('neq'), ci('lss'), ci('leq'), ci('gtr'), ci('geq')))),
88
- goto_stmt: () => prec(8, seq(
130
+ goto_stmt: ($) => prec(8, seq(
89
131
  optional('@'), kw('goto'),
90
- choice(token(prec(10, ci(':eof'))), token(seq(optional(':'), /[a-zA-Z_][a-zA-Z0-9_-]*/))),
132
+ optional(choice(
133
+ token(prec(10, ci(':eof'))),
134
+ seq(token(seq(optional(':'), /[$a-zA-Z_][$a-zA-Z0-9_.#-]*/)), optional($.variable_reference)),
135
+ )),
136
+ optional($.comment),
91
137
  )),
92
138
  call_stmt: ($) => prec(8, seq(
93
139
  optional('@'), kw('call'),
94
- choice(token(seq(':', /[a-zA-Z_][a-zA-Z0-9_-]*/)), $.command_name),
140
+ choice(token(seq(':', /[$a-zA-Z_][$a-zA-Z0-9_.#-]*/)), $.command_name, $.variable_reference),
95
141
  optional($.argument_list),
96
142
  )),
97
143
  exit_stmt: ($) => prec(8, seq(
@@ -104,31 +150,46 @@ export default grammar({
104
150
  )),
105
151
  setlocal_stmt: () => prec(8, seq(
106
152
  optional('@'), kw('setlocal'),
107
- optional(choice(kw('enabledelayedexpansion'), kw('disabledelayedexpansion'), kw('enableextensions'), kw('disableextensions'))),
153
+ repeat(choice(kw('enabledelayedexpansion'), kw('disabledelayedexpansion'), kw('enableextensions'), kw('disableextensions'))),
108
154
  )),
109
155
  endlocal_stmt: () => prec(8, seq(optional('@'), kw('endlocal'))),
110
156
  for_stmt: ($) => prec(8, seq(
111
- optional('@'), kw('for'),
112
- optional($.for_options), $.for_variable,
157
+ choice(
158
+ seq(optional('@'), kw('for'), optional($.for_options)),
159
+ $.variable_reference,
160
+ ),
161
+ $.for_variable,
113
162
  kw('in'), '(', optional($.for_set), ')', kw('do'),
114
- choice($.parenthesized, $.cmd),
163
+ choice($.parenthesized, $._body_stmt),
115
164
  )),
116
165
  for_options: () => token(prec(10, choice(ci('/d'), seq(ci('/r'), optional(seq(/[ \t]+/, /(%[^\s%]|[^\s%])+%?/))), ci('/l'), seq(ci('/f'), optional(seq(/[ \t]+/, '"', /[^"]*/, '"')))))),
117
166
  for_variable: () => token(seq('%%', optional('~'), /[a-zA-Z]/)),
118
167
  for_set: ($) => prec.right(repeat1(choice(
119
168
  $.variable_reference,
120
- alias(/[^%!)\r\n]+/, $.for_set_literal),
169
+ $.for_set_group,
170
+ alias(/[^%!()\r\n]+/, $.for_set_literal),
171
+ /\r?\n/,
121
172
  alias('%', $.for_set_literal),
122
173
  alias('!', $.for_set_literal),
123
174
  ))),
175
+ for_set_group: ($) => seq('(', repeat(choice(
176
+ $.variable_reference,
177
+ $.for_set_group,
178
+ alias(/[^%!()\r\n]+/, $.for_set_literal),
179
+ alias('%', $.for_set_literal),
180
+ alias('!', $.for_set_literal),
181
+ )), ')'),
124
182
  parenthesized: ($) => seq('(', repeat(choice(seq($._stmt, /\r?\n/), /\r?\n/)), optional($._stmt), ')'),
125
- redirect_stmt: ($) => prec.right(4, seq(choice($.call_stmt, $.cmd, $.parenthesized), $.redirection)),
183
+ redirect_stmt: ($) => prec.right(4, choice(
184
+ seq(choice($.call_stmt, $.cmd, $.parenthesized), $.redirection),
185
+ seq($.redirection, choice($.call_stmt, $.cmd, $.parenthesized)),
186
+ )),
126
187
  redirection: ($) => {
127
188
  const file_redir = seq(optional(/[0-2]/), $.redirect_op, $.redirect_target);
128
189
  const one_redir = choice(file_redir, $.fd_redirect);
129
190
  return prec.right(repeat1(one_redir));
130
191
  },
131
- fd_redirect: () => token(choice('2>&1', '>&1')),
192
+ fd_redirect: () => token(seq(optional(/[0-2]/), '>&', /[0-9]/)),
132
193
  redirect_op: () => token(choice('2>>', '2>', '>>', '>', '<')),
133
194
  redirect_target: () => token(choice(ci('nul'), ci('con'), /[^\s|&><\r\n]+/)),
134
195
  pipe_stmt: ($) => prec.left(3, seq(choice($.pipe_stmt, $.redirect_stmt, $.call_stmt, $.cmd, $.parenthesized), '|', choice($.redirect_stmt, $.call_stmt, $.cmd, $.parenthesized))),
@@ -139,19 +200,27 @@ export default grammar({
139
200
  command_sep: ($) => prec.left(0, seq(
140
201
  choice($.command_sep, ...operand($)),
141
202
  '&',
142
- choice(...operand($)),
203
+ choice(...operand($), $.comment),
143
204
  )),
144
205
  variable_reference: () => token(choice(
145
- seq('%', /[a-zA-Z_][a-zA-Z0-9_()\[\]]*/, '%'),
206
+ seq('%', /[$@a-zA-Z_][$@a-zA-Z0-9_.#()\[\]]*/, '%'),
146
207
  seq('%~', /[a-zA-Z]*/, /[0-9]/),
147
208
  seq('%', /[0-9]/),
209
+ '%*',
148
210
  seq('%%', optional('~'), /[a-zA-Z]/),
149
- seq('!', /[a-zA-Z_][a-zA-Z0-9_]*/, '!'),
150
- seq('%', /[a-zA-Z_][a-zA-Z0-9_()\[\]]*/, ':', /[^%]+/, '%'),
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]+"/, '%'),
151
218
  )),
152
219
  string: () => token(seq('"', /[^"\r\n]*/, '"')),
153
- cmd: ($) => prec.right(5, seq(optional('@'), $.command_name, optional($.argument_list))),
154
- command_name: () => /[a-zA-Z_][a-zA-Z0-9_.-]*/,
220
+ 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))),
222
+ macro_invocation: ($) => prec.right(6, seq($.variable_reference, $.parenthesized, optional($.else_clause))),
223
+ command_name: () => /[$a-zA-Z_][$a-zA-Z0-9_.#-]*/,
155
224
  argument_list: ($) => prec.right(repeat1($._arg)),
156
225
  _arg: ($) => choice($.string, $.variable_reference, $.command_option, $.paren_expression, $.argument_value),
157
226
  command_option: () => token(seq('/', /[a-zA-Z_?][a-zA-Z0-9_:]*/)),
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "tree-sitter-batch",
3
- "version": "0.7.2",
3
+ "version": "0.8.0",
4
4
  "description": "A Windows Batch/CMD grammar for tree-sitter",
5
5
  "type": "module",
6
6
  "repository": {