pub(crate) mod baseline_parse; pub(crate) mod binary; pub(crate) mod expand_external_tokens; pub(crate) mod external_command; pub(crate) mod named; pub(crate) mod path; pub(crate) mod syntax_shape; pub(crate) mod tokens_iterator; use crate::parser::{registry, Operator, Unit}; use crate::prelude::*; use derive_new::new; use getset::Getters; use serde::{Deserialize, Serialize}; use std::fmt; use std::path::PathBuf; use crate::evaluate::Scope; use crate::parser::parse::tokens::RawNumber; use crate::traits::ToDebug; pub(crate) use self::binary::Binary; pub(crate) use self::external_command::ExternalCommand; pub(crate) use self::named::NamedArguments; pub(crate) use self::path::Path; pub(crate) use self::syntax_shape::ExpandContext; pub(crate) use self::tokens_iterator::debug::debug_tokens; pub(crate) use self::tokens_iterator::TokensIterator; pub use self::syntax_shape::SyntaxShape; #[derive(Debug, Clone, Eq, PartialEq, Getters, Serialize, Deserialize, new)] pub struct Call { #[get = "pub(crate)"] pub head: Box, #[get = "pub(crate)"] pub positional: Option>, #[get = "pub(crate)"] pub named: Option, } impl Call { pub fn evaluate( &self, registry: ®istry::CommandRegistry, scope: &Scope, source: &Text, ) -> Result { registry::evaluate_args(self, registry, scope, source) } } impl ToDebug for Call { fn fmt_debug(&self, f: &mut fmt::Formatter, source: &str) -> fmt::Result { write!(f, "({}", self.head.debug(source))?; if let Some(positional) = &self.positional { write!(f, " ")?; write!( f, "{}", &itertools::join(positional.iter().map(|p| p.debug(source)), " ") )?; } if let Some(named) = &self.named { write!(f, "{}", named.debug(source))?; } write!(f, ")")?; Ok(()) } } #[derive(Debug, Clone, Eq, PartialEq, Ord, PartialOrd, Hash, Serialize, Deserialize)] pub enum RawExpression { Literal(Literal), ExternalWord, Synthetic(Synthetic), Variable(Variable), Binary(Box), Block(Vec), List(Vec), Path(Box), FilePath(PathBuf), ExternalCommand(ExternalCommand), Command(Span), Boolean(bool), } #[derive(Debug, Clone, Eq, PartialEq, Ord, PartialOrd, Hash, Serialize, Deserialize)] pub enum Synthetic { String(String), } impl Synthetic { pub fn type_name(&self) -> &'static str { match self { Synthetic::String(_) => "string", } } } impl RawExpression { pub fn type_name(&self) -> &'static str { match self { RawExpression::Literal(literal) => literal.type_name(), RawExpression::Synthetic(synthetic) => synthetic.type_name(), RawExpression::Command(..) => "command", RawExpression::ExternalWord => "external word", RawExpression::FilePath(..) => "file path", RawExpression::Variable(..) => "variable", RawExpression::List(..) => "list", RawExpression::Binary(..) => "binary", RawExpression::Block(..) => "block", RawExpression::Path(..) => "variable path", RawExpression::Boolean(..) => "boolean", RawExpression::ExternalCommand(..) => "external", } } } pub type Expression = Spanned; impl std::fmt::Display for Expression { fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result { let span = self.span; match &self.item { RawExpression::Literal(literal) => write!(f, "{}", literal.tagged(self.span)), RawExpression::Synthetic(Synthetic::String(s)) => write!(f, "{}", s), RawExpression::Command(_) => write!(f, "Command{{ {}..{} }}", span.start(), span.end()), RawExpression::ExternalWord => { write!(f, "ExternalWord{{ {}..{} }}", span.start(), span.end()) } RawExpression::FilePath(file) => write!(f, "Path{{ {} }}", file.display()), RawExpression::Variable(variable) => write!(f, "{}", variable), RawExpression::List(list) => f .debug_list() .entries(list.iter().map(|e| format!("{}", e))) .finish(), RawExpression::Binary(binary) => write!(f, "{}", binary), RawExpression::Block(items) => { write!(f, "Block")?; f.debug_set() .entries(items.iter().map(|i| format!("{}", i))) .finish() } RawExpression::Path(path) => write!(f, "{}", path), RawExpression::Boolean(b) => write!(f, "${}", b), RawExpression::ExternalCommand(..) => { write!(f, "ExternalComment{{ {}..{} }}", span.start(), span.end()) } } } } impl Expression { pub(crate) fn number(i: impl Into, span: impl Into) -> Expression { RawExpression::Literal(Literal::Number(i.into())).spanned(span.into()) } pub(crate) fn size( i: impl Into, unit: impl Into, span: impl Into, ) -> Expression { RawExpression::Literal(Literal::Size(i.into(), unit.into())).spanned(span.into()) } pub(crate) fn synthetic_string(s: impl Into) -> Expression { RawExpression::Synthetic(Synthetic::String(s.into())).spanned_unknown() } pub(crate) fn string(inner: impl Into, outer: impl Into) -> Expression { RawExpression::Literal(Literal::String(inner.into())).spanned(outer.into()) } pub(crate) fn path( head: Expression, tail: Vec>>, span: impl Into, ) -> Expression { let tail = tail.into_iter().map(|t| t.map(|s| s.into())).collect(); RawExpression::Path(Box::new(Path::new(head, tail))).spanned(span.into()) } pub(crate) fn dot_member(head: Expression, next: Spanned>) -> Expression { let Spanned { item, span } = head; let new_span = head.span.until(next.span); match item { RawExpression::Path(path) => { let (head, mut tail) = path.parts(); tail.push(next.map(|i| i.into())); Expression::path(head, tail, new_span) } other => Expression::path(other.spanned(span), vec![next], new_span), } } pub(crate) fn infix( left: Expression, op: Spanned>, right: Expression, ) -> Expression { let new_span = left.span.until(right.span); RawExpression::Binary(Box::new(Binary::new(left, op.map(|o| o.into()), right))) .spanned(new_span) } pub(crate) fn file_path(path: impl Into, outer: impl Into) -> Expression { RawExpression::FilePath(path.into()).spanned(outer) } pub(crate) fn list(list: Vec, span: impl Into) -> Expression { RawExpression::List(list).spanned(span) } pub(crate) fn bare(span: impl Into) -> Expression { RawExpression::Literal(Literal::Bare).spanned(span) } pub(crate) fn pattern(inner: impl Into, outer: impl Into) -> Expression { RawExpression::Literal(Literal::GlobPattern(inner.into())).spanned(outer.into()) } pub(crate) fn variable(inner: impl Into, outer: impl Into) -> Expression { RawExpression::Variable(Variable::Other(inner.into())).spanned(outer) } pub(crate) fn external_command(inner: impl Into, outer: impl Into) -> Expression { RawExpression::ExternalCommand(ExternalCommand::new(inner.into())).spanned(outer) } pub(crate) fn it_variable(inner: impl Into, outer: impl Into) -> Expression { RawExpression::Variable(Variable::It(inner.into())).spanned(outer) } } impl ToDebug for Expression { fn fmt_debug(&self, f: &mut fmt::Formatter, source: &str) -> fmt::Result { match &self.item { RawExpression::Literal(l) => l.spanned(self.span).fmt_debug(f, source), RawExpression::FilePath(p) => write!(f, "{}", p.display()), RawExpression::ExternalWord => write!(f, "{}", self.span.slice(source)), RawExpression::Command(tag) => write!(f, "{}", tag.slice(source)), RawExpression::Synthetic(Synthetic::String(s)) => write!(f, "{:?}", s), RawExpression::Variable(Variable::It(_)) => write!(f, "$it"), RawExpression::Variable(Variable::Other(s)) => write!(f, "${}", s.slice(source)), RawExpression::Binary(b) => write!(f, "{}", b.debug(source)), RawExpression::ExternalCommand(c) => write!(f, "^{}", c.name().slice(source)), RawExpression::Block(exprs) => { write!(f, "{{ ")?; for expr in exprs { write!(f, "{} ", expr.debug(source))?; } write!(f, "}}") } RawExpression::List(exprs) => { write!(f, "[ ")?; for expr in exprs { write!(f, "{} ", expr.debug(source))?; } write!(f, "]") } RawExpression::Path(p) => write!(f, "{}", p.debug(source)), RawExpression::Boolean(true) => write!(f, "$yes"), RawExpression::Boolean(false) => write!(f, "$no"), } } } impl From> for Expression { fn from(path: Spanned) -> Expression { path.map(|p| RawExpression::Path(Box::new(p))) } } /// Literals are expressions that are: /// /// 1. Copy /// 2. Can be evaluated without additional context /// 3. Evaluation cannot produce an error #[derive(Debug, Clone, Eq, PartialEq, Ord, PartialOrd, Hash, Serialize, Deserialize)] pub enum Literal { Number(Number), Size(Number, Unit), String(Span), GlobPattern(String), Bare, } impl std::fmt::Display for Tagged { fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result { write!(f, "{}", Tagged::new(self.tag.clone(), &self.item)) } } impl std::fmt::Display for Tagged<&Literal> { fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result { let span = self.tag.span; match &self.item { Literal::Number(number) => write!(f, "{}", number), Literal::Size(number, unit) => write!(f, "{}{}", number, unit.as_str()), Literal::String(_) => write!(f, "String{{ {}..{} }}", span.start(), span.end()), Literal::GlobPattern(_) => write!(f, "Glob{{ {}..{} }}", span.start(), span.end()), Literal::Bare => write!(f, "Bare{{ {}..{} }}", span.start(), span.end()), } } } impl ToDebug for Spanned<&Literal> { fn fmt_debug(&self, f: &mut fmt::Formatter, source: &str) -> fmt::Result { match self.item { Literal::Number(number) => write!(f, "{:?}", number), Literal::Size(number, unit) => write!(f, "{:?}{:?}", *number, unit), Literal::String(tag) => write!(f, "{}", tag.slice(source)), Literal::GlobPattern(_) => write!(f, "{}", self.span.slice(source)), Literal::Bare => write!(f, "{}", self.span.slice(source)), } } } impl Literal { fn type_name(&self) -> &'static str { match self { Literal::Number(..) => "number", Literal::Size(..) => "size", Literal::String(..) => "string", Literal::Bare => "string", Literal::GlobPattern(_) => "pattern", } } } #[derive(Debug, Clone, Eq, PartialEq, Ord, PartialOrd, Hash, Serialize, Deserialize)] pub enum Variable { It(Span), Other(Span), } impl std::fmt::Display for Variable { fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result { match self { Variable::It(_) => write!(f, "$it"), Variable::Other(span) => write!(f, "${{ {}..{} }}", span.start(), span.end()), } } }