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::hir::path::PathMember; use crate::parser::hir::syntax_shape::Member; use crate::parser::{registry, Operator, Unit}; use crate::prelude::*; use derive_new::new; use getset::Getters; use nu_source::Spanned; use serde::{Deserialize, Serialize}; use std::path::PathBuf; use crate::evaluate::Scope; use crate::parser::parse::tokens::RawNumber; 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::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, pub span: Span, } impl PrettyDebugWithSource for Call { fn pretty_debug(&self, source: &str) -> DebugDocBuilder { b::delimit( "(", self.head.pretty_debug(source) + b::preceded_option( Some(b::space()), self.positional.as_ref().map(|pos| { b::intersperse(pos.iter().map(|expr| expr.pretty_debug(source)), b::space()) }), ) + b::preceded_option( Some(b::space()), self.named.as_ref().map(|named| named.pretty_debug(source)), ), ")", ) } } impl Call { pub fn evaluate( &self, registry: ®istry::CommandRegistry, scope: &Scope, source: &Text, ) -> Result { registry::evaluate_args(self, registry, scope, source) } } #[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), } impl ShellTypeName for RawExpression { 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", } } } #[derive(Debug, Clone, Eq, PartialEq, Ord, PartialOrd, Hash, Serialize, Deserialize)] pub enum Synthetic { String(String), } impl ShellTypeName for Synthetic { fn type_name(&self) -> &'static str { match self { Synthetic::String(_) => "string", } } } impl RawExpression { pub fn into_expr(self, span: impl Into) -> Expression { Expression { expr: self, span: span.into(), } } pub fn into_unspanned_expr(self) -> Expression { Expression { expr: self, span: Span::unknown(), } } } #[derive(Debug, Clone, Eq, PartialEq, Ord, PartialOrd, Hash, Serialize, Deserialize)] pub struct Expression { pub expr: RawExpression, pub span: Span, } impl std::ops::Deref for Expression { type Target = RawExpression; fn deref(&self) -> &RawExpression { &self.expr } } impl HasSpan for Expression { fn span(&self) -> Span { self.span } } impl PrettyDebugWithSource for Expression { fn pretty_debug(&self, source: &str) -> DebugDocBuilder { match &self.expr { RawExpression::Literal(literal) => literal.spanned(self.span).pretty_debug(source), RawExpression::ExternalWord => { b::typed("external word", b::primitive(self.span.slice(source))) } RawExpression::Synthetic(s) => match s { Synthetic::String(s) => b::typed("synthetic", b::primitive(format!("{:?}", s))), }, RawExpression::Variable(_) => b::keyword(self.span.slice(source)), RawExpression::Binary(binary) => binary.pretty_debug(source), RawExpression::Block(_) => b::opaque("block"), RawExpression::List(list) => b::delimit( "[", b::intersperse( list.iter().map(|item| item.pretty_debug(source)), b::space(), ), "]", ), RawExpression::Path(path) => path.pretty_debug(source), RawExpression::FilePath(path) => b::typed("path", b::primitive(path.display())), RawExpression::ExternalCommand(external) => b::typed( "external command", b::primitive(external.name.slice(source)), ), RawExpression::Command(command) => { b::typed("command", b::primitive(command.slice(source))) } RawExpression::Boolean(boolean) => match boolean { true => b::primitive("$yes"), false => b::primitive("$no"), }, } } } impl std::fmt::Display for Expression { fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result { let span = self.span; match &self.expr { RawExpression::Literal(literal) => write!(f, "{:?}", literal), 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 { let span = span.into(); RawExpression::Literal(RawLiteral::Number(i.into()).into_literal(span)).into_expr(span) } pub(crate) fn size( i: impl Into, unit: impl Into, span: impl Into, ) -> Expression { let span = span.into(); RawExpression::Literal(RawLiteral::Size(i.into(), unit.into()).into_literal(span)) .into_expr(span) } pub(crate) fn synthetic_string(s: impl Into) -> Expression { RawExpression::Synthetic(Synthetic::String(s.into())).into_unspanned_expr() } pub(crate) fn string(inner: impl Into, outer: impl Into) -> Expression { let outer = outer.into(); RawExpression::Literal(RawLiteral::String(inner.into()).into_literal(outer)) .into_expr(outer) } pub(crate) fn column_path(members: Vec, span: impl Into) -> Expression { let span = span.into(); RawExpression::Literal(RawLiteral::ColumnPath(members).into_literal(span)).into_expr(span) } pub(crate) fn path( head: Expression, tail: Vec>, span: impl Into, ) -> Expression { let tail = tail.into_iter().map(|t| t.into()).collect(); RawExpression::Path(Box::new(Path::new(head, tail))).into_expr(span.into()) } pub(crate) fn dot_member(head: Expression, next: impl Into) -> Expression { let Expression { expr: item, span } = head; let next = next.into(); let new_span = head.span.until(next.span); match item { RawExpression::Path(path) => { let (head, mut tail) = path.parts(); tail.push(next); Expression::path(head, tail, new_span) } other => Expression::path(other.into_expr(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))) .into_expr(new_span) } pub(crate) fn file_path(path: impl Into, outer: impl Into) -> Expression { RawExpression::FilePath(path.into()).into_expr(outer) } pub(crate) fn list(list: Vec, span: impl Into) -> Expression { RawExpression::List(list).into_expr(span) } pub(crate) fn bare(span: impl Into) -> Expression { let span = span.into(); RawExpression::Literal(RawLiteral::Bare.into_literal(span)).into_expr(span) } pub(crate) fn pattern(inner: impl Into, outer: impl Into) -> Expression { let outer = outer.into(); RawExpression::Literal(RawLiteral::GlobPattern(inner.into()).into_literal(outer)) .into_expr(outer) } pub(crate) fn variable(inner: impl Into, outer: impl Into) -> Expression { RawExpression::Variable(Variable::Other(inner.into())).into_expr(outer) } pub(crate) fn external_command(inner: impl Into, outer: impl Into) -> Expression { RawExpression::ExternalCommand(ExternalCommand::new(inner.into())).into_expr(outer) } pub(crate) fn it_variable(inner: impl Into, outer: impl Into) -> Expression { RawExpression::Variable(Variable::It(inner.into())).into_expr(outer) } } impl From> for Expression { fn from(path: Spanned) -> Expression { RawExpression::Path(Box::new(path.item)).into_expr(path.span) } } /// 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 RawLiteral { Number(Number), Size(Number, Unit), String(Span), GlobPattern(String), ColumnPath(Vec), Bare, } impl RawLiteral { pub fn into_literal(self, span: impl Into) -> Literal { Literal { literal: self, span: span.into(), } } } #[derive(Debug, Clone, Eq, PartialEq, Ord, PartialOrd, Hash, Serialize, Deserialize)] pub struct Literal { pub literal: RawLiteral, pub span: Span, } impl ShellTypeName for Literal { fn type_name(&self) -> &'static str { match &self.literal { RawLiteral::Number(..) => "number", RawLiteral::Size(..) => "size", RawLiteral::String(..) => "string", RawLiteral::ColumnPath(..) => "column path", RawLiteral::Bare => "string", RawLiteral::GlobPattern(_) => "pattern", } } } impl PrettyDebugWithSource for Literal { fn pretty_debug(&self, source: &str) -> DebugDocBuilder { match &self.literal { RawLiteral::Number(number) => number.pretty(), RawLiteral::Size(number, unit) => (number.pretty() + unit.pretty()).group(), RawLiteral::String(string) => b::primitive(format!("{:?}", string.slice(source))), RawLiteral::GlobPattern(pattern) => b::typed("pattern", b::primitive(pattern)), RawLiteral::ColumnPath(path) => b::typed( "column path", b::intersperse_with_source(path.iter(), b::space(), source), ), RawLiteral::Bare => b::primitive(self.span.slice(source)), } } } #[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()), } } }