From efcd9f2c6bbfd7314ac0191b040fecb9ae93ee0a Mon Sep 17 00:00:00 2001 From: ghostly_zsh Date: Wed, 14 Aug 2024 01:22:13 -0500 Subject: [PATCH] get through variables test --- kabel/opcodes.txt | 41 +++++++-------- kabel/src/codegen.rs | 71 ++++++++++++++++++++------ kabel/src/debug.rs | 89 +++++++++++++++++---------------- kabel/src/extension.rs | 2 +- kabel/src/macros.rs | 16 ++++++ kabel/src/main.rs | 26 +++++----- kabel/src/name_resolution.rs | 37 +++++++++++--- kabel/src/opcodes.rs | 84 ++++++++++++++++--------------- kabel/src/vm.rs | 61 +++++++++++----------- kabel/test/runtime/variable.kab | 30 +++++++++++ kabel/test/runtime/variable.out | 9 ++++ 11 files changed, 302 insertions(+), 164 deletions(-) create mode 100644 kabel/test/runtime/variable.kab create mode 100644 kabel/test/runtime/variable.out diff --git a/kabel/opcodes.txt b/kabel/opcodes.txt index ca1359c340707d8f8db2b26f5a65d81e6c6aa604..52e942cfe82d198ede36d51937d1c06fce6aa102 100644 --- a/kabel/opcodes.txt +++ b/kabel/opcodes.txt @@ -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 diff --git a/kabel/src/codegen.rs b/kabel/src/codegen.rs index 47a1f39ff0d045f21cf4c1a85c564aa90e0d6ba8..b8241b4095f9057a0ed988d4e91f93a5a1ce35cf 100644 --- a/kabel/src/codegen.rs +++ b/kabel/src/codegen.rs @@ -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, // 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) { + pub fn visit_block(&mut self, ast: &AST, stmts: Vec) { + 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; + } + } } _ => {} } diff --git a/kabel/src/debug.rs b/kabel/src/debug.rs index b53d00bbf9c1d4b2ae886f789108545b1fd83cd0..57edd16bfb8649f6771dcaad1b2cc021471f783a 100644 --- a/kabel/src/debug.rs +++ b/kabel/src/debug.rs @@ -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) -> 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) -> 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 } diff --git a/kabel/src/extension.rs b/kabel/src/extension.rs index 34fc51f77aa2c655fbf185fb0013c2b9f60872c9..6efbee9033bc4d537401c98cd0bba86202f7588f 100644 --- a/kabel/src/extension.rs +++ b/kabel/src/extension.rs @@ -1,4 +1,4 @@ #[derive(Debug, Clone)] pub enum Extension { - Resolution(usize), // pointer to local table + Resolution(usize, usize), // scope, pointer to local table } diff --git a/kabel/src/macros.rs b/kabel/src/macros.rs index 410560a5d098044e96fce6fefe3ba0cbb0ef7940..16313977013cc14304e052bb7e9e3168ee11d381 100644 --- a/kabel/src/macros.rs +++ b/kabel/src/macros.rs @@ -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 { diff --git a/kabel/src/main.rs b/kabel/src/main.rs index b8200ad9d0a23f9be2302791a18d01c433658976..7505556bc1399d606af411311682ca4a6073e940 100644 --- a/kabel/src/main.rs +++ b/kabel/src/main.rs @@ -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 = env::args().collect(); + /*let args: Vec = 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(()) => {} diff --git a/kabel/src/name_resolution.rs b/kabel/src/name_resolution.rs index b6a9355824a266caacfefdad08afcc7f37beef4a..ca90f0b537a4ef1888782e3ac575e5ded5291f93 100644 --- a/kabel/src/name_resolution.rs +++ b/kabel/src/name_resolution.rs @@ -5,7 +5,8 @@ use crate::{ast::{ASTType, AST}, ast_from_ast, collect_lines, error::{ErrorKind, pub struct Resolver { text: Vec, symbol_table: Vec>, // (Symbol, reference to locals) - pub locals: Vec, // reference to stack + pub locals: Vec, // scope + pub scope: usize, pub errors: Vec, } @@ -15,6 +16,7 @@ impl Resolver { text: text.lines().collect::>().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), diff --git a/kabel/src/opcodes.rs b/kabel/src/opcodes.rs index a2a1018782edd510f1925a67fb0fc88b81afc5b1..1453d362c52d7866a734247634722de0d5f081a3 100644 --- a/kabel/src/opcodes.rs +++ b/kabel/src/opcodes.rs @@ -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 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 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, diff --git a/kabel/src/vm.rs b/kabel/src/vm.rs index 56f1d92df6b07283ff3274388cf39ac65dc8c694..ef54c9a14b224af49c628d449fb8239e46d382ea 100644 --- a/kabel/src/vm.rs +++ b/kabel/src/vm.rs @@ -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, pub stack: Vec, pub pool: Vec, - pub local: HashMap, // (name, stack pointer) pub lines: Vec<(usize, usize)>, // line #, repeats number of instructions text: Vec } impl VM { pub fn new(bytecode: Vec, lines: Vec<(usize, usize)>, pool: Vec, - local: HashMap, 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::>(), } } 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") } } diff --git a/kabel/test/runtime/variable.kab b/kabel/test/runtime/variable.kab new file mode 100644 index 0000000000000000000000000000000000000000..24d77b5002ad31f8815ec93a460ed45f5179a2fd --- /dev/null +++ b/kabel/test/runtime/variable.kab @@ -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 diff --git a/kabel/test/runtime/variable.out b/kabel/test/runtime/variable.out new file mode 100644 index 0000000000000000000000000000000000000000..719c5d1f12e8718c5920e9e9f863f7d4f3de7c34 --- /dev/null +++ b/kabel/test/runtime/variable.out @@ -0,0 +1,9 @@ +3 +3 +3 +0 +3 +7 +0 +0 +1