This commit is contained in:
JT 2021-09-06 11:16:27 +12:00
parent 036c6a9a52
commit aaee3a8b61
10 changed files with 192 additions and 124 deletions

View File

@ -252,61 +252,76 @@ pub fn report_shell_error(
let writer = StandardStream::stderr(ColorChoice::Always); let writer = StandardStream::stderr(ColorChoice::Always);
let config = codespan_reporting::term::Config::default(); let config = codespan_reporting::term::Config::default();
let diagnostic = match error { let diagnostic =
ShellError::OperatorMismatch { match error {
op_span, ShellError::OperatorMismatch {
lhs_ty, op_span,
lhs_span, lhs_ty,
rhs_ty, lhs_span,
rhs_span, rhs_ty,
} => { rhs_span,
let (lhs_file_id, lhs_range) = convert_span_to_diag(working_set, lhs_span)?; } => {
let (rhs_file_id, rhs_range) = convert_span_to_diag(working_set, rhs_span)?; let (lhs_file_id, lhs_range) = convert_span_to_diag(working_set, lhs_span)?;
let (op_file_id, op_range) = convert_span_to_diag(working_set, op_span)?; let (rhs_file_id, rhs_range) = convert_span_to_diag(working_set, rhs_span)?;
Diagnostic::error() let (op_file_id, op_range) = convert_span_to_diag(working_set, op_span)?;
.with_message("Type mismatch during operation") Diagnostic::error()
.with_labels(vec![ .with_message("Type mismatch during operation")
Label::primary(op_file_id, op_range).with_message("type mismatch for operator"), .with_labels(vec![
Label::secondary(lhs_file_id, lhs_range).with_message(lhs_ty.to_string()), Label::primary(op_file_id, op_range)
Label::secondary(rhs_file_id, rhs_range).with_message(rhs_ty.to_string()), .with_message("type mismatch for operator"),
]) Label::secondary(lhs_file_id, lhs_range).with_message(lhs_ty.to_string()),
} Label::secondary(rhs_file_id, rhs_range).with_message(rhs_ty.to_string()),
ShellError::Unsupported(span) => { ])
let (diag_file_id, diag_range) = convert_span_to_diag(working_set, span)?; }
Diagnostic::error() ShellError::UnsupportedOperator(op, span) => {
.with_message("Unsupported operation") let (diag_file_id, diag_range) = convert_span_to_diag(working_set, span)?;
.with_labels(vec![ Diagnostic::error()
Label::primary(diag_file_id, diag_range).with_message("unsupported operation") .with_message(format!("Unsupported operator: {}", op))
]) .with_labels(vec![Label::primary(diag_file_id, diag_range)
} .with_message("unsupported operator")])
ShellError::InternalError(s) => { }
Diagnostic::error().with_message(format!("Internal error: {}", s)) ShellError::UnknownOperator(op, span) => {
} let (diag_file_id, diag_range) = convert_span_to_diag(working_set, span)?;
ShellError::VariableNotFound(span) => { Diagnostic::error()
let (diag_file_id, diag_range) = convert_span_to_diag(working_set, span)?; .with_message(format!("Unsupported operator: {}", op))
Diagnostic::error() .with_labels(vec![Label::primary(diag_file_id, diag_range)
.with_message("Variable not found") .with_message("unsupported operator")])
.with_labels(vec![ }
Label::primary(diag_file_id, diag_range).with_message("variable not found") ShellError::ExternalNotSupported(span) => {
]) let (diag_file_id, diag_range) = convert_span_to_diag(working_set, span)?;
} Diagnostic::error()
ShellError::CantConvert(s, span) => { .with_message("External commands not yet supported")
let (diag_file_id, diag_range) = convert_span_to_diag(working_set, span)?; .with_labels(vec![Label::primary(diag_file_id, diag_range)
Diagnostic::error() .with_message("external not supported")])
.with_message(format!("Can't convert to {}", s)) }
.with_labels(vec![Label::primary(diag_file_id, diag_range) ShellError::InternalError(s) => {
.with_message(format!("can't convert to {}", s))]) Diagnostic::error().with_message(format!("Internal error: {}", s))
} }
ShellError::DivisionByZero(span) => { ShellError::VariableNotFound(span) => {
let (diag_file_id, diag_range) = convert_span_to_diag(working_set, span)?; let (diag_file_id, diag_range) = convert_span_to_diag(working_set, span)?;
Diagnostic::error()
.with_message("Variable not found")
.with_labels(vec![
Label::primary(diag_file_id, diag_range).with_message("variable not found")
])
}
ShellError::CantConvert(s, span) => {
let (diag_file_id, diag_range) = convert_span_to_diag(working_set, span)?;
Diagnostic::error()
.with_message(format!("Can't convert to {}", s))
.with_labels(vec![Label::primary(diag_file_id, diag_range)
.with_message(format!("can't convert to {}", s))])
}
ShellError::DivisionByZero(span) => {
let (diag_file_id, diag_range) = convert_span_to_diag(working_set, span)?;
Diagnostic::error() Diagnostic::error()
.with_message("Division by zero") .with_message("Division by zero")
.with_labels(vec![ .with_labels(vec![
Label::primary(diag_file_id, diag_range).with_message("division by zero") Label::primary(diag_file_id, diag_range).with_message("division by zero")
]) ])
} }
}; };
// println!("DIAG"); // println!("DIAG");
// println!("{:?}", diagnostic); // println!("{:?}", diagnostic);

View File

@ -15,13 +15,7 @@ impl Command for Each {
} }
fn signature(&self) -> nu_protocol::Signature { fn signature(&self) -> nu_protocol::Signature {
Signature::build("each") Signature::build("each").required("block", SyntaxShape::Block, "the block to run")
.required(
"var_name",
SyntaxShape::Variable,
"name of the looping variable",
)
.required("block", SyntaxShape::Block, "the block to run")
} }
fn run( fn run(
@ -30,11 +24,7 @@ impl Command for Each {
call: &Call, call: &Call,
input: Value, input: Value,
) -> Result<nu_protocol::Value, nu_protocol::ShellError> { ) -> Result<nu_protocol::Value, nu_protocol::ShellError> {
let var_id = call.positional[0] let block_id = call.positional[0]
.as_var()
.expect("internal error: missing variable");
let block = call.positional[1]
.as_block() .as_block()
.expect("internal error: expected block"); .expect("internal error: expected block");
let context = context.clone(); let context = context.clone();
@ -45,13 +35,19 @@ impl Command for Each {
.into_iter() .into_iter()
.map(move |x| { .map(move |x| {
let engine_state = context.engine_state.borrow(); let engine_state = context.engine_state.borrow();
let block = engine_state.get_block(block); let block = engine_state.get_block(block_id);
let state = context.enter_scope(); let state = context.enter_scope();
state.add_var(var_id, x); if let Some(var) = block.signature.required_positional.first() {
if let Some(var_id) = &var.var_id {
state.add_var(*var_id, x);
}
}
//FIXME: DON'T UNWRAP match eval_block(&state, block, Value::nothing()) {
eval_block(&state, block, Value::nothing()).unwrap() Ok(v) => v,
Err(err) => Value::Error { err },
}
}) })
.collect(), .collect(),
span: call.head, span: call.head,
@ -60,13 +56,19 @@ impl Command for Each {
stream: stream stream: stream
.map(move |x| { .map(move |x| {
let engine_state = context.engine_state.borrow(); let engine_state = context.engine_state.borrow();
let block = engine_state.get_block(block); let block = engine_state.get_block(block_id);
let state = context.enter_scope(); let state = context.enter_scope();
state.add_var(var_id, x); if let Some(var) = block.signature.required_positional.first() {
if let Some(var_id) = &var.var_id {
state.add_var(*var_id, x);
}
}
//FIXME: DON'T UNWRAP match eval_block(&state, block, Value::nothing()) {
eval_block(&state, block, Value::nothing()).unwrap() Ok(v) => v,
Err(err) => Value::Error { err },
}
}) })
.into_value_stream(), .into_value_stream(),
span: call.head, span: call.head,

View File

@ -8,14 +8,16 @@ pub fn eval_operator(op: &Expression) -> Result<Operator, ShellError> {
expr: Expr::Operator(operator), expr: Expr::Operator(operator),
.. ..
} => Ok(operator.clone()), } => Ok(operator.clone()),
Expression { span, .. } => Err(ShellError::Unsupported(*span)), Expression { span, expr, .. } => {
Err(ShellError::UnknownOperator(format!("{:?}", expr), *span))
}
} }
} }
fn eval_call(context: &EvaluationContext, call: &Call, input: Value) -> Result<Value, ShellError> { fn eval_call(context: &EvaluationContext, call: &Call, input: Value) -> Result<Value, ShellError> {
let engine_state = context.engine_state.borrow(); let engine_state = context.engine_state.borrow();
let decl = engine_state.get_decl(call.decl_id); let decl = engine_state.get_decl(call.decl_id);
if let Some(block_id) = decl.get_custom_command() { if let Some(block_id) = decl.get_block_id() {
let state = context.enter_scope(); let state = context.enter_scope();
for (arg, param) in call.positional.iter().zip( for (arg, param) in call.positional.iter().zip(
decl.signature() decl.signature()
@ -101,7 +103,7 @@ pub fn eval_expression(
.get_var(*var_id) .get_var(*var_id)
.map_err(move |_| ShellError::VariableNotFound(expr.span)), .map_err(move |_| ShellError::VariableNotFound(expr.span)),
Expr::Call(call) => eval_call(context, call, Value::nothing()), Expr::Call(call) => eval_call(context, call, Value::nothing()),
Expr::ExternalCall(_, _) => Err(ShellError::Unsupported(expr.span)), Expr::ExternalCall(_, _) => Err(ShellError::ExternalNotSupported(expr.span)),
Expr::Operator(_) => Ok(Value::Nothing { span: expr.span }), Expr::Operator(_) => Ok(Value::Nothing { span: expr.span }),
Expr::BinaryOp(lhs, op, rhs) => { Expr::BinaryOp(lhs, op, rhs) => {
let op_span = op.span; let op_span = op.span;
@ -120,7 +122,7 @@ pub fn eval_expression(
Operator::GreaterThanOrEqual => lhs.gte(op_span, &rhs), Operator::GreaterThanOrEqual => lhs.gte(op_span, &rhs),
Operator::Equal => lhs.eq(op_span, &rhs), Operator::Equal => lhs.eq(op_span, &rhs),
Operator::NotEqual => lhs.ne(op_span, &rhs), Operator::NotEqual => lhs.ne(op_span, &rhs),
_ => Err(ShellError::Unsupported(op_span)), x => Err(ShellError::UnsupportedOperator(x, op_span)),
} }
} }

View File

@ -1223,16 +1223,6 @@ pub fn parse_signature(
working_set: &mut StateWorkingSet, working_set: &mut StateWorkingSet,
span: Span, span: Span,
) -> (Expression, Option<ParseError>) { ) -> (Expression, Option<ParseError>) {
enum ParseMode {
ArgMode,
TypeMode,
}
enum Arg {
Positional(PositionalArg, bool), // bool - required
Flag(Flag),
}
let bytes = working_set.get_span_contents(span); let bytes = working_set.get_span_contents(span);
let mut error = None; let mut error = None;
@ -1256,7 +1246,34 @@ pub fn parse_signature(
}); });
} }
let span = Span { start, end }; let (sig, err) = parse_signature_helper(working_set, Span { start, end });
error = error.or(err);
(
Expression {
expr: Expr::Signature(sig),
span,
ty: Type::Unknown,
},
error,
)
}
pub fn parse_signature_helper(
working_set: &mut StateWorkingSet,
span: Span,
) -> (Box<Signature>, Option<ParseError>) {
enum ParseMode {
ArgMode,
TypeMode,
}
enum Arg {
Positional(PositionalArg, bool), // bool - required
Flag(Flag),
}
let mut error = None;
let source = working_set.get_span_contents(span); let source = working_set.get_span_contents(span);
let (output, err) = lex(source, span.start, &[b'\n', b','], &[b':']); let (output, err) = lex(source, span.start, &[b'\n', b','], &[b':']);
@ -1535,14 +1552,7 @@ pub fn parse_signature(
} }
} }
( (Box::new(sig), error)
Expression {
expr: Expr::Signature(Box::new(sig)),
span,
ty: Type::Unknown,
},
error,
)
} }
pub fn parse_list_expression( pub fn parse_list_expression(
@ -1762,37 +1772,59 @@ pub fn parse_block_expression(
error = error.or(err); error = error.or(err);
// Check to see if we have parameters // Check to see if we have parameters
let _params = if matches!( let (signature, amt_to_skip): (Option<Box<Signature>>, usize) = match output.first() {
output.first(),
Some(Token { Some(Token {
contents: TokenContents::Pipe, contents: TokenContents::Pipe,
.. span,
}) }) => {
) { // We've found a parameter list
// We've found a parameter list let start_point = span.start;
let mut param_tokens = vec![]; let mut token_iter = output.iter().enumerate().skip(1);
let mut token_iter = output.iter().skip(1); let mut end_span = None;
for token in &mut token_iter { let mut amt_to_skip = 1;
if matches!(
token, for token in &mut token_iter {
Token { if let Token {
contents: TokenContents::Pipe, contents: TokenContents::Pipe,
.. span,
} = token.1
{
end_span = Some(span);
amt_to_skip = token.0;
break;
} }
) {
break;
} else {
param_tokens.push(token);
} }
let end_point = if let Some(span) = end_span {
span.end
} else {
end
};
let (signature, err) = parse_signature_helper(
working_set,
Span {
start: start_point,
end: end_point,
},
);
error = error.or(err);
(Some(signature), amt_to_skip)
} }
_ => (None, 0),
}; };
let (output, err) = lite_parse(&output); let (output, err) = lite_parse(&output[amt_to_skip..]);
error = error.or(err); error = error.or(err);
let (output, err) = parse_block(working_set, &output, true); let (mut output, err) = parse_block(working_set, &output, true);
error = error.or(err); error = error.or(err);
if let Some(signature) = signature {
output.signature = signature;
}
let block_id = working_set.add_block(output); let block_id = working_set.add_block(output);
( (

View File

@ -1,9 +1,12 @@
use std::ops::{Index, IndexMut}; use std::ops::{Index, IndexMut};
use crate::Signature;
use super::Statement; use super::Statement;
#[derive(Debug, Clone)] #[derive(Debug, Clone)]
pub struct Block { pub struct Block {
pub signature: Box<Signature>,
pub stmts: Vec<Statement>, pub stmts: Vec<Statement>,
} }
@ -39,6 +42,9 @@ impl Default for Block {
impl Block { impl Block {
pub fn new() -> Self { pub fn new() -> Self {
Self { stmts: vec![] } Self {
signature: Box::new(Signature::new("")),
stmts: vec![],
}
} }
} }

View File

@ -50,8 +50,8 @@ pub trait Command {
false false
} }
// If command is a custom command i.e. def blah [] { }, get the block id // If command is a block i.e. def blah [] { }, get the block id
fn get_custom_command(&self) -> Option<BlockId> { fn get_block_id(&self) -> Option<BlockId> {
None None
} }
} }

View File

@ -1,6 +1,6 @@
use crate::{Span, Type}; use crate::{ast::Operator, Span, Type};
#[derive(Debug)] #[derive(Debug, Clone)]
pub enum ShellError { pub enum ShellError {
OperatorMismatch { OperatorMismatch {
op_span: Span, op_span: Span,
@ -9,7 +9,9 @@ pub enum ShellError {
rhs_ty: Type, rhs_ty: Type,
rhs_span: Span, rhs_span: Span,
}, },
Unsupported(Span), UnsupportedOperator(Operator, Span),
UnknownOperator(String, Span),
ExternalNotSupported(Span),
InternalError(String), InternalError(String),
VariableNotFound(Span), VariableNotFound(Span),
CantConvert(String, Span), CantConvert(String, Span),

View File

@ -350,7 +350,7 @@ impl Command for BlockCommand {
} }
fn signature(&self) -> Signature { fn signature(&self) -> Signature {
self.signature.clone() panic!("Internal error: can't get signature with 'signature', use block_id");
} }
fn usage(&self) -> &str { fn usage(&self) -> &str {
@ -366,7 +366,7 @@ impl Command for BlockCommand {
panic!("Internal error: can't run custom command with 'run', use block_id"); panic!("Internal error: can't run custom command with 'run', use block_id");
} }
fn get_custom_command(&self) -> Option<BlockId> { fn get_block_id(&self) -> Option<BlockId> {
Some(self.block_id) Some(self.block_id)
} }
} }

View File

@ -19,6 +19,7 @@ pub enum Type {
RowStream, RowStream,
ValueStream, ValueStream,
Unknown, Unknown,
Error,
} }
impl Display for Type { impl Display for Type {
@ -41,6 +42,7 @@ impl Display for Type {
Type::ValueStream => write!(f, "value stream"), Type::ValueStream => write!(f, "value stream"),
Type::RowStream => write!(f, "row stream"), Type::RowStream => write!(f, "row stream"),
Type::Unknown => write!(f, "unknown"), Type::Unknown => write!(f, "unknown"),
Type::Error => write!(f, "error"),
} }
} }
} }

View File

@ -158,6 +158,9 @@ pub enum Value {
Nothing { Nothing {
span: Span, span: Span,
}, },
Error {
err: ShellError,
},
} }
impl Value { impl Value {
@ -181,6 +184,7 @@ impl Value {
Value::RowStream { span, .. } => *span, Value::RowStream { span, .. } => *span,
Value::ValueStream { span, .. } => *span, Value::ValueStream { span, .. } => *span,
Value::Nothing { span, .. } => *span, Value::Nothing { span, .. } => *span,
Value::Error { .. } => Span::unknown(),
} }
} }
@ -197,6 +201,7 @@ impl Value {
Value::Table { span, .. } => *span = new_span, Value::Table { span, .. } => *span = new_span,
Value::Block { span, .. } => *span = new_span, Value::Block { span, .. } => *span = new_span,
Value::Nothing { span, .. } => *span = new_span, Value::Nothing { span, .. } => *span = new_span,
Value::Error { .. } => {}
} }
self self
@ -215,6 +220,7 @@ impl Value {
Value::Block { .. } => Type::Block, Value::Block { .. } => Type::Block,
Value::ValueStream { .. } => Type::ValueStream, Value::ValueStream { .. } => Type::ValueStream,
Value::RowStream { .. } => Type::RowStream, Value::RowStream { .. } => Type::RowStream,
Value::Error { .. } => Type::Error,
} }
} }
@ -264,6 +270,7 @@ impl Value {
} => stream.into_string(headers), } => stream.into_string(headers),
Value::Block { val, .. } => format!("<Block {}>", val), Value::Block { val, .. } => format!("<Block {}>", val),
Value::Nothing { .. } => String::new(), Value::Nothing { .. } => String::new(),
Value::Error { err } => format!("{:?}", err),
} }
} }