Implement break & continue
- Fix return propagation inside loops
This commit is contained in:
parent
4e92a416ed
commit
2880ba81ab
@ -129,6 +129,8 @@ pub struct FunDecl {
|
||||
#[derive(Debug, PartialEq, Eq, Clone)]
|
||||
pub enum Statement {
|
||||
Return(Expression),
|
||||
Break,
|
||||
Continue,
|
||||
Declaration(Sid, usize, Expression),
|
||||
FunDeclare(FunDecl),
|
||||
Expr(Expression),
|
||||
|
||||
@ -43,6 +43,7 @@ impl SimpleAstOptimizer {
|
||||
Statement::Declaration(_, _, expr) => Self::optimize_expr(expr),
|
||||
Statement::FunDeclare(_) => (),
|
||||
Statement::Return(expr) => Self::optimize_expr(expr),
|
||||
Statement::Break | Statement::Continue => (),
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@ -48,6 +48,8 @@ pub enum Value {
|
||||
#[derive(Debug, PartialEq, Eq, Clone)]
|
||||
pub enum BlockExit {
|
||||
Normal,
|
||||
Break,
|
||||
Continue,
|
||||
Return(Value),
|
||||
}
|
||||
|
||||
@ -139,6 +141,9 @@ impl Interpreter {
|
||||
|
||||
for stmt in prog {
|
||||
match stmt {
|
||||
Statement::Break => return Ok(BlockExit::Break),
|
||||
Statement::Continue => return Ok(BlockExit::Continue),
|
||||
|
||||
Statement::Return(expr) => {
|
||||
let val = self.resolve_expr(expr)?;
|
||||
|
||||
@ -156,9 +161,10 @@ impl Interpreter {
|
||||
}
|
||||
|
||||
Statement::Block(block) => match self.run_block(block)? {
|
||||
BlockExit::Return(val) => {
|
||||
// Propagate return, continue and break
|
||||
be @ (BlockExit::Return(_) | BlockExit::Continue | BlockExit::Break) => {
|
||||
self.vartable.truncate(framepointer);
|
||||
return Ok(BlockExit::Return(val));
|
||||
return Ok(be);
|
||||
}
|
||||
_ => (),
|
||||
},
|
||||
@ -170,7 +176,16 @@ impl Interpreter {
|
||||
break;
|
||||
}
|
||||
|
||||
self.run_block(&looop.body)?;
|
||||
let be = self.run_block(&looop.body)?;
|
||||
match be {
|
||||
// Propagate return
|
||||
be @ BlockExit::Return(_) => {
|
||||
self.vartable.truncate(framepointer);
|
||||
return Ok(be);
|
||||
}
|
||||
BlockExit::Break => break,
|
||||
BlockExit::Continue | BlockExit::Normal => (),
|
||||
}
|
||||
|
||||
if let Some(adv) = &looop.advancement {
|
||||
self.resolve_expr(&adv)?;
|
||||
@ -198,10 +213,12 @@ impl Interpreter {
|
||||
} else {
|
||||
self.run_block(body_true)?
|
||||
};
|
||||
|
||||
match exit {
|
||||
BlockExit::Return(val) => {
|
||||
// Propagate return, continue and break
|
||||
be @ (BlockExit::Return(_) | BlockExit::Continue | BlockExit::Break) => {
|
||||
self.vartable.truncate(framepointer);
|
||||
return Ok(BlockExit::Return(val));
|
||||
return Ok(be);
|
||||
}
|
||||
_ => (),
|
||||
}
|
||||
@ -269,7 +286,7 @@ impl Interpreter {
|
||||
&Rc::clone(&self.funtable.get(*fun_stackpos).unwrap().body),
|
||||
expected_num_args,
|
||||
)? {
|
||||
BlockExit::Normal => Value::Void,
|
||||
BlockExit::Normal | BlockExit::Continue | BlockExit::Break => Value::Void,
|
||||
BlockExit::Return(val) => val,
|
||||
}
|
||||
}
|
||||
|
||||
@ -202,6 +202,8 @@ impl<'a> Lexer<'a> {
|
||||
"else" => T![else],
|
||||
"fun" => T![fun],
|
||||
"return" => T![return],
|
||||
"break" => T![break],
|
||||
"continue" => T![continue],
|
||||
|
||||
// If it doesn't match a keyword, it is a normal identifier
|
||||
_ => T![ident(ident)],
|
||||
|
||||
@ -107,6 +107,22 @@ impl<T: Iterator<Item = Token>> Parser<T> {
|
||||
/// Parse a single statement from the tokens.
|
||||
fn parse_stmt(&mut self) -> ResPE<Statement> {
|
||||
let stmt = match self.peek() {
|
||||
T![break] => {
|
||||
self.next();
|
||||
|
||||
validate_next!(self, T![;], ";");
|
||||
|
||||
Statement::Break
|
||||
}
|
||||
|
||||
T![continue] => {
|
||||
self.next();
|
||||
|
||||
validate_next!(self, T![;], ";");
|
||||
|
||||
Statement::Continue
|
||||
}
|
||||
|
||||
T![loop] => Statement::Loop(self.parse_loop()?),
|
||||
|
||||
T![print] => {
|
||||
|
||||
12
src/token.rs
12
src/token.rs
@ -18,6 +18,10 @@ pub enum Keyword {
|
||||
Fun,
|
||||
/// Return keyword ("return")
|
||||
Return,
|
||||
/// Break keyword ("break")
|
||||
Break,
|
||||
/// Continue keyword ("continue")
|
||||
Continue,
|
||||
}
|
||||
|
||||
/// Literal values
|
||||
@ -217,6 +221,14 @@ macro_rules! T {
|
||||
crate::token::Token::Keyword(crate::token::Keyword::Return)
|
||||
};
|
||||
|
||||
[break] => {
|
||||
crate::token::Token::Keyword(crate::token::Keyword::Break)
|
||||
};
|
||||
|
||||
[continue] => {
|
||||
crate::token::Token::Keyword(crate::token::Keyword::Continue)
|
||||
};
|
||||
|
||||
// Literals
|
||||
[i64($($val:tt)*)] => {
|
||||
crate::token::Token::Literal(crate::token::Literal::I64($($val)*))
|
||||
|
||||
Loading…
x
Reference in New Issue
Block a user