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
- [ ] Line comments `//`
- [x] Strings
- [x] For loops `for X; Y; Z { ... }`
- [ ] IO Intrinsics
- [x] Print
- [ ] ReadLine

View File

@ -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

View File

@ -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)),
}
}

View File

@ -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<T: Iterator<Item = Token>> {
@ -142,6 +145,7 @@ impl<T: Iterator<Item = Token>> Parser<T> {
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<T: Iterator<Item = Token>> Parser<T> {
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");