From 1e504d7d6bd49ecb594ef9767800bac622c7161a Mon Sep 17 00:00:00 2001 From: ghostly_zsh Date: Fri, 16 Aug 2024 17:54:07 -0500 Subject: [PATCH] break and continue work? --- kabel/src/codegen.rs | 82 +++++++++++++++++++++++++++++++++++- kabel/src/name_resolution.rs | 11 +++++ kabel/src/parser.rs | 10 ++--- kabel/tmp.kab | 10 +++-- 4 files changed, 103 insertions(+), 10 deletions(-) diff --git a/kabel/src/codegen.rs b/kabel/src/codegen.rs index 92c526b32588cc2c4d6ca958784be3ac0103fcfb..e30bc3c864c62b707aa5cdb527d7860f80f01eab 100644 --- a/kabel/src/codegen.rs +++ b/kabel/src/codegen.rs @@ -28,6 +28,9 @@ impl Codegen { While(condition, block) => { self.visit_while(*condition, *block); } + For(expr1, expr2, expr3, block) => { + self.visit_for(*expr1, *expr2, *expr3, *block); + } Break => { self.visit_break(&ast); } @@ -106,6 +109,83 @@ impl Codegen { self.vm.chunk[loc + 1] = (jump & 0xFF) as u8; } } + pub fn visit_for(&mut self, expr1: Option, expr2: Option, + expr3: Option, block: AST) { + self.scopes.push((ScopeType::Other, 0)); + + self.break_stack.push(Vec::new()); + self.continue_stack.push(Vec::new()); + + if let Some(expr1) = expr1 { + self.visit(expr1); + } + let end_jmp = self.vm.chunk.len(); + let mut start_jmp_loc = None; + if let Some(expr2) = expr2 { + self.visit(expr2.clone()); + self.vm.chunk.push(OpCode::JNE.into()); + self.vm.chunk.push(0xFF); // placeholder + self.vm.chunk.push(0xFF); // placeholder + start_jmp_loc = Some(self.vm.chunk.len()-2); + if self.vm.lines.last().unwrap().0 != expr2.end_line { + self.vm.lines.push((expr2.end_line, 3)); + } else { + self.vm.lines.last_mut().unwrap().1 += 3; + } + } + if let ASTType::Block(ref stmts) = block.ast_type { + self.visit_block(&block, stmts.clone(), ScopeType::Loop); + } + let continues = self.continue_stack.pop().expect("continue stack empty on pop"); + for loc in continues { + /*let jump = loc - end_jmp + 2; + self.vm.chunk[loc] = ((jump >> 8) & 0xFF) as u8; + self.vm.chunk[loc + 1] = (jump & 0xFF) as u8;*/ + self.patch_jump(loc, 0); + } + if let Some(expr3) = expr3 { + self.visit(expr3); + self.vm.chunk.push(OpCode::POP.into()); + self.vm.chunk.push(0x01); + if self.vm.lines.last().unwrap().0 != block.end_line { + self.vm.lines.push((block.end_line, 2)); + } else { + self.vm.lines.last_mut().unwrap().1 += 2; + } + } + + // write instruction to loop + self.vm.chunk.push(OpCode::JMP_UP.into()); + let current = self.vm.chunk.len()+2; + let current_to_start = current - end_jmp; + self.vm.chunk.push(((current_to_start >> 8) & 0xFF) as u8); + self.vm.chunk.push((current_to_start & 0xFF) as u8); + if self.vm.lines.last().unwrap().0 != block.end_line { + self.vm.lines.push((block.end_line, 3)); + } else { + self.vm.lines.last_mut().unwrap().1 += 3; + } + + let breaks = self.break_stack.pop().expect("break stack empty on pop"); + for loc in breaks { + self.patch_jump(loc, 0); + } + + + if let Some(loc) = start_jmp_loc { + self.patch_jump(loc, 0); + } + + let (_scope_type, variables) = self.scopes.pop().expect("popped scope in block"); + self.vm.chunk.push(OpCode::POP.into()); + self.vm.chunk.push(variables as u8); + if self.vm.lines.last().unwrap().0 != block.end_line { + self.vm.lines.push((block.end_line, 2)); + } else { + self.vm.lines.last_mut().unwrap().1 += 2; + } + + } pub fn visit_break(&mut self, ast: &AST) { let mut scopes = self.scopes.clone(); let mut pop_count = 0; @@ -145,7 +225,7 @@ impl Codegen { self.vm.chunk.push(OpCode::POP.into()); self.vm.chunk.push(pop_count as u8); - self.vm.chunk.push(OpCode::JMP_UP.into()); + self.vm.chunk.push(OpCode::JMP.into()); self.vm.chunk.push(0xFF); self.vm.chunk.push(0xFF); if self.vm.lines.last().unwrap().0 != ast.end_line { diff --git a/kabel/src/name_resolution.rs b/kabel/src/name_resolution.rs index fdacaad4c285977917d60719d71da4444005da16..1e323d88c96851ea26d58421a1acdb6908e934b4 100644 --- a/kabel/src/name_resolution.rs +++ b/kabel/src/name_resolution.rs @@ -67,6 +67,8 @@ impl Resolver { Break => { ast_from_ast!(Break, ast, ast) } Continue => { ast_from_ast!(Continue, ast, ast) } For(expr1, expr2, expr3, block) => { + self.symbol_table.push(HashMap::new()); + self.scope += 1; let mut n_expr1 = None; let mut n_expr2 = None; let mut n_expr3 = None; @@ -80,6 +82,15 @@ impl Resolver { n_expr3 = Some(self.visit(expr)); } let block = self.visit(*block); + while let Some(scope) = self.locals.last() { + if self.scope == *scope { + self.locals.pop(); + } else { + break; + } + } + self.scope -= 1; + self.symbol_table.pop(); ast_from_ast!(For(Box::new(n_expr1), Box::new(n_expr2), Box::new(n_expr3), Box::new(block)), ast, ast) } If(condition, block, else_expr) => { diff --git a/kabel/src/parser.rs b/kabel/src/parser.rs index 1325c595fbe185caf8ec1d2ac6cbf1994aceb7f6..2d07102b9dbbe2f9263c7af067f907c7dd81cf61 100644 --- a/kabel/src/parser.rs +++ b/kabel/src/parser.rs @@ -194,8 +194,8 @@ impl Parser { let right_paren = self.read_token()?; if let TokenType::RightParen = right_paren.token_type { let block = self.block()?; - return Ok(Self::build_for(for_ident, semicolon_2, expression1, expression2, expression3, block)); - /*return Ok(ast_from_token_ast!( + //return Ok(Self::build_for(for_ident, semicolon_2, expression1, expression2, expression3, block)); + return Ok(ast_from_token_ast!( ASTType::For( Box::new(expression1), Box::new(expression2), @@ -204,7 +204,7 @@ impl Parser { ), for_ident, block - ));*/ + )); } else { return Err(unexpected_token!(self, "Expected ) but found {}", right_paren)); } @@ -215,7 +215,7 @@ impl Parser { return Err(unexpected_token!(self, "Expected ( but found {}", left_paren)); } } - fn build_for(for_ident: Token, semicolon_2: Token, expression1: Option, expression2: Option, expression3: Option, block: AST) -> AST { + /*fn build_for(for_ident: Token, semicolon_2: Token, expression1: Option, expression2: Option, expression3: Option, block: AST) -> AST { let mut outer_block = Vec::new(); if let Some(expression1) = expression1.clone() { outer_block.push(expression1); @@ -235,7 +235,7 @@ impl Parser { outer_block.push(while_ast.clone()); let outer_block = ast_from_token_ast!(ASTType::Block(outer_block), for_ident, new_block); outer_block - } + }*/ pub fn break_statement(&mut self) -> Result { let break_ident = self.read_token()?; diff --git a/kabel/tmp.kab b/kabel/tmp.kab index 9e4efe2dff62cfab7baa95cd3367438eceeca59a..d889a14c35e2d315bbc310ca1894a5cb5f8d7031 100644 --- a/kabel/tmp.kab +++ b/kabel/tmp.kab @@ -1,6 +1,8 @@ for (var i = 1; i < 101; i++) { - if (i % 3 != 0 && i % 5 != 0) { print i; } - else if (i % 3 == 0 && i % 5 != 0) { print "Fizz"; } - else if (i % 3 != 0 && i % 5 == 0) { print "Buzz"; } - else if (i % 3 == 0 && i % 5 == 0) { print "FizzBuzz"; } + //if (i % 3 != 0 && i % 5 != 0) { print i; } + //else if (i % 3 == 0 && i % 5 != 0) { print "Fizz"; } + //else if (i % 3 != 0 && i % 5 == 0) { print "Buzz"; } + //else if (i % 3 == 0 && i % 5 == 0) { print "FizzBuzz"; } + print i; + break; }