From 2ee9958ed9779739e20afab5f3d127a43d1eb651 Mon Sep 17 00:00:00 2001 From: ghostly_zsh Date: Wed, 21 Aug 2024 11:39:29 -0500 Subject: [PATCH] first draft of functions and calls --- kabel/opcodes.txt | 2 +- kabel/src/codegen.rs | 46 +++++++++++++++++++++++++----- kabel/src/debug.rs | 12 ++++++++ kabel/src/macros.rs | 33 ++++++++++++++++------ kabel/src/main.rs | 1 + kabel/src/name_resolution.rs | 2 +- kabel/src/vm.rs | 55 +++++++++++++++++++++++------------- kabel/tmp.kab | 10 +++++-- 8 files changed, 121 insertions(+), 40 deletions(-) diff --git a/kabel/opcodes.txt b/kabel/opcodes.txt index c92a88ba9bd6dbdea1afc2c51fd423938c1a9ca2..ce10c02f6e5760136c1d943555f6b642b0826c63 100644 --- a/kabel/opcodes.txt +++ b/kabel/opcodes.txt @@ -1,4 +1,4 @@ -CONSTANT VAL ; 0x00 +LOAD VAL ; 0x00 VAR STACKPTR ; 0x01 ASSIGN PTR ; 0x02 diff --git a/kabel/src/codegen.rs b/kabel/src/codegen.rs index c93294ab343349c63c68b6bed417391184a62c90..5e4ef26478a62a27fbf1a1a580a38c28af5b11b3 100644 --- a/kabel/src/codegen.rs +++ b/kabel/src/codegen.rs @@ -28,6 +28,9 @@ impl Codegen { Function(name, args, block) => { self.visit_function(name, args, *block); } + Return(ref expr) => { + self.visit_return(&ast, *expr.clone()); + } While(condition, block) => { self.visit_while(*condition, *block); } @@ -88,27 +91,56 @@ impl Codegen { } match self.vm.units[self.vm.unit_ptr].code.last() { Some(instr) => { - if *instr != OpCode::RET.into() { + if *instr != >::into(OpCode::RET) { + self.vm.units[self.vm.unit_ptr].pool.push(Value::Null); + 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); 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)); + self.vm.units[self.vm.unit_ptr].lines.push((block.end_line, 3)); } else { - self.vm.units[self.vm.unit_ptr].lines.last_mut().unwrap().1 += 1; + self.vm.units[self.vm.unit_ptr].lines.last_mut().unwrap().1 += 3; } } } None => { + self.vm.units[self.vm.unit_ptr].pool.push(Value::Null); + 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); 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)); + self.vm.units[self.vm.unit_ptr].lines.push((block.end_line, 3)); } else { - self.vm.units[self.vm.unit_ptr].lines.last_mut().unwrap().1 += 1; + self.vm.units[self.vm.unit_ptr].lines.last_mut().unwrap().1 += 3; } } }; self.vm.unit_ptr = old_unit_ptr; self.vm.ip = old_ip; } + pub fn visit_return(&mut self, ast: &AST, expr: Option) { + if let Some(expr) = expr { + self.visit(expr); + } else { + self.vm.units[self.vm.unit_ptr].pool.push(Value::Null); + 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.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; + } + } + self.vm.units[self.vm.unit_ptr].code.push(OpCode::RET.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; + } + } pub fn visit_while(&mut self, condition: AST, block: AST) { self.break_stack.push(Vec::new()); self.continue_stack.push(Vec::new()); @@ -459,8 +491,8 @@ impl Codegen { } } pub fn visit_call(&mut self, ast: &AST, _name: Name, args: Vec) { - for arg in args.clone() { - self.visit(arg); + for arg in args.iter().rev() { + self.visit(arg.clone()); } 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); diff --git a/kabel/src/debug.rs b/kabel/src/debug.rs index a8acb49c098019d3ac152ecae69287843eef3450..ae9c6168615ee6be7b06d615360374285475ee9d 100644 --- a/kabel/src/debug.rs +++ b/kabel/src/debug.rs @@ -286,6 +286,18 @@ pub fn debug_bytecode(vm: &VM) -> String { output += &(byte_one | byte_two).to_string(); output += "\n"; } + CALL => { + output += &vm.ip.to_string(); + output += " "; + output += &vm.find_line().to_string(); + output += " CALL "; + vm.ip += 1; + output += &(vm.units[vm.unit_ptr].code[vm.ip]).to_string(); + output += " "; + vm.ip += 1; + output += &(vm.units[vm.unit_ptr].code[vm.ip]).to_string(); + output += "\n"; + } RET => { output += &vm.ip.to_string(); output += " "; diff --git a/kabel/src/macros.rs b/kabel/src/macros.rs index f115d3630209e7c69fe102a0a987b5ebac1b7707..10b7ab3720583b302f9aea5b98f82260179e307c 100644 --- a/kabel/src/macros.rs +++ b/kabel/src/macros.rs @@ -276,8 +276,8 @@ macro_rules! codegen_unary { match $match_to { $( $oper => { $self.visit($right); - $self.vm.units[0].code.push(OpCode::$code.into()); - $self.vm.units[0].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; } )* } }; @@ -298,16 +298,31 @@ macro_rules! push_codegen { } }; } +#[macro_export] +macro_rules! vm_boolean_equality { + ($self:expr, $oper:tt) => { + match ($self.units[$self.unit_ptr].stack.pop().expect(&("Couldn't pop left side of ".to_owned() + stringify!($oper))), + $self.units[$self.unit_ptr].stack.pop().expect(&("Couldn't pop right side of ".to_owned() + stringify!($oper)))) { + (Num(v1), Num(v2)) => $self.units[$self.unit_ptr].stack.push(Bool(v1 $oper v2)), + (Str(v1), Str(v2)) => $self.units[$self.unit_ptr].stack.push(Bool(v1 $oper v2)), + (Bool(v1), Bool(v2)) => $self.units[$self.unit_ptr].stack.push(Bool(v1 $oper v2)), + (Null, Null) => $self.units[$self.unit_ptr].stack.push(Bool(true)), + (_v1, _v2) => $self.units[$self.unit_ptr].stack.push(Bool(false)), + } + }; +} #[macro_export] -macro_rules! vm_boolean_binary { +macro_rules! vm_boolean_comparison { ($self:expr, $oper:tt) => { - 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)), + match ($self.units[$self.unit_ptr].stack.pop().expect(&("Couldn't pop left side of ".to_owned() + stringify!($oper))), + $self.units[$self.unit_ptr].stack.pop().expect(&("Couldn't pop right side of ".to_owned() + stringify!($oper)))) { + (Num(v1), Num(v2)) => $self.units[$self.unit_ptr].stack.push(Bool(v1 $oper v2)), + (Str(v1), Str(v2)) => $self.units[$self.unit_ptr].stack.push(Bool(v1 $oper v2)), + (Bool(v1), Bool(v2)) => $self.units[$self.unit_ptr].stack.push(Bool(v1 $oper v2)), + (Null, _) => return Err(vm_error!($self, RuntimeErrorKind::WrongType, "Tried to perform comparison \"{}\" on value null", stringify!($tt))), + (_, Null) => return Err(vm_error!($self, RuntimeErrorKind::WrongType, "Tried to perform comparison \"{}\" on value null", stringify!($tt))), + (_v1, _v2) => $self.units[$self.unit_ptr].stack.push(Bool(false)), } }; } diff --git a/kabel/src/main.rs b/kabel/src/main.rs index 72d7cc3af504855b138c496d30ad8208abcc4efe..9a71d653574333bce04c43ca746edd1211b6b8c8 100644 --- a/kabel/src/main.rs +++ b/kabel/src/main.rs @@ -61,6 +61,7 @@ fn main() { output += "\n"; } vm.unit_ptr = 0; + println!("{}", output); output += "\n"; match vm.run(&mut output) { diff --git a/kabel/src/name_resolution.rs b/kabel/src/name_resolution.rs index 49a31a2b6bab91fc7860b46cdec4de4f6e2e8d3c..921688debc9ef9f7203370beb5e8253e9ce45969 100644 --- a/kabel/src/name_resolution.rs +++ b/kabel/src/name_resolution.rs @@ -287,7 +287,7 @@ impl Resolver { } return AST { ast_type: Call(ident, n_args), - extensions: vec![Extension::Resolution(self.scope, place)], + extensions: vec![Extension::Resolution(self.scope, place+1)], start_line: ast.start_line, end_line: ast.end_line, start_column: ast.start_column, diff --git a/kabel/src/vm.rs b/kabel/src/vm.rs index 34d69fd3e4834916e55edfa15635db3ed76c13df..5861c6d698267fe1c5d961ac293085228ca212ee 100644 --- a/kabel/src/vm.rs +++ b/kabel/src/vm.rs @@ -1,5 +1,5 @@ -use crate::{runtime_error::{KabelRuntimeError, RuntimeErrorKind}, vm_boolean_binary}; +use crate::{runtime_error::{KabelRuntimeError, RuntimeErrorKind}, vm_boolean_comparison, vm_boolean_equality}; use crate::vm_error; #[derive(Debug, Clone)] @@ -213,26 +213,28 @@ impl VM { } } // EQ - 0x0b => vm_boolean_binary!(self, ==), + 0x0b => vm_boolean_equality!(self, ==), // NE - 0x0C => vm_boolean_binary!(self, !=), + 0x0C => vm_boolean_equality!(self, !=), // GR - 0x0D => vm_boolean_binary!(self, >), + 0x0D => vm_boolean_comparison!(self, >), // GE - 0x0E => vm_boolean_binary!(self, >=), + 0x0E => vm_boolean_comparison!(self, >=), // LS - 0x0F => vm_boolean_binary!(self, <), + 0x0F => vm_boolean_comparison!(self, <), // LE - 0x10 => vm_boolean_binary!(self, <=), + 0x10 => vm_boolean_comparison!(self, <=), // OR 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")) + return Err(vm_error!(self, RuntimeErrorKind::WrongType, "Tried to perform \"||\" on non-boolean numbers")) } (Str(_v1), Str(_v2)) => { - return Err(vm_error!(self, RuntimeErrorKind::WrongType, "Cannot perform logical OR on strings")) + return Err(vm_error!(self, RuntimeErrorKind::WrongType, "Tried to perform \"||\" on non-boolean strings")) }, (Bool(v1), Bool(v2)) => self.units[self.unit_ptr].stack.push(Bool(v1 || v2)), + (Null, _) => return Err(vm_error!(self, RuntimeErrorKind::WrongType, "Tried to perform \"||\" on non-boolean value null")), + (_, Null) => return Err(vm_error!(self, RuntimeErrorKind::WrongType, "Tried to perform \"||\" on non-boolean value null")), (v1, v2) => { return Err(vm_error!(self, RuntimeErrorKind::MismatchedTypes, "Mismatched types: {} and {}", v1.type_str(), v2.type_str())) } @@ -240,34 +242,38 @@ impl VM { // AND 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")) + return Err(vm_error!(self, RuntimeErrorKind::WrongType, "Tried to perform \"&&\" on non-boolean numbers")) } (Str(_v1), Str(_v2)) => { - return Err(vm_error!(self, RuntimeErrorKind::WrongType, "Cannot perform logical AND on strings")) + return Err(vm_error!(self, RuntimeErrorKind::WrongType, "Tried to perform \"&&\" on non-boolean strings")) }, (Bool(v1), Bool(v2)) => self.units[self.unit_ptr].stack.push(Bool(v1 && v2)), + (Null, _) => return Err(vm_error!(self, RuntimeErrorKind::WrongType, "Tried to perform \"&&\" on non-boolean value null")), + (_, Null) => return Err(vm_error!(self, RuntimeErrorKind::WrongType, "Tried to perform \"&&\" on non-boolean value null")), (v1, v2) => { return Err(vm_error!(self, RuntimeErrorKind::MismatchedTypes, "Mismatched types: {} and {}", v1.type_str(), v2.type_str())) } } // NOT 0x13 => match self.units[self.unit_ptr].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, "Cannot perform logical NOT on numbers")) + return Err(vm_error!(self, RuntimeErrorKind::WrongType, "Tried to perform \"!\" on non-boolean number")) } Str(_v1) => { - return Err(vm_error!(self, RuntimeErrorKind::WrongType, "Cannot perform logical NOT on strings")) + return Err(vm_error!(self, RuntimeErrorKind::WrongType, "Tried to perform \"!\" on non-boolean string")) } Bool(v1) => self.units[self.unit_ptr].stack.push(Bool(!v1)), } // NEG 0x14 => match self.units[self.unit_ptr].stack.pop().unwrap() { + Null => { return Err(vm_error!(self, RuntimeErrorKind::WrongType, "Tried to perform \"-\" on non-number value null")) } Num(v1) => self.units[self.unit_ptr].stack.push(Num(-v1)), Str(_v1) => { - return Err(vm_error!(self, RuntimeErrorKind::WrongType, "Cannot negate strings")) + return Err(vm_error!(self, RuntimeErrorKind::WrongType, "Tried to perform \"-\" on non-number string")) } Bool(_v1) => { - return Err(vm_error!(self, RuntimeErrorKind::WrongType, "Cannot negate bools")) + return Err(vm_error!(self, RuntimeErrorKind::WrongType, "Tried to perform \"-\" on non-number boolean")) } } // JMP @@ -300,13 +306,22 @@ impl VM { 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 { - + for _ in 0..num_args { + let arg = self.units[self.unit_ptr].stack.pop().expect("Missing arguments in call"); + self.units[unit_ptr as usize].stack.push(arg); } + self.ip = 0; + self.unit_ptr = unit_ptr as usize; } // RET 0x19 => { - + let (unit_ptr, ip) = self.call_stack.pop().expect("Call stack empty on RET"); + let ret = self.units[self.unit_ptr].stack.pop().expect("Missing return value"); + self.units[self.unit_ptr].stack.clear(); + self.unit_ptr = unit_ptr; + self.ip = ip; + // returned to code + self.units[self.unit_ptr].stack.push(ret); } 0xFD => { // POP @@ -318,6 +333,7 @@ impl VM { 0xFE => { // PRINT let value = self.units[self.unit_ptr].stack.pop().unwrap(); match value { + Null => *output += "null", Num(v) => *output += &v.to_string(), Str(v) => *output += &v, Bool(v) => *output += &v.to_string(), @@ -356,12 +372,13 @@ impl VM { #[derive(Debug, Clone)] pub enum Value { - Num(f32), Str(String), Bool(bool), + Null, Num(f32), Str(String), Bool(bool), } impl Value { pub fn type_str(&self) -> String { match self { + Value::Null => "null".to_string(), Value::Num(_) => "number".to_string(), Value::Str(_) => "string".to_string(), Value::Bool(_) => "bool".to_string(), diff --git a/kabel/tmp.kab b/kabel/tmp.kab index 7ba20beb3ff8eb37734611fce8938ccd29d34f1e..2bd4c07e7c27fce1764eefa512207c5645f3951d 100644 --- a/kabel/tmp.kab +++ b/kabel/tmp.kab @@ -1,4 +1,8 @@ -function i(j) { - j+1; +var k = 0; +function bar(i) { + return i+2; } -print i(2); +function foo(i) { + return i+1; +} +print foo(2);