From 489fd0db1bf7f1de31a043e315179e83b77921aa Mon Sep 17 00:00:00 2001 From: Jesse Luehrs Date: Sat, 8 Jan 2022 00:28:37 -0500 Subject: add basic variable parsing --- src/parse/ast.rs | 34 ++++++++++++++++++++++++++-------- src/shell.pest | 18 ++++++++++++------ 2 files changed, 38 insertions(+), 14 deletions(-) diff --git a/src/parse/ast.rs b/src/parse/ast.rs index 28593bb..71cb9af 100644 --- a/src/parse/ast.rs +++ b/src/parse/ast.rs @@ -142,6 +142,7 @@ struct Word { word: String, interpolate: bool, quoted: bool, + var: bool, } impl Word { @@ -150,22 +151,33 @@ impl Word { matches!(rule, Rule::bareword | Rule::double_string); let quoted = matches!(rule, Rule::single_string | Rule::double_string); - let mut word_str = s.to_string(); - if interpolate { - word_str = strip_escape(&word_str); + let var = matches!(rule, Rule::var); + let word_str = if var { + let inner = s.strip_prefix('$').unwrap(); + inner + .strip_prefix('{') + .map_or(inner, |inner| inner.strip_suffix('}').unwrap()) + .to_string() + } else if interpolate { + strip_escape(s) } else { - word_str = strip_basic_escape(&word_str); - } + strip_basic_escape(s) + }; Self { word: word_str, interpolate, quoted, + var, } } fn eval(self, _env: &Env) -> String { - // TODO - self.word + if self.var { + // TODO + format!("'value-of-${{{}}}'", self.word) + } else { + self.word + } } } @@ -247,7 +259,10 @@ impl WordOrRedirect { } assert!(matches!( word.as_rule(), - Rule::bareword | Rule::single_string | Rule::double_string + Rule::var + | Rule::bareword + | Rule::single_string + | Rule::double_string )); let word = Word::parse(word.as_str(), word.as_rule()); if let Some(prefix) = prefix { @@ -381,6 +396,7 @@ macro_rules! w { word: $word.to_string(), interpolate: true, quoted: false, + var: false, } }; ($word:expr, $interpolate:expr) => { @@ -388,6 +404,7 @@ macro_rules! w { word: $word.to_string(), interpolate: $interpolate, quoted: false, + var: false, } }; ($word:expr, $interpolate:expr, $quoted:expr) => { @@ -395,6 +412,7 @@ macro_rules! w { word: $word.to_string(), interpolate: $interpolate, quoted: $quoted, + var: false, } }; } diff --git a/src/shell.pest b/src/shell.pest index ffb0f42..b1bcae5 100644 --- a/src/shell.pest +++ b/src/shell.pest @@ -3,11 +3,17 @@ escape_char = @{ "\\" ~ ANY } bareword_char = @{ escape_char | - !("|" | ";" | "\"" | "'" | WHITESPACE | COMMENT) ~ ANY + !("|" | ";" | "\"" | "'" | "$" | WHITESPACE | COMMENT) ~ ANY } single_string_char = @{ basic_escape_char | (!"'" ~ ANY) } double_string_char = @{ escape_char | (!"\"" ~ ANY) } +var = @{ + ("$" ~ XID_START ~ XID_CONTINUE*) | + ("$" ~ ("?" | "$" | "*" | ASCII_DIGIT)) | + ("${" ~ (!"}" ~ ANY)+ ~ "}") +} + redir_prefix = @{ ASCII_DIGIT* ~ (">>" | ">" | "<") ~ WHITESPACE* } bareword = @{ bareword_char+ } single_string = @{ single_string_char+ } @@ -15,17 +21,17 @@ double_string = @{ double_string_char+ } word = ${ redir_prefix? ~ - (bareword | + (var | bareword | "'" ~ single_string ~ "'" | "\"" ~ double_string ~ "\"") } exe = ${ word ~ (w ~ word)* } -pipeline = ${ exe ~ (w ~ "|" ~ w ~ exe)* } -commands = ${ pipeline ~ (w ~ ";" ~ w ~ pipeline)* } +pipeline = ${ exe ~ (w? ~ "|" ~ w? ~ exe)* } +commands = ${ pipeline ~ (w? ~ ";" ~ w? ~ pipeline)* } -line = ${ SOI ~ w ~ commands ~ w ~ EOI } +line = ${ SOI ~ w? ~ commands ~ w? ~ EOI } -w = _{ (WHITESPACE | COMMENT)* } +w = _{ (WHITESPACE | COMMENT)+ } WHITESPACE = _{ (" " | "\t" | "\n") } COMMENT = _{ "#" ~ ANY* } -- cgit v1.2.3-54-g00ecf