add more type helpers and span fixes

This commit is contained in:
Jonathan Turner 2021-08-10 17:55:25 +12:00
parent ef4af443a5
commit 828585a312
4 changed files with 89 additions and 19 deletions

View file

@ -78,7 +78,7 @@ impl<'a> codespan_reporting::files::Files<'a> for ParserWorkingSet<'a> {
if count > line_index { if count > line_index {
break; break;
} else if count == line_index { } else if count == line_index {
start = Some(byte.0); start = Some(byte.0 + 1);
} }
} }
} }
@ -286,12 +286,15 @@ pub fn report_shell_error(
let config = codespan_reporting::term::Config::default(); let config = codespan_reporting::term::Config::default();
let diagnostic = match error { let diagnostic = match error {
ShellError::Mismatch(missing, span) => { ShellError::OperatorMismatch(operator, ty1, span1, ty2, span2) => {
let (diag_file_id, diag_range) = convert_span_to_diag(working_set, span)?; let (diag_file_id1, diag_range1) = convert_span_to_diag(working_set, span1)?;
let (diag_file_id2, diag_range2) = convert_span_to_diag(working_set, span2)?;
Diagnostic::error() Diagnostic::error()
.with_message("Type mismatch during operation") .with_message(format!("Type mismatch during operation '{}'", operator))
.with_labels(vec![Label::primary(diag_file_id, diag_range) .with_labels(vec![
.with_message(format!("expected {}", missing))]) Label::primary(diag_file_id1, diag_range1).with_message(ty1.to_string()),
Label::secondary(diag_file_id2, diag_range2).with_message(ty2.to_string()),
])
} }
ShellError::Unsupported(span) => { ShellError::Unsupported(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)?;
@ -312,6 +315,13 @@ pub fn report_shell_error(
Label::primary(diag_file_id, diag_range).with_message("variable not found") 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))])
}
}; };
// println!("DIAG"); // println!("DIAG");

View file

@ -1,15 +1,17 @@
use std::{cell::RefCell, collections::HashMap, fmt::Display, rc::Rc, time::Instant}; use std::{cell::RefCell, collections::HashMap, fmt::Display, rc::Rc, time::Instant};
use crate::{ use crate::{
parser::Operator, Block, BlockId, Call, Expr, Expression, ParserState, Span, Statement, VarId, parser::Operator, parser_state::Type, Block, BlockId, Call, Expr, Expression, ParserState,
Span, Statement, VarId,
}; };
#[derive(Debug)] #[derive(Debug)]
pub enum ShellError { pub enum ShellError {
Mismatch(String, Span), OperatorMismatch(String, Type, Span, Type, Span),
Unsupported(Span), Unsupported(Span),
InternalError(String), InternalError(String),
VariableNotFound(Span), VariableNotFound(Span),
CantConvert(String, Span),
} }
#[derive(Debug, Clone)] #[derive(Debug, Clone)]
@ -27,7 +29,7 @@ impl Value {
pub fn as_string(&self) -> Result<String, ShellError> { pub fn as_string(&self) -> Result<String, ShellError> {
match self { match self {
Value::String { val, .. } => Ok(val.to_string()), Value::String { val, .. } => Ok(val.to_string()),
_ => Err(ShellError::Mismatch("string".into(), self.span())), _ => Err(ShellError::CantConvert("string".into(), self.span())),
} }
} }
@ -42,6 +44,32 @@ impl Value {
Value::Nothing { span, .. } => *span, Value::Nothing { span, .. } => *span,
} }
} }
pub fn with_span(mut self, new_span: Span) -> Value {
match &mut self {
Value::Bool { span, .. } => *span = new_span,
Value::Int { span, .. } => *span = new_span,
Value::Float { span, .. } => *span = new_span,
Value::String { span, .. } => *span = new_span,
Value::List { span, .. } => *span = new_span,
Value::Block { span, .. } => *span = new_span,
Value::Nothing { span, .. } => *span = new_span,
}
self
}
pub fn get_type(&self) -> Type {
match self {
Value::Bool { .. } => Type::Bool,
Value::Int { .. } => Type::Int,
Value::Float { .. } => Type::Float,
Value::String { .. } => Type::String,
Value::List { .. } => Type::List(Box::new(Type::Unknown)), // FIXME
Value::Nothing { .. } => Type::Nothing,
Value::Block { .. } => Type::Block,
}
}
} }
impl PartialEq for Value { impl PartialEq for Value {
@ -80,29 +108,37 @@ impl Display for Value {
impl Value { impl Value {
pub fn add(&self, rhs: &Value) -> Result<Value, ShellError> { pub fn add(&self, rhs: &Value) -> Result<Value, ShellError> {
let span = crate::parser::span(&[self.span(), rhs.span()]);
match (self, rhs) { match (self, rhs) {
(Value::Int { val: lhs, .. }, Value::Int { val: rhs, .. }) => Ok(Value::Int { (Value::Int { val: lhs, .. }, Value::Int { val: rhs, .. }) => Ok(Value::Int {
val: lhs + rhs, val: lhs + rhs,
span: Span::unknown(), span,
}), }),
(Value::Int { val: lhs, .. }, Value::Float { val: rhs, .. }) => Ok(Value::Float { (Value::Int { val: lhs, .. }, Value::Float { val: rhs, .. }) => Ok(Value::Float {
val: *lhs as f64 + *rhs, val: *lhs as f64 + *rhs,
span: Span::unknown(), span,
}), }),
(Value::Float { val: lhs, .. }, Value::Int { val: rhs, .. }) => Ok(Value::Float { (Value::Float { val: lhs, .. }, Value::Int { val: rhs, .. }) => Ok(Value::Float {
val: *lhs + *rhs as f64, val: *lhs + *rhs as f64,
span: Span::unknown(), span,
}), }),
(Value::Float { val: lhs, .. }, Value::Float { val: rhs, .. }) => Ok(Value::Float { (Value::Float { val: lhs, .. }, Value::Float { val: rhs, .. }) => Ok(Value::Float {
val: lhs + rhs, val: lhs + rhs,
span: Span::unknown(), span,
}), }),
(Value::String { val: lhs, .. }, Value::String { val: rhs, .. }) => Ok(Value::String { (Value::String { val: lhs, .. }, Value::String { val: rhs, .. }) => Ok(Value::String {
val: lhs.to_string() + rhs, val: lhs.to_string() + rhs,
span: Span::unknown(), span,
}), }),
_ => Err(ShellError::Mismatch("addition".into(), self.span())), _ => Err(ShellError::OperatorMismatch(
"+".into(),
self.get_type(),
self.span(),
rhs.get_type(),
rhs.span(),
)),
} }
} }
} }
@ -193,7 +229,7 @@ pub fn eval_operator(
expr: Expr::Operator(operator), expr: Expr::Operator(operator),
.. ..
} => Ok(operator.clone()), } => Ok(operator.clone()),
Expression { span, .. } => Err(ShellError::Mismatch("operator".to_string(), *span)), Expression { span, .. } => Err(ShellError::Unsupported(*span)),
} }
} }
@ -280,7 +316,7 @@ fn eval_call(state: &State, stack: Stack, call: &Call) -> Result<Value, ShellErr
Ok(Value::Nothing { span }) Ok(Value::Nothing { span })
} }
} }
_ => Err(ShellError::Mismatch("bool".into(), Span::unknown())), _ => Err(ShellError::CantConvert("bool".into(), result.span())),
} }
} else if decl.signature.name == "build-string" { } else if decl.signature.name == "build-string" {
let mut output = vec![]; let mut output = vec![];
@ -385,6 +421,7 @@ pub fn eval_expression(
}), }),
Expr::Var(var_id) => stack Expr::Var(var_id) => stack
.get_var(*var_id) .get_var(*var_id)
.map(|x| x.with_span(expr.span))
.map_err(move |_| ShellError::VariableNotFound(expr.span)), .map_err(move |_| ShellError::VariableNotFound(expr.span)),
Expr::Call(call) => eval_call(state, stack, call), Expr::Call(call) => eval_call(state, stack, call),
Expr::ExternalCall(_, _) => Err(ShellError::Unsupported(expr.span)), Expr::ExternalCall(_, _) => Err(ShellError::Unsupported(expr.span)),

View file

@ -375,7 +375,7 @@ fn check_call(command: Span, sig: &Signature, call: &Call) -> Option<ParseError>
} }
} }
fn span(spans: &[Span]) -> Span { pub(crate) fn span(spans: &[Span]) -> Span {
let length = spans.len(); let length = spans.len();
if length == 0 { if length == 0 {

View file

@ -1,6 +1,6 @@
use crate::{parser::Block, Declaration, Span}; use crate::{parser::Block, Declaration, Span};
use core::panic; use core::panic;
use std::{collections::HashMap, slice::Iter}; use std::{collections::HashMap, fmt::Display, slice::Iter};
#[derive(Debug)] #[derive(Debug)]
pub struct ParserState { pub struct ParserState {
@ -15,6 +15,7 @@ pub struct ParserState {
#[derive(Clone, Debug, PartialEq, Eq)] #[derive(Clone, Debug, PartialEq, Eq)]
pub enum Type { pub enum Type {
Int, Int,
Float,
Bool, Bool,
String, String,
Block, Block,
@ -24,10 +25,32 @@ pub enum Type {
Filesize, Filesize,
List(Box<Type>), List(Box<Type>),
Number, Number,
Nothing,
Table, Table,
Unknown, Unknown,
} }
impl Display for Type {
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
match self {
Type::Block => write!(f, "block"),
Type::Bool => write!(f, "bool"),
Type::ColumnPath => write!(f, "column path"),
Type::Duration => write!(f, "duration"),
Type::FilePath => write!(f, "filepath"),
Type::Filesize => write!(f, "filesize"),
Type::Float => write!(f, "float"),
Type::Int => write!(f, "int"),
Type::List(l) => write!(f, "list<{}>", l),
Type::Nothing => write!(f, "nothing"),
Type::Number => write!(f, "number"),
Type::String => write!(f, "string"),
Type::Table => write!(f, "table"),
Type::Unknown => write!(f, "unknown"),
}
}
}
pub type VarId = usize; pub type VarId = usize;
pub type DeclId = usize; pub type DeclId = usize;
pub type BlockId = usize; pub type BlockId = usize;