diff options
Diffstat (limited to 'src')
| -rw-r--r-- | src/parse.rs | 144 | ||||
| -rw-r--r-- | src/run/builtin.rs | 34 | ||||
| -rw-r--r-- | src/run/mod.rs | 1 |
3 files changed, 178 insertions, 1 deletions
diff --git a/src/parse.rs b/src/parse.rs index 809f76b..61d268d 100644 --- a/src/parse.rs +++ b/src/parse.rs @@ -4,6 +4,10 @@ pub trait Stage { type Str: std::fmt::Debug + Clone; } +pub trait CmdDisplay { + fn cdisplay(&self, w: &mut dyn std::io::Write) -> std::io::Result<()>; +} + #[derive(Debug, Clone)] pub struct PreExpansion; #[derive(Debug, Clone)] @@ -32,6 +36,146 @@ pub enum Ast<T: Stage> { Pipes(Pipes<T>), } +pub fn decl(name: ExpString, body: Ast<PreExpansion>) -> Ast<PreExpansion> { + Ast::FunDecl(FunDecl { + name: name, + body: FunBody { + body: Box::new(body), + }, + }) +} + +pub fn assign(var: ExpString, val: ExpString) -> Ast<PreExpansion> { + Ast::VarAssign(VarAssign { var, val }) +} + +pub fn pipes<const N: usize>(cmds: [Command<PreExpansion>; N]) -> Ast<PreExpansion> { + Ast::Pipes(Pipes { + cmds: cmds.to_vec(), + }) +} + +pub fn estr(x: &[u8]) -> ExpString { + ExpString { + parts: vec![StringPart::Boring(x.to_vec())], + } +} + +pub fn str<const N: usize>(parts: [StringPart; N]) -> ExpString { + ExpString { + parts: parts.to_vec(), + } +} + +pub fn plain(x: &[u8]) -> StringPart { + StringPart::Boring(x.to_vec()) +} + +pub fn var(x: &[u8]) -> StringPart { + StringPart::Var(VarName { name: x.to_vec() }) +} + +pub fn cmdp(x: Ast<PreExpansion>) -> StringPart { + StringPart::Cmd(x) +} + +pub fn cmd<const N: usize>(x: [ExpString; N]) -> Command<PreExpansion> { + Command { + cmd: x[0].clone(), + args: x[1..].to_vec(), + } +} + +impl CmdDisplay for Ast<PreExpansion> { + fn cdisplay(&self, w: &mut dyn std::io::Write) -> std::io::Result<()> { + match self { + Ast::FunDecl(fun_decl) => { + write!(w, "decl(")?; + fun_decl.name.cdisplay(w)?; + write!(w, ", ")?; + fun_decl.body.body.cdisplay(w)?; + write!(w, ")")?; + } + Ast::VarAssign(var_assign) => { + write!(w, "assign(")?; + var_assign.var.cdisplay(w)?; + write!(w, ", ")?; + var_assign.val.cdisplay(w)?; + write!(w, ")")?; + } + Ast::Pipes(pipes) => { + write!(w, "pipes([")?; + for cmd in pipes.cmds.iter() { + cmd.cdisplay(w)?; + write!(w, ",")?; + } + write!(w, "])")?; + } + } + Ok(()) + } +} + +impl CmdDisplay for ExpString { + fn cdisplay(&self, w: &mut dyn std::io::Write) -> std::io::Result<()> { + if self.parts.len() == 1 && self.parts[0].is_boring() { + write!( + w, + "estr({})", + self.parts[0].clone().unwrap_boring().escape_ascii() + ) + } else { + write!(w, "str([")?; + for part in self.parts.iter() { + part.cdisplay(w)?; + } + write!(w, "])") + } + } +} + +impl CmdDisplay for StringPart { + fn cdisplay(&self, w: &mut dyn std::io::Write) -> std::io::Result<()> { + match self { + StringPart::Boring(items) => { + write!(w, "bstr(")?; + items.as_slice().cdisplay(w)?; + write!(w, ")") + } + StringPart::Var(var_name) => { + write!(w, "var(")?; + var_name.name.as_slice().cdisplay(w)?; + write!(w, ")") + }, + StringPart::Cmd(ast) => { + write!(w, "cmdp(")?; + ast.cdisplay(w)?; + write!(w, ")") + } + } + } +} + +impl CmdDisplay for Command<PreExpansion> { + fn cdisplay(&self, w: &mut dyn std::io::Write) -> std::io::Result<()> { + write!(w, "cmd([")?; + self.cmd.cdisplay(w)?; + for arg in self.args.iter() { + write!(w, ", ")?; + arg.cdisplay(w)?; + } + write!(w, "])") + } +} + +impl CmdDisplay for &[u8] { + fn cdisplay(&self, w: &mut dyn std::io::Write) -> std::io::Result<()> { + write!(w, "b\"")?; + write!(w, "{}", self.escape_ascii())?; + write!(w, "\"") + } +} + impl Ast<PreExpansion> { pub fn expand<E: Expander>(self, e: &mut E) -> Res<Ast<PostExpansion>, E::Error> { match self { diff --git a/src/run/builtin.rs b/src/run/builtin.rs index c71f10f..0b2b3bc 100644 --- a/src/run/builtin.rs +++ b/src/run/builtin.rs @@ -3,7 +3,8 @@ use std::sync::{Arc, Mutex}; use std::{env::*, fs::OpenOptions, path::PathBuf}; -use super::{Builtin, BuiltinResult as Result}; +use super::{Builtin, BuiltinError as Error, BuiltinResult as Result}; +use crate::parse::CmdDisplay; use crate::*; pub struct cd; @@ -242,3 +243,34 @@ impl Builtin for escape { Ok(()) } } + +pub struct parse; +impl Builtin for parse { + fn name(&self) -> &str { + "parse" + } + + fn io( + &self, + _session: Arc<Mutex<Session>>, + args: &[BString], + _stdin: &mut dyn Read, + stdout: &mut dyn Write, + ) -> Result { + let mut is_ok = true; + for arg in args { + match crate::parse::do_parse(arg) { + Ok(parsed) => { + write!(stdout, "ok ")?; + parsed.cdisplay(stdout)?; + writeln!(stdout)?; + }, + Err(err) => { + is_ok = false; + writeln!(stdout, "err {err:?}")?; + } + } + } + if is_ok { Ok(()) } else { Err(Error::Exit(-1)) } + } +} diff --git a/src/run/mod.rs b/src/run/mod.rs index 2d137c6..c0a108a 100644 --- a/src/run/mod.rs +++ b/src/run/mod.rs @@ -305,6 +305,7 @@ const BUILTINS: &[&'static dyn Builtin] = &[ &builtin::_type, &builtin::history, &builtin::escape, + &builtin::parse, ]; pub struct CommandDispatch { |
