Generalize case statement parsing
* Fix handling of '|' in case items * Don't require ;; for last case item Fixes #8
This commit is contained in:
parent
2a5b01b885
commit
87b3276186
|
@ -115,6 +115,10 @@ case "opt" in
|
|||
;;
|
||||
esac
|
||||
|
||||
case "$Z" in
|
||||
ab*|cd*) ef
|
||||
esac
|
||||
|
||||
---
|
||||
|
||||
(program
|
||||
|
@ -122,7 +126,10 @@ esac
|
|||
(case_item (word)
|
||||
(command (command_name (word)) (word)))
|
||||
(case_item (word)
|
||||
(command (command_name (word)) (word)))))
|
||||
(command (command_name (word)) (word))))
|
||||
(case_statement (string (simple_expansion (variable_name)))
|
||||
(case_item (word) (word)
|
||||
(command (command_name (word))))))
|
||||
|
||||
===============================
|
||||
Subshells
|
||||
|
|
13
grammar.js
13
grammar.js
|
@ -5,7 +5,7 @@ const SPECIAL_CHARACTERS = [
|
|||
'\\[', '\\]',
|
||||
'(', ')',
|
||||
'`', '$',
|
||||
'&', ';',
|
||||
'|', '&', ';',
|
||||
'\\',
|
||||
'\\s',
|
||||
'#',
|
||||
|
@ -120,7 +120,10 @@ module.exports = grammar({
|
|||
optional($._terminator),
|
||||
'in',
|
||||
$._terminator,
|
||||
optional(seq(
|
||||
repeat($.case_item),
|
||||
alias($.last_case_item, $.case_item),
|
||||
)),
|
||||
'esac'
|
||||
),
|
||||
|
||||
|
@ -132,6 +135,14 @@ module.exports = grammar({
|
|||
';;'
|
||||
),
|
||||
|
||||
last_case_item: $ => seq(
|
||||
$._expression,
|
||||
repeat(seq('|', $._expression)),
|
||||
')',
|
||||
repeat($._terminated_statement),
|
||||
optional(';;')
|
||||
),
|
||||
|
||||
function_definition: $ => seq(
|
||||
choice(
|
||||
seq('function', $.word, optional(seq('(', ')'))),
|
||||
|
|
|
@ -116,6 +116,26 @@
|
|||
{
|
||||
"type": "SYMBOL",
|
||||
"name": "do_group"
|
||||
},
|
||||
{
|
||||
"type": "REPEAT",
|
||||
"content": {
|
||||
"type": "CHOICE",
|
||||
"members": [
|
||||
{
|
||||
"type": "SYMBOL",
|
||||
"name": "file_redirect"
|
||||
},
|
||||
{
|
||||
"type": "SYMBOL",
|
||||
"name": "heredoc_redirect"
|
||||
},
|
||||
{
|
||||
"type": "SYMBOL",
|
||||
"name": "herestring_redirect"
|
||||
}
|
||||
]
|
||||
}
|
||||
}
|
||||
]
|
||||
},
|
||||
|
@ -257,6 +277,12 @@
|
|||
"type": "SYMBOL",
|
||||
"name": "_terminator"
|
||||
},
|
||||
{
|
||||
"type": "CHOICE",
|
||||
"members": [
|
||||
{
|
||||
"type": "SEQ",
|
||||
"members": [
|
||||
{
|
||||
"type": "REPEAT",
|
||||
"content": {
|
||||
|
@ -264,6 +290,22 @@
|
|||
"name": "case_item"
|
||||
}
|
||||
},
|
||||
{
|
||||
"type": "ALIAS",
|
||||
"content": {
|
||||
"type": "SYMBOL",
|
||||
"name": "last_case_item"
|
||||
},
|
||||
"named": true,
|
||||
"value": "case_item"
|
||||
}
|
||||
]
|
||||
},
|
||||
{
|
||||
"type": "BLANK"
|
||||
}
|
||||
]
|
||||
},
|
||||
{
|
||||
"type": "STRING",
|
||||
"value": "esac"
|
||||
|
@ -310,6 +352,54 @@
|
|||
}
|
||||
]
|
||||
},
|
||||
"last_case_item": {
|
||||
"type": "SEQ",
|
||||
"members": [
|
||||
{
|
||||
"type": "SYMBOL",
|
||||
"name": "_expression"
|
||||
},
|
||||
{
|
||||
"type": "REPEAT",
|
||||
"content": {
|
||||
"type": "SEQ",
|
||||
"members": [
|
||||
{
|
||||
"type": "STRING",
|
||||
"value": "|"
|
||||
},
|
||||
{
|
||||
"type": "SYMBOL",
|
||||
"name": "_expression"
|
||||
}
|
||||
]
|
||||
}
|
||||
},
|
||||
{
|
||||
"type": "STRING",
|
||||
"value": ")"
|
||||
},
|
||||
{
|
||||
"type": "REPEAT",
|
||||
"content": {
|
||||
"type": "SYMBOL",
|
||||
"name": "_terminated_statement"
|
||||
}
|
||||
},
|
||||
{
|
||||
"type": "CHOICE",
|
||||
"members": [
|
||||
{
|
||||
"type": "STRING",
|
||||
"value": ";;"
|
||||
},
|
||||
{
|
||||
"type": "BLANK"
|
||||
}
|
||||
]
|
||||
}
|
||||
]
|
||||
},
|
||||
"function_definition": {
|
||||
"type": "SEQ",
|
||||
"members": [
|
||||
|
@ -1130,15 +1220,10 @@
|
|||
},
|
||||
{
|
||||
"type": "CHOICE",
|
||||
"members": [
|
||||
{
|
||||
"type": "SEQ",
|
||||
"members": [
|
||||
{
|
||||
"type": "SYMBOL",
|
||||
"name": "_expression"
|
||||
}
|
||||
]
|
||||
},
|
||||
{
|
||||
"type": "BLANK"
|
||||
|
@ -1168,14 +1253,14 @@
|
|||
]
|
||||
},
|
||||
{
|
||||
"type": "REPEAT",
|
||||
"content": {
|
||||
"type": "CHOICE",
|
||||
"members": [
|
||||
{
|
||||
"type": "SEQ",
|
||||
"members": [
|
||||
{
|
||||
"type": "CHOICE",
|
||||
"members": [
|
||||
"type": "SYMBOL",
|
||||
"name": "_expression"
|
||||
},
|
||||
{
|
||||
"type": "STRING",
|
||||
"value": ":"
|
||||
|
@ -1203,32 +1288,13 @@
|
|||
{
|
||||
"type": "STRING",
|
||||
"value": "-"
|
||||
}
|
||||
]
|
||||
},
|
||||
{
|
||||
"type": "CHOICE",
|
||||
"members": [
|
||||
{
|
||||
"type": "SEQ",
|
||||
"members": [
|
||||
{
|
||||
"type": "SYMBOL",
|
||||
"name": "_expression"
|
||||
}
|
||||
]
|
||||
},
|
||||
{
|
||||
"type": "BLANK"
|
||||
"type": "STRING",
|
||||
"value": "#"
|
||||
}
|
||||
]
|
||||
}
|
||||
]
|
||||
},
|
||||
{
|
||||
"type": "BLANK"
|
||||
}
|
||||
]
|
||||
}
|
||||
]
|
||||
}
|
||||
|
@ -1376,7 +1442,7 @@
|
|||
"members": [
|
||||
{
|
||||
"type": "PATTERN",
|
||||
"value": "[^'\"<>{}\\[\\]()`$&;\\\\\\s#]"
|
||||
"value": "[^'\"<>{}\\[\\]()`$|&;\\\\\\s#]"
|
||||
},
|
||||
{
|
||||
"type": "SEQ",
|
||||
|
|
File diff suppressed because it is too large
Load Diff
|
@ -86,6 +86,7 @@ struct Scanner {
|
|||
bool scan(TSLexer *lexer, const bool *valid_symbols) {
|
||||
if (valid_symbols[CONCAT]) {
|
||||
if (!(
|
||||
lexer->lookahead == 0 ||
|
||||
iswspace(lexer->lookahead) ||
|
||||
lexer->lookahead == '>' ||
|
||||
lexer->lookahead == '<' ||
|
||||
|
@ -93,8 +94,8 @@ struct Scanner {
|
|||
lexer->lookahead == '(' ||
|
||||
lexer->lookahead == ';' ||
|
||||
lexer->lookahead == '&' ||
|
||||
lexer->lookahead == '|' ||
|
||||
lexer->lookahead == '`' ||
|
||||
lexer->lookahead == 0 ||
|
||||
(lexer->lookahead == '}' && valid_symbols[CLOSING_BRACE]) ||
|
||||
(lexer->lookahead == ']' && valid_symbols[CLOSING_BRACKET])
|
||||
)) {
|
||||
|
|
Loading…
Reference in New Issue