Fix function validation and parsing
This commit is contained in:
parent
e272d99bae
commit
2dd1628bca
@ -42,6 +42,8 @@ impl AbstractTree for Assignment {
|
|||||||
}
|
}
|
||||||
|
|
||||||
fn validate(&self, context: &Context) -> Result<(), ValidationError> {
|
fn validate(&self, context: &Context) -> Result<(), ValidationError> {
|
||||||
|
self.statement.validate(context)?;
|
||||||
|
|
||||||
let statement_type = self.statement.expected_type(context)?;
|
let statement_type = self.statement.expected_type(context)?;
|
||||||
|
|
||||||
if let Some(expected) = &self.r#type {
|
if let Some(expected) = &self.r#type {
|
||||||
|
@ -1,7 +1,6 @@
|
|||||||
use crate::{
|
use crate::{
|
||||||
context::Context,
|
context::Context,
|
||||||
error::{RuntimeError, ValidationError},
|
error::{RuntimeError, ValidationError},
|
||||||
Value,
|
|
||||||
};
|
};
|
||||||
|
|
||||||
use super::{AbstractTree, Action, Statement, Type};
|
use super::{AbstractTree, Action, Statement, Type};
|
||||||
@ -19,9 +18,11 @@ impl Block {
|
|||||||
|
|
||||||
impl AbstractTree for Block {
|
impl AbstractTree for Block {
|
||||||
fn expected_type(&self, _context: &Context) -> Result<Type, ValidationError> {
|
fn expected_type(&self, _context: &Context) -> Result<Type, ValidationError> {
|
||||||
let final_statement = self.statements.last().unwrap();
|
if let Some(statement) = self.statements.last() {
|
||||||
|
statement.expected_type(_context)
|
||||||
final_statement.expected_type(_context)
|
} else {
|
||||||
|
Ok(Type::None)
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
fn validate(&self, _context: &Context) -> Result<(), ValidationError> {
|
fn validate(&self, _context: &Context) -> Result<(), ValidationError> {
|
||||||
@ -33,23 +34,26 @@ impl AbstractTree for Block {
|
|||||||
}
|
}
|
||||||
|
|
||||||
fn run(self, _context: &Context) -> Result<Action, RuntimeError> {
|
fn run(self, _context: &Context) -> Result<Action, RuntimeError> {
|
||||||
let mut previous = Value::none();
|
let mut previous = Action::None;
|
||||||
|
|
||||||
for statement in self.statements {
|
for statement in self.statements {
|
||||||
let action = statement.run(_context)?;
|
let action = statement.run(_context)?;
|
||||||
previous = match action {
|
previous = match action {
|
||||||
Action::Return(value) => value,
|
Action::Return(value) => Action::Return(value),
|
||||||
r#break => return Ok(r#break),
|
r#break => return Ok(r#break),
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
Ok(Action::Return(previous))
|
Ok(previous)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
#[cfg(test)]
|
#[cfg(test)]
|
||||||
mod tests {
|
mod tests {
|
||||||
use crate::abstract_tree::{Expression, ValueNode};
|
use crate::{
|
||||||
|
abstract_tree::{Expression, ValueNode},
|
||||||
|
Value,
|
||||||
|
};
|
||||||
|
|
||||||
use super::*;
|
use super::*;
|
||||||
|
|
||||||
|
@ -6,7 +6,7 @@ use crate::{
|
|||||||
Value,
|
Value,
|
||||||
};
|
};
|
||||||
|
|
||||||
use super::{AbstractTree, Action, Expression, Identifier, Statement, Type};
|
use super::{AbstractTree, Action, Block, Expression, Identifier, Type};
|
||||||
|
|
||||||
#[derive(Clone, Debug, PartialEq)]
|
#[derive(Clone, Debug, PartialEq)]
|
||||||
pub enum ValueNode {
|
pub enum ValueNode {
|
||||||
@ -21,7 +21,7 @@ pub enum ValueNode {
|
|||||||
Function {
|
Function {
|
||||||
parameters: Vec<(Identifier, Type)>,
|
parameters: Vec<(Identifier, Type)>,
|
||||||
return_type: Type,
|
return_type: Type,
|
||||||
body: Box<Statement>,
|
body: Block,
|
||||||
},
|
},
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -72,6 +72,23 @@ impl AbstractTree for ValueNode {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if let ValueNode::Function {
|
||||||
|
parameters,
|
||||||
|
return_type,
|
||||||
|
body,
|
||||||
|
} = self
|
||||||
|
{
|
||||||
|
let function_context = Context::new();
|
||||||
|
|
||||||
|
for (identifier, r#type) in parameters {
|
||||||
|
function_context.set_type(identifier.clone(), r#type.clone())?;
|
||||||
|
}
|
||||||
|
|
||||||
|
let actual_return_type = body.expected_type(&function_context)?;
|
||||||
|
|
||||||
|
return_type.check(&actual_return_type)?;
|
||||||
|
}
|
||||||
|
|
||||||
Ok(())
|
Ok(())
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -115,7 +132,7 @@ impl AbstractTree for ValueNode {
|
|||||||
parameters,
|
parameters,
|
||||||
return_type,
|
return_type,
|
||||||
body,
|
body,
|
||||||
} => Value::function(parameters, return_type, *body),
|
} => Value::function(parameters, return_type, body),
|
||||||
};
|
};
|
||||||
|
|
||||||
Ok(Action::Return(value))
|
Ok(Action::Return(value))
|
||||||
|
@ -210,6 +210,7 @@ pub fn lexer<'src>() -> impl Parser<
|
|||||||
.map(Token::Control);
|
.map(Token::Control);
|
||||||
|
|
||||||
let keyword = choice((
|
let keyword = choice((
|
||||||
|
just("any").padded(),
|
||||||
just("bool").padded(),
|
just("bool").padded(),
|
||||||
just("break").padded(),
|
just("break").padded(),
|
||||||
just("else").padded(),
|
just("else").padded(),
|
||||||
@ -218,6 +219,7 @@ pub fn lexer<'src>() -> impl Parser<
|
|||||||
just("if").padded(),
|
just("if").padded(),
|
||||||
just("list").padded(),
|
just("list").padded(),
|
||||||
just("map").padded(),
|
just("map").padded(),
|
||||||
|
just("none").padded(),
|
||||||
just("range").padded(),
|
just("range").padded(),
|
||||||
just("str").padded(),
|
just("str").padded(),
|
||||||
just("loop").padded(),
|
just("loop").padded(),
|
||||||
|
376
src/parser.rs
376
src/parser.rs
@ -47,10 +47,21 @@ pub fn parser<'src>() -> DustParser<'src> {
|
|||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
|
let basic_value = select! {
|
||||||
|
Token::Boolean(boolean) => ValueNode::Boolean(boolean),
|
||||||
|
Token::Integer(integer) => ValueNode::Integer(integer),
|
||||||
|
Token::Float(float) => ValueNode::Float(float),
|
||||||
|
Token::String(string) => ValueNode::String(string.to_string()),
|
||||||
|
}
|
||||||
|
.map(|value| Expression::Value(value))
|
||||||
|
.boxed();
|
||||||
|
|
||||||
let basic_type = choice((
|
let basic_type = choice((
|
||||||
|
just(Token::Keyword("any")).to(Type::Any),
|
||||||
just(Token::Keyword("bool")).to(Type::Boolean),
|
just(Token::Keyword("bool")).to(Type::Boolean),
|
||||||
just(Token::Keyword("float")).to(Type::Float),
|
just(Token::Keyword("float")).to(Type::Float),
|
||||||
just(Token::Keyword("int")).to(Type::Integer),
|
just(Token::Keyword("int")).to(Type::Integer),
|
||||||
|
just(Token::Keyword("none")).to(Type::None),
|
||||||
just(Token::Keyword("range")).to(Type::Range),
|
just(Token::Keyword("range")).to(Type::Range),
|
||||||
just(Token::Keyword("str")).to(Type::String),
|
just(Token::Keyword("str")).to(Type::String),
|
||||||
just(Token::Keyword("list")).to(Type::List),
|
just(Token::Keyword("list")).to(Type::List),
|
||||||
@ -80,150 +91,194 @@ pub fn parser<'src>() -> DustParser<'src> {
|
|||||||
.map(|identifier| Type::Custom(identifier)),
|
.map(|identifier| Type::Custom(identifier)),
|
||||||
)));
|
)));
|
||||||
|
|
||||||
let expression = recursive(|expression| {
|
let statement = recursive(|statement| {
|
||||||
let basic_value = select! {
|
let block = statement
|
||||||
Token::Boolean(boolean) => ValueNode::Boolean(boolean),
|
|
||||||
Token::Integer(integer) => ValueNode::Integer(integer),
|
|
||||||
Token::Float(float) => ValueNode::Float(float),
|
|
||||||
Token::String(string) => ValueNode::String(string.to_string()),
|
|
||||||
}
|
|
||||||
.map(|value| Expression::Value(value))
|
|
||||||
.boxed();
|
|
||||||
|
|
||||||
let identifier_expression = identifier
|
|
||||||
.clone()
|
.clone()
|
||||||
.map(|identifier| Expression::Identifier(identifier))
|
.repeated()
|
||||||
.boxed();
|
|
||||||
|
|
||||||
let range = {
|
|
||||||
let raw_integer = select! {
|
|
||||||
Token::Integer(integer) => integer
|
|
||||||
};
|
|
||||||
|
|
||||||
raw_integer
|
|
||||||
.clone()
|
|
||||||
.then_ignore(just(Token::Control(Control::DoubleDot)))
|
|
||||||
.then(raw_integer)
|
|
||||||
.map(|(start, end)| Expression::Value(ValueNode::Range(start..end)))
|
|
||||||
};
|
|
||||||
|
|
||||||
let list = expression
|
|
||||||
.clone()
|
|
||||||
.separated_by(just(Token::Control(Control::Comma)))
|
|
||||||
.allow_trailing()
|
|
||||||
.collect()
|
|
||||||
.delimited_by(
|
|
||||||
just(Token::Control(Control::SquareOpen)),
|
|
||||||
just(Token::Control(Control::SquareClose)),
|
|
||||||
)
|
|
||||||
.map(|list| Expression::Value(ValueNode::List(list)))
|
|
||||||
.boxed();
|
|
||||||
|
|
||||||
let map_assignment = identifier
|
|
||||||
.clone()
|
|
||||||
.then(type_specification.clone().or_not())
|
|
||||||
.then_ignore(just(Token::Operator(Operator::Assign)))
|
|
||||||
.then(expression.clone())
|
|
||||||
.map(|((identifier, r#type), expression)| (identifier, r#type, expression));
|
|
||||||
|
|
||||||
let map = map_assignment
|
|
||||||
.separated_by(just(Token::Control(Control::Comma)).or_not())
|
|
||||||
.allow_trailing()
|
|
||||||
.collect()
|
.collect()
|
||||||
.delimited_by(
|
.delimited_by(
|
||||||
just(Token::Control(Control::CurlyOpen)),
|
just(Token::Control(Control::CurlyOpen)),
|
||||||
just(Token::Control(Control::CurlyClose)),
|
just(Token::Control(Control::CurlyClose)),
|
||||||
)
|
)
|
||||||
.map(|map_assigment_list| Expression::Value(ValueNode::Map(map_assigment_list)));
|
.map(|statements| Block::new(statements));
|
||||||
|
|
||||||
let r#enum = identifier
|
let expression = recursive(|expression| {
|
||||||
.clone()
|
let identifier_expression = identifier
|
||||||
.then_ignore(just(Token::Control(Control::DoubleColon)))
|
.clone()
|
||||||
.then(identifier.clone())
|
.map(|identifier| Expression::Identifier(identifier))
|
||||||
.map(|(name, variant)| Expression::Value(ValueNode::Enum(name, variant)))
|
.boxed();
|
||||||
.boxed();
|
|
||||||
|
|
||||||
let atom = choice((
|
let range = {
|
||||||
identifier_expression.clone(),
|
let raw_integer = select! {
|
||||||
basic_value.clone(),
|
Token::Integer(integer) => integer
|
||||||
list.clone(),
|
};
|
||||||
r#enum.clone(),
|
|
||||||
expression.clone().delimited_by(
|
|
||||||
just(Token::Control(Control::ParenOpen)),
|
|
||||||
just(Token::Control(Control::ParenClose)),
|
|
||||||
),
|
|
||||||
));
|
|
||||||
|
|
||||||
use Operator::*;
|
raw_integer
|
||||||
|
.clone()
|
||||||
|
.then_ignore(just(Token::Control(Control::DoubleDot)))
|
||||||
|
.then(raw_integer)
|
||||||
|
.map(|(start, end)| Expression::Value(ValueNode::Range(start..end)))
|
||||||
|
};
|
||||||
|
|
||||||
let logic_math_and_index = atom
|
let list = expression
|
||||||
.pratt((
|
.clone()
|
||||||
prefix(2, just(Token::Operator(Not)), |expression| {
|
.separated_by(just(Token::Control(Control::Comma)))
|
||||||
Expression::Logic(Box::new(Logic::Not(expression)))
|
.allow_trailing()
|
||||||
}),
|
.collect()
|
||||||
infix(left(1), just(Token::Operator(Equal)), |left, right| {
|
.delimited_by(
|
||||||
Expression::Logic(Box::new(Logic::Equal(left, right)))
|
just(Token::Control(Control::SquareOpen)),
|
||||||
}),
|
just(Token::Control(Control::SquareClose)),
|
||||||
infix(left(1), just(Token::Operator(NotEqual)), |left, right| {
|
)
|
||||||
Expression::Logic(Box::new(Logic::NotEqual(left, right)))
|
.map(|list| Expression::Value(ValueNode::List(list)))
|
||||||
}),
|
.boxed();
|
||||||
infix(left(1), just(Token::Operator(Greater)), |left, right| {
|
|
||||||
Expression::Logic(Box::new(Logic::Greater(left, right)))
|
let map_assignment = identifier
|
||||||
}),
|
.clone()
|
||||||
infix(left(1), just(Token::Operator(Less)), |left, right| {
|
.then(type_specification.clone().or_not())
|
||||||
Expression::Logic(Box::new(Logic::Less(left, right)))
|
.then_ignore(just(Token::Operator(Operator::Assign)))
|
||||||
}),
|
.then(expression.clone())
|
||||||
infix(
|
.map(|((identifier, r#type), expression)| (identifier, r#type, expression));
|
||||||
left(1),
|
|
||||||
just(Token::Operator(GreaterOrEqual)),
|
let map = map_assignment
|
||||||
|left, right| Expression::Logic(Box::new(Logic::GreaterOrEqual(left, right))),
|
.separated_by(just(Token::Control(Control::Comma)).or_not())
|
||||||
),
|
.allow_trailing()
|
||||||
infix(
|
.collect()
|
||||||
left(1),
|
.delimited_by(
|
||||||
just(Token::Operator(LessOrEqual)),
|
just(Token::Control(Control::CurlyOpen)),
|
||||||
|left, right| Expression::Logic(Box::new(Logic::LessOrEqual(left, right))),
|
just(Token::Control(Control::CurlyClose)),
|
||||||
),
|
)
|
||||||
infix(left(1), just(Token::Operator(And)), |left, right| {
|
.map(|map_assigment_list| Expression::Value(ValueNode::Map(map_assigment_list)));
|
||||||
Expression::Logic(Box::new(Logic::And(left, right)))
|
|
||||||
}),
|
let r#enum = identifier
|
||||||
infix(left(1), just(Token::Operator(Or)), |left, right| {
|
.clone()
|
||||||
Expression::Logic(Box::new(Logic::Or(left, right)))
|
.then_ignore(just(Token::Control(Control::DoubleColon)))
|
||||||
}),
|
.then(identifier.clone())
|
||||||
infix(left(1), just(Token::Operator(Add)), |left, right| {
|
.map(|(name, variant)| Expression::Value(ValueNode::Enum(name, variant)))
|
||||||
Expression::Math(Box::new(Math::Add(left, right)))
|
.boxed();
|
||||||
}),
|
|
||||||
infix(left(1), just(Token::Operator(Subtract)), |left, right| {
|
let function = identifier
|
||||||
Expression::Math(Box::new(Math::Subtract(left, right)))
|
.clone()
|
||||||
}),
|
.then(type_specification.clone())
|
||||||
infix(left(2), just(Token::Operator(Multiply)), |left, right| {
|
.separated_by(just(Token::Control(Control::Comma)))
|
||||||
Expression::Math(Box::new(Math::Multiply(left, right)))
|
.collect::<Vec<(Identifier, Type)>>()
|
||||||
}),
|
.delimited_by(
|
||||||
infix(left(2), just(Token::Operator(Divide)), |left, right| {
|
just(Token::Control(Control::ParenOpen)),
|
||||||
Expression::Math(Box::new(Math::Divide(left, right)))
|
just(Token::Control(Control::ParenClose)),
|
||||||
}),
|
)
|
||||||
infix(left(1), just(Token::Operator(Modulo)), |left, right| {
|
.then(type_specification.clone())
|
||||||
Expression::Math(Box::new(Math::Modulo(left, right)))
|
.then(block.clone())
|
||||||
}),
|
.map(|((parameters, return_type), body)| {
|
||||||
infix(
|
Expression::Value(ValueNode::Function {
|
||||||
left(3),
|
parameters,
|
||||||
just(Token::Control(Control::Dot)),
|
return_type,
|
||||||
|left, right| Expression::Index(Box::new(Index::new(left, right))),
|
body,
|
||||||
|
})
|
||||||
|
})
|
||||||
|
.boxed();
|
||||||
|
|
||||||
|
let function_expression = choice((identifier_expression.clone(), function.clone()));
|
||||||
|
|
||||||
|
let function_call = function_expression
|
||||||
|
.then(
|
||||||
|
expression
|
||||||
|
.clone()
|
||||||
|
.separated_by(just(Token::Control(Control::Comma)))
|
||||||
|
.collect()
|
||||||
|
.delimited_by(
|
||||||
|
just(Token::Control(Control::ParenOpen)),
|
||||||
|
just(Token::Control(Control::ParenClose)),
|
||||||
|
),
|
||||||
|
)
|
||||||
|
.map(|(function, arguments)| {
|
||||||
|
Expression::FunctionCall(FunctionCall::new(function, arguments))
|
||||||
|
})
|
||||||
|
.boxed();
|
||||||
|
|
||||||
|
let atom = choice((
|
||||||
|
function_call,
|
||||||
|
identifier_expression.clone(),
|
||||||
|
basic_value.clone(),
|
||||||
|
list.clone(),
|
||||||
|
r#enum.clone(),
|
||||||
|
expression.clone().delimited_by(
|
||||||
|
just(Token::Control(Control::ParenOpen)),
|
||||||
|
just(Token::Control(Control::ParenClose)),
|
||||||
),
|
),
|
||||||
|
));
|
||||||
|
|
||||||
|
use Operator::*;
|
||||||
|
|
||||||
|
let logic_math_and_index = atom
|
||||||
|
.pratt((
|
||||||
|
prefix(2, just(Token::Operator(Not)), |expression| {
|
||||||
|
Expression::Logic(Box::new(Logic::Not(expression)))
|
||||||
|
}),
|
||||||
|
infix(left(1), just(Token::Operator(Equal)), |left, right| {
|
||||||
|
Expression::Logic(Box::new(Logic::Equal(left, right)))
|
||||||
|
}),
|
||||||
|
infix(left(1), just(Token::Operator(NotEqual)), |left, right| {
|
||||||
|
Expression::Logic(Box::new(Logic::NotEqual(left, right)))
|
||||||
|
}),
|
||||||
|
infix(left(1), just(Token::Operator(Greater)), |left, right| {
|
||||||
|
Expression::Logic(Box::new(Logic::Greater(left, right)))
|
||||||
|
}),
|
||||||
|
infix(left(1), just(Token::Operator(Less)), |left, right| {
|
||||||
|
Expression::Logic(Box::new(Logic::Less(left, right)))
|
||||||
|
}),
|
||||||
|
infix(
|
||||||
|
left(1),
|
||||||
|
just(Token::Operator(GreaterOrEqual)),
|
||||||
|
|left, right| {
|
||||||
|
Expression::Logic(Box::new(Logic::GreaterOrEqual(left, right)))
|
||||||
|
},
|
||||||
|
),
|
||||||
|
infix(
|
||||||
|
left(1),
|
||||||
|
just(Token::Operator(LessOrEqual)),
|
||||||
|
|left, right| Expression::Logic(Box::new(Logic::LessOrEqual(left, right))),
|
||||||
|
),
|
||||||
|
infix(left(1), just(Token::Operator(And)), |left, right| {
|
||||||
|
Expression::Logic(Box::new(Logic::And(left, right)))
|
||||||
|
}),
|
||||||
|
infix(left(1), just(Token::Operator(Or)), |left, right| {
|
||||||
|
Expression::Logic(Box::new(Logic::Or(left, right)))
|
||||||
|
}),
|
||||||
|
infix(left(1), just(Token::Operator(Add)), |left, right| {
|
||||||
|
Expression::Math(Box::new(Math::Add(left, right)))
|
||||||
|
}),
|
||||||
|
infix(left(1), just(Token::Operator(Subtract)), |left, right| {
|
||||||
|
Expression::Math(Box::new(Math::Subtract(left, right)))
|
||||||
|
}),
|
||||||
|
infix(left(2), just(Token::Operator(Multiply)), |left, right| {
|
||||||
|
Expression::Math(Box::new(Math::Multiply(left, right)))
|
||||||
|
}),
|
||||||
|
infix(left(2), just(Token::Operator(Divide)), |left, right| {
|
||||||
|
Expression::Math(Box::new(Math::Divide(left, right)))
|
||||||
|
}),
|
||||||
|
infix(left(1), just(Token::Operator(Modulo)), |left, right| {
|
||||||
|
Expression::Math(Box::new(Math::Modulo(left, right)))
|
||||||
|
}),
|
||||||
|
infix(
|
||||||
|
left(3),
|
||||||
|
just(Token::Control(Control::Dot)),
|
||||||
|
|left, right| Expression::Index(Box::new(Index::new(left, right))),
|
||||||
|
),
|
||||||
|
))
|
||||||
|
.boxed();
|
||||||
|
|
||||||
|
choice((
|
||||||
|
function,
|
||||||
|
range,
|
||||||
|
r#enum,
|
||||||
|
logic_math_and_index,
|
||||||
|
identifier_expression,
|
||||||
|
list,
|
||||||
|
map,
|
||||||
|
basic_value,
|
||||||
))
|
))
|
||||||
.boxed();
|
.boxed()
|
||||||
|
});
|
||||||
|
|
||||||
choice((
|
|
||||||
range,
|
|
||||||
r#enum,
|
|
||||||
logic_math_and_index,
|
|
||||||
identifier_expression,
|
|
||||||
list,
|
|
||||||
map,
|
|
||||||
basic_value,
|
|
||||||
))
|
|
||||||
});
|
|
||||||
|
|
||||||
let statement = recursive(|statement| {
|
|
||||||
let expression_statement = expression
|
let expression_statement = expression
|
||||||
.clone()
|
.clone()
|
||||||
.map(|expression| Statement::Expression(expression))
|
.map(|expression| Statement::Expression(expression))
|
||||||
@ -247,16 +302,7 @@ pub fn parser<'src>() -> DustParser<'src> {
|
|||||||
})
|
})
|
||||||
.boxed();
|
.boxed();
|
||||||
|
|
||||||
let block = statement
|
let block_statement = block.clone().map(|block| Statement::Block(block));
|
||||||
.clone()
|
|
||||||
.repeated()
|
|
||||||
.collect()
|
|
||||||
.delimited_by(
|
|
||||||
just(Token::Control(Control::CurlyOpen)),
|
|
||||||
just(Token::Control(Control::CurlyClose)),
|
|
||||||
)
|
|
||||||
.map(|statements| Statement::Block(Block::new(statements)))
|
|
||||||
.boxed();
|
|
||||||
|
|
||||||
let r#loop = statement
|
let r#loop = statement
|
||||||
.clone()
|
.clone()
|
||||||
@ -283,54 +329,16 @@ pub fn parser<'src>() -> DustParser<'src> {
|
|||||||
})
|
})
|
||||||
.boxed();
|
.boxed();
|
||||||
|
|
||||||
let function = identifier
|
|
||||||
.clone()
|
|
||||||
.then(type_specification.clone())
|
|
||||||
.separated_by(just(Token::Control(Control::Comma)))
|
|
||||||
.collect::<Vec<(Identifier, Type)>>()
|
|
||||||
.delimited_by(
|
|
||||||
just(Token::Control(Control::ParenOpen)),
|
|
||||||
just(Token::Control(Control::ParenClose)),
|
|
||||||
)
|
|
||||||
.then(type_specification)
|
|
||||||
.then(statement.clone())
|
|
||||||
.map(|((parameters, return_type), body)| {
|
|
||||||
Statement::Expression(Expression::Value(ValueNode::Function {
|
|
||||||
parameters,
|
|
||||||
return_type,
|
|
||||||
body: Box::new(body),
|
|
||||||
}))
|
|
||||||
});
|
|
||||||
|
|
||||||
let function_call = expression
|
|
||||||
.clone()
|
|
||||||
.then(
|
|
||||||
expression
|
|
||||||
.clone()
|
|
||||||
.separated_by(just(Token::Control(Control::Comma)))
|
|
||||||
.collect()
|
|
||||||
.delimited_by(
|
|
||||||
just(Token::Control(Control::ParenOpen)),
|
|
||||||
just(Token::Control(Control::ParenClose)),
|
|
||||||
),
|
|
||||||
)
|
|
||||||
.map(|(function, arguments)| {
|
|
||||||
Statement::Expression(Expression::FunctionCall(FunctionCall::new(
|
|
||||||
function, arguments,
|
|
||||||
)))
|
|
||||||
});
|
|
||||||
|
|
||||||
choice((
|
choice((
|
||||||
function_call,
|
|
||||||
assignment,
|
assignment,
|
||||||
expression_statement,
|
expression_statement,
|
||||||
r#break,
|
r#break,
|
||||||
block,
|
block_statement,
|
||||||
r#loop,
|
r#loop,
|
||||||
if_else,
|
if_else,
|
||||||
function,
|
|
||||||
))
|
))
|
||||||
.then_ignore(just(Token::Control(Control::Semicolon)).or_not())
|
.then_ignore(just(Token::Control(Control::Semicolon)).or_not())
|
||||||
|
.boxed()
|
||||||
});
|
});
|
||||||
|
|
||||||
statement
|
statement
|
||||||
@ -368,13 +376,13 @@ mod tests {
|
|||||||
#[test]
|
#[test]
|
||||||
fn function() {
|
fn function() {
|
||||||
assert_eq!(
|
assert_eq!(
|
||||||
parse(&lex("(x: int): int x ").unwrap()).unwrap()[0].0,
|
parse(&lex("(x: int): int { x }").unwrap()).unwrap()[0].0,
|
||||||
Statement::Expression(Expression::Value(ValueNode::Function {
|
Statement::Expression(Expression::Value(ValueNode::Function {
|
||||||
parameters: vec![(Identifier::new("x"), Type::Integer)],
|
parameters: vec![(Identifier::new("x"), Type::Integer)],
|
||||||
return_type: Type::Integer,
|
return_type: Type::Integer,
|
||||||
body: Box::new(Statement::Expression(Expression::Identifier(
|
body: Block::new(vec![Statement::Expression(Expression::Identifier(
|
||||||
Identifier::new("x")
|
Identifier::new("x")
|
||||||
)))
|
))])
|
||||||
}))
|
}))
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
10
src/value.rs
10
src/value.rs
@ -13,7 +13,7 @@ use stanza::{
|
|||||||
};
|
};
|
||||||
|
|
||||||
use crate::{
|
use crate::{
|
||||||
abstract_tree::{AbstractTree, Action, Identifier, Statement, Type},
|
abstract_tree::{AbstractTree, Action, Block, Identifier, Type},
|
||||||
context::Context,
|
context::Context,
|
||||||
error::{RuntimeError, ValidationError},
|
error::{RuntimeError, ValidationError},
|
||||||
};
|
};
|
||||||
@ -73,11 +73,7 @@ impl Value {
|
|||||||
Value(Arc::new(ValueInner::Enum(name, variant)))
|
Value(Arc::new(ValueInner::Enum(name, variant)))
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn function(
|
pub fn function(parameters: Vec<(Identifier, Type)>, return_type: Type, body: Block) -> Self {
|
||||||
parameters: Vec<(Identifier, Type)>,
|
|
||||||
return_type: Type,
|
|
||||||
body: Statement,
|
|
||||||
) -> Self {
|
|
||||||
Value(Arc::new(ValueInner::Function(Function::Parsed(
|
Value(Arc::new(ValueInner::Function(Function::Parsed(
|
||||||
ParsedFunction {
|
ParsedFunction {
|
||||||
parameters,
|
parameters,
|
||||||
@ -369,7 +365,7 @@ impl Function {
|
|||||||
pub struct ParsedFunction {
|
pub struct ParsedFunction {
|
||||||
parameters: Vec<(Identifier, Type)>,
|
parameters: Vec<(Identifier, Type)>,
|
||||||
return_type: Type,
|
return_type: Type,
|
||||||
body: Statement,
|
body: Block,
|
||||||
}
|
}
|
||||||
|
|
||||||
#[derive(Clone, Debug, Eq, PartialEq, PartialOrd, Ord)]
|
#[derive(Clone, Debug, Eq, PartialEq, PartialOrd, Ord)]
|
||||||
|
@ -38,7 +38,7 @@ fn callback() {
|
|||||||
foobar = (cb : () -> str) : str {
|
foobar = (cb : () -> str) : str {
|
||||||
cb()
|
cb()
|
||||||
}
|
}
|
||||||
foobar(() : str { 'Hiya' })
|
foobar(() : str 'Hiya')
|
||||||
",
|
",
|
||||||
),
|
),
|
||||||
Ok(Some(Value::string("Hiya".to_string())))
|
Ok(Some(Value::string("Hiya".to_string())))
|
||||||
@ -57,12 +57,12 @@ fn function_context_does_not_capture_values() {
|
|||||||
"
|
"
|
||||||
x = 1
|
x = 1
|
||||||
|
|
||||||
foo = () : any { x }
|
foo = () : any { x }
|
||||||
"
|
"
|
||||||
),
|
),
|
||||||
Err(vec![Error::Validation {
|
Err(vec![Error::Validation {
|
||||||
error: ValidationError::VariableNotFound(Identifier::new("x")),
|
error: ValidationError::VariableNotFound(Identifier::new("x")),
|
||||||
span: (0..0).into()
|
span: (32..66).into()
|
||||||
}])
|
}])
|
||||||
);
|
);
|
||||||
|
|
||||||
|
@ -1,5 +1,5 @@
|
|||||||
use dust_lang::{
|
use dust_lang::{
|
||||||
abstract_tree::{Expression, Identifier, Statement, Type},
|
abstract_tree::{Block, Expression, Identifier, Statement, Type},
|
||||||
error::{Error, TypeCheckError, ValidationError},
|
error::{Error, TypeCheckError, ValidationError},
|
||||||
*,
|
*,
|
||||||
};
|
};
|
||||||
@ -41,7 +41,9 @@ fn function_variable() {
|
|||||||
Ok(Some(Value::function(
|
Ok(Some(Value::function(
|
||||||
vec![(Identifier::new("x"), Type::Integer)],
|
vec![(Identifier::new("x"), Type::Integer)],
|
||||||
Type::Integer,
|
Type::Integer,
|
||||||
Statement::Expression(Expression::Identifier(Identifier::new("x")))
|
Block::new(vec![Statement::Expression(Expression::Identifier(
|
||||||
|
Identifier::new("x")
|
||||||
|
))])
|
||||||
)))
|
)))
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
Loading…
Reference in New Issue
Block a user