aboutsummaryrefslogtreecommitdiffstats
path: root/src
diff options
context:
space:
mode:
Diffstat (limited to 'src')
-rw-r--r--src/parse.rs144
-rw-r--r--src/run/builtin.rs34
-rw-r--r--src/run/mod.rs1
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 {