@@ 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<usize>, // number of variables declared in the scope
+ pub scopes: Vec<(ScopeType, usize)>, // number of variables declared in the scope
break_stack: Vec<Vec<usize>>,
continue_stack: Vec<Vec<usize>>,
}
@@ 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<AST>) {
- self.scopes.push(0);
+ pub fn visit_block(&mut self, ast: &AST, stmts: Vec<AST>, 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,
+}