From 048af52933dbe34e211c90d9d511c0d10bbbe19e Mon Sep 17 00:00:00 2001 From: ghostly_zsh Date: Sat, 21 Sep 2024 01:09:43 -0500 Subject: [PATCH] remove variables from stack, maybe other things pushed too --- kabel/opcodes.txt | 57 ++++++++++--------- kabel/src/codegen.rs | 46 ++++++++++----- kabel/src/debug.rs | 20 ++++++- kabel/src/opcodes.rs | 132 ++++++++++++++++++++++--------------------- kabel/src/vm.rs | 111 ++++++++++++++++++++++-------------- kabel/tmp.kab | 6 +- 6 files changed, 223 insertions(+), 149 deletions(-) diff --git a/kabel/opcodes.txt b/kabel/opcodes.txt index a95da8e84be7eeda43eabe9cce2eb0adffbb2f97..2fe9fb52c4bab60c84ce1822750cd3bb1915bd46 100644 --- a/kabel/opcodes.txt +++ b/kabel/opcodes.txt @@ -1,32 +1,37 @@ LOAD VAL ; 0x00 VAR STACKPTR ; 0x01 -ASSIGN PTR ; 0x02 +ASN PTR ; 0x02 +ASNARR ; 0x03 +DECL ; 0x04 -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 ; 0x13 -NEG ; 0x14 -JMP LOC ; 0x15 -JMP_UP LOC ; 0x16 -JNE ELSE ; 0x17 -CALL ARITY ; 0x18 -RET ; 0x19 -LIST LEN ; 0x1A -SCR ; 0x1B +ADD ; 0x05 +SUB ; 0x06 +MUL ; 0x07 +DIV ; 0x08 +MOD ; 0x09 +BITAND ; 0x0a +BITXOR ; 0x0b +BITOR ; 0x0c +EQ ; 0x0D +NE ; 0x0E +GR ; 0x0F +GE ; 0x10 +LS ; 0x11 +LE ; 0x12 +OR ; 0x13 +AND ; 0x14 +NOT ; 0x15 +NEG ; 0x16 + +JMP LOC ; 0x17 +JMP_UP LOC ; 0x18 +JNE ELSE ; 0x19 + +CALL ARITY ; 0x1A +RET ; 0x1B + +LIST LEN ; 0x1C +SCR ; 0x1D POP COUNT ; 0xFD PRINT ; 0xFE diff --git a/kabel/src/codegen.rs b/kabel/src/codegen.rs index 449ce001aae51b57f5782579b9ff352849dde2d2..464b1fd2053d78ab5accd79a477875b11aa2bd33 100644 --- a/kabel/src/codegen.rs +++ b/kabel/src/codegen.rs @@ -1,4 +1,4 @@ -use crate::{ast::{ASTType, BinOp, LhsAssign, Lit, Name, UnOp, AST}, codegen_binary, codegen_unary, extension::Extension, opcodes::OpCode, vm::{Function, Unit, Value, VM}}; +use crate::{ast::{ASTType, BinOp, LhsAssign, LhsAssignType, Lit, Name, UnOp, AST}, codegen_binary, codegen_unary, extension::Extension, opcodes::OpCode, vm::{Function, Unit, Value, VM}}; pub struct Codegen { pub vm: VM, @@ -407,6 +407,12 @@ impl Codegen { } pub fn visit_decl(&mut self, ast: &AST, _name: Name, expr: AST) { self.visit(expr); + self.vm.units[self.vm.unit_ptr].code.push(OpCode::DECL.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.units[self.vm.unit_ptr].lines.last_mut().unwrap().1 += 1; + } #[allow(irrefutable_let_patterns)] if let Extension::Resolution(_scope, _ptr) = ast.extensions[0] { self.scopes.last_mut().expect("codegen scopes vec was empty").1 += 1; @@ -432,23 +438,33 @@ impl Codegen { self.vm.units[self.vm.unit_ptr].lines.last_mut().unwrap().1 += 1; } } - pub fn visit_assign(&mut self, ast: &AST, _name: LhsAssign, expr: AST) { + pub fn visit_assign(&mut self, ast: &AST, name: LhsAssign, expr: AST) { self.visit(expr); // pop stack to get value. then find variable in stack. set variable to value. - 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.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.units[self.vm.unit_ptr].lines.last_mut().unwrap().1 += 1; + match name.kind { + LhsAssignType::Ident(_) => { + #[allow(irrefutable_let_patterns)] + if let Extension::Resolution(_scope, ptr) = ast.extensions[0] { + self.vm.units[self.vm.unit_ptr].code.push(OpCode::ASN.into()); + 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, 2)); + } else { + self.vm.units[self.vm.unit_ptr].lines.last_mut().unwrap().1 += 2; + } + } + } + LhsAssignType::Subscript(name, index) => { + self.visit(*index); + self.visit(*name); + self.vm.units[self.vm.unit_ptr].code.push(OpCode::ASNARR.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.units[self.vm.unit_ptr].lines.last_mut().unwrap().1 += 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.units[self.vm.unit_ptr].lines.last_mut().unwrap().1 += 1; } } pub fn visit_anonymous(&mut self, params: Vec, block: AST) { diff --git a/kabel/src/debug.rs b/kabel/src/debug.rs index f48fe0e4d145ff4ea1aa80ef524da3f8b01f4155..4ac58000abfb4047541d8a50a5947ad00966d31c 100644 --- a/kabel/src/debug.rs +++ b/kabel/src/debug.rs @@ -247,7 +247,7 @@ pub fn debug_bytecode(vm: &VM) -> String { output += &vm.ip.to_string(); output += " "; output += &vm.find_line().to_string(); - output += " CONSTANT "; + output += " LOAD "; vm.ip += 1; output += &vm.units[vm.unit_ptr].code[vm.ip].to_string(); output += "\n"; @@ -261,15 +261,29 @@ pub fn debug_bytecode(vm: &VM) -> String { output += &vm.units[vm.unit_ptr].code[vm.ip].to_string(); output += "\n"; } - ASSIGN => { + ASN => { output += &vm.ip.to_string(); output += " "; output += &vm.find_line().to_string(); - output += " ASSIGN "; + output += " ASN "; vm.ip += 1; output += &vm.units[vm.unit_ptr].code[vm.ip].to_string(); output += "\n"; } + ASNARR => { + output += &vm.ip.to_string(); + output += " "; + output += &vm.find_line().to_string(); + output += " ASNARR"; + output += "\n"; + } + DECL => { + output += &vm.ip.to_string(); + output += " "; + output += &vm.find_line().to_string(); + output += " DECL"; + output += "\n"; + } JMP => { output += &vm.ip.to_string(); diff --git a/kabel/src/opcodes.rs b/kabel/src/opcodes.rs index 95600255f9b3a744ec196556886ccd8883aaccca..be9945f9a37f69c77992bb7ae6b415faaa80c9c2 100644 --- a/kabel/src/opcodes.rs +++ b/kabel/src/opcodes.rs @@ -4,7 +4,9 @@ pub enum OpCode { LOAD, VAR, - ASSIGN, + ASN, + ASNARR, + DECL, ADD, SUB, @@ -47,37 +49,39 @@ impl From for u8 { match value { LOAD => 0x00, VAR => 0x01, - 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 => 0x12, - - NOT => 0x13, - NEG => 0x14, - - JMP => 0x15, - JMP_UP => 0x16, - JNE => 0x17, - - CALL => 0x18, - RET => 0x19, - - LIST => 0x1A, - SCR => 0x1B, + ASN => 0x02, + ASNARR => 0x03, + DECL => 0x04, + + ADD => 0x05, + SUB => 0x06, + MUL => 0x07, + DIV => 0x08, + MOD => 0x09, + BITAND => 0x0a, + BITXOR => 0x0b, + BITOR => 0x0c, + EQ => 0x0D, + NE => 0x0E, + GR => 0x0F, + GE => 0x10, + LS => 0x11, + LE => 0x12, + OR => 0x13, + AND => 0x14, + + NOT => 0x15, + NEG => 0x16, + + JMP => 0x17, + JMP_UP => 0x18, + JNE => 0x19, + + CALL => 0x1A, + RET => 0x1B, + + LIST => 0x1C, + SCR => 0x1D, POP => 0xFD, PRINT => 0xFE, @@ -90,37 +94,39 @@ impl From for OpCode { use OpCode::*; match value { 0x00 => LOAD, 0x01 => VAR, - 0x02 => ASSIGN, - - 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, - - 0x13 => NOT, - 0x14 => NEG, - - 0x15 => JMP, - 0x16 => JMP_UP, - 0x17 => JNE, - - 0x18 => CALL, - 0x19 => RET, - - 0x1A => LIST, - 0x1B => SCR, + 0x02 => ASN, + 0x03 => ASNARR, + 0x04 => DECL, + + 0x05 => ADD, + 0x06 => SUB, + 0x07 => MUL, + 0x08 => DIV, + 0x09 => MOD, + 0x0A => BITAND, + 0x0b => BITXOR, + 0x0c => BITOR, + 0x0D => EQ, + 0x0E => NE, + 0x0F => GR, + 0x10 => GE, + 0x11 => LS, + 0x12 => LE, + 0x13 => OR, + 0x14 => AND, + + 0x15 => NOT, + 0x16 => NEG, + + 0x17 => JMP, + 0x18 => JMP_UP, + 0x19 => JNE, + + 0x1A => CALL, + 0x1b => RET, + + 0x1C => LIST, + 0x1D => SCR, 0xFD => POP, 0xFE => PRINT, diff --git a/kabel/src/vm.rs b/kabel/src/vm.rs index 6ddcd38d4b1d1a9a1fa3d83b6fe22c725fc22bd1..eaf69bb912550a38aae923604cbf07e8e283060a 100644 --- a/kabel/src/vm.rs +++ b/kabel/src/vm.rs @@ -1,4 +1,6 @@ +use std::rc::Rc; + use crate::{runtime_error::{KabelRuntimeError, RuntimeErrorKind}, vm_boolean_comparison, vm_boolean_equality}; use crate::vm_error; @@ -32,7 +34,8 @@ pub struct VM { pub call_stack: Vec<(usize, usize, usize)>, // (unit_ptr, ip, stack_offset) pub units: Vec, pub stack: Vec, - pub stack_offset: usize, + pub variables: Vec, + pub variables_offset: usize, text: Vec } @@ -45,7 +48,8 @@ impl VM { call_stack: vec![(0, 0, 0)], units: vec![Unit::new(bytecode, pool, lines)], stack: Vec::new(), - stack_offset: 0, + variables: Vec::new(), + variables_offset: 0, text: text.lines().map(|s| s.to_string()).collect::>(), } } @@ -60,24 +64,49 @@ impl VM { } 0x01 => { // VAR let ptr = self.read() as usize; - let value = self.stack[ptr+self.stack_offset].clone(); - //println!("offset {} ptr {}", offset, ptr); - //println!("stack {:?}", self.stack); + let value = self.variables[ptr+self.variables_offset].clone(); self.stack.push(value); } - // ASSIGN - 0x02 => { + 0x02 => { // ASN let value = self.stack.pop().unwrap(); let ptr = self.read(); let offset = self.call_stack.last().expect("var call stack last").2; - self.stack[ptr as usize + offset] = value.clone(); + self.variables[ptr as usize + offset] = value.clone(); self.stack.push(value); } - 0x03 => { // ADD + 0x03 => { // ASNARR + let mut list = self.stack.pop().unwrap(); + let index = self.stack.pop().unwrap(); + let value = self.stack.pop().unwrap(); + if let Value::Num(index) = index { + if index.fract() != 0.0 { + return Err(vm_error!(self, RuntimeErrorKind::WrongType, "Subscript index must be an integer but found {}", index)) + } + let index = index as usize; + if let Value::List(ref mut list) = list { + let len = list.len(); + if index > len { + return Err(vm_error!(self, RuntimeErrorKind::ArrayOutOfBounds, "List length is {} but found index {}", len, index)) + } + println!("index: {}", index); + list[index] = value.clone(); + self.stack.push(value); + } else { + return Err(vm_error!(self, RuntimeErrorKind::WrongType, "Tried to subscript non-list type {}", list.type_str())) + } + } else { + return Err(vm_error!(self, RuntimeErrorKind::WrongType, "Tried to use non-integer type {} to subscript list", index.type_str())) + } + } + 0x04 => { // DECL + let value = self.stack.pop().unwrap(); + self.variables.push(value); + } + 0x05 => { // ADD match (self.stack.pop().unwrap(), self.stack.pop().unwrap()) { (Num(v1), Num(v2)) => self.stack.push(Num(v1 + v2)), (Str(v1), Str(v2)) => { - self.stack.push(Str(v1 + &v2)); + self.stack.push(Str(v1.clone() + &v2)); }, (Bool(_v1), Bool(_v2)) => { return Err(vm_error!(self, RuntimeErrorKind::WrongType, "Cannot add booleans")) @@ -87,7 +116,7 @@ impl VM { } } } - 0x04 => { // SUB + 0x06 => { // SUB match (self.stack.pop().unwrap(), self.stack.pop().unwrap()) { (Num(v1), Num(v2)) => self.stack.push(Num(v1 - v2)), (Str(_v1), Str(_v2)) => { @@ -101,7 +130,7 @@ impl VM { } } } - 0x05 => { // MUL + 0x07 => { // MUL match (self.stack.pop().unwrap(), self.stack.pop().unwrap()) { (Num(v1), Num(v2)) => self.stack.push(Num(v1 * v2)), (Str(v1), Num(v2)) => { @@ -122,7 +151,7 @@ impl VM { } } } - 0x06 => { // DIV + 0x08 => { // DIV match (self.stack.pop().unwrap(), self.stack.pop().unwrap()) { (Num(v1), Num(v2)) => self.stack.push(Num(v1 / v2)), (Str(_v1), Str(_v2)) => { @@ -136,7 +165,7 @@ impl VM { } } } - 0x07 => { // MOD + 0x09 => { // MOD match (self.stack.pop().unwrap(), self.stack.pop().unwrap()) { (Num(v1), Num(v2)) => self.stack.push(Num(v1 % v2)), (Str(_v1), Str(_v2)) => { @@ -150,7 +179,7 @@ impl VM { } } } - 0x08 => { // BITAND + 0x0A => { // BITAND match (self.stack.pop().unwrap(), self.stack.pop().unwrap()) { (Num(v1), Num(v2)) => { if v1.fract() != 0.0 { @@ -172,7 +201,7 @@ impl VM { } } } - 0x09 => { // BITXOR + 0x0B => { // BITXOR match (self.stack.pop().unwrap(), self.stack.pop().unwrap()) { (Num(v1), Num(v2)) => { if v1.fract() != 0.0 { @@ -194,7 +223,7 @@ impl VM { } } } - 0x0A => { // BITOR + 0x0C => { // BITOR match (self.stack.pop().unwrap(), self.stack.pop().unwrap()) { (Num(v1), Num(v2)) => { if v1.fract() != 0.0 { @@ -217,19 +246,19 @@ impl VM { } } // EQ - 0x0b => vm_boolean_equality!(self, ==), + 0x0D => vm_boolean_equality!(self, ==), // NE - 0x0C => vm_boolean_equality!(self, !=), + 0x0E => vm_boolean_equality!(self, !=), // GR - 0x0D => vm_boolean_comparison!(self, >), + 0x0F => vm_boolean_comparison!(self, >), // GE - 0x0E => vm_boolean_comparison!(self, >=), + 0x10 => vm_boolean_comparison!(self, >=), // LS - 0x0F => vm_boolean_comparison!(self, <), + 0x11 => vm_boolean_comparison!(self, <), // LE - 0x10 => vm_boolean_comparison!(self, <=), + 0x12 => vm_boolean_comparison!(self, <=), // OR - 0x11 => match (self.stack.pop().unwrap(), self.stack.pop().unwrap()) { + 0x13 => match (self.stack.pop().unwrap(), self.stack.pop().unwrap()) { (Num(_v1), Num(_v2)) => { return Err(vm_error!(self, RuntimeErrorKind::WrongType, "Tried to perform \"||\" on non-boolean numbers")) } @@ -244,7 +273,7 @@ impl VM { } } // AND - 0x12 => match (self.stack.pop().unwrap(), self.stack.pop().unwrap()) { + 0x14 => match (self.stack.pop().unwrap(), self.stack.pop().unwrap()) { (Num(_v1), Num(_v2)) => { return Err(vm_error!(self, RuntimeErrorKind::WrongType, "Tried to perform \"&&\" on non-boolean numbers")) } @@ -259,7 +288,7 @@ impl VM { } } // NOT - 0x13 => match self.stack.pop().unwrap() { + 0x15 => match self.stack.pop().unwrap() { Null => { return Err(vm_error!(self, RuntimeErrorKind::WrongType, "Tried to perform \"!\" on non-boolean value null")) } Num(_v1) => { return Err(vm_error!(self, RuntimeErrorKind::WrongType, "Tried to perform \"!\" on non-boolean number")) @@ -276,7 +305,7 @@ impl VM { } } // NEG - 0x14 => match self.stack.pop().unwrap() { + 0x16 => match self.stack.pop().unwrap() { Null => { return Err(vm_error!(self, RuntimeErrorKind::WrongType, "Tried to perform \"-\" on non-number value null")) } Num(v1) => self.stack.push(Num(-v1)), Str(_v1) => { @@ -293,17 +322,17 @@ impl VM { } } // JMP - 0x15 => { + 0x17 => { let loc = self.read_u16(); self.ip += loc as usize; } // JMP_UP - 0x16 => { + 0x18 => { let loc = self.read_u16(); self.ip -= loc as usize; } // JNE - 0x17 => { + 0x19 => { let condition = self.stack.pop().unwrap(); if let Value::Bool(condition) = condition { if !condition { @@ -318,15 +347,15 @@ impl VM { } // CALL - 0x18 => { + 0x1A => { let num_args = self.read(); let function = self.stack.pop().expect("Stack was empty in call"); if let Value::Fun(function) = function { if num_args as usize != function.arity { return Err(vm_error!(self, RuntimeErrorKind::IncorrectArity, "Function has {} arguments, {} provided", function.arity, num_args)) } - self.stack_offset = self.stack.len() - num_args as usize; - self.call_stack.push((self.unit_ptr, self.ip, self.stack_offset)); + self.variables_offset = self.stack.len() - num_args as usize; + self.call_stack.push((self.unit_ptr, self.ip, self.variables_offset)); self.stack.insert(self.stack.len()-num_args as usize, Value::Fun(function)); self.ip = 0; self.unit_ptr = function.unit_ptr as usize; @@ -335,11 +364,11 @@ impl VM { } } // RET - 0x19 => { - let (unit_ptr, ip, stack_offset) = self.call_stack.pop().expect("Call stack empty on RET"); + 0x1B => { + let (unit_ptr, ip, variables_offset) = self.call_stack.pop().expect("Call stack empty on RET"); let ret = self.stack.pop().expect("Missing return value"); - self.stack = self.stack[..stack_offset].to_vec(); - self.stack_offset = self.call_stack.last().expect("call stack empty").2; + self.stack = self.stack[..variables_offset].to_vec(); + self.variables_offset = self.call_stack.last().expect("call stack empty").2; self.unit_ptr = unit_ptr; self.ip = ip; // returned to code @@ -347,13 +376,13 @@ impl VM { } // LIST - 0x1A => { + 0x1C => { let len = self.read(); let list = self.stack.drain(self.stack.len()-len as usize..).collect(); self.stack.push(Value::List(list)); } // SCR - 0x1B => { + 0x1D => { let index = self.stack.pop().expect("stack empty on subscript index"); let list = self.stack.pop().expect("stack empty on subscript list"); if let Value::Num(index) = index { @@ -430,7 +459,7 @@ impl VM { #[derive(Debug, Clone)] pub enum Value { - Null, Num(f32), Str(String), Bool(bool), List(Vec), Fun(Function) + Null, Num(f32), Str(String), Bool(bool), List(Vec), Fun(Function), } impl Value { @@ -456,7 +485,7 @@ impl ToString for Value { List(v) => { let mut output = "".to_string(); output += "["; - for value in v { + for value in >::clone(&v).into_iter() { output += &value.to_string(); output += ","; } diff --git a/kabel/tmp.kab b/kabel/tmp.kab index f2db6779ae5fbd2bd4234bd60c4fa55e05eda1ee..40cbb358e694d6d436254fa23c7ff0b8a41994a4 100644 --- a/kabel/tmp.kab +++ b/kabel/tmp.kab @@ -1,2 +1,6 @@ +// put [3, 2] on stack var i = [3, 2]; -i[0] = 3; +// get reference to i +// set index 0 from i to 3 +i[0] = 1; +print i;