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 {
break;
} 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 diagnostic = match error {
ShellError::Mismatch(missing, span) => {
let (diag_file_id, diag_range) = convert_span_to_diag(working_set, span)?;
ShellError::OperatorMismatch(operator, ty1, span1, ty2, span2) => {
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()
.with_message("Type mismatch during operation")
.with_labels(vec![Label::primary(diag_file_id, diag_range)
.with_message(format!("expected {}", missing))])
.with_message(format!("Type mismatch during operation '{}'", operator))
.with_labels(vec![
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) => {
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")
])
}
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");

View file

@ -1,15 +1,17 @@
use std::{cell::RefCell, collections::HashMap, fmt::Display, rc::Rc, time::Instant};
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)]
pub enum ShellError {
Mismatch(String, Span),
OperatorMismatch(String, Type, Span, Type, Span),
Unsupported(Span),
InternalError(String),
VariableNotFound(Span),
CantConvert(String, Span),
}
#[derive(Debug, Clone)]
@ -27,7 +29,7 @@ impl Value {
pub fn as_string(&self) -> Result<String, ShellError> {
match self {
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,
}
}
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 {
@ -80,29 +108,37 @@ impl Display for Value {
impl Value {
pub fn add(&self, rhs: &Value) -> Result<Value, ShellError> {
let span = crate::parser::span(&[self.span(), rhs.span()]);
match (self, rhs) {
(Value::Int { val: lhs, .. }, Value::Int { val: rhs, .. }) => Ok(Value::Int {
val: lhs + rhs,
span: Span::unknown(),
span,
}),
(Value::Int { val: lhs, .. }, Value::Float { val: rhs, .. }) => Ok(Value::Float {
val: *lhs as f64 + *rhs,
span: Span::unknown(),
span,
}),
(Value::Float { val: lhs, .. }, Value::Int { val: rhs, .. }) => Ok(Value::Float {
val: *lhs + *rhs as f64,
span: Span::unknown(),
span,
}),
(Value::Float { val: lhs, .. }, Value::Float { val: rhs, .. }) => Ok(Value::Float {
val: lhs + rhs,
span: Span::unknown(),
span,
}),
(Value::String { val: lhs, .. }, Value::String { val: rhs, .. }) => Ok(Value::String {
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),
..
} => 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 })
}
}
_ => Err(ShellError::Mismatch("bool".into(), Span::unknown())),
_ => Err(ShellError::CantConvert("bool".into(), result.span())),
}
} else if decl.signature.name == "build-string" {
let mut output = vec![];
@ -385,6 +421,7 @@ pub fn eval_expression(
}),
Expr::Var(var_id) => stack
.get_var(*var_id)
.map(|x| x.with_span(expr.span))
.map_err(move |_| ShellError::VariableNotFound(expr.span)),
Expr::Call(call) => eval_call(state, stack, call),
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();
if length == 0 {

View file

@ -1,6 +1,6 @@
use crate::{parser::Block, Declaration, Span};
use core::panic;
use std::{collections::HashMap, slice::Iter};
use std::{collections::HashMap, fmt::Display, slice::Iter};
#[derive(Debug)]
pub struct ParserState {
@ -15,6 +15,7 @@ pub struct ParserState {
#[derive(Clone, Debug, PartialEq, Eq)]
pub enum Type {
Int,
Float,
Bool,
String,
Block,
@ -24,10 +25,32 @@ pub enum Type {
Filesize,
List(Box<Type>),
Number,
Nothing,
Table,
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 DeclId = usize;
pub type BlockId = usize;