From 44e83922483fa7ef728c31dddbe689e661f374c9 Mon Sep 17 00:00:00 2001 From: Andrew Morris Date: Wed, 4 May 2022 10:38:28 +1000 Subject: [PATCH] Implement bind --- src/vstc/virtual_machine/bytecode_decoder.rs | 13 ++++- src/vstc/virtual_machine/virtual_machine.rs | 46 ++++++++++++---- src/vstc/virtual_machine/vs_function.rs | 56 ++++++++++---------- src/vstc/virtual_machine/vs_pointer.rs | 8 +++ src/vstc/virtual_machine/vs_value.rs | 24 +++++++++ 5 files changed, 109 insertions(+), 38 deletions(-) diff --git a/src/vstc/virtual_machine/bytecode_decoder.rs b/src/vstc/virtual_machine/bytecode_decoder.rs index 9f82dd5..ec9b4b3 100644 --- a/src/vstc/virtual_machine/bytecode_decoder.rs +++ b/src/vstc/virtual_machine/bytecode_decoder.rs @@ -92,7 +92,17 @@ impl BytecodeDecoder { String => Val::String(Rc::new( self.decode_string() )), - Array => std::panic!("Not implemented"), + Array => { + let mut vals: Vec = Vec::new(); + + while self.peek_type() != BytecodeType::End { + vals.push(self.decode_val(registers)); + } + + self.decode_byte(); // End (TODO: assert) + + Val::Array(Rc::new(vals)) + }, Object => std::panic!("Not implemented"), Function => self.decode_function_header(), Instance => std::panic!("Not implemented"), @@ -185,6 +195,7 @@ impl BytecodeDecoder { register_count: register_count, parameter_count: parameter_count, start: self.pos, + binds: Vec::new(), })); } diff --git a/src/vstc/virtual_machine/virtual_machine.rs b/src/vstc/virtual_machine/virtual_machine.rs index a48606c..2089b50 100644 --- a/src/vstc/virtual_machine/virtual_machine.rs +++ b/src/vstc/virtual_machine/virtual_machine.rs @@ -14,6 +14,8 @@ pub struct VirtualMachine { pub struct StackFrame { pub decoder: BytecodeDecoder, pub registers: Vec, + pub param_start: usize, + pub param_end: usize, pub this_target: Option, pub return_target: Option, } @@ -56,6 +58,8 @@ impl VirtualMachine { pos: 0, }, registers: registers, + param_start: 2, + param_end: 2, return_target: Some(0), this_target: Some(1), }; @@ -91,7 +95,12 @@ impl VirtualMachine { frame.registers[register_index] = val; }, - OpDec => std::panic!("Instruction not implemented: OpDec"), + OpDec => { + let register_index = frame.decoder.decode_register_index().unwrap(); + let mut val = frame.registers[register_index].clone(); + val = operations::op_minus(&val, &Val::Number(1_f64)); + frame.registers[register_index] = val; + }, OpPlus => { let left = frame.decoder.decode_val(&frame.registers); @@ -252,7 +261,31 @@ impl VirtualMachine { self.stack.push(new_frame); } - Bind => std::panic!("Instruction not implemented: Bind"), + Bind => { + let fn_val = frame.decoder.decode_val(&frame.registers); + let params = frame.decoder.decode_val(&frame.registers); + let register_index = frame.decoder.decode_register_index(); + + let params_array = params.as_array(); + + if params_array.is_none() { + // Not sure this needs to be an exception in future since compiled + // code should never violate this + std::panic!("bind params should always be array") + } + + let bound_fn = fn_val.bind((*params_array.unwrap()).clone()); + + if bound_fn.is_none() { + // Not sure this needs to be an exception in future since compiled + // code should never violate this + std::panic!("fn parameter of bind should always be bindable"); + } + + if register_index.is_some() { + frame.registers[register_index.unwrap()] = bound_fn.unwrap(); + } + }, Sub => std::panic!("Instruction not implemented: Sub"), @@ -300,17 +333,12 @@ fn load_parameters( std::panic!("Not implemented: call instruction not using inline array"); } - // Params start at 2 since 0:return, 1:this - let mut reg_i = 2; + let mut reg_i = new_frame.param_start; while frame.decoder.peek_type() != BytecodeType::End { let val = frame.decoder.decode_val(&frame.registers); - if reg_i < new_frame.registers.len() { - // TODO: We should also stop writing into registers when hitting the - // parameter count. This won't matter for correctly constructed - // bytecode but hand-written assembly/bytecode may violate - // optimization assumptions. + if reg_i < new_frame.param_end { new_frame.registers[reg_i] = val; reg_i += 1; } diff --git a/src/vstc/virtual_machine/vs_function.rs b/src/vstc/virtual_machine/vs_function.rs index b892398..a5eeeed 100644 --- a/src/vstc/virtual_machine/vs_function.rs +++ b/src/vstc/virtual_machine/vs_function.rs @@ -1,8 +1,6 @@ use std::rc::Rc; -use super::vs_value::VsType; use super::vs_value::Val; -use super::vs_value::ValTrait; use super::virtual_machine::StackFrame; use super::bytecode_decoder::BytecodeDecoder; @@ -11,33 +9,37 @@ pub struct VsFunction { pub register_count: usize, pub parameter_count: usize, pub start: usize, + pub binds: Vec, } -impl ValTrait for VsFunction { - fn typeof_(&self) -> VsType { - return VsType::Function; +impl VsFunction { + pub fn bind(&self, params: Vec) -> VsFunction { + let mut new_binds = self.binds.clone(); + + for p in params { + new_binds.push(p); + } + + return VsFunction { + bytecode: self.bytecode.clone(), + register_count: self.register_count, + parameter_count: self.parameter_count, + start: self.start, + binds: new_binds, + }; } - fn val_to_string(&self) -> String { - return "[function]".to_string(); - } - - fn to_number(&self) -> f64 { - return f64::NAN; - } - - fn is_primitive(&self) -> bool { - return false; - } - - fn to_primitive(&self) -> Val { - return Val::String(Rc::new(self.val_to_string())); - } - - fn make_frame(&self) -> Option { + pub fn make_frame(&self) -> Option { let mut registers: Vec = Vec::with_capacity(self.register_count - 1); - - for _ in 0..(self.register_count - 1) { + + registers.push(Val::Undefined); + registers.push(Val::Undefined); + + for bind_val in &self.binds { + registers.push(bind_val.clone()); + } + + while registers.len() < registers.capacity() { registers.push(Val::Undefined); } @@ -47,12 +49,10 @@ impl ValTrait for VsFunction { pos: self.start, }, registers: registers, + param_start: self.binds.len() + 2, + param_end: self.parameter_count + 2, this_target: None, return_target: None, }); } - - fn is_truthy(&self) -> bool { - return true; - } } diff --git a/src/vstc/virtual_machine/vs_pointer.rs b/src/vstc/virtual_machine/vs_pointer.rs index 4930ad7..ac4b36c 100644 --- a/src/vstc/virtual_machine/vs_pointer.rs +++ b/src/vstc/virtual_machine/vs_pointer.rs @@ -78,6 +78,10 @@ impl ValTrait for VsPointer { return self.decode().to_number(); } + fn as_array(&self) -> Option>> { + return self.decode().as_array(); + } + fn is_primitive(&self) -> bool { return match self.typeof_() { Undefined => true, @@ -95,6 +99,10 @@ impl ValTrait for VsPointer { return self.decode().to_primitive(); } + fn bind(&self, params: Vec) -> Option { + return self.decode().bind(params); + } + fn make_frame(&self) -> Option { return self.decode().make_frame(); } diff --git a/src/vstc/virtual_machine/vs_value.rs b/src/vstc/virtual_machine/vs_value.rs index 44b02e9..3289a5a 100644 --- a/src/vstc/virtual_machine/vs_value.rs +++ b/src/vstc/virtual_machine/vs_value.rs @@ -35,9 +35,11 @@ pub trait ValTrait { fn typeof_(&self) -> VsType; fn val_to_string(&self) -> String; fn to_number(&self) -> f64; + fn as_array(&self) -> Option>>; fn is_primitive(&self) -> bool; fn to_primitive(&self) -> Val; fn is_truthy(&self) -> bool; + fn bind(&self, params: Vec) -> Option; fn make_frame(&self) -> Option; } @@ -114,6 +116,17 @@ impl ValTrait for Val { }; } + fn as_array(&self) -> Option>> { + use Val::*; + + return match self { + Array(a) => Some(a.clone()), + Custom(val) => val.as_array(), + + _ => None, + } + } + fn is_primitive(&self) -> bool { use Val::*; @@ -156,6 +169,17 @@ impl ValTrait for Val { } } + fn bind(&self, params: Vec) -> Option { + use Val::*; + + return match self { + Function(f) => Some(Val::Function(Rc::new(f.bind(params)))), + Custom(val) => val.bind(params), + + _ => None, + } + } + fn make_frame(&self) -> Option { use Val::*;