diff options
| author | Jonas Maier <> | 2026-03-06 16:53:55 +0100 |
|---|---|---|
| committer | Jonas Maier <> | 2026-03-06 16:53:55 +0100 |
| commit | 0e73fe1d5edfe01789efa43c1c97a2c448cd25be (patch) | |
| tree | 1fa7046f790c5b22673a3bd44bff7c923475b6d8 /src | |
| parent | 64323dc8f4b97790dfd4617d965cd304d3f5158c (diff) | |
| download | pish-0e73fe1d5edfe01789efa43c1c97a2c448cd25be.tar.gz | |
visitor for expansion
Diffstat (limited to 'src')
| -rw-r--r-- | src/parse.rs | 75 |
1 files changed, 64 insertions, 11 deletions
diff --git a/src/parse.rs b/src/parse.rs index d56b3e6..c30206a 100644 --- a/src/parse.rs +++ b/src/parse.rs @@ -1,12 +1,12 @@ use crate::BString; pub trait Stage { - type Str: std::fmt::Debug; + type Str: std::fmt::Debug + Clone; } -#[derive(Debug)] +#[derive(Debug, Clone)] pub struct PreExpansion; -#[derive(Debug)] +#[derive(Debug, Clone)] pub struct PostExpansion; impl Stage for PreExpansion { @@ -17,24 +17,51 @@ impl Stage for PostExpansion { type Str = BString; } -#[derive(Debug)] +type Res<T, E> = std::result::Result<T, E>; + +trait Expander { + type Error; + fn expand_var(&mut self, v: VarName) -> Res<BString, Self::Error>; + fn expand_cmd(&mut self, c: Ast<PreExpansion>) -> Res<BString, Self::Error>; +} + +#[derive(Debug, Clone)] pub enum Ast<T: Stage> { AssignVar(AssignVar), Pipes(Pipes<T>), } -#[derive(Debug)] +impl Ast<PreExpansion> { + pub fn expand<E: Expander>(self, e: &mut E) -> Res<Ast<PostExpansion>, E::Error> { + match self { + Ast::AssignVar(assign_var) => todo!(), + Ast::Pipes(pipes) => Ok(Ast::Pipes(pipes.expand(e)?)), + } + } +} + +#[derive(Debug, Clone)] pub struct AssignVar { pub to: String, // TODO: body } -#[derive(Debug)] +#[derive(Debug, Clone)] pub struct Pipes<T: Stage> { pub cmds: Vec<Command<T>>, } -#[derive(Debug)] +impl Pipes<PreExpansion> { + fn expand<E: Expander>(self, e: &mut E) -> Res<Pipes<PostExpansion>, E::Error> { + let mut cmds = Vec::with_capacity(self.cmds.len()); + for cmd in self.cmds.into_iter() { + cmds.push(cmd.expand(e)?); + } + Ok(Pipes { cmds }) + } +} + +#[derive(Debug, Clone)] pub enum StringPart { Boring(BString), Var(VarName), @@ -45,7 +72,7 @@ impl StringPart { pub fn is_boring(&self) -> bool { matches!(self, StringPart::Boring(..)) } - pub fn unwrap_boring(&self) -> BString { + pub fn unwrap_boring(self) -> BString { match self { StringPart::Boring(items) => items, _ => panic!("unwrap on non-boring value"), @@ -59,6 +86,21 @@ pub struct ExpString { parts: Vec<StringPart>, } +impl ExpString { + fn expand<E: Expander>(self, e: &mut E) -> Res<BString, E::Error> { + let mut out = BString::new(); + for part in self.parts.into_iter() { + let mut x = match part { + StringPart::Boring(items) => items, + StringPart::Var(v) => e.expand_var(v)?, + StringPart::Cmd(ast) => e.expand_cmd(ast)?, + }; + out.append(&mut x); + } + Ok(out) + } +} + fn is_symbol(x: u8) -> bool { match x { b'|' | b'{' | b'}' | b'$' => true, @@ -73,7 +115,7 @@ fn is_var_name(x: u8) -> bool { x.is_ascii_alphanumeric() || x == b'_' } -#[derive(Debug)] +#[derive(Debug, Clone)] struct VarName { name: BString, } @@ -211,12 +253,23 @@ impl Parse for ExpString { } } -#[derive(Debug)] +#[derive(Debug, Clone)] pub struct Command<T: Stage> { pub cmd: T::Str, pub args: Vec<T::Str>, } +impl Command<PreExpansion> { + fn expand<E: Expander>(self, e: &mut E) -> Res<Command<PostExpansion>, E::Error> { + let cmd = self.cmd.expand(e)?; + let mut args = Vec::with_capacity(self.args.len()); + for arg in self.args.into_iter() { + args.push(arg.expand(e)?); + } + Ok(Command { cmd, args }) + } +} + #[derive(Debug)] pub enum ParseError { /// "clean" EOF, i.e. not in the middle of something @@ -264,7 +317,7 @@ fn expstr_cc(s: &ExpString, kind: CompletionKind) -> CompletionContext { } else { CompletionContext { kind, - partial: s.parts[0].unwrap_boring().clone(), + partial: s.parts[0].clone().unwrap_boring().clone(), } } } |
