Implement for loop

This commit is contained in:
Daniel M 2022-01-28 23:00:49 +01:00
parent ffdce64df8
commit e62121c75b
4 changed files with 68 additions and 2 deletions

View File

@ -23,6 +23,7 @@
- [x] Else statement - [x] Else statement
- [ ] Line comments `//` - [ ] Line comments `//`
- [x] Strings - [x] Strings
- [x] For loops `for X; Y; Z { ... }`
- [ ] IO Intrinsics - [ ] IO Intrinsics
- [x] Print - [x] Print
- [ ] ReadLine - [ ] ReadLine

View File

@ -49,6 +49,28 @@ impl Interpreter {
let result = self.resolve_expr(rhs); let result = self.resolve_expr(rhs);
self.vartable.insert(name.clone(), result); 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) => { Stmt::While(condition, body) => {
loop { loop {
// Check condition // Check condition

View File

@ -37,6 +37,9 @@ pub enum Token {
/// While (while) /// While (while)
While, While,
/// For (for)
For,
/// If (if) /// If (if)
If, If,
@ -246,6 +249,7 @@ impl<'a> Lexer<'a> {
"while" => tokens.push(Token::While), "while" => tokens.push(Token::While),
"if" => tokens.push(Token::If), "if" => tokens.push(Token::If),
"else" => tokens.push(Token::Else), "else" => tokens.push(Token::Else),
"for" => tokens.push(Token::For),
_ => tokens.push(Token::Ident(ident)), _ => tokens.push(Token::Ident(ident)),
} }
} }

View File

@ -74,6 +74,7 @@ pub enum Stmt {
Expr(Expr), Expr(Expr),
Let(String, Expr), Let(String, Expr),
While(Expr, Ast), While(Expr, Ast),
For((String, Expr), Expr, Expr, Ast),
If(Expr, Ast, Ast), If(Expr, Ast, Ast),
DbgPrint(Expr), DbgPrint(Expr),
Print(Expr), Print(Expr),
@ -112,9 +113,11 @@ expr = expr_bor
stmt_expr = expr stmt_expr = expr
stmt_let = "let" IDENT "=" expr stmt_let = "let" IDENT "=" expr
stmt_while = "while" expr "{" (stmt)* "}" stmt_while = "while" expr "{" (stmt)* "}"
stmt_for = "for" stmt_let ";" expr ";" expr "{" (stmt)* "}"
stmt_if = "if" expr "{" (stmt)* "}" ( "else" "{" (stmt)* "}" ) stmt_if = "if" expr "{" (stmt)* "}" ( "else" "{" (stmt)* "}" )
stmt_dbgprint = "$" expr stmt_dbgprint = "$$" expr
stmt = stmt_expr | stmt_let | stmt_while | stmt_if | stmt_dbgprint stmt_print = "$" expr
stmt = stmt_expr | stmt_let | stmt_while | stmt_for | stmt_if | stmt_dbgprint | stmt_print
*/ */
struct Parser<T: Iterator<Item = Token>> { struct Parser<T: Iterator<Item = Token>> {
@ -142,6 +145,7 @@ impl<T: Iterator<Item = Token>> Parser<T> {
Token::Let => self.parse_let_stmt(), Token::Let => self.parse_let_stmt(),
Token::While => self.parse_while(), Token::While => self.parse_while(),
Token::If => self.parse_if(), Token::If => self.parse_if(),
Token::For => self.parse_for(),
Token::Dollar => { Token::Dollar => {
self.next(); self.next();
Stmt::Print(self.parse_expr()) Stmt::Print(self.parse_expr())
@ -160,6 +164,41 @@ impl<T: Iterator<Item = Token>> Parser<T> {
Ast { prog } 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 { fn parse_if(&mut self) -> Stmt {
if !matches!(self.next(), Token::If) { if !matches!(self.next(), Token::If) {
panic!("Error parsing if: Expected if token"); panic!("Error parsing if: Expected if token");