From 0e73fe1d5edfe01789efa43c1c97a2c448cd25be Mon Sep 17 00:00:00 2001 From: Jonas Maier <> Date: Fri, 6 Mar 2026 16:53:55 +0100 Subject: visitor for expansion --- src/parse.rs | 75 +++++++++++++++++++++++++++++++++++++++++++++++++++--------- 1 file 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 = std::result::Result; + +trait Expander { + type Error; + fn expand_var(&mut self, v: VarName) -> Res; + fn expand_cmd(&mut self, c: Ast) -> Res; +} + +#[derive(Debug, Clone)] pub enum Ast { AssignVar(AssignVar), Pipes(Pipes), } -#[derive(Debug)] +impl Ast { + pub fn expand(self, e: &mut E) -> Res, 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 { pub cmds: Vec>, } -#[derive(Debug)] +impl Pipes { + fn expand(self, e: &mut E) -> Res, 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, } +impl ExpString { + fn expand(self, e: &mut E) -> Res { + 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 { pub cmd: T::Str, pub args: Vec, } +impl Command { + fn expand(self, e: &mut E) -> Res, 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(), } } } -- cgit v1.2.3