1
0

Fix tests; Refine parsing

This commit is contained in:
Jeff 2024-03-17 07:31:45 -04:00
parent f9b4b1bc01
commit 4ea19f238e
19 changed files with 291 additions and 302 deletions

View File

@ -3,14 +3,14 @@ use crate::{
Context, Context,
}; };
use super::{AbstractTree, Action, Identifier, Positioned, Statement, Type}; use super::{AbstractTree, Action, Identifier, Statement, Type, WithPosition};
#[derive(Clone, Debug, Eq, PartialEq, PartialOrd, Ord)] #[derive(Clone, Debug, Eq, PartialEq, PartialOrd, Ord)]
pub struct Assignment { pub struct Assignment {
identifier: Identifier, identifier: Identifier,
r#type: Option<Positioned<Type>>, r#type: Option<WithPosition<Type>>,
operator: AssignmentOperator, operator: AssignmentOperator,
statement: Box<Positioned<Statement>>, statement: Box<WithPosition<Statement>>,
} }
#[derive(Clone, Debug, Eq, PartialEq, PartialOrd, Ord)] #[derive(Clone, Debug, Eq, PartialEq, PartialOrd, Ord)]
@ -23,9 +23,9 @@ pub enum AssignmentOperator {
impl Assignment { impl Assignment {
pub fn new( pub fn new(
identifier: Identifier, identifier: Identifier,
r#type: Option<Positioned<Type>>, r#type: Option<WithPosition<Type>>,
operator: AssignmentOperator, operator: AssignmentOperator,
statement: Positioned<Statement>, statement: WithPosition<Statement>,
) -> Self { ) -> Self {
Self { Self {
identifier, identifier,
@ -44,7 +44,7 @@ impl AbstractTree for Assignment {
fn validate(&self, context: &Context) -> Result<(), ValidationError> { fn validate(&self, context: &Context) -> Result<(), ValidationError> {
let statement_type = self.statement.node.expected_type(context)?; let statement_type = self.statement.node.expected_type(context)?;
if let Some(Positioned { if let Some(WithPosition {
node: expected_type, node: expected_type,
position: expected_position, position: expected_position,
}) = &self.r#type }) = &self.r#type
@ -125,12 +125,8 @@ mod tests {
Identifier::new("foobar"), Identifier::new("foobar"),
None, None,
AssignmentOperator::Assign, AssignmentOperator::Assign,
Positioned { Statement::Expression(Expression::Value(ValueNode::Integer(42)))
node: Statement::Expression( .with_position((0..0).into()),
Expression::Value(ValueNode::Integer(42)).positioned((0..1).into()),
),
position: (0, 0),
},
) )
.run(&context) .run(&context)
.unwrap(); .unwrap();
@ -153,12 +149,8 @@ mod tests {
Identifier::new("foobar"), Identifier::new("foobar"),
None, None,
AssignmentOperator::AddAssign, AssignmentOperator::AddAssign,
Positioned { Statement::Expression(Expression::Value(ValueNode::Integer(41)))
node: Statement::Expression( .with_position((0..0).into()),
Expression::Value(ValueNode::Integer(41)).positioned((0..1).into()),
),
position: (0, 0),
},
) )
.run(&context) .run(&context)
.unwrap(); .unwrap();
@ -181,12 +173,8 @@ mod tests {
Identifier::new("foobar"), Identifier::new("foobar"),
None, None,
AssignmentOperator::SubAssign, AssignmentOperator::SubAssign,
Positioned { Statement::Expression(Expression::Value(ValueNode::Integer(1)))
node: Statement::Expression( .with_position((0..0).into()),
Expression::Value(ValueNode::Integer(1)).positioned((0..1).into()),
),
position: (0, 0),
},
) )
.run(&context) .run(&context)
.unwrap(); .unwrap();
@ -201,17 +189,13 @@ mod tests {
fn type_check() { fn type_check() {
let validation = Assignment::new( let validation = Assignment::new(
Identifier::new("foobar"), Identifier::new("foobar"),
Some(Positioned { Some(WithPosition {
node: Type::Boolean, node: Type::Boolean,
position: (0, 0), position: (0, 0),
}), }),
AssignmentOperator::Assign, AssignmentOperator::Assign,
Positioned { Statement::Expression(Expression::Value(ValueNode::Integer(42)))
node: Statement::Expression( .with_position((0..0).into()),
Expression::Value(ValueNode::Integer(42)).positioned((0..1).into()),
),
position: (0, 0),
},
) )
.validate(&Context::new()); .validate(&Context::new());

View File

@ -3,15 +3,15 @@ use crate::{
error::{RuntimeError, ValidationError}, error::{RuntimeError, ValidationError},
}; };
use super::{AbstractTree, Action, Positioned, Statement, Type}; use super::{AbstractTree, Action, Statement, Type, WithPosition};
#[derive(Clone, Debug, Eq, PartialEq, PartialOrd, Ord)] #[derive(Clone, Debug, Eq, PartialEq, PartialOrd, Ord)]
pub struct Block { pub struct Block {
statements: Vec<Positioned<Statement>>, statements: Vec<WithPosition<Statement>>,
} }
impl Block { impl Block {
pub fn new(statements: Vec<Positioned<Statement>>) -> Self { pub fn new(statements: Vec<WithPosition<Statement>>) -> Self {
Self { statements } Self { statements }
} }
} }
@ -61,18 +61,12 @@ mod tests {
#[test] #[test]
fn run_returns_value_of_final_statement() { fn run_returns_value_of_final_statement() {
let block = Block::new(vec![ let block = Block::new(vec![
Statement::Expression( Statement::Expression(Expression::Value(ValueNode::Integer(1)))
Expression::Value(ValueNode::Integer(1)).positioned((0..0).into()), .with_position((0..0).into()),
) Statement::Expression(Expression::Value(ValueNode::Integer(2)))
.positioned((0..0).into()), .with_position((0..0).into()),
Statement::Expression( Statement::Expression(Expression::Value(ValueNode::Integer(42)))
Expression::Value(ValueNode::Integer(2)).positioned((0..0).into()), .with_position((0..0).into()),
)
.positioned((0..0).into()),
Statement::Expression(
Expression::Value(ValueNode::Integer(42)).positioned((0..0).into()),
)
.positioned((0..0).into()),
]); ]);
assert_eq!( assert_eq!(
@ -84,14 +78,10 @@ mod tests {
#[test] #[test]
fn expected_type_returns_type_of_final_statement() { fn expected_type_returns_type_of_final_statement() {
let block = Block::new(vec![ let block = Block::new(vec![
Statement::Expression( Statement::Expression(Expression::Value(ValueNode::String("42".to_string())))
Expression::Value(ValueNode::String("42".to_string())).positioned((0..0).into()), .with_position((0..0).into()),
) Statement::Expression(Expression::Value(ValueNode::Integer(42)))
.positioned((0..0).into()), .with_position((0..0).into()),
Statement::Expression(
Expression::Value(ValueNode::Integer(42)).positioned((0..0).into()),
)
.positioned((0..0).into()),
]); ]);
assert_eq!(block.expected_type(&Context::new()), Ok(Type::Integer)) assert_eq!(block.expected_type(&Context::new()), Ok(Type::Integer))

View File

@ -3,16 +3,19 @@ use crate::{
error::{RuntimeError, ValidationError}, error::{RuntimeError, ValidationError},
}; };
use super::{AbstractTree, Action, Expression, Positioned, Type}; use super::{AbstractTree, Action, Expression, Type, WithPosition};
#[derive(Debug, Clone, Eq, PartialEq, PartialOrd, Ord)] #[derive(Debug, Clone, Eq, PartialEq, PartialOrd, Ord)]
pub struct FunctionCall { pub struct FunctionCall {
function: Box<Positioned<Expression>>, function: Box<WithPosition<Expression>>,
arguments: Vec<Positioned<Expression>>, arguments: Vec<WithPosition<Expression>>,
} }
impl FunctionCall { impl FunctionCall {
pub fn new(function: Positioned<Expression>, arguments: Vec<Positioned<Expression>>) -> Self { pub fn new(
function: WithPosition<Expression>,
arguments: Vec<WithPosition<Expression>>,
) -> Self {
FunctionCall { FunctionCall {
function: Box::new(function), function: Box::new(function),
arguments, arguments,

View File

@ -3,20 +3,20 @@ use crate::{
error::{RuntimeError, ValidationError}, error::{RuntimeError, ValidationError},
}; };
use super::{AbstractTree, Action, Block, Expression, Positioned, Type}; use super::{AbstractTree, Action, Block, Expression, Type, WithPosition};
#[derive(Clone, Debug, Eq, PartialEq, PartialOrd, Ord)] #[derive(Clone, Debug, Eq, PartialEq, PartialOrd, Ord)]
pub struct IfElse { pub struct IfElse {
if_expression: Positioned<Expression>, if_expression: WithPosition<Expression>,
if_block: Positioned<Block>, if_block: WithPosition<Block>,
else_block: Option<Positioned<Block>>, else_block: Option<WithPosition<Block>>,
} }
impl IfElse { impl IfElse {
pub fn new( pub fn new(
if_expression: Positioned<Expression>, if_expression: WithPosition<Expression>,
if_block: Positioned<Block>, if_block: WithPosition<Block>,
else_block: Option<Positioned<Block>>, else_block: Option<WithPosition<Block>>,
) -> Self { ) -> Self {
Self { Self {
if_expression, if_expression,
@ -83,13 +83,12 @@ mod tests {
fn simple_if() { fn simple_if() {
assert_eq!( assert_eq!(
IfElse::new( IfElse::new(
Expression::Value(ValueNode::Boolean(true)).positioned((0..0).into()), Expression::Value(ValueNode::Boolean(true)).with_position((0..0).into()),
Block::new(vec![Statement::Expression( Block::new(vec![Statement::Expression(Expression::Value(
Expression::Value(ValueNode::String("foo".to_string())) ValueNode::String("foo".to_string())
.positioned((0..0).into()) ))
) .with_position((0..0).into())])
.positioned((0..0).into())]) .with_position((0..0).into()),
.positioned((0..0).into()),
None None
) )
.run(&Context::new()), .run(&Context::new()),
@ -101,20 +100,18 @@ mod tests {
fn simple_if_else() { fn simple_if_else() {
assert_eq!( assert_eq!(
IfElse::new( IfElse::new(
Expression::Value(ValueNode::Boolean(false)).positioned((0..0).into()), Expression::Value(ValueNode::Boolean(false)).with_position((0..0).into()),
Block::new(vec![Statement::Expression( Block::new(vec![Statement::Expression(Expression::Value(
Expression::Value(ValueNode::String("foo".to_string())) ValueNode::String("foo".to_string())
.positioned((0..0).into()) ))
) .with_position((0..0).into())])
.positioned((0..0).into())]) .with_position((0..0).into()),
.positioned((0..0).into()),
Some( Some(
Block::new(vec![Statement::Expression( Block::new(vec![Statement::Expression(Expression::Value(
Expression::Value(ValueNode::String("bar".to_string())) ValueNode::String("bar".to_string())
.positioned((0..0).into()) ))
) .with_position((0..0).into())])
.positioned((0..0).into())]) .with_position((0..0).into())
.positioned((0..0).into())
) )
) )
.run(&Context::new()), .run(&Context::new()),

View File

@ -3,16 +3,16 @@ use crate::{
error::{RuntimeError, ValidationError}, error::{RuntimeError, ValidationError},
}; };
use super::{AbstractTree, Action, Expression, Positioned, Type, ValueNode}; use super::{AbstractTree, Action, Expression, Type, ValueNode, WithPosition};
#[derive(Clone, Debug, Eq, PartialEq, PartialOrd, Ord)] #[derive(Clone, Debug, Eq, PartialEq, PartialOrd, Ord)]
pub struct Index { pub struct Index {
left: Positioned<Expression>, left: WithPosition<Expression>,
right: Positioned<Expression>, right: WithPosition<Expression>,
} }
impl Index { impl Index {
pub fn new(left: Positioned<Expression>, right: Positioned<Expression>) -> Self { pub fn new(left: WithPosition<Expression>, right: WithPosition<Expression>) -> Self {
Self { left, right } Self { left, right }
} }
} }

View File

@ -4,19 +4,19 @@ use crate::{
Value, Value,
}; };
use super::{AbstractTree, Action, Expression, Positioned, Type}; use super::{AbstractTree, Action, Expression, Type, WithPosition};
#[derive(Clone, Debug, Eq, PartialEq, PartialOrd, Ord)] #[derive(Clone, Debug, Eq, PartialEq, PartialOrd, Ord)]
pub enum Logic { pub enum Logic {
Equal(Positioned<Expression>, Positioned<Expression>), Equal(WithPosition<Expression>, WithPosition<Expression>),
NotEqual(Positioned<Expression>, Positioned<Expression>), NotEqual(WithPosition<Expression>, WithPosition<Expression>),
Greater(Positioned<Expression>, Positioned<Expression>), Greater(WithPosition<Expression>, WithPosition<Expression>),
Less(Positioned<Expression>, Positioned<Expression>), Less(WithPosition<Expression>, WithPosition<Expression>),
GreaterOrEqual(Positioned<Expression>, Positioned<Expression>), GreaterOrEqual(WithPosition<Expression>, WithPosition<Expression>),
LessOrEqual(Positioned<Expression>, Positioned<Expression>), LessOrEqual(WithPosition<Expression>, WithPosition<Expression>),
And(Positioned<Expression>, Positioned<Expression>), And(WithPosition<Expression>, WithPosition<Expression>),
Or(Positioned<Expression>, Positioned<Expression>), Or(WithPosition<Expression>, WithPosition<Expression>),
Not(Positioned<Expression>), Not(WithPosition<Expression>),
} }
impl AbstractTree for Logic { impl AbstractTree for Logic {
@ -139,8 +139,8 @@ mod tests {
#[test] #[test]
fn equal() { fn equal() {
assert!(Logic::Equal( assert!(Logic::Equal(
Expression::Value(ValueNode::Integer(42)).positioned((0..0).into()), Expression::Value(ValueNode::Integer(42)).with_position((0..0).into()),
Expression::Value(ValueNode::Integer(42)).positioned((0..0).into()), Expression::Value(ValueNode::Integer(42)).with_position((0..0).into()),
) )
.run(&Context::new()) .run(&Context::new())
.unwrap() .unwrap()
@ -153,8 +153,8 @@ mod tests {
#[test] #[test]
fn not_equal() { fn not_equal() {
assert!(Logic::NotEqual( assert!(Logic::NotEqual(
Expression::Value(ValueNode::Integer(42)).positioned((0..0).into()), Expression::Value(ValueNode::Integer(42)).with_position((0..0).into()),
Expression::Value(ValueNode::Integer(43)).positioned((0..0).into()), Expression::Value(ValueNode::Integer(43)).with_position((0..0).into()),
) )
.run(&Context::new()) .run(&Context::new())
.unwrap() .unwrap()
@ -167,8 +167,8 @@ mod tests {
#[test] #[test]
fn greater() { fn greater() {
assert!(Logic::Greater( assert!(Logic::Greater(
Expression::Value(ValueNode::Integer(43)).positioned((0..0).into()), Expression::Value(ValueNode::Integer(43)).with_position((0..0).into()),
Expression::Value(ValueNode::Integer(42)).positioned((0..0).into()), Expression::Value(ValueNode::Integer(42)).with_position((0..0).into()),
) )
.run(&Context::new()) .run(&Context::new())
.unwrap() .unwrap()
@ -181,8 +181,8 @@ mod tests {
#[test] #[test]
fn less() { fn less() {
assert!(Logic::Less( assert!(Logic::Less(
Expression::Value(ValueNode::Integer(42)).positioned((0..0).into()), Expression::Value(ValueNode::Integer(42)).with_position((0..0).into()),
Expression::Value(ValueNode::Integer(43)).positioned((0..0).into()), Expression::Value(ValueNode::Integer(43)).with_position((0..0).into()),
) )
.run(&Context::new()) .run(&Context::new())
.unwrap() .unwrap()
@ -195,8 +195,8 @@ mod tests {
#[test] #[test]
fn greater_or_equal() { fn greater_or_equal() {
assert!(Logic::GreaterOrEqual( assert!(Logic::GreaterOrEqual(
Expression::Value(ValueNode::Integer(42)).positioned((0..0).into()), Expression::Value(ValueNode::Integer(42)).with_position((0..0).into()),
Expression::Value(ValueNode::Integer(41)).positioned((0..0).into()), Expression::Value(ValueNode::Integer(41)).with_position((0..0).into()),
) )
.run(&Context::new()) .run(&Context::new())
.unwrap() .unwrap()
@ -206,8 +206,8 @@ mod tests {
.unwrap()); .unwrap());
assert!(Logic::GreaterOrEqual( assert!(Logic::GreaterOrEqual(
Expression::Value(ValueNode::Integer(42)).positioned((0..0).into()), Expression::Value(ValueNode::Integer(42)).with_position((0..0).into()),
Expression::Value(ValueNode::Integer(42)).positioned((0..0).into()), Expression::Value(ValueNode::Integer(42)).with_position((0..0).into()),
) )
.run(&Context::new()) .run(&Context::new())
.unwrap() .unwrap()
@ -220,8 +220,8 @@ mod tests {
#[test] #[test]
fn less_or_equal() { fn less_or_equal() {
assert!(Logic::LessOrEqual( assert!(Logic::LessOrEqual(
Expression::Value(ValueNode::Integer(42)).positioned((0..0).into()), Expression::Value(ValueNode::Integer(42)).with_position((0..0).into()),
Expression::Value(ValueNode::Integer(43)).positioned((0..0).into()), Expression::Value(ValueNode::Integer(43)).with_position((0..0).into()),
) )
.run(&Context::new()) .run(&Context::new())
.unwrap() .unwrap()
@ -231,8 +231,8 @@ mod tests {
.unwrap()); .unwrap());
assert!(Logic::LessOrEqual( assert!(Logic::LessOrEqual(
Expression::Value(ValueNode::Integer(42)).positioned((0..0).into()), Expression::Value(ValueNode::Integer(42)).with_position((0..0).into()),
Expression::Value(ValueNode::Integer(42)).positioned((0..0).into()), Expression::Value(ValueNode::Integer(42)).with_position((0..0).into()),
) )
.run(&Context::new()) .run(&Context::new())
.unwrap() .unwrap()
@ -245,8 +245,8 @@ mod tests {
#[test] #[test]
fn and() { fn and() {
assert!(Logic::And( assert!(Logic::And(
Expression::Value(ValueNode::Boolean(true)).positioned((0..0).into()), Expression::Value(ValueNode::Boolean(true)).with_position((0..0).into()),
Expression::Value(ValueNode::Boolean(true)).positioned((0..0).into()), Expression::Value(ValueNode::Boolean(true)).with_position((0..0).into()),
) )
.run(&Context::new()) .run(&Context::new())
.unwrap() .unwrap()
@ -259,8 +259,8 @@ mod tests {
#[test] #[test]
fn or() { fn or() {
assert!(Logic::Or( assert!(Logic::Or(
Expression::Value(ValueNode::Boolean(true)).positioned((0..0).into()), Expression::Value(ValueNode::Boolean(true)).with_position((0..0).into()),
Expression::Value(ValueNode::Boolean(false)).positioned((0..0).into()), Expression::Value(ValueNode::Boolean(false)).with_position((0..0).into()),
) )
.run(&Context::new()) .run(&Context::new())
.unwrap() .unwrap()
@ -272,14 +272,14 @@ mod tests {
#[test] #[test]
fn not() { fn not() {
assert!( assert!(Logic::Not(
Logic::Not(Expression::Value(ValueNode::Boolean(false)).positioned((0..0).into())) Expression::Value(ValueNode::Boolean(false)).with_position((0..0).into())
.run(&Context::new())
.unwrap()
.as_return_value()
.unwrap()
.as_boolean()
.unwrap()
) )
.run(&Context::new())
.unwrap()
.as_return_value()
.unwrap()
.as_boolean()
.unwrap())
} }
} }

View File

@ -3,15 +3,15 @@ use crate::{
error::{RuntimeError, ValidationError}, error::{RuntimeError, ValidationError},
}; };
use super::{AbstractTree, Action, Positioned, Statement, Type}; use super::{AbstractTree, Action, Statement, Type, WithPosition};
#[derive(Clone, Debug, Eq, PartialEq, PartialOrd, Ord)] #[derive(Clone, Debug, Eq, PartialEq, PartialOrd, Ord)]
pub struct Loop { pub struct Loop {
statements: Vec<Positioned<Statement>>, statements: Vec<WithPosition<Statement>>,
} }
impl Loop { impl Loop {
pub fn new(statements: Vec<Positioned<Statement>>) -> Self { pub fn new(statements: Vec<WithPosition<Statement>>) -> Self {
Self { statements } Self { statements }
} }
} }
@ -58,7 +58,7 @@ mod tests {
#[test] #[test]
fn basic_loop() { fn basic_loop() {
let result = Loop { let result = Loop {
statements: vec![Statement::Break.positioned((0..0).into())], statements: vec![Statement::Break.with_position((0..0).into())],
} }
.run(&Context::new()); .run(&Context::new());

View File

@ -5,15 +5,15 @@ use crate::{
Value, Value,
}; };
use super::{AbstractTree, Action, Expression, Positioned, Type}; use super::{AbstractTree, Action, Expression, Type, WithPosition};
#[derive(Clone, Debug, Eq, PartialEq, PartialOrd, Ord)] #[derive(Clone, Debug, Eq, PartialEq, PartialOrd, Ord)]
pub enum Math { pub enum Math {
Add(Positioned<Expression>, Positioned<Expression>), Add(WithPosition<Expression>, WithPosition<Expression>),
Subtract(Positioned<Expression>, Positioned<Expression>), Subtract(WithPosition<Expression>, WithPosition<Expression>),
Multiply(Positioned<Expression>, Positioned<Expression>), Multiply(WithPosition<Expression>, WithPosition<Expression>),
Divide(Positioned<Expression>, Positioned<Expression>), Divide(WithPosition<Expression>, WithPosition<Expression>),
Modulo(Positioned<Expression>, Positioned<Expression>), Modulo(WithPosition<Expression>, WithPosition<Expression>),
} }
impl AbstractTree for Math { impl AbstractTree for Math {

View File

@ -39,7 +39,7 @@ use crate::{
}; };
#[derive(Clone, Debug, Eq, PartialEq, PartialOrd, Ord)] #[derive(Clone, Debug, Eq, PartialEq, PartialOrd, Ord)]
pub struct Positioned<T> { pub struct WithPosition<T> {
pub node: T, pub node: T,
pub position: (usize, usize), pub position: (usize, usize),
} }
@ -49,8 +49,8 @@ pub trait AbstractTree: Sized {
fn validate(&self, context: &Context) -> Result<(), ValidationError>; fn validate(&self, context: &Context) -> Result<(), ValidationError>;
fn run(self, context: &Context) -> Result<Action, RuntimeError>; fn run(self, context: &Context) -> Result<Action, RuntimeError>;
fn positioned(self, span: SimpleSpan) -> Positioned<Self> { fn with_position(self, span: SimpleSpan) -> WithPosition<Self> {
Positioned { WithPosition {
node: self, node: self,
position: (span.start(), span.end()), position: (span.start(), span.end()),
} }

View File

@ -3,16 +3,14 @@ use crate::{
error::{RuntimeError, ValidationError}, error::{RuntimeError, ValidationError},
}; };
use super::{ use super::{AbstractTree, Action, Assignment, Block, Expression, IfElse, Loop, Type, While};
AbstractTree, Action, Assignment, Block, Expression, IfElse, Loop, Positioned, Type, While,
};
#[derive(Clone, Debug, Eq, PartialEq, PartialOrd, Ord)] #[derive(Clone, Debug, Eq, PartialEq, PartialOrd, Ord)]
pub enum Statement { pub enum Statement {
Assignment(Assignment), Assignment(Assignment),
Block(Block), Block(Block),
Break, Break,
Expression(Positioned<Expression>), Expression(Expression),
IfElse(IfElse), IfElse(IfElse),
Loop(Loop), Loop(Loop),
While(While), While(While),
@ -24,7 +22,7 @@ impl AbstractTree for Statement {
Statement::Assignment(assignment) => assignment.expected_type(_context), Statement::Assignment(assignment) => assignment.expected_type(_context),
Statement::Block(block) => block.expected_type(_context), Statement::Block(block) => block.expected_type(_context),
Statement::Break => Ok(Type::None), Statement::Break => Ok(Type::None),
Statement::Expression(expression) => expression.node.expected_type(_context), Statement::Expression(expression) => expression.expected_type(_context),
Statement::IfElse(if_else) => if_else.expected_type(_context), Statement::IfElse(if_else) => if_else.expected_type(_context),
Statement::Loop(r#loop) => r#loop.expected_type(_context), Statement::Loop(r#loop) => r#loop.expected_type(_context),
Statement::While(r#while) => r#while.expected_type(_context), Statement::While(r#while) => r#while.expected_type(_context),
@ -36,7 +34,7 @@ impl AbstractTree for Statement {
Statement::Assignment(assignment) => assignment.validate(_context), Statement::Assignment(assignment) => assignment.validate(_context),
Statement::Block(block) => block.validate(_context), Statement::Block(block) => block.validate(_context),
Statement::Break => Ok(()), Statement::Break => Ok(()),
Statement::Expression(expression) => expression.node.validate(_context), Statement::Expression(expression) => expression.validate(_context),
Statement::IfElse(if_else) => if_else.validate(_context), Statement::IfElse(if_else) => if_else.validate(_context),
Statement::Loop(r#loop) => r#loop.validate(_context), Statement::Loop(r#loop) => r#loop.validate(_context),
Statement::While(r#while) => r#while.validate(_context), Statement::While(r#while) => r#while.validate(_context),
@ -48,7 +46,7 @@ impl AbstractTree for Statement {
Statement::Assignment(assignment) => assignment.run(_context), Statement::Assignment(assignment) => assignment.run(_context),
Statement::Block(block) => block.run(_context), Statement::Block(block) => block.run(_context),
Statement::Break => Ok(Action::Break), Statement::Break => Ok(Action::Break),
Statement::Expression(expression) => expression.node.run(_context), Statement::Expression(expression) => expression.run(_context),
Statement::IfElse(if_else) => if_else.run(_context), Statement::IfElse(if_else) => if_else.run(_context),
Statement::Loop(r#loop) => r#loop.run(_context), Statement::Loop(r#loop) => r#loop.run(_context),
Statement::While(r#while) => r#while.run(_context), Statement::While(r#while) => r#while.run(_context),

View File

@ -6,21 +6,27 @@ use crate::{
Value, Value,
}; };
use super::{AbstractTree, Action, Block, Expression, Identifier, Positioned, Type}; use super::{AbstractTree, Action, Block, Expression, Identifier, Type, WithPosition};
#[derive(Clone, Debug, PartialEq)] #[derive(Clone, Debug, PartialEq)]
pub enum ValueNode { pub enum ValueNode {
Boolean(bool), Boolean(bool),
Float(f64), Float(f64),
Integer(i64), Integer(i64),
List(Vec<Positioned<Expression>>), List(Vec<WithPosition<Expression>>),
Map(Vec<(Identifier, Option<Positioned<Type>>, Positioned<Expression>)>), Map(
Vec<(
Identifier,
Option<WithPosition<Type>>,
WithPosition<Expression>,
)>,
),
Range(Range<i64>), Range(Range<i64>),
String(String), String(String),
Function { Function {
parameters: Vec<(Identifier, Positioned<Type>)>, parameters: Vec<(Identifier, WithPosition<Type>)>,
return_type: Positioned<Type>, return_type: WithPosition<Type>,
body: Positioned<Block>, body: WithPosition<Block>,
}, },
} }
@ -70,7 +76,7 @@ impl AbstractTree for ValueNode {
actual_position: expression.position, actual_position: expression.position,
expected_position: expected_type.position, expected_position: expected_type.position,
} }
}); })?;
} }
} }
} }

View File

@ -3,16 +3,16 @@ use crate::{
error::{RuntimeError, ValidationError}, error::{RuntimeError, ValidationError},
}; };
use super::{AbstractTree, Action, Block, Expression, Positioned, Type}; use super::{AbstractTree, Action, Block, Expression, Type, WithPosition};
#[derive(Clone, Debug, Eq, PartialEq, PartialOrd, Ord)] #[derive(Clone, Debug, Eq, PartialEq, PartialOrd, Ord)]
pub struct While { pub struct While {
expression: Positioned<Expression>, expression: WithPosition<Expression>,
block: Block, block: Block,
} }
impl While { impl While {
pub fn new(expression: Positioned<Expression>, block: Block) -> Self { pub fn new(expression: WithPosition<Expression>, block: Block) -> Self {
Self { expression, block } Self { expression, block }
} }
} }

View File

@ -19,7 +19,10 @@ pub enum Error {
span: (usize, usize), span: (usize, usize),
}, },
Runtime(RuntimeError), Runtime(RuntimeError),
Validation(ValidationError, (usize, usize)), Validation {
error: ValidationError,
position: (usize, usize),
},
} }
impl Error { impl Error {
@ -46,7 +49,7 @@ impl Error {
.finish() .finish()
} }
Error::Runtime(_) => todo!(), Error::Runtime(_) => todo!(),
Error::Validation(validation_error, position) => { Error::Validation { error, position } => {
let mut report = Report::build( let mut report = Report::build(
ReportKind::Custom("Validation Error: The code was not run.", Color::White), ReportKind::Custom("Validation Error: The code was not run.", Color::White),
(), (),
@ -56,7 +59,7 @@ impl Error {
Label::new(position.0..position.1).with_message("Error found in this item."), Label::new(position.0..position.1).with_message("Error found in this item."),
); );
match validation_error { match error {
ValidationError::ExpectedBoolean => { ValidationError::ExpectedBoolean => {
report = report =
report.with_label(Label::new(0..0).with_message("Expected boolean.")); report.with_label(Label::new(0..0).with_message("Expected boolean."));

View File

@ -5,7 +5,7 @@ pub mod lexer;
pub mod parser; pub mod parser;
pub mod value; pub mod value;
use abstract_tree::{AbstractTree, Action}; use abstract_tree::{AbstractTree, Action, WithPosition};
use context::Context; use context::Context;
use error::Error; use error::Error;
use lexer::lex; use lexer::lex;
@ -33,12 +33,13 @@ impl Interpreter {
let statements = parse(&tokens)?; let statements = parse(&tokens)?;
let errors = statements let errors = statements
.iter() .iter()
.filter_map(|statement| { .filter_map(|WithPosition { node, position }| {
statement node.validate(&self.context)
.node
.validate(&self.context)
.err() .err()
.map(|validation_error| Error::Validation(validation_error, statement.position)) .map(|error| Error::Validation {
error,
position: position.clone(),
})
}) })
.collect::<Vec<Error>>(); .collect::<Vec<Error>>();

View File

@ -12,7 +12,7 @@ pub type DustParser<'src> = Boxed<
'src, 'src,
'src, 'src,
ParserInput<'src>, ParserInput<'src>,
Vec<Positioned<Statement>>, Vec<WithPosition<Statement>>,
extra::Err<Rich<'src, Token<'src>, SimpleSpan>>, extra::Err<Rich<'src, Token<'src>, SimpleSpan>>,
>; >;
@ -21,7 +21,7 @@ pub type ParserInput<'src> =
pub fn parse<'src>( pub fn parse<'src>(
tokens: &'src [(Token<'src>, SimpleSpan)], tokens: &'src [(Token<'src>, SimpleSpan)],
) -> Result<Vec<Positioned<Statement>>, Vec<Error>> { ) -> Result<Vec<WithPosition<Statement>>, Vec<Error>> {
parser() parser()
.parse(tokens.spanned((tokens.len()..tokens.len()).into())) .parse(tokens.spanned((tokens.len()..tokens.len()).into()))
.into_result() .into_result()
@ -53,7 +53,7 @@ pub fn parser<'src>() -> DustParser<'src> {
Token::Float(float) => ValueNode::Float(float), Token::Float(float) => ValueNode::Float(float),
Token::String(string) => ValueNode::String(string.to_string()), Token::String(string) => ValueNode::String(string.to_string()),
} }
.map_with(|value, state| Expression::Value(value).positioned(state.span())) .map_with(|value, state| Expression::Value(value).with_position(state.span()))
.boxed(); .boxed();
let r#type = recursive(|r#type| { let r#type = recursive(|r#type| {
@ -106,12 +106,12 @@ pub fn parser<'src>() -> DustParser<'src> {
.map(|identifier| Type::Custom(identifier)), .map(|identifier| Type::Custom(identifier)),
)) ))
}) })
.map_with(|r#type, state| r#type.positioned(state.span())); .map_with(|r#type, state| r#type.with_position(state.span()));
let type_specification = just(Token::Control(Control::Colon)).ignore_then(r#type.clone()); let type_specification = just(Token::Control(Control::Colon)).ignore_then(r#type.clone());
let statement = recursive(|statement| { let positioned_statement = recursive(|positioned_statement| {
let block = statement let block = positioned_statement
.clone() .clone()
.repeated() .repeated()
.collect() .collect()
@ -123,11 +123,11 @@ pub fn parser<'src>() -> DustParser<'src> {
let positioned_block = block let positioned_block = block
.clone() .clone()
.map_with(|block, state| block.positioned(state.span())); .map_with(|block, state| block.with_position(state.span()));
let expression = recursive(|expression| { let positioned_expression = recursive(|positioned_expression| {
let identifier_expression = identifier.clone().map_with(|identifier, state| { let identifier_expression = identifier.clone().map_with(|identifier, state| {
Expression::Identifier(identifier).positioned(state.span()) Expression::Identifier(identifier).with_position(state.span())
}); });
let range = { let range = {
@ -140,11 +140,11 @@ pub fn parser<'src>() -> DustParser<'src> {
.then_ignore(just(Token::Control(Control::DoubleDot))) .then_ignore(just(Token::Control(Control::DoubleDot)))
.then(raw_integer) .then(raw_integer)
.map_with(|(start, end), state| { .map_with(|(start, end), state| {
Expression::Value(ValueNode::Range(start..end)).positioned(state.span()) Expression::Value(ValueNode::Range(start..end)).with_position(state.span())
}) })
}; };
let list = expression let list = positioned_expression
.clone() .clone()
.separated_by(just(Token::Control(Control::Comma))) .separated_by(just(Token::Control(Control::Comma)))
.allow_trailing() .allow_trailing()
@ -154,14 +154,14 @@ pub fn parser<'src>() -> DustParser<'src> {
just(Token::Control(Control::SquareClose)), just(Token::Control(Control::SquareClose)),
) )
.map_with(|list, state| { .map_with(|list, state| {
Expression::Value(ValueNode::List(list)).positioned(state.span()) Expression::Value(ValueNode::List(list)).with_position(state.span())
}); });
let map_assignment = identifier let map_assignment = identifier
.clone() .clone()
.then(type_specification.clone().or_not()) .then(type_specification.clone().or_not())
.then_ignore(just(Token::Operator(Operator::Assign))) .then_ignore(just(Token::Operator(Operator::Assign)))
.then(expression.clone()) .then(positioned_expression.clone())
.map(|((identifier, r#type), expression)| (identifier, r#type, expression)); .map(|((identifier, r#type), expression)| (identifier, r#type, expression));
let map = map_assignment let map = map_assignment
@ -173,7 +173,8 @@ pub fn parser<'src>() -> DustParser<'src> {
just(Token::Control(Control::CurlyClose)), just(Token::Control(Control::CurlyClose)),
) )
.map_with(|map_assigment_list, state| { .map_with(|map_assigment_list, state| {
Expression::Value(ValueNode::Map(map_assigment_list)).positioned(state.span()) Expression::Value(ValueNode::Map(map_assigment_list))
.with_position(state.span())
}); });
let function = identifier let function = identifier
@ -191,16 +192,16 @@ pub fn parser<'src>() -> DustParser<'src> {
Expression::Value(ValueNode::Function { Expression::Value(ValueNode::Function {
parameters, parameters,
return_type, return_type,
body: body.positioned(state.span()), body: body.with_position(state.span()),
}) })
.positioned(state.span()) .with_position(state.span())
}); });
let function_expression = choice((identifier_expression.clone(), function.clone())); let function_expression = choice((identifier_expression.clone(), function.clone()));
let function_call = function_expression let function_call = function_expression
.then( .then(
expression positioned_expression
.clone() .clone()
.separated_by(just(Token::Control(Control::Comma))) .separated_by(just(Token::Control(Control::Comma)))
.collect() .collect()
@ -211,7 +212,7 @@ pub fn parser<'src>() -> DustParser<'src> {
) )
.map_with(|(function, arguments), state| { .map_with(|(function, arguments), state| {
Expression::FunctionCall(FunctionCall::new(function, arguments)) Expression::FunctionCall(FunctionCall::new(function, arguments))
.positioned(state.span()) .with_position(state.span())
}); });
let atom = choice(( let atom = choice((
@ -219,7 +220,7 @@ pub fn parser<'src>() -> DustParser<'src> {
identifier_expression.clone(), identifier_expression.clone(),
basic_value.clone(), basic_value.clone(),
list.clone(), list.clone(),
expression.clone().delimited_by( positioned_expression.clone().delimited_by(
just(Token::Control(Control::ParenOpen)), just(Token::Control(Control::ParenOpen)),
just(Token::Control(Control::ParenClose)), just(Token::Control(Control::ParenClose)),
), ),
@ -229,41 +230,42 @@ pub fn parser<'src>() -> DustParser<'src> {
let logic_math_and_index = atom.pratt(( let logic_math_and_index = atom.pratt((
prefix(2, just(Token::Operator(Not)), |_, expression, span| { prefix(2, just(Token::Operator(Not)), |_, expression, span| {
Expression::Logic(Box::new(Logic::Not(expression))).positioned(span) Expression::Logic(Box::new(Logic::Not(expression))).with_position(span)
}), }),
infix( infix(
left(3), left(3),
just(Token::Control(Control::Dot)), just(Token::Control(Control::Dot)),
|left, _, right, span| { |left, _, right, span| {
Expression::Index(Box::new(Index::new(left, right))).positioned(span) Expression::Index(Box::new(Index::new(left, right))).with_position(span)
}, },
), ),
infix( infix(
left(1), left(1),
just(Token::Operator(Equal)), just(Token::Operator(Equal)),
|left, _, right, span| { |left, _, right, span| {
Expression::Logic(Box::new(Logic::Equal(left, right))).positioned(span) Expression::Logic(Box::new(Logic::Equal(left, right))).with_position(span)
}, },
), ),
infix( infix(
left(1), left(1),
just(Token::Operator(NotEqual)), just(Token::Operator(NotEqual)),
|left, _, right, span| { |left, _, right, span| {
Expression::Logic(Box::new(Logic::NotEqual(left, right))).positioned(span) Expression::Logic(Box::new(Logic::NotEqual(left, right)))
.with_position(span)
}, },
), ),
infix( infix(
left(1), left(1),
just(Token::Operator(Greater)), just(Token::Operator(Greater)),
|left, _, right, span| { |left, _, right, span| {
Expression::Logic(Box::new(Logic::Greater(left, right))).positioned(span) Expression::Logic(Box::new(Logic::Greater(left, right))).with_position(span)
}, },
), ),
infix( infix(
left(1), left(1),
just(Token::Operator(Less)), just(Token::Operator(Less)),
|left, _, right, span| { |left, _, right, span| {
Expression::Logic(Box::new(Logic::Less(left, right))).positioned(span) Expression::Logic(Box::new(Logic::Less(left, right))).with_position(span)
}, },
), ),
infix( infix(
@ -271,7 +273,7 @@ pub fn parser<'src>() -> DustParser<'src> {
just(Token::Operator(GreaterOrEqual)), just(Token::Operator(GreaterOrEqual)),
|left, _, right, span| { |left, _, right, span| {
Expression::Logic(Box::new(Logic::GreaterOrEqual(left, right))) Expression::Logic(Box::new(Logic::GreaterOrEqual(left, right)))
.positioned(span) .with_position(span)
}, },
), ),
infix( infix(
@ -279,56 +281,56 @@ pub fn parser<'src>() -> DustParser<'src> {
just(Token::Operator(LessOrEqual)), just(Token::Operator(LessOrEqual)),
|left, _, right, span| { |left, _, right, span| {
Expression::Logic(Box::new(Logic::LessOrEqual(left, right))) Expression::Logic(Box::new(Logic::LessOrEqual(left, right)))
.positioned(span) .with_position(span)
}, },
), ),
infix( infix(
left(1), left(1),
just(Token::Operator(And)), just(Token::Operator(And)),
|left, _, right, span| { |left, _, right, span| {
Expression::Logic(Box::new(Logic::And(left, right))).positioned(span) Expression::Logic(Box::new(Logic::And(left, right))).with_position(span)
}, },
), ),
infix( infix(
left(1), left(1),
just(Token::Operator(Or)), just(Token::Operator(Or)),
|left, _, right, span| { |left, _, right, span| {
Expression::Logic(Box::new(Logic::Or(left, right))).positioned(span) Expression::Logic(Box::new(Logic::Or(left, right))).with_position(span)
}, },
), ),
infix( infix(
left(1), left(1),
just(Token::Operator(Add)), just(Token::Operator(Add)),
|left, _, right, span| { |left, _, right, span| {
Expression::Math(Box::new(Math::Add(left, right))).positioned(span) Expression::Math(Box::new(Math::Add(left, right))).with_position(span)
}, },
), ),
infix( infix(
left(1), left(1),
just(Token::Operator(Subtract)), just(Token::Operator(Subtract)),
|left, _, right, span| { |left, _, right, span| {
Expression::Math(Box::new(Math::Subtract(left, right))).positioned(span) Expression::Math(Box::new(Math::Subtract(left, right))).with_position(span)
}, },
), ),
infix( infix(
left(2), left(2),
just(Token::Operator(Multiply)), just(Token::Operator(Multiply)),
|left, _, right, span| { |left, _, right, span| {
Expression::Math(Box::new(Math::Multiply(left, right))).positioned(span) Expression::Math(Box::new(Math::Multiply(left, right))).with_position(span)
}, },
), ),
infix( infix(
left(2), left(2),
just(Token::Operator(Divide)), just(Token::Operator(Divide)),
|left, _, right, span| { |left, _, right, span| {
Expression::Math(Box::new(Math::Divide(left, right))).positioned(span) Expression::Math(Box::new(Math::Divide(left, right))).with_position(span)
}, },
), ),
infix( infix(
left(1), left(1),
just(Token::Operator(Modulo)), just(Token::Operator(Modulo)),
|left, _, right, span| { |left, _, right, span| {
Expression::Math(Box::new(Math::Modulo(left, right))).positioned(span) Expression::Math(Box::new(Math::Modulo(left, right))).with_position(span)
}, },
), ),
)); ));
@ -345,12 +347,15 @@ pub fn parser<'src>() -> DustParser<'src> {
)) ))
}); });
let expression_statement = expression.clone().map_with(|expression, state| { let expression_statement =
Statement::Expression(expression).positioned(state.span()) positioned_expression
}); .clone()
.map_with(|positioned_expression, state| {
Statement::Expression(positioned_expression.node).with_position(state.span())
});
let r#break = just(Token::Keyword("break")) let r#break = just(Token::Keyword("break"))
.map_with(|_, state| Statement::Break.positioned(state.span())); .map_with(|_, state| Statement::Break.with_position(state.span()));
let assignment = identifier let assignment = identifier
.clone() .clone()
@ -360,17 +365,17 @@ pub fn parser<'src>() -> DustParser<'src> {
just(Token::Operator(Operator::AddAssign)).to(AssignmentOperator::AddAssign), just(Token::Operator(Operator::AddAssign)).to(AssignmentOperator::AddAssign),
just(Token::Operator(Operator::SubAssign)).to(AssignmentOperator::SubAssign), just(Token::Operator(Operator::SubAssign)).to(AssignmentOperator::SubAssign),
))) )))
.then(statement.clone()) .then(positioned_statement.clone())
.map_with(|(((identifier, r#type), operator), statement), state| { .map_with(|(((identifier, r#type), operator), statement), state| {
Statement::Assignment(Assignment::new(identifier, r#type, operator, statement)) Statement::Assignment(Assignment::new(identifier, r#type, operator, statement))
.positioned(state.span()) .with_position(state.span())
}); });
let block_statement = block let block_statement = block
.clone() .clone()
.map_with(|block, state| Statement::Block(block).positioned(state.span())); .map_with(|block, state| Statement::Block(block).with_position(state.span()));
let r#loop = statement let r#loop = positioned_statement
.clone() .clone()
.repeated() .repeated()
.at_least(1) .at_least(1)
@ -380,18 +385,18 @@ pub fn parser<'src>() -> DustParser<'src> {
just(Token::Control(Control::CurlyClose)), just(Token::Control(Control::CurlyClose)),
) )
.map_with(|statements, state| { .map_with(|statements, state| {
Statement::Loop(Loop::new(statements)).positioned(state.span()) Statement::Loop(Loop::new(statements)).with_position(state.span())
}); });
let r#while = just(Token::Keyword("while")) let r#while = just(Token::Keyword("while"))
.ignore_then(expression.clone()) .ignore_then(positioned_expression.clone())
.then(block.clone()) .then(block.clone())
.map_with(|(expression, block), state| { .map_with(|(expression, block), state| {
Statement::While(While::new(expression, block)).positioned(state.span()) Statement::While(While::new(expression, block)).with_position(state.span())
}); });
let if_else = just(Token::Keyword("if")) let if_else = just(Token::Keyword("if"))
.ignore_then(expression.clone()) .ignore_then(positioned_expression.clone())
.then(positioned_block.clone()) .then(positioned_block.clone())
.then( .then(
just(Token::Keyword("else")) just(Token::Keyword("else"))
@ -400,7 +405,7 @@ pub fn parser<'src>() -> DustParser<'src> {
) )
.map_with(|((if_expression, if_block), else_block), state| { .map_with(|((if_expression, if_block), else_block), state| {
Statement::IfElse(IfElse::new(if_expression, if_block, else_block)) Statement::IfElse(IfElse::new(if_expression, if_block, else_block))
.positioned(state.span()) .with_position(state.span())
}); });
choice(( choice((
@ -415,7 +420,7 @@ pub fn parser<'src>() -> DustParser<'src> {
.then_ignore(just(Token::Control(Control::Semicolon)).or_not()) .then_ignore(just(Token::Control(Control::Semicolon)).or_not())
}); });
statement.repeated().collect().boxed() positioned_statement.repeated().collect().boxed()
} }
#[cfg(test)] #[cfg(test)]
@ -429,19 +434,18 @@ mod tests {
assert_eq!( assert_eq!(
parse(&lex("while true { output('hi') }").unwrap()).unwrap()[0], parse(&lex("while true { output('hi') }").unwrap()).unwrap()[0],
Statement::While(While::new( Statement::While(While::new(
Expression::Value(ValueNode::Boolean(true)).positioned((6..11).into()), Expression::Value(ValueNode::Boolean(true)).with_position((6..11).into()),
Block::new(vec![Statement::Expression( Block::new(vec![Statement::Expression(Expression::FunctionCall(
Expression::FunctionCall(FunctionCall::new( FunctionCall::new(
Expression::Identifier(Identifier::new("output")) Expression::Identifier(Identifier::new("output"))
.positioned((13..19).into()), .with_position((13..19).into()),
vec![Expression::Value(ValueNode::String("hi".to_string())) vec![Expression::Value(ValueNode::String("hi".to_string()))
.positioned((20..24).into())] .with_position((20..24).into())]
)) )
.positioned((13..26).into()) ))
) .with_position((13..26).into())])
.positioned((13..26).into())])
)) ))
.positioned((0..27).into()) .with_position((0..27).into())
) )
} }
@ -451,14 +455,12 @@ mod tests {
parse(&lex("foobar : bool = true").unwrap()).unwrap()[0], parse(&lex("foobar : bool = true").unwrap()).unwrap()[0],
Statement::Assignment(Assignment::new( Statement::Assignment(Assignment::new(
Identifier::new("foobar"), Identifier::new("foobar"),
Some(Type::Boolean.positioned((9..14).into())), Some(Type::Boolean.with_position((9..14).into())),
AssignmentOperator::Assign, AssignmentOperator::Assign,
Statement::Expression( Statement::Expression(Expression::Value(ValueNode::Boolean(true)))
Expression::Value(ValueNode::Boolean(true)).positioned((16..20).into()) .with_position((16..20).into())
)
.positioned((16..20).into())
),) ),)
.positioned((0..20).into()) .with_position((0..20).into())
); );
} }
@ -468,18 +470,15 @@ mod tests {
parse(&lex("foobar : list(bool) = [true]").unwrap()).unwrap()[0], parse(&lex("foobar : list(bool) = [true]").unwrap()).unwrap()[0],
Statement::Assignment(Assignment::new( Statement::Assignment(Assignment::new(
Identifier::new("foobar"), Identifier::new("foobar"),
Some(Type::ListOf(Box::new(Type::Boolean)).positioned((9..20).into())), Some(Type::ListOf(Box::new(Type::Boolean)).with_position((9..20).into())),
AssignmentOperator::Assign, AssignmentOperator::Assign,
Statement::Expression( Statement::Expression(Expression::Value(ValueNode::List(vec![Expression::Value(
Expression::Value(ValueNode::List(vec![Expression::Value( ValueNode::Boolean(true)
ValueNode::Boolean(true)
)
.positioned((23..27).into())]))
.positioned((22..28).into())
) )
.positioned((22..28).into()) .with_position((23..27).into())])))
.with_position((22..28).into())
)) ))
.positioned((0..28).into()) .with_position((0..28).into())
); );
} }
@ -489,19 +488,19 @@ mod tests {
parse(&lex("foobar : [bool, str] = [true, '42']").unwrap()).unwrap()[0], parse(&lex("foobar : [bool, str] = [true, '42']").unwrap()).unwrap()[0],
Statement::Assignment(Assignment::new( Statement::Assignment(Assignment::new(
Identifier::new("foobar"), Identifier::new("foobar"),
Some(Type::ListExact(vec![Type::Boolean, Type::String]).positioned((9..21).into())), Some(
Type::ListExact(vec![Type::Boolean, Type::String])
.with_position((9..21).into())
),
AssignmentOperator::Assign, AssignmentOperator::Assign,
Statement::Expression( Statement::Expression(Expression::Value(ValueNode::List(vec![
Expression::Value(ValueNode::List(vec![ Expression::Value(ValueNode::Boolean(true)).with_position((24..28).into()),
Expression::Value(ValueNode::Boolean(true)).positioned((24..28).into()), Expression::Value(ValueNode::String("42".to_string()))
Expression::Value(ValueNode::String("42".to_string())) .with_position((30..34).into())
.positioned((30..34).into()) ])))
])) .with_position((23..35).into())
.positioned((23..35).into())
)
.positioned((23..35).into())
),) ),)
.positioned((0..35).into()) .with_position((0..35).into())
); );
} }
@ -516,40 +515,36 @@ mod tests {
parameter_types: vec![], parameter_types: vec![],
return_type: Box::new(Type::Any) return_type: Box::new(Type::Any)
} }
.positioned((9..19).into()) .with_position((9..19).into())
), ),
AssignmentOperator::Assign, AssignmentOperator::Assign,
Statement::Expression( Statement::Expression(Expression::Identifier(Identifier::new("some_function")))
Expression::Identifier(Identifier::new("some_function")) .with_position((21..34).into())
.positioned((21..34).into())
)
.positioned((21..34).into())
),) ),)
.positioned((0..34).into()) .with_position((0..34).into())
); );
} }
// #[test] #[test]
// fn function_call() { fn function_call() {
// assert_eq!( assert_eq!(
// parse(&lex("output()").unwrap()).unwrap()[0], parse(&lex("output()").unwrap()).unwrap()[0],
// Statement::expression( Statement::Expression(Expression::FunctionCall(FunctionCall::new(
// Expression::FunctionCall(FunctionCall::new( Expression::Identifier(Identifier::new("output")).with_position((0..6).into()),
// Expression::Identifier(Identifier::new("output")), Vec::with_capacity(0),
// Vec::with_capacity(0), )))
// )), .with_position((0..8).into())
// (0..0).into() )
// ) }
// )
// }
// #[test] #[test]
// fn range() { fn range() {
// assert_eq!( assert_eq!(
// parse(&lex("1..10").unwrap()).unwrap()[0], parse(&lex("1..10").unwrap()).unwrap()[0],
// Statement::expression(Expression::Value(ValueNode::Range(1..10)), (0..0).into()) Statement::Expression(Expression::Value(ValueNode::Range(1..10)))
// ) .with_position((0..5).into())
// } )
}
// #[test] // #[test]
// fn function() { // fn function() {

View File

@ -13,7 +13,7 @@ use stanza::{
}; };
use crate::{ use crate::{
abstract_tree::{AbstractTree, Action, Block, Identifier, Positioned, Type}, abstract_tree::{AbstractTree, Action, Block, Identifier, Type, WithPosition},
context::Context, context::Context,
error::{RuntimeError, ValidationError}, error::{RuntimeError, ValidationError},
}; };
@ -55,9 +55,9 @@ impl Value {
} }
pub fn function( pub fn function(
parameters: Vec<(Identifier, Positioned<Type>)>, parameters: Vec<(Identifier, WithPosition<Type>)>,
return_type: Positioned<Type>, return_type: WithPosition<Type>,
body: Positioned<Block>, body: WithPosition<Block>,
) -> Self { ) -> Self {
Value(Arc::new(ValueInner::Function(Function::Parsed( Value(Arc::new(ValueInner::Function(Function::Parsed(
ParsedFunction { ParsedFunction {
@ -330,9 +330,9 @@ impl Function {
#[derive(Clone, Debug, Eq, PartialEq, PartialOrd, Ord)] #[derive(Clone, Debug, Eq, PartialEq, PartialOrd, Ord)]
pub struct ParsedFunction { pub struct ParsedFunction {
parameters: Vec<(Identifier, Positioned<Type>)>, parameters: Vec<(Identifier, WithPosition<Type>)>,
return_type: Positioned<Type>, return_type: WithPosition<Type>,
body: Positioned<Block>, body: WithPosition<Block>,
} }
#[derive(Clone, Debug, Eq, PartialEq, PartialOrd, Ord)] #[derive(Clone, Debug, Eq, PartialEq, PartialOrd, Ord)]

View File

@ -62,7 +62,7 @@ fn function_context_does_not_capture_values() {
), ),
Err(vec![Error::Validation { Err(vec![Error::Validation {
error: ValidationError::VariableNotFound(Identifier::new("x")), error: ValidationError::VariableNotFound(Identifier::new("x")),
span: (32, 66) position: (0, 0)
}]) }])
); );

View File

@ -136,11 +136,15 @@ fn map_type_errors() {
assert_eq!( assert_eq!(
interpret("{ foo : bool = 'bar' }"), interpret("{ foo : bool = 'bar' }"),
Err(vec![Error::Validation { Err(vec![Error::Validation {
error: ValidationError::TypeCheck(TypeConflict { error: ValidationError::TypeCheck {
actual: Type::String, conflict: TypeConflict {
expected: Type::Boolean actual: Type::String,
}), expected: Type::Boolean
span: (0, 22) },
actual_position: (0, 0),
expected_position: (0, 0),
},
position: (0, 22)
}]) }])
); );
} }

View File

@ -1,5 +1,5 @@
use dust_lang::{ use dust_lang::{
abstract_tree::{Block, Expression, Identifier, Statement, Type}, abstract_tree::{AbstractTree, Block, Expression, Identifier, Statement, Type},
error::{Error, TypeConflict, ValidationError}, error::{Error, TypeConflict, ValidationError},
*, *,
}; };
@ -25,11 +25,15 @@ fn set_variable_with_type_error() {
assert_eq!( assert_eq!(
interpret("foobar: str = true"), interpret("foobar: str = true"),
Err(vec![Error::Validation { Err(vec![Error::Validation {
error: ValidationError::TypeCheck(TypeConflict { error: ValidationError::TypeCheck {
actual: Type::Boolean, conflict: TypeConflict {
expected: Type::String actual: Type::Boolean,
}), expected: Type::String
span: (0, 18) },
actual_position: (0, 0),
expected_position: (0, 0)
},
position: (0, 18)
}]) }])
); );
} }
@ -39,12 +43,16 @@ fn function_variable() {
assert_eq!( assert_eq!(
interpret("foobar = (x: int): int { x }; foobar"), interpret("foobar = (x: int): int { x }; foobar"),
Ok(Some(Value::function( Ok(Some(Value::function(
vec![(Identifier::new("x"), Type::Integer)], vec![(
Type::Integer, Identifier::new("x"),
Block::new(vec![Statement::expression( Type::Integer.with_position((0..0).into())
Expression::Identifier(Identifier::new("x")), )],
(0..0).into() Type::Integer.with_position((0..0).into()),
)]) Block::new(vec![Statement::Expression(Expression::Identifier(
Identifier::new("x")
))
.with_position((0..0).into())])
.with_position((0..0).into())
))) )))
); );
} }