aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--src/parse/mod.rs (renamed from src/parse.rs)38
-rw-r--r--src/parse/test.rs16
2 files changed, 39 insertions, 15 deletions
diff --git a/src/parse.rs b/src/parse/mod.rs
index 61d268d..4f38f9b 100644
--- a/src/parse.rs
+++ b/src/parse/mod.rs
@@ -1,16 +1,19 @@
use crate::BString;
-pub trait Stage {
- type Str: std::fmt::Debug + Clone;
+#[cfg(test)]
+mod test;
+
+pub trait Stage : PartialEq {
+ type Str: std::fmt::Debug + Clone + PartialEq;
}
pub trait CmdDisplay {
fn cdisplay(&self, w: &mut dyn std::io::Write) -> std::io::Result<()>;
}
-#[derive(Debug, Clone)]
+#[derive(Debug, Clone, PartialEq)]
pub struct PreExpansion;
-#[derive(Debug, Clone)]
+#[derive(Debug, Clone, PartialEq)]
pub struct PostExpansion;
impl Stage for PreExpansion {
@@ -29,7 +32,7 @@ pub trait Expander {
fn expand_cmd(&mut self, c: Ast<PostExpansion>) -> Res<BString, Self::Error>;
}
-#[derive(Debug, Clone)]
+#[derive(Debug, Clone, PartialEq)]
pub enum Ast<T: Stage> {
FunDecl(FunDecl<T>),
VarAssign(VarAssign<T>),
@@ -121,12 +124,17 @@ impl CmdDisplay for ExpString {
if self.parts.len() == 1 && self.parts[0].is_boring() {
write!(
w,
- "estr({})",
+ "estr(b\"{}\")",
self.parts[0].clone().unwrap_boring().escape_ascii()
)
} else {
write!(w, "str([")?;
+ let mut first = true;
for part in self.parts.iter() {
+ if !first {
+ write!(w, ",")?;
+ }
+ first = false;
part.cdisplay(w)?;
}
write!(w, "])")
@@ -138,7 +146,7 @@ impl CmdDisplay for StringPart {
fn cdisplay(&self, w: &mut dyn std::io::Write) -> std::io::Result<()> {
match self {
StringPart::Boring(items) => {
- write!(w, "bstr(")?;
+ write!(w, "plain(")?;
items.as_slice().cdisplay(w)?;
write!(w, ")")
}
@@ -186,7 +194,7 @@ impl Ast<PreExpansion> {
}
}
-#[derive(Debug, Clone)]
+#[derive(Debug, Clone, PartialEq)]
pub struct FunBody {
pub body: Box<Ast<PreExpansion>>,
}
@@ -219,7 +227,7 @@ impl Parse for FunBody {
}
}
-#[derive(Debug, Clone)]
+#[derive(Debug, Clone, PartialEq)]
pub struct FunDecl<S: Stage> {
pub name: S::Str,
pub body: FunBody,
@@ -247,7 +255,7 @@ impl FunDecl<PreExpansion> {
}
}
-#[derive(Debug, Clone)]
+#[derive(Debug, Clone, PartialEq)]
pub struct VarAssign<S: Stage> {
pub var: S::Str,
pub val: S::Str,
@@ -285,7 +293,7 @@ impl VarAssign<PreExpansion> {
}
}
-#[derive(Debug, Clone)]
+#[derive(Debug, Clone, PartialEq)]
pub struct Pipes<T: Stage> {
pub cmds: Vec<Command<T>>,
}
@@ -300,7 +308,7 @@ impl Pipes<PreExpansion> {
}
}
-#[derive(Debug, Clone)]
+#[derive(Debug, Clone, PartialEq)]
pub enum StringPart {
Boring(BString),
Var(VarName),
@@ -319,7 +327,7 @@ impl StringPart {
}
}
-#[derive(Debug, Clone)]
+#[derive(Debug, Clone, PartialEq)]
/// `"hi ${var} $(cmd) "` gets mapped to `[Boring("hi "), Var("var"), String(" "), Cmd(...), Boring(" ")]`
pub struct ExpString {
parts: Vec<StringPart>,
@@ -357,7 +365,7 @@ fn is_var_name(x: u8) -> bool {
x.is_ascii_alphanumeric() || x == b'_'
}
-#[derive(Debug, Clone)]
+#[derive(Debug, Clone, PartialEq)]
pub struct VarName {
name: BString,
}
@@ -509,7 +517,7 @@ impl Parse for ExpString {
}
}
-#[derive(Debug, Clone)]
+#[derive(Debug, Clone, PartialEq)]
pub struct Command<T: Stage> {
pub cmd: T::Str,
pub args: Vec<T::Str>,
diff --git a/src/parse/test.rs b/src/parse/test.rs
new file mode 100644
index 0000000..6cd7793
--- /dev/null
+++ b/src/parse/test.rs
@@ -0,0 +1,16 @@
+use super::*;
+
+fn parse(x: &[u8]) -> Ast<PreExpansion> {
+ do_parse(x).unwrap()
+}
+
+#[test]
+fn command_interp() {
+ assert_eq!(
+ parse(br#"echo "$(echo hi)""#),
+ pipes([cmd([
+ estr(b"echo"),
+ str([cmdp(pipes([cmd([estr(b"echo"), estr(b"hi")]),])),])
+ ]),])
+ );
+}