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)]
|
#[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),
|
||||||
|
|||||||
@ -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 => (),
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@ -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,
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@ -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)],
|
||||||
|
|||||||
@ -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] => {
|
||||||
|
|||||||
12
src/token.rs
12
src/token.rs
@ -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)*))
|
||||||
|
|||||||
Loading…
x
Reference in New Issue
Block a user