M kabel/opcodes.txt => kabel/opcodes.txt +3 -0
@@ 26,5 26,8 @@ JMP LOC ; 0x15
JMP_UP LOC ; 0x16
JNE ELSE ; 0x17
+CALL NUMARGS UNIT_PTR ; 0x18
+RET ; 0x19
+
POP COUNT ; 0xFD
PRINT ; 0xFE
M kabel/src/codegen.rs => kabel/src/codegen.rs +198 -135
@@ 1,4 1,4 @@
-use crate::{ast::{ASTType, BinOp, Lit, Name, UnOp, AST}, codegen_binary, codegen_unary, extension::Extension, opcodes::OpCode, vm::{Value, VM}};
+use crate::{ast::{ASTType, BinOp, Lit, Name, UnOp, AST}, codegen_binary, codegen_unary, extension::Extension, opcodes::OpCode, vm::{Unit, Value, VM}};
pub struct Codegen {
pub vm: VM,
@@ 25,6 25,9 @@ impl Codegen {
self.visit(ast);
}
}
+ Function(name, args, block) => {
+ self.visit_function(name, args, *block);
+ }
While(condition, block) => {
self.visit_while(*condition, *block);
}
@@ 65,36 68,74 @@ impl Codegen {
Lit(ref lit) => {
self.visit_lit(&ast, lit.clone());
}
+ Call(ref name, ref args) => {
+ self.visit_call(&ast, name.clone(), args.clone());
+ }
_ => {}
}
}
+ pub fn visit_function(&mut self, _name: Name, _args: Vec<Name>, block: AST) {
+ let old_unit_ptr = self.vm.unit_ptr;
+ let old_ip = self.vm.ip;
+ // create new compilation unit
+ self.vm.units.push(Unit::new_empty());
+ // set unit to write to
+ self.vm.unit_ptr = self.vm.units.len()-1;
+ self.vm.ip = 0;
+
+ if let ASTType::Block(ref stmts) = block.ast_type {
+ self.visit_block(&block, stmts.clone(), ScopeType::Function);
+ }
+ match self.vm.units[self.vm.unit_ptr].code.last() {
+ Some(instr) => {
+ if *instr != OpCode::RET.into() {
+ self.vm.units[self.vm.unit_ptr].code.push(OpCode::RET.into());
+ if self.vm.units[self.vm.unit_ptr].lines.last().unwrap().0 != block.end_line {
+ self.vm.units[self.vm.unit_ptr].lines.push((block.end_line, 1));
+ } else {
+ self.vm.units[self.vm.unit_ptr].lines.last_mut().unwrap().1 += 1;
+ }
+ }
+ }
+ None => {
+ self.vm.units[self.vm.unit_ptr].code.push(OpCode::RET.into());
+ if self.vm.units[self.vm.unit_ptr].lines.last().unwrap().0 != block.end_line {
+ self.vm.units[self.vm.unit_ptr].lines.push((block.end_line, 1));
+ } else {
+ self.vm.units[self.vm.unit_ptr].lines.last_mut().unwrap().1 += 1;
+ }
+ }
+ };
+ self.vm.unit_ptr = old_unit_ptr;
+ self.vm.ip = old_ip;
+ }
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();
+ let end_jmp = self.vm.units[self.vm.unit_ptr].code.len();
self.visit(condition.clone());
- self.vm.chunk.push(OpCode::JNE.into());
- self.vm.chunk.push(0xFF); // placeholder
- 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.units[self.vm.unit_ptr].code.push(OpCode::JNE.into());
+ self.vm.units[self.vm.unit_ptr].code.push(0xFF); // placeholder
+ self.vm.units[self.vm.unit_ptr].code.push(0xFF); // placeholder
+ let start_jmp_loc = self.vm.units[self.vm.unit_ptr].code.len()-2;
+ if self.vm.units[self.vm.unit_ptr].lines.last().unwrap().0 != condition.end_line {
+ self.vm.units[self.vm.unit_ptr].lines.push((condition.end_line, 3));
} else {
- self.vm.lines.last_mut().unwrap().1 += 3;
+ self.vm.units[self.vm.unit_ptr].lines.last_mut().unwrap().1 += 3;
}
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;
+ self.vm.units[self.vm.unit_ptr].code.push(OpCode::JMP_UP.into());
+ let current = self.vm.units[self.vm.unit_ptr].code.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));
+ self.vm.units[self.vm.unit_ptr].code.push(((current_to_start >> 8) & 0xFF) as u8);
+ self.vm.units[self.vm.unit_ptr].code.push((current_to_start & 0xFF) as u8);
+ if self.vm.units[self.vm.unit_ptr].lines.last().unwrap().0 != block.end_line {
+ self.vm.units[self.vm.unit_ptr].lines.push((block.end_line, 3));
} else {
- self.vm.lines.last_mut().unwrap().1 += 3;
+ self.vm.units[self.vm.unit_ptr].lines.last_mut().unwrap().1 += 3;
}
self.patch_jump(start_jmp_loc, 0);
@@ 105,8 146,8 @@ impl Codegen {
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.vm.units[self.vm.unit_ptr].code[loc] = ((jump >> 8) & 0xFF) as u8;
+ self.vm.units[self.vm.unit_ptr].code[loc + 1] = (jump & 0xFF) as u8;
}
}
pub fn visit_for(&mut self, expr1: Option<AST>, expr2: Option<AST>,
@@ 119,18 160,18 @@ impl Codegen {
if let Some(expr1) = expr1 {
self.visit(expr1);
}
- let end_jmp = self.vm.chunk.len();
+ let end_jmp = self.vm.units[self.vm.unit_ptr].code.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));
+ self.vm.units[self.vm.unit_ptr].code.push(OpCode::JNE.into());
+ self.vm.units[self.vm.unit_ptr].code.push(0xFF); // placeholder
+ self.vm.units[self.vm.unit_ptr].code.push(0xFF); // placeholder
+ start_jmp_loc = Some(self.vm.units[self.vm.unit_ptr].code.len()-2);
+ if self.vm.units[self.vm.unit_ptr].lines.last().unwrap().0 != expr2.end_line {
+ self.vm.units[self.vm.unit_ptr].lines.push((expr2.end_line, 3));
} else {
- self.vm.lines.last_mut().unwrap().1 += 3;
+ self.vm.units[self.vm.unit_ptr].lines.last_mut().unwrap().1 += 3;
}
}
if let ASTType::Block(ref stmts) = block.ast_type {
@@ 139,31 180,31 @@ impl Codegen {
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.vm.units[self.vm.unit_ptr].code[loc] = ((jump >> 8) & 0xFF) as u8;
+ self.vm.units[self.vm.unit_ptr].code[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));
+ self.vm.units[self.vm.unit_ptr].code.push(OpCode::POP.into());
+ self.vm.units[self.vm.unit_ptr].code.push(0x01);
+ if self.vm.units[self.vm.unit_ptr].lines.last().unwrap().0 != block.end_line {
+ self.vm.units[self.vm.unit_ptr].lines.push((block.end_line, 2));
} else {
- self.vm.lines.last_mut().unwrap().1 += 2;
+ self.vm.units[self.vm.unit_ptr].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;
+ self.vm.units[self.vm.unit_ptr].code.push(OpCode::JMP_UP.into());
+ let current = self.vm.units[self.vm.unit_ptr].code.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));
+ self.vm.units[self.vm.unit_ptr].code.push(((current_to_start >> 8) & 0xFF) as u8);
+ self.vm.units[self.vm.unit_ptr].code.push((current_to_start & 0xFF) as u8);
+ if self.vm.units[self.vm.unit_ptr].lines.last().unwrap().0 != block.end_line {
+ self.vm.units[self.vm.unit_ptr].lines.push((block.end_line, 3));
} else {
- self.vm.lines.last_mut().unwrap().1 += 3;
+ self.vm.units[self.vm.unit_ptr].lines.last_mut().unwrap().1 += 3;
}
let breaks = self.break_stack.pop().expect("break stack empty on pop");
@@ 177,12 218,12 @@ impl Codegen {
}
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));
+ self.vm.units[self.vm.unit_ptr].code.push(OpCode::POP.into());
+ self.vm.units[self.vm.unit_ptr].code.push(variables as u8);
+ if self.vm.units[self.vm.unit_ptr].lines.last().unwrap().0 != block.end_line {
+ self.vm.units[self.vm.unit_ptr].lines.push((block.end_line, 2));
} else {
- self.vm.lines.last_mut().unwrap().1 += 2;
+ self.vm.units[self.vm.unit_ptr].lines.last_mut().unwrap().1 += 2;
}
}
@@ 196,18 237,18 @@ impl Codegen {
break;
}
}
- self.vm.chunk.push(OpCode::POP.into());
- self.vm.chunk.push(pop_count as u8);
+ self.vm.units[self.vm.unit_ptr].code.push(OpCode::POP.into());
+ self.vm.units[self.vm.unit_ptr].code.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, 5));
+ self.vm.units[self.vm.unit_ptr].code.push(OpCode::JMP.into());
+ self.vm.units[self.vm.unit_ptr].code.push(0xFF);
+ self.vm.units[self.vm.unit_ptr].code.push(0xFF);
+ if self.vm.units[self.vm.unit_ptr].lines.last().unwrap().0 != ast.end_line {
+ self.vm.units[self.vm.unit_ptr].lines.push((ast.end_line, 5));
} else {
- self.vm.lines.last_mut().unwrap().1 += 5;
+ self.vm.units[self.vm.unit_ptr].lines.last_mut().unwrap().1 += 5;
}
- self.break_stack.last_mut().expect("break not in a loop").push(self.vm.chunk.len()-2);
+ self.break_stack.last_mut().expect("break not in a loop").push(self.vm.units[self.vm.unit_ptr].code.len()-2);
}
// ======================================================================
// CONTINUE IS BROKEN AND HANGS IN FOR LOOPS, FIX LATER
@@ 222,29 263,29 @@ impl Codegen {
break;
}
}
- self.vm.chunk.push(OpCode::POP.into());
- self.vm.chunk.push(pop_count as u8);
+ self.vm.units[self.vm.unit_ptr].code.push(OpCode::POP.into());
+ self.vm.units[self.vm.unit_ptr].code.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, 5));
+ self.vm.units[self.vm.unit_ptr].code.push(OpCode::JMP.into());
+ self.vm.units[self.vm.unit_ptr].code.push(0xFF);
+ self.vm.units[self.vm.unit_ptr].code.push(0xFF);
+ if self.vm.units[self.vm.unit_ptr].lines.last().unwrap().0 != ast.end_line {
+ self.vm.units[self.vm.unit_ptr].lines.push((ast.end_line, 5));
} else {
- self.vm.lines.last_mut().unwrap().1 += 5;
+ self.vm.units[self.vm.unit_ptr].lines.last_mut().unwrap().1 += 5;
}
- self.continue_stack.last_mut().expect("continue not in a loop").push(self.vm.chunk.len()-2);
+ self.continue_stack.last_mut().expect("continue not in a loop").push(self.vm.units[self.vm.unit_ptr].code.len()-2);
}
pub fn visit_if(&mut self, condition: AST, block: AST, else_expr: Option<AST>) {
self.visit(condition.clone());
- self.vm.chunk.push(OpCode::JNE.into());
- self.vm.chunk.push(0xFF); // placeholder
- 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, 5));
+ self.vm.units[self.vm.unit_ptr].code.push(OpCode::JNE.into());
+ self.vm.units[self.vm.unit_ptr].code.push(0xFF); // placeholder
+ self.vm.units[self.vm.unit_ptr].code.push(0xFF); // placeholder
+ let start_jmp_loc = self.vm.units[self.vm.unit_ptr].code.len()-2;
+ if self.vm.units[self.vm.unit_ptr].lines.last().unwrap().0 != condition.end_line {
+ self.vm.units[self.vm.unit_ptr].lines.push((condition.end_line, 5));
} else {
- self.vm.lines.last_mut().unwrap().1 += 5;
+ self.vm.units[self.vm.unit_ptr].lines.last_mut().unwrap().1 += 5;
}
if let ASTType::Block(ref stmts) = block.ast_type {
self.visit_block(&block, stmts.clone(), ScopeType::If);
@@ 252,14 293,14 @@ impl Codegen {
if let Some(ast) = else_expr {
match ast.ast_type {
ASTType::If(_, _, _) => {
- self.vm.chunk.push(OpCode::JMP.into());
- self.vm.chunk.push(0xFF); // placeholder
- self.vm.chunk.push(0xFF); // placeholder
- let end_jmp_loc = self.vm.chunk.len()-2;
- if self.vm.lines.last().unwrap().0 != ast.end_line {
- self.vm.lines.push((ast.end_line, 3));
+ self.vm.units[self.vm.unit_ptr].code.push(OpCode::JMP.into());
+ self.vm.units[self.vm.unit_ptr].code.push(0xFF); // placeholder
+ self.vm.units[self.vm.unit_ptr].code.push(0xFF); // placeholder
+ let end_jmp_loc = self.vm.units[self.vm.unit_ptr].code.len()-2;
+ if self.vm.units[self.vm.unit_ptr].lines.last().unwrap().0 != ast.end_line {
+ self.vm.units[self.vm.unit_ptr].lines.push((ast.end_line, 3));
} else {
- self.vm.lines.last_mut().unwrap().1 += 3;
+ self.vm.units[self.vm.unit_ptr].lines.last_mut().unwrap().1 += 3;
}
self.patch_jump(start_jmp_loc, 0);
@@ 268,16 309,16 @@ impl Codegen {
}
ASTType::Block(_) => {
- self.vm.chunk.push(OpCode::JMP.into());
- self.vm.chunk.push(0xFF); // placeholder
- self.vm.chunk.push(0xFF); // placeholder
- if self.vm.lines.last().unwrap().0 != ast.end_line {
- self.vm.lines.push((ast.end_line, 3));
+ self.vm.units[self.vm.unit_ptr].code.push(OpCode::JMP.into());
+ self.vm.units[self.vm.unit_ptr].code.push(0xFF); // placeholder
+ self.vm.units[self.vm.unit_ptr].code.push(0xFF); // placeholder
+ if self.vm.units[self.vm.unit_ptr].lines.last().unwrap().0 != ast.end_line {
+ self.vm.units[self.vm.unit_ptr].lines.push((ast.end_line, 3));
} else {
- self.vm.lines.last_mut().unwrap().1 += 3;
+ self.vm.units[self.vm.unit_ptr].lines.last_mut().unwrap().1 += 3;
}
- let end_jmp_loc = self.vm.chunk.len()-2;
+ let end_jmp_loc = self.vm.units[self.vm.unit_ptr].code.len()-2;
self.patch_jump(start_jmp_loc, 0); // jmp to else
if let ASTType::Block(ref stmts) = ast.ast_type {
self.visit_block(&ast, stmts.clone(), ScopeType::If);
@@ 296,12 337,15 @@ impl Codegen {
self.visit(stmt);
}
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 {
- self.vm.lines.push((ast.end_line, 2));
- } else {
- self.vm.lines.last_mut().unwrap().1 += 2;
+ self.vm.units[self.vm.unit_ptr].code.push(OpCode::POP.into());
+ self.vm.units[self.vm.unit_ptr].code.push(variables as u8);
+ match self.vm.units[self.vm.unit_ptr].lines.last() {
+ Some(last) => if last.0 != ast.end_line {
+ self.vm.units[self.vm.unit_ptr].lines.push((ast.end_line, 2));
+ } else {
+ self.vm.units[self.vm.unit_ptr].lines.last_mut().unwrap().1 += 2;
+ }
+ None => self.vm.units[self.vm.unit_ptr].lines.push((ast.end_line, 2))
}
}
pub fn visit_decl(&mut self, ast: &AST, _name: Name, expr: AST) {
@@ 313,41 357,41 @@ impl Codegen {
}
pub fn visit_expr_stmt(&mut self, ast: &AST, expr: AST) {
self.visit(expr);
- self.vm.chunk.push(OpCode::POP.into());
- self.vm.chunk.push(0x01);
- if self.vm.lines.last().unwrap().0 != ast.end_line {
- self.vm.lines.push((ast.end_line, 2));
+ self.vm.units[self.vm.unit_ptr].code.push(OpCode::POP.into());
+ self.vm.units[self.vm.unit_ptr].code.push(0x01);
+ if self.vm.units[self.vm.unit_ptr].lines.last().unwrap().0 != ast.end_line {
+ self.vm.units[self.vm.unit_ptr].lines.push((ast.end_line, 2));
} else {
- self.vm.lines.last_mut().unwrap().1 += 2;
+ self.vm.units[self.vm.unit_ptr].lines.last_mut().unwrap().1 += 2;
}
}
// REMOVE LATER
pub fn visit_print(&mut self, ast: &AST, expr: AST) {
self.visit(expr);
- self.vm.chunk.push(OpCode::PRINT.into());
- if self.vm.lines.last().unwrap().0 != ast.end_line {
- self.vm.lines.push((ast.end_line, 1));
+ self.vm.units[self.vm.unit_ptr].code.push(OpCode::PRINT.into());
+ if self.vm.units[self.vm.unit_ptr].lines.last().unwrap().0 != ast.end_line {
+ self.vm.units[self.vm.unit_ptr].lines.push((ast.end_line, 1));
} else {
- self.vm.lines.last_mut().unwrap().1 += 1;
+ self.vm.units[self.vm.unit_ptr].lines.last_mut().unwrap().1 += 1;
}
}
pub fn visit_assign(&mut self, ast: &AST, _name: Name, expr: AST) {
self.visit(expr);
// pop stack to get value. then find variable in stack. set variable to value.
- self.vm.chunk.push(OpCode::ASSIGN.into());
+ self.vm.units[self.vm.unit_ptr].code.push(OpCode::ASSIGN.into());
#[allow(irrefutable_let_patterns)]
if let Extension::Resolution(_scope, ptr) = ast.extensions[0] {
- self.vm.chunk.push(ptr as u8);
- if self.vm.lines.last().unwrap().0 != ast.end_line {
- self.vm.lines.push((ast.end_line, 1));
+ self.vm.units[self.vm.unit_ptr].code.push(ptr as u8);
+ if self.vm.units[self.vm.unit_ptr].lines.last().unwrap().0 != ast.end_line {
+ self.vm.units[self.vm.unit_ptr].lines.push((ast.end_line, 1));
} else {
- self.vm.lines.last_mut().unwrap().1 += 1;
+ self.vm.units[self.vm.unit_ptr].lines.last_mut().unwrap().1 += 1;
}
}
- if self.vm.lines.last().unwrap().0 != ast.end_line {
- self.vm.lines.push((ast.end_line, 1));
+ if self.vm.units[self.vm.unit_ptr].lines.last().unwrap().0 != ast.end_line {
+ self.vm.units[self.vm.unit_ptr].lines.push((ast.end_line, 1));
} else {
- self.vm.lines.last_mut().unwrap().1 += 1;
+ self.vm.units[self.vm.unit_ptr].lines.last_mut().unwrap().1 += 1;
}
}
pub fn visit_binary(&mut self, left: AST, oper: BinOp, right: AST) {
@@ 363,63 407,82 @@ impl Codegen {
pub fn visit_lit(&mut self, ast: &AST, lit: Lit) {
match lit {
Lit::Num(value) => {
- self.vm.pool.push(Value::Num(value));
- self.vm.chunk.push(OpCode::LOAD.into());
- self.vm.chunk.push((self.vm.pool.len()-1) as u8);
- if self.vm.lines.len() == 0 || self.vm.lines.last().unwrap().0 != ast.end_line {
- self.vm.lines.push((ast.end_line, 2));
+ self.vm.units[self.vm.unit_ptr].pool.push(Value::Num(value));
+ self.vm.units[self.vm.unit_ptr].code.push(OpCode::LOAD.into());
+ let loc = (self.vm.units[self.vm.unit_ptr].pool.len()-1) as u8;
+ self.vm.units[self.vm.unit_ptr].code.push(loc);
+ if self.vm.units[self.vm.unit_ptr].lines.len() == 0 || self.vm.units[self.vm.unit_ptr].lines.last().unwrap().0 != ast.end_line {
+ self.vm.units[self.vm.unit_ptr].lines.push((ast.end_line, 2));
} else {
- self.vm.lines.last_mut().unwrap().1 += 2;
+ self.vm.units[self.vm.unit_ptr].lines.last_mut().unwrap().1 += 2;
}
}
Lit::Str(value) => {
- self.vm.pool.push(Value::Str(value.into()));
- self.vm.chunk.push(OpCode::LOAD.into());
- self.vm.chunk.push((self.vm.pool.len()-1) as u8);
- if self.vm.lines.len() == 0 || self.vm.lines.last().unwrap().0 != ast.end_line {
- self.vm.lines.push((ast.end_line, 2));
+ self.vm.units[self.vm.unit_ptr].pool.push(Value::Str(value.into()));
+ self.vm.units[self.vm.unit_ptr].code.push(OpCode::LOAD.into());
+ let loc = (self.vm.units[self.vm.unit_ptr].pool.len()-1) as u8;
+ self.vm.units[self.vm.unit_ptr].code.push(loc);
+ if self.vm.units[self.vm.unit_ptr].lines.len() == 0 || self.vm.units[self.vm.unit_ptr].lines.last().unwrap().0 != ast.end_line {
+ self.vm.units[self.vm.unit_ptr].lines.push((ast.end_line, 2));
} else {
- self.vm.lines.last_mut().unwrap().1 += 2;
+ self.vm.units[self.vm.unit_ptr].lines.last_mut().unwrap().1 += 2;
}
}
Lit::Bool(value) => {
- self.vm.pool.push(Value::Bool(value));
- self.vm.chunk.push(OpCode::LOAD.into());
- self.vm.chunk.push((self.vm.pool.len()-1) as u8);
- if self.vm.lines.len() == 0 || self.vm.lines.last().unwrap().0 != ast.end_line {
- self.vm.lines.push((ast.end_line, 2));
+ self.vm.units[self.vm.unit_ptr].pool.push(Value::Bool(value));
+ self.vm.units[self.vm.unit_ptr].code.push(OpCode::LOAD.into());
+ let loc = (self.vm.units[self.vm.unit_ptr].pool.len()-1) as u8;
+ self.vm.units[self.vm.unit_ptr].code.push(loc);
+ if self.vm.units[self.vm.unit_ptr].lines.len() == 0 || self.vm.units[self.vm.unit_ptr].lines.last().unwrap().0 != ast.end_line {
+ self.vm.units[self.vm.unit_ptr].lines.push((ast.end_line, 2));
} else {
- self.vm.lines.last_mut().unwrap().1 += 2;
+ self.vm.units[self.vm.unit_ptr].lines.last_mut().unwrap().1 += 2;
}
}
Lit::Ident(_name) => {
- self.vm.chunk.push(OpCode::VAR.into());
+ self.vm.units[self.vm.unit_ptr].code.push(OpCode::VAR.into());
#[allow(irrefutable_let_patterns)]
if let Extension::Resolution(_scope, ptr) = ast.extensions[0] {
/*println!("line: {} ptr: {} locals: {:?}", ast.end_line, ptr, self.locals);
let (_scope, slot) = self.locals.get(ptr).unwrap();
println!("slot: {}", *slot);
- self.vm.chunk.push(*slot);*/
- self.vm.chunk.push(ptr as u8);
- if self.vm.lines.len() == 0 || self.vm.lines.last().unwrap().0 != ast.end_line {
- self.vm.lines.push((ast.end_line, 2));
+ self.vm.units[self.vm.unit_ptr].code.push(*slot);*/
+ self.vm.units[self.vm.unit_ptr].code.push(ptr as u8);
+ if self.vm.units[self.vm.unit_ptr].lines.len() == 0 || self.vm.units[self.vm.unit_ptr].lines.last().unwrap().0 != ast.end_line {
+ self.vm.units[self.vm.unit_ptr].lines.push((ast.end_line, 2));
} else {
- self.vm.lines.last_mut().unwrap().1 += 2;
+ self.vm.units[self.vm.unit_ptr].lines.last_mut().unwrap().1 += 2;
}
}
}
_ => {}
}
}
+ pub fn visit_call(&mut self, ast: &AST, _name: Name, args: Vec<AST>) {
+ for arg in args.clone() {
+ self.visit(arg);
+ }
+ self.vm.units[self.vm.unit_ptr].code.push(OpCode::CALL.into());
+ self.vm.units[self.vm.unit_ptr].code.push(args.len() as u8);
+ #[allow(irrefutable_let_patterns)]
+ if let Extension::Resolution(_scope, ptr) = ast.extensions[0] {
+ self.vm.units[self.vm.unit_ptr].code.push(ptr as u8);
+ if self.vm.units[self.vm.unit_ptr].lines.len() == 0 || self.vm.units[self.vm.unit_ptr].lines.last().unwrap().0 != ast.end_line {
+ self.vm.units[self.vm.unit_ptr].lines.push((ast.end_line, 3));
+ } else {
+ self.vm.units[self.vm.unit_ptr].lines.last_mut().unwrap().1 += 3;
+ }
+ }
+ }
pub fn patch_jump(&mut self, loc: usize, offset: i32) {
- let jump = ((self.vm.chunk.len() - loc - 2) as i32) + offset;
+ let jump = ((self.vm.units[self.vm.unit_ptr].code.len() - loc - 2) as i32) + offset;
- self.vm.chunk[loc] = ((jump >> 8) & 0xFF) as u8;
- self.vm.chunk[loc + 1] = (jump & 0xFF) as u8;
+ self.vm.units[self.vm.unit_ptr].code[loc] = ((jump >> 8) & 0xFF) as u8;
+ self.vm.units[self.vm.unit_ptr].code[loc + 1] = (jump & 0xFF) as u8;
}
}
#[derive(Debug, Clone, PartialEq, Eq)]
pub enum ScopeType {
- Main, Loop, If, Other,
+ Main, Function, Loop, If, Other,
}
M kabel/src/debug.rs => kabel/src/debug.rs +25 -14
@@ 1,4 1,4 @@
-use crate::{ast::AST, lexer::Token, push_codegen, push_output, vm::{Value, VM}};
+use crate::{ast::AST, extension::Extension, lexer::Token, push_codegen, push_output, vm::{Value, VM}};
pub fn debug_token_array(tokens: Vec<Token>) -> String {
let mut output = "".to_string();
@@ 30,6 30,7 @@ pub fn debug_ast(ast: AST, level: usize) -> String {
for arg in args {
output += &(" ".to_string() + &arg.name);
}
+ output += &format!(" {:?}", ast.extensions);
output += "\n";
output += &debug_ast(*block, level+1);
}
@@ 118,6 119,7 @@ pub fn debug_ast(ast: AST, level: usize) -> String {
output += &"| ".repeat(level);
output += "Decl ";
output += &name.name;
+ output += &format!(" {:?}", ast.extensions);
output += "\n";
output += &debug_ast(*expr, level+1);
}
@@ 125,6 127,7 @@ pub fn debug_ast(ast: AST, level: usize) -> String {
output += &"| ".repeat(level);
output += "Assign ";
output += &name.name;
+ output += &format!(" {:?}", ast.extensions);
output += "\n";
output += &debug_ast(*expr, level+1);
}
@@ 169,6 172,7 @@ pub fn debug_ast(ast: AST, level: usize) -> String {
match lit {
Ident(name) => {
output += &name;
+ output += &format!(" {:?}", ast.extensions);
}
Str(value) => {
output += &value;
@@ 212,19 216,19 @@ pub fn debug_bytecode(vm: &VM) -> String {
//let mut ip = 0;
let mut output = "".to_string();
let mut vm = vm.clone();
- while vm.ip < vm.chunk.len() {
+ while vm.ip < vm.units[vm.unit_ptr].code.len() {
// remove PRINT later
- push_codegen!(vm.chunk[vm.ip].into(), vm, output, ADD, SUB, MUL, DIV, MOD, BITAND,
+ push_codegen!(vm.units[vm.unit_ptr].code[vm.ip].into(), vm, output, ADD, SUB, MUL, DIV, MOD, BITAND,
BITXOR, BITOR, EQ, NE, GR, GE, LS, LE, OR, AND, NOT, NEG,
PRINT, ERR);
- match vm.chunk[vm.ip].into() {
+ match vm.units[vm.unit_ptr].code[vm.ip].into() {
LOAD => {
output += &vm.ip.to_string();
output += " ";
output += &vm.find_line().to_string();
output += " CONSTANT ";
vm.ip += 1;
- output += &vm.chunk[vm.ip].to_string();
+ output += &vm.units[vm.unit_ptr].code[vm.ip].to_string();
output += "\n";
}
VAR => {
@@ 233,7 237,7 @@ pub fn debug_bytecode(vm: &VM) -> String {
output += &vm.find_line().to_string();
output += " VAR ";
vm.ip += 1;
- output += &vm.chunk[vm.ip].to_string();
+ output += &vm.units[vm.unit_ptr].code[vm.ip].to_string();
output += "\n";
}
ASSIGN => {
@@ 242,7 246,7 @@ pub fn debug_bytecode(vm: &VM) -> String {
output += &vm.find_line().to_string();
output += " ASSIGN ";
vm.ip += 1;
- output += &vm.chunk[vm.ip].to_string();
+ output += &vm.units[vm.unit_ptr].code[vm.ip].to_string();
output += "\n";
}
@@ 252,9 256,9 @@ pub fn debug_bytecode(vm: &VM) -> String {
output += &vm.find_line().to_string();
output += " JMP ";
vm.ip += 1;
- let byte_one = (vm.chunk[vm.ip] as u16) << 8;
+ let byte_one = (vm.units[vm.unit_ptr].code[vm.ip] as u16) << 8;
vm.ip += 1;
- let byte_two = vm.chunk[vm.ip] as u16;
+ let byte_two = vm.units[vm.unit_ptr].code[vm.ip] as u16;
output += &(byte_one | byte_two).to_string();
output += "\n";
}
@@ 264,9 268,9 @@ pub fn debug_bytecode(vm: &VM) -> String {
output += &vm.find_line().to_string();
output += " JMP_UP ";
vm.ip += 1;
- let byte_one = (vm.chunk[vm.ip] as u16) << 8;
+ let byte_one = (vm.units[vm.unit_ptr].code[vm.ip] as u16) << 8;
vm.ip += 1;
- let byte_two = vm.chunk[vm.ip] as u16;
+ let byte_two = vm.units[vm.unit_ptr].code[vm.ip] as u16;
output += &(byte_one | byte_two).to_string();
output += "\n";
}
@@ 276,19 280,26 @@ pub fn debug_bytecode(vm: &VM) -> String {
output += &vm.find_line().to_string();
output += " JNE ";
vm.ip += 1;
- let byte_one = (vm.chunk[vm.ip] as u16) << 8;
+ let byte_one = (vm.units[vm.unit_ptr].code[vm.ip] as u16) << 8;
vm.ip += 1;
- let byte_two = vm.chunk[vm.ip] as u16;
+ let byte_two = vm.units[vm.unit_ptr].code[vm.ip] as u16;
output += &(byte_one | byte_two).to_string();
output += "\n";
}
+ RET => {
+ output += &vm.ip.to_string();
+ output += " ";
+ output += &vm.find_line().to_string();
+ output += " RET ";
+ output += "\n";
+ }
POP => {
output += &vm.ip.to_string();
output += " ";
output += &vm.find_line().to_string();
output += " POP ";
vm.ip += 1;
- output += &vm.chunk[vm.ip].to_string();
+ output += &vm.units[vm.unit_ptr].code[vm.ip].to_string();
output += "\n";
}
_ => {}
M kabel/src/macros.rs => kabel/src/macros.rs +10 -10
@@ 264,8 264,8 @@ macro_rules! codegen_binary {
$( $oper => {
$self.visit($right);
$self.visit($left);
- $self.vm.chunk.push(OpCode::$code.into());
- $self.vm.lines.last_mut().unwrap().1 += 1;
+ $self.vm.units[$self.vm.unit_ptr].code.push(OpCode::$code.into());
+ $self.vm.units[$self.vm.unit_ptr].lines.last_mut().unwrap().1 += 1;
} )*
}
};
@@ 276,8 276,8 @@ macro_rules! codegen_unary {
match $match_to {
$( $oper => {
$self.visit($right);
- $self.vm.chunk.push(OpCode::$code.into());
- $self.vm.lines.last_mut().unwrap().1 += 1;
+ $self.vm.units[0].code.push(OpCode::$code.into());
+ $self.vm.units[0].lines.last_mut().unwrap().1 += 1;
} )*
}
};
@@ 302,12 302,12 @@ macro_rules! push_codegen {
#[macro_export]
macro_rules! vm_boolean_binary {
($self:expr, $oper:tt) => {
- match ($self.stack.pop().expect(&("Couldn't pop left side of ".to_owned() + stringify!($oper))),
- $self.stack.pop().expect(&("Couldn't pop right side of ".to_owned() + stringify!($oper)))) {
- (Num(v1), Num(v2)) => $self.stack.push(Bool(v1 $oper v2)),
- (Str(v1), Str(v2)) => $self.stack.push(Bool(v1 $oper v2)),
- (Bool(v1), Bool(v2)) => $self.stack.push(Bool(v1 $oper v2)),
- (_v1, _v2) => $self.stack.push(Bool(false)),
+ match ($self.units[0].stack.pop().expect(&("Couldn't pop left side of ".to_owned() + stringify!($oper))),
+ $self.units[0].stack.pop().expect(&("Couldn't pop right side of ".to_owned() + stringify!($oper)))) {
+ (Num(v1), Num(v2)) => $self.units[0].stack.push(Bool(v1 $oper v2)),
+ (Str(v1), Str(v2)) => $self.units[0].stack.push(Bool(v1 $oper v2)),
+ (Bool(v1), Bool(v2)) => $self.units[0].stack.push(Bool(v1 $oper v2)),
+ (_v1, _v2) => $self.units[0].stack.push(Bool(false)),
}
};
}
M kabel/src/main.rs => kabel/src/main.rs +10 -3
@@ 52,15 52,22 @@ fn main() {
let codegen = run_codegen(program.to_string(), ast);
let mut vm = codegen.vm;
- output += &debug_bytecode(&vm);
- output += "\n";
+ for (index, _) in vm.units.iter().enumerate() {
+ vm.unit_ptr = index;
+ output += "unit ptr: ";
+ output += &vm.unit_ptr.to_string();
+ output += "\n";
+ output += &debug_bytecode(&vm);
+ output += "\n";
+ }
+ vm.unit_ptr = 0;
output += "\n";
match vm.run(&mut output) {
Ok(()) => {}
Err(e) => output += &e.to_string(),
}
- output += &debug_stack(&vm.stack);
+ output += &debug_stack(&vm.units[0].stack);
println!("{}", output);
}
M kabel/src/name_resolution.rs => kabel/src/name_resolution.rs +29 -10
@@ 61,14 61,23 @@ impl Resolver {
} else {}
}
}
- self.symbol_table.last_mut().unwrap().insert(name.name.clone(), (Symbol::Function(args.len()),0));
self.symbol_table.push(HashMap::new());
for arg in args.clone() {
self.symbol_table.last_mut().unwrap().insert(arg.name, (Symbol::Var,0));
}
let block = self.visit(*block);
self.symbol_table.pop();
- ast_from_ast!(Function(name, args, Box::new(block)), ast, ast)
+ self.locals.push(self.scope);
+ self.symbol_table.last_mut().unwrap().insert(name.name.clone(),
+ (Symbol::Function(args.len()), self.locals.len()-1));
+ AST {
+ ast_type: Function(name, args, Box::new(block)),
+ extensions: vec![Extension::Resolution(self.scope, self.locals.len()-1)],
+ start_line: ast.start_line,
+ end_line: ast.end_line,
+ start_column: ast.start_column,
+ end_column: ast.end_column,
+ }
}
Return(expr) => {
if let Some(expr) = *expr {
@@ 251,9 260,11 @@ impl Resolver {
ast_from_ast!(Lit(lit), ast, ast)
}
Call(ident, args) => {
- if let Err(e) = self.resolve_function(&ident.name, args.len()) {
- match e {
- (ErrorKind::OutOfScope, _, _) => self.errors.push(ast_error!(self, ErrorKind::OutOfScope, ast, "Function \"{}\" not in scope", ident.name)),
+ let resolution = self.resolve_function(&ident.name, args.len());
+ let place = match resolution {
+ Ok(place) => place,
+ Err(e) => match e {
+ (ErrorKind::OutOfScope, _, _) => { self.errors.push(ast_error!(self, ErrorKind::OutOfScope, ast, "Function \"{}\" not in scope", ident.name)); 0 },
(ErrorKind::IncorrectArity, Some(f_arity), Some(arity)) => {
self.errors.push(
KabelError::new(
@@ 265,15 276,23 @@ impl Resolver {
collect_lines!(self.text[ast.start_line-1..ast.end_line-1]),
)
);
+ 0
}
_ => { panic!("Returned invalid ErrorKind from resolve_function") },
}
- }
+ };
let mut n_args = Vec::new();
for arg in args {
n_args.push(self.visit(arg));
}
- ast_from_ast!(Call(ident, n_args), ast, ast)
+ return AST {
+ ast_type: Call(ident, n_args),
+ extensions: vec![Extension::Resolution(self.scope, place)],
+ start_line: ast.start_line,
+ end_line: ast.end_line,
+ start_column: ast.start_column,
+ end_column: ast.end_column,
+ };
}
/*Member(left, right) => {
self.visit_member(*left, *right);
@@ 294,11 313,11 @@ impl Resolver {
}
(false, 0)
}
- fn resolve_function(&mut self, name: &String, arity: usize) -> Result<(), (ErrorKind, Option<usize>, Option<usize>)>{
+ fn resolve_function(&mut self, name: &String, arity: usize) -> Result<usize, (ErrorKind, Option<usize>, Option<usize>)>{
for scope in self.symbol_table.iter().rev() {
- if let Some((Symbol::Function(f_arity), _place)) = scope.get(name) {
+ if let Some((Symbol::Function(f_arity), place)) = scope.get(name) {
if *f_arity == arity {
- return Ok(());
+ return Ok(*place);
} else {
return Err((ErrorKind::IncorrectArity, Some(*f_arity), Some(arity)));
}
M kabel/src/opcodes.rs => kabel/src/opcodes.rs +9 -0
@@ 30,6 30,9 @@ pub enum OpCode {
JMP_UP,
JNE,
+ CALL,
+ RET,
+
POP,
PRINT,
ERR,
@@ 67,6 70,9 @@ impl From<OpCode> for u8 {
JMP_UP => 0x16,
JNE => 0x17,
+ CALL => 0x18,
+ RET => 0x19,
+
POP => 0xFD,
PRINT => 0xFE,
ERR => 0xFF
@@ 104,6 110,9 @@ impl From<u8> for OpCode {
0x16 => JMP_UP,
0x17 => JNE,
+ 0x18 => CALL,
+ 0x19 => RET,
+
0xFD => POP,
0xFE => PRINT,
_ => ERR
M kabel/src/parser.rs => kabel/src/parser.rs +1 -1
@@ 1,5 1,5 @@
use crate::{
- ast_from_ast, ast_from_ast_token, ast_from_token, ast_from_token_ast, collect_lines, error::{ErrorKind, KabelError}, extension::Extension, lexer::{Token, TokenType}, lit, name, unexpected_token
+ ast_from_ast, ast_from_ast_token, ast_from_token, ast_from_token_ast, collect_lines, error::{ErrorKind, KabelError}, lexer::{Token, TokenType}, lit, name, unexpected_token
};
use crate::ast::{AST, ASTType, BinOp, UnOp, Lit};
M kabel/src/vm.rs => kabel/src/vm.rs +88 -49
@@ 1,15 1,39 @@
-use std::collections::HashMap;
-use crate::{opcodes::OpCode, runtime_error::{KabelRuntimeError, RuntimeErrorKind}, vm, vm_boolean_binary};
+use crate::{runtime_error::{KabelRuntimeError, RuntimeErrorKind}, vm_boolean_binary};
use crate::vm_error;
-#[derive(Clone)]
-pub struct VM {
- pub ip: usize,
- pub chunk: Vec<u8>,
+#[derive(Debug, Clone)]
+pub struct Unit {
+ pub code: Vec<u8>,
pub stack: Vec<Value>,
pub pool: Vec<Value>,
pub lines: Vec<(usize, usize)>, // line #, repeats number of instructions
+}
+impl Unit {
+ pub fn new(code: Vec<u8>, stack: Vec<Value>, pool: Vec<Value>, lines: Vec<(usize, usize)>) -> Self {
+ Self {
+ code,
+ stack,
+ pool,
+ lines,
+ }
+ }
+ pub fn new_empty() -> Self {
+ Self {
+ code: Vec::new(),
+ stack: Vec::new(),
+ pool: Vec::new(),
+ lines: Vec::new(),
+ }
+ }
+}
+
+#[derive(Clone)]
+pub struct VM {
+ pub ip: usize,
+ pub unit_ptr: usize,
+ pub call_stack: Vec<(usize, usize)>, // (unit_ptr, ip)
+ pub units: Vec<Unit>,
text: Vec<String>
}
@@ 18,37 42,38 @@ impl VM {
text: String) -> Self {
Self {
ip: 0,
- chunk: bytecode,
- stack: Vec::new(),
- pool,
- lines,
+ unit_ptr: 0,
+ call_stack: Vec::new(),
+ units: vec![Unit::new(bytecode, Vec::new(), pool, lines)],
text: text.lines().map(|s| s.to_string()).collect::<Vec<String>>(),
}
}
pub fn run(&mut self, output: &mut String) -> Result<(), KabelRuntimeError> {
use Value::*;
- while self.ip < self.chunk.len() {
+ while self.ip < self.units[self.unit_ptr].code.len() {
match self.read() {
0x00 => { // LOAD
let byte = self.read() as usize;
- self.stack.push(self.pool[byte].clone());
+ let value = self.units[self.unit_ptr].pool[byte].clone();
+ self.units[self.unit_ptr].stack.push(value);
}
0x01 => { // VAR
let ptr = self.read() as usize;
- self.stack.push(self.stack[ptr].clone());
+ let value = self.units[self.unit_ptr].stack[ptr].clone();
+ self.units[self.unit_ptr].stack.push(value);
}
// ASSIGN
0x02 => {
- let value = self.stack.pop().unwrap();
+ let value = self.units[self.unit_ptr].stack.pop().unwrap();
let ptr = self.read();
- self.stack[ptr as usize] = value.clone();
- self.stack.push(value);
+ self.units[self.unit_ptr].stack[ptr as usize] = value.clone();
+ self.units[self.unit_ptr].stack.push(value);
}
0x03 => { // ADD
- match (self.stack.pop().unwrap(), self.stack.pop().unwrap()) {
- (Num(v1), Num(v2)) => self.stack.push(Num(v1 + v2)),
+ match (self.units[self.unit_ptr].stack.pop().unwrap(), self.units[self.unit_ptr].stack.pop().unwrap()) {
+ (Num(v1), Num(v2)) => self.units[self.unit_ptr].stack.push(Num(v1 + v2)),
(Str(v1), Str(v2)) => {
- self.stack.push(Str(v1 + &v2));
+ self.units[self.unit_ptr].stack.push(Str(v1 + &v2));
},
(Bool(_v1), Bool(_v2)) => {
return Err(vm_error!(self, RuntimeErrorKind::WrongType, "Cannot add booleans"))
@@ 59,8 84,8 @@ impl VM {
}
}
0x04 => { // SUB
- match (self.stack.pop().unwrap(), self.stack.pop().unwrap()) {
- (Num(v1), Num(v2)) => self.stack.push(Num(v1 - v2)),
+ match (self.units[self.unit_ptr].stack.pop().unwrap(), self.units[self.unit_ptr].stack.pop().unwrap()) {
+ (Num(v1), Num(v2)) => self.units[self.unit_ptr].stack.push(Num(v1 - v2)),
(Str(_v1), Str(_v2)) => {
return Err(vm_error!(self, RuntimeErrorKind::WrongType, "Cannot subtract strings"))
},
@@ 73,11 98,11 @@ impl VM {
}
}
0x05 => { // MUL
- match (self.stack.pop().unwrap(), self.stack.pop().unwrap()) {
- (Num(v1), Num(v2)) => self.stack.push(Num(v1 * v2)),
+ match (self.units[self.unit_ptr].stack.pop().unwrap(), self.units[self.unit_ptr].stack.pop().unwrap()) {
+ (Num(v1), Num(v2)) => self.units[self.unit_ptr].stack.push(Num(v1 * v2)),
(Str(v1), Num(v2)) => {
if v2.fract() == 0.0 {
- self.stack.push(Str(v1.repeat(v2 as usize)));
+ self.units[self.unit_ptr].stack.push(Str(v1.repeat(v2 as usize)));
} else {
return Err(vm_error!(self, RuntimeErrorKind::WrongType, "Number must be an integer"))
}
@@ 94,8 119,8 @@ impl VM {
}
}
0x06 => { // DIV
- match (self.stack.pop().unwrap(), self.stack.pop().unwrap()) {
- (Num(v1), Num(v2)) => self.stack.push(Num(v1 / v2)),
+ match (self.units[self.unit_ptr].stack.pop().unwrap(), self.units[self.unit_ptr].stack.pop().unwrap()) {
+ (Num(v1), Num(v2)) => self.units[self.unit_ptr].stack.push(Num(v1 / v2)),
(Str(_v1), Str(_v2)) => {
return Err(vm_error!(self, RuntimeErrorKind::WrongType, "Cannot divide strings"))
},
@@ 108,8 133,8 @@ impl VM {
}
}
0x07 => { // MOD
- match (self.stack.pop().unwrap(), self.stack.pop().unwrap()) {
- (Num(v1), Num(v2)) => self.stack.push(Num(v1 % v2)),
+ match (self.units[self.unit_ptr].stack.pop().unwrap(), self.units[self.unit_ptr].stack.pop().unwrap()) {
+ (Num(v1), Num(v2)) => self.units[self.unit_ptr].stack.push(Num(v1 % v2)),
(Str(_v1), Str(_v2)) => {
return Err(vm_error!(self, RuntimeErrorKind::WrongType, "Cannot perform modulus on strings"))
},
@@ 122,7 147,7 @@ impl VM {
}
}
0x08 => { // BITAND
- match (self.stack.pop().unwrap(), self.stack.pop().unwrap()) {
+ match (self.units[self.unit_ptr].stack.pop().unwrap(), self.units[self.unit_ptr].stack.pop().unwrap()) {
(Num(v1), Num(v2)) => {
if v1.fract() != 0.0 {
return Err(vm_error!(self, RuntimeErrorKind::WrongType, "Cannot perform bitwise AND on {}", v1))
@@ 130,7 155,7 @@ impl VM {
if v2.fract() != 0.0 {
return Err(vm_error!(self, RuntimeErrorKind::WrongType, "Cannot perform bitwise AND on {}", v2))
}
- self.stack.push(Num((v1 as u32 & v2 as u32) as f32))
+ self.units[self.unit_ptr].stack.push(Num((v1 as u32 & v2 as u32) as f32))
}
(Str(_v1), Str(_v2)) => {
return Err(vm_error!(self, RuntimeErrorKind::WrongType, "Cannot perform bitwise AND on strings"))
@@ 144,7 169,7 @@ impl VM {
}
}
0x09 => { // BITXOR
- match (self.stack.pop().unwrap(), self.stack.pop().unwrap()) {
+ match (self.units[self.unit_ptr].stack.pop().unwrap(), self.units[self.unit_ptr].stack.pop().unwrap()) {
(Num(v1), Num(v2)) => {
if v1.fract() != 0.0 {
return Err(vm_error!(self, RuntimeErrorKind::WrongType, "Cannot perform bitwise XOR on {}", v1))
@@ 152,7 177,7 @@ impl VM {
if v2.fract() != 0.0 {
return Err(vm_error!(self, RuntimeErrorKind::WrongType, "Cannot perform bitwise XOR on {}", v2))
}
- self.stack.push(Num((v1 as u32 ^ v2 as u32) as f32))
+ self.units[self.unit_ptr].stack.push(Num((v1 as u32 ^ v2 as u32) as f32))
}
(Str(_v1), Str(_v2)) => {
return Err(vm_error!(self, RuntimeErrorKind::WrongType, "Cannot perform bitwise XOR on strings"))
@@ 166,7 191,7 @@ impl VM {
}
}
0x0A => { // BITOR
- match (self.stack.pop().unwrap(), self.stack.pop().unwrap()) {
+ match (self.units[self.unit_ptr].stack.pop().unwrap(), self.units[self.unit_ptr].stack.pop().unwrap()) {
(Num(v1), Num(v2)) => {
if v1.fract() != 0.0 {
return Err(vm_error!(self, RuntimeErrorKind::WrongType, "Cannot perform bitwise OR on {}", v1))
@@ 174,7 199,7 @@ impl VM {
if v2.fract() != 0.0 {
return Err(vm_error!(self, RuntimeErrorKind::WrongType, "Cannot perform bitwise OR on {}", v2))
}
- self.stack.push(Num((v1 as u32 | v2 as u32) as f32))
+ self.units[self.unit_ptr].stack.push(Num((v1 as u32 | v2 as u32) as f32))
}
(Str(_v1), Str(_v2)) => {
return Err(vm_error!(self, RuntimeErrorKind::WrongType, "Cannot perform bitwise OR on strings"))
@@ 200,44 225,44 @@ impl VM {
// LE
0x10 => vm_boolean_binary!(self, <=),
// OR
- 0x11 => match (self.stack.pop().unwrap(), self.stack.pop().unwrap()) {
+ 0x11 => match (self.units[self.unit_ptr].stack.pop().unwrap(), self.units[self.unit_ptr].stack.pop().unwrap()) {
(Num(_v1), Num(_v2)) => {
return Err(vm_error!(self, RuntimeErrorKind::WrongType, "Cannot perform logical OR on numbers"))
}
(Str(_v1), Str(_v2)) => {
return Err(vm_error!(self, RuntimeErrorKind::WrongType, "Cannot perform logical OR on strings"))
},
- (Bool(v1), Bool(v2)) => self.stack.push(Bool(v1 || v2)),
+ (Bool(v1), Bool(v2)) => self.units[self.unit_ptr].stack.push(Bool(v1 || v2)),
(v1, v2) => {
return Err(vm_error!(self, RuntimeErrorKind::MismatchedTypes, "Mismatched types: {} and {}", v1.type_str(), v2.type_str()))
}
}
// AND
- 0x12 => match (self.stack.pop().unwrap(), self.stack.pop().unwrap()) {
+ 0x12 => match (self.units[self.unit_ptr].stack.pop().unwrap(), self.units[self.unit_ptr].stack.pop().unwrap()) {
(Num(_v1), Num(_v2)) => {
return Err(vm_error!(self, RuntimeErrorKind::WrongType, "Cannot perform logical AND on numbers"))
}
(Str(_v1), Str(_v2)) => {
return Err(vm_error!(self, RuntimeErrorKind::WrongType, "Cannot perform logical AND on strings"))
},
- (Bool(v1), Bool(v2)) => self.stack.push(Bool(v1 && v2)),
+ (Bool(v1), Bool(v2)) => self.units[self.unit_ptr].stack.push(Bool(v1 && v2)),
(v1, v2) => {
return Err(vm_error!(self, RuntimeErrorKind::MismatchedTypes, "Mismatched types: {} and {}", v1.type_str(), v2.type_str()))
}
}
// NOT
- 0x13 => match self.stack.pop().unwrap() {
+ 0x13 => match self.units[self.unit_ptr].stack.pop().unwrap() {
Num(_v1) => {
return Err(vm_error!(self, RuntimeErrorKind::WrongType, "Cannot perform logical NOT on numbers"))
}
Str(_v1) => {
return Err(vm_error!(self, RuntimeErrorKind::WrongType, "Cannot perform logical NOT on strings"))
}
- Bool(v1) => self.stack.push(Bool(!v1)),
+ Bool(v1) => self.units[self.unit_ptr].stack.push(Bool(!v1)),
}
// NEG
- 0x14 => match self.stack.pop().unwrap() {
- Num(v1) => self.stack.push(Num(-v1)),
+ 0x14 => match self.units[self.unit_ptr].stack.pop().unwrap() {
+ Num(v1) => self.units[self.unit_ptr].stack.push(Num(-v1)),
Str(_v1) => {
return Err(vm_error!(self, RuntimeErrorKind::WrongType, "Cannot negate strings"))
}
@@ 257,7 282,7 @@ impl VM {
}
// JNE
0x17 => {
- let condition = self.stack.pop().unwrap();
+ let condition = self.units[self.unit_ptr].stack.pop().unwrap();
if let Value::Bool(condition) = condition {
if !condition {
let loc = self.read_u16();
@@ 270,14 295,28 @@ impl VM {
}
}
+ // CALL
+ 0x18 => {
+ let num_args = self.read();
+ let unit_ptr = self.read();
+ self.call_stack.push((self.unit_ptr, self.ip));
+ for i in 0..num_args {
+
+ }
+ }
+ // RET
+ 0x19 => {
+
+ }
+
0xFD => { // POP
let times = self.read();
for _ in 0..times {
- self.stack.pop().expect(&format!("{}: Unable to pop stack", self.ip));
+ self.units[self.unit_ptr].stack.pop().expect(&format!("{}: Unable to pop stack", self.ip));
}
}
0xFE => { // PRINT
- let value = self.stack.pop().unwrap();
+ let value = self.units[self.unit_ptr].stack.pop().unwrap();
match value {
Num(v) => *output += &v.to_string(),
Str(v) => *output += &v,
@@ 291,20 330,20 @@ impl VM {
Ok(())
}
pub fn read(&mut self) -> u8 {
- let byte = self.chunk[self.ip];
+ let byte = self.units[self.unit_ptr].code[self.ip];
self.ip += 1;
byte
}
pub fn read_u16(&mut self) -> u16 {
- let byte_one = (self.chunk[self.ip] as u16) << 0x08;
+ let byte_one = (self.units[self.unit_ptr].code[self.ip] as u16) << 0x08;
self.ip += 1;
- let byte_two = self.chunk[self.ip] as u16;
+ let byte_two = self.units[self.unit_ptr].code[self.ip] as u16;
self.ip += 1;
byte_one | byte_two
}
pub fn find_line(&self) -> usize { // returns line # at ip
let mut line_ip = 0;
- for (line, rep) in self.lines.clone() {
+ for (line, rep) in self.units[self.unit_ptr].lines.clone() {
if line_ip + rep > self.ip {
return line;
}
M kabel/tmp.kab => kabel/tmp.kab +4 -2
@@ 1,2 1,4 @@
-var i = 0;
-function i() {}
+function i(j) {
+ j+1;
+}
+print i(2);