use future::{Async, EnvFuture, Poll};
use glob;
use env::{StringWrapper, VariableEnvironment};
use error::ExpansionError;
use std::borrow::Borrow;
mod concat;
mod double_quoted;
mod fields;
mod param_subst;
mod redirect;
mod redirect_or_cmd_word;
mod redirect_or_var_assig;
#[cfg(feature = "conch-parser")]
pub mod ast_impl;
pub use self::concat::{Concat, concat};
pub use self::double_quoted::{double_quoted, DoubleQuoted};
pub use self::fields::Fields;
pub use self::param_subst::{alternative, assign, default, error, len,
remove_largest_prefix, remove_largest_suffix, remove_smallest_prefix,
remove_smallest_suffix, split};
pub use self::param_subst::{Alternative, Assign, EvalDefault, Error, RemoveLargestPrefix,
RemoveLargestSuffix, RemoveSmallestPrefix, RemoveSmallestSuffix, Split};
pub use self::redirect::{Redirect, RedirectAction, RedirectEval,
redirect_append, redirect_clobber, redirect_dup_read, redirect_dup_write,
redirect_heredoc, redirect_read, redirect_readwrite, redirect_write};
pub use self::redirect_or_cmd_word::{EvalRedirectOrCmdWord, EvalRedirectOrCmdWordError,
RedirectOrCmdWord, eval_redirects_or_cmd_words,
eval_redirects_or_cmd_words_with_restorer};
#[allow(deprecated)]
pub use self::redirect_or_var_assig::{EvalRedirectOrVarAssig, eval_redirects_or_var_assignments,
eval_redirects_or_var_assignments_with_restorer};
pub use self::redirect_or_var_assig::{EvalRedirectOrVarAssig2, EvalRedirectOrVarAssigError,
RedirectOrVarAssig,
eval_redirects_or_var_assignments_with_restorers};
pub trait ParamEval<E: ?Sized> {
type EvalResult: StringWrapper;
fn eval(&self, split_fields_further: bool, env: &E) -> Option<Fields<Self::EvalResult>>;
fn assig_name(&self) -> Option<Self::EvalResult>;
}
impl<'a, E: ?Sized, P: ?Sized + ParamEval<E>> ParamEval<E> for &'a P {
type EvalResult = P::EvalResult;
fn eval(&self, split_fields_further: bool, env: &E) -> Option<Fields<Self::EvalResult>> {
(**self).eval(split_fields_further, env)
}
fn assig_name(&self) -> Option<Self::EvalResult> {
(**self).assig_name()
}
}
pub trait ArithEval<E: ?Sized> {
fn eval(&self, env: &mut E) -> Result<isize, ExpansionError>;
}
impl<'a, T: ?Sized + ArithEval<E>, E: ?Sized> ArithEval<E> for &'a T {
fn eval(&self, env: &mut E) -> Result<isize, ExpansionError> {
(**self).eval(env)
}
}
#[derive(PartialEq, Eq, Copy, Clone, Debug)]
pub enum TildeExpansion {
None,
First,
All,
}
#[derive(PartialEq, Eq, Copy, Clone, Debug)]
pub struct WordEvalConfig {
pub tilde_expansion: TildeExpansion,
pub split_fields_further: bool,
}
pub trait WordEval<E: ?Sized>: Sized {
type EvalResult: StringWrapper;
type Error;
type EvalFuture: EnvFuture<E, Item = Fields<Self::EvalResult>, Error = Self::Error>;
fn eval(self, env: &E) -> Self::EvalFuture {
self.eval_with_config(env, WordEvalConfig {
tilde_expansion: TildeExpansion::First,
split_fields_further: true,
})
}
fn eval_as_assignment(self, env: &E) -> Assignment<Self::EvalFuture>
where E: VariableEnvironment,
E::VarName: Borrow<String>,
E::Var: Borrow<String>,
{
Assignment {
f: self.eval_with_config(env, WordEvalConfig {
tilde_expansion: TildeExpansion::All,
split_fields_further: false,
}),
}
}
fn eval_as_pattern(self, env: &E) -> Pattern<Self::EvalFuture> {
Pattern {
f: self.eval_with_config(env, WordEvalConfig {
tilde_expansion: TildeExpansion::First,
split_fields_further: false,
}),
}
}
fn eval_with_config(self, env: &E, cfg: WordEvalConfig) -> Self::EvalFuture;
}
impl<E: ?Sized, W: WordEval<E>> WordEval<E> for Box<W> {
type EvalResult = W::EvalResult;
type Error = W::Error;
type EvalFuture = W::EvalFuture;
#[cfg_attr(feature = "clippy", allow(boxed_local))]
fn eval_with_config(self, env: &E, cfg: WordEvalConfig) -> Self::EvalFuture {
(*self).eval_with_config(env, cfg)
}
}
impl<'a, E: ?Sized, W: 'a> WordEval<E> for &'a Box<W>
where &'a W: WordEval<E>,
{
type EvalResult = <&'a W as WordEval<E>>::EvalResult;
type Error = <&'a W as WordEval<E>>::Error;
type EvalFuture = <&'a W as WordEval<E>>::EvalFuture;
#[cfg_attr(feature = "clippy", allow(boxed_local))]
fn eval_with_config(self, env: &E, cfg: WordEvalConfig) -> Self::EvalFuture {
(&**self).eval_with_config(env, cfg)
}
}
#[must_use = "futures do nothing unless polled"]
#[derive(Debug)]
pub struct Assignment<F> {
f: F,
}
impl<E: ?Sized, T, F> EnvFuture<E> for Assignment<F>
where E: VariableEnvironment,
E::VarName: Borrow<String>,
E::Var: Borrow<String>,
T: StringWrapper,
F: EnvFuture<E, Item = Fields<T>>,
{
type Item = T;
type Error = F::Error;
fn poll(&mut self, env: &mut E) -> Poll<Self::Item, Self::Error> {
let ret = match try_ready!(self.f.poll(env)) {
f@Fields::Zero |
f@Fields::Single(_) |
f@Fields::At(_) |
f@Fields::Split(_) => f.join(),
f@Fields::Star(_) => f.join_with_ifs(env),
};
Ok(Async::Ready(ret))
}
fn cancel(&mut self, env: &mut E) {
self.f.cancel(env)
}
}
#[must_use = "futures do nothing unless polled"]
#[derive(Debug)]
pub struct Pattern<F> {
f: F,
}
impl<E: ?Sized, T, F> EnvFuture<E> for Pattern<F>
where F: EnvFuture<E, Item = Fields<T>>,
T: StringWrapper,
{
type Item = glob::Pattern;
type Error = F::Error;
fn poll(&mut self, env: &mut E) -> Poll<Self::Item, Self::Error> {
let pat = try_ready!(self.f.poll(env)).join();
let pat = glob::Pattern::new(pat.as_str())
.or_else(|_| glob::Pattern::new(&glob::Pattern::escape(pat.as_str())));
Ok(Async::Ready(pat.expect("pattern compilation unexpectedly failed")))
}
fn cancel(&mut self, env: &mut E) {
self.f.cancel(env)
}
}