Allow endless loops with no condition
This commit is contained in:
parent
2880ba81ab
commit
3806a61756
11
src/ast.rs
11
src/ast.rs
@ -101,7 +101,7 @@ pub enum Expression {
|
||||
#[derive(Debug, PartialEq, Eq, Clone)]
|
||||
pub struct Loop {
|
||||
/// The condition that determines if the loop should continue
|
||||
pub condition: Expression,
|
||||
pub condition: Option<Expression>,
|
||||
/// This is executed after each loop to advance the condition variables
|
||||
pub advancement: Option<Expression>,
|
||||
/// The loop body that is executed each loop
|
||||
@ -126,12 +126,19 @@ pub struct FunDecl {
|
||||
pub body: Rc<BlockScope>,
|
||||
}
|
||||
|
||||
#[derive(Debug, PartialEq, Eq, Clone)]
|
||||
pub struct VarDecl {
|
||||
pub name: Sid,
|
||||
pub var_stackpos: usize,
|
||||
pub rhs: Expression,
|
||||
}
|
||||
|
||||
#[derive(Debug, PartialEq, Eq, Clone)]
|
||||
pub enum Statement {
|
||||
Return(Expression),
|
||||
Break,
|
||||
Continue,
|
||||
Declaration(Sid, usize, Expression),
|
||||
Declaration(VarDecl),
|
||||
FunDeclare(FunDecl),
|
||||
Expr(Expression),
|
||||
Block(BlockScope),
|
||||
|
||||
@ -1,4 +1,4 @@
|
||||
use crate::ast::{Ast, BlockScope, Expression, If, Loop, Statement, BinOpType, UnOpType};
|
||||
use crate::ast::{Ast, BlockScope, Expression, If, Loop, Statement, BinOpType, UnOpType, VarDecl};
|
||||
|
||||
pub trait AstOptimizer {
|
||||
fn optimize(ast: Ast) -> Ast;
|
||||
@ -24,7 +24,9 @@ impl SimpleAstOptimizer {
|
||||
advancement,
|
||||
body,
|
||||
}) => {
|
||||
Self::optimize_expr(condition);
|
||||
if let Some(condition) = condition {
|
||||
Self::optimize_expr(condition);
|
||||
}
|
||||
if let Some(advancement) = advancement {
|
||||
Self::optimize_expr(advancement)
|
||||
}
|
||||
@ -40,7 +42,7 @@ impl SimpleAstOptimizer {
|
||||
Self::optimize_block(body_false);
|
||||
}
|
||||
Statement::Print(expr) => Self::optimize_expr(expr),
|
||||
Statement::Declaration(_, _, expr) => Self::optimize_expr(expr),
|
||||
Statement::Declaration(VarDecl { name: _, var_stackpos: _, rhs}) => Self::optimize_expr(rhs),
|
||||
Statement::FunDeclare(_) => (),
|
||||
Statement::Return(expr) => Self::optimize_expr(expr),
|
||||
Statement::Break | Statement::Continue => (),
|
||||
|
||||
@ -155,8 +155,8 @@ impl Interpreter {
|
||||
self.resolve_expr(expr)?;
|
||||
}
|
||||
|
||||
Statement::Declaration(_sid, _idx, rhs) => {
|
||||
let rhs = self.resolve_expr(rhs)?;
|
||||
Statement::Declaration(decl) => {
|
||||
let rhs = self.resolve_expr(&decl.rhs)?;
|
||||
self.vartable.push(rhs);
|
||||
}
|
||||
|
||||
@ -172,8 +172,10 @@ impl Interpreter {
|
||||
Statement::Loop(looop) => {
|
||||
// loop runs as long condition != 0
|
||||
loop {
|
||||
if matches!(self.resolve_expr(&looop.condition)?, Value::I64(0)) {
|
||||
break;
|
||||
if let Some(condition) = &looop.condition {
|
||||
if matches!(self.resolve_expr(condition)?, Value::I64(0)) {
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
let be = self.run_block(&looop.body)?;
|
||||
|
||||
@ -1,7 +1,7 @@
|
||||
use thiserror::Error;
|
||||
|
||||
use crate::{
|
||||
ast::{Ast, BlockScope, Expression, FunDecl, If, Loop, Statement},
|
||||
ast::{Ast, BlockScope, Expression, FunDecl, If, Loop, Statement, VarDecl},
|
||||
stringstore::{Sid, StringStore},
|
||||
token::Token,
|
||||
util::{PutBackIter, PutBackableExt},
|
||||
@ -139,7 +139,7 @@ impl<T: Iterator<Item = Token>> Parser<T> {
|
||||
T![return] => {
|
||||
self.next();
|
||||
let stmt = Statement::Return(self.parse_expr()?);
|
||||
|
||||
|
||||
// After a statement, there must be a semicolon
|
||||
validate_next!(self, T![;], ";");
|
||||
|
||||
@ -223,7 +223,11 @@ impl<T: Iterator<Item = Token>> Parser<T> {
|
||||
let sp = self.var_stack.len();
|
||||
self.var_stack.push(sid);
|
||||
|
||||
Statement::Declaration(sid, sp, rhs)
|
||||
Statement::Declaration(VarDecl {
|
||||
name: sid,
|
||||
var_stackpos: sp,
|
||||
rhs,
|
||||
})
|
||||
}
|
||||
(first, _) => {
|
||||
self.putback(first);
|
||||
@ -275,27 +279,22 @@ impl<T: Iterator<Item = Token>> Parser<T> {
|
||||
fn parse_loop(&mut self) -> ResPE<Loop> {
|
||||
validate_next!(self, T![loop], "loop");
|
||||
|
||||
let condition = self.parse_expr()?;
|
||||
let mut condition = None;
|
||||
let mut advancement = None;
|
||||
|
||||
let body;
|
||||
if !matches!(self.peek(), T!['{']) {
|
||||
condition = Some(self.parse_expr()?);
|
||||
|
||||
match self.next() {
|
||||
T!['{'] => {
|
||||
body = self.parse_scoped_block()?;
|
||||
}
|
||||
|
||||
T![;] => {
|
||||
if matches!(self.peek(), T![;]) {
|
||||
self.next();
|
||||
advancement = Some(self.parse_expr()?);
|
||||
|
||||
validate_next!(self, T!['{'], "{");
|
||||
|
||||
body = self.parse_scoped_block()?;
|
||||
}
|
||||
|
||||
tok => return Err(ParseErr::UnexpectedToken(tok, ";\" or \"{".to_string())),
|
||||
}
|
||||
|
||||
validate_next!(self, T!['{'], "{");
|
||||
|
||||
let body = self.parse_scoped_block()?;
|
||||
|
||||
validate_next!(self, T!['}'], "}");
|
||||
|
||||
Ok(Loop {
|
||||
|
||||
Loading…
x
Reference in New Issue
Block a user