Begin using Positioned type
This commit is contained in:
parent
15b1808741
commit
e9bfd9f1f8
@ -3,14 +3,14 @@ use crate::{
|
||||
Context,
|
||||
};
|
||||
|
||||
use super::{AbstractTree, Action, Identifier, Statement, Type};
|
||||
use super::{AbstractTree, Action, Identifier, Positioned, Statement, Type};
|
||||
|
||||
#[derive(Clone, Debug, Eq, PartialEq, PartialOrd, Ord)]
|
||||
pub struct Assignment {
|
||||
identifier: Identifier,
|
||||
r#type: Option<Type>,
|
||||
r#type: Option<Positioned<Type>>,
|
||||
operator: AssignmentOperator,
|
||||
statement: Box<Statement>,
|
||||
statement: Box<Positioned<Statement>>,
|
||||
}
|
||||
|
||||
#[derive(Clone, Debug, Eq, PartialEq, PartialOrd, Ord)]
|
||||
@ -23,9 +23,9 @@ pub enum AssignmentOperator {
|
||||
impl Assignment {
|
||||
pub fn new(
|
||||
identifier: Identifier,
|
||||
r#type: Option<Type>,
|
||||
r#type: Option<Positioned<Type>>,
|
||||
operator: AssignmentOperator,
|
||||
statement: Statement,
|
||||
statement: Positioned<Statement>,
|
||||
) -> Self {
|
||||
Self {
|
||||
identifier,
|
||||
@ -42,24 +42,34 @@ impl AbstractTree for Assignment {
|
||||
}
|
||||
|
||||
fn validate(&self, context: &Context) -> Result<(), ValidationError> {
|
||||
let statement_type = self.statement.expected_type(context)?;
|
||||
let statement_type = self.statement.node.expected_type(context)?;
|
||||
|
||||
if let Some(expected) = &self.r#type {
|
||||
expected.check(&statement_type)?;
|
||||
if let Some(Positioned {
|
||||
node: expected_type,
|
||||
position: expected_position,
|
||||
}) = &self.r#type
|
||||
{
|
||||
expected_type.check(&statement_type).map_err(|conflict| {
|
||||
ValidationError::TypeCheck {
|
||||
conflict,
|
||||
actual_position: self.statement.position,
|
||||
expected_position: expected_position.clone(),
|
||||
}
|
||||
})?;
|
||||
|
||||
context.set_type(self.identifier.clone(), expected.clone())?;
|
||||
context.set_type(self.identifier.clone(), expected_type.clone())?;
|
||||
} else {
|
||||
context.set_type(self.identifier.clone(), statement_type)?;
|
||||
}
|
||||
|
||||
self.identifier.validate(context)?;
|
||||
self.statement.validate(context)?;
|
||||
self.statement.node.validate(context)?;
|
||||
|
||||
Ok(())
|
||||
}
|
||||
|
||||
fn run(self, context: &Context) -> Result<Action, RuntimeError> {
|
||||
let action = self.statement.run(context)?;
|
||||
let action = self.statement.node.run(context)?;
|
||||
let value = match action {
|
||||
Action::Return(value) => value,
|
||||
r#break => return Ok(r#break),
|
||||
@ -101,7 +111,7 @@ impl AbstractTree for Assignment {
|
||||
mod tests {
|
||||
use crate::{
|
||||
abstract_tree::{Expression, ValueNode},
|
||||
error::TypeCheckError,
|
||||
error::TypeConflict,
|
||||
Value,
|
||||
};
|
||||
|
||||
@ -115,7 +125,10 @@ mod tests {
|
||||
Identifier::new("foobar"),
|
||||
None,
|
||||
AssignmentOperator::Assign,
|
||||
Statement::expression(Expression::Value(ValueNode::Integer(42)), (0..0).into()),
|
||||
Positioned {
|
||||
node: Statement::Expression(Expression::Value(ValueNode::Integer(42))),
|
||||
position: (0, 0),
|
||||
},
|
||||
)
|
||||
.run(&context)
|
||||
.unwrap();
|
||||
@ -138,7 +151,10 @@ mod tests {
|
||||
Identifier::new("foobar"),
|
||||
None,
|
||||
AssignmentOperator::AddAssign,
|
||||
Statement::expression(Expression::Value(ValueNode::Integer(41)), (0..0).into()),
|
||||
Positioned {
|
||||
node: Statement::Expression(Expression::Value(ValueNode::Integer(41))),
|
||||
position: (0, 0),
|
||||
},
|
||||
)
|
||||
.run(&context)
|
||||
.unwrap();
|
||||
@ -161,7 +177,10 @@ mod tests {
|
||||
Identifier::new("foobar"),
|
||||
None,
|
||||
AssignmentOperator::SubAssign,
|
||||
Statement::expression(Expression::Value(ValueNode::Integer(1)), (0..0).into()),
|
||||
Positioned {
|
||||
node: Statement::Expression(Expression::Value(ValueNode::Integer(1))),
|
||||
position: (0, 0),
|
||||
},
|
||||
)
|
||||
.run(&context)
|
||||
.unwrap();
|
||||
@ -176,18 +195,28 @@ mod tests {
|
||||
fn type_check() {
|
||||
let validation = Assignment::new(
|
||||
Identifier::new("foobar"),
|
||||
Some(Type::Boolean),
|
||||
Some(Positioned {
|
||||
node: Type::Boolean,
|
||||
position: (0, 0),
|
||||
}),
|
||||
AssignmentOperator::Assign,
|
||||
Statement::expression(Expression::Value(ValueNode::Integer(42)), (0..0).into()),
|
||||
Positioned {
|
||||
node: Statement::Expression(Expression::Value(ValueNode::Integer(42))),
|
||||
position: (0, 0),
|
||||
},
|
||||
)
|
||||
.validate(&Context::new());
|
||||
|
||||
assert_eq!(
|
||||
validation,
|
||||
Err(ValidationError::TypeCheck(TypeCheckError {
|
||||
Err(ValidationError::TypeCheck {
|
||||
conflict: TypeConflict {
|
||||
actual: Type::Integer,
|
||||
expected: Type::Boolean
|
||||
}))
|
||||
},
|
||||
actual_position: (0, 0),
|
||||
expected_position: (0, 0),
|
||||
})
|
||||
)
|
||||
}
|
||||
}
|
||||
|
@ -61,9 +61,9 @@ mod tests {
|
||||
#[test]
|
||||
fn run_returns_value_of_final_statement() {
|
||||
let block = Block::new(vec![
|
||||
Statement::expression(Expression::Value(ValueNode::Integer(1)), (0..0).into()),
|
||||
Statement::expression(Expression::Value(ValueNode::Integer(2)), (0..0).into()),
|
||||
Statement::expression(Expression::Value(ValueNode::Integer(42)), (0..0).into()),
|
||||
Statement::Expression(Expression::Value(ValueNode::Integer(1))),
|
||||
Statement::Expression(Expression::Value(ValueNode::Integer(2))),
|
||||
Statement::Expression(Expression::Value(ValueNode::Integer(42))),
|
||||
]);
|
||||
|
||||
assert_eq!(
|
||||
@ -75,11 +75,8 @@ mod tests {
|
||||
#[test]
|
||||
fn expected_type_returns_type_of_final_statement() {
|
||||
let block = Block::new(vec![
|
||||
Statement::expression(
|
||||
Expression::Value(ValueNode::String("42".to_string())),
|
||||
(0..0).into(),
|
||||
),
|
||||
Statement::expression(Expression::Value(ValueNode::Integer(42)), (0..0).into()),
|
||||
Statement::Expression(Expression::Value(ValueNode::String("42".to_string()))),
|
||||
Statement::Expression(Expression::Value(ValueNode::Integer(42))),
|
||||
]);
|
||||
|
||||
assert_eq!(block.expected_type(&Context::new()), Ok(Type::Integer))
|
||||
|
@ -3,17 +3,21 @@ use crate::{
|
||||
error::{RuntimeError, ValidationError},
|
||||
};
|
||||
|
||||
use super::{AbstractTree, Action, Block, Expression, Type};
|
||||
use super::{AbstractTree, Action, Block, Expression, Positioned, Type};
|
||||
|
||||
#[derive(Clone, Debug, Eq, PartialEq, PartialOrd, Ord)]
|
||||
pub struct IfElse {
|
||||
if_expression: Expression,
|
||||
if_block: Block,
|
||||
else_block: Option<Block>,
|
||||
if_expression: Positioned<Expression>,
|
||||
if_block: Positioned<Block>,
|
||||
else_block: Option<Positioned<Block>>,
|
||||
}
|
||||
|
||||
impl IfElse {
|
||||
pub fn new(if_expression: Expression, if_block: Block, else_block: Option<Block>) -> Self {
|
||||
pub fn new(
|
||||
if_expression: Positioned<Expression>,
|
||||
if_block: Positioned<Block>,
|
||||
else_block: Option<Positioned<Block>>,
|
||||
) -> Self {
|
||||
Self {
|
||||
if_expression,
|
||||
if_block,
|
||||
@ -24,16 +28,22 @@ impl IfElse {
|
||||
|
||||
impl AbstractTree for IfElse {
|
||||
fn expected_type(&self, _context: &Context) -> Result<Type, ValidationError> {
|
||||
self.if_block.expected_type(_context)
|
||||
self.if_block.node.expected_type(_context)
|
||||
}
|
||||
|
||||
fn validate(&self, context: &Context) -> Result<(), ValidationError> {
|
||||
if let Type::Boolean = self.if_expression.expected_type(context)? {
|
||||
if let Type::Boolean = self.if_expression.node.expected_type(context)? {
|
||||
if let Some(else_block) = &self.else_block {
|
||||
let expected = self.if_block.expected_type(context)?;
|
||||
let actual = else_block.expected_type(context)?;
|
||||
let expected = self.if_block.node.expected_type(context)?;
|
||||
let actual = else_block.node.expected_type(context)?;
|
||||
|
||||
expected.check(&actual)?;
|
||||
expected
|
||||
.check(&actual)
|
||||
.map_err(|conflict| ValidationError::TypeCheck {
|
||||
conflict,
|
||||
actual_position: self.if_block.position,
|
||||
expected_position: self.if_expression.position,
|
||||
})?;
|
||||
}
|
||||
|
||||
Ok(())
|
||||
@ -45,14 +55,15 @@ impl AbstractTree for IfElse {
|
||||
fn run(self, _context: &Context) -> Result<Action, RuntimeError> {
|
||||
let if_boolean = self
|
||||
.if_expression
|
||||
.node
|
||||
.run(_context)?
|
||||
.as_return_value()?
|
||||
.as_boolean()?;
|
||||
|
||||
if if_boolean {
|
||||
self.if_block.run(_context)
|
||||
self.if_block.node.run(_context)
|
||||
} else if let Some(else_statement) = self.else_block {
|
||||
else_statement.run(_context)
|
||||
else_statement.node.run(_context)
|
||||
} else {
|
||||
Ok(Action::None)
|
||||
}
|
||||
@ -72,11 +83,11 @@ mod tests {
|
||||
fn simple_if() {
|
||||
assert_eq!(
|
||||
IfElse::new(
|
||||
Expression::Value(ValueNode::Boolean(true)),
|
||||
Block::new(vec![Statement::expression(
|
||||
Expression::Value(ValueNode::String("foo".to_string())),
|
||||
(0..0).into()
|
||||
)]),
|
||||
Expression::Value(ValueNode::Boolean(true)).positioned((0, 0)),
|
||||
Block::new(vec![Statement::Expression(Expression::Value(
|
||||
ValueNode::String("foo".to_string())
|
||||
),)])
|
||||
.positioned((0, 0)),
|
||||
None
|
||||
)
|
||||
.run(&Context::new()),
|
||||
@ -88,15 +99,17 @@ mod tests {
|
||||
fn simple_if_else() {
|
||||
assert_eq!(
|
||||
IfElse::new(
|
||||
Expression::Value(ValueNode::Boolean(false)),
|
||||
Block::new(vec![Statement::expression(
|
||||
Expression::Value(ValueNode::String("foo".to_string())),
|
||||
(0..0).into()
|
||||
),]),
|
||||
Some(Block::new(vec![Statement::expression(
|
||||
Expression::Value(ValueNode::String("bar".to_string())),
|
||||
(0..0).into()
|
||||
)]))
|
||||
Expression::Value(ValueNode::Boolean(false)).positioned((0, 0)),
|
||||
Block::new(vec![Statement::Expression(Expression::Value(
|
||||
ValueNode::String("foo".to_string())
|
||||
))])
|
||||
.positioned((0, 0)),
|
||||
Some(
|
||||
Block::new(vec![Statement::Expression(Expression::Value(
|
||||
ValueNode::String("bar".to_string())
|
||||
))])
|
||||
.positioned((0, 0))
|
||||
)
|
||||
)
|
||||
.run(&Context::new()),
|
||||
Ok(Action::Return(Value::string("bar".to_string())))
|
||||
|
39
src/abstract_tree/item.rs
Normal file
39
src/abstract_tree/item.rs
Normal file
@ -0,0 +1,39 @@
|
||||
use super::{AbstractTree, Expression, Positioned, Statement};
|
||||
|
||||
#[derive(Clone, Debug, Eq, PartialEq, PartialOrd, Ord)]
|
||||
pub enum Item {
|
||||
Expression(Positioned<Expression>),
|
||||
Statement(Positioned<Statement>),
|
||||
}
|
||||
|
||||
impl Item {
|
||||
pub fn position(&self) -> &(usize, usize) {
|
||||
match self {
|
||||
Item::Expression((_, position)) => position,
|
||||
Item::Statement((_, position)) => position,
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl AbstractTree for Item {
|
||||
fn expected_type(
|
||||
&self,
|
||||
context: &crate::context::Context,
|
||||
) -> Result<super::Type, crate::error::ValidationError> {
|
||||
todo!()
|
||||
}
|
||||
|
||||
fn validate(
|
||||
&self,
|
||||
context: &crate::context::Context,
|
||||
) -> Result<(), crate::error::ValidationError> {
|
||||
todo!()
|
||||
}
|
||||
|
||||
fn run(
|
||||
self,
|
||||
context: &crate::context::Context,
|
||||
) -> Result<super::Action, crate::error::RuntimeError> {
|
||||
todo!()
|
||||
}
|
||||
}
|
@ -36,10 +36,23 @@ use crate::{
|
||||
Value,
|
||||
};
|
||||
|
||||
pub trait AbstractTree {
|
||||
#[derive(Clone, Debug, Eq, PartialEq, PartialOrd, Ord)]
|
||||
pub struct Positioned<T> {
|
||||
pub node: T,
|
||||
pub position: (usize, usize),
|
||||
}
|
||||
|
||||
pub trait AbstractTree: Sized {
|
||||
fn expected_type(&self, context: &Context) -> Result<Type, ValidationError>;
|
||||
fn validate(&self, context: &Context) -> Result<(), ValidationError>;
|
||||
fn run(self, context: &Context) -> Result<Action, RuntimeError>;
|
||||
|
||||
fn positioned(self, position: (usize, usize)) -> Positioned<Self> {
|
||||
Positioned {
|
||||
node: self,
|
||||
position,
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
#[derive(Debug, Clone, Eq, PartialEq, PartialOrd, Ord)]
|
||||
|
@ -8,72 +8,7 @@ use crate::{
|
||||
use super::{AbstractTree, Action, Assignment, Block, Expression, IfElse, Loop, Type, While};
|
||||
|
||||
#[derive(Clone, Debug, Eq, PartialEq, PartialOrd, Ord)]
|
||||
pub struct Statement {
|
||||
pub inner: StatementInner,
|
||||
pub span: (usize, usize),
|
||||
}
|
||||
|
||||
impl Statement {
|
||||
pub fn assignment(assignment: Assignment, span: SimpleSpan) -> Self {
|
||||
Statement {
|
||||
inner: StatementInner::Assignment(assignment),
|
||||
span: (span.start(), span.end()),
|
||||
}
|
||||
}
|
||||
|
||||
pub fn block(block: Block, span: SimpleSpan) -> Self {
|
||||
Statement {
|
||||
inner: StatementInner::Block(block),
|
||||
span: (span.start(), span.end()),
|
||||
}
|
||||
}
|
||||
|
||||
pub fn r#break(span: SimpleSpan) -> Self {
|
||||
Statement {
|
||||
inner: StatementInner::Break,
|
||||
span: (span.start(), span.end()),
|
||||
}
|
||||
}
|
||||
|
||||
pub fn expression(expression: Expression, span: SimpleSpan) -> Self {
|
||||
Statement {
|
||||
inner: StatementInner::Expression(expression),
|
||||
span: (span.start(), span.end()),
|
||||
}
|
||||
}
|
||||
|
||||
pub fn if_else(if_else: IfElse, span: SimpleSpan) -> Self {
|
||||
Statement {
|
||||
inner: StatementInner::IfElse(if_else),
|
||||
span: (span.start(), span.end()),
|
||||
}
|
||||
}
|
||||
|
||||
pub fn r#loop(r#loop: Loop, span: SimpleSpan) -> Self {
|
||||
Statement {
|
||||
inner: StatementInner::Loop(r#loop),
|
||||
span: (span.start(), span.end()),
|
||||
}
|
||||
}
|
||||
|
||||
pub fn r#while(r#while: While, span: SimpleSpan) -> Self {
|
||||
Statement {
|
||||
inner: StatementInner::While(r#while),
|
||||
span: (span.start(), span.end()),
|
||||
}
|
||||
}
|
||||
|
||||
pub fn span(&self) -> (usize, usize) {
|
||||
self.span
|
||||
}
|
||||
|
||||
pub fn inner(&self) -> &StatementInner {
|
||||
&self.inner
|
||||
}
|
||||
}
|
||||
|
||||
#[derive(Clone, Debug, Eq, PartialEq, PartialOrd, Ord)]
|
||||
pub enum StatementInner {
|
||||
pub enum Statement {
|
||||
Assignment(Assignment),
|
||||
Block(Block),
|
||||
Break,
|
||||
@ -85,7 +20,7 @@ pub enum StatementInner {
|
||||
|
||||
impl AbstractTree for Statement {
|
||||
fn expected_type(&self, _context: &Context) -> Result<Type, ValidationError> {
|
||||
match &self.inner {
|
||||
match self {
|
||||
StatementInner::Assignment(assignment) => assignment.expected_type(_context),
|
||||
StatementInner::Block(block) => block.expected_type(_context),
|
||||
StatementInner::Break => Ok(Type::None),
|
||||
@ -97,7 +32,7 @@ impl AbstractTree for Statement {
|
||||
}
|
||||
|
||||
fn validate(&self, _context: &Context) -> Result<(), ValidationError> {
|
||||
match &self.inner {
|
||||
match self {
|
||||
StatementInner::Assignment(assignment) => assignment.validate(_context),
|
||||
StatementInner::Block(block) => block.validate(_context),
|
||||
StatementInner::Break => Ok(()),
|
||||
@ -109,7 +44,7 @@ impl AbstractTree for Statement {
|
||||
}
|
||||
|
||||
fn run(self, _context: &Context) -> Result<Action, RuntimeError> {
|
||||
match self.inner {
|
||||
match self {
|
||||
StatementInner::Assignment(assignment) => assignment.run(_context),
|
||||
StatementInner::Block(block) => block.run(_context),
|
||||
StatementInner::Break => Ok(Action::Break),
|
||||
|
@ -3,7 +3,7 @@ use std::fmt::{self, Display, Formatter};
|
||||
use crate::{
|
||||
abstract_tree::Identifier,
|
||||
context::Context,
|
||||
error::{RuntimeError, TypeCheckError, ValidationError},
|
||||
error::{RuntimeError, TypeConflict, ValidationError},
|
||||
};
|
||||
|
||||
use super::{AbstractTree, Action};
|
||||
@ -29,7 +29,7 @@ pub enum Type {
|
||||
}
|
||||
|
||||
impl Type {
|
||||
pub fn check(&self, other: &Type) -> Result<(), TypeCheckError> {
|
||||
pub fn check(&self, other: &Type) -> Result<(), TypeConflict> {
|
||||
match (self, other) {
|
||||
(Type::Any, _)
|
||||
| (_, Type::Any)
|
||||
@ -49,7 +49,7 @@ impl Type {
|
||||
if left == right {
|
||||
Ok(())
|
||||
} else {
|
||||
Err(TypeCheckError {
|
||||
Err(TypeConflict {
|
||||
actual: other.clone(),
|
||||
expected: self.clone(),
|
||||
})
|
||||
@ -59,7 +59,7 @@ impl Type {
|
||||
if let Ok(()) = left.check(right) {
|
||||
Ok(())
|
||||
} else {
|
||||
Err(TypeCheckError {
|
||||
Err(TypeConflict {
|
||||
actual: left.as_ref().clone(),
|
||||
expected: right.as_ref().clone(),
|
||||
})
|
||||
@ -86,7 +86,7 @@ impl Type {
|
||||
|
||||
Ok(())
|
||||
}
|
||||
_ => Err(TypeCheckError {
|
||||
_ => Err(TypeConflict {
|
||||
actual: other.clone(),
|
||||
expected: self.clone(),
|
||||
}),
|
||||
@ -188,14 +188,14 @@ mod tests {
|
||||
|
||||
assert_eq!(
|
||||
foo.check(&bar),
|
||||
Err(TypeCheckError {
|
||||
Err(TypeConflict {
|
||||
actual: bar.clone(),
|
||||
expected: foo.clone()
|
||||
})
|
||||
);
|
||||
assert_eq!(
|
||||
bar.check(&foo),
|
||||
Err(TypeCheckError {
|
||||
Err(TypeConflict {
|
||||
actual: foo.clone(),
|
||||
expected: bar.clone()
|
||||
})
|
||||
@ -222,7 +222,7 @@ mod tests {
|
||||
|
||||
assert_eq!(
|
||||
left.check(right),
|
||||
Err(TypeCheckError {
|
||||
Err(TypeConflict {
|
||||
actual: right.clone(),
|
||||
expected: left.clone()
|
||||
})
|
||||
|
61
src/error.rs
61
src/error.rs
@ -19,10 +19,7 @@ pub enum Error {
|
||||
span: (usize, usize),
|
||||
},
|
||||
Runtime(RuntimeError),
|
||||
Validation {
|
||||
error: ValidationError,
|
||||
span: (usize, usize),
|
||||
},
|
||||
Validation(ValidationError),
|
||||
}
|
||||
|
||||
impl Error {
|
||||
@ -49,33 +46,38 @@ impl Error {
|
||||
.finish()
|
||||
}
|
||||
Error::Runtime(_) => todo!(),
|
||||
Error::Validation { error, span } => {
|
||||
let mut report = Report::build(
|
||||
ReportKind::Custom("Validation Error", Color::White),
|
||||
(),
|
||||
span.0,
|
||||
);
|
||||
Error::Validation(validation_error) => {
|
||||
let mut report =
|
||||
Report::build(ReportKind::Custom("Validation Error", Color::White), (), 0);
|
||||
|
||||
match error {
|
||||
match validation_error {
|
||||
ValidationError::ExpectedBoolean => {
|
||||
report = report.with_label(
|
||||
Label::new(span.0..span.1).with_message("Expected boolean."),
|
||||
);
|
||||
report =
|
||||
report.with_label(Label::new(0..0).with_message("Expected boolean."));
|
||||
}
|
||||
ValidationError::ExpectedIntegerOrFloat => {
|
||||
report = report.with_label(
|
||||
Label::new(span.0..span.1).with_message("Expected integer or float."),
|
||||
Label::new(0..0).with_message("Expected integer or float."),
|
||||
);
|
||||
}
|
||||
ValidationError::RwLockPoison(_) => todo!(),
|
||||
ValidationError::TypeCheck(TypeCheckError { actual, expected }) => {
|
||||
report = report.with_label(Label::new(span.0..span.1).with_message(
|
||||
format!("Type error. Expected {expected} but got {actual}."),
|
||||
));
|
||||
ValidationError::TypeCheck {
|
||||
conflict,
|
||||
actual_position,
|
||||
expected_position: expected_postion,
|
||||
} => {
|
||||
let TypeConflict { actual, expected } = conflict;
|
||||
|
||||
report = report.with_labels([
|
||||
Label::new(expected_postion.0..expected_postion.1)
|
||||
.with_message(format!("Type {expected} established here.")),
|
||||
Label::new(actual_position.0..actual_position.1)
|
||||
.with_message(format!("Got type {actual} here.")),
|
||||
]);
|
||||
}
|
||||
ValidationError::VariableNotFound(identifier) => {
|
||||
report = report
|
||||
.with_label(Label::new(span.0..span.1).with_message(format!(
|
||||
.with_label(Label::new(0..0).with_message(format!(
|
||||
"The variable {identifier} does not exist."
|
||||
)));
|
||||
}
|
||||
@ -144,7 +146,16 @@ pub enum ValidationError {
|
||||
ExpectedValue,
|
||||
InterpreterExpectedReturn,
|
||||
RwLockPoison(RwLockPoisonError),
|
||||
TypeCheck(TypeCheckError),
|
||||
TypeCheck {
|
||||
/// The mismatch that caused the error.
|
||||
conflict: TypeConflict,
|
||||
|
||||
/// The position of the item that gave the "actual" type.
|
||||
actual_position: (usize, usize),
|
||||
|
||||
/// The position of the item that gave the "expected" type.
|
||||
expected_position: (usize, usize),
|
||||
},
|
||||
VariableNotFound(Identifier),
|
||||
}
|
||||
|
||||
@ -154,12 +165,6 @@ impl From<RwLockPoisonError> for ValidationError {
|
||||
}
|
||||
}
|
||||
|
||||
impl From<TypeCheckError> for ValidationError {
|
||||
fn from(error: TypeCheckError) -> Self {
|
||||
ValidationError::TypeCheck(error)
|
||||
}
|
||||
}
|
||||
|
||||
#[derive(Debug, PartialEq)]
|
||||
pub struct RwLockPoisonError;
|
||||
|
||||
@ -170,7 +175,7 @@ impl<T> From<PoisonError<T>> for RwLockPoisonError {
|
||||
}
|
||||
|
||||
#[derive(Debug, PartialEq)]
|
||||
pub struct TypeCheckError {
|
||||
pub struct TypeConflict {
|
||||
pub actual: Type,
|
||||
pub expected: Type,
|
||||
}
|
||||
|
@ -36,11 +36,8 @@ impl Interpreter {
|
||||
.filter_map(|statement| {
|
||||
statement
|
||||
.validate(&self.context)
|
||||
.map_err(|validation_error| Error::Validation {
|
||||
error: validation_error,
|
||||
span: statement.span(),
|
||||
})
|
||||
.err()
|
||||
.map(|validation_error| Error::Validation(validation_error))
|
||||
})
|
||||
.collect::<Vec<Error>>();
|
||||
|
||||
|
@ -2,7 +2,7 @@ use std::collections::BTreeMap;
|
||||
|
||||
use dust_lang::{
|
||||
abstract_tree::{Identifier, Type},
|
||||
error::{Error, TypeCheckError, ValidationError},
|
||||
error::{Error, TypeConflict, ValidationError},
|
||||
*,
|
||||
};
|
||||
|
||||
@ -136,7 +136,7 @@ fn map_type_errors() {
|
||||
assert_eq!(
|
||||
interpret("{ foo : bool = 'bar' }"),
|
||||
Err(vec![Error::Validation {
|
||||
error: ValidationError::TypeCheck(TypeCheckError {
|
||||
error: ValidationError::TypeCheck(TypeConflict {
|
||||
actual: Type::String,
|
||||
expected: Type::Boolean
|
||||
}),
|
||||
|
@ -1,6 +1,6 @@
|
||||
use dust_lang::{
|
||||
abstract_tree::{Block, Expression, Identifier, Statement, Type},
|
||||
error::{Error, TypeCheckError, ValidationError},
|
||||
error::{Error, TypeConflict, ValidationError},
|
||||
*,
|
||||
};
|
||||
|
||||
@ -25,7 +25,7 @@ fn set_variable_with_type_error() {
|
||||
assert_eq!(
|
||||
interpret("foobar: str = true"),
|
||||
Err(vec![Error::Validation {
|
||||
error: ValidationError::TypeCheck(TypeCheckError {
|
||||
error: ValidationError::TypeCheck(TypeConflict {
|
||||
actual: Type::Boolean,
|
||||
expected: Type::String
|
||||
}),
|
||||
|
Loading…
Reference in New Issue
Block a user