Pass all tests
This commit is contained in:
parent
bf72e779fe
commit
780ea0858b
@ -38,7 +38,7 @@ impl Assignment {
|
||||
|
||||
impl AbstractTree for Assignment {
|
||||
fn expected_type(&self, _context: &Context) -> Result<Type, ValidationError> {
|
||||
todo!()
|
||||
Ok(Type::None)
|
||||
}
|
||||
|
||||
fn validate(&self, context: &Context) -> Result<(), ValidationError> {
|
||||
|
@ -63,10 +63,12 @@ mod tests {
|
||||
#[test]
|
||||
fn basic_loop() {
|
||||
let result = Loop {
|
||||
statements: vec![Statement::Break(Expression::Value(ValueNode::Integer(42)))],
|
||||
statements: vec![Statement::Break(Some(Expression::Value(
|
||||
ValueNode::Integer(42),
|
||||
)))],
|
||||
}
|
||||
.run(&Context::new());
|
||||
|
||||
assert_eq!(result, Ok(Action::Break(Value::integer(42))))
|
||||
assert_eq!(result, Ok(Action::Break(Some(Value::integer(42)))))
|
||||
}
|
||||
}
|
||||
|
@ -42,7 +42,7 @@ pub trait AbstractTree {
|
||||
|
||||
#[derive(Debug, Clone, Eq, PartialEq, PartialOrd, Ord)]
|
||||
pub enum Action {
|
||||
Break(Value),
|
||||
Break(Option<Value>),
|
||||
Return(Value),
|
||||
None,
|
||||
}
|
||||
@ -50,7 +50,13 @@ pub enum Action {
|
||||
impl Action {
|
||||
pub fn as_value(self) -> Result<Value, ValidationError> {
|
||||
match self {
|
||||
Action::Break(value) => Ok(value),
|
||||
Action::Break(value) => {
|
||||
if let Some(value) = value {
|
||||
Ok(value)
|
||||
} else {
|
||||
Err(ValidationError::ExpectedValue)
|
||||
}
|
||||
}
|
||||
Action::Return(value) => Ok(value),
|
||||
Action::None => Err(ValidationError::ExpectedValue),
|
||||
}
|
||||
|
@ -9,7 +9,7 @@ use super::{AbstractTree, Action, Assignment, Block, Expression, IfElse, Loop, T
|
||||
pub enum Statement {
|
||||
Assignment(Assignment),
|
||||
Block(Block),
|
||||
Break(Expression),
|
||||
Break(Option<Expression>),
|
||||
Expression(Expression),
|
||||
IfElse(IfElse),
|
||||
Loop(Loop),
|
||||
@ -20,7 +20,13 @@ impl AbstractTree for Statement {
|
||||
match self {
|
||||
Statement::Assignment(assignment) => assignment.expected_type(_context),
|
||||
Statement::Block(block) => block.expected_type(_context),
|
||||
Statement::Break(expression) => expression.expected_type(_context),
|
||||
Statement::Break(expression_option) => {
|
||||
if let Some(expression) = expression_option {
|
||||
expression.expected_type(_context)
|
||||
} else {
|
||||
Ok(Type::None)
|
||||
}
|
||||
}
|
||||
Statement::Expression(expression) => expression.expected_type(_context),
|
||||
Statement::IfElse(if_else) => if_else.expected_type(_context),
|
||||
Statement::Loop(r#loop) => r#loop.expected_type(_context),
|
||||
@ -31,7 +37,13 @@ impl AbstractTree for Statement {
|
||||
match self {
|
||||
Statement::Assignment(assignment) => assignment.validate(_context),
|
||||
Statement::Block(block) => block.validate(_context),
|
||||
Statement::Break(expression) => expression.validate(_context),
|
||||
Statement::Break(expression_option) => {
|
||||
if let Some(expression) = expression_option {
|
||||
expression.validate(_context)
|
||||
} else {
|
||||
Ok(())
|
||||
}
|
||||
}
|
||||
Statement::Expression(expression) => expression.validate(_context),
|
||||
Statement::IfElse(if_else) => if_else.validate(_context),
|
||||
Statement::Loop(r#loop) => r#loop.validate(_context),
|
||||
@ -43,9 +55,13 @@ impl AbstractTree for Statement {
|
||||
Statement::Assignment(assignment) => assignment.run(_context),
|
||||
Statement::Block(block) => block.run(_context),
|
||||
Statement::Break(expression) => {
|
||||
let value = expression.run(_context)?.as_return_value()?;
|
||||
if let Some(expression) = expression {
|
||||
let value = expression.run(_context)?.as_return_value()?;
|
||||
|
||||
Ok(Action::Break(value))
|
||||
Ok(Action::Break(Some(value)))
|
||||
} else {
|
||||
Ok(Action::Break(None))
|
||||
}
|
||||
}
|
||||
Statement::Expression(expression) => expression.run(_context),
|
||||
Statement::IfElse(if_else) => if_else.run(_context),
|
||||
|
@ -53,7 +53,13 @@ impl Interpreter {
|
||||
for (statement, _span) in statements {
|
||||
value = match statement.run(&self.context) {
|
||||
Ok(action) => match action {
|
||||
Action::Break(value) => Some(value),
|
||||
Action::Break(value_option) => {
|
||||
if let Some(value) = value_option {
|
||||
Some(value)
|
||||
} else {
|
||||
None
|
||||
}
|
||||
}
|
||||
Action::Return(value) => Some(value),
|
||||
Action::None => continue,
|
||||
},
|
||||
|
@ -305,7 +305,7 @@ pub fn parser<'src>() -> DustParser<'src> {
|
||||
.boxed();
|
||||
|
||||
let r#break = just(Token::Keyword("break"))
|
||||
.ignore_then(expression.clone())
|
||||
.ignore_then(expression.clone().or_not())
|
||||
.map(|expression| Statement::Break(expression));
|
||||
|
||||
let assignment = identifier
|
||||
|
@ -5,24 +5,25 @@ fn loops_and_breaks() {
|
||||
assert_eq!(
|
||||
interpret(
|
||||
"
|
||||
i = 0;
|
||||
i = 0
|
||||
loop {
|
||||
if i == 3 {
|
||||
break 'foobar'
|
||||
break
|
||||
} else {
|
||||
i += 1
|
||||
}
|
||||
}
|
||||
i
|
||||
"
|
||||
),
|
||||
Ok(Some(Value::string("foobar".to_string())))
|
||||
Ok(Some(Value::integer(3)))
|
||||
)
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn r#if() {
|
||||
assert_eq!(
|
||||
interpret("if true 'foobar'"),
|
||||
interpret("if true { 'foobar' }"),
|
||||
Ok(Some(Value::string("foobar".to_string())))
|
||||
)
|
||||
}
|
||||
@ -30,7 +31,7 @@ fn r#if() {
|
||||
#[test]
|
||||
fn if_else() {
|
||||
assert_eq!(
|
||||
interpret("if false 'foo' else 'bar'"),
|
||||
interpret("if false { 'foo' } else { 'bar' }"),
|
||||
Ok(Some(Value::string("bar".to_string())))
|
||||
)
|
||||
}
|
||||
|
@ -37,7 +37,7 @@ fn set_variable_with_type_error() {
|
||||
#[test]
|
||||
fn function_variable() {
|
||||
assert_eq!(
|
||||
interpret("foobar = (x: int): int x; foobar"),
|
||||
interpret("foobar = (x: int): int { x }; foobar"),
|
||||
Ok(Some(Value::function(
|
||||
vec![(Identifier::new("x"), Type::Integer)],
|
||||
Type::Integer,
|
||||
|
Loading…
Reference in New Issue
Block a user