Implement if/else, loops and breaks
This commit is contained in:
parent
5571418d44
commit
b7288ceed8
@ -28,11 +28,15 @@ impl<'src> IfElse<'src> {
|
|||||||
|
|
||||||
impl<'src> AbstractTree for IfElse<'src> {
|
impl<'src> AbstractTree for IfElse<'src> {
|
||||||
fn expected_type(&self, _context: &Context) -> Result<Type, ValidationError> {
|
fn expected_type(&self, _context: &Context) -> Result<Type, ValidationError> {
|
||||||
todo!()
|
Ok(Type::None)
|
||||||
}
|
}
|
||||||
|
|
||||||
fn validate(&self, _context: &Context) -> Result<(), ValidationError> {
|
fn validate(&self, _context: &Context) -> Result<(), ValidationError> {
|
||||||
todo!()
|
if let Type::Boolean = self.if_expression.expected_type(_context)? {
|
||||||
|
Ok(())
|
||||||
|
} else {
|
||||||
|
Err(ValidationError::ExpectedBoolean)
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
fn run(self, _context: &Context) -> Result<Action, RuntimeError> {
|
fn run(self, _context: &Context) -> Result<Action, RuntimeError> {
|
||||||
|
@ -40,11 +40,12 @@ impl<'src> AbstractTree for Loop<'src> {
|
|||||||
}
|
}
|
||||||
|
|
||||||
let statement = self.statements[index].clone();
|
let statement = self.statements[index].clone();
|
||||||
|
let action = statement.run(_context)?;
|
||||||
|
|
||||||
if let Statement::Break(expression) = statement {
|
match action {
|
||||||
break expression.run(_context);
|
Action::Return(_) => {}
|
||||||
} else {
|
Action::None => {}
|
||||||
statement.run(_context)?;
|
r#break => return Ok(r#break),
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -66,6 +67,6 @@ mod tests {
|
|||||||
}
|
}
|
||||||
.run(&Context::new());
|
.run(&Context::new());
|
||||||
|
|
||||||
assert_eq!(result, Ok(Action::Return(Value::integer(42))))
|
assert_eq!(result, Ok(Action::Break(Value::integer(42))))
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -22,7 +22,7 @@ impl<'src> AbstractTree for Statement<'src> {
|
|||||||
Statement::Block(block) => block.expected_type(_context),
|
Statement::Block(block) => block.expected_type(_context),
|
||||||
Statement::Break(expression) => expression.expected_type(_context),
|
Statement::Break(expression) => expression.expected_type(_context),
|
||||||
Statement::Expression(expression) => expression.expected_type(_context),
|
Statement::Expression(expression) => expression.expected_type(_context),
|
||||||
Statement::IfElse(_) => todo!(),
|
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),
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -30,10 +30,10 @@ impl<'src> AbstractTree for Statement<'src> {
|
|||||||
fn validate(&self, _context: &Context) -> Result<(), ValidationError> {
|
fn validate(&self, _context: &Context) -> Result<(), ValidationError> {
|
||||||
match self {
|
match self {
|
||||||
Statement::Assignment(assignment) => assignment.validate(_context),
|
Statement::Assignment(assignment) => assignment.validate(_context),
|
||||||
Statement::Block(_) => todo!(),
|
Statement::Block(block) => block.validate(_context),
|
||||||
Statement::Break(expression) => expression.validate(_context),
|
Statement::Break(expression) => expression.validate(_context),
|
||||||
Statement::Expression(expression) => expression.validate(_context),
|
Statement::Expression(expression) => expression.validate(_context),
|
||||||
Statement::IfElse(_) => todo!(),
|
Statement::IfElse(if_else) => if_else.validate(_context),
|
||||||
Statement::Loop(r#loop) => r#loop.validate(_context),
|
Statement::Loop(r#loop) => r#loop.validate(_context),
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -41,10 +41,14 @@ impl<'src> AbstractTree for Statement<'src> {
|
|||||||
fn run(self, _context: &Context) -> Result<Action, RuntimeError> {
|
fn run(self, _context: &Context) -> Result<Action, RuntimeError> {
|
||||||
match self {
|
match self {
|
||||||
Statement::Assignment(assignment) => assignment.run(_context),
|
Statement::Assignment(assignment) => assignment.run(_context),
|
||||||
Statement::Block(_) => todo!(),
|
Statement::Block(block) => block.run(_context),
|
||||||
Statement::Break(expression) => expression.run(_context),
|
Statement::Break(expression) => {
|
||||||
|
let value = expression.run(_context)?.as_return_value()?;
|
||||||
|
|
||||||
|
Ok(Action::Break(value))
|
||||||
|
}
|
||||||
Statement::Expression(expression) => expression.run(_context),
|
Statement::Expression(expression) => expression.run(_context),
|
||||||
Statement::IfElse(_) => todo!(),
|
Statement::IfElse(if_else) => if_else.run(_context),
|
||||||
Statement::Loop(r#loop) => r#loop.run(_context),
|
Statement::Loop(r#loop) => r#loop.run(_context),
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -259,10 +259,13 @@ 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(statement.clone())
|
||||||
.then_ignore(just(Token::Keyword("else")))
|
.then(
|
||||||
.then(statement.clone().or_not())
|
just(Token::Keyword("else"))
|
||||||
.map(|((if_expression, if_block), else_block)| {
|
.ignore_then(statement.clone())
|
||||||
Statement::IfElse(IfElse::new(if_expression, if_block, else_block))
|
.or_not(),
|
||||||
|
)
|
||||||
|
.map(|((if_expression, if_statement), else_statement)| {
|
||||||
|
Statement::IfElse(IfElse::new(if_expression, if_statement, else_statement))
|
||||||
})
|
})
|
||||||
.boxed();
|
.boxed();
|
||||||
|
|
||||||
@ -290,6 +293,18 @@ mod tests {
|
|||||||
|
|
||||||
use super::*;
|
use super::*;
|
||||||
|
|
||||||
|
#[test]
|
||||||
|
fn r#if() {
|
||||||
|
assert_eq!(
|
||||||
|
parse(&lex("if true 'foo'").unwrap()).unwrap()[0].0,
|
||||||
|
Statement::IfElse(IfElse::new(
|
||||||
|
Expression::Value(ValueNode::Boolean(true)),
|
||||||
|
Statement::Expression(Expression::Value(ValueNode::String("foo"))),
|
||||||
|
None
|
||||||
|
))
|
||||||
|
)
|
||||||
|
}
|
||||||
|
|
||||||
#[test]
|
#[test]
|
||||||
fn if_else() {
|
fn if_else() {
|
||||||
assert_eq!(
|
assert_eq!(
|
||||||
|
@ -18,3 +18,19 @@ fn loops_and_breaks() {
|
|||||||
Ok(Some(Value::string("foobar")))
|
Ok(Some(Value::string("foobar")))
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#[test]
|
||||||
|
fn r#if() {
|
||||||
|
assert_eq!(
|
||||||
|
interpret("if true 'foobar'"),
|
||||||
|
Ok(Some(Value::string("foobar")))
|
||||||
|
)
|
||||||
|
}
|
||||||
|
|
||||||
|
#[test]
|
||||||
|
fn if_else() {
|
||||||
|
assert_eq!(
|
||||||
|
interpret("if false 'foo' else 'bar'"),
|
||||||
|
Ok(Some(Value::string("bar")))
|
||||||
|
)
|
||||||
|
}
|
||||||
|
Loading…
Reference in New Issue
Block a user