diff --git a/src/ast.rs b/src/ast.rs index 042e80e..33bedc3 100644 --- a/src/ast.rs +++ b/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, /// This is executed after each loop to advance the condition variables pub advancement: Option, /// The loop body that is executed each loop @@ -126,12 +126,19 @@ pub struct FunDecl { pub body: Rc, } +#[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), diff --git a/src/astoptimizer.rs b/src/astoptimizer.rs index 71fe509..12f1f76 100644 --- a/src/astoptimizer.rs +++ b/src/astoptimizer.rs @@ -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 => (), diff --git a/src/interpreter.rs b/src/interpreter.rs index 0726ab2..70cf0b7 100644 --- a/src/interpreter.rs +++ b/src/interpreter.rs @@ -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)?; diff --git a/src/parser.rs b/src/parser.rs index 2bbc6ef..19b3221 100644 --- a/src/parser.rs +++ b/src/parser.rs @@ -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> Parser { 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> Parser { 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> Parser { fn parse_loop(&mut self) -> ResPE { 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 {