diff --git a/README.md b/README.md index 29e73fe..74dfe8a 100644 --- a/README.md +++ b/README.md @@ -23,6 +23,7 @@ - [x] Else statement - [ ] Line comments `//` - [x] Strings +- [x] For loops `for X; Y; Z { ... }` - [ ] IO Intrinsics - [x] Print - [ ] ReadLine diff --git a/src/interpreter.rs b/src/interpreter.rs index b74c237..9b66b54 100644 --- a/src/interpreter.rs +++ b/src/interpreter.rs @@ -49,6 +49,28 @@ impl Interpreter { let result = self.resolve_expr(rhs); self.vartable.insert(name.clone(), result); } + Stmt::For(init, condition, advance, body) => { + // Execute initital let instruction + let init_val = self.resolve_expr(&init.1); + self.vartable.insert(init.0.clone(), init_val); + + loop { + // Check condition + match self.resolve_expr(condition) { + Value::I64(val) if val == 0 => break, + Value::I64(_) => (), + + Value::Str(text) if text.is_empty() => break, + Value::Str(_) => (), + } + + // Execute loop body + self.run(body); + + // Execute advancement + self.resolve_expr(advance); + } + } Stmt::While(condition, body) => { loop { // Check condition diff --git a/src/lexer.rs b/src/lexer.rs index 10ffc5e..5566748 100644 --- a/src/lexer.rs +++ b/src/lexer.rs @@ -37,6 +37,9 @@ pub enum Token { /// While (while) While, + /// For (for) + For, + /// If (if) If, @@ -246,6 +249,7 @@ impl<'a> Lexer<'a> { "while" => tokens.push(Token::While), "if" => tokens.push(Token::If), "else" => tokens.push(Token::Else), + "for" => tokens.push(Token::For), _ => tokens.push(Token::Ident(ident)), } } diff --git a/src/parser.rs b/src/parser.rs index 04739f9..0746aed 100644 --- a/src/parser.rs +++ b/src/parser.rs @@ -74,6 +74,7 @@ pub enum Stmt { Expr(Expr), Let(String, Expr), While(Expr, Ast), + For((String, Expr), Expr, Expr, Ast), If(Expr, Ast, Ast), DbgPrint(Expr), Print(Expr), @@ -112,9 +113,11 @@ expr = expr_bor stmt_expr = expr stmt_let = "let" IDENT "=" expr stmt_while = "while" expr "{" (stmt)* "}" +stmt_for = "for" stmt_let ";" expr ";" expr "{" (stmt)* "}" stmt_if = "if" expr "{" (stmt)* "}" ( "else" "{" (stmt)* "}" ) -stmt_dbgprint = "$" expr -stmt = stmt_expr | stmt_let | stmt_while | stmt_if | stmt_dbgprint +stmt_dbgprint = "$$" expr +stmt_print = "$" expr +stmt = stmt_expr | stmt_let | stmt_while | stmt_for | stmt_if | stmt_dbgprint | stmt_print */ struct Parser> { @@ -142,6 +145,7 @@ impl> Parser { Token::Let => self.parse_let_stmt(), Token::While => self.parse_while(), Token::If => self.parse_if(), + Token::For => self.parse_for(), Token::Dollar => { self.next(); Stmt::Print(self.parse_expr()) @@ -160,6 +164,41 @@ impl> Parser { Ast { prog } } + fn parse_for(&mut self) -> Stmt { + if !matches!(self.next(), Token::For) { + panic!("Error parsing for: Expected for token"); + } + + let init = match self.parse_let_stmt() { + Stmt::Let(name, rhs) => (name, rhs), + _ => unreachable!() + }; + + if !matches!(self.next(), Token::Semicolon) { + panic!("Error parsing for: Expected semicolon token"); + } + + let condition = self.parse_expr(); + + if !matches!(self.next(), Token::Semicolon) { + panic!("Error parsing for: Expected semicolon token"); + } + + let advance = self.parse_expr(); + + if !matches!(self.next(), Token::LBrace) { + panic!("Error parsing for: Expected '{{' token"); + } + + let body = self.parse(); + + if !matches!(self.next(), Token::RBrace) { + panic!("Error parsing for: Expected '}}' token"); + } + + Stmt::For(init, condition, advance, body) + } + fn parse_if(&mut self) -> Stmt { if !matches!(self.next(), Token::If) { panic!("Error parsing if: Expected if token");