~starkingdoms/starkingdoms

efcd9f2c6bbfd7314ac0191b040fecb9ae93ee0a — ghostly_zsh 1 year, 4 months ago 2ff4364
get through variables test
M kabel/opcodes.txt => kabel/opcodes.txt +21 -20
@@ 1,28 1,29 @@
CONSTANT VAL    ; 0x00
VAR STACKPTR    ; 0x01
ASSIGN PTR      ; 0x02

ADD             ; 0x02
SUB             ; 0x03
MUL             ; 0x04
DIV             ; 0x05
MOD             ; 0x06
BITAND          ; 0x07
BITXOR          ; 0x08
BITOR           ; 0x09
EQ              ; 0x0A
NE              ; 0x0B
GR              ; 0x0C
GE              ; 0x0D
LS              ; 0x0E
LE              ; 0x0F
OR              ; 0x10
AND             ; 0x11
ADD             ; 0x03
SUB             ; 0x04
MUL             ; 0x05
DIV             ; 0x06
MOD             ; 0x07
BITAND          ; 0x08
BITXOR          ; 0x09
BITOR           ; 0x0a
EQ              ; 0x0B
NE              ; 0x0C
GR              ; 0x0D
GE              ; 0x0E
LS              ; 0x0F
LE              ; 0x10
OR              ; 0x11
AND             ; 0x12

NOT             ; 0x12
NEG             ; 0x13
NOT             ; 0x13
NEG             ; 0x14

JMP LOC         ; 0x14
IF_NE ELSE      ; 0x15
JMP LOC         ; 0x15
IF_NE ELSE      ; 0x16

POP             ; 0xFD
PRINT           ; 0xFE

M kabel/src/codegen.rs => kabel/src/codegen.rs +57 -14
@@ 1,16 1,16 @@
use std::collections::HashMap;

use crate::{ast::{ASTType, BinOp, Lit, Name, UnOp, AST}, codegen_binary, codegen_unary, extension::Extension, opcodes::OpCode, vm::{Value, VM}};

pub struct Codegen {
    pub vm: VM
    pub vm: VM,
    pub scopes: Vec<usize>, // number of variables declared in the scope
}

impl Codegen {
    pub fn new(text: String) -> Self {
        Codegen {
            vm: VM::new(Vec::new(), Vec::new(),
                Vec::new(), HashMap::new(), text),
                Vec::new(), text),
            scopes: vec![0],
        }
    }
    pub fn visit(&mut self, ast: AST) {


@@ 24,8 24,8 @@ impl Codegen {
            If(condition, block, else_expr) => {
                self.visit_if(*condition, *block, *else_expr);
            }
            Block(stmts) => {
                self.visit_block(stmts);
            Block(ref stmts) => {
                self.visit_block(&ast, stmts.clone());
            }
            Decl(ref name, ref expr) => {
                self.visit_decl(&ast, name.clone(), *expr.clone());


@@ 37,6 37,9 @@ impl Codegen {
            Print(ref expr) => {
                self.visit_print(&ast, *expr.clone());
            }
            Assign(ref name, ref expr) => {
                self.visit_assign(&ast, name.clone(), *expr.clone());
            }
            Binary(left, oper, right) => {
                self.visit_binary(*left, oper, *right);
            }


@@ 94,22 97,32 @@ impl Codegen {
                    self.visit(ast);
                    self.patch_jump(end_jmp_loc); // jmp to after else
                }
                _ => {}
                _ => { println!("unimplemented"); }
            }
        } else {
            self.patch_jump(start_jmp_loc);
        }
    }
    pub fn visit_block(&mut self, stmts: Vec<AST>) {
    pub fn visit_block(&mut self, ast: &AST, stmts: Vec<AST>) {
        self.scopes.push(0);
        for stmt in stmts {
            self.visit(stmt);
        }
        let variables = self.scopes.pop().expect("popped scope in block");
        for _ in 0..variables {
            self.vm.chunk.push(OpCode::POP.into());
            if self.vm.lines.last().unwrap().0 != ast.end_line {
                self.vm.lines.push((ast.end_line, 1));
            } else {
                self.vm.lines.last_mut().unwrap().1 += 1;
            }
        }
    }
    pub fn visit_decl(&mut self, ast: &AST, name: Name, expr: AST) {
    pub fn visit_decl(&mut self, ast: &AST, _name: Name, expr: AST) {
        self.visit(expr);
        #[allow(irrefutable_let_patterns)]
        if let Extension::Resolution(ptr) = ast.extensions[0] {
            self.vm.local.insert(name.name, ptr as u8);
        if let Extension::Resolution(_scope, _ptr) = ast.extensions[0] {
            *self.scopes.last_mut().expect("codegen scopes vec was empty") += 1;
        }
    }
    pub fn visit_expr_stmt(&mut self, ast: &AST, expr: AST) {


@@ 131,6 144,25 @@ impl Codegen {
            self.vm.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());
        #[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));
            } else {
                self.vm.lines.last_mut().unwrap().1 += 1;
            }
        }
        if self.vm.lines.last().unwrap().0 != ast.end_line {
            self.vm.lines.push((ast.end_line, 1));
        } else {
            self.vm.lines.last_mut().unwrap().1 += 1;
        }
    }
    pub fn visit_binary(&mut self, left: AST, oper: BinOp, right: AST) {
        use crate::ast::BinOp::*;
        codegen_binary!(self, left, right, oper, Add, ADD, Sub, SUB, Mul, MUL,


@@ 173,10 205,21 @@ impl Codegen {
                    self.vm.lines.last_mut().unwrap().1 += 2;
                }
            }
            Lit::Ident(name) => {
            Lit::Ident(_name) => {
                self.vm.chunk.push(OpCode::VAR.into());
                let slot = self.vm.local.get(&name).unwrap();
                self.vm.chunk.push(*slot);
                #[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));
                    } else {
                        self.vm.lines.last_mut().unwrap().1 += 2;
                    }
                }
            }
            _ => {}
        }

M kabel/src/debug.rs => kabel/src/debug.rs +46 -43
@@ 1,4 1,4 @@
use crate::{lexer::Token, ast::AST, push_output, vm::Value};
use crate::{ast::AST, lexer::Token, push_codegen, push_output, vm::{Value, VM}};

pub fn debug_token_array(tokens: Vec<Token>) -> String {
    let mut output = "".to_string();


@@ 201,69 201,72 @@ pub fn debug_ast(ast: AST, level: usize) -> String {
    output
}

pub fn debug_bytecode(code: &Vec<u8>) -> String {
pub fn debug_bytecode(vm: &VM) -> String {
    use crate::opcodes::OpCode::*;
    let mut ip = 0;
    //let mut ip = 0;
    let mut output = "".to_string();
    while ip < code.len() {
        match code[ip].into() {
    let mut vm = vm.clone();
    while vm.ip < vm.chunk.len() {
        // remove PRINT later
        push_codegen!(vm.chunk[vm.ip].into(), vm, output, ADD, SUB, MUL, DIV, MOD, BITAND,
            BITXOR, BITOR, EQ, NE, GR, GE, LS, LE, OR, AND, NOT, NEG, POP,
            PRINT, ERR);
        match vm.chunk[vm.ip].into() {
            LOAD => {
                output += &ip.to_string();
                output += &vm.ip.to_string();
                output += " ";
                output += &vm.find_line().to_string();
                output += " CONSTANT ";
                ip += 1;
                output += &code[ip].to_string();
                vm.ip += 1;
                output += &vm.chunk[vm.ip].to_string();
                output += "\n";
            }
            VAR => {
                output += &ip.to_string();
                output += &vm.ip.to_string();
                output += " ";
                output += &vm.find_line().to_string();
                output += " VAR ";
                ip += 1;
                output += &code[ip].to_string();
                vm.ip += 1;
                output += &vm.chunk[vm.ip].to_string();
                output += "\n";
            }
            ADD => { output += &ip.to_string(); output += " ADD\n" }
            SUB => { output += &ip.to_string(); output += " SUB\n" }
            MUL => { output += &ip.to_string(); output += " MUL\n" }
            DIV => { output += &ip.to_string(); output += " DIV\n" }
            MOD => { output += &ip.to_string(); output += " MOD\n" }
            BITAND => { output += &ip.to_string(); output += " BITAND\n" }
            BITXOR => { output += &ip.to_string(); output += " BITXOR\n" }
            BITOR => { output += &ip.to_string(); output += " BITOR\n" }
            EQ => { output += &ip.to_string(); output += " EQ\n" }
            NE => { output += &ip.to_string(); output += " NE\n" }
            GR => { output += &ip.to_string(); output += " GR\n" }
            GE => { output += &ip.to_string(); output += " GE\n" }
            LS => { output += &ip.to_string(); output += " LS\n" }
            LE => { output += &ip.to_string(); output += " LE\n" }
            OR => { output += &ip.to_string(); output += " OR\n" }
            AND => { output += &ip.to_string(); output += " AND\n" }
            NOT => { output += &ip.to_string(); output += " NOT\n" }
            NEG => { output += &ip.to_string(); output += " NEG\n" }
            ASSIGN => { 
                output += &vm.ip.to_string();
                output += " ";
                output += &vm.find_line().to_string();
                output += " ASSIGN ";
                vm.ip += 1;
                output += &vm.chunk[vm.ip].to_string();
                output += "\n";
            }

            JMP => {
                output += &ip.to_string();
                output += &vm.ip.to_string();
                output += " ";
                output += &vm.find_line().to_string();
                output += " JMP ";
                ip += 1;
                let byte_one = (code[ip] as u16) << 8;
                ip += 1;
                let byte_two = code[ip] as u16;
                vm.ip += 1;
                let byte_one = (vm.chunk[vm.ip] as u16) << 8;
                vm.ip += 1;
                let byte_two = vm.chunk[vm.ip] as u16;
                output += &(byte_one | byte_two).to_string();
                output += "\n";
            }
            IF_NE => {
                output += &ip.to_string();
                output += &vm.ip.to_string();
                output += " ";
                output += &vm.find_line().to_string();
                output += " IF_NE ";
                ip += 1;
                let byte_one = (code[ip] as u16) << 8;
                ip += 1;
                let byte_two = code[ip] as u16;
                vm.ip += 1;
                let byte_one = (vm.chunk[vm.ip] as u16) << 8;
                vm.ip += 1;
                let byte_two = vm.chunk[vm.ip] as u16;
                output += &(byte_one | byte_two).to_string();
                output += "\n";
            }
            POP => { output += &ip.to_string(); output += " POP\n" }
            PRINT => { output += &ip.to_string(); output += " PRINT\n" }
            ERR => output += "ERR\n",
            _ => {}
        }
        ip += 1;
        vm.ip += 1;
    }
    output
}

M kabel/src/extension.rs => kabel/src/extension.rs +1 -1
@@ 1,4 1,4 @@
#[derive(Debug, Clone)]
pub enum Extension {
    Resolution(usize), // pointer to local table
    Resolution(usize, usize), // scope, pointer to local table
}

M kabel/src/macros.rs => kabel/src/macros.rs +16 -0
@@ 206,6 206,22 @@ macro_rules! codegen_unary {
        }
    };
}
#[macro_export]
macro_rules! push_codegen {
    ($match_to:expr, $vm:expr, $output:expr, $( $code:tt ), *) => {
        match $match_to {
            $( $code => {
                $output += &$vm.ip.to_string();
                $output += " ";
                $output += &$vm.find_line().to_string();
                $output += " ";
                $output += stringify!($code);
                $output += "\n";
            } )*
            _ => {}
        }
    };
}

#[macro_export]
macro_rules! vm_boolean_binary {

M kabel/src/main.rs => kabel/src/main.rs +14 -12
@@ 5,20 5,18 @@ use std::{env, fs};
use kabel::{debug::{debug_ast, debug_bytecode, debug_stack, debug_token_array}, run_codegen, run_lexer, run_parser, run_semantic_analysis};

fn main() {
    let args: Vec<String> = env::args().collect();
    /*let args: Vec<String> = env::args().collect();
    let program =
        fs::read_to_string(args[1].clone()).unwrap();
        fs::read_to_string(args[1].clone()).unwrap();*/

    /*let program =
    let program =
"var a = 2;
var b = 3;
print a+b;
{
    var b = 7;
    var c = 4;
    print c;
    var a = 3;
    print a;
}
".to_string();*/
print a;
".to_string();

    let mut output = "".to_string();



@@ 45,7 43,7 @@ print a+b;
        println!("{}", output);
        return;
    }
    output += &debug_ast(ast.clone(), 0);
    //output += &debug_ast(ast.clone(), 0);
    output += "\n\n";
    //output += &format!("{:#?}", ast);
    let (ast, analyzer) = run_semantic_analysis(program.to_string(), ast.clone());


@@ 57,12 55,16 @@ print a+b;
        println!("{}", output);
        return;
    }
    //output += &format!("{:#?}", ast);
    output += &debug_ast(ast.clone(), 0);
    output += "\n";

    let codegen = run_codegen(program.to_string(), ast);

    let mut vm = codegen.vm;
    output += &debug_bytecode(&vm.chunk);
    output += &debug_bytecode(&vm);
    output += "\n";
    //output += &format!("{:?}", codegen.local);

    output += "\n";
    match vm.run(&mut output) {
        Ok(()) => {}

M kabel/src/name_resolution.rs => kabel/src/name_resolution.rs +31 -6
@@ 5,7 5,8 @@ use crate::{ast::{ASTType, AST}, ast_from_ast, collect_lines, error::{ErrorKind,
pub struct Resolver {
    text: Vec<String>,
    symbol_table: Vec<HashMap<String, (Symbol, usize)>>, // (Symbol, reference to locals)
    pub locals: Vec<usize>, // reference to stack
    pub locals: Vec<usize>, // scope
    pub scope: usize,
    pub errors: Vec<KabelError>,
}



@@ 15,6 16,7 @@ impl Resolver {
            text: text.lines().collect::<Vec<&str>>().iter().map(|s| s.to_string()).collect(),
            symbol_table: vec![HashMap::new()],
            locals: Vec::new(),
            scope: 0,
            errors: Vec::new(),
        }
    }


@@ 89,20 91,34 @@ impl Resolver {
            }
            Block(stmts) => {
                self.symbol_table.push(HashMap::new());
                self.scope += 1;
                let mut n_stmts = Vec::new();
                for stmt in stmts {
                    n_stmts.push(self.visit(stmt));
                }
                /*for (index, scope) in self.locals.clone().iter().enumerate() {
                    if self.scope == *scope {
                        self.locals.remove(index);
                    }
                }*/
                while let Some(scope) = self.locals.last() {
                    if self.scope == *scope {
                        self.locals.pop();
                    } else {
                        break;
                    }
                }
                self.scope -= 1;
                self.symbol_table.pop();
                ast_from_ast!(Block(n_stmts), ast, ast)
            }
            Decl(name, expr) => {
                let expr = self.visit(*expr);
                self.locals.push(0);
                self.locals.push(self.scope);
                self.symbol_table.last_mut().unwrap().insert(name.name.clone(), (Symbol::Var, self.locals.len()-1));
                AST {
                    ast_type: Decl(name, Box::new(expr)),
                    extensions: vec![Extension::Resolution(self.locals.len()-1)],
                    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,


@@ 120,10 136,18 @@ impl Resolver {
            }
            Assign(name, expr) => {
                let expr = self.visit(*expr);
                if !self.symbol_table.last().unwrap().contains_key(&name.name) {
                let resolution = self.resolve_var(&name.name);
                if !resolution.0 {
                    self.errors.push(out_of_scope_var!(self, "Variable \"{}\" not in scope", name, ast));
                }
                ast_from_ast!(Assign(name, Box::new(expr)), ast, ast)
                AST {
                    ast_type: Assign(name, Box::new(expr)),
                    extensions: vec![Extension::Resolution(self.scope, resolution.1)],
                    start_line: ast.start_line,
                    end_line: ast.end_line,
                    start_column: ast.start_column,
                    end_column: ast.end_column,
                }
            }
            Ternary(condition, true_expr, false_expr) => {
                let condition = self.visit(*condition);


@@ 155,7 179,7 @@ impl Resolver {
                        } else {
                            return AST {
                                ast_type: Lit(lit),
                                extensions: vec![Extension::Resolution(resolution.1)],
                                extensions: vec![Extension::Resolution(self.scope, resolution.1)],
                                start_line: ast.start_line,
                                end_line: ast.end_line,
                                start_column: ast.start_column,


@@ 224,6 248,7 @@ impl Resolver {
    }
}

#[derive(Debug, Clone, Copy)]
pub enum Symbol {
    Var,
    Function(usize),

M kabel/src/opcodes.rs => kabel/src/opcodes.rs +44 -40
@@ 1,8 1,10 @@
#![allow(non_camel_case_types)]

#[derive(Debug)]
pub enum OpCode {
    LOAD,
    VAR,
    ASSIGN,

    ADD,
    SUB,


@@ 38,29 40,30 @@ impl From<OpCode> for u8 {
        match value {
            LOAD    => 0x00,
            VAR     => 0x01,
            ASSIGN  => 0x02,

            ADD     => 0x02,
            SUB     => 0x03,
            MUL     => 0x04,
            DIV     => 0x05,
            MOD     => 0x06,
            BITAND  => 0x07,
            BITXOR  => 0x08,
            BITOR   => 0x09,
            EQ      => 0x0A,
            NE      => 0x0B,
            GR      => 0x0C,
            GE      => 0x0D,
            LS      => 0x0E,
            LE      => 0x0F,
            OR      => 0x10,
            AND     => 0x11,
            ADD     => 0x03,
            SUB     => 0x04,
            MUL     => 0x05,
            DIV     => 0x06,
            MOD     => 0x07,
            BITAND  => 0x08,
            BITXOR  => 0x09,
            BITOR   => 0x0a,
            EQ      => 0x0B,
            NE      => 0x0C,
            GR      => 0x0D,
            GE      => 0x0E,
            LS      => 0x0F,
            LE      => 0x10,
            OR      => 0x11,
            AND     => 0x12,

            NOT     => 0x12,
            NEG     => 0x13,
            NOT     => 0x13,
            NEG     => 0x14,

            JMP     => 0x14,
            IF_NE   => 0x15,
            JMP     => 0x15,
            IF_NE   => 0x16,

            POP     => 0xFD,
            PRINT   => 0xFE,


@@ 74,29 77,30 @@ impl From<u8> for OpCode {
        match value {
            0x00 => LOAD,
            0x01 => VAR,
            0x02 => ASSIGN,

            0x02 => ADD,
            0x03 => SUB,
            0x04 => MUL,
            0x05 => DIV,
            0x06 => MOD,
            0x07 => BITAND,
            0x08 => BITXOR,
            0x09 => BITOR,
            0x0A => EQ,
            0x0B => NE,
            0x0C => GR,
            0x0D => GE,
            0x0E => LS,
            0x0F => LE,
            0x10 => OR,
            0x11 => AND,
            0x03 => ADD,
            0x04 => SUB,
            0x05 => MUL,
            0x06 => DIV,
            0x07 => MOD,
            0x08 => BITAND,
            0x09 => BITXOR,
            0x0a => BITOR,
            0x0B => EQ,
            0x0C => NE,
            0x0D => GR,
            0x0E => GE,
            0x0F => LS,
            0x10 => LE,
            0x11 => OR,
            0x12 => AND,

            0x12 => NOT,
            0x13 => NEG,
            0x13 => NOT,
            0x14 => NEG,

            0x14 => JMP,
            0x15 => IF_NE,
            0x15 => JMP,
            0x16 => IF_NE,

            0xFD => POP,
            0xFE => PRINT,

M kabel/src/vm.rs => kabel/src/vm.rs +33 -28
@@ 1,34 1,31 @@
use std::collections::HashMap;

use crate::{mismatched_types, runtime_error::KabelRuntimeError, vm_boolean_binary, wrong_type};
use crate::{mismatched_types, opcodes::OpCode, runtime_error::KabelRuntimeError, vm_boolean_binary, wrong_type};

#[derive(Clone)]
pub struct VM {
    ip: usize,
    pub ip: usize,
    pub chunk: Vec<u8>,
    pub stack: Vec<Value>,
    pub pool: Vec<Value>,
    pub local: HashMap<String, u8>, // (name, stack pointer)
    pub lines: Vec<(usize, usize)>, // line #, repeats number of instructions
    text: Vec<String>
}

impl VM {
    pub fn new(bytecode: Vec<u8>, lines: Vec<(usize, usize)>, pool: Vec<Value>,
        local: HashMap<String, u8>, text: String) -> Self {
        println!("{:#?}", text);
        text: String) -> Self {
        Self {
            ip: 0,
            chunk: bytecode,
            stack: Vec::new(),
            pool,
            local,
            lines,
            text: text.lines().map(|s| s.to_string()).collect::<Vec<String>>(),
        }
    }
    pub fn run(&mut self, output: &mut String) -> Result<(), KabelRuntimeError> {
        use Value::*;
        println!("{:#?}", self.text);
        while self.ip < self.chunk.len() {
            match self.read() {
                0x00 => { // LOAD


@@ 39,7 36,14 @@ impl VM {
                    let ptr = self.read() as usize;
                    self.stack.push(self.stack[ptr].clone());
                }
                0x02 => { // ADD
                // ASSIGN
                0x02 => {
                    let value = self.stack.pop().unwrap();
                    let ptr = self.read();
                    self.stack[ptr as usize] = value.clone();
                    self.stack.push(value);
                }
                0x03 => { // ADD
                    match (self.stack.pop().unwrap(), self.stack.pop().unwrap()) {
                        (Num(v1), Num(v2)) => self.stack.push(Num(v1 + v2)),
                        (Str(v1), Str(v2)) => {


@@ 53,7 57,7 @@ impl VM {
                        }
                    }
                }
                0x03 => { // SUB
                0x04 => { // SUB
                    match (self.stack.pop().unwrap(), self.stack.pop().unwrap()) {
                        (Num(v1), Num(v2)) => self.stack.push(Num(v1 - v2)),
                        (Str(_v1), Str(_v2)) => {


@@ 67,7 71,7 @@ impl VM {
                        }
                    }
                }
                0x04 => { // MUL
                0x05 => { // MUL
                    match (self.stack.pop().unwrap(), self.stack.pop().unwrap()) {
                        (Num(v1), Num(v2)) => self.stack.push(Num(v1 * v2)),
                        (Str(v1), Num(v2)) => {


@@ 88,7 92,7 @@ impl VM {
                        }
                    }
                }
                0x05 => { // DIV
                0x06 => { // DIV
                    match (self.stack.pop().unwrap(), self.stack.pop().unwrap()) {
                        (Num(v1), Num(v2)) => self.stack.push(Num(v1 / v2)),
                        (Str(_v1), Str(_v2)) => {


@@ 102,7 106,7 @@ impl VM {
                        }
                    }
                }
                0x06 => { // MOD
                0x07 => { // MOD
                    match (self.stack.pop().unwrap(), self.stack.pop().unwrap()) {
                        (Num(v1), Num(v2)) => self.stack.push(Num(v1 % v2)),
                        (Str(_v1), Str(_v2)) => {


@@ 116,7 120,7 @@ impl VM {
                        }
                    }
                }
                0x07 => { // BITAND
                0x08 => { // BITAND
                    match (self.stack.pop().unwrap(), self.stack.pop().unwrap()) {
                        (Num(v1), Num(v2)) => {
                            if v1.fract() != 0.0 {


@@ 138,7 142,7 @@ impl VM {
                        }
                    }
                }
                0x08 => { // BITXOR
                0x09 => { // BITXOR
                    match (self.stack.pop().unwrap(), self.stack.pop().unwrap()) {
                        (Num(v1), Num(v2)) => {
                            if v1.fract() != 0.0 {


@@ 160,7 164,7 @@ impl VM {
                        }
                    }
                }
                0x09 => { // BITOR
                0x0A => { // BITOR
                    match (self.stack.pop().unwrap(), self.stack.pop().unwrap()) {
                        (Num(v1), Num(v2)) => {
                            if v1.fract() != 0.0 {


@@ 183,19 187,19 @@ impl VM {
                    }
                }
                // EQ
                0x0a => vm_boolean_binary!(self, ==),
                0x0b => vm_boolean_binary!(self, ==),
                // NE
                0x0B => vm_boolean_binary!(self, !=),
                0x0C => vm_boolean_binary!(self, !=),
                // GR
                0x0C => vm_boolean_binary!(self, >),
                0x0D => vm_boolean_binary!(self, >),
                // GE
                0x0D => vm_boolean_binary!(self, >=),
                0x0E => vm_boolean_binary!(self, >=),
                // LS
                0x0E => vm_boolean_binary!(self, <),
                0x0F => vm_boolean_binary!(self, <),
                // LE
                0x0F => vm_boolean_binary!(self, <=),
                0x10 => vm_boolean_binary!(self, <=),
                // OR
                0x10 => match (self.stack.pop().unwrap(), self.stack.pop().unwrap()) {
                0x11 => match (self.stack.pop().unwrap(), self.stack.pop().unwrap()) {
                    (Num(_v1), Num(_v2)) => {
                        return Err(wrong_type!(self, "Cannot perform logical OR on numbers"))
                    }


@@ 208,7 212,7 @@ impl VM {
                    }
                }
                // AND
                0x11 => match (self.stack.pop().unwrap(), self.stack.pop().unwrap()) {
                0x12 => match (self.stack.pop().unwrap(), self.stack.pop().unwrap()) {
                    (Num(_v1), Num(_v2)) => {
                        return Err(wrong_type!(self, "Cannot perform logical AND on numbers"))
                    }


@@ 221,7 225,7 @@ impl VM {
                    }
                }
                // NOT
                0x12 => match self.stack.pop().unwrap() {
                0x13 => match self.stack.pop().unwrap() {
                    Num(_v1) => {
                        return Err(wrong_type!(self, "Cannot perform logical NOT on numbers"))
                    }


@@ 231,7 235,7 @@ impl VM {
                    Bool(v1) => self.stack.push(Bool(!v1)),
                }
                // NEG
                0x13 => match self.stack.pop().unwrap() {
                0x14 => match self.stack.pop().unwrap() {
                    Num(v1) => self.stack.push(Num(-v1)),
                    Str(_v1) => {
                        return Err(wrong_type!(self, "Cannot negate strings"))


@@ 241,12 245,12 @@ impl VM {
                    }
                }
                // JMP
                0x14 => {
                0x15 => {
                    let loc = self.read_u16();
                    self.ip += loc as usize;
                }
                // IF_NE
                0x15 => {
                0x16 => {
                    let condition = self.stack.pop().unwrap();
                    if let Value::Bool(condition) = condition {
                        if !condition {


@@ 289,7 293,7 @@ impl VM {
        self.ip += 1;
        byte_one | byte_two
    }
    pub fn find_line(&mut self) -> usize { // returns line # at ip
    pub fn find_line(&self) -> usize { // returns line # at ip
        let mut line_ip = 0;
        for (line, rep) in self.lines.clone() {
            if line_ip + rep > self.ip {


@@ 297,6 301,7 @@ impl VM {
            }
            line_ip += rep;
        }
        println!("{} {}", line_ip, self.ip);
        panic!("Something went wrong in finding line for error")
    }
}

A kabel/test/runtime/variable.kab => kabel/test/runtime/variable.kab +30 -0
@@ 0,0 1,30 @@
var x = 1;
print x + 2; // 3

{
    x = 3;
    print x; // 3
}
print x; // 3

var y = 0;
print y; // 0
print x; // 3

{
    var y = 5;
    print y + 2; // 7
}
print y; // 0

if(x == 3) {
    var y = 6;
} else {
    var y = 5;
    print y; // not run
}
print y; // 0
if(y != 1) {
    y = 1;
}
print y; // 1

A kabel/test/runtime/variable.out => kabel/test/runtime/variable.out +9 -0
@@ 0,0 1,9 @@
3
3
3
0
3
7
0
0
1