aboutsummaryrefslogtreecommitdiffstats
path: root/src
diff options
context:
space:
mode:
authorJonas Maier <>2026-03-06 16:53:55 +0100
committerJonas Maier <>2026-03-06 16:53:55 +0100
commit0e73fe1d5edfe01789efa43c1c97a2c448cd25be (patch)
tree1fa7046f790c5b22673a3bd44bff7c923475b6d8 /src
parent64323dc8f4b97790dfd4617d965cd304d3f5158c (diff)
downloadpish-0e73fe1d5edfe01789efa43c1c97a2c448cd25be.tar.gz
visitor for expansion
Diffstat (limited to 'src')
-rw-r--r--src/parse.rs75
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(),
}
}
}