Support evaluating most expressions

Blocks, paths, and others

Plus a bunch of other infra improvements
This commit is contained in:
Yehuda Katz 2019-06-29 01:55:42 -07:00
parent 7074d3ffcc
commit 3379c23a49
13 changed files with 497 additions and 150 deletions

View file

@ -1,5 +1,3 @@
cargo-features = ["default-run"]
[package] [package]
name = "nu" name = "nu"
version = "0.1.2" version = "0.1.2"

View file

@ -1,12 +1,9 @@
use crate::errors::ShellError; use crate::errors::ShellError;
use crate::parser::registry::{CommandConfig, PositionalType};
use crate::parser::Spanned;
use crate::prelude::*; use crate::prelude::*;
use serde::{self, Deserialize, Serialize}; use serde::{self, Deserialize, Serialize};
use std::io::prelude::*; use std::io::prelude::*;
use std::io::BufReader; use std::io::BufReader;
use std::io::{Read, Write}; use std::io::Write;
use subprocess::Exec;
#[derive(Debug, Serialize, Deserialize)] #[derive(Debug, Serialize, Deserialize)]
pub struct JsonRpc<T> { pub struct JsonRpc<T> {
@ -14,6 +11,7 @@ pub struct JsonRpc<T> {
pub method: String, pub method: String,
pub params: T, pub params: T,
} }
impl<T> JsonRpc<T> { impl<T> JsonRpc<T> {
pub fn new<U: Into<String>>(method: U, params: T) -> Self { pub fn new<U: Into<String>>(method: U, params: T) -> Self {
JsonRpc { JsonRpc {
@ -50,15 +48,16 @@ pub fn plugin(plugin_name: String, args: CommandArgs) -> Result<OutputStream, Sh
.expect("Failed to spawn child process"); .expect("Failed to spawn child process");
{ {
let mut stdin = child.stdin.as_mut().expect("Failed to open stdin"); let stdin = child.stdin.as_mut().expect("Failed to open stdin");
let mut stdout = child.stdout.as_mut().expect("Failed to open stdout"); let stdout = child.stdout.as_mut().expect("Failed to open stdout");
let mut reader = BufReader::new(stdout); let _reader = BufReader::new(stdout);
let request = JsonRpc::new("init", args.clone()); let request = JsonRpc::new("init", args.clone());
let request_raw = serde_json::to_string(&request).unwrap(); let request_raw = serde_json::to_string(&request).unwrap();
stdin.write(format!("{}\n", request_raw).as_bytes()); stdin.write(format!("{}\n", request_raw).as_bytes())?;
} }
let mut eos = VecDeque::new(); let mut eos = VecDeque::new();
eos.push_back(Value::Primitive(Primitive::EndOfStream)); eos.push_back(Value::Primitive(Primitive::EndOfStream));
@ -66,25 +65,25 @@ pub fn plugin(plugin_name: String, args: CommandArgs) -> Result<OutputStream, Sh
.chain(eos) .chain(eos)
.map(move |v| match v { .map(move |v| match v {
Value::Primitive(Primitive::EndOfStream) => { Value::Primitive(Primitive::EndOfStream) => {
let mut stdin = child.stdin.as_mut().expect("Failed to open stdin"); let stdin = child.stdin.as_mut().expect("Failed to open stdin");
let mut stdout = child.stdout.as_mut().expect("Failed to open stdout"); let stdout = child.stdout.as_mut().expect("Failed to open stdout");
let mut reader = BufReader::new(stdout); let _ = BufReader::new(stdout);
let request: JsonRpc<std::vec::Vec<Value>> = JsonRpc::new("quit", vec![]); let request: JsonRpc<std::vec::Vec<Value>> = JsonRpc::new("quit", vec![]);
let request_raw = serde_json::to_string(&request).unwrap(); let request_raw = serde_json::to_string(&request).unwrap();
stdin.write(format!("{}\n", request_raw).as_bytes()); let _ = stdin.write(format!("{}\n", request_raw).as_bytes()); // TODO: Handle error
VecDeque::new() VecDeque::new()
} }
_ => { _ => {
let mut stdin = child.stdin.as_mut().expect("Failed to open stdin"); let stdin = child.stdin.as_mut().expect("Failed to open stdin");
let mut stdout = child.stdout.as_mut().expect("Failed to open stdout"); let stdout = child.stdout.as_mut().expect("Failed to open stdout");
let mut reader = BufReader::new(stdout); let mut reader = BufReader::new(stdout);
let request = JsonRpc::new("filter", v); let request = JsonRpc::new("filter", v);
let request_raw = serde_json::to_string(&request).unwrap(); let request_raw = serde_json::to_string(&request).unwrap();
stdin.write(format!("{}\n", request_raw).as_bytes()); let _ = stdin.write(format!("{}\n", request_raw).as_bytes()); // TODO: Handle error
let mut input = String::new(); let mut input = String::new();
match reader.read_line(&mut input) { match reader.read_line(&mut input) {
@ -101,7 +100,7 @@ pub fn plugin(plugin_name: String, args: CommandArgs) -> Result<OutputStream, Sh
} }
} }
} }
Err(x) => { Err(_) => {
let mut result = VecDeque::new(); let mut result = VecDeque::new();
result.push_back(ReturnValue::Value(Value::Error(Box::new( result.push_back(ReturnValue::Value(Value::Error(Box::new(
ShellError::string("Error while processing input"), ShellError::string("Error while processing input"),

View file

@ -36,7 +36,10 @@ impl Description {
#[derive(Debug, Eq, PartialEq, Clone, Ord, PartialOrd, Serialize, Deserialize)] #[derive(Debug, Eq, PartialEq, Clone, Ord, PartialOrd, Serialize, Deserialize)]
pub enum ShellError { pub enum ShellError {
String(StringError), String(StringError),
TypeError(Spanned<String>), TypeError {
expected: String,
actual: Spanned<Option<String>>,
},
MissingProperty { MissingProperty {
subpath: Description, subpath: Description,
expr: Description, expr: Description,
@ -49,6 +52,16 @@ pub enum ShellError {
} }
impl ShellError { impl ShellError {
crate fn type_error(
expected: impl Into<String>,
actual: Spanned<impl Into<String>>,
) -> ShellError {
ShellError::TypeError {
expected: expected.into(),
actual: actual.map(|i| Some(i.into())),
}
}
crate fn parse_error( crate fn parse_error(
error: nom::Err<(nom_locate::LocatedSpan<&str>, nom::error::ErrorKind)>, error: nom::Err<(nom_locate::LocatedSpan<&str>, nom::error::ErrorKind)>,
) -> ShellError { ) -> ShellError {
@ -57,9 +70,8 @@ impl ShellError {
match error { match error {
nom::Err::Incomplete(_) => unreachable!(), nom::Err::Incomplete(_) => unreachable!(),
nom::Err::Failure(span) | nom::Err::Error(span) => { nom::Err::Failure(span) | nom::Err::Error(span) => {
let diagnostic = let diagnostic = Diagnostic::new(Severity::Error, format!("Parse Error"))
Diagnostic::new(Severity::Error, format!("Parse Error")) .with_label(Label::new_primary(Span::from(span.0)));
.with_label(Label::new_primary(Span::from(span.0)));
ShellError::diagnostic(diagnostic) ShellError::diagnostic(diagnostic)
// nom::Context::Code(span, kind) => { // nom::Context::Code(span, kind) => {
@ -69,21 +81,20 @@ impl ShellError {
// ShellError::diagnostic(diagnostic) // ShellError::diagnostic(diagnostic)
// } // }
} } // ParseError::UnrecognizedToken {
// ParseError::UnrecognizedToken { // token: (start, SpannedToken { token, .. }, end),
// token: (start, SpannedToken { token, .. }, end), // expected,
// expected, // } => {
// } => { // let diagnostic = Diagnostic::new(
// let diagnostic = Diagnostic::new( // Severity::Error,
// Severity::Error, // format!("Unexpected {:?}, expected {:?}", token, expected),
// format!("Unexpected {:?}, expected {:?}", token, expected), // )
// ) // .with_label(Label::new_primary(Span::from((start, end))));
// .with_label(Label::new_primary(Span::from((start, end))));
// ShellError::diagnostic(diagnostic) // ShellError::diagnostic(diagnostic)
// } // }
// ParseError::User { error } => error, // ParseError::User { error } => error,
// other => ShellError::string(format!("{:?}", other)), // other => ShellError::string(format!("{:?}", other)),
} }
} }
@ -96,8 +107,23 @@ impl ShellError {
ShellError::String(StringError { title, .. }) => { ShellError::String(StringError { title, .. }) => {
Diagnostic::new(Severity::Error, title) Diagnostic::new(Severity::Error, title)
} }
ShellError::TypeError(s) => Diagnostic::new(Severity::Error, "Type Error") ShellError::TypeError {
.with_label(Label::new_primary(s.span).with_message(s.item)), expected,
actual:
Spanned {
item: Some(actual),
span,
},
} => Diagnostic::new(Severity::Error, "Type Error").with_label(
Label::new_primary(span)
.with_message(format!("Expected {}, found {}", expected, actual)),
),
ShellError::TypeError {
expected,
actual: Spanned { item: None, span },
} => Diagnostic::new(Severity::Error, "Type Error")
.with_label(Label::new_primary(span).with_message(expected)),
ShellError::MissingProperty { subpath, expr } => { ShellError::MissingProperty { subpath, expr } => {
let subpath = subpath.into_label(); let subpath = subpath.into_label();

View file

@ -46,8 +46,8 @@ crate fn evaluate_baseline_expr(
} }
} }
RawExpression::Block(block) => Ok(Spanned::from_item( RawExpression::Block(block) => Ok(Spanned::from_item(
Value::Block(Block::new(*block.clone(), source.clone())), Value::Block(Block::new(block.clone(), source.clone(), *expr.span())),
block.span(), expr.span(),
)), )),
RawExpression::Path(path) => { RawExpression::Path(path) => {
let value = evaluate_baseline_expr(path.head(), registry, scope, source)?; let value = evaluate_baseline_expr(path.head(), registry, scope, source)?;

View file

@ -3,6 +3,7 @@
#![feature(async_await)] #![feature(async_await)]
#![feature(try_trait)] #![feature(try_trait)]
#![feature(bind_by_move_pattern_guards)] #![feature(bind_by_move_pattern_guards)]
#![feature(box_syntax)]
mod cli; mod cli;
mod commands; mod commands;
@ -19,6 +20,7 @@ mod shell;
mod stream; mod stream;
pub use crate::commands::command::ReturnValue; pub use crate::commands::command::ReturnValue;
pub use crate::parser::parse::span::SpannedItem;
pub use crate::parser::Spanned; pub use crate::parser::Spanned;
pub use cli::cli; pub use cli::cli;
pub use errors::ShellError; pub use errors::ShellError;

View file

@ -1,7 +1,7 @@
use crate::errors::ShellError; use crate::errors::ShellError;
use crate::evaluate::{evaluate_baseline_expr, Scope}; use crate::evaluate::{evaluate_baseline_expr, Scope};
use crate::object::DataDescriptor; use crate::object::DataDescriptor;
use crate::parser::{hir, Operator, Spanned}; use crate::parser::{hir, Operator, Span, Spanned};
use crate::prelude::*; use crate::prelude::*;
use crate::Text; use crate::Text;
use ansi_term::Color; use ansi_term::Color;
@ -9,7 +9,7 @@ use chrono::{DateTime, Utc};
use chrono_humanize::Humanize; use chrono_humanize::Humanize;
use derive_new::new; use derive_new::new;
use ordered_float::OrderedFloat; use ordered_float::OrderedFloat;
use serde::{Deserialize, Deserializer, Serialize, Serializer}; use serde::{ser::SerializeSeq, Deserialize, Deserializer, Serialize, Serializer};
use std::fmt; use std::fmt;
use std::time::SystemTime; use std::time::SystemTime;
@ -137,8 +137,9 @@ pub struct Operation {
#[derive(Debug, Ord, PartialOrd, Eq, PartialEq, Clone, new)] #[derive(Debug, Ord, PartialOrd, Eq, PartialEq, Clone, new)]
pub struct Block { pub struct Block {
crate expression: hir::Expression, crate expressions: Vec<hir::Expression>,
crate source: Text, crate source: Text,
crate span: Span,
} }
impl Serialize for Block { impl Serialize for Block {
@ -146,7 +147,18 @@ impl Serialize for Block {
where where
S: Serializer, S: Serializer,
{ {
serializer.serialize_str(&self.expression.source(&self.source.clone())) let mut seq = serializer.serialize_seq(None)?;
let list = self
.expressions
.iter()
.map(|e| e.source(&self.source.clone()));
for item in list {
seq.serialize_element(item.as_ref())?;
}
seq.end()
} }
} }
@ -167,7 +179,18 @@ impl Deserialize<'de> for Block {
impl Block { impl Block {
pub fn invoke(&self, value: &Value) -> Result<Spanned<Value>, ShellError> { pub fn invoke(&self, value: &Value) -> Result<Spanned<Value>, ShellError> {
let scope = Scope::new(value.copy()); let scope = Scope::new(value.copy());
evaluate_baseline_expr(&self.expression, &(), &scope, &self.source)
if self.expressions.len() == 0 {
return Ok(Spanned::from_item(Value::nothing(), self.span));
}
let mut last = None;
for expr in self.expressions.iter() {
last = Some(evaluate_baseline_expr(&expr, &(), &scope, &self.source)?)
}
Ok(last.unwrap())
} }
} }
@ -305,7 +328,12 @@ impl Value {
crate fn format_leaf(&self, desc: Option<&DataDescriptor>) -> String { crate fn format_leaf(&self, desc: Option<&DataDescriptor>) -> String {
match self { match self {
Value::Primitive(p) => p.format(desc), Value::Primitive(p) => p.format(desc),
Value::Block(b) => b.expression.source(&b.source).to_string(), Value::Block(b) => itertools::join(
b.expressions
.iter()
.map(|e| e.source(&b.source).to_string()),
"; ",
),
Value::Object(_) => format!("[object Object]"), Value::Object(_) => format!("[object Object]"),
Value::List(_) => format!("[list List]"), Value::List(_) => format!("[list List]"),
Value::Error(e) => format!("{}", e), Value::Error(e) => format!("{}", e),
@ -403,11 +431,6 @@ impl Value {
} }
} }
#[allow(unused)]
pub fn block(e: hir::Expression, source: Text) -> Value {
Value::Block(Block::new(e, source))
}
pub fn string(s: impl Into<String>) -> Value { pub fn string(s: impl Into<String>) -> Value {
Value::Primitive(Primitive::String(s.into())) Value::Primitive(Primitive::String(s.into()))
} }

View file

@ -5,7 +5,7 @@ crate mod registry;
use crate::errors::ShellError; use crate::errors::ShellError;
crate use hir::baseline_parse_tokens::baseline_parse_tokens; crate use hir::baseline_parse_tokens::{baseline_parse_tokens, trace_remaining};
crate use parse::call_node::CallNode; crate use parse::call_node::CallNode;
crate use parse::files::Files; crate use parse::files::Files;
crate use parse::flag::Flag; crate use parse::flag::Flag;
@ -14,7 +14,7 @@ crate use parse::parser::{nom_input, pipeline};
crate use parse::pipeline::{Pipeline, PipelineElement}; crate use parse::pipeline::{Pipeline, PipelineElement};
pub use parse::span::{Span, Spanned}; pub use parse::span::{Span, Spanned};
crate use parse::text::Text; crate use parse::text::Text;
crate use parse::token_tree::TokenNode; crate use parse::token_tree::{DelimitedNode, Delimiter, PathNode, TokenNode};
crate use parse::tokens::{RawToken, Token}; crate use parse::tokens::{RawToken, Token};
crate use parse::unit::Unit; crate use parse::unit::Unit;
crate use parse_command::parse_command; crate use parse_command::parse_command;

View file

@ -9,11 +9,20 @@ use derive_new::new;
use getset::Getters; use getset::Getters;
crate use baseline_parse::baseline_parse_single_token; crate use baseline_parse::baseline_parse_single_token;
crate use baseline_parse_tokens::{baseline_parse_next_expr, ExpressionKindHint}; crate use baseline_parse_tokens::{baseline_parse_next_expr, ExpressionKindHint, TokensIterator};
crate use binary::Binary; crate use binary::Binary;
crate use named::NamedArguments; crate use named::NamedArguments;
crate use path::Path; crate use path::Path;
pub fn path(head: impl Into<Expression>, tail: Vec<Spanned<impl Into<String>>>) -> Path {
Path::new(
head.into(),
tail.into_iter()
.map(|item| item.map(|string| string.into()))
.collect(),
)
}
#[derive(Debug, Clone, Eq, PartialEq, Getters, new)] #[derive(Debug, Clone, Eq, PartialEq, Getters, new)]
pub struct Call { pub struct Call {
#[get = "crate"] #[get = "crate"]
@ -29,7 +38,7 @@ pub enum RawExpression {
Literal(Literal), Literal(Literal),
Variable(Variable), Variable(Variable),
Binary(Box<Binary>), Binary(Box<Binary>),
Block(Box<Expression>), Block(Vec<Expression>),
Path(Box<Path>), Path(Box<Path>),
#[allow(unused)] #[allow(unused)]
@ -76,6 +85,12 @@ impl Expression {
} }
} }
impl From<Spanned<Path>> for Expression {
fn from(path: Spanned<Path>) -> Expression {
path.map(|p| RawExpression::Path(Box::new(p)))
}
}
#[derive(Debug, Clone, Copy, Eq, PartialEq, Ord, PartialOrd, Hash)] #[derive(Debug, Clone, Copy, Eq, PartialEq, Ord, PartialOrd, Hash)]
pub enum Literal { pub enum Literal {
Integer(i64), Integer(i64),

View file

@ -1,24 +1,27 @@
use crate::errors::ShellError; use crate::errors::ShellError;
use crate::parser::registry::CommandRegistry; use crate::parser::registry::CommandRegistry;
use crate::parser::{hir, hir::baseline_parse_single_token, Span, Spanned, TokenNode}; use crate::parser::{
use crate::Text; hir, hir::baseline_parse_single_token, DelimitedNode, Delimiter, PathNode, RawToken, Span,
Spanned, TokenNode,
};
use crate::{SpannedItem, Text};
use derive_new::new;
use log::trace;
pub fn baseline_parse_tokens( pub fn baseline_parse_tokens(
token_nodes: &[TokenNode], token_nodes: &mut TokensIterator<'_>,
registry: &dyn CommandRegistry, registry: &dyn CommandRegistry,
source: &Text, source: &Text,
) -> Result<Vec<hir::Expression>, ShellError> { ) -> Result<Vec<hir::Expression>, ShellError> {
let mut exprs: Vec<hir::Expression> = vec![]; let mut exprs: Vec<hir::Expression> = vec![];
let mut rest = token_nodes;
loop { loop {
if rest.len() == 0 { if token_nodes.at_end() {
break; break;
} }
let (expr, remainder) = baseline_parse_next_expr(rest, registry, source, None)?; let expr = baseline_parse_next_expr(token_nodes, registry, source, None)?;
exprs.push(expr); exprs.push(expr);
rest = remainder;
} }
Ok(exprs) Ok(exprs)
@ -35,25 +38,21 @@ pub enum ExpressionKindHint {
} }
pub fn baseline_parse_next_expr( pub fn baseline_parse_next_expr(
token_nodes: &'nodes [TokenNode], tokens: &mut TokensIterator,
_registry: &dyn CommandRegistry, registry: &dyn CommandRegistry,
source: &Text, source: &Text,
coerce_hint: Option<ExpressionKindHint>, coerce_hint: Option<ExpressionKindHint>,
) -> Result<(hir::Expression, &'nodes [TokenNode]), ShellError> { ) -> Result<hir::Expression, ShellError> {
let mut tokens = token_nodes.iter().peekable(); let first = match tokens.next() {
let first = next_token(&mut tokens);
let first = match first {
None => return Err(ShellError::string("Expected token, found none")), None => return Err(ShellError::string("Expected token, found none")),
Some(token) => baseline_parse_semantic_token(token, source)?, Some(token) => baseline_parse_semantic_token(token, registry, source)?,
}; };
let possible_op = tokens.peek(); let possible_op = tokens.peek();
let op = match possible_op { let op = match possible_op {
Some(TokenNode::Operator(op)) => op, Some(TokenNode::Operator(op)) => op.clone(),
_ => return Ok((first, &token_nodes[1..])), _ => return Ok(first),
}; };
tokens.next(); tokens.next();
@ -64,7 +63,7 @@ pub fn baseline_parse_next_expr(
"Expected op followed by another expr, found nothing", "Expected op followed by another expr, found nothing",
)) ))
} }
Some(token) => baseline_parse_semantic_token(token, source)?, Some(token) => baseline_parse_semantic_token(token, registry, source)?,
}; };
// We definitely have a binary expression here -- let's see if we should coerce it into a block // We definitely have a binary expression here -- let's see if we should coerce it into a block
@ -72,11 +71,11 @@ pub fn baseline_parse_next_expr(
match coerce_hint { match coerce_hint {
None => { None => {
let span = (first.span.start, second.span.end); let span = (first.span.start, second.span.end);
let binary = hir::Binary::new(first, *op, second); let binary = hir::Binary::new(first, op, second);
let binary = hir::RawExpression::Binary(Box::new(binary)); let binary = hir::RawExpression::Binary(Box::new(binary));
let binary = Spanned::from_item(binary, span); let binary = Spanned::from_item(binary, span);
Ok((binary, &token_nodes[3..])) Ok(binary)
} }
Some(hint) => match hint { Some(hint) => match hint {
@ -133,14 +132,14 @@ pub fn baseline_parse_next_expr(
} }
}; };
let binary = hir::Binary::new(path, *op, second); let binary = hir::Binary::new(path, op, second);
let binary = hir::RawExpression::Binary(Box::new(binary)); let binary = hir::RawExpression::Binary(Box::new(binary));
let binary = Spanned::from_item(binary, span); let binary = Spanned::from_item(binary, span);
let block = hir::RawExpression::Block(Box::new(binary)); let block = hir::RawExpression::Block(vec![binary]);
let block = Spanned::from_item(block, span); let block = Spanned::from_item(block, span);
Ok((block, &token_nodes[3..])) Ok(block)
} }
other => unimplemented!("coerce hint {:?}", other), other => unimplemented!("coerce hint {:?}", other),
@ -150,27 +149,199 @@ pub fn baseline_parse_next_expr(
pub fn baseline_parse_semantic_token( pub fn baseline_parse_semantic_token(
token: &TokenNode, token: &TokenNode,
registry: &dyn CommandRegistry,
source: &Text, source: &Text,
) -> Result<hir::Expression, ShellError> { ) -> Result<hir::Expression, ShellError> {
match token { match token {
TokenNode::Token(token) => Ok(baseline_parse_single_token(token, source)), TokenNode::Token(token) => Ok(baseline_parse_single_token(token, source)),
TokenNode::Call(_call) => unimplemented!(), TokenNode::Call(_call) => unimplemented!(),
TokenNode::Delimited(_delimited) => unimplemented!(), TokenNode::Delimited(delimited) => baseline_parse_delimited(delimited, registry, source),
TokenNode::Pipeline(_pipeline) => unimplemented!(), TokenNode::Pipeline(_pipeline) => unimplemented!(),
TokenNode::Operator(_op) => unreachable!(), TokenNode::Operator(_op) => unreachable!(),
TokenNode::Flag(_flag) => unimplemented!(), TokenNode::Flag(_flag) => unimplemented!(),
TokenNode::Identifier(_span) => unreachable!(), TokenNode::Identifier(_span) => unreachable!(),
TokenNode::Whitespace(_span) => unreachable!(), TokenNode::Whitespace(_span) => unreachable!(),
TokenNode::Error(error) => Err(*error.item.clone()), TokenNode::Error(error) => Err(*error.item.clone()),
TokenNode::Path(_path) => unimplemented!(), TokenNode::Path(path) => baseline_parse_path(path, registry, source),
} }
} }
fn next_token(nodes: &mut impl Iterator<Item = &'a TokenNode>) -> Option<&'a TokenNode> { pub fn baseline_parse_delimited(
loop { token: &Spanned<DelimitedNode>,
match nodes.next() { registry: &dyn CommandRegistry,
Some(TokenNode::Whitespace(_)) => continue, source: &Text,
other => return other, ) -> Result<hir::Expression, ShellError> {
match token.delimiter() {
Delimiter::Brace => {
let children = token.children();
let exprs =
baseline_parse_tokens(&mut TokensIterator::new(children), registry, source)?;
let expr = hir::RawExpression::Block(exprs);
Ok(Spanned::from_item(expr, token.span()))
}
Delimiter::Paren => unimplemented!(),
Delimiter::Square => unimplemented!(),
}
}
pub fn baseline_parse_path(
token: &Spanned<PathNode>,
registry: &dyn CommandRegistry,
source: &Text,
) -> Result<hir::Expression, ShellError> {
let head = baseline_parse_semantic_token(token.head(), registry, source)?;
let mut tail = vec![];
for part in token.tail() {
let string = match part {
TokenNode::Token(token) => match token.item() {
RawToken::Bare => token.span().slice(source),
RawToken::String(span) => span.slice(source),
RawToken::Integer(_) | RawToken::Size(..) | RawToken::Variable(_) => {
return Err(ShellError::type_error(
"String",
token.type_name().spanned(part),
))
}
},
TokenNode::Identifier(span) => span.slice(source),
// TODO: Make this impossible
other => unreachable!("{:?}", other),
}
.to_string();
tail.push(string.spanned(part));
}
Ok(hir::path(head, tail).spanned(token).into())
}
#[derive(Debug, new)]
pub struct TokensIterator<'a> {
tokens: &'a [TokenNode],
#[new(default)]
index: usize,
#[new(default)]
seen: indexmap::IndexSet<usize>,
}
impl TokensIterator<'a> {
pub fn remove(&mut self, position: usize) {
self.seen.insert(position);
}
pub fn len(&self) -> usize {
self.tokens.len()
}
pub fn at_end(&self) -> bool {
for index in self.index..self.tokens.len() {
if !self.seen.contains(&index) {
return false;
}
}
true
}
pub fn advance(&mut self) {
self.seen.insert(self.index);
self.index += 1;
}
pub fn extract<T>(&mut self, f: impl Fn(&TokenNode) -> Option<T>) -> Option<(usize, T)> {
for (i, item) in self.tokens.iter().enumerate() {
if self.seen.contains(&i) {
continue;
}
match f(item) {
None => {
continue;
}
Some(value) => {
self.seen.insert(i);
return Some((i, value));
}
}
}
None
}
pub fn move_to(&mut self, pos: usize) {
self.index = pos;
}
pub fn restart(&mut self) {
self.index = 0;
}
pub fn clone(&self) -> TokensIterator {
TokensIterator {
tokens: self.tokens,
index: self.index,
seen: self.seen.clone(),
}
}
pub fn peek(&self) -> Option<&TokenNode> {
let mut tokens = self.clone();
tokens.next()
}
pub fn debug_remaining(&self) -> Vec<TokenNode> {
let mut tokens = self.clone();
tokens.restart();
tokens.cloned().collect()
}
}
impl Iterator for TokensIterator<'a> {
type Item = &'a TokenNode;
fn next(&mut self) -> Option<&'a TokenNode> {
loop {
if self.index >= self.tokens.len() {
return None;
}
if self.seen.contains(&self.index) {
self.advance();
continue;
}
if self.index >= self.tokens.len() {
return None;
}
match &self.tokens[self.index] {
TokenNode::Whitespace(_) => {
self.advance();
}
other => {
self.advance();
return Some(other);
}
}
} }
} }
} }
pub fn trace_remaining(desc: &'static str, tail: hir::TokensIterator<'a>, source: &Text) {
trace!(
"{} = {:?}",
desc,
itertools::join(
tail.debug_remaining()
.iter()
.map(|i| format!("%{:?}%", i.debug(source))),
" "
)
);
}

View file

@ -12,6 +12,14 @@ pub struct Spanned<T> {
pub item: T, pub item: T,
} }
pub trait SpannedItem: Sized {
fn spanned(self, span: impl Into<Span>) -> Spanned<Self> {
Spanned::from_item(self, span.into())
}
}
impl<T> SpannedItem for T {}
impl<T> std::ops::Deref for Spanned<T> { impl<T> std::ops::Deref for Spanned<T> {
type Target = T; type Target = T;
@ -56,6 +64,12 @@ pub struct Span {
// source: &'source str, // source: &'source str,
} }
impl<T> From<&Spanned<T>> for Span {
fn from(input: &Spanned<T>) -> Span {
input.span
}
}
impl From<&Span> for Span { impl From<&Span> for Span {
fn from(input: &Span) -> Span { fn from(input: &Span) -> Span {
*input *input

View file

@ -3,6 +3,8 @@ use crate::parser::parse::{call_node::*, flag::*, operator::*, pipeline::*, span
use crate::Text; use crate::Text;
use derive_new::new; use derive_new::new;
use enum_utils::FromStr; use enum_utils::FromStr;
use getset::Getters;
use std::fmt;
#[derive(Debug, Clone, Eq, PartialEq, Ord, PartialOrd)] #[derive(Debug, Clone, Eq, PartialEq, Ord, PartialOrd)]
pub enum TokenNode { pub enum TokenNode {
@ -20,6 +22,67 @@ pub enum TokenNode {
Path(Spanned<PathNode>), Path(Spanned<PathNode>),
} }
pub struct DebugTokenNode<'a> {
node: &'a TokenNode,
source: &'a Text,
}
impl fmt::Debug for DebugTokenNode<'a> {
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
match self.node {
TokenNode::Token(t) => write!(f, "{:?}", t.debug(self.source)),
TokenNode::Call(s) => {
write!(f, "(")?;
write!(f, "{:?}", s.head().debug(self.source))?;
if let Some(children) = s.children() {
for child in children {
write!(f, "{:?}", child.debug(self.source))?;
}
}
write!(f, ")")
}
TokenNode::Delimited(d) => {
write!(
f,
"{}",
match d.delimiter {
Delimiter::Brace => "{",
Delimiter::Paren => "(",
Delimiter::Square => "[",
}
)?;
for child in d.children() {
write!(f, "{:?}", child.debug(self.source))?;
}
write!(
f,
"{}",
match d.delimiter {
Delimiter::Brace => "}",
Delimiter::Paren => ")",
Delimiter::Square => "]",
}
)
}
TokenNode::Pipeline(s) => write!(f, "<todo:pipeline>"),
TokenNode::Error(s) => write!(f, "<error> for {:?}", s.span().slice(self.source)),
rest => write!(f, "{}", rest.span().slice(self.source)),
}
}
}
impl From<&TokenNode> for Span {
fn from(token: &TokenNode) -> Span {
token.span()
}
}
impl TokenNode { impl TokenNode {
pub fn span(&self) -> Span { pub fn span(&self) -> Span {
match self { match self {
@ -36,6 +99,10 @@ impl TokenNode {
} }
} }
pub fn debug(&'a self, source: &'a Text) -> DebugTokenNode<'a> {
DebugTokenNode { node: self, source }
}
pub fn as_external_arg(&self, source: &Text) -> String { pub fn as_external_arg(&self, source: &Text) -> String {
self.span().slice(source).to_string() self.span().slice(source).to_string()
} }
@ -73,7 +140,8 @@ impl TokenNode {
} }
} }
#[derive(Debug, Clone, Eq, PartialEq, Ord, PartialOrd, new)] #[derive(Debug, Clone, Eq, PartialEq, Ord, PartialOrd, Getters, new)]
#[get = "crate"]
pub struct DelimitedNode { pub struct DelimitedNode {
delimiter: Delimiter, delimiter: Delimiter,
children: Vec<TokenNode>, children: Vec<TokenNode>,
@ -86,7 +154,8 @@ pub enum Delimiter {
Square, Square,
} }
#[derive(Debug, Clone, Eq, PartialEq, Ord, PartialOrd, new)] #[derive(Debug, Clone, Eq, PartialEq, Ord, PartialOrd, Getters, new)]
#[get = "crate"]
pub struct PathNode { pub struct PathNode {
head: Box<TokenNode>, head: Box<TokenNode>,
tail: Vec<TokenNode>, tail: Vec<TokenNode>,

View file

@ -1,5 +1,7 @@
use crate::parser::parse::span::*; use crate::parser::parse::span::*;
use crate::parser::parse::unit::*; use crate::parser::parse::unit::*;
use crate::Text;
use std::fmt;
#[derive(Debug, Clone, Copy, Eq, PartialEq, Ord, PartialOrd, Hash)] #[derive(Debug, Clone, Copy, Eq, PartialEq, Ord, PartialOrd, Hash)]
pub enum RawToken { pub enum RawToken {
@ -10,4 +12,36 @@ pub enum RawToken {
Bare, Bare,
} }
impl RawToken {
pub fn type_name(&self) -> &'static str {
match self {
RawToken::Integer(_) => "Integer",
RawToken::Size(..) => "Size",
RawToken::String(_) => "String",
RawToken::Variable(_) => "Variable",
RawToken::Bare => "String",
}
}
}
pub type Token = Spanned<RawToken>; pub type Token = Spanned<RawToken>;
impl Token {
pub fn debug(&self, source: &'a Text) -> DebugToken<'a> {
DebugToken {
node: *self,
source,
}
}
}
pub struct DebugToken<'a> {
node: Token,
source: &'a Text,
}
impl fmt::Debug for DebugToken<'a> {
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
write!(f, "{}", self.node.span().slice(self.source))
}
}

View file

@ -67,77 +67,81 @@ fn parse_command_tail(
tail: Option<Vec<TokenNode>>, tail: Option<Vec<TokenNode>>,
source: &Text, source: &Text,
) -> Result<Option<(Option<Vec<hir::Expression>>, Option<NamedArguments>)>, ShellError> { ) -> Result<Option<(Option<Vec<hir::Expression>>, Option<NamedArguments>)>, ShellError> {
let mut tail = match tail { let tail = &mut match &tail {
None => return Ok(None), None => return Ok(None),
Some(tail) => tail, Some(tail) => hir::TokensIterator::new(tail),
}; };
let mut named = NamedArguments::new(); let mut named = NamedArguments::new();
trace_remaining("nodes", tail.clone(), source);
for (name, kind) in config.named() { for (name, kind) in config.named() {
trace!("looking for {} : {:?}", name, kind); trace!("looking for {} : {:?}", name, kind);
match kind { match kind {
NamedType::Switch => { NamedType::Switch => {
let (rest, flag) = extract_switch(name, tail, source); let flag = extract_switch(name, tail, source);
tail = rest;
named.insert_switch(name, flag); named.insert_switch(name, flag);
} }
NamedType::Mandatory(kind) => match extract_mandatory(name, tail, source) { NamedType::Mandatory(kind) => match extract_mandatory(name, tail, source) {
Err(err) => return Err(err), // produce a correct diagnostic Err(err) => return Err(err), // produce a correct diagnostic
Ok((rest, pos, _flag)) => { Ok((pos, _flag)) => {
let (expr, rest) = hir::baseline_parse_next_expr( tail.move_to(pos);
&rest[pos..], let expr = hir::baseline_parse_next_expr(
tail,
registry, registry,
source, source,
kind.to_coerce_hint(), kind.to_coerce_hint(),
)?; )?;
tail = rest.to_vec();
tail.restart();
named.insert_mandatory(name, expr); named.insert_mandatory(name, expr);
} }
}, },
NamedType::Optional(kind) => match extract_optional(name, tail, source) { NamedType::Optional(kind) => match extract_optional(name, tail, source) {
Err(err) => return Err(err), // produce a correct diagnostic Err(err) => return Err(err), // produce a correct diagnostic
Ok((rest, Some((pos, _flag)))) => { Ok(Some((pos, _flag))) => {
let (expr, rest) = hir::baseline_parse_next_expr( tail.move_to(pos);
&rest[pos..], let expr = hir::baseline_parse_next_expr(
tail,
registry, registry,
source, source,
kind.to_coerce_hint(), kind.to_coerce_hint(),
)?; )?;
tail = rest.to_vec();
tail.restart();
named.insert_optional(name, Some(expr)); named.insert_optional(name, Some(expr));
} }
Ok((rest, None)) => { Ok(None) => {
tail = rest; tail.restart();
named.insert_optional(name, None); named.insert_optional(name, None);
} }
}, },
}; };
} }
trace_remaining("after named", tail.clone(), source);
let mut positional = vec![]; let mut positional = vec![];
let mandatory = config.mandatory_positional(); let mandatory = config.mandatory_positional();
for arg in mandatory { for arg in mandatory {
trace!("Processing mandatory {:?}", arg);
if tail.len() == 0 { if tail.len() == 0 {
return Err(ShellError::unimplemented("Missing mandatory argument")); return Err(ShellError::unimplemented("Missing mandatory argument"));
} }
let (result, rest) = let result = hir::baseline_parse_next_expr(tail, registry, source, arg.to_coerce_hint())?;
hir::baseline_parse_next_expr(&tail, registry, source, arg.to_coerce_hint())?;
positional.push(result); positional.push(result);
tail = rest.to_vec();
} }
trace_remaining("after mandatory", tail.clone(), source);
let optional = config.optional_positional(); let optional = config.optional_positional();
for arg in optional { for arg in optional {
@ -145,18 +149,19 @@ fn parse_command_tail(
break; break;
} }
let (result, rest) = let result = hir::baseline_parse_next_expr(tail, registry, source, arg.to_coerce_hint())?;
hir::baseline_parse_next_expr(&tail, registry, source, arg.to_coerce_hint())?;
positional.push(result); positional.push(result);
tail = rest.to_vec();
} }
trace_remaining("after optional", tail.clone(), source);
// TODO: Only do this if rest params are specified // TODO: Only do this if rest params are specified
let remainder = baseline_parse_tokens(&tail, registry, source)?; let remainder = baseline_parse_tokens(tail, registry, source)?;
positional.extend(remainder); positional.extend(remainder);
trace_remaining("after rest", tail.clone(), source);
trace!("Constructed positional={:?} named={:?}", positional, named); trace!("Constructed positional={:?} named={:?}", positional, named);
let positional = match positional { let positional = match positional {
@ -174,38 +179,20 @@ fn parse_command_tail(
Ok(Some((positional, named))) Ok(Some((positional, named)))
} }
fn extract_switch( fn extract_switch(name: &str, tokens: &mut hir::TokensIterator<'_>, source: &Text) -> Option<Flag> {
name: &str, tokens
mut tokens: Vec<TokenNode>, .extract(|t| t.as_flag(name, source))
source: &Text, .map(|(_pos, flag)| flag.item)
) -> (Vec<TokenNode>, Option<Flag>) {
let pos = tokens
.iter()
.enumerate()
.filter_map(|(i, t)| t.as_flag(name, source).map(|f| (i, f)))
.nth(0);
match pos {
None => (tokens, None),
Some((pos, flag)) => {
tokens.remove(pos);
(tokens, Some(*flag))
}
}
} }
fn extract_mandatory( fn extract_mandatory(
name: &str, name: &str,
mut tokens: Vec<TokenNode>, tokens: &mut hir::TokensIterator<'a>,
source: &Text, source: &Text,
) -> Result<(Vec<TokenNode>, usize, Flag), ShellError> { ) -> Result<(usize, Flag), ShellError> {
let pos = tokens let flag = tokens.extract(|t| t.as_flag(name, source));
.iter()
.enumerate()
.filter_map(|(i, t)| t.as_flag(name, source).map(|f| (i, f)))
.nth(0);
match pos { match flag {
None => Err(ShellError::unimplemented( None => Err(ShellError::unimplemented(
"Better error: mandatory flags must be present", "Better error: mandatory flags must be present",
)), )),
@ -218,24 +205,20 @@ fn extract_mandatory(
tokens.remove(pos); tokens.remove(pos);
Ok((tokens, pos, *flag)) Ok((pos, *flag))
} }
} }
} }
fn extract_optional( fn extract_optional(
name: &str, name: &str,
mut tokens: Vec<TokenNode>, tokens: &mut hir::TokensIterator<'a>,
source: &Text, source: &Text,
) -> Result<(Vec<TokenNode>, Option<(usize, Flag)>), ShellError> { ) -> Result<(Option<(usize, Flag)>), ShellError> {
let pos = tokens let flag = tokens.extract(|t| t.as_flag(name, source));
.iter()
.enumerate()
.filter_map(|(i, t)| t.as_flag(name, source).map(|f| (i, f)))
.nth(0);
match pos { match flag {
None => Ok((tokens, None)), None => Ok(None),
Some((pos, flag)) => { Some((pos, flag)) => {
if tokens.len() <= pos { if tokens.len() <= pos {
return Err(ShellError::unimplemented( return Err(ShellError::unimplemented(
@ -245,7 +228,20 @@ fn extract_optional(
tokens.remove(pos); tokens.remove(pos);
Ok((tokens, Some((pos, *flag)))) Ok(Some((pos, *flag)))
} }
} }
} }
pub fn trace_remaining(desc: &'static str, tail: hir::TokensIterator<'a>, source: &Text) {
trace!(
"{} = {:?}",
desc,
itertools::join(
tail.debug_remaining()
.iter()
.map(|i| format!("%{:?}%", i.debug(source))),
" "
)
);
}