Implement break & continue

- Fix return propagation inside loops
This commit is contained in:
Daniel M 2022-02-10 13:13:15 +01:00
parent 4e92a416ed
commit 2880ba81ab
6 changed files with 56 additions and 6 deletions

View File

@ -129,6 +129,8 @@ pub struct FunDecl {
#[derive(Debug, PartialEq, Eq, Clone)] #[derive(Debug, PartialEq, Eq, Clone)]
pub enum Statement { pub enum Statement {
Return(Expression), Return(Expression),
Break,
Continue,
Declaration(Sid, usize, Expression), Declaration(Sid, usize, Expression),
FunDeclare(FunDecl), FunDeclare(FunDecl),
Expr(Expression), Expr(Expression),

View File

@ -43,6 +43,7 @@ impl SimpleAstOptimizer {
Statement::Declaration(_, _, expr) => Self::optimize_expr(expr), Statement::Declaration(_, _, expr) => Self::optimize_expr(expr),
Statement::FunDeclare(_) => (), Statement::FunDeclare(_) => (),
Statement::Return(expr) => Self::optimize_expr(expr), Statement::Return(expr) => Self::optimize_expr(expr),
Statement::Break | Statement::Continue => (),
} }
} }
} }

View File

@ -48,6 +48,8 @@ pub enum Value {
#[derive(Debug, PartialEq, Eq, Clone)] #[derive(Debug, PartialEq, Eq, Clone)]
pub enum BlockExit { pub enum BlockExit {
Normal, Normal,
Break,
Continue,
Return(Value), Return(Value),
} }
@ -139,6 +141,9 @@ impl Interpreter {
for stmt in prog { for stmt in prog {
match stmt { match stmt {
Statement::Break => return Ok(BlockExit::Break),
Statement::Continue => return Ok(BlockExit::Continue),
Statement::Return(expr) => { Statement::Return(expr) => {
let val = self.resolve_expr(expr)?; let val = self.resolve_expr(expr)?;
@ -156,9 +161,10 @@ impl Interpreter {
} }
Statement::Block(block) => match self.run_block(block)? { 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); self.vartable.truncate(framepointer);
return Ok(BlockExit::Return(val)); return Ok(be);
} }
_ => (), _ => (),
}, },
@ -170,7 +176,16 @@ impl Interpreter {
break; 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 { if let Some(adv) = &looop.advancement {
self.resolve_expr(&adv)?; self.resolve_expr(&adv)?;
@ -198,10 +213,12 @@ impl Interpreter {
} else { } else {
self.run_block(body_true)? self.run_block(body_true)?
}; };
match exit { match exit {
BlockExit::Return(val) => { // Propagate return, continue and break
be @ (BlockExit::Return(_) | BlockExit::Continue | BlockExit::Break) => {
self.vartable.truncate(framepointer); 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), &Rc::clone(&self.funtable.get(*fun_stackpos).unwrap().body),
expected_num_args, expected_num_args,
)? { )? {
BlockExit::Normal => Value::Void, BlockExit::Normal | BlockExit::Continue | BlockExit::Break => Value::Void,
BlockExit::Return(val) => val, BlockExit::Return(val) => val,
} }
} }

View File

@ -202,6 +202,8 @@ impl<'a> Lexer<'a> {
"else" => T![else], "else" => T![else],
"fun" => T![fun], "fun" => T![fun],
"return" => T![return], "return" => T![return],
"break" => T![break],
"continue" => T![continue],
// If it doesn't match a keyword, it is a normal identifier // If it doesn't match a keyword, it is a normal identifier
_ => T![ident(ident)], _ => T![ident(ident)],

View File

@ -107,6 +107,22 @@ impl<T: Iterator<Item = Token>> Parser<T> {
/// Parse a single statement from the tokens. /// Parse a single statement from the tokens.
fn parse_stmt(&mut self) -> ResPE<Statement> { fn parse_stmt(&mut self) -> ResPE<Statement> {
let stmt = match self.peek() { 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![loop] => Statement::Loop(self.parse_loop()?),
T![print] => { T![print] => {

View File

@ -18,6 +18,10 @@ pub enum Keyword {
Fun, Fun,
/// Return keyword ("return") /// Return keyword ("return")
Return, Return,
/// Break keyword ("break")
Break,
/// Continue keyword ("continue")
Continue,
} }
/// Literal values /// Literal values
@ -217,6 +221,14 @@ macro_rules! T {
crate::token::Token::Keyword(crate::token::Keyword::Return) 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 // Literals
[i64($($val:tt)*)] => { [i64($($val:tt)*)] => {
crate::token::Token::Literal(crate::token::Literal::I64($($val)*)) crate::token::Token::Literal(crate::token::Literal::I64($($val)*))