Implement while loop

This commit is contained in:
Daniel M 2022-01-28 19:34:31 +01:00
parent 788c4a8e82
commit 2a014fd210
3 changed files with 59 additions and 6 deletions

View File

@ -29,6 +29,18 @@ impl Interpreter {
let result = self.resolve_expr(rhs);
self.vartable.insert(name, result);
},
Stmt::While(condition, body) => {
loop {
// Check condition
match self.resolve_expr(condition.clone()) {
Value::I64(val) if val == 0 => break,
Value::I64(_) => (),
}
// Execute loop body
self.run(body.clone());
}
}
}
}
}
@ -59,7 +71,7 @@ impl Interpreter {
_ => panic!("Runtime error: Left hand side of assignment must be an identifier"),
}
}
let lhs = self.resolve_expr(lhs);
let rhs = self.resolve_expr(rhs);

View File

@ -13,12 +13,21 @@ pub enum Token {
/// Right parentheses (')')
RParen,
/// Left brace ({)
LBrace,
/// Right brace (})
RBrace,
/// Identifier (variable / function / ... name)
Ident(String),
/// Let identifier (let)
Let,
/// While (while)
While,
/// Assignment (single equal) (=)
Assign,
@ -158,6 +167,8 @@ impl<'a> Lexer<'a> {
'>' => tokens.push(Token::Gt),
'=' => tokens.push(Token::Assign),
';' => tokens.push(Token::Semicolon),
'{' => tokens.push(Token::LBrace),
'}' => tokens.push(Token::RBrace),
'a'..='z' | 'A'..='Z' | '_' => {
let mut ident = String::from(ch);
@ -172,6 +183,7 @@ impl<'a> Lexer<'a> {
"true" => tokens.push(Token::I64(1)),
"false" => tokens.push(Token::I64(0)),
"let" => tokens.push(Token::Let),
"while" => tokens.push(Token::While),
_ => tokens.push(Token::Ident(ident)),
}
}

View File

@ -73,6 +73,7 @@ pub struct Ast {
pub enum Stmt {
Expr(Expr),
Let(String, Expr),
While(Expr, Ast),
}
#[derive(Debug, PartialEq, Eq, Clone)]
@ -104,7 +105,8 @@ expr = expr_bor
## Statements
stmt_expr = expr
stmt_let = "let" IDENT "=" expr
stmt = stmt_expr | stmt_let (";")*
stmt_while = "while" expr "{" (stmt)* "}"
stmt = stmt_expr | stmt_let | stmt_while
*/
struct Parser<T: Iterator<Item = Token>> {
@ -128,17 +130,39 @@ impl<T: Iterator<Item = Token>> Parser<T> {
continue;
}
Token::EoF => break,
Token::RBrace => break,
Token::Let => self.parse_let_stmt(),
Token::While => self.parse_while(),
// By default try to parse an expression
_ => Stmt::Expr(self.parse_expr()),
};
prog.push(stmt);
}
Ast { prog }
}
fn parse_while(&mut self) -> Stmt {
if !matches!(self.next(), Token::While) {
panic!("Error parsing while: Expected while token");
}
let condition = self.parse_expr();
if !matches!(self.next(), Token::LBrace) {
panic!("Error parsing while: Expected '{{' token");
}
let body = self.parse();
if !matches!(self.next(), Token::RBrace) {
panic!("Error parsing while: Expected '}}' token");
}
Stmt::While(condition, body)
}
fn parse_let_stmt(&mut self) -> Stmt {
if !matches!(self.next(), Token::Let) {
panic!("Error parsing let: Expected let token");
@ -257,8 +281,11 @@ impl BinOpType {
#[cfg(test)]
mod tests {
use super::{parse, Expr, BinOpType};
use crate::{lexer::Token, parser::{Stmt, Ast}};
use super::{parse, BinOpType, Expr};
use crate::{
lexer::Token,
parser::{Ast, Stmt},
};
#[test]
fn test_parser() {
@ -285,7 +312,9 @@ mod tests {
Expr::I64(4).into(),
);
let expected = Ast { prog: vec![Stmt::Expr(expected)] };
let expected = Ast {
prog: vec![Stmt::Expr(expected)],
};
let actual = parse(tokens);
assert_eq!(expected, actual);