From 731aaaa6ce6390700ad53797b117193576ef8a82 Mon Sep 17 00:00:00 2001 From: ghostly_zsh Date: Thu, 22 Aug 2024 13:55:13 -0500 Subject: [PATCH] self-recursion works --- kabel/src/codegen.rs | 23 ++++++ kabel/src/macros.rs | 26 +++---- kabel/src/main.rs | 2 +- kabel/src/name_resolution.rs | 34 +++++---- kabel/src/vm.rs | 100 +++++++++++++------------ kabel/test/runtime/fn_absent_block.out | 2 +- kabel/test/runtime/max.kab | 12 +++ kabel/test/runtime/max.out | 4 + kabel/test/runtime/recursive_fib.kab | 13 ++++ kabel/test/runtime/recursive_fib.out | 4 + kabel/test/syntax/assignment.out | 6 +- kabel/test/syntax/function.out | 6 +- kabel/test/syntax/if_else.out | 10 +-- kabel/tmp.kab | 16 ++-- 14 files changed, 164 insertions(+), 94 deletions(-) create mode 100644 kabel/test/runtime/max.kab create mode 100644 kabel/test/runtime/max.out create mode 100644 kabel/test/runtime/recursive_fib.kab create mode 100644 kabel/test/runtime/recursive_fib.out diff --git a/kabel/src/codegen.rs b/kabel/src/codegen.rs index f716bb87bc191d772ef9e702fc3c482e8f2f7d7f..93b1474e29e2fe93e4ddfb1e43f7841f200c1222 100644 --- a/kabel/src/codegen.rs +++ b/kabel/src/codegen.rs @@ -95,12 +95,18 @@ impl Codegen { } else { self.vm.units[self.vm.unit_ptr].lines.last_mut().unwrap().1 += 2; } + self.scopes.last_mut().expect("codegen scopes vec was empty").1 += 1; let old_unit_ptr = self.vm.unit_ptr; let old_ip = self.vm.ip; // set unit to write to self.vm.unit_ptr = new_unit_ptr; self.vm.ip = 0; + self.vm.units[self.vm.unit_ptr].pool.push(Value::Fun(Function { + unit_ptr: new_unit_ptr, + arity: args.len(), + })); + self.scopes.last_mut().expect("codegen scopes vec was empty").1 += args.len(); if let ASTType::Block(ref stmts) = block.ast_type { self.visit_block(&block, stmts.clone(), ScopeType::Function); @@ -137,6 +143,23 @@ impl Codegen { self.vm.ip = old_ip; } pub fn visit_return(&mut self, ast: &AST, expr: Option) { + let mut scopes = self.scopes.clone(); + let mut pop_count = 0; + /*loop { + let (scope_type, scope) = scopes.pop().expect("scopes empty in return"); + pop_count += scope; + if scope_type == ScopeType::Function { + break; + } + }*/ + 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); + 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; + } + if let Some(expr) = expr { self.visit(expr); } else { diff --git a/kabel/src/macros.rs b/kabel/src/macros.rs index 10b7ab3720583b302f9aea5b98f82260179e307c..7d663edf2b01475c77ad03965bc42f834170d85d 100644 --- a/kabel/src/macros.rs +++ b/kabel/src/macros.rs @@ -301,13 +301,13 @@ 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)), + match ($self.stacks[$self.stack_ptr].pop().expect(&("Couldn't pop left side of ".to_owned() + stringify!($oper))), + $self.stacks[$self.stack_ptr].pop().expect(&("Couldn't pop right side of ".to_owned() + stringify!($oper)))) { + (Num(v1), Num(v2)) => $self.stacks[$self.stack_ptr].push(Bool(v1 $oper v2)), + (Str(v1), Str(v2)) => $self.stacks[$self.stack_ptr].push(Bool(v1 $oper v2)), + (Bool(v1), Bool(v2)) => $self.stacks[$self.stack_ptr].push(Bool(v1 $oper v2)), + (Null, Null) => $self.stacks[$self.stack_ptr].push(Bool(true)), + (_v1, _v2) => $self.stacks[$self.stack_ptr].push(Bool(false)), } }; } @@ -315,14 +315,14 @@ macro_rules! vm_boolean_equality { #[macro_export] macro_rules! vm_boolean_comparison { ($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)), + match ($self.stacks[$self.stack_ptr].pop().expect(&("Couldn't pop left side of ".to_owned() + stringify!($oper))), + $self.stacks[$self.stack_ptr].pop().expect(&("Couldn't pop right side of ".to_owned() + stringify!($oper)))) { + (Num(v1), Num(v2)) => $self.stacks[$self.stack_ptr].push(Bool(v1 $oper v2)), + (Str(v1), Str(v2)) => $self.stacks[$self.stack_ptr].push(Bool(v1 $oper v2)), + (Bool(v1), Bool(v2)) => $self.stacks[$self.stack_ptr].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)), + (_v1, _v2) => $self.stacks[$self.stack_ptr].push(Bool(false)), } }; } diff --git a/kabel/src/main.rs b/kabel/src/main.rs index dbf7fa8f96e44df4734f9bf51e893e6d674a689a..2ce4fc3b1dbc831eb3fb3b29b23e2fbbca2b9746 100644 --- a/kabel/src/main.rs +++ b/kabel/src/main.rs @@ -52,9 +52,9 @@ fn main() { let codegen = run_codegen(program.to_string(), ast); let mut vm = codegen.vm; - output += &debug_stack(&vm.units[0].stack); for (index, _) in vm.units.iter().enumerate() { vm.unit_ptr = index; + output += &format!("{:?}", vm.units[vm.unit_ptr].pool); output += "unit ptr: "; output += &vm.unit_ptr.to_string(); output += "\n"; diff --git a/kabel/src/name_resolution.rs b/kabel/src/name_resolution.rs index 1430fc31ae20549b00a443d4413629659c3216ca..de5eeab9cca225e5864e2f14803571f2b399de0c 100644 --- a/kabel/src/name_resolution.rs +++ b/kabel/src/name_resolution.rs @@ -5,7 +5,7 @@ use crate::{ast::{ASTType, AST}, ast_error, ast_from_ast, error::{ErrorKind, Kab pub struct Resolver { text: Vec, symbol_table: Vec>, // (Symbol, reference to locals) - pub locals: Vec, // scope + pub locals: Vec>, // scope pub scope: usize, pub errors: Vec, } @@ -15,7 +15,7 @@ impl Resolver { Self { text: text.lines().collect::>().iter().map(|s| s.to_string()).collect(), symbol_table: vec![HashMap::new()], - locals: Vec::new(), + locals: vec![Vec::new()], scope: 0, errors: Vec::new(), } @@ -61,18 +61,24 @@ impl Resolver { } else {} } } + self.locals.last_mut().expect("locals last in function push").push(self.scope); + self.symbol_table.last_mut().unwrap().insert(name.name.clone(), + (Symbol::Function(args.len()), self.locals.last().expect("locals last in function symbol len").len()-1)); + + self.locals.push(Vec::new()); self.symbol_table.push(HashMap::new()); + self.locals.last_mut().expect("locals last in function self-reference push").push(self.scope+1); + self.symbol_table.last_mut().unwrap().insert(name.name.clone(), (Symbol::Var,self.locals.last().expect("locals last in function self-reference len").len()-1)); for arg in args.clone() { - self.symbol_table.last_mut().unwrap().insert(arg.name, (Symbol::Var,0)); + self.locals.last_mut().expect("locals last in function arg push").push(self.scope+1); + self.symbol_table.last_mut().unwrap().insert(arg.name, (Symbol::Var,self.locals.last().expect("locals last in function arg len").len()-1)); } let block = self.visit(*block); self.symbol_table.pop(); - self.locals.push(self.scope); - self.symbol_table.last_mut().unwrap().insert(name.name.clone(), - (Symbol::Function(args.len()), self.locals.len()-1)); + self.locals.pop(); AST { ast_type: Function(name, args, Box::new(block)), - extensions: vec![Extension::Resolution(self.scope, self.locals.len()-1)], + extensions: vec![Extension::Resolution(self.scope, self.locals.last().expect("locals last in function ast len").len()-1)], start_line: ast.start_line, end_line: ast.end_line, start_column: ast.start_column, @@ -113,9 +119,9 @@ impl Resolver { n_expr3 = Some(self.visit(expr)); } let block = self.visit(*block); - while let Some(scope) = self.locals.last() { + while let Some(scope) = self.locals.last().expect("locals failed in For").last() { if self.scope == *scope { - self.locals.pop(); + self.locals.last_mut().expect("locals failed in For pop").pop(); } else { break; } @@ -145,9 +151,9 @@ impl Resolver { self.locals.remove(index); } }*/ - while let Some(scope) = self.locals.last() { + while let Some(scope) = self.locals.last().expect("locals last in block").last() { if self.scope == *scope { - self.locals.pop(); + self.locals.last_mut().expect("locals last in block pop").pop(); } else { break; } @@ -158,7 +164,7 @@ impl Resolver { } Decl(name, expr) => { let expr = self.visit(*expr); - self.locals.push(self.scope); + self.locals.last_mut().expect("locals last in decl push").push(self.scope); if self.resolve_var(&name.name).0 { self.errors.push(out_of_scope_var!(self, ErrorKind::VariableAlreadyDeclaredVariable, ast, @@ -181,10 +187,10 @@ impl Resolver { } else {} } } - self.symbol_table.last_mut().unwrap().insert(name.name.clone(), (Symbol::Var, self.locals.len()-1)); + self.symbol_table.last_mut().unwrap().insert(name.name.clone(), (Symbol::Var, self.locals.last().expect("locals last in decl symbol").len()-1)); AST { ast_type: Decl(name, Box::new(expr)), - extensions: vec![Extension::Resolution(self.scope, self.locals.len()-1)], + extensions: vec![Extension::Resolution(self.scope, self.locals.last().expect("locals last in decl ast").len()-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 73ed4f16a570a303d3c2e05d7d070ca5f2460457..789896998d3a77006828813997b4c10ecf897187 100644 --- a/kabel/src/vm.rs +++ b/kabel/src/vm.rs @@ -5,15 +5,13 @@ use crate::vm_error; #[derive(Debug, Clone)] pub struct Unit { pub code: Vec, - pub stack: Vec, pub pool: Vec, pub lines: Vec<(usize, usize)>, // line #, repeats number of instructions } impl Unit { - pub fn new(code: Vec, stack: Vec, pool: Vec, lines: Vec<(usize, usize)>) -> Self { + pub fn new(code: Vec, pool: Vec, lines: Vec<(usize, usize)>) -> Self { Self { code, - stack, pool, lines, } @@ -21,7 +19,6 @@ impl Unit { pub fn new_empty() -> Self { Self { code: Vec::new(), - stack: Vec::new(), pool: Vec::new(), lines: Vec::new(), } @@ -32,8 +29,10 @@ impl Unit { pub struct VM { pub ip: usize, pub unit_ptr: usize, + pub stack_ptr: usize, pub call_stack: Vec<(usize, usize)>, // (unit_ptr, ip) pub units: Vec, + pub stacks: Vec>, text: Vec } @@ -43,8 +42,10 @@ impl VM { Self { ip: 0, unit_ptr: 0, + stack_ptr: 0, call_stack: Vec::new(), - units: vec![Unit::new(bytecode, Vec::new(), pool, lines)], + units: vec![Unit::new(bytecode, pool, lines)], + stacks: vec![Vec::new()], text: text.lines().map(|s| s.to_string()).collect::>(), } } @@ -55,25 +56,25 @@ impl VM { 0x00 => { // LOAD let byte = self.read() as usize; let value = self.units[self.unit_ptr].pool[byte].clone(); - self.units[self.unit_ptr].stack.push(value); + self.stacks[self.stack_ptr].push(value); } 0x01 => { // VAR let ptr = self.read() as usize; - let value = self.units[self.unit_ptr].stack[ptr].clone(); - self.units[self.unit_ptr].stack.push(value); + let value = self.stacks[self.stack_ptr][ptr].clone(); + self.stacks[self.stack_ptr].push(value); } // ASSIGN 0x02 => { - let value = self.units[self.unit_ptr].stack.pop().unwrap(); + let value = self.stacks[self.stack_ptr].pop().unwrap(); let ptr = self.read(); - self.units[self.unit_ptr].stack[ptr as usize] = value.clone(); - self.units[self.unit_ptr].stack.push(value); + self.stacks[self.stack_ptr][ptr as usize] = value.clone(); + self.stacks[self.stack_ptr].push(value); } 0x03 => { // ADD - 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)), + match (self.stacks[self.stack_ptr].pop().unwrap(), self.stacks[self.stack_ptr].pop().unwrap()) { + (Num(v1), Num(v2)) => self.stacks[self.stack_ptr].push(Num(v1 + v2)), (Str(v1), Str(v2)) => { - self.units[self.unit_ptr].stack.push(Str(v1 + &v2)); + self.stacks[self.stack_ptr].push(Str(v1 + &v2)); }, (Bool(_v1), Bool(_v2)) => { return Err(vm_error!(self, RuntimeErrorKind::WrongType, "Cannot add booleans")) @@ -84,8 +85,8 @@ impl VM { } } 0x04 => { // SUB - 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)), + match (self.stacks[self.stack_ptr].pop().unwrap(), self.stacks[self.stack_ptr].pop().unwrap()) { + (Num(v1), Num(v2)) => self.stacks[self.stack_ptr].push(Num(v1 - v2)), (Str(_v1), Str(_v2)) => { return Err(vm_error!(self, RuntimeErrorKind::WrongType, "Cannot subtract strings")) }, @@ -98,11 +99,11 @@ impl VM { } } 0x05 => { // MUL - 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)), + match (self.stacks[self.stack_ptr].pop().unwrap(), self.stacks[self.stack_ptr].pop().unwrap()) { + (Num(v1), Num(v2)) => self.stacks[self.stack_ptr].push(Num(v1 * v2)), (Str(v1), Num(v2)) => { if v2.fract() == 0.0 { - self.units[self.unit_ptr].stack.push(Str(v1.repeat(v2 as usize))); + self.stacks[self.stack_ptr].push(Str(v1.repeat(v2 as usize))); } else { return Err(vm_error!(self, RuntimeErrorKind::WrongType, "Number must be an integer")) } @@ -119,8 +120,8 @@ impl VM { } } 0x06 => { // DIV - 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)), + match (self.stacks[self.stack_ptr].pop().unwrap(), self.stacks[self.stack_ptr].pop().unwrap()) { + (Num(v1), Num(v2)) => self.stacks[self.stack_ptr].push(Num(v1 / v2)), (Str(_v1), Str(_v2)) => { return Err(vm_error!(self, RuntimeErrorKind::WrongType, "Cannot divide strings")) }, @@ -133,8 +134,8 @@ impl VM { } } 0x07 => { // MOD - 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)), + match (self.stacks[self.stack_ptr].pop().unwrap(), self.stacks[self.stack_ptr].pop().unwrap()) { + (Num(v1), Num(v2)) => self.stacks[self.stack_ptr].push(Num(v1 % v2)), (Str(_v1), Str(_v2)) => { return Err(vm_error!(self, RuntimeErrorKind::WrongType, "Cannot perform modulus on strings")) }, @@ -147,7 +148,7 @@ impl VM { } } 0x08 => { // BITAND - match (self.units[self.unit_ptr].stack.pop().unwrap(), self.units[self.unit_ptr].stack.pop().unwrap()) { + match (self.stacks[self.stack_ptr].pop().unwrap(), self.stacks[self.stack_ptr].pop().unwrap()) { (Num(v1), Num(v2)) => { if v1.fract() != 0.0 { return Err(vm_error!(self, RuntimeErrorKind::WrongType, "Cannot perform bitwise AND on {}", v1)) @@ -155,7 +156,7 @@ impl VM { if v2.fract() != 0.0 { return Err(vm_error!(self, RuntimeErrorKind::WrongType, "Cannot perform bitwise AND on {}", v2)) } - self.units[self.unit_ptr].stack.push(Num((v1 as u32 & v2 as u32) as f32)) + self.stacks[self.stack_ptr].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")) @@ -169,7 +170,7 @@ impl VM { } } 0x09 => { // BITXOR - match (self.units[self.unit_ptr].stack.pop().unwrap(), self.units[self.unit_ptr].stack.pop().unwrap()) { + match (self.stacks[self.stack_ptr].pop().unwrap(), self.stacks[self.stack_ptr].pop().unwrap()) { (Num(v1), Num(v2)) => { if v1.fract() != 0.0 { return Err(vm_error!(self, RuntimeErrorKind::WrongType, "Cannot perform bitwise XOR on {}", v1)) @@ -177,7 +178,7 @@ impl VM { if v2.fract() != 0.0 { return Err(vm_error!(self, RuntimeErrorKind::WrongType, "Cannot perform bitwise XOR on {}", v2)) } - self.units[self.unit_ptr].stack.push(Num((v1 as u32 ^ v2 as u32) as f32)) + self.stacks[self.stack_ptr].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")) @@ -191,7 +192,7 @@ impl VM { } } 0x0A => { // BITOR - match (self.units[self.unit_ptr].stack.pop().unwrap(), self.units[self.unit_ptr].stack.pop().unwrap()) { + match (self.stacks[self.stack_ptr].pop().unwrap(), self.stacks[self.stack_ptr].pop().unwrap()) { (Num(v1), Num(v2)) => { if v1.fract() != 0.0 { return Err(vm_error!(self, RuntimeErrorKind::WrongType, "Cannot perform bitwise OR on {}", v1)) @@ -199,7 +200,7 @@ impl VM { if v2.fract() != 0.0 { return Err(vm_error!(self, RuntimeErrorKind::WrongType, "Cannot perform bitwise OR on {}", v2)) } - self.units[self.unit_ptr].stack.push(Num((v1 as u32 | v2 as u32) as f32)) + self.stacks[self.stack_ptr].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")) @@ -225,14 +226,14 @@ impl VM { // LE 0x10 => vm_boolean_comparison!(self, <=), // OR - 0x11 => match (self.units[self.unit_ptr].stack.pop().unwrap(), self.units[self.unit_ptr].stack.pop().unwrap()) { + 0x11 => match (self.stacks[self.stack_ptr].pop().unwrap(), self.stacks[self.stack_ptr].pop().unwrap()) { (Num(_v1), Num(_v2)) => { 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, "Tried to perform \"||\" on non-boolean strings")) }, - (Bool(v1), Bool(v2)) => self.units[self.unit_ptr].stack.push(Bool(v1 || v2)), + (Bool(v1), Bool(v2)) => self.stacks[self.stack_ptr].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) => { @@ -240,14 +241,14 @@ impl VM { } } // AND - 0x12 => match (self.units[self.unit_ptr].stack.pop().unwrap(), self.units[self.unit_ptr].stack.pop().unwrap()) { + 0x12 => match (self.stacks[self.stack_ptr].pop().unwrap(), self.stacks[self.stack_ptr].pop().unwrap()) { (Num(_v1), Num(_v2)) => { 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, "Tried to perform \"&&\" on non-boolean strings")) }, - (Bool(v1), Bool(v2)) => self.units[self.unit_ptr].stack.push(Bool(v1 && v2)), + (Bool(v1), Bool(v2)) => self.stacks[self.stack_ptr].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) => { @@ -255,7 +256,7 @@ impl VM { } } // NOT - 0x13 => match self.units[self.unit_ptr].stack.pop().unwrap() { + 0x13 => match self.stacks[self.stack_ptr].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")) @@ -263,15 +264,15 @@ impl VM { Str(_v1) => { 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)), + Bool(v1) => self.stacks[self.stack_ptr].push(Bool(!v1)), Fun(_v1) => { return Err(vm_error!(self, RuntimeErrorKind::WrongType, "Tried to perform \"!\" on non-boolean function")) } } // NEG - 0x14 => match self.units[self.unit_ptr].stack.pop().unwrap() { + 0x14 => match self.stacks[self.stack_ptr].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)), + Num(v1) => self.stacks[self.stack_ptr].push(Num(-v1)), Str(_v1) => { return Err(vm_error!(self, RuntimeErrorKind::WrongType, "Tried to perform \"-\" on non-number string")) } @@ -294,7 +295,7 @@ impl VM { } // JNE 0x17 => { - let condition = self.units[self.unit_ptr].stack.pop().unwrap(); + let condition = self.stacks[self.stack_ptr].pop().unwrap(); if let Value::Bool(condition) = condition { if !condition { let loc = self.read_u16(); @@ -310,16 +311,19 @@ impl VM { // CALL 0x18 => { let num_args = self.read(); - let function = self.units[self.unit_ptr].stack.pop().expect("Stack was empty in call"); + let function = self.stacks[self.stack_ptr].pop().expect("Stack was empty in call"); if let Value::Fun(function) = function { + self.stacks.push(Vec::new()); if num_args as usize != function.arity { return Err(vm_error!(self, RuntimeErrorKind::IncorrectArity, "Function has {} arguments, {} provided", function.arity, num_args)) } self.call_stack.push((self.unit_ptr, self.ip)); + self.stacks[self.stack_ptr+1].push(Value::Fun(function)); for _ in 0..num_args { - let arg = self.units[self.unit_ptr].stack.pop().expect("Missing arguments in call"); - self.units[function.unit_ptr as usize].stack.push(arg); + let arg = self.stacks[self.stack_ptr].pop().expect("Missing arguments in call"); + self.stacks[self.stack_ptr+1].push(arg); } + self.stack_ptr += 1; self.ip = 0; self.unit_ptr = function.unit_ptr as usize; } else { @@ -329,22 +333,24 @@ impl VM { // 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(); + let ret = self.stacks[self.stack_ptr].pop().expect("Missing return value"); + //self.stacks[self.stack_ptr].clear(); self.unit_ptr = unit_ptr; self.ip = ip; // returned to code - self.units[self.unit_ptr].stack.push(ret); + self.stack_ptr -= 1; + self.stacks.pop().expect("RET pop stacks failed"); + self.stacks[self.stack_ptr].push(ret); } 0xFD => { // POP let times = self.read(); for _ in 0..times { - self.units[self.unit_ptr].stack.pop().expect(&format!("{}: Unable to pop stack", self.ip)); + self.stacks[self.stack_ptr].pop().expect(&format!("{}: Unable to pop stack", self.ip)); } } 0xFE => { // PRINT - let value = self.units[self.unit_ptr].stack.pop().unwrap(); + let value = self.stacks[self.stack_ptr].pop().unwrap(); match value { Null => *output += "null", Num(v) => *output += &v.to_string(), @@ -401,7 +407,7 @@ impl Value { } } -#[derive(Debug, Clone)] +#[derive(Debug, Clone, Copy)] pub struct Function { pub unit_ptr: usize, pub arity: usize, diff --git a/kabel/test/runtime/fn_absent_block.out b/kabel/test/runtime/fn_absent_block.out index c2511d5557b072e3c0e141b00ed8e8e295b6be5a..03d0d4b76bcaf85a4e749d314c614fbcf5693617 100644 --- a/kabel/test/runtime/fn_absent_block.out +++ b/kabel/test/runtime/fn_absent_block.out @@ -1,3 +1,3 @@ -Error 0004: Function "foo" not in scope at line 3, column 5 +Error 0004: Variable "foo" not in scope at line 3, column 5 foo(); ^ diff --git a/kabel/test/runtime/max.kab b/kabel/test/runtime/max.kab new file mode 100644 index 0000000000000000000000000000000000000000..bb4fda95db4144add9af54e05762f1ab4645df27 --- /dev/null +++ b/kabel/test/runtime/max.kab @@ -0,0 +1,12 @@ +function max(first, second) { + if(first > second) { + return first; + } else { + return second; + } +} + +print max(1, 2); // 2 +print max(3, 6); // 6 +print max(-5.2, 5); // 5 +print max(5, -5.2); // 5 diff --git a/kabel/test/runtime/max.out b/kabel/test/runtime/max.out new file mode 100644 index 0000000000000000000000000000000000000000..a25abc73e3b137d7d2e8f4b9a512b5328cd534b8 --- /dev/null +++ b/kabel/test/runtime/max.out @@ -0,0 +1,4 @@ +2 +6 +5 +5 diff --git a/kabel/test/runtime/recursive_fib.kab b/kabel/test/runtime/recursive_fib.kab new file mode 100644 index 0000000000000000000000000000000000000000..370bb02d49485526e38c38a0829d7bbcbaadc78b --- /dev/null +++ b/kabel/test/runtime/recursive_fib.kab @@ -0,0 +1,13 @@ +function fib(x) { + if(x == 0) { + return 0; + } + if(x == 1 || x == 2) { + return 1; + } + return fib(x-1) + fib(x-2); +} +print fib(2); // 1 +print fib(3); // 2 +print fib(4); // 3 +print fib(5); // 5 diff --git a/kabel/test/runtime/recursive_fib.out b/kabel/test/runtime/recursive_fib.out new file mode 100644 index 0000000000000000000000000000000000000000..e0d13b09c85b36934c6ed353e8f800a096891351 --- /dev/null +++ b/kabel/test/runtime/recursive_fib.out @@ -0,0 +1,4 @@ +1 +2 +3 +5 diff --git a/kabel/test/syntax/assignment.out b/kabel/test/syntax/assignment.out index 69ba98f1fd3135a93b872c29cfdd8af48ba01736..8afb749e423db62306b1b17e3890ac07b718cd0c 100644 --- a/kabel/test/syntax/assignment.out +++ b/kabel/test/syntax/assignment.out @@ -1,8 +1,8 @@ Program -| Decl i +| Decl i [] | | Lit 0 | Expr -| | Assign i +| | Assign i [] | | | Lit string -| Decl _foo +| Decl _foo [] | | Lit 3 diff --git a/kabel/test/syntax/function.out b/kabel/test/syntax/function.out index c1e6cb8f4e793d16a027adc82d27d3a89da05616..210b2c13b2a12e1ff333eed56bfb5c95e5161228 100644 --- a/kabel/test/syntax/function.out +++ b/kabel/test/syntax/function.out @@ -1,7 +1,7 @@ Program -| Function foo one two +| Function foo one two [] | | Block | | | Return | | | | Binary Add -| | | | | Lit one -| | | | | Lit two +| | | | | Lit one [] +| | | | | Lit two [] diff --git a/kabel/test/syntax/if_else.out b/kabel/test/syntax/if_else.out index e6a156ba5b721643105866707d80116ee81ebfee..567498cf091d3cac6fd9cec50879d2e6cefabf4a 100644 --- a/kabel/test/syntax/if_else.out +++ b/kabel/test/syntax/if_else.out @@ -1,23 +1,23 @@ Program | If | | Binary Eq -| | | Lit i +| | | Lit i [] | | | Lit 0 | | Block | | | Expr -| | | | Assign i +| | | | Assign i [] | | | | | Lit 1 | Else | | If | | | Binary Eq -| | | | Lit i +| | | | Lit i [] | | | | Lit 1 | | | Block | | | | Expr -| | | | | Assign i +| | | | | Assign i [] | | | | | | Lit 2 | | Else | | | Block | | | | Expr -| | | | | Assign i +| | | | | Assign i [] | | | | | | Lit 3 diff --git a/kabel/tmp.kab b/kabel/tmp.kab index 1b7fb356a4a142a89ac542937e42b76e8a7dd380..3524b2707b9e9e84244f3d7724a03bfd82acfd7b 100644 --- a/kabel/tmp.kab +++ b/kabel/tmp.kab @@ -1,8 +1,10 @@ -var k = 0; -function bar(i) { - return i+2; +function fib(x) { + if(x == 0) { + return 0; + } + if(x == 1 || x == 2) { + return 1; + } + return fib(x-1) + fib(x-2); } -function foo(i) { - return i+1; -} -print foo(bar(k)); +print fib(35);