forked from extern/nushell
193b00764b
* Moves off of draining between filters. Instead, the sink will pull on the stream, and will drain element-wise. This moves the whole stream to being lazy. * Adds ctrl-c support and connects it into some of the key points where we pull on the stream. If a ctrl-c is detect, we immediately halt pulling on the stream and return to the prompt. * Moves away from having a SourceMap where anchor locations are stored. Now AnchorLocation is kept directly in the Tag. * To make this possible, split tag and span. Span is largely used in the parser and is copyable. Tag is now no longer copyable.
362 lines
12 KiB
Rust
362 lines
12 KiB
Rust
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<Expression>,
|
|
#[get = "pub(crate)"]
|
|
pub positional: Option<Vec<Expression>>,
|
|
#[get = "pub(crate)"]
|
|
pub named: Option<NamedArguments>,
|
|
}
|
|
|
|
impl Call {
|
|
pub fn evaluate(
|
|
&self,
|
|
registry: ®istry::CommandRegistry,
|
|
scope: &Scope,
|
|
source: &Text,
|
|
) -> Result<registry::EvaluatedArgs, ShellError> {
|
|
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<Binary>),
|
|
Block(Vec<Expression>),
|
|
List(Vec<Expression>),
|
|
Path(Box<Path>),
|
|
|
|
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<RawExpression>;
|
|
|
|
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<Number>, span: impl Into<Span>) -> Expression {
|
|
RawExpression::Literal(Literal::Number(i.into())).spanned(span.into())
|
|
}
|
|
|
|
pub(crate) fn size(
|
|
i: impl Into<Number>,
|
|
unit: impl Into<Unit>,
|
|
span: impl Into<Span>,
|
|
) -> Expression {
|
|
RawExpression::Literal(Literal::Size(i.into(), unit.into())).spanned(span.into())
|
|
}
|
|
|
|
pub(crate) fn synthetic_string(s: impl Into<String>) -> Expression {
|
|
RawExpression::Synthetic(Synthetic::String(s.into())).spanned_unknown()
|
|
}
|
|
|
|
pub(crate) fn string(inner: impl Into<Span>, outer: impl Into<Span>) -> Expression {
|
|
RawExpression::Literal(Literal::String(inner.into())).spanned(outer.into())
|
|
}
|
|
|
|
pub(crate) fn path(
|
|
head: Expression,
|
|
tail: Vec<Spanned<impl Into<String>>>,
|
|
span: impl Into<Span>,
|
|
) -> 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<impl Into<String>>) -> 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<impl Into<Operator>>,
|
|
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<PathBuf>, outer: impl Into<Span>) -> Expression {
|
|
RawExpression::FilePath(path.into()).spanned(outer)
|
|
}
|
|
|
|
pub(crate) fn list(list: Vec<Expression>, span: impl Into<Span>) -> Expression {
|
|
RawExpression::List(list).spanned(span)
|
|
}
|
|
|
|
pub(crate) fn bare(span: impl Into<Span>) -> Expression {
|
|
RawExpression::Literal(Literal::Bare).spanned(span)
|
|
}
|
|
|
|
pub(crate) fn pattern(span: impl Into<Span>) -> Expression {
|
|
RawExpression::Literal(Literal::GlobPattern).spanned(span.into())
|
|
}
|
|
|
|
pub(crate) fn variable(inner: impl Into<Span>, outer: impl Into<Span>) -> Expression {
|
|
RawExpression::Variable(Variable::Other(inner.into())).spanned(outer)
|
|
}
|
|
|
|
pub(crate) fn external_command(inner: impl Into<Span>, outer: impl Into<Span>) -> Expression {
|
|
RawExpression::ExternalCommand(ExternalCommand::new(inner.into())).spanned(outer)
|
|
}
|
|
|
|
pub(crate) fn it_variable(inner: impl Into<Span>, outer: impl Into<Span>) -> 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<Spanned<Path>> for Expression {
|
|
fn from(path: Spanned<Path>) -> 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,
|
|
Bare,
|
|
}
|
|
|
|
impl std::fmt::Display for Tagged<Literal> {
|
|
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()),
|
|
}
|
|
}
|
|
}
|