Clean up type parsing
This commit is contained in:
parent
2dd1628bca
commit
a3591d19af
@ -3,25 +3,21 @@ use crate::{
|
|||||||
error::{RuntimeError, ValidationError},
|
error::{RuntimeError, ValidationError},
|
||||||
};
|
};
|
||||||
|
|
||||||
use super::{AbstractTree, Action, Expression, Statement, Type};
|
use super::{AbstractTree, Action, Block, Expression, Type};
|
||||||
|
|
||||||
#[derive(Clone, Debug, Eq, PartialEq, PartialOrd, Ord)]
|
#[derive(Clone, Debug, Eq, PartialEq, PartialOrd, Ord)]
|
||||||
pub struct IfElse {
|
pub struct IfElse {
|
||||||
if_expression: Expression,
|
if_expression: Expression,
|
||||||
if_statement: Box<Statement>,
|
if_block: Block,
|
||||||
else_statement: Option<Box<Statement>>,
|
else_block: Option<Block>,
|
||||||
}
|
}
|
||||||
|
|
||||||
impl IfElse {
|
impl IfElse {
|
||||||
pub fn new(
|
pub fn new(if_expression: Expression, if_block: Block, else_block: Option<Block>) -> Self {
|
||||||
if_expression: Expression,
|
|
||||||
if_statement: Statement,
|
|
||||||
else_statement: Option<Statement>,
|
|
||||||
) -> Self {
|
|
||||||
Self {
|
Self {
|
||||||
if_expression,
|
if_expression,
|
||||||
if_statement: Box::new(if_statement),
|
if_block,
|
||||||
else_statement: else_statement.map(|statement| Box::new(statement)),
|
else_block,
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -47,8 +43,8 @@ impl AbstractTree for IfElse {
|
|||||||
.as_boolean()?;
|
.as_boolean()?;
|
||||||
|
|
||||||
if if_boolean {
|
if if_boolean {
|
||||||
self.if_statement.run(_context)
|
self.if_block.run(_context)
|
||||||
} else if let Some(else_statement) = self.else_statement {
|
} else if let Some(else_statement) = self.else_block {
|
||||||
else_statement.run(_context)
|
else_statement.run(_context)
|
||||||
} else {
|
} else {
|
||||||
Ok(Action::None)
|
Ok(Action::None)
|
||||||
@ -59,7 +55,7 @@ impl AbstractTree for IfElse {
|
|||||||
#[cfg(test)]
|
#[cfg(test)]
|
||||||
mod tests {
|
mod tests {
|
||||||
use crate::{
|
use crate::{
|
||||||
abstract_tree::{Action, ValueNode},
|
abstract_tree::{Action, Statement, ValueNode},
|
||||||
context::Context,
|
context::Context,
|
||||||
Value,
|
Value,
|
||||||
};
|
};
|
||||||
@ -71,7 +67,9 @@ mod tests {
|
|||||||
assert_eq!(
|
assert_eq!(
|
||||||
IfElse::new(
|
IfElse::new(
|
||||||
Expression::Value(ValueNode::Boolean(true)),
|
Expression::Value(ValueNode::Boolean(true)),
|
||||||
Statement::Expression(Expression::Value(ValueNode::String("foo".to_string()))),
|
Block::new(vec![Statement::Expression(Expression::Value(
|
||||||
|
ValueNode::String("foo".to_string())
|
||||||
|
)),]),
|
||||||
None
|
None
|
||||||
)
|
)
|
||||||
.run(&Context::new()),
|
.run(&Context::new()),
|
||||||
@ -84,10 +82,12 @@ mod tests {
|
|||||||
assert_eq!(
|
assert_eq!(
|
||||||
IfElse::new(
|
IfElse::new(
|
||||||
Expression::Value(ValueNode::Boolean(false)),
|
Expression::Value(ValueNode::Boolean(false)),
|
||||||
Statement::Expression(Expression::Value(ValueNode::String("foo".to_string()))),
|
Block::new(vec![Statement::Expression(Expression::Value(
|
||||||
Some(Statement::Expression(Expression::Value(ValueNode::String(
|
ValueNode::String("foo".to_string())
|
||||||
"bar".to_string()
|
)),]),
|
||||||
))))
|
Some(Block::new(vec![Statement::Expression(Expression::Value(
|
||||||
|
ValueNode::String("bar".to_string())
|
||||||
|
))]))
|
||||||
)
|
)
|
||||||
.run(&Context::new()),
|
.run(&Context::new()),
|
||||||
Ok(Action::Return(Value::string("bar".to_string())))
|
Ok(Action::Return(Value::string("bar".to_string())))
|
||||||
|
110
src/parser.rs
110
src/parser.rs
@ -56,40 +56,60 @@ pub fn parser<'src>() -> DustParser<'src> {
|
|||||||
.map(|value| Expression::Value(value))
|
.map(|value| Expression::Value(value))
|
||||||
.boxed();
|
.boxed();
|
||||||
|
|
||||||
let basic_type = choice((
|
let type_specification = recursive(|type_specification| {
|
||||||
just(Token::Keyword("any")).to(Type::Any),
|
let r#type = recursive(|r#type| {
|
||||||
just(Token::Keyword("bool")).to(Type::Boolean),
|
let function_type = type_specification
|
||||||
just(Token::Keyword("float")).to(Type::Float),
|
.clone()
|
||||||
just(Token::Keyword("int")).to(Type::Integer),
|
.separated_by(just(Token::Control(Control::Comma)))
|
||||||
just(Token::Keyword("none")).to(Type::None),
|
.collect()
|
||||||
just(Token::Keyword("range")).to(Type::Range),
|
.delimited_by(
|
||||||
just(Token::Keyword("str")).to(Type::String),
|
just(Token::Control(Control::ParenOpen)),
|
||||||
just(Token::Keyword("list")).to(Type::List),
|
just(Token::Control(Control::ParenClose)),
|
||||||
));
|
)
|
||||||
|
.then_ignore(just(Token::Control(Control::Colon)))
|
||||||
|
.then(r#type.clone())
|
||||||
|
.map(|(parameter_types, return_type)| Type::Function {
|
||||||
|
parameter_types,
|
||||||
|
return_type: Box::new(return_type),
|
||||||
|
});
|
||||||
|
|
||||||
let type_arguments = basic_type.clone().delimited_by(
|
choice((
|
||||||
just(Token::Control(Control::ParenOpen)),
|
function_type,
|
||||||
just(Token::Control(Control::ParenClose)),
|
just(Token::Keyword("any")).to(Type::Any),
|
||||||
);
|
just(Token::Keyword("bool")).to(Type::Boolean),
|
||||||
|
just(Token::Keyword("float")).to(Type::Float),
|
||||||
|
just(Token::Keyword("int")).to(Type::Integer),
|
||||||
|
just(Token::Keyword("none")).to(Type::None),
|
||||||
|
just(Token::Keyword("range")).to(Type::Range),
|
||||||
|
just(Token::Keyword("str")).to(Type::String),
|
||||||
|
just(Token::Keyword("list")).to(Type::List),
|
||||||
|
))
|
||||||
|
});
|
||||||
|
|
||||||
let type_specification = just(Token::Control(Control::Colon)).ignore_then(choice((
|
let type_arguments = r#type.clone().delimited_by(
|
||||||
basic_type
|
just(Token::Control(Control::ParenOpen)),
|
||||||
.clone()
|
just(Token::Control(Control::ParenClose)),
|
||||||
.separated_by(just(Token::Control(Control::Comma)))
|
);
|
||||||
.collect()
|
|
||||||
.delimited_by(
|
just(Token::Control(Control::Colon)).ignore_then(choice((
|
||||||
just(Token::Control(Control::SquareOpen)),
|
r#type
|
||||||
just(Token::Control(Control::SquareClose)),
|
.clone()
|
||||||
)
|
.separated_by(just(Token::Control(Control::Comma)))
|
||||||
.map(|types| Type::ListExact(types)),
|
.collect()
|
||||||
just(Token::Keyword("list"))
|
.delimited_by(
|
||||||
.then(type_arguments)
|
just(Token::Control(Control::SquareOpen)),
|
||||||
.map(|(_, item_type)| Type::ListOf(Box::new(item_type))),
|
just(Token::Control(Control::SquareClose)),
|
||||||
basic_type.clone(),
|
)
|
||||||
identifier
|
.map(|types| Type::ListExact(types)),
|
||||||
.clone()
|
just(Token::Keyword("list"))
|
||||||
.map(|identifier| Type::Custom(identifier)),
|
.then(type_arguments)
|
||||||
)));
|
.map(|(_, item_type)| Type::ListOf(Box::new(item_type))),
|
||||||
|
r#type.clone(),
|
||||||
|
identifier
|
||||||
|
.clone()
|
||||||
|
.map(|identifier| Type::Custom(identifier)),
|
||||||
|
)))
|
||||||
|
});
|
||||||
|
|
||||||
let statement = recursive(|statement| {
|
let statement = recursive(|statement| {
|
||||||
let block = statement
|
let block = statement
|
||||||
@ -318,14 +338,14 @@ pub fn parser<'src>() -> DustParser<'src> {
|
|||||||
|
|
||||||
let if_else = just(Token::Keyword("if"))
|
let if_else = just(Token::Keyword("if"))
|
||||||
.ignore_then(expression.clone())
|
.ignore_then(expression.clone())
|
||||||
.then(statement.clone())
|
.then(block.clone())
|
||||||
.then(
|
.then(
|
||||||
just(Token::Keyword("else"))
|
just(Token::Keyword("else"))
|
||||||
.ignore_then(statement.clone())
|
.ignore_then(block.clone())
|
||||||
.or_not(),
|
.or_not(),
|
||||||
)
|
)
|
||||||
.map(|((if_expression, if_statement), else_statement)| {
|
.map(|((if_expression, if_block), else_block)| {
|
||||||
Statement::IfElse(IfElse::new(if_expression, if_statement, else_statement))
|
Statement::IfElse(IfElse::new(if_expression, if_block, else_block))
|
||||||
})
|
})
|
||||||
.boxed();
|
.boxed();
|
||||||
|
|
||||||
@ -390,10 +410,12 @@ mod tests {
|
|||||||
#[test]
|
#[test]
|
||||||
fn r#if() {
|
fn r#if() {
|
||||||
assert_eq!(
|
assert_eq!(
|
||||||
parse(&lex("if true 'foo'").unwrap()).unwrap()[0].0,
|
parse(&lex("if true { 'foo' }").unwrap()).unwrap()[0].0,
|
||||||
Statement::IfElse(IfElse::new(
|
Statement::IfElse(IfElse::new(
|
||||||
Expression::Value(ValueNode::Boolean(true)),
|
Expression::Value(ValueNode::Boolean(true)),
|
||||||
Statement::Expression(Expression::Value(ValueNode::String("foo".to_string()))),
|
Block::new(vec![Statement::Expression(Expression::Value(
|
||||||
|
ValueNode::String("foo".to_string())
|
||||||
|
))]),
|
||||||
None
|
None
|
||||||
))
|
))
|
||||||
)
|
)
|
||||||
@ -402,13 +424,15 @@ mod tests {
|
|||||||
#[test]
|
#[test]
|
||||||
fn if_else() {
|
fn if_else() {
|
||||||
assert_eq!(
|
assert_eq!(
|
||||||
parse(&lex("if true 'foo' else 'bar'").unwrap()).unwrap()[0].0,
|
parse(&lex("if true {'foo' } else { 'bar' }").unwrap()).unwrap()[0].0,
|
||||||
Statement::IfElse(IfElse::new(
|
Statement::IfElse(IfElse::new(
|
||||||
Expression::Value(ValueNode::Boolean(true)),
|
Expression::Value(ValueNode::Boolean(true)),
|
||||||
Statement::Expression(Expression::Value(ValueNode::String("foo".to_string()))),
|
Block::new(vec![Statement::Expression(Expression::Value(
|
||||||
Some(Statement::Expression(Expression::Value(ValueNode::String(
|
ValueNode::String("foo".to_string())
|
||||||
"bar".to_string()
|
))]),
|
||||||
))))
|
Some(Block::new(vec![Statement::Expression(Expression::Value(
|
||||||
|
ValueNode::String("bar".to_string())
|
||||||
|
))]))
|
||||||
))
|
))
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
Loading…
Reference in New Issue
Block a user