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 config = codespan_reporting::term::Config::default();
let diagnostic = match error {
ShellError::OperatorMismatch {
op_span,
lhs_ty,
lhs_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 (op_file_id, op_range) = convert_span_to_diag(working_set, op_span)?;
Diagnostic::error()
.with_message("Type mismatch during operation")
.with_labels(vec![
Label::primary(op_file_id, op_range).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()
.with_message("Unsupported operation")
.with_labels(vec![
Label::primary(diag_file_id, diag_range).with_message("unsupported operation")
])
}
ShellError::InternalError(s) => {
Diagnostic::error().with_message(format!("Internal error: {}", s))
}
ShellError::VariableNotFound(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)?;
let diagnostic =
match error {
ShellError::OperatorMismatch {
op_span,
lhs_ty,
lhs_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 (op_file_id, op_range) = convert_span_to_diag(working_set, op_span)?;
Diagnostic::error()
.with_message("Type mismatch during operation")
.with_labels(vec![
Label::primary(op_file_id, op_range)
.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::UnsupportedOperator(op, span) => {
let (diag_file_id, diag_range) = convert_span_to_diag(working_set, span)?;
Diagnostic::error()
.with_message(format!("Unsupported operator: {}", op))
.with_labels(vec![Label::primary(diag_file_id, diag_range)
.with_message("unsupported operator")])
}
ShellError::UnknownOperator(op, span) => {
let (diag_file_id, diag_range) = convert_span_to_diag(working_set, span)?;
Diagnostic::error()
.with_message(format!("Unsupported operator: {}", op))
.with_labels(vec![Label::primary(diag_file_id, diag_range)
.with_message("unsupported operator")])
}
ShellError::ExternalNotSupported(span) => {
let (diag_file_id, diag_range) = convert_span_to_diag(working_set, span)?;
Diagnostic::error()
.with_message("External commands not yet supported")
.with_labels(vec![Label::primary(diag_file_id, diag_range)
.with_message("external not supported")])
}
ShellError::InternalError(s) => {
Diagnostic::error().with_message(format!("Internal error: {}", s))
}
ShellError::VariableNotFound(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()
.with_message("Division by zero")
.with_labels(vec![
Label::primary(diag_file_id, diag_range).with_message("division by zero")
])
}
};
Diagnostic::error()
.with_message("Division by zero")
.with_labels(vec![
Label::primary(diag_file_id, diag_range).with_message("division by zero")
])
}
};
// println!("DIAG");
// println!("{:?}", diagnostic);

View File

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

View File

@ -8,14 +8,16 @@ pub fn eval_operator(op: &Expression) -> Result<Operator, ShellError> {
expr: Expr::Operator(operator),
..
} => 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> {
let engine_state = context.engine_state.borrow();
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();
for (arg, param) in call.positional.iter().zip(
decl.signature()
@ -101,7 +103,7 @@ pub fn eval_expression(
.get_var(*var_id)
.map_err(move |_| ShellError::VariableNotFound(expr.span)),
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::BinaryOp(lhs, op, rhs) => {
let op_span = op.span;
@ -120,7 +122,7 @@ pub fn eval_expression(
Operator::GreaterThanOrEqual => lhs.gte(op_span, &rhs),
Operator::Equal => lhs.eq(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,
span: Span,
) -> (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 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 (output, err) = lex(source, span.start, &[b'\n', b','], &[b':']);
@ -1535,14 +1552,7 @@ pub fn parse_signature(
}
}
(
Expression {
expr: Expr::Signature(Box::new(sig)),
span,
ty: Type::Unknown,
},
error,
)
(Box::new(sig), error)
}
pub fn parse_list_expression(
@ -1762,37 +1772,59 @@ pub fn parse_block_expression(
error = error.or(err);
// Check to see if we have parameters
let _params = if matches!(
output.first(),
let (signature, amt_to_skip): (Option<Box<Signature>>, usize) = match output.first() {
Some(Token {
contents: TokenContents::Pipe,
..
})
) {
// We've found a parameter list
let mut param_tokens = vec![];
let mut token_iter = output.iter().skip(1);
for token in &mut token_iter {
if matches!(
token,
Token {
span,
}) => {
// We've found a parameter list
let start_point = span.start;
let mut token_iter = output.iter().enumerate().skip(1);
let mut end_span = None;
let mut amt_to_skip = 1;
for token in &mut token_iter {
if let Token {
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);
let (output, err) = parse_block(working_set, &output, true);
let (mut output, err) = parse_block(working_set, &output, true);
error = error.or(err);
if let Some(signature) = signature {
output.signature = signature;
}
let block_id = working_set.add_block(output);
(

View File

@ -1,9 +1,12 @@
use std::ops::{Index, IndexMut};
use crate::Signature;
use super::Statement;
#[derive(Debug, Clone)]
pub struct Block {
pub signature: Box<Signature>,
pub stmts: Vec<Statement>,
}
@ -39,6 +42,9 @@ impl Default for Block {
impl Block {
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
}
// If command is a custom command i.e. def blah [] { }, get the block id
fn get_custom_command(&self) -> Option<BlockId> {
// If command is a block i.e. def blah [] { }, get the block id
fn get_block_id(&self) -> Option<BlockId> {
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 {
OperatorMismatch {
op_span: Span,
@ -9,7 +9,9 @@ pub enum ShellError {
rhs_ty: Type,
rhs_span: Span,
},
Unsupported(Span),
UnsupportedOperator(Operator, Span),
UnknownOperator(String, Span),
ExternalNotSupported(Span),
InternalError(String),
VariableNotFound(Span),
CantConvert(String, Span),

View File

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

View File

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

View File

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