~starkingdoms/starkingdoms

364d4a85a2f9f86d7c719da1b2ee51ca7244e1df — ghostly_zsh 1 year, 3 months ago aee322a
repo synchronization between computers
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);