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