Fix tests; Refine parsing
This commit is contained in:
parent
f9b4b1bc01
commit
4ea19f238e
@ -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());
|
||||||
|
|
||||||
|
@ -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))
|
||||||
|
@ -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,
|
||||||
|
@ -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()),
|
||||||
|
@ -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 }
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -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())
|
.run(&Context::new())
|
||||||
.unwrap()
|
.unwrap()
|
||||||
.as_return_value()
|
.as_return_value()
|
||||||
.unwrap()
|
.unwrap()
|
||||||
.as_boolean()
|
.as_boolean()
|
||||||
.unwrap()
|
.unwrap())
|
||||||
)
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -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());
|
||||||
|
|
||||||
|
@ -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 {
|
||||||
|
@ -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()),
|
||||||
}
|
}
|
||||||
|
@ -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),
|
||||||
|
@ -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,
|
||||||
}
|
}
|
||||||
});
|
})?;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -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 }
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -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."));
|
||||||
|
13
src/lib.rs
13
src/lib.rs
@ -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>>();
|
||||||
|
|
||||||
|
209
src/parser.rs
209
src/parser.rs
@ -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())
|
|
||||||
)
|
)
|
||||||
.positioned((13..26).into())])
|
|
||||||
))
|
))
|
||||||
.positioned((0..27).into())
|
.with_position((13..26).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())]))
|
.with_position((23..27).into())])))
|
||||||
.positioned((22..28).into())
|
.with_position((22..28).into())
|
||||||
)
|
|
||||||
.positioned((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()))
|
||||||
.positioned((30..34).into())
|
.with_position((30..34).into())
|
||||||
]))
|
])))
|
||||||
.positioned((23..35).into())
|
.with_position((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() {
|
||||||
|
14
src/value.rs
14
src/value.rs
@ -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)]
|
||||||
|
@ -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)
|
||||||
}])
|
}])
|
||||||
);
|
);
|
||||||
|
|
||||||
|
@ -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 {
|
||||||
|
conflict: TypeConflict {
|
||||||
actual: Type::String,
|
actual: Type::String,
|
||||||
expected: Type::Boolean
|
expected: Type::Boolean
|
||||||
}),
|
},
|
||||||
span: (0, 22)
|
actual_position: (0, 0),
|
||||||
|
expected_position: (0, 0),
|
||||||
|
},
|
||||||
|
position: (0, 22)
|
||||||
}])
|
}])
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
@ -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 {
|
||||||
|
conflict: TypeConflict {
|
||||||
actual: Type::Boolean,
|
actual: Type::Boolean,
|
||||||
expected: Type::String
|
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())
|
||||||
)))
|
)))
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
Loading…
Reference in New Issue
Block a user