diff options
| author | Jonas Maier <> | 2026-03-06 16:17:48 +0100 |
|---|---|---|
| committer | Jonas Maier <> | 2026-03-06 16:17:48 +0100 |
| commit | 2564bed64f695fc767d668f47c583944e5b5f3b9 (patch) | |
| tree | c9f02d303bc74301f5f1844337ab7df927c2bbf4 /src | |
| parent | 40387917c8ba4703aee111e1cf37dcd793e39ba2 (diff) | |
| download | pish-2564bed64f695fc767d668f47c583944e5b5f3b9.tar.gz | |
paaaarser
Diffstat (limited to 'src')
| -rw-r--r-- | src/parse.rs | 88 |
1 files changed, 84 insertions, 4 deletions
diff --git a/src/parse.rs b/src/parse.rs index a685f5d..05ca020 100644 --- a/src/parse.rs +++ b/src/parse.rs @@ -19,7 +19,7 @@ pub struct Pipes { pub enum StringPart { Boring(BString), - Var(BString), + Var(VarName), Cmd(Ast), } @@ -30,11 +30,47 @@ pub struct ShellString { fn is_symbol(x: u8) -> bool { match x { - b'|' => true, + b'|' | b'{' | b'}' | b'$' => true, _ => false, } } +fn is_var_begin(x: u8) -> bool { + x.is_ascii_alphabetic() +} +fn is_var_name(x: u8) -> bool { + x.is_ascii_alphanumeric() || x == b'_' +} + +struct VarName { + name: BString, +} + +impl Parse for VarName { + fn parse(b: &mut Cursor<'_>) -> Result<Self> { + if b.is_empty() { + return Err(ParseError::Eof); + } + + if !is_var_begin(b.peek()) { + return Err(ParseError::ExpectedAlphabetic); + } + + let mut name = BString::new(); + while b.has() { + let x = b.peek(); + if is_var_name(x) { + b.adv(); + name.push(x) + } else { + break; + } + } + + Ok(Self { name }) + } +} + impl Parse for ShellString { fn parse(b: &mut Cursor<'_>) -> Result<Self> { b.spaces(); @@ -77,13 +113,55 @@ impl Parse for ShellString { b.adv(); + if delim == b'\'' { + // no fancy stuff here + add_char(p, x); + continue; + } + if x == b'\\' { escaping = true; continue; } if x == b'$' { - todo!() + if !b.has() { + add_char(p, x); + continue; + } + + let x = b.peek(); + + if is_var_begin(x) { + let v = VarName::parse(b)?; + p.push(StringPart::Var(v)); + } else if x == b'{' { + b.adv(); + let v = VarName::parse(b)?; + + if !b.has() { + return Err(ParseError::Eof); + } else if b.peek() == b':' { + todo!(": in var expansion") + } + + if !b.has() { + return Err(ParseError::Eof); + } else if b.peek() != b'}' { + return Err(ParseError::Incomplete); + } + + b.adv(); + p.push(StringPart::Var(v)); + } else if x == b'(' { + todo!() + } else { + // doesn't seem to be a variable or expansion, just add $ back into the string + add_char(p, b'$'); + continue; + } + + continue; } if delim == b' ' && is_symbol(x) { @@ -93,7 +171,7 @@ impl Parse for ShellString { add_char(p, x); } - if b.is_completion() { + if b.is_completion() || delim == b' ' { Ok(Self { parts }) } else { Err(ParseError::Eof) @@ -117,6 +195,8 @@ pub enum ParseError { UnexpectedPipe, + ExpectedAlphabetic, + Unknown(u8), } |
