From 73a203ce8ed8742d653a87a08f51e6739984d5e9 Mon Sep 17 00:00:00 2001 From: ghostly_zsh Date: Fri, 16 Aug 2024 12:57:13 -0500 Subject: [PATCH] break works, continue works-ish --- kabel/src/codegen.rs | 74 ++++++++++++++++++++++++++++++++++---------- kabel/src/main.rs | 4 +-- 2 files changed, 58 insertions(+), 20 deletions(-) diff --git a/kabel/src/codegen.rs b/kabel/src/codegen.rs index 72858baba94124d2ee0b8490370c15f78509b3b1..2ba82cac526fa9208cf27f1fbfdb92a4f99bd70e 100644 --- a/kabel/src/codegen.rs +++ b/kabel/src/codegen.rs @@ -2,7 +2,7 @@ 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 + pub scopes: Vec<(ScopeType, usize)>, // number of variables declared in the scope break_stack: Vec>, continue_stack: Vec>, } @@ -12,7 +12,7 @@ impl Codegen { Codegen { vm: VM::new(Vec::new(), Vec::new(), Vec::new(), text), - scopes: vec![0], + scopes: vec![(ScopeType::Main, 0)], break_stack: Vec::new(), continue_stack: Vec::new(), } @@ -38,7 +38,7 @@ impl Codegen { self.visit_if(*condition, *block, *else_expr); } Block(ref stmts) => { - self.visit_block(&ast, stmts.clone()); + self.visit_block(&ast, stmts.clone(), ScopeType::Other); } Decl(ref name, ref expr) => { self.visit_decl(&ast, name.clone(), *expr.clone()); @@ -80,7 +80,9 @@ impl Codegen { } else { self.vm.lines.last_mut().unwrap().1 += 3; } - self.visit(block.clone()); + if let ASTType::Block(ref stmts) = block.ast_type { + self.visit_block(&block, stmts.clone(), ScopeType::Loop); + } self.vm.chunk.push(OpCode::JMP_UP.into()); let current = self.vm.chunk.len()+2; let current_to_start = current - end_jmp; @@ -107,24 +109,51 @@ impl Codegen { } } pub fn visit_break(&mut self, ast: &AST) { + let mut scopes = self.scopes.clone(); + let mut pop_count = 0; + loop { + let (scope_type, scope) = scopes.pop().expect("scopes empty in break"); + pop_count += scope; + if scope_type == ScopeType::Loop { + break; + } + } + self.vm.chunk.push(OpCode::POP.into()); + self.vm.chunk.push(pop_count as u8); + 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)); + self.vm.lines.push((ast.end_line, 5)); } else { - self.vm.lines.last_mut().unwrap().1 += 3; + self.vm.lines.last_mut().unwrap().1 += 5; } self.break_stack.last_mut().expect("break not in a loop").push(self.vm.chunk.len()-2); } + // ====================================================================== + // CONTINUE IS BROKEN AND HANGS IN FOR LOOPS, FIX LATER + // ====================================================================== pub fn visit_continue(&mut self, ast: &AST) { + let mut scopes = self.scopes.clone(); + let mut pop_count = 0; + loop { + let (scope_type, scope) = scopes.pop().expect("scopes empty in break"); + pop_count += scope; + if scope_type == ScopeType::Loop { + break; + } + } + 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(0xFF); self.vm.chunk.push(0xFF); if self.vm.lines.last().unwrap().0 != ast.end_line { - self.vm.lines.push((ast.end_line, 3)); + self.vm.lines.push((ast.end_line, 5)); } else { - self.vm.lines.last_mut().unwrap().1 += 3; + self.vm.lines.last_mut().unwrap().1 += 5; } self.continue_stack.last_mut().expect("continue not in a loop").push(self.vm.chunk.len()-2); } @@ -135,11 +164,13 @@ impl Codegen { self.vm.chunk.push(0xFF); // placeholder let start_jmp_loc = self.vm.chunk.len()-2; if self.vm.lines.last().unwrap().0 != condition.end_line { - self.vm.lines.push((condition.end_line, 3)); + self.vm.lines.push((condition.end_line, 5)); } else { - self.vm.lines.last_mut().unwrap().1 += 3; + self.vm.lines.last_mut().unwrap().1 += 5; + } + if let ASTType::Block(ref stmts) = block.ast_type { + self.visit_block(&block, stmts.clone(), ScopeType::If); } - self.visit(block); if let Some(ast) = else_expr { match ast.ast_type { ASTType::If(_, _, _) => { @@ -154,7 +185,9 @@ impl Codegen { } self.patch_jump(start_jmp_loc, 0); - self.visit(ast); + if let ASTType::Block(ref stmts) = ast.ast_type { + self.visit_block(&ast, stmts.clone(), ScopeType::If); + } self.patch_jump(end_jmp_loc, 0); } ASTType::Block(_) => { @@ -170,7 +203,9 @@ impl Codegen { let end_jmp_loc = self.vm.chunk.len()-2; self.patch_jump(start_jmp_loc, 0); // jmp to else - self.visit(ast); + if let ASTType::Block(ref stmts) = ast.ast_type { + self.visit_block(&ast, stmts.clone(), ScopeType::If); + } self.patch_jump(end_jmp_loc, 0); // jmp to after else } _ => { println!("unimplemented"); } @@ -179,12 +214,12 @@ impl Codegen { self.patch_jump(start_jmp_loc, 0); } } - pub fn visit_block(&mut self, ast: &AST, stmts: Vec) { - self.scopes.push(0); + pub fn visit_block(&mut self, ast: &AST, stmts: Vec, scope_type: ScopeType) { + self.scopes.push((scope_type, 0)); for stmt in stmts { self.visit(stmt); } - let variables = self.scopes.pop().expect("popped scope in block"); + 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 != ast.end_line { @@ -197,7 +232,7 @@ impl Codegen { self.visit(expr); #[allow(irrefutable_let_patterns)] if let Extension::Resolution(_scope, _ptr) = ast.extensions[0] { - *self.scopes.last_mut().expect("codegen scopes vec was empty") += 1; + self.scopes.last_mut().expect("codegen scopes vec was empty").1 += 1; } } pub fn visit_expr_stmt(&mut self, ast: &AST, expr: AST) { @@ -307,3 +342,8 @@ impl Codegen { self.vm.chunk[loc + 1] = (jump & 0xFF) as u8; } } + +#[derive(Debug, Clone, PartialEq, Eq)] +pub enum ScopeType { + Main, Loop, If, Other, +} diff --git a/kabel/src/main.rs b/kabel/src/main.rs index 91875e5fb693a87f88367d8a78c240fc682c0ca9..f355469e57773cf596cb3ad1fdeb3e46e77feb2f 100644 --- a/kabel/src/main.rs +++ b/kabel/src/main.rs @@ -11,10 +11,8 @@ fn main() { let program = " -var i = 0; -while(i < 5) { +for(var i = 0; i < 5; i++) { print i; - i += 1; continue; } ".to_string();