diff options
Diffstat (limited to 'src')
| -rw-r--r-- | src/parse/mod.rs | 77 | ||||
| -rw-r--r-- | src/parse/test.rs | 8 | ||||
| -rw-r--r-- | src/run/mod.rs | 11 |
3 files changed, 80 insertions, 16 deletions
diff --git a/src/parse/mod.rs b/src/parse/mod.rs index d25767d..4806421 100644 --- a/src/parse/mod.rs +++ b/src/parse/mod.rs @@ -28,7 +28,7 @@ type Res<T, E> = std::result::Result<T, E>; pub trait Expander { type Error; - fn expand_var(&mut self, v: BString) -> Res<BString, Self::Error>; + fn expand_var(&mut self, v: BString, default: Option<BString>) -> Res<BString, Self::Error>; fn expand_cmd(&mut self, c: Ast<PostExpansion>) -> Res<BString, Self::Error>; } @@ -75,7 +75,17 @@ pub fn plain(x: &[u8]) -> StringPart { } pub fn var(x: &[u8]) -> StringPart { - StringPart::Var(VarName { name: x.to_vec() }) + StringPart::Var(Var { + name: VarName { name: x.to_vec() }, + default: None, + }) +} + +pub fn var_default(x: &[u8], default: ExpString) -> StringPart { + StringPart::Var(Var { + name: VarName { name: x.to_vec() }, + default: Some(default), + }) } pub fn cmdp(x: Ast<PreExpansion>) -> StringPart { @@ -150,10 +160,18 @@ impl CmdDisplay for StringPart { items.as_slice().cdisplay(w)?; write!(w, ")") } - StringPart::Var(var_name) => { - write!(w, "var(")?; - var_name.name.as_slice().cdisplay(w)?; - write!(w, ")") + StringPart::Var(var) => { + if let Some(default) = &var.default { + write!(w, "var_default(")?; + var.name.name.as_slice().cdisplay(w)?; + write!(w, ",")?; + default.cdisplay(w)?; + write!(w, ")") + } else { + write!(w, "var(")?; + var.name.name.as_slice().cdisplay(w)?; + write!(w, ")") + } } StringPart::Cmd(ast) => { write!(w, "cmdp(")?; @@ -312,10 +330,16 @@ impl Pipes<PreExpansion> { #[derive(Debug, Clone, PartialEq)] pub enum StringPart { Boring(BString), - Var(VarName), + Var(Var), Cmd(Ast<PreExpansion>), } +#[derive(Debug, Clone, PartialEq)] +pub struct Var { + name: VarName, + default: Option<ExpString>, +} + impl StringPart { pub fn is_boring(&self) -> bool { matches!(self, StringPart::Boring(..)) @@ -340,7 +364,13 @@ impl ExpString { for part in self.parts.into_iter() { let mut x = match part { StringPart::Boring(items) => items, - StringPart::Var(v) => e.expand_var(v.name)?, + StringPart::Var(v) => { + let default = match v.default { + Some(default) => Some(default.expand(e)?), + None => None, + }; + e.expand_var(v.name.name, default)? + } StringPart::Cmd(ast) => { let exp = ast.expand(e)?; e.expand_cmd(exp)? @@ -483,18 +513,34 @@ impl Parse for ExpString { if x == b'?' || x == b'!' { b.adv(); - p.push(StringPart::Var(VarName { name: vec![x] })) + p.push(StringPart::Var(Var { + name: VarName { name: vec![x] }, + default: None, + })) } else if is_var_begin(x) { let v = VarName::parse(b)?; - p.push(StringPart::Var(v)); + p.push(StringPart::Var(Var { + name: v, + default: None, + })); } else if x == b'{' { b.adv(); let v = VarName::parse(b)?; + let mut default = None; if !b.has() { return Err(ParseError::Eof); } else if b.peek() == b':' { - todo!(": in var expansion") + b.adv(); + if !b.has() { + return Err(ParseError::Eof); + } + if b.peek() == b'-' { + b.adv(); + default = Some(ExpString::parse(b)?); + } else { + todo!(": in var expansion") + } } if !b.has() { @@ -504,7 +550,7 @@ impl Parse for ExpString { } b.adv(); - p.push(StringPart::Var(v)); + p.push(StringPart::Var(Var { name: v, default })); } else if x == b'(' { b.adv(); let cmd = Ast::parse(b)?; @@ -530,8 +576,11 @@ impl Parse for ExpString { } if delim == b' ' && x == b'~' { - p.push(StringPart::Var(VarName { - name: b"HOME".to_vec(), + p.push(StringPart::Var(Var { + name: VarName { + name: b"HOME".to_vec(), + }, + default: None, })); } else { add_char(p, x); diff --git a/src/parse/test.rs b/src/parse/test.rs index 28cf4a2..ca57e75 100644 --- a/src/parse/test.rs +++ b/src/parse/test.rs @@ -86,3 +86,11 @@ fn set_variable_in_fun() { decl(estr(b"setter"), assign(estr(b"x"), estr(b"1"))), ); } + +#[test] +fn variable_with_defaults() { + parse_test( + parse(b"${x:-y}"), + pipes([cmd([str([var_default(b"x", estr(b"y"))])])]), + ); +} diff --git a/src/run/mod.rs b/src/run/mod.rs index c7414a8..e041066 100644 --- a/src/run/mod.rs +++ b/src/run/mod.rs @@ -305,7 +305,11 @@ impl Executor { impl parse::Expander for Executor { type Error = ExecError; - fn expand_var(&mut self, var: BString) -> Result<BString, Self::Error> { + fn expand_var( + &mut self, + var: BString, + default: Option<BString>, + ) -> Result<BString, Self::Error> { if var.is_empty() { return Err(ExecError::UnknownVariable(var)); } @@ -331,7 +335,10 @@ impl parse::Expander for Executor { match std::env::var_os(OsStr::from_bytes(&var)) { Some(val) => Ok(val.as_bytes().to_vec()), - None => Err(ExecError::UnknownVariable(var)), + None => match default { + Some(d) => Ok(d), + None => Err(ExecError::UnknownVariable(var)), + }, } } |
