use super::super::Error;
use super::super::attr::AttrChar;
use super::super::attr::Origin;
use super::Env;
use super::Expand;
use super::Phrase;
use super::param::ParamRef;
use crate::Runtime;
use yash_syntax::syntax::Text;
use yash_syntax::syntax::TextUnit::{self, *};
use yash_syntax::syntax::Unquote as _;
impl<S: Runtime + 'static> Expand<S> for TextUnit {
async fn expand(&self, env: &mut Env<'_, S>) -> Result<Phrase, Error> {
match self {
&Literal(value) => Ok(Phrase::Char(AttrChar {
value,
origin: Origin::Literal,
is_quoted: false,
is_quoting: false,
})),
&Backslashed(value) => {
let bs = AttrChar {
value: '\\',
origin: Origin::Literal,
is_quoted: false,
is_quoting: true,
};
let c = AttrChar {
value,
origin: Origin::Literal,
is_quoted: true,
is_quoting: false,
};
Ok(Phrase::Field(vec![bs, c]))
}
RawParam { param, location } => {
let param_ref = ParamRef {
param,
modifier: &yash_syntax::syntax::Modifier::None,
location,
};
Box::pin(param_ref.expand(env)).await }
BracedParam(param) => Box::pin(ParamRef::from(param).expand(env)).await,
CommandSubst { content, location } => {
let command = content.clone();
let location = location.clone();
super::command_subst::expand(command, location, env).await
}
Backquote { content, location } => {
let command = content.unquote().0;
let location = location.clone();
super::command_subst::expand(command, location, env).await
}
Arith { content, location } => {
Box::pin(super::arith::expand(content, location, env)).await
}
}
}
}
impl<S: Runtime + 'static> Expand<S> for Text {
async fn expand(&self, env: &mut Env<'_, S>) -> Result<Phrase, Error> {
self.0.expand(env).await
}
}
#[cfg(test)]
mod tests {
use super::super::param::tests::braced_variable;
use super::*;
use crate::tests::echo_builtin;
use futures_util::FutureExt as _;
use yash_env::test_helper::in_virtual_system;
use yash_env::variable::Scope;
use yash_syntax::source::Location;
use yash_syntax::syntax::BracedParam;
use yash_syntax::syntax::Param;
#[test]
fn literal() {
let mut env = yash_env::Env::new_virtual();
let mut env = Env::new(&mut env);
let result = Literal('L').expand(&mut env).now_or_never().unwrap();
let c = AttrChar {
value: 'L',
origin: Origin::Literal,
is_quoted: false,
is_quoting: false,
};
assert_eq!(result, Ok(Phrase::Char(c)));
}
#[test]
fn backslashed() {
let mut env = yash_env::Env::new_virtual();
let mut env = Env::new(&mut env);
let result = Backslashed('L').expand(&mut env).now_or_never().unwrap();
let bs = AttrChar {
value: '\\',
origin: Origin::Literal,
is_quoted: false,
is_quoting: true,
};
let c = AttrChar {
value: 'L',
origin: Origin::Literal,
is_quoted: true,
is_quoting: false,
};
assert_eq!(result, Ok(Phrase::Field(vec![bs, c])));
}
#[test]
fn raw_param() {
let mut env = yash_env::Env::new_virtual();
env.variables
.get_or_new("foo", Scope::Global)
.assign("x", None)
.unwrap();
let mut env = Env::new(&mut env);
let raw_param = RawParam {
param: Param::variable("foo"),
location: Location::dummy(""),
};
let result = raw_param.expand(&mut env).now_or_never().unwrap();
let c = AttrChar {
value: 'x',
origin: Origin::SoftExpansion,
is_quoted: false,
is_quoting: false,
};
assert_eq!(result, Ok(Phrase::Char(c)));
}
#[test]
fn braced_param() {
let mut env = yash_env::Env::new_virtual();
env.variables
.get_or_new("foo", Scope::Global)
.assign("x", None)
.unwrap();
let mut env = Env::new(&mut env);
let param = BracedParam(braced_variable("foo"));
let result = param.expand(&mut env).now_or_never().unwrap();
let c = AttrChar {
value: 'x',
origin: Origin::SoftExpansion,
is_quoted: false,
is_quoting: false,
};
assert_eq!(result, Ok(Phrase::Char(c)));
}
#[test]
fn command_subst() {
in_virtual_system(|mut env, _state| async move {
env.builtins.insert("echo", echo_builtin());
let mut env = Env::new(&mut env);
let subst = TextUnit::CommandSubst {
content: "echo .".into(),
location: Location::dummy(""),
};
let result = subst.expand(&mut env).await;
let c = AttrChar {
value: '.',
origin: Origin::SoftExpansion,
is_quoted: false,
is_quoting: false,
};
assert_eq!(result, Ok(Phrase::Char(c)));
})
}
#[test]
fn backquote() {
in_virtual_system(|mut env, _state| async move {
env.builtins.insert("echo", echo_builtin());
let mut env = Env::new(&mut env);
use yash_syntax::syntax::BackquoteUnit::*;
let subst = TextUnit::Backquote {
content: vec![
Literal('e'),
Literal('c'),
Literal('h'),
Literal('o'),
Literal(' '),
Backslashed('\\'),
Backslashed('\\'),
],
location: Location::dummy(""),
};
let result = subst.expand(&mut env).await;
let c = AttrChar {
value: '\\',
origin: Origin::SoftExpansion,
is_quoted: false,
is_quoting: false,
};
assert_eq!(result, Ok(Phrase::Char(c)));
})
}
#[test]
fn arithmetic() {
let mut env = yash_env::Env::new_virtual();
let mut env = Env::new(&mut env);
let arith = TextUnit::Arith {
content: "1+2*3".parse().unwrap(),
location: Location::dummy(""),
};
let result = arith.expand(&mut env).now_or_never().unwrap();
let c = AttrChar {
value: '7',
origin: Origin::SoftExpansion,
is_quoted: false,
is_quoting: false,
};
assert_eq!(result, Ok(Phrase::Char(c)));
}
}