/
sh.bnf
447 lines (377 loc) · 17.4 KB
/
sh.bnf
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
348
349
350
351
352
353
354
355
356
357
358
359
360
361
362
363
364
365
366
367
368
369
370
371
372
373
374
375
376
377
378
379
380
381
382
383
384
385
386
387
388
389
390
391
392
393
394
395
396
397
398
399
400
401
402
403
404
405
406
407
408
409
410
411
412
413
414
415
416
417
418
419
420
421
422
423
424
425
426
427
428
429
430
431
432
433
434
435
436
437
438
439
440
441
442
443
444
445
446
447
// Copyright 2000-2019 JetBrains s.r.o. Use of this source code is governed by the Apache 2.0 license that can be found in the LICENSE file.
{
generate = [token-accessors="yes" java="8"]
parserClass="com.intellij.sh.parser.ShParser"
parserUtilClass="com.intellij.sh.parser.ShParserUtil"
implements="com.intellij.sh.psi.ShCompositeElement"
extends="com.intellij.sh.psi.impl.ShCompositeElementImpl"
elementTypeHolderClass="com.intellij.sh.ShTypes"
elementTypeClass="com.intellij.sh.psi.ShCompositeElementType"
tokenTypeClass="com.intellij.sh.psi.ShTokenType"
psiClassPrefix="Sh"
psiImplClassSuffix="Impl"
psiPackage="com.intellij.sh.psi"
psiImplPackage="com.intellij.sh.psi.impl"
psiImplUtilClass="com.intellij.sh.psi.impl.ShPsiImplUtil"
tokens = [
// Arithmetic operations
MULT_ASSIGN = '*='
DIV_ASSIGN = '/='
MOD_ASSIGN = '%='
PLUS_ASSIGN = '+='
MINUS_ASSIGN = '-='
SHIFT_RIGHT_ASSIGN = '>>='
SHIFT_LEFT_ASSIGN = '<<='
BIT_AND_ASSIGN = '&='
BIT_OR_ASSIGN = '|='
BIT_XOR_ASSIGN = '^='
NE = '!='
EQ = '=='
LE = '<='
GE = '>='
PLUS_PLUS = "++"
MINUS_MINUS = "--"
EXPONENT = '**'
BITWISE_NEGATION = '~'
BANG = '!'
PLUS = "+"
MINUS = "-"
MULT = '*'
DIV = '/'
MOD = '%'
SHIFT_LEFT = '<<'
SHIFT_RIGHT = '>>'
LT = '<'
GT = '>'
AND_AND = '&&'
OR_OR = '||'
AMP = '&'
XOR = '^'
PIPE = '|'
QMARK = '?'
COLON = ':'
COMMA = ','
//Conditional operations
REGEXP = '=~'
DOLLAR = '$'
LEFT_PAREN = '('
RIGHT_PAREN = ')'
LEFT_CURLY = '{'
RIGHT_CURLY = '}'
LEFT_SQUARE = '['
RIGHT_SQUARE = ']'
EXPR_CONDITIONAL_LEFT = "[ "
EXPR_CONDITIONAL_RIGHT = " ]"
LEFT_DOUBLE_BRACKET = "[["
RIGHT_DOUBLE_BRACKET = "]]"
BACKSLASH = '\\'
ASSIGN = '='
SEMI = ';'
PIPE_AMP = '|&' //bash 4 only, equivalent to 2>&1 |
LINEFEED = '\n'
CASE_END = ';;'
REDIRECT_HERE_STRING = "<<<"
REDIRECT_LESS_AMP = "<&"
REDIRECT_GREATER_AMP = ">&"
REDIRECT_AMP_GREATER = "&>"
REDIRECT_AMP_GREATER_GREATER = "&>>"
REDIRECT_LESS_GREATER = "<>"
REDIRECT_GREATER_BAR = ">|"
OUTPUT_PROCESS_SUBSTITUTION = ">("
INPUT_PROCESS_SUBSTITUTION = "<("
OPEN_QUOTE = 'OPEN_QUOTE'
CLOSE_QUOTE = 'CLOSE_QUOTE'
OPEN_BACKQUOTE = 'OPEN_BACKQUOTE'
CLOSE_BACKQUOTE = 'CLOSE_BACKQUOTE'
EVAL_CONTENT = 'EVAL_CONTENT'
FILEDESCRIPTOR='file descriptor'
PARAM_SEPARATOR='param separator'
]
pin('.*list(?:_\d.*)?')=1
pin('.*_(command|clause)')=1
extends("variable|string|number")=literal
extends(".*command|function_definition")=command
implements("function_definition|assignment_command|assignment_expression|literal")="com.intellij.psi.PsiNameIdentifierOwner"
extends("(comma|assignment|conditional|logical_or|logical_and|bitwise_or|bitwise_exclusive_or|bitwise_and|equality|comparison|bitwise_shift|add|mul|exp)_operation")=binary_operation
extends("(comma|assignment|conditional|logical_or|logical_and|bitwise_or|bitwise_exclusive_or|bitwise_and|equality|comparison|bitwise_shift|add|mul|exp)_expression")=binary_expression
extends(".*operation")=operation
extends(".*expression")=expression
extends(".*condition")=condition
generateTokenAccessors(".*block")=false
generateTokenAccessors("redirection")=false
extraRoot(".*block")=true
}
private file ::=
shebang? newlines
simple_list
private simple_list ::= (commands_list newlines)*
commands_list ::= pipeline_command (
('&&' | '||') newlines? pipeline_command
| ('|' | '|&' | '&'| ';') pipeline_command?
)*
pipeline_command ::= '!'? command
| '!'? eval_command
| '!'? test_command
| let_command {recoverWhile=pipeline_recover}
let_command ::= let expression
eval_command ::= eval (EVAL_CONTENT|simple_command_element)*
test_command ::= test simple_command_element*
private pipeline_recover ::= !(case|if|while|until|select|'{'|function|'$'|'&&'|';'|';;'|'||'|'&'|'!'|'['|'[['|'('|')'|'|'|'|&'|'\n'|
var | word|EXPR_CONDITIONAL_LEFT|ARITH_SQUARE_LEFT | CLOSE_BACKQUOTE | do | done | '}')
command ::= shell_command [heredoc | redirection+]
| include_command
| simple_command
redirection ::= redirection_inner | '&>' w | number redirection_inner | process_substitution
private redirection_inner ::= ('<&' | '>&') (number | '-')
| ('>' | '<' | '>>' | '<<<' | '<<' | '<&' | '>&' | '&>>' | '<>' | '>|') redirection_target
private redirection_target ::= process_substitution | <<parseUntilSpace w>> {name="redirection target"}
process_substitution ::= ('<(' | '>(') list ')' {pin=1}
include_command ::= include_directive (simple_command_element | <<keywordsRemapped>>)+ {
pin=0
mixin="com.intellij.sh.psi.impl.ShIncludeCommandMixin"
}
include_directive ::= &('source' | '.') word {extends=generic_command_directive}
shell_command ::= if_command
| for_command
| case_command
| while_command
| until_command
| select_command
| arithmetic_expansion
| subshell_command
| block
| function_definition
for_command ::= for for_clause any_block
for_clause ::= arithmetic_for_clause
| in_for_clause
private arithmetic_for_clause ::= '(''(' arithmetic_for_expression ')'')' list_terminator? newlines
private arithmetic_for_expression ::= expression? ';' newlines expression? ';' newlines expression? {recoverWhile=arithmetic_for_expression_recover}
private arithmetic_for_expression_recover ::= !(')'')')
private in_for_clause ::= w (';' newlines | newlines in_clause?)
select_command ::= select w select_expression newlines any_block
private select_expression ::= in_clause | list_terminator?
private in_clause ::= in w+ list_terminator newlines
list_terminator ::= '\n' | ';' {recoverWhile = list_terminator_recover}
private list_terminator_recover ::= !(do | '{' | '\n')
while_command ::= while block_compound_list do_block
until_command ::= until block_compound_list do_block
case_command ::= case w+ in case_clause_list esac
private case_clause_list ::= case_clause (';;' (case_clause | newlines))* {pin(".*")=1 recoverWhile = case_clause_recover}
private case_clause_recover ::= !(esac)
case_clause ::= newlines pattern ')' newlines compound_case_list? {pin=3}
compound_case_list ::= pipeline_command_list end_of_list? newlines {pin(".*")=1 elementType=compound_list}
pattern ::= '('? w+ ('|' w+)* {pin('.*')=1 recoverWhile = case_pattern_recover}
private case_pattern_recover ::= !(')'|';;'|esac)
if_command ::= if compound_list then_clause
elif_clause*
else_clause?
fi
elif_clause ::= elif compound_list then_clause
else_clause ::= else compound_list
then_clause ::= then compound_list
compound_list ::= newlines pipeline_command_list end_of_list newlines {pin(".*")=2 recoverWhile=compound_list_recover}
private compound_list_recover ::= !(elif | else | then | fi)
private pipeline_command_list ::= pipeline_command (pipeline_command_list_separator pipeline_command)* {
pin=1
} // todo with pin
private pipeline_command_list_separator ::= ('&&'| '||' | '&' | ';' | '|' | '|&' | '\n') newlines
function_definition ::= &(function | word '(') function_definition_inner {
mixin="com.intellij.sh.psi.impl.ShFunctionDefinitionMixin"
}
private function_definition_inner ::= word argument_list newlines (block | parentheses_block)
| function (word | <<functionNameKeywordsRemapped>>) argument_list? newlines (block | parentheses_block)
{ pin(".*")="function|argument_list" }
private argument_list ::= '(' ')' {recoverWhile = argument_list_recover}
private argument_list_recover ::= !('\n'| '{' | '(')
private any_block ::= block | do_block
parentheses_block ::= '(' block_compound_list ')' { pin=1 }
do_block ::= do block_compound_list done {
pin(".*")=1
implements="com.intellij.sh.psi.ShLazyDoBlock"
extends="com.intellij.sh.psi.impl.ShLazyDoBlockImpl"
elementTypeClass="com.intellij.sh.lexer.ShLazyDoBlockElementType"
}
block ::= '{' block_compound_list '}' {
pin(".*")=1
implements="com.intellij.sh.psi.ShLazyBlock"
extends="com.intellij.sh.psi.impl.ShLazyBlockImpl"
elementTypeClass="com.intellij.sh.lexer.ShLazyBlockElementType"
}
block_compound_list ::= (nl pipeline_command_list | pipeline_command_list) end_of_list newlines {
pin(".*")=1
elementType=compound_list
recoverWhile=block_compound_list_recover
}
private block_compound_list_recover ::= !('{' | '\n' | '}' | do | done | '(' | ')')
simple_command ::= generic_command_directive (simple_command_element | <<keywordsRemapped>>)* {pin=1}
generic_command_directive ::= simple_command_element_inner {extends=simple_command}
simple_command_element ::= simple_command_element_inner
private simple_command_element_inner ::= literal assignment_command?
| not_lvalue
| redirection
| composed_var
| heredoc
| conditional_command
| command_substitution_command
| arithmetic_expansion
| old_arithmetic_expansion {pin(".*")=1}
heredoc ::= HEREDOC_MARKER_TAG HEREDOC_MARKER_START [commands_list heredoc_pipeline_separator? | heredoc_pipeline_separator commands_list?] newlines
HEREDOC_CONTENT?
(HEREDOC_MARKER_END | <<eof>>)
private heredoc_pipeline_separator ::= ('&&' | '||' | '&' | '|' | '|&' | ';')
private vars ::= variable | composed_var | command_substitution_command | old_arithmetic_expansion
private composed_var ::= '$' &('(' | '{') composed_var_inner {pin=2}
private composed_var_inner ::= arithmetic_expansion
| subshell_command
| shell_parameter_expansion
command_substitution_command ::= !<<isModeOn "BACKQUOTE">> OPEN_BACKQUOTE <<withOn "BACKQUOTE" list?>> CLOSE_BACKQUOTE {pin=2}
arithmetic_expansion ::= '(''(' expression? ')'')'
old_arithmetic_expansion ::= ARITH_SQUARE_LEFT old_arithmetic_expansion_expression? ARITH_SQUARE_RIGHT {pin=1 extends=arithmetic_expansion}
private old_arithmetic_expansion_expression ::= expression {pin=1 recoverWhile=old_arithmetic_expansion_expression_recover}
private old_arithmetic_expansion_expression_recover ::= !(ARITH_SQUARE_RIGHT)
subshell_command ::= '(' list ')'
list ::= newlines pipeline_command_list end_of_list? newlines {pin(".*")=2 elementType=compound_list}
private nl ::= '\n'+
private end_of_list ::= '\n' | ';' | '&'
shell_parameter_expansion ::= '{' shell_parameter_expansion_inner+ '}' {pin=1}
//noinspection BnfSuspiciousToken
private shell_parameter_expansion_inner ::= w | array_expression | param_separator | vars { name="parameter expansion" }
left assignment_command ::= array_expression? ('='|"+=") [assignment_list | <<parseUntilSpace (literal | composed_var)>>]
{'=' <<parseUntilSpace literal >>}* {
pin=0
mixin="com.intellij.sh.psi.impl.ShAssignmentCommandMixin"
}
literal ::= word | string | number | variable | <<arithmeticOperationsRemapped>> {
extends=simple_command_element
implements="com.intellij.model.psi.UrlReferenceHost"
mixin="com.intellij.sh.psi.impl.ShLiteralMixin"
methods=[getReferences]
}
private not_lvalue ::= '!' | vars | '$' | brace_expansion | 'file descriptor'
brace_expansion ::= '{' (word | brace_expansion)* '}'
variable ::= var { methods=[getReferences] }
number ::= int | hex | octal
string ::= OPEN_QUOTE (STRING_CONTENT | vars | <<notQuote>>)* CLOSE_QUOTE | RAW_STRING {pin(".*")=1}
private w ::= string | number | not_lvalue | <<arithmeticOperationsRemapped>>
private newlines ::= '\n'*
expression ::=
comma_expression
| assignment_expression
| conditional_expression
| logical_or_expression
| logical_and_expression
| bitwise_or_expression
| bitwise_exclusive_or_expression
| bitwise_and_expression
| equality_expression
| comparison_expression
| bitwise_shift_expression
| add_expression
| mul_expression
| exp_expression
| logical_bitwise_negation_expression
| unary_expression
| pre_expression
| post_expression
| index_expression
| array_expression
| literal_expression
| parentheses_expression
comma_expression ::= expression ',' expression
assignment_expression ::= expression ('=' |'*=' |'/=' |'%=' |'+=' |'-=' |'<<=' |'>>=' |'&=' |'^=' |'|=') expression {
mixin="com.intellij.sh.psi.impl.ShAssignmentExpressionMixin"
}
conditional_expression ::= expression '?' expression ':' expression
logical_or_expression ::= expression '||' expression
logical_and_expression ::= expression '&&' expression
bitwise_or_expression ::= expression '|' expression
bitwise_exclusive_or_expression ::= expression '^' expression
bitwise_and_expression ::= expression '&' expression
equality_expression ::= expression ('==' | '!=') expression
comparison_expression ::= expression ('<=' | '>=' | '<' | '>') expression
bitwise_shift_expression ::= expression ('<<' | '>>') expression
add_expression ::= expression ('+' | '-') expression
mul_expression ::= expression ('*' | '/' | '%') expression
exp_expression ::= expression '**' expression
fake binary_expression ::= expression+ { methods=[left="expression[0]" right="expression[1]"] }
logical_bitwise_negation_expression ::= ('!' | '~') expression
unary_expression ::= ('-' | '+') expression
pre_expression ::= ('--' | '++') expression
post_expression ::= expression ('--' | '++')
index_expression ::= expression '[' expression ']'
array_expression ::= '[' expression ']'
parentheses_expression ::= '(' expression ')' {pin=1}
literal_expression ::= word_in_expression+ { methods=[getReferences] }
private word_in_expression ::= word | string | number | not_lvalue
assignment_list ::= '(' (<<backslash>> | array_assignment)* ')'
array_assignment ::= newlines '='? operation newlines
// Most widely used operators: COMMA_OPERATION, LITERAL_OPERATION, ASSIGNMENT_OPERATION, ARRAY_OPERATION, EXP_OPERATION
operation ::=
comma_operation
|assignment_operation
|conditional_operation
|logical_or_operation
|logical_and_operation
|bitwise_or_operation
|bitwise_exclusive_or_operation
|bitwise_and_operation
|equality_operation
|comparison_operation
|bitwise_shift_operation
|add_operation
|mul_operation
|exp_operation
|logical_bitwise_negation_operation
|unary_operation
|pre_operation
|post_operation
|index_operation
|array_operation
|literal_operation
|parentheses_operation
comma_operation ::= operation ',' operation
assignment_operation ::= operation ('=' |'*=' |'/=' |'%=' |'+=' |'-=' |'<<=' |'>>=' |'&=' |'^=' |'|=') operation
conditional_operation ::= operation '?' operation ':' operation
logical_or_operation ::= operation '||' operation
logical_and_operation ::= operation '&&' operation
bitwise_or_operation ::= operation '|' operation
bitwise_exclusive_or_operation ::= operation '^' operation
bitwise_and_operation ::= operation '&' operation
equality_operation ::= operation ('==' | '!=') operation
comparison_operation ::= operation ('<=' | '>=' | '<' | '>') operation
bitwise_shift_operation ::= operation ('<<' | '>>') operation
add_operation ::= operation ('+' | '-') operation
mul_operation ::= operation ('*' | '/' | '%') operation
exp_operation ::= operation '**' operation
fake binary_operation ::= operation+ { methods=[left="operation[0]" right="operation[1]"] }
logical_bitwise_negation_operation ::= ('!' | '~') operation
unary_operation ::= ('-' | '+') operation
pre_operation ::= ('--' | '++') operation
post_operation ::= operation ('--' | '++')
index_operation ::= operation '[' operation ']'
array_operation ::= '[' operation ']'
parentheses_operation ::= '(' operation ')' {pin=1}
literal_operation ::= w+ { methods=[getReferences] }
conditional_command ::= '[[' condition* (']]'|']' <<differentBracketsWarning>>)
| '[' condition* ( ']'|']]' <<differentBracketsWarning>>) {pin(".*")=1}
condition ::=
assignment_condition
| logical_or_condition
| logical_and_condition
| equality_condition
| regex_condition
| comparison_condition
| logical_bitwise_condition
| literal_condition
| parentheses_condition
assignment_condition ::= condition '=' condition
logical_or_condition ::= condition newlines '||' newlines condition
logical_and_condition ::= condition newlines '&&' newlines condition
equality_condition ::= condition ('==' | '!=') condition
regex_condition ::= condition '=~' regex_pattern
comparison_condition ::= condition ('<' | '>') condition
logical_bitwise_condition ::= '!' simple_command
parentheses_condition ::= '(' condition ')'
literal_condition ::= (word_in_condition newlines | newlines word_in_condition)
regex_pattern ::= word_in_condition+
private word_in_condition ::= word | string | number | not_lvalue