From 426c4c005ea227b6953945c8bacb92575f5e392d Mon Sep 17 00:00:00 2001 From: ghostly_zsh Date: Thu, 15 Aug 2024 15:53:16 -0500 Subject: [PATCH] basic break and continue but it doesn't quite work --- kabel/src/codegen.rs | 46 ++++++++++++++++++++++++++++++++++++ kabel/src/main.rs | 5 ++-- kabel/src/name_resolution.rs | 2 ++ 3 files changed, 50 insertions(+), 3 deletions(-) diff --git a/kabel/src/codegen.rs b/kabel/src/codegen.rs index 057ffd4cf342e96ea8d98d23893a41b05e90ec32..222dc7bb633041e6601d5d2534ae1fba75d25618 100644 --- a/kabel/src/codegen.rs +++ b/kabel/src/codegen.rs @@ -3,6 +3,8 @@ use crate::{ast::{ASTType, BinOp, Lit, Name, UnOp, AST}, codegen_binary, codegen pub struct Codegen { pub vm: VM, pub scopes: Vec, // number of variables declared in the scope + break_stack: Vec>, + continue_stack: Vec>, } impl Codegen { @@ -11,6 +13,8 @@ impl Codegen { vm: VM::new(Vec::new(), Vec::new(), Vec::new(), text), scopes: vec![0], + break_stack: Vec::new(), + continue_stack: Vec::new(), } } pub fn visit(&mut self, ast: AST) { @@ -24,6 +28,12 @@ impl Codegen { While(condition, block) => { self.visit_while(*condition, *block); } + Break => { + self.visit_break(&ast); + } + Continue => { + self.visit_continue(&ast); + } If(condition, block, else_expr) => { self.visit_if(*condition, *block, *else_expr); } @@ -56,6 +66,9 @@ impl Codegen { } } pub fn visit_while(&mut self, condition: AST, block: AST) { + self.break_stack.push(Vec::new()); + self.continue_stack.push(Vec::new()); + let end_jmp = self.vm.chunk.len(); self.visit(condition.clone()); self.vm.chunk.push(OpCode::JNE.into()); @@ -79,6 +92,39 @@ impl Codegen { self.vm.lines.last_mut().unwrap().1 += 3; } self.patch_jump(start_jmp_loc); + + let breaks = self.break_stack.pop().expect("break stack empty on pop"); + for loc in breaks { + self.patch_jump(loc); + } + 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; + } + } + pub fn visit_break(&mut self, ast: &AST) { + 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 { + self.vm.lines.push((ast.end_line, 3)); + } else { + self.vm.lines.last_mut().unwrap().1 += 3; + } + self.break_stack.last_mut().expect("break not in a loop").push(self.vm.chunk.len()-2); + } + pub fn visit_continue(&mut self, ast: &AST) { + self.vm.chunk.push(OpCode::JMP_UP.into()); + self.vm.chunk.push(0xFF); + self.vm.chunk.push(0xFF); + if self.vm.lines.last().unwrap().0 != ast.end_line { + self.vm.lines.push((ast.end_line, 3)); + } else { + self.vm.lines.last_mut().unwrap().1 += 3; + } + self.continue_stack.last_mut().expect("continue not in a loop").push(self.vm.chunk.len()-2); } pub fn visit_if(&mut self, condition: AST, block: AST, else_expr: Option) { self.visit(condition.clone()); diff --git a/kabel/src/main.rs b/kabel/src/main.rs index 7dbe4058ef88fb1545efcf072e7003485229ccd2..ca5ecc15529cee374297d9d509a8942d959cd00b 100644 --- a/kabel/src/main.rs +++ b/kabel/src/main.rs @@ -12,10 +12,9 @@ fn main() { let program = " for(var i = 0; i < 5; i++) { - var j = 0; print i; - print j; - j++; + continue; + print i; } ".to_string(); diff --git a/kabel/src/name_resolution.rs b/kabel/src/name_resolution.rs index ca90f0b537a4ef1888782e3ac575e5ded5291f93..fdacaad4c285977917d60719d71da4444005da16 100644 --- a/kabel/src/name_resolution.rs +++ b/kabel/src/name_resolution.rs @@ -64,6 +64,8 @@ impl Resolver { let block = self.visit(*block); ast_from_ast!(While(Box::new(condition), Box::new(block)), ast, ast) } + Break => { ast_from_ast!(Break, ast, ast) } + Continue => { ast_from_ast!(Continue, ast, ast) } For(expr1, expr2, expr3, block) => { let mut n_expr1 = None; let mut n_expr2 = None;