Fix tests; Refine parsing
This commit is contained in:
parent
f9b4b1bc01
commit
4ea19f238e
@ -3,14 +3,14 @@ use crate::{
|
||||
Context,
|
||||
};
|
||||
|
||||
use super::{AbstractTree, Action, Identifier, Positioned, Statement, Type};
|
||||
use super::{AbstractTree, Action, Identifier, Statement, Type, WithPosition};
|
||||
|
||||
#[derive(Clone, Debug, Eq, PartialEq, PartialOrd, Ord)]
|
||||
pub struct Assignment {
|
||||
identifier: Identifier,
|
||||
r#type: Option<Positioned<Type>>,
|
||||
r#type: Option<WithPosition<Type>>,
|
||||
operator: AssignmentOperator,
|
||||
statement: Box<Positioned<Statement>>,
|
||||
statement: Box<WithPosition<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<Positioned<Type>>,
|
||||
r#type: Option<WithPosition<Type>>,
|
||||
operator: AssignmentOperator,
|
||||
statement: Positioned<Statement>,
|
||||
statement: WithPosition<Statement>,
|
||||
) -> Self {
|
||||
Self {
|
||||
identifier,
|
||||
@ -44,7 +44,7 @@ impl AbstractTree for Assignment {
|
||||
fn validate(&self, context: &Context) -> Result<(), ValidationError> {
|
||||
let statement_type = self.statement.node.expected_type(context)?;
|
||||
|
||||
if let Some(Positioned {
|
||||
if let Some(WithPosition {
|
||||
node: expected_type,
|
||||
position: expected_position,
|
||||
}) = &self.r#type
|
||||
@ -125,12 +125,8 @@ mod tests {
|
||||
Identifier::new("foobar"),
|
||||
None,
|
||||
AssignmentOperator::Assign,
|
||||
Positioned {
|
||||
node: Statement::Expression(
|
||||
Expression::Value(ValueNode::Integer(42)).positioned((0..1).into()),
|
||||
),
|
||||
position: (0, 0),
|
||||
},
|
||||
Statement::Expression(Expression::Value(ValueNode::Integer(42)))
|
||||
.with_position((0..0).into()),
|
||||
)
|
||||
.run(&context)
|
||||
.unwrap();
|
||||
@ -153,12 +149,8 @@ mod tests {
|
||||
Identifier::new("foobar"),
|
||||
None,
|
||||
AssignmentOperator::AddAssign,
|
||||
Positioned {
|
||||
node: Statement::Expression(
|
||||
Expression::Value(ValueNode::Integer(41)).positioned((0..1).into()),
|
||||
),
|
||||
position: (0, 0),
|
||||
},
|
||||
Statement::Expression(Expression::Value(ValueNode::Integer(41)))
|
||||
.with_position((0..0).into()),
|
||||
)
|
||||
.run(&context)
|
||||
.unwrap();
|
||||
@ -181,12 +173,8 @@ mod tests {
|
||||
Identifier::new("foobar"),
|
||||
None,
|
||||
AssignmentOperator::SubAssign,
|
||||
Positioned {
|
||||
node: Statement::Expression(
|
||||
Expression::Value(ValueNode::Integer(1)).positioned((0..1).into()),
|
||||
),
|
||||
position: (0, 0),
|
||||
},
|
||||
Statement::Expression(Expression::Value(ValueNode::Integer(1)))
|
||||
.with_position((0..0).into()),
|
||||
)
|
||||
.run(&context)
|
||||
.unwrap();
|
||||
@ -201,17 +189,13 @@ mod tests {
|
||||
fn type_check() {
|
||||
let validation = Assignment::new(
|
||||
Identifier::new("foobar"),
|
||||
Some(Positioned {
|
||||
Some(WithPosition {
|
||||
node: Type::Boolean,
|
||||
position: (0, 0),
|
||||
}),
|
||||
AssignmentOperator::Assign,
|
||||
Positioned {
|
||||
node: Statement::Expression(
|
||||
Expression::Value(ValueNode::Integer(42)).positioned((0..1).into()),
|
||||
),
|
||||
position: (0, 0),
|
||||
},
|
||||
Statement::Expression(Expression::Value(ValueNode::Integer(42)))
|
||||
.with_position((0..0).into()),
|
||||
)
|
||||
.validate(&Context::new());
|
||||
|
||||
|
@ -3,15 +3,15 @@ use crate::{
|
||||
error::{RuntimeError, ValidationError},
|
||||
};
|
||||
|
||||
use super::{AbstractTree, Action, Positioned, Statement, Type};
|
||||
use super::{AbstractTree, Action, Statement, Type, WithPosition};
|
||||
|
||||
#[derive(Clone, Debug, Eq, PartialEq, PartialOrd, Ord)]
|
||||
pub struct Block {
|
||||
statements: Vec<Positioned<Statement>>,
|
||||
statements: Vec<WithPosition<Statement>>,
|
||||
}
|
||||
|
||||
impl Block {
|
||||
pub fn new(statements: Vec<Positioned<Statement>>) -> Self {
|
||||
pub fn new(statements: Vec<WithPosition<Statement>>) -> Self {
|
||||
Self { statements }
|
||||
}
|
||||
}
|
||||
@ -61,18 +61,12 @@ mod tests {
|
||||
#[test]
|
||||
fn run_returns_value_of_final_statement() {
|
||||
let block = Block::new(vec![
|
||||
Statement::Expression(
|
||||
Expression::Value(ValueNode::Integer(1)).positioned((0..0).into()),
|
||||
)
|
||||
.positioned((0..0).into()),
|
||||
Statement::Expression(
|
||||
Expression::Value(ValueNode::Integer(2)).positioned((0..0).into()),
|
||||
)
|
||||
.positioned((0..0).into()),
|
||||
Statement::Expression(
|
||||
Expression::Value(ValueNode::Integer(42)).positioned((0..0).into()),
|
||||
)
|
||||
.positioned((0..0).into()),
|
||||
Statement::Expression(Expression::Value(ValueNode::Integer(1)))
|
||||
.with_position((0..0).into()),
|
||||
Statement::Expression(Expression::Value(ValueNode::Integer(2)))
|
||||
.with_position((0..0).into()),
|
||||
Statement::Expression(Expression::Value(ValueNode::Integer(42)))
|
||||
.with_position((0..0).into()),
|
||||
]);
|
||||
|
||||
assert_eq!(
|
||||
@ -84,14 +78,10 @@ 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())).positioned((0..0).into()),
|
||||
)
|
||||
.positioned((0..0).into()),
|
||||
Statement::Expression(
|
||||
Expression::Value(ValueNode::Integer(42)).positioned((0..0).into()),
|
||||
)
|
||||
.positioned((0..0).into()),
|
||||
Statement::Expression(Expression::Value(ValueNode::String("42".to_string())))
|
||||
.with_position((0..0).into()),
|
||||
Statement::Expression(Expression::Value(ValueNode::Integer(42)))
|
||||
.with_position((0..0).into()),
|
||||
]);
|
||||
|
||||
assert_eq!(block.expected_type(&Context::new()), Ok(Type::Integer))
|
||||
|
@ -3,16 +3,19 @@ use crate::{
|
||||
error::{RuntimeError, ValidationError},
|
||||
};
|
||||
|
||||
use super::{AbstractTree, Action, Expression, Positioned, Type};
|
||||
use super::{AbstractTree, Action, Expression, Type, WithPosition};
|
||||
|
||||
#[derive(Debug, Clone, Eq, PartialEq, PartialOrd, Ord)]
|
||||
pub struct FunctionCall {
|
||||
function: Box<Positioned<Expression>>,
|
||||
arguments: Vec<Positioned<Expression>>,
|
||||
function: Box<WithPosition<Expression>>,
|
||||
arguments: Vec<WithPosition<Expression>>,
|
||||
}
|
||||
|
||||
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 {
|
||||
function: Box::new(function),
|
||||
arguments,
|
||||
|
@ -3,20 +3,20 @@ use crate::{
|
||||
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)]
|
||||
pub struct IfElse {
|
||||
if_expression: Positioned<Expression>,
|
||||
if_block: Positioned<Block>,
|
||||
else_block: Option<Positioned<Block>>,
|
||||
if_expression: WithPosition<Expression>,
|
||||
if_block: WithPosition<Block>,
|
||||
else_block: Option<WithPosition<Block>>,
|
||||
}
|
||||
|
||||
impl IfElse {
|
||||
pub fn new(
|
||||
if_expression: Positioned<Expression>,
|
||||
if_block: Positioned<Block>,
|
||||
else_block: Option<Positioned<Block>>,
|
||||
if_expression: WithPosition<Expression>,
|
||||
if_block: WithPosition<Block>,
|
||||
else_block: Option<WithPosition<Block>>,
|
||||
) -> Self {
|
||||
Self {
|
||||
if_expression,
|
||||
@ -83,13 +83,12 @@ mod tests {
|
||||
fn simple_if() {
|
||||
assert_eq!(
|
||||
IfElse::new(
|
||||
Expression::Value(ValueNode::Boolean(true)).positioned((0..0).into()),
|
||||
Block::new(vec![Statement::Expression(
|
||||
Expression::Value(ValueNode::String("foo".to_string()))
|
||||
.positioned((0..0).into())
|
||||
)
|
||||
.positioned((0..0).into())])
|
||||
.positioned((0..0).into()),
|
||||
Expression::Value(ValueNode::Boolean(true)).with_position((0..0).into()),
|
||||
Block::new(vec![Statement::Expression(Expression::Value(
|
||||
ValueNode::String("foo".to_string())
|
||||
))
|
||||
.with_position((0..0).into())])
|
||||
.with_position((0..0).into()),
|
||||
None
|
||||
)
|
||||
.run(&Context::new()),
|
||||
@ -101,20 +100,18 @@ mod tests {
|
||||
fn simple_if_else() {
|
||||
assert_eq!(
|
||||
IfElse::new(
|
||||
Expression::Value(ValueNode::Boolean(false)).positioned((0..0).into()),
|
||||
Block::new(vec![Statement::Expression(
|
||||
Expression::Value(ValueNode::String("foo".to_string()))
|
||||
.positioned((0..0).into())
|
||||
)
|
||||
.positioned((0..0).into())])
|
||||
.positioned((0..0).into()),
|
||||
Expression::Value(ValueNode::Boolean(false)).with_position((0..0).into()),
|
||||
Block::new(vec![Statement::Expression(Expression::Value(
|
||||
ValueNode::String("foo".to_string())
|
||||
))
|
||||
.with_position((0..0).into())])
|
||||
.with_position((0..0).into()),
|
||||
Some(
|
||||
Block::new(vec![Statement::Expression(
|
||||
Expression::Value(ValueNode::String("bar".to_string()))
|
||||
.positioned((0..0).into())
|
||||
)
|
||||
.positioned((0..0).into())])
|
||||
.positioned((0..0).into())
|
||||
Block::new(vec![Statement::Expression(Expression::Value(
|
||||
ValueNode::String("bar".to_string())
|
||||
))
|
||||
.with_position((0..0).into())])
|
||||
.with_position((0..0).into())
|
||||
)
|
||||
)
|
||||
.run(&Context::new()),
|
||||
|
@ -3,16 +3,16 @@ use crate::{
|
||||
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)]
|
||||
pub struct Index {
|
||||
left: Positioned<Expression>,
|
||||
right: Positioned<Expression>,
|
||||
left: WithPosition<Expression>,
|
||||
right: WithPosition<Expression>,
|
||||
}
|
||||
|
||||
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 }
|
||||
}
|
||||
}
|
||||
|
@ -4,19 +4,19 @@ use crate::{
|
||||
Value,
|
||||
};
|
||||
|
||||
use super::{AbstractTree, Action, Expression, Positioned, Type};
|
||||
use super::{AbstractTree, Action, Expression, Type, WithPosition};
|
||||
|
||||
#[derive(Clone, Debug, Eq, PartialEq, PartialOrd, Ord)]
|
||||
pub enum Logic {
|
||||
Equal(Positioned<Expression>, Positioned<Expression>),
|
||||
NotEqual(Positioned<Expression>, Positioned<Expression>),
|
||||
Greater(Positioned<Expression>, Positioned<Expression>),
|
||||
Less(Positioned<Expression>, Positioned<Expression>),
|
||||
GreaterOrEqual(Positioned<Expression>, Positioned<Expression>),
|
||||
LessOrEqual(Positioned<Expression>, Positioned<Expression>),
|
||||
And(Positioned<Expression>, Positioned<Expression>),
|
||||
Or(Positioned<Expression>, Positioned<Expression>),
|
||||
Not(Positioned<Expression>),
|
||||
Equal(WithPosition<Expression>, WithPosition<Expression>),
|
||||
NotEqual(WithPosition<Expression>, WithPosition<Expression>),
|
||||
Greater(WithPosition<Expression>, WithPosition<Expression>),
|
||||
Less(WithPosition<Expression>, WithPosition<Expression>),
|
||||
GreaterOrEqual(WithPosition<Expression>, WithPosition<Expression>),
|
||||
LessOrEqual(WithPosition<Expression>, WithPosition<Expression>),
|
||||
And(WithPosition<Expression>, WithPosition<Expression>),
|
||||
Or(WithPosition<Expression>, WithPosition<Expression>),
|
||||
Not(WithPosition<Expression>),
|
||||
}
|
||||
|
||||
impl AbstractTree for Logic {
|
||||
@ -139,8 +139,8 @@ mod tests {
|
||||
#[test]
|
||||
fn equal() {
|
||||
assert!(Logic::Equal(
|
||||
Expression::Value(ValueNode::Integer(42)).positioned((0..0).into()),
|
||||
Expression::Value(ValueNode::Integer(42)).positioned((0..0).into()),
|
||||
Expression::Value(ValueNode::Integer(42)).with_position((0..0).into()),
|
||||
Expression::Value(ValueNode::Integer(42)).with_position((0..0).into()),
|
||||
)
|
||||
.run(&Context::new())
|
||||
.unwrap()
|
||||
@ -153,8 +153,8 @@ mod tests {
|
||||
#[test]
|
||||
fn not_equal() {
|
||||
assert!(Logic::NotEqual(
|
||||
Expression::Value(ValueNode::Integer(42)).positioned((0..0).into()),
|
||||
Expression::Value(ValueNode::Integer(43)).positioned((0..0).into()),
|
||||
Expression::Value(ValueNode::Integer(42)).with_position((0..0).into()),
|
||||
Expression::Value(ValueNode::Integer(43)).with_position((0..0).into()),
|
||||
)
|
||||
.run(&Context::new())
|
||||
.unwrap()
|
||||
@ -167,8 +167,8 @@ mod tests {
|
||||
#[test]
|
||||
fn greater() {
|
||||
assert!(Logic::Greater(
|
||||
Expression::Value(ValueNode::Integer(43)).positioned((0..0).into()),
|
||||
Expression::Value(ValueNode::Integer(42)).positioned((0..0).into()),
|
||||
Expression::Value(ValueNode::Integer(43)).with_position((0..0).into()),
|
||||
Expression::Value(ValueNode::Integer(42)).with_position((0..0).into()),
|
||||
)
|
||||
.run(&Context::new())
|
||||
.unwrap()
|
||||
@ -181,8 +181,8 @@ mod tests {
|
||||
#[test]
|
||||
fn less() {
|
||||
assert!(Logic::Less(
|
||||
Expression::Value(ValueNode::Integer(42)).positioned((0..0).into()),
|
||||
Expression::Value(ValueNode::Integer(43)).positioned((0..0).into()),
|
||||
Expression::Value(ValueNode::Integer(42)).with_position((0..0).into()),
|
||||
Expression::Value(ValueNode::Integer(43)).with_position((0..0).into()),
|
||||
)
|
||||
.run(&Context::new())
|
||||
.unwrap()
|
||||
@ -195,8 +195,8 @@ mod tests {
|
||||
#[test]
|
||||
fn greater_or_equal() {
|
||||
assert!(Logic::GreaterOrEqual(
|
||||
Expression::Value(ValueNode::Integer(42)).positioned((0..0).into()),
|
||||
Expression::Value(ValueNode::Integer(41)).positioned((0..0).into()),
|
||||
Expression::Value(ValueNode::Integer(42)).with_position((0..0).into()),
|
||||
Expression::Value(ValueNode::Integer(41)).with_position((0..0).into()),
|
||||
)
|
||||
.run(&Context::new())
|
||||
.unwrap()
|
||||
@ -206,8 +206,8 @@ mod tests {
|
||||
.unwrap());
|
||||
|
||||
assert!(Logic::GreaterOrEqual(
|
||||
Expression::Value(ValueNode::Integer(42)).positioned((0..0).into()),
|
||||
Expression::Value(ValueNode::Integer(42)).positioned((0..0).into()),
|
||||
Expression::Value(ValueNode::Integer(42)).with_position((0..0).into()),
|
||||
Expression::Value(ValueNode::Integer(42)).with_position((0..0).into()),
|
||||
)
|
||||
.run(&Context::new())
|
||||
.unwrap()
|
||||
@ -220,8 +220,8 @@ mod tests {
|
||||
#[test]
|
||||
fn less_or_equal() {
|
||||
assert!(Logic::LessOrEqual(
|
||||
Expression::Value(ValueNode::Integer(42)).positioned((0..0).into()),
|
||||
Expression::Value(ValueNode::Integer(43)).positioned((0..0).into()),
|
||||
Expression::Value(ValueNode::Integer(42)).with_position((0..0).into()),
|
||||
Expression::Value(ValueNode::Integer(43)).with_position((0..0).into()),
|
||||
)
|
||||
.run(&Context::new())
|
||||
.unwrap()
|
||||
@ -231,8 +231,8 @@ mod tests {
|
||||
.unwrap());
|
||||
|
||||
assert!(Logic::LessOrEqual(
|
||||
Expression::Value(ValueNode::Integer(42)).positioned((0..0).into()),
|
||||
Expression::Value(ValueNode::Integer(42)).positioned((0..0).into()),
|
||||
Expression::Value(ValueNode::Integer(42)).with_position((0..0).into()),
|
||||
Expression::Value(ValueNode::Integer(42)).with_position((0..0).into()),
|
||||
)
|
||||
.run(&Context::new())
|
||||
.unwrap()
|
||||
@ -245,8 +245,8 @@ mod tests {
|
||||
#[test]
|
||||
fn and() {
|
||||
assert!(Logic::And(
|
||||
Expression::Value(ValueNode::Boolean(true)).positioned((0..0).into()),
|
||||
Expression::Value(ValueNode::Boolean(true)).positioned((0..0).into()),
|
||||
Expression::Value(ValueNode::Boolean(true)).with_position((0..0).into()),
|
||||
Expression::Value(ValueNode::Boolean(true)).with_position((0..0).into()),
|
||||
)
|
||||
.run(&Context::new())
|
||||
.unwrap()
|
||||
@ -259,8 +259,8 @@ mod tests {
|
||||
#[test]
|
||||
fn or() {
|
||||
assert!(Logic::Or(
|
||||
Expression::Value(ValueNode::Boolean(true)).positioned((0..0).into()),
|
||||
Expression::Value(ValueNode::Boolean(false)).positioned((0..0).into()),
|
||||
Expression::Value(ValueNode::Boolean(true)).with_position((0..0).into()),
|
||||
Expression::Value(ValueNode::Boolean(false)).with_position((0..0).into()),
|
||||
)
|
||||
.run(&Context::new())
|
||||
.unwrap()
|
||||
@ -272,14 +272,14 @@ mod tests {
|
||||
|
||||
#[test]
|
||||
fn not() {
|
||||
assert!(
|
||||
Logic::Not(Expression::Value(ValueNode::Boolean(false)).positioned((0..0).into()))
|
||||
.run(&Context::new())
|
||||
.unwrap()
|
||||
.as_return_value()
|
||||
.unwrap()
|
||||
.as_boolean()
|
||||
.unwrap()
|
||||
assert!(Logic::Not(
|
||||
Expression::Value(ValueNode::Boolean(false)).with_position((0..0).into())
|
||||
)
|
||||
.run(&Context::new())
|
||||
.unwrap()
|
||||
.as_return_value()
|
||||
.unwrap()
|
||||
.as_boolean()
|
||||
.unwrap())
|
||||
}
|
||||
}
|
||||
|
@ -3,15 +3,15 @@ use crate::{
|
||||
error::{RuntimeError, ValidationError},
|
||||
};
|
||||
|
||||
use super::{AbstractTree, Action, Positioned, Statement, Type};
|
||||
use super::{AbstractTree, Action, Statement, Type, WithPosition};
|
||||
|
||||
#[derive(Clone, Debug, Eq, PartialEq, PartialOrd, Ord)]
|
||||
pub struct Loop {
|
||||
statements: Vec<Positioned<Statement>>,
|
||||
statements: Vec<WithPosition<Statement>>,
|
||||
}
|
||||
|
||||
impl Loop {
|
||||
pub fn new(statements: Vec<Positioned<Statement>>) -> Self {
|
||||
pub fn new(statements: Vec<WithPosition<Statement>>) -> Self {
|
||||
Self { statements }
|
||||
}
|
||||
}
|
||||
@ -58,7 +58,7 @@ mod tests {
|
||||
#[test]
|
||||
fn basic_loop() {
|
||||
let result = Loop {
|
||||
statements: vec![Statement::Break.positioned((0..0).into())],
|
||||
statements: vec![Statement::Break.with_position((0..0).into())],
|
||||
}
|
||||
.run(&Context::new());
|
||||
|
||||
|
@ -5,15 +5,15 @@ use crate::{
|
||||
Value,
|
||||
};
|
||||
|
||||
use super::{AbstractTree, Action, Expression, Positioned, Type};
|
||||
use super::{AbstractTree, Action, Expression, Type, WithPosition};
|
||||
|
||||
#[derive(Clone, Debug, Eq, PartialEq, PartialOrd, Ord)]
|
||||
pub enum Math {
|
||||
Add(Positioned<Expression>, Positioned<Expression>),
|
||||
Subtract(Positioned<Expression>, Positioned<Expression>),
|
||||
Multiply(Positioned<Expression>, Positioned<Expression>),
|
||||
Divide(Positioned<Expression>, Positioned<Expression>),
|
||||
Modulo(Positioned<Expression>, Positioned<Expression>),
|
||||
Add(WithPosition<Expression>, WithPosition<Expression>),
|
||||
Subtract(WithPosition<Expression>, WithPosition<Expression>),
|
||||
Multiply(WithPosition<Expression>, WithPosition<Expression>),
|
||||
Divide(WithPosition<Expression>, WithPosition<Expression>),
|
||||
Modulo(WithPosition<Expression>, WithPosition<Expression>),
|
||||
}
|
||||
|
||||
impl AbstractTree for Math {
|
||||
|
@ -39,7 +39,7 @@ use crate::{
|
||||
};
|
||||
|
||||
#[derive(Clone, Debug, Eq, PartialEq, PartialOrd, Ord)]
|
||||
pub struct Positioned<T> {
|
||||
pub struct WithPosition<T> {
|
||||
pub node: T,
|
||||
pub position: (usize, usize),
|
||||
}
|
||||
@ -49,8 +49,8 @@ pub trait AbstractTree: Sized {
|
||||
fn validate(&self, context: &Context) -> Result<(), ValidationError>;
|
||||
fn run(self, context: &Context) -> Result<Action, RuntimeError>;
|
||||
|
||||
fn positioned(self, span: SimpleSpan) -> Positioned<Self> {
|
||||
Positioned {
|
||||
fn with_position(self, span: SimpleSpan) -> WithPosition<Self> {
|
||||
WithPosition {
|
||||
node: self,
|
||||
position: (span.start(), span.end()),
|
||||
}
|
||||
|
@ -3,16 +3,14 @@ use crate::{
|
||||
error::{RuntimeError, ValidationError},
|
||||
};
|
||||
|
||||
use super::{
|
||||
AbstractTree, Action, Assignment, Block, Expression, IfElse, Loop, Positioned, Type, While,
|
||||
};
|
||||
use super::{AbstractTree, Action, Assignment, Block, Expression, IfElse, Loop, Type, While};
|
||||
|
||||
#[derive(Clone, Debug, Eq, PartialEq, PartialOrd, Ord)]
|
||||
pub enum Statement {
|
||||
Assignment(Assignment),
|
||||
Block(Block),
|
||||
Break,
|
||||
Expression(Positioned<Expression>),
|
||||
Expression(Expression),
|
||||
IfElse(IfElse),
|
||||
Loop(Loop),
|
||||
While(While),
|
||||
@ -24,7 +22,7 @@ impl AbstractTree for Statement {
|
||||
Statement::Assignment(assignment) => assignment.expected_type(_context),
|
||||
Statement::Block(block) => block.expected_type(_context),
|
||||
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::Loop(r#loop) => r#loop.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::Block(block) => block.validate(_context),
|
||||
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::Loop(r#loop) => r#loop.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::Block(block) => block.run(_context),
|
||||
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::Loop(r#loop) => r#loop.run(_context),
|
||||
Statement::While(r#while) => r#while.run(_context),
|
||||
|
@ -6,21 +6,27 @@ use crate::{
|
||||
Value,
|
||||
};
|
||||
|
||||
use super::{AbstractTree, Action, Block, Expression, Identifier, Positioned, Type};
|
||||
use super::{AbstractTree, Action, Block, Expression, Identifier, Type, WithPosition};
|
||||
|
||||
#[derive(Clone, Debug, PartialEq)]
|
||||
pub enum ValueNode {
|
||||
Boolean(bool),
|
||||
Float(f64),
|
||||
Integer(i64),
|
||||
List(Vec<Positioned<Expression>>),
|
||||
Map(Vec<(Identifier, Option<Positioned<Type>>, Positioned<Expression>)>),
|
||||
List(Vec<WithPosition<Expression>>),
|
||||
Map(
|
||||
Vec<(
|
||||
Identifier,
|
||||
Option<WithPosition<Type>>,
|
||||
WithPosition<Expression>,
|
||||
)>,
|
||||
),
|
||||
Range(Range<i64>),
|
||||
String(String),
|
||||
Function {
|
||||
parameters: Vec<(Identifier, Positioned<Type>)>,
|
||||
return_type: Positioned<Type>,
|
||||
body: Positioned<Block>,
|
||||
parameters: Vec<(Identifier, WithPosition<Type>)>,
|
||||
return_type: WithPosition<Type>,
|
||||
body: WithPosition<Block>,
|
||||
},
|
||||
}
|
||||
|
||||
@ -70,7 +76,7 @@ impl AbstractTree for ValueNode {
|
||||
actual_position: expression.position,
|
||||
expected_position: expected_type.position,
|
||||
}
|
||||
});
|
||||
})?;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -3,16 +3,16 @@ use crate::{
|
||||
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)]
|
||||
pub struct While {
|
||||
expression: Positioned<Expression>,
|
||||
expression: WithPosition<Expression>,
|
||||
block: Block,
|
||||
}
|
||||
|
||||
impl While {
|
||||
pub fn new(expression: Positioned<Expression>, block: Block) -> Self {
|
||||
pub fn new(expression: WithPosition<Expression>, block: Block) -> Self {
|
||||
Self { expression, block }
|
||||
}
|
||||
}
|
||||
|
@ -19,7 +19,10 @@ pub enum Error {
|
||||
span: (usize, usize),
|
||||
},
|
||||
Runtime(RuntimeError),
|
||||
Validation(ValidationError, (usize, usize)),
|
||||
Validation {
|
||||
error: ValidationError,
|
||||
position: (usize, usize),
|
||||
},
|
||||
}
|
||||
|
||||
impl Error {
|
||||
@ -46,7 +49,7 @@ impl Error {
|
||||
.finish()
|
||||
}
|
||||
Error::Runtime(_) => todo!(),
|
||||
Error::Validation(validation_error, position) => {
|
||||
Error::Validation { error, position } => {
|
||||
let mut report = Report::build(
|
||||
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."),
|
||||
);
|
||||
|
||||
match validation_error {
|
||||
match error {
|
||||
ValidationError::ExpectedBoolean => {
|
||||
report =
|
||||
report.with_label(Label::new(0..0).with_message("Expected boolean."));
|
||||
|
13
src/lib.rs
13
src/lib.rs
@ -5,7 +5,7 @@ pub mod lexer;
|
||||
pub mod parser;
|
||||
pub mod value;
|
||||
|
||||
use abstract_tree::{AbstractTree, Action};
|
||||
use abstract_tree::{AbstractTree, Action, WithPosition};
|
||||
use context::Context;
|
||||
use error::Error;
|
||||
use lexer::lex;
|
||||
@ -33,12 +33,13 @@ impl Interpreter {
|
||||
let statements = parse(&tokens)?;
|
||||
let errors = statements
|
||||
.iter()
|
||||
.filter_map(|statement| {
|
||||
statement
|
||||
.node
|
||||
.validate(&self.context)
|
||||
.filter_map(|WithPosition { node, position }| {
|
||||
node.validate(&self.context)
|
||||
.err()
|
||||
.map(|validation_error| Error::Validation(validation_error, statement.position))
|
||||
.map(|error| Error::Validation {
|
||||
error,
|
||||
position: position.clone(),
|
||||
})
|
||||
})
|
||||
.collect::<Vec<Error>>();
|
||||
|
||||
|
217
src/parser.rs
217
src/parser.rs
@ -12,7 +12,7 @@ pub type DustParser<'src> = Boxed<
|
||||
'src,
|
||||
'src,
|
||||
ParserInput<'src>,
|
||||
Vec<Positioned<Statement>>,
|
||||
Vec<WithPosition<Statement>>,
|
||||
extra::Err<Rich<'src, Token<'src>, SimpleSpan>>,
|
||||
>;
|
||||
|
||||
@ -21,7 +21,7 @@ pub type ParserInput<'src> =
|
||||
|
||||
pub fn parse<'src>(
|
||||
tokens: &'src [(Token<'src>, SimpleSpan)],
|
||||
) -> Result<Vec<Positioned<Statement>>, Vec<Error>> {
|
||||
) -> Result<Vec<WithPosition<Statement>>, Vec<Error>> {
|
||||
parser()
|
||||
.parse(tokens.spanned((tokens.len()..tokens.len()).into()))
|
||||
.into_result()
|
||||
@ -53,7 +53,7 @@ pub fn parser<'src>() -> DustParser<'src> {
|
||||
Token::Float(float) => ValueNode::Float(float),
|
||||
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();
|
||||
|
||||
let r#type = recursive(|r#type| {
|
||||
@ -106,12 +106,12 @@ pub fn parser<'src>() -> DustParser<'src> {
|
||||
.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 statement = recursive(|statement| {
|
||||
let block = statement
|
||||
let positioned_statement = recursive(|positioned_statement| {
|
||||
let block = positioned_statement
|
||||
.clone()
|
||||
.repeated()
|
||||
.collect()
|
||||
@ -123,11 +123,11 @@ pub fn parser<'src>() -> DustParser<'src> {
|
||||
|
||||
let positioned_block = block
|
||||
.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| {
|
||||
Expression::Identifier(identifier).positioned(state.span())
|
||||
Expression::Identifier(identifier).with_position(state.span())
|
||||
});
|
||||
|
||||
let range = {
|
||||
@ -140,11 +140,11 @@ pub fn parser<'src>() -> DustParser<'src> {
|
||||
.then_ignore(just(Token::Control(Control::DoubleDot)))
|
||||
.then(raw_integer)
|
||||
.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()
|
||||
.separated_by(just(Token::Control(Control::Comma)))
|
||||
.allow_trailing()
|
||||
@ -154,14 +154,14 @@ pub fn parser<'src>() -> DustParser<'src> {
|
||||
just(Token::Control(Control::SquareClose)),
|
||||
)
|
||||
.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
|
||||
.clone()
|
||||
.then(type_specification.clone().or_not())
|
||||
.then_ignore(just(Token::Operator(Operator::Assign)))
|
||||
.then(expression.clone())
|
||||
.then(positioned_expression.clone())
|
||||
.map(|((identifier, r#type), expression)| (identifier, r#type, expression));
|
||||
|
||||
let map = map_assignment
|
||||
@ -173,7 +173,8 @@ pub fn parser<'src>() -> DustParser<'src> {
|
||||
just(Token::Control(Control::CurlyClose)),
|
||||
)
|
||||
.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
|
||||
@ -191,16 +192,16 @@ pub fn parser<'src>() -> DustParser<'src> {
|
||||
Expression::Value(ValueNode::Function {
|
||||
parameters,
|
||||
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_call = function_expression
|
||||
.then(
|
||||
expression
|
||||
positioned_expression
|
||||
.clone()
|
||||
.separated_by(just(Token::Control(Control::Comma)))
|
||||
.collect()
|
||||
@ -211,7 +212,7 @@ pub fn parser<'src>() -> DustParser<'src> {
|
||||
)
|
||||
.map_with(|(function, arguments), state| {
|
||||
Expression::FunctionCall(FunctionCall::new(function, arguments))
|
||||
.positioned(state.span())
|
||||
.with_position(state.span())
|
||||
});
|
||||
|
||||
let atom = choice((
|
||||
@ -219,7 +220,7 @@ pub fn parser<'src>() -> DustParser<'src> {
|
||||
identifier_expression.clone(),
|
||||
basic_value.clone(),
|
||||
list.clone(),
|
||||
expression.clone().delimited_by(
|
||||
positioned_expression.clone().delimited_by(
|
||||
just(Token::Control(Control::ParenOpen)),
|
||||
just(Token::Control(Control::ParenClose)),
|
||||
),
|
||||
@ -229,41 +230,42 @@ pub fn parser<'src>() -> DustParser<'src> {
|
||||
|
||||
let logic_math_and_index = atom.pratt((
|
||||
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(
|
||||
left(3),
|
||||
just(Token::Control(Control::Dot)),
|
||||
|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(
|
||||
left(1),
|
||||
just(Token::Operator(Equal)),
|
||||
|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(
|
||||
left(1),
|
||||
just(Token::Operator(NotEqual)),
|
||||
|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(
|
||||
left(1),
|
||||
just(Token::Operator(Greater)),
|
||||
|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(
|
||||
left(1),
|
||||
just(Token::Operator(Less)),
|
||||
|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(
|
||||
@ -271,7 +273,7 @@ pub fn parser<'src>() -> DustParser<'src> {
|
||||
just(Token::Operator(GreaterOrEqual)),
|
||||
|left, _, right, span| {
|
||||
Expression::Logic(Box::new(Logic::GreaterOrEqual(left, right)))
|
||||
.positioned(span)
|
||||
.with_position(span)
|
||||
},
|
||||
),
|
||||
infix(
|
||||
@ -279,56 +281,56 @@ pub fn parser<'src>() -> DustParser<'src> {
|
||||
just(Token::Operator(LessOrEqual)),
|
||||
|left, _, right, span| {
|
||||
Expression::Logic(Box::new(Logic::LessOrEqual(left, right)))
|
||||
.positioned(span)
|
||||
.with_position(span)
|
||||
},
|
||||
),
|
||||
infix(
|
||||
left(1),
|
||||
just(Token::Operator(And)),
|
||||
|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(
|
||||
left(1),
|
||||
just(Token::Operator(Or)),
|
||||
|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(
|
||||
left(1),
|
||||
just(Token::Operator(Add)),
|
||||
|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(
|
||||
left(1),
|
||||
just(Token::Operator(Subtract)),
|
||||
|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(
|
||||
left(2),
|
||||
just(Token::Operator(Multiply)),
|
||||
|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(
|
||||
left(2),
|
||||
just(Token::Operator(Divide)),
|
||||
|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(
|
||||
left(1),
|
||||
just(Token::Operator(Modulo)),
|
||||
|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| {
|
||||
Statement::Expression(expression).positioned(state.span())
|
||||
});
|
||||
let expression_statement =
|
||||
positioned_expression
|
||||
.clone()
|
||||
.map_with(|positioned_expression, state| {
|
||||
Statement::Expression(positioned_expression.node).with_position(state.span())
|
||||
});
|
||||
|
||||
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
|
||||
.clone()
|
||||
@ -360,17 +365,17 @@ pub fn parser<'src>() -> DustParser<'src> {
|
||||
just(Token::Operator(Operator::AddAssign)).to(AssignmentOperator::AddAssign),
|
||||
just(Token::Operator(Operator::SubAssign)).to(AssignmentOperator::SubAssign),
|
||||
)))
|
||||
.then(statement.clone())
|
||||
.then(positioned_statement.clone())
|
||||
.map_with(|(((identifier, r#type), operator), statement), state| {
|
||||
Statement::Assignment(Assignment::new(identifier, r#type, operator, statement))
|
||||
.positioned(state.span())
|
||||
.with_position(state.span())
|
||||
});
|
||||
|
||||
let block_statement = block
|
||||
.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()
|
||||
.repeated()
|
||||
.at_least(1)
|
||||
@ -380,18 +385,18 @@ pub fn parser<'src>() -> DustParser<'src> {
|
||||
just(Token::Control(Control::CurlyClose)),
|
||||
)
|
||||
.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"))
|
||||
.ignore_then(expression.clone())
|
||||
.ignore_then(positioned_expression.clone())
|
||||
.then(block.clone())
|
||||
.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"))
|
||||
.ignore_then(expression.clone())
|
||||
.ignore_then(positioned_expression.clone())
|
||||
.then(positioned_block.clone())
|
||||
.then(
|
||||
just(Token::Keyword("else"))
|
||||
@ -400,7 +405,7 @@ pub fn parser<'src>() -> DustParser<'src> {
|
||||
)
|
||||
.map_with(|((if_expression, if_block), else_block), state| {
|
||||
Statement::IfElse(IfElse::new(if_expression, if_block, else_block))
|
||||
.positioned(state.span())
|
||||
.with_position(state.span())
|
||||
});
|
||||
|
||||
choice((
|
||||
@ -415,7 +420,7 @@ pub fn parser<'src>() -> DustParser<'src> {
|
||||
.then_ignore(just(Token::Control(Control::Semicolon)).or_not())
|
||||
});
|
||||
|
||||
statement.repeated().collect().boxed()
|
||||
positioned_statement.repeated().collect().boxed()
|
||||
}
|
||||
|
||||
#[cfg(test)]
|
||||
@ -429,19 +434,18 @@ mod tests {
|
||||
assert_eq!(
|
||||
parse(&lex("while true { output('hi') }").unwrap()).unwrap()[0],
|
||||
Statement::While(While::new(
|
||||
Expression::Value(ValueNode::Boolean(true)).positioned((6..11).into()),
|
||||
Block::new(vec![Statement::Expression(
|
||||
Expression::FunctionCall(FunctionCall::new(
|
||||
Expression::Value(ValueNode::Boolean(true)).with_position((6..11).into()),
|
||||
Block::new(vec![Statement::Expression(Expression::FunctionCall(
|
||||
FunctionCall::new(
|
||||
Expression::Identifier(Identifier::new("output"))
|
||||
.positioned((13..19).into()),
|
||||
.with_position((13..19).into()),
|
||||
vec![Expression::Value(ValueNode::String("hi".to_string()))
|
||||
.positioned((20..24).into())]
|
||||
))
|
||||
.positioned((13..26).into())
|
||||
)
|
||||
.positioned((13..26).into())])
|
||||
.with_position((20..24).into())]
|
||||
)
|
||||
))
|
||||
.with_position((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],
|
||||
Statement::Assignment(Assignment::new(
|
||||
Identifier::new("foobar"),
|
||||
Some(Type::Boolean.positioned((9..14).into())),
|
||||
Some(Type::Boolean.with_position((9..14).into())),
|
||||
AssignmentOperator::Assign,
|
||||
Statement::Expression(
|
||||
Expression::Value(ValueNode::Boolean(true)).positioned((16..20).into())
|
||||
)
|
||||
.positioned((16..20).into())
|
||||
Statement::Expression(Expression::Value(ValueNode::Boolean(true)))
|
||||
.with_position((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],
|
||||
Statement::Assignment(Assignment::new(
|
||||
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,
|
||||
Statement::Expression(
|
||||
Expression::Value(ValueNode::List(vec![Expression::Value(
|
||||
ValueNode::Boolean(true)
|
||||
)
|
||||
.positioned((23..27).into())]))
|
||||
.positioned((22..28).into())
|
||||
Statement::Expression(Expression::Value(ValueNode::List(vec![Expression::Value(
|
||||
ValueNode::Boolean(true)
|
||||
)
|
||||
.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],
|
||||
Statement::Assignment(Assignment::new(
|
||||
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,
|
||||
Statement::Expression(
|
||||
Expression::Value(ValueNode::List(vec![
|
||||
Expression::Value(ValueNode::Boolean(true)).positioned((24..28).into()),
|
||||
Expression::Value(ValueNode::String("42".to_string()))
|
||||
.positioned((30..34).into())
|
||||
]))
|
||||
.positioned((23..35).into())
|
||||
)
|
||||
.positioned((23..35).into())
|
||||
Statement::Expression(Expression::Value(ValueNode::List(vec![
|
||||
Expression::Value(ValueNode::Boolean(true)).with_position((24..28).into()),
|
||||
Expression::Value(ValueNode::String("42".to_string()))
|
||||
.with_position((30..34).into())
|
||||
])))
|
||||
.with_position((23..35).into())
|
||||
),)
|
||||
.positioned((0..35).into())
|
||||
.with_position((0..35).into())
|
||||
);
|
||||
}
|
||||
|
||||
@ -516,40 +515,36 @@ mod tests {
|
||||
parameter_types: vec![],
|
||||
return_type: Box::new(Type::Any)
|
||||
}
|
||||
.positioned((9..19).into())
|
||||
.with_position((9..19).into())
|
||||
),
|
||||
AssignmentOperator::Assign,
|
||||
Statement::Expression(
|
||||
Expression::Identifier(Identifier::new("some_function"))
|
||||
.positioned((21..34).into())
|
||||
)
|
||||
.positioned((21..34).into())
|
||||
Statement::Expression(Expression::Identifier(Identifier::new("some_function")))
|
||||
.with_position((21..34).into())
|
||||
),)
|
||||
.positioned((0..34).into())
|
||||
.with_position((0..34).into())
|
||||
);
|
||||
}
|
||||
|
||||
// #[test]
|
||||
// fn function_call() {
|
||||
// assert_eq!(
|
||||
// parse(&lex("output()").unwrap()).unwrap()[0],
|
||||
// Statement::expression(
|
||||
// Expression::FunctionCall(FunctionCall::new(
|
||||
// Expression::Identifier(Identifier::new("output")),
|
||||
// Vec::with_capacity(0),
|
||||
// )),
|
||||
// (0..0).into()
|
||||
// )
|
||||
// )
|
||||
// }
|
||||
#[test]
|
||||
fn function_call() {
|
||||
assert_eq!(
|
||||
parse(&lex("output()").unwrap()).unwrap()[0],
|
||||
Statement::Expression(Expression::FunctionCall(FunctionCall::new(
|
||||
Expression::Identifier(Identifier::new("output")).with_position((0..6).into()),
|
||||
Vec::with_capacity(0),
|
||||
)))
|
||||
.with_position((0..8).into())
|
||||
)
|
||||
}
|
||||
|
||||
// #[test]
|
||||
// fn range() {
|
||||
// assert_eq!(
|
||||
// parse(&lex("1..10").unwrap()).unwrap()[0],
|
||||
// Statement::expression(Expression::Value(ValueNode::Range(1..10)), (0..0).into())
|
||||
// )
|
||||
// }
|
||||
#[test]
|
||||
fn range() {
|
||||
assert_eq!(
|
||||
parse(&lex("1..10").unwrap()).unwrap()[0],
|
||||
Statement::Expression(Expression::Value(ValueNode::Range(1..10)))
|
||||
.with_position((0..5).into())
|
||||
)
|
||||
}
|
||||
|
||||
// #[test]
|
||||
// fn function() {
|
||||
|
14
src/value.rs
14
src/value.rs
@ -13,7 +13,7 @@ use stanza::{
|
||||
};
|
||||
|
||||
use crate::{
|
||||
abstract_tree::{AbstractTree, Action, Block, Identifier, Positioned, Type},
|
||||
abstract_tree::{AbstractTree, Action, Block, Identifier, Type, WithPosition},
|
||||
context::Context,
|
||||
error::{RuntimeError, ValidationError},
|
||||
};
|
||||
@ -55,9 +55,9 @@ impl Value {
|
||||
}
|
||||
|
||||
pub fn function(
|
||||
parameters: Vec<(Identifier, Positioned<Type>)>,
|
||||
return_type: Positioned<Type>,
|
||||
body: Positioned<Block>,
|
||||
parameters: Vec<(Identifier, WithPosition<Type>)>,
|
||||
return_type: WithPosition<Type>,
|
||||
body: WithPosition<Block>,
|
||||
) -> Self {
|
||||
Value(Arc::new(ValueInner::Function(Function::Parsed(
|
||||
ParsedFunction {
|
||||
@ -330,9 +330,9 @@ impl Function {
|
||||
|
||||
#[derive(Clone, Debug, Eq, PartialEq, PartialOrd, Ord)]
|
||||
pub struct ParsedFunction {
|
||||
parameters: Vec<(Identifier, Positioned<Type>)>,
|
||||
return_type: Positioned<Type>,
|
||||
body: Positioned<Block>,
|
||||
parameters: Vec<(Identifier, WithPosition<Type>)>,
|
||||
return_type: WithPosition<Type>,
|
||||
body: WithPosition<Block>,
|
||||
}
|
||||
|
||||
#[derive(Clone, Debug, Eq, PartialEq, PartialOrd, Ord)]
|
||||
|
@ -62,7 +62,7 @@ fn function_context_does_not_capture_values() {
|
||||
),
|
||||
Err(vec![Error::Validation {
|
||||
error: ValidationError::VariableNotFound(Identifier::new("x")),
|
||||
span: (32, 66)
|
||||
position: (0, 0)
|
||||
}])
|
||||
);
|
||||
|
||||
|
@ -136,11 +136,15 @@ fn map_type_errors() {
|
||||
assert_eq!(
|
||||
interpret("{ foo : bool = 'bar' }"),
|
||||
Err(vec![Error::Validation {
|
||||
error: ValidationError::TypeCheck(TypeConflict {
|
||||
actual: Type::String,
|
||||
expected: Type::Boolean
|
||||
}),
|
||||
span: (0, 22)
|
||||
error: ValidationError::TypeCheck {
|
||||
conflict: TypeConflict {
|
||||
actual: Type::String,
|
||||
expected: Type::Boolean
|
||||
},
|
||||
actual_position: (0, 0),
|
||||
expected_position: (0, 0),
|
||||
},
|
||||
position: (0, 22)
|
||||
}])
|
||||
);
|
||||
}
|
||||
|
@ -1,5 +1,5 @@
|
||||
use dust_lang::{
|
||||
abstract_tree::{Block, Expression, Identifier, Statement, Type},
|
||||
abstract_tree::{AbstractTree, Block, Expression, Identifier, Statement, Type},
|
||||
error::{Error, TypeConflict, ValidationError},
|
||||
*,
|
||||
};
|
||||
@ -25,11 +25,15 @@ fn set_variable_with_type_error() {
|
||||
assert_eq!(
|
||||
interpret("foobar: str = true"),
|
||||
Err(vec![Error::Validation {
|
||||
error: ValidationError::TypeCheck(TypeConflict {
|
||||
actual: Type::Boolean,
|
||||
expected: Type::String
|
||||
}),
|
||||
span: (0, 18)
|
||||
error: ValidationError::TypeCheck {
|
||||
conflict: TypeConflict {
|
||||
actual: Type::Boolean,
|
||||
expected: Type::String
|
||||
},
|
||||
actual_position: (0, 0),
|
||||
expected_position: (0, 0)
|
||||
},
|
||||
position: (0, 18)
|
||||
}])
|
||||
);
|
||||
}
|
||||
@ -39,12 +43,16 @@ fn function_variable() {
|
||||
assert_eq!(
|
||||
interpret("foobar = (x: int): int { x }; foobar"),
|
||||
Ok(Some(Value::function(
|
||||
vec![(Identifier::new("x"), Type::Integer)],
|
||||
Type::Integer,
|
||||
Block::new(vec![Statement::expression(
|
||||
Expression::Identifier(Identifier::new("x")),
|
||||
(0..0).into()
|
||||
)])
|
||||
vec![(
|
||||
Identifier::new("x"),
|
||||
Type::Integer.with_position((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())
|
||||
)))
|
||||
);
|
||||
}
|
||||
|
Loading…
Reference in New Issue
Block a user