Implement while loop
This commit is contained in:
parent
788c4a8e82
commit
2a014fd210
@ -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);
|
||||
|
||||
12
src/lexer.rs
12
src/lexer.rs
@ -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)),
|
||||
}
|
||||
}
|
||||
|
||||
@ -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);
|
||||
|
||||
Loading…
x
Reference in New Issue
Block a user