summaryrefslogtreecommitdiffstats
path: root/src/shell.pest
diff options
context:
space:
mode:
Diffstat (limited to 'src/shell.pest')
-rw-r--r--src/shell.pest72
1 files changed, 72 insertions, 0 deletions
diff --git a/src/shell.pest b/src/shell.pest
new file mode 100644
index 0000000..92b173a
--- /dev/null
+++ b/src/shell.pest
@@ -0,0 +1,72 @@
+basic_escape_char = @{ "\\\\" | "\\'" }
+escape_char = @{ "\\" ~ ANY }
+
+bareword_char = @{
+ escape_char |
+ !("|" | ";" | "\"" | "'" | "$" | "{" | "(" | ")" | WHITESPACE | COMMENT)
+ ~ ANY
+}
+single_string_char = @{ basic_escape_char | (!"'" ~ ANY) }
+double_string_char = @{ escape_char | (!("\"" | "$") ~ ANY) }
+
+var = @{
+ ("$" ~ XID_START ~ XID_CONTINUE*) |
+ ("$" ~ ("?" | "$" | "*" | ASCII_DIGIT)) |
+ ("${" ~ (!"}" ~ ANY)+ ~ "}")
+}
+bareword = @{ bareword_char+ }
+single_string = @{ single_string_char+ }
+double_string = @{ double_string_char+ }
+
+alternation_bareword_char = @{ !("," | "}") ~ bareword_char }
+alternation_bareword = @{ alternation_bareword_char+ }
+alternation_word_part = ${
+ var |
+ alternation_bareword |
+ "'" ~ single_string? ~ "'" |
+ "\"" ~ (var | double_string)* ~ "\""
+}
+alternation_word = ${ alternation_word_part* }
+alternation = ${ "{" ~ alternation_word ~ ("," ~ alternation_word)* ~ "}" }
+
+substitution = ${ "$(" ~ w? ~ commands ~ w? ~ ")"}
+
+word_part = ${
+ alternation |
+ substitution |
+ var |
+ bareword |
+ "'" ~ single_string? ~ "'" |
+ "\"" ~ (substitution | var | double_string)* ~ "\""
+}
+word = ${ word_part+ }
+
+redir_prefix = @{
+ ("in" | "out" | "err" | ASCII_DIGIT*) ~ (">>" | ">" | "<")
+}
+redirect = ${ redir_prefix ~ w? ~ word }
+
+exe = ${ (redirect | word) ~ (w ~ (redirect | word))* }
+subshell = ${
+ "(" ~ w? ~ commands ~ w? ~ ")" ~ (w? ~ redirect ~ (w ~ redirect)*)?
+}
+list = ${ word ~ (w ~ word)* }
+pipeline = ${ (subshell | exe) ~ (w? ~ "|" ~ w? ~ (subshell | exe))* }
+
+control_if = ${ "if" ~ w ~ pipeline }
+control_while = ${ "while" ~ w ~ pipeline }
+control_for = ${ "for" ~ w ~ bareword ~ w ~ "in" ~ w ~ list }
+control_else = ${ "else" ~ (w ~ "if" ~ w ~ pipeline)? }
+control_end = ${ "end" }
+control = ${
+ control_if | control_while | control_for | control_else | control_end
+}
+
+command = ${ control | pipeline }
+commands = ${ command ~ (w? ~ ";" ~ w? ~ command)* }
+
+line = ${ SOI ~ w? ~ commands ~ w? ~ EOI }
+
+w = _{ (WHITESPACE | COMMENT)+ }
+WHITESPACE = _{ (" " | "\t" | "\n") }
+COMMENT = _{ "#" ~ ANY* }