1
0

Improve errors

This commit is contained in:
Jeff 2024-03-18 05:39:09 -04:00
parent 1750132ed8
commit 7dcfccf7cb
14 changed files with 508 additions and 413 deletions

View File

@ -1,6 +1,7 @@
use crate::{
error::{RuntimeError, ValidationError},
Context,
value::ValueInner,
Context, Value,
};
use super::{AbstractTree, Action, Identifier, Statement, Type, WithPosition};
@ -70,40 +71,94 @@ impl AbstractTree for Assignment {
fn run(self, context: &Context) -> Result<Action, RuntimeError> {
let action = self.statement.node.run(context)?;
let value = match action {
let right = match action {
Action::Return(value) => value,
r#break => return Ok(r#break),
};
match self.operator {
AssignmentOperator::Assign => {
context.set_value(self.identifier.node, value)?;
context.set_value(self.identifier.node, right)?;
}
AssignmentOperator::AddAssign => {
if let Some(previous_value) = context.get_value(&self.identifier.node)? {
let new_value = previous_value.add(&value)?;
if let Some(left) = context.get_value(&self.identifier.node)? {
let new_value = match (left.inner().as_ref(), right.inner().as_ref()) {
(ValueInner::Integer(left), ValueInner::Integer(right)) => {
let sum = left.saturating_add(*right);
Value::integer(sum)
}
(ValueInner::Float(left), ValueInner::Float(right)) => {
let sum = left + right;
Value::float(sum)
}
(ValueInner::Float(left), ValueInner::Integer(right)) => {
let sum = left + *right as f64;
Value::float(sum)
}
(ValueInner::Integer(left), ValueInner::Float(right)) => {
let sum = *left as f64 + right;
Value::float(sum)
}
(ValueInner::Integer(_) | ValueInner::Float(_), _) => {
return Err(RuntimeError::ValidationFailure(
ValidationError::ExpectedIntegerOrFloat(self.statement.position),
))
}
_ => {
return Err(RuntimeError::ValidationFailure(
ValidationError::ExpectedIntegerOrFloat(self.identifier.position),
))
}
};
context.set_value(self.identifier.node, new_value)?;
} else {
return Err(RuntimeError::ValidationFailure(
ValidationError::VariableNotFound {
identifier: self.identifier.node,
position: self.identifier.position,
},
ValidationError::VariableNotFound(self.identifier.node),
));
}
}
AssignmentOperator::SubAssign => {
if let Some(previous_value) = context.get_value(&self.identifier.node)? {
let new_value = previous_value.subtract(&value)?;
if let Some(left) = context.get_value(&self.identifier.node)? {
let new_value = match (left.inner().as_ref(), right.inner().as_ref()) {
(ValueInner::Integer(left), ValueInner::Integer(right)) => {
let difference = left.saturating_sub(*right);
Value::integer(difference)
}
(ValueInner::Float(left), ValueInner::Float(right)) => {
let difference = left - right;
Value::float(difference)
}
(ValueInner::Float(left), ValueInner::Integer(right)) => {
let difference = left - *right as f64;
Value::float(difference)
}
(ValueInner::Integer(left), ValueInner::Float(right)) => {
let difference = *left as f64 - right;
Value::float(difference)
}
(ValueInner::Integer(_) | ValueInner::Float(_), _) => {
return Err(RuntimeError::ValidationFailure(
ValidationError::ExpectedIntegerOrFloat(self.statement.position),
))
}
_ => {
return Err(RuntimeError::ValidationFailure(
ValidationError::ExpectedIntegerOrFloat(self.identifier.position),
))
}
};
context.set_value(self.identifier.node, new_value)?;
} else {
return Err(RuntimeError::ValidationFailure(
ValidationError::VariableNotFound {
identifier: self.identifier.node,
position: self.identifier.position,
},
ValidationError::VariableNotFound(self.identifier.node),
));
}
}
@ -118,7 +173,6 @@ mod tests {
use crate::{
abstract_tree::{Expression, ValueNode},
error::TypeConflict,
Value,
};
use super::*;

View File

@ -28,10 +28,7 @@ impl AbstractTree for Identifier {
if let Some(r#type) = context.get_type(self)? {
Ok(r#type)
} else {
Err(ValidationError::VariableNotFound {
identifier: todo!(),
position: todo!(),
})
Err(ValidationError::VariableNotFound(self.clone()))
}
}
@ -39,10 +36,7 @@ impl AbstractTree for Identifier {
if context.contains(self)? {
Ok(())
} else {
Err(ValidationError::VariableNotFound {
identifier: todo!(),
position: todo!(),
})
Err(ValidationError::VariableNotFound(self.clone()))
}
}
@ -53,10 +47,7 @@ impl AbstractTree for Identifier {
Ok(action)
} else {
Err(RuntimeError::ValidationFailure(
ValidationError::VariableNotFound {
identifier: todo!(),
position: todo!(),
},
ValidationError::VariableNotFound(self.clone()),
))
}
}

View File

@ -64,7 +64,14 @@ impl AbstractTree for IfElse {
}
fn run(self, _context: &Context) -> Result<Action, RuntimeError> {
let value = self.if_expression.node.run(_context)?.as_return_value()?;
let action = self.if_expression.node.run(_context)?;
let value = if let Action::Return(value) = action {
value
} else {
return Err(RuntimeError::ValidationFailure(
ValidationError::InterpreterExpectedReturn(self.if_expression.position),
));
};
if let ValueInner::Boolean(if_boolean) = value.inner().as_ref() {
if *if_boolean {

View File

@ -69,8 +69,22 @@ impl AbstractTree for ListIndex {
}
fn run(self, _context: &Context) -> Result<Action, RuntimeError> {
let left_value = self.left.node.run(_context)?.as_return_value()?;
let right_value = self.right.node.run(_context)?.as_return_value()?;
let left_action = self.left.node.run(_context)?;
let left_value = if let Action::Return(value) = left_action {
value
} else {
return Err(RuntimeError::ValidationFailure(
ValidationError::InterpreterExpectedReturn(self.left.position),
));
};
let right_action = self.right.node.run(_context)?;
let right_value = if let Action::Return(value) = right_action {
value
} else {
return Err(RuntimeError::ValidationFailure(
ValidationError::InterpreterExpectedReturn(self.left.position),
));
};
if let (Some(list), Some(index)) = (left_value.as_list(), right_value.as_integer()) {
let found_item = list.get(index as usize);

View File

@ -84,110 +84,100 @@ impl AbstractTree for Logic {
}
fn run(self, _context: &Context) -> Result<Action, RuntimeError> {
let boolean = match self {
Logic::Equal(left, right) => {
let left = left.node.run(_context)?.as_return_value()?;
let right = right.node.run(_context)?.as_return_value()?;
left == right
}
Logic::NotEqual(left, right) => {
let left = left.node.run(_context)?.as_return_value()?;
let right = right.node.run(_context)?.as_return_value()?;
left != right
}
Logic::Greater(left, right) => {
let left = left.node.run(_context)?.as_return_value()?;
let right = right.node.run(_context)?.as_return_value()?;
left > right
}
Logic::Less(left, right) => {
let left = left.node.run(_context)?.as_return_value()?;
let right = right.node.run(_context)?.as_return_value()?;
left < right
}
Logic::GreaterOrEqual(left, right) => {
let left = left.node.run(_context)?.as_return_value()?;
let right = right.node.run(_context)?.as_return_value()?;
left >= right
}
Logic::LessOrEqual(left, right) => {
let left = left.node.run(_context)?.as_return_value()?;
let right = right.node.run(_context)?.as_return_value()?;
left <= right
}
Logic::And(left, right) => {
let left_value = left.node.run(_context)?.as_return_value()?;
let right_value = right.node.run(_context)?.as_return_value()?;
let left = if let ValueInner::Boolean(boolean) = left_value.inner().as_ref() {
boolean
let run_and_expect_value =
|expression: WithPosition<Expression>| -> Result<Value, RuntimeError> {
let action = expression.node.run(_context)?;
let value = if let Action::Return(value) = action {
value
} else {
return Err(RuntimeError::ValidationFailure(
ValidationError::ExpectedBoolean {
actual: left_value.r#type(),
position: left.position,
},
));
};
let right = if let ValueInner::Boolean(boolean) = right_value.inner().as_ref() {
boolean
} else {
return Err(RuntimeError::ValidationFailure(
ValidationError::ExpectedBoolean {
actual: right_value.r#type(),
position: right.position,
},
ValidationError::InterpreterExpectedReturn(expression.position),
));
};
*left && *right
}
Logic::Or(left, right) => {
let left_value = left.node.run(_context)?.as_return_value()?;
let right_value = right.node.run(_context)?.as_return_value()?;
let left = if let ValueInner::Boolean(boolean) = left_value.inner().as_ref() {
boolean
} else {
return Err(RuntimeError::ValidationFailure(
ValidationError::ExpectedBoolean {
actual: left_value.r#type(),
position: left.position,
},
));
};
let right = if let ValueInner::Boolean(boolean) = right_value.inner().as_ref() {
boolean
} else {
return Err(RuntimeError::ValidationFailure(
ValidationError::ExpectedBoolean {
actual: right_value.r#type(),
position: right.position,
},
));
Ok(value)
};
*left || *right
}
Logic::Not(statement) => {
let value = statement.node.run(_context)?.as_return_value()?;
let run_and_expect_boolean =
|expression: WithPosition<Expression>| -> Result<bool, RuntimeError> {
let action = expression.node.run(_context)?;
let value = if let Action::Return(value) = action {
value
} else {
return Err(RuntimeError::ValidationFailure(
ValidationError::InterpreterExpectedReturn(expression.position),
));
};
if let ValueInner::Boolean(boolean) = value.inner().as_ref() {
!boolean
Ok(*boolean)
} else {
return Err(RuntimeError::ValidationFailure(
ValidationError::ExpectedBoolean {
actual: value.r#type(),
position: statement.position,
position: expression.position,
},
));
}
};
let boolean = match self {
Logic::Equal(left, right) => {
let (left_value, right_value) =
(run_and_expect_value(left)?, run_and_expect_value(right)?);
left_value == right_value
}
Logic::NotEqual(left, right) => {
let (left_value, right_value) =
(run_and_expect_value(left)?, run_and_expect_value(right)?);
left_value != right_value
}
Logic::Greater(left, right) => {
let (left_value, right_value) =
(run_and_expect_value(left)?, run_and_expect_value(right)?);
left_value > right_value
}
Logic::Less(left, right) => {
let (left_value, right_value) =
(run_and_expect_value(left)?, run_and_expect_value(right)?);
left_value < right_value
}
Logic::GreaterOrEqual(left, right) => {
let (left_value, right_value) =
(run_and_expect_value(left)?, run_and_expect_value(right)?);
left_value >= right_value
}
Logic::LessOrEqual(left, right) => {
let (left_value, right_value) =
(run_and_expect_value(left)?, run_and_expect_value(right)?);
left_value <= right_value
}
Logic::And(left, right) => {
let (left_boolean, right_boolean) = (
run_and_expect_boolean(left)?,
run_and_expect_boolean(right)?,
);
left_boolean && right_boolean
}
Logic::Or(left, right) => {
let (left_boolean, right_boolean) = (
run_and_expect_boolean(left)?,
run_and_expect_boolean(right)?,
);
left_boolean || right_boolean
}
Logic::Not(statement) => {
let boolean = run_and_expect_boolean(statement)?;
!boolean
}
};
@ -203,148 +193,124 @@ mod tests {
#[test]
fn equal() {
assert!(Logic::Equal(
assert_eq!(
Logic::Equal(
Expression::Value(ValueNode::Integer(42)).with_position((0, 0)),
Expression::Value(ValueNode::Integer(42)).with_position((0, 0)),
)
.run(&Context::new())
.unwrap()
.as_return_value()
.unwrap()
.as_boolean()
.unwrap())
.run(&Context::new()),
Ok(Action::Return(Value::boolean(true)))
)
}
#[test]
fn not_equal() {
assert!(Logic::NotEqual(
assert_eq!(
Logic::NotEqual(
Expression::Value(ValueNode::Integer(42)).with_position((0, 0)),
Expression::Value(ValueNode::Integer(43)).with_position((0, 0)),
)
.run(&Context::new())
.unwrap()
.as_return_value()
.unwrap()
.as_boolean()
.unwrap())
.run(&Context::new()),
Ok(Action::Return(Value::boolean(true)))
)
}
#[test]
fn greater() {
assert!(Logic::Greater(
assert_eq!(
Logic::Greater(
Expression::Value(ValueNode::Integer(43)).with_position((0, 0)),
Expression::Value(ValueNode::Integer(42)).with_position((0, 0)),
)
.run(&Context::new())
.unwrap()
.as_return_value()
.unwrap()
.as_boolean()
.unwrap())
.run(&Context::new()),
Ok(Action::Return(Value::boolean(true)))
)
}
#[test]
fn less() {
assert!(Logic::Less(
assert_eq!(
Logic::Less(
Expression::Value(ValueNode::Integer(42)).with_position((0, 0)),
Expression::Value(ValueNode::Integer(43)).with_position((0, 0)),
)
.run(&Context::new())
.unwrap()
.as_return_value()
.unwrap()
.as_boolean()
.unwrap())
.run(&Context::new()),
Ok(Action::Return(Value::boolean(true)))
)
}
#[test]
fn greater_or_equal() {
assert!(Logic::GreaterOrEqual(
assert_eq!(
Logic::GreaterOrEqual(
Expression::Value(ValueNode::Integer(42)).with_position((0, 0)),
Expression::Value(ValueNode::Integer(41)).with_position((0, 0)),
)
.run(&Context::new())
.unwrap()
.as_return_value()
.unwrap()
.as_boolean()
.unwrap());
.run(&Context::new()),
Ok(Action::Return(Value::boolean(true)))
);
assert!(Logic::GreaterOrEqual(
assert_eq!(
Logic::GreaterOrEqual(
Expression::Value(ValueNode::Integer(42)).with_position((0, 0)),
Expression::Value(ValueNode::Integer(42)).with_position((0, 0)),
)
.run(&Context::new())
.unwrap()
.as_return_value()
.unwrap()
.as_boolean()
.unwrap())
.run(&Context::new()),
Ok(Action::Return(Value::boolean(true)))
);
}
#[test]
fn less_or_equal() {
assert!(Logic::LessOrEqual(
assert_eq!(
Logic::LessOrEqual(
Expression::Value(ValueNode::Integer(41)).with_position((0, 0)),
Expression::Value(ValueNode::Integer(42)).with_position((0, 0)),
Expression::Value(ValueNode::Integer(43)).with_position((0, 0)),
)
.run(&Context::new())
.unwrap()
.as_return_value()
.unwrap()
.as_boolean()
.unwrap());
.run(&Context::new()),
Ok(Action::Return(Value::boolean(true)))
);
assert!(Logic::LessOrEqual(
assert_eq!(
Logic::LessOrEqual(
Expression::Value(ValueNode::Integer(42)).with_position((0, 0)),
Expression::Value(ValueNode::Integer(42)).with_position((0, 0)),
)
.run(&Context::new())
.unwrap()
.as_return_value()
.unwrap()
.as_boolean()
.unwrap())
.run(&Context::new()),
Ok(Action::Return(Value::boolean(true)))
);
}
#[test]
fn and() {
assert!(Logic::And(
assert_eq!(
Logic::And(
Expression::Value(ValueNode::Boolean(true)).with_position((0, 0)),
Expression::Value(ValueNode::Boolean(true)).with_position((0, 0)),
)
.run(&Context::new())
.unwrap()
.as_return_value()
.unwrap()
.as_boolean()
.unwrap())
.run(&Context::new()),
Ok(Action::Return(Value::boolean(true)))
)
}
#[test]
fn or() {
assert!(Logic::Or(
assert_eq!(
Logic::Or(
Expression::Value(ValueNode::Boolean(true)).with_position((0, 0)),
Expression::Value(ValueNode::Boolean(false)).with_position((0, 0)),
)
.run(&Context::new())
.unwrap()
.as_return_value()
.unwrap()
.as_boolean()
.unwrap())
.run(&Context::new()),
Ok(Action::Return(Value::boolean(true)))
)
}
#[test]
fn not() {
assert!(
Logic::Not(Expression::Value(ValueNode::Boolean(false)).with_position((0, 0)))
.run(&Context::new())
.unwrap()
.as_return_value()
.unwrap()
.as_boolean()
.unwrap()
assert_eq!(
Logic::Not(Expression::Value(ValueNode::Boolean(false)).with_position((0, 0)),)
.run(&Context::new()),
Ok(Action::Return(Value::boolean(true)))
)
}
}

View File

@ -90,7 +90,7 @@ mod tests {
fn complex_loop() {
let action = Block::new(vec![
Statement::Assignment(Assignment::new(
Identifier::new("i"),
Identifier::new("i").with_position((0, 0)),
None,
AssignmentOperator::Assign,
Statement::Expression(Expression::Value(ValueNode::Integer(1)))
@ -105,7 +105,7 @@ mod tests {
.with_position((10, 15)),
Block::new(vec![Statement::Break.with_position((18, 24))]),
Some(Block::new(vec![Statement::Assignment(Assignment::new(
Identifier::new("i"),
Identifier::new("i").with_position((0, 0)),
None,
AssignmentOperator::AddAssign,
Statement::Expression(Expression::Value(ValueNode::Integer(1)))

View File

@ -39,9 +39,10 @@ impl AbstractTree for MapIndex {
return if let Some(value) = map.get(index_identifier) {
Ok(value.r#type())
} else {
Err(ValidationError::PropertyNotFound(
collection_identifier.clone(),
))
Err(ValidationError::PropertyNotFound {
identifier: index_identifier.clone(),
position: self.right.position,
})
};
};
}
@ -72,7 +73,7 @@ impl AbstractTree for MapIndex {
Err(ValidationError::CannotIndexWith {
collection_type: left_type,
collection_position: todo!(),
collection_position: self.left.position,
index_type: self.right.node.expected_type(_context)?,
index_position: self.right.position,
})
@ -100,7 +101,14 @@ impl AbstractTree for MapIndex {
}
fn run(self, _context: &Context) -> Result<Action, RuntimeError> {
let collection = self.left.node.run(_context)?.as_return_value()?;
let action = self.left.node.run(_context)?;
let collection = if let Action::Return(value) = action {
value
} else {
return Err(RuntimeError::ValidationFailure(
ValidationError::InterpreterExpectedReturn(self.left.position),
));
};
if let (ValueInner::Map(map), Expression::Identifier(identifier)) =
(collection.inner().as_ref(), &self.right.node)
@ -115,7 +123,7 @@ impl AbstractTree for MapIndex {
Err(RuntimeError::ValidationFailure(
ValidationError::CannotIndexWith {
collection_type: collection.r#type(),
collection_position: todo!(),
collection_position: self.left.position,
index_type: self.right.node.expected_type(_context)?,
index_position: self.right.position,
},

View File

@ -5,7 +5,7 @@ use crate::{
Value,
};
use super::{AbstractTree, Action, Expression, Type, WithPosition};
use super::{AbstractTree, Action, Expression, SourcePosition, Type, WithPosition};
#[derive(Clone, Debug, Eq, PartialEq, PartialOrd, Ord)]
pub enum Math {
@ -37,71 +37,218 @@ impl AbstractTree for Math {
let left_type = left.node.expected_type(context)?;
let right_type = right.node.expected_type(context)?;
match (left_type, right_type) {
(Type::Integer, Type::Integer)
| (Type::Float, Type::Float)
| (Type::Integer, Type::Float)
| (Type::Float, Type::Integer) => Ok(()),
_ => Err(ValidationError::ExpectedIntegerOrFloat),
if let Type::Integer | Type::Float = left_type {
if let Type::Integer | Type::Float = right_type {
Ok(())
} else {
Err(ValidationError::ExpectedIntegerOrFloat(right.position))
}
} else {
Err(ValidationError::ExpectedIntegerOrFloat(left.position))
}
}
}
}
fn run(self, _context: &Context) -> Result<Action, RuntimeError> {
let value = match self {
Math::Add(left, right) => {
let left_value = left.node.run(_context)?.as_return_value()?;
let right_value = right.node.run(_context)?.as_return_value()?;
left_value.add(&right_value)?
}
Math::Subtract(left, right) => {
let left_value = left.node.run(_context)?.as_return_value()?;
let right_value = right.node.run(_context)?.as_return_value()?;
left_value.subtract(&right_value)?
}
Math::Multiply(left, right) => {
let left_value = left.node.run(_context)?.as_return_value()?;
let right_value = right.node.run(_context)?.as_return_value()?;
if let (ValueInner::Integer(left), ValueInner::Integer(right)) =
(left_value.inner().as_ref(), right_value.inner().as_ref())
{
Value::integer(left * right)
let run_and_expect_value =
|expression: Expression, position: SourcePosition| -> Result<Value, RuntimeError> {
let action = expression.run(_context)?;
let value = if let Action::Return(value) = action {
value
} else {
return Err(RuntimeError::ValidationFailure(
ValidationError::ExpectedIntegerOrFloat,
ValidationError::InterpreterExpectedReturn(position),
));
};
Ok(value)
};
let value = match self {
Math::Add(left, right) => {
let left_value = run_and_expect_value(left.node, left.position)?;
let right_value = run_and_expect_value(right.node, right.position)?;
match (left_value.inner().as_ref(), right_value.inner().as_ref()) {
(ValueInner::Integer(left), ValueInner::Integer(right)) => {
let sum = left.saturating_add(*right);
Value::integer(sum)
}
(ValueInner::Float(left), ValueInner::Float(right)) => {
let sum = left + right;
Value::float(sum)
}
(ValueInner::Float(left), ValueInner::Integer(right)) => {
let sum = left + *right as f64;
Value::float(sum)
}
(ValueInner::Integer(left), ValueInner::Float(right)) => {
let sum = *left as f64 + right;
Value::float(sum)
}
(ValueInner::Integer(_) | ValueInner::Float(_), _) => {
return Err(RuntimeError::ValidationFailure(
ValidationError::ExpectedIntegerOrFloat(right.position),
))
}
_ => {
return Err(RuntimeError::ValidationFailure(
ValidationError::ExpectedIntegerOrFloat(left.position),
))
}
}
}
Math::Subtract(left, right) => {
let left_value = run_and_expect_value(left.node, left.position)?;
let right_value = run_and_expect_value(right.node, right.position)?;
match (left_value.inner().as_ref(), right_value.inner().as_ref()) {
(ValueInner::Integer(left), ValueInner::Integer(right)) => {
let difference = left.saturating_sub(*right);
Value::integer(difference)
}
(ValueInner::Float(left), ValueInner::Float(right)) => {
let difference = left - right;
Value::float(difference)
}
(ValueInner::Float(left), ValueInner::Integer(right)) => {
let difference = left - *right as f64;
Value::float(difference)
}
(ValueInner::Integer(left), ValueInner::Float(right)) => {
let difference = *left as f64 - right;
Value::float(difference)
}
(ValueInner::Integer(_) | ValueInner::Float(_), _) => {
return Err(RuntimeError::ValidationFailure(
ValidationError::ExpectedIntegerOrFloat(right.position),
))
}
_ => {
return Err(RuntimeError::ValidationFailure(
ValidationError::ExpectedIntegerOrFloat(left.position),
))
}
}
}
Math::Multiply(left, right) => {
let left_value = run_and_expect_value(left.node, left.position)?;
let right_value = run_and_expect_value(right.node, right.position)?;
match (left_value.inner().as_ref(), right_value.inner().as_ref()) {
(ValueInner::Integer(left), ValueInner::Integer(right)) => {
let product = left.saturating_mul(*right);
Value::integer(product)
}
(ValueInner::Float(left), ValueInner::Float(right)) => {
let product = left * right;
Value::float(product)
}
(ValueInner::Float(left), ValueInner::Integer(right)) => {
let product = left * *right as f64;
Value::float(product)
}
(ValueInner::Integer(left), ValueInner::Float(right)) => {
let product = *left as f64 * right;
Value::float(product)
}
(ValueInner::Integer(_) | ValueInner::Float(_), _) => {
return Err(RuntimeError::ValidationFailure(
ValidationError::ExpectedIntegerOrFloat(right.position).into(),
))
}
_ => {
return Err(RuntimeError::ValidationFailure(
ValidationError::ExpectedIntegerOrFloat(left.position),
))
}
}
}
Math::Divide(left, right) => {
let left_value = left.node.run(_context)?.as_return_value()?;
let right_value = right.node.run(_context)?.as_return_value()?;
let left_value = run_and_expect_value(left.node, left.position)?;
let right_value = run_and_expect_value(right.node, right.position)?;
if let (ValueInner::Integer(left), ValueInner::Integer(right)) =
(left_value.inner().as_ref(), right_value.inner().as_ref())
{
Value::integer(left / right)
} else {
match (left_value.inner().as_ref(), right_value.inner().as_ref()) {
(ValueInner::Integer(left), ValueInner::Integer(right)) => {
let quotient = left.saturating_div(*right);
Value::integer(quotient)
}
(ValueInner::Float(left), ValueInner::Float(right)) => {
let quotient = left / right;
Value::float(quotient)
}
(ValueInner::Float(left), ValueInner::Integer(right)) => {
let quotient = left / *right as f64;
Value::float(quotient)
}
(ValueInner::Integer(left), ValueInner::Float(right)) => {
let quotient = *left as f64 / right;
Value::float(quotient)
}
(ValueInner::Integer(_) | ValueInner::Float(_), _) => {
return Err(RuntimeError::ValidationFailure(
ValidationError::ExpectedIntegerOrFloat,
));
ValidationError::ExpectedIntegerOrFloat(right.position).into(),
))
}
_ => {
return Err(RuntimeError::ValidationFailure(
ValidationError::ExpectedIntegerOrFloat(left.position),
))
}
}
}
Math::Modulo(left, right) => {
let left_value = left.node.run(_context)?.as_return_value()?;
let right_value = right.node.run(_context)?.as_return_value()?;
let left_value = run_and_expect_value(left.node, left.position)?;
let right_value = run_and_expect_value(right.node, right.position)?;
if let (ValueInner::Integer(left), ValueInner::Integer(right)) =
(left_value.inner().as_ref(), right_value.inner().as_ref())
{
Value::integer(left % right)
} else {
match (left_value.inner().as_ref(), right_value.inner().as_ref()) {
(ValueInner::Integer(left), ValueInner::Integer(right)) => {
let remainder = left % right;
Value::integer(remainder)
}
(ValueInner::Float(left), ValueInner::Float(right)) => {
let remainder = left % right;
Value::float(remainder)
}
(ValueInner::Float(left), ValueInner::Integer(right)) => {
let remainder = left % *right as f64;
Value::float(remainder)
}
(ValueInner::Integer(left), ValueInner::Float(right)) => {
let remainder = *left as f64 % right;
Value::float(remainder)
}
(ValueInner::Integer(_) | ValueInner::Float(_), _) => {
return Err(RuntimeError::ValidationFailure(
ValidationError::ExpectedIntegerOrFloat,
));
ValidationError::ExpectedIntegerOrFloat(right.position).into(),
))
}
_ => {
return Err(RuntimeError::ValidationFailure(
ValidationError::ExpectedIntegerOrFloat(left.position),
))
}
}
}
};

View File

@ -121,7 +121,14 @@ impl AbstractTree for ValueNode {
let mut value_list = Vec::with_capacity(expression_list.len());
for expression in expression_list {
let value = expression.node.run(_context)?.as_return_value()?;
let action = expression.node.run(_context)?;
let value = if let Action::Return(value) = action {
value
} else {
return Err(RuntimeError::ValidationFailure(
ValidationError::InterpreterExpectedReturn(expression.position),
));
};
value_list.push(value);
}
@ -132,7 +139,14 @@ impl AbstractTree for ValueNode {
let mut property_map = BTreeMap::new();
for (identifier, _type, expression) in property_list {
let value = expression.node.run(_context)?.as_return_value()?;
let action = expression.node.run(_context)?;
let value = if let Action::Return(value) = action {
value
} else {
return Err(RuntimeError::ValidationFailure(
ValidationError::InterpreterExpectedReturn(expression.position),
));
};
property_map.insert(identifier, value);
}

View File

@ -42,9 +42,15 @@ impl AbstractTree for While {
fn run(self, _context: &Context) -> Result<Action, RuntimeError> {
let get_boolean = || -> Result<Value, RuntimeError> {
let value = self.expression.node.run(_context)?.as_return_value()?;
let action = self.expression.node.run(_context)?;
if let Action::Return(value) = action {
Ok(value)
} else {
Err(RuntimeError::ValidationFailure(
ValidationError::InterpreterExpectedReturn(self.expression.position),
))
}
};
if let ValueInner::Boolean(boolean) = get_boolean()?.inner().as_ref() {
@ -77,7 +83,7 @@ mod tests {
fn simple_while_loop() {
let action = Statement::Block(Block::new(vec![
Statement::Assignment(Assignment::new(
Identifier::new("i"),
Identifier::new("i").with_position((0, 0)),
None,
AssignmentOperator::Assign,
Statement::Expression(Expression::Value(ValueNode::Integer(3)))
@ -91,7 +97,7 @@ mod tests {
)))
.with_position((0, 0)),
statements: vec![Statement::Assignment(Assignment::new(
Identifier::new("i"),
Identifier::new("i").with_position((0, 0)),
None,
AssignmentOperator::AddAssign,
Statement::Expression(Expression::Value(ValueNode::Integer(1)))

View File

@ -96,6 +96,7 @@ impl Error {
};
let type_color = Color::Green;
let identifier_color = Color::Blue;
if let Some(validation_error) = validation_error {
match validation_error {
@ -133,16 +134,10 @@ impl Error {
.with_message(format!("Got type {} here.", actual.fg(type_color))),
]);
}
ValidationError::VariableNotFound {
identifier,
position,
} => {
builder.add_label(
Label::new(("input", position.0..position.1))
.with_message(format!("The variable {identifier} does not exist."))
.with_priority(1),
);
}
ValidationError::VariableNotFound(identifier) => builder.set_message(format!(
"{} does not exist in this context.",
identifier.fg(identifier_color)
)),
ValidationError::CannotIndex { r#type, position } => builder.add_label(
Label::new(("input", position.0..position.1))
.with_message(format!("Cannot index into a {}.", r#type.fg(type_color))),
@ -270,11 +265,7 @@ pub enum ValidationError {
/// The position of the item that gave the "expected" type.
expected_position: SourcePosition,
},
VariableNotFound {
identifier: Identifier,
position: SourcePosition,
},
VariableNotFound(Identifier),
PropertyNotFound {
identifier: Identifier,
position: SourcePosition,

View File

@ -1,13 +1,12 @@
//! Command line interface for the dust programming language.
use ariadne::{sources, Color, Label, Report, ReportKind, Source};
use chumsky::span::SimpleSpan;
use ariadne::sources;
use clap::Parser;
use colored::Colorize;
use std::{fs::read_to_string, io::Write, ops::Range};
use std::{fs::read_to_string, io::Write};
use dust_lang::{context::Context, error::Error, Interpreter};
use dust_lang::{context::Context, Interpreter};
/// Command-line arguments to be parsed.
#[derive(Parser, Debug)]
@ -55,58 +54,8 @@ fn main() {
}
Err(errors) => {
for error in errors {
let mut report_builder = match &error {
Error::Parse { expected, span } => {
let message = if expected.is_empty() {
"Invalid token.".to_string()
} else {
format!("Expected {expected}.")
};
Report::build(
ReportKind::Custom("Parsing Error", Color::White),
"input",
span.1,
)
.with_label(
Label::new(("input", span.0..span.1))
.with_message(message)
.with_color(Color::Red),
)
}
Error::Lex { expected, span } => {
let message = if expected.is_empty() {
"Invalid token.".to_string()
} else {
format!("Expected {expected}.")
};
Report::build(
ReportKind::Custom("Dust Error", Color::White),
"input",
span.1,
)
.with_label(
Label::new(("input", span.0..span.1))
.with_message(message)
.with_color(Color::Red),
)
}
Error::Runtime { error, position } => Report::build(
ReportKind::Custom("Dust Error", Color::White),
"input",
position.1,
),
Error::Validation { error, position } => Report::build(
ReportKind::Custom("Dust Error", Color::White),
"input",
position.1,
),
};
report_builder = error.build_report(report_builder);
report_builder
error
.build_report()
.finish()
.eprint(sources([("input", &source)]))
.unwrap()

View File

@ -491,7 +491,7 @@ mod tests {
assert_eq!(
parse(&lex("foobar : bool = true").unwrap()).unwrap()[0].node,
Statement::Assignment(Assignment::new(
Identifier::new("foobar"),
Identifier::new("foobar").with_position((0, 6)),
Some(Type::Boolean.with_position((9, 14))),
AssignmentOperator::Assign,
Statement::Expression(Expression::Value(ValueNode::Boolean(true)))
@ -505,7 +505,7 @@ mod tests {
assert_eq!(
parse(&lex("foobar: list = []").unwrap()).unwrap()[0].node,
Statement::Assignment(Assignment::new(
Identifier::new("foobar"),
Identifier::new("foobar").with_position((0, 6)),
Some(Type::List.with_position((8, 13))),
AssignmentOperator::Assign,
Statement::Expression(Expression::Value(ValueNode::List(vec![])))
@ -519,7 +519,7 @@ mod tests {
assert_eq!(
parse(&lex("foobar : list(bool) = [true]").unwrap()).unwrap()[0].node,
Statement::Assignment(Assignment::new(
Identifier::new("foobar"),
Identifier::new("foobar").with_position((0, 6)),
Some(Type::ListOf(Box::new(Type::Boolean)).with_position((9, 20))),
AssignmentOperator::Assign,
Statement::Expression(Expression::Value(ValueNode::List(vec![Expression::Value(
@ -536,7 +536,7 @@ mod tests {
assert_eq!(
parse(&lex("foobar : [bool, str] = [true, '42']").unwrap()).unwrap()[0],
Statement::Assignment(Assignment::new(
Identifier::new("foobar"),
Identifier::new("foobar").with_position((0, 6)),
Some(Type::ListExact(vec![Type::Boolean, Type::String]).with_position((9, 21))),
AssignmentOperator::Assign,
Statement::Expression(Expression::Value(ValueNode::List(vec![
@ -554,7 +554,7 @@ mod tests {
assert_eq!(
parse(&lex("foobar : () -> any = some_function").unwrap()).unwrap()[0].node,
Statement::Assignment(Assignment::new(
Identifier::new("foobar"),
Identifier::new("foobar").with_position((0, 6)),
Some(
Type::Function {
parameter_types: vec![],
@ -709,7 +709,7 @@ mod tests {
.with_position((10, 15)),
Block::new(vec![Statement::Break.with_position((18, 24))]),
Some(Block::new(vec![Statement::Assignment(Assignment::new(
Identifier::new("i"),
Identifier::new("i").with_position((33, 34)),
None,
AssignmentOperator::AddAssign,
Statement::Expression(Expression::Value(ValueNode::Integer(1)))
@ -799,7 +799,7 @@ mod tests {
assert_eq!(
parse(&lex("foobar = 1").unwrap()).unwrap()[0].node,
Statement::Assignment(Assignment::new(
Identifier::new("foobar"),
Identifier::new("foobar").with_position((0, 6)),
None,
AssignmentOperator::Assign,
Statement::Expression(Expression::Value(ValueNode::Integer(1)))
@ -813,7 +813,7 @@ mod tests {
assert_eq!(
parse(&lex("foobar: int = 1").unwrap()).unwrap()[0].node,
Statement::Assignment(Assignment::new(
Identifier::new("foobar"),
Identifier::new("foobar").with_position((0, 6)),
Some(Type::Integer.with_position((8, 12))),
AssignmentOperator::Assign,
Statement::Expression(Expression::Value(ValueNode::Integer(1)))

View File

@ -16,7 +16,7 @@ use stanza::{
use crate::{
abstract_tree::{AbstractTree, Action, Block, Identifier, Type, WithPosition},
context::Context,
error::{RuntimeError, ValidationError},
error::RuntimeError,
};
#[derive(Clone, Debug, PartialEq)]
@ -127,58 +127,6 @@ impl Value {
None
}
}
pub fn add(&self, other: &Self) -> Result<Value, ValidationError> {
match (self.inner().as_ref(), other.inner().as_ref()) {
(ValueInner::Integer(left), ValueInner::Integer(right)) => {
let sum = left.saturating_add(*right);
Ok(Value::integer(sum))
}
(ValueInner::Float(left), ValueInner::Float(right)) => {
let sum = left + right;
Ok(Value::float(sum))
}
(ValueInner::Float(left), ValueInner::Integer(right)) => {
let sum = left + *right as f64;
Ok(Value::float(sum))
}
(ValueInner::Integer(left), ValueInner::Float(right)) => {
let sum = *left as f64 + right;
Ok(Value::float(sum))
}
_ => Err(ValidationError::ExpectedIntegerOrFloat),
}
}
pub fn subtract(&self, other: &Self) -> Result<Value, ValidationError> {
match (self.inner().as_ref(), other.inner().as_ref()) {
(ValueInner::Integer(left), ValueInner::Integer(right)) => {
let sum = left.saturating_sub(*right);
Ok(Value::integer(sum))
}
(ValueInner::Float(left), ValueInner::Float(right)) => {
let sum = left - right;
Ok(Value::float(sum))
}
(ValueInner::Float(left), ValueInner::Integer(right)) => {
let sum = left - *right as f64;
Ok(Value::float(sum))
}
(ValueInner::Integer(left), ValueInner::Float(right)) => {
let sum = *left as f64 - right;
Ok(Value::float(sum))
}
_ => Err(ValidationError::ExpectedIntegerOrFloat),
}
}
}
impl Display for Value {