Implement while loop
This commit is contained in:
parent
788c4a8e82
commit
2a014fd210
@ -29,6 +29,18 @@ impl Interpreter {
|
|||||||
let result = self.resolve_expr(rhs);
|
let result = self.resolve_expr(rhs);
|
||||||
self.vartable.insert(name, result);
|
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());
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
12
src/lexer.rs
12
src/lexer.rs
@ -13,12 +13,21 @@ pub enum Token {
|
|||||||
/// Right parentheses (')')
|
/// Right parentheses (')')
|
||||||
RParen,
|
RParen,
|
||||||
|
|
||||||
|
/// Left brace ({)
|
||||||
|
LBrace,
|
||||||
|
|
||||||
|
/// Right brace (})
|
||||||
|
RBrace,
|
||||||
|
|
||||||
/// Identifier (variable / function / ... name)
|
/// Identifier (variable / function / ... name)
|
||||||
Ident(String),
|
Ident(String),
|
||||||
|
|
||||||
/// Let identifier (let)
|
/// Let identifier (let)
|
||||||
Let,
|
Let,
|
||||||
|
|
||||||
|
/// While (while)
|
||||||
|
While,
|
||||||
|
|
||||||
/// Assignment (single equal) (=)
|
/// Assignment (single equal) (=)
|
||||||
Assign,
|
Assign,
|
||||||
|
|
||||||
@ -158,6 +167,8 @@ impl<'a> Lexer<'a> {
|
|||||||
'>' => tokens.push(Token::Gt),
|
'>' => tokens.push(Token::Gt),
|
||||||
'=' => tokens.push(Token::Assign),
|
'=' => tokens.push(Token::Assign),
|
||||||
';' => tokens.push(Token::Semicolon),
|
';' => tokens.push(Token::Semicolon),
|
||||||
|
'{' => tokens.push(Token::LBrace),
|
||||||
|
'}' => tokens.push(Token::RBrace),
|
||||||
|
|
||||||
'a'..='z' | 'A'..='Z' | '_' => {
|
'a'..='z' | 'A'..='Z' | '_' => {
|
||||||
let mut ident = String::from(ch);
|
let mut ident = String::from(ch);
|
||||||
@ -172,6 +183,7 @@ impl<'a> Lexer<'a> {
|
|||||||
"true" => tokens.push(Token::I64(1)),
|
"true" => tokens.push(Token::I64(1)),
|
||||||
"false" => tokens.push(Token::I64(0)),
|
"false" => tokens.push(Token::I64(0)),
|
||||||
"let" => tokens.push(Token::Let),
|
"let" => tokens.push(Token::Let),
|
||||||
|
"while" => tokens.push(Token::While),
|
||||||
_ => tokens.push(Token::Ident(ident)),
|
_ => tokens.push(Token::Ident(ident)),
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@ -73,6 +73,7 @@ pub struct Ast {
|
|||||||
pub enum Stmt {
|
pub enum Stmt {
|
||||||
Expr(Expr),
|
Expr(Expr),
|
||||||
Let(String, Expr),
|
Let(String, Expr),
|
||||||
|
While(Expr, Ast),
|
||||||
}
|
}
|
||||||
|
|
||||||
#[derive(Debug, PartialEq, Eq, Clone)]
|
#[derive(Debug, PartialEq, Eq, Clone)]
|
||||||
@ -104,7 +105,8 @@ expr = expr_bor
|
|||||||
## Statements
|
## Statements
|
||||||
stmt_expr = expr
|
stmt_expr = expr
|
||||||
stmt_let = "let" IDENT "=" 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>> {
|
struct Parser<T: Iterator<Item = Token>> {
|
||||||
@ -128,7 +130,9 @@ impl<T: Iterator<Item = Token>> Parser<T> {
|
|||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
Token::EoF => break,
|
Token::EoF => break,
|
||||||
|
Token::RBrace => break,
|
||||||
Token::Let => self.parse_let_stmt(),
|
Token::Let => self.parse_let_stmt(),
|
||||||
|
Token::While => self.parse_while(),
|
||||||
// By default try to parse an expression
|
// By default try to parse an expression
|
||||||
_ => Stmt::Expr(self.parse_expr()),
|
_ => Stmt::Expr(self.parse_expr()),
|
||||||
};
|
};
|
||||||
@ -139,6 +143,26 @@ impl<T: Iterator<Item = Token>> Parser<T> {
|
|||||||
Ast { prog }
|
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 {
|
fn parse_let_stmt(&mut self) -> Stmt {
|
||||||
if !matches!(self.next(), Token::Let) {
|
if !matches!(self.next(), Token::Let) {
|
||||||
panic!("Error parsing let: Expected let token");
|
panic!("Error parsing let: Expected let token");
|
||||||
@ -257,8 +281,11 @@ impl BinOpType {
|
|||||||
|
|
||||||
#[cfg(test)]
|
#[cfg(test)]
|
||||||
mod tests {
|
mod tests {
|
||||||
use super::{parse, Expr, BinOpType};
|
use super::{parse, BinOpType, Expr};
|
||||||
use crate::{lexer::Token, parser::{Stmt, Ast}};
|
use crate::{
|
||||||
|
lexer::Token,
|
||||||
|
parser::{Ast, Stmt},
|
||||||
|
};
|
||||||
|
|
||||||
#[test]
|
#[test]
|
||||||
fn test_parser() {
|
fn test_parser() {
|
||||||
@ -285,7 +312,9 @@ mod tests {
|
|||||||
Expr::I64(4).into(),
|
Expr::I64(4).into(),
|
||||||
);
|
);
|
||||||
|
|
||||||
let expected = Ast { prog: vec![Stmt::Expr(expected)] };
|
let expected = Ast {
|
||||||
|
prog: vec![Stmt::Expr(expected)],
|
||||||
|
};
|
||||||
|
|
||||||
let actual = parse(tokens);
|
let actual = parse(tokens);
|
||||||
assert_eq!(expected, actual);
|
assert_eq!(expected, actual);
|
||||||
|
|||||||
Loading…
x
Reference in New Issue
Block a user