From aceb44fa5153a33eb8013be41f1c455ca424f92d Mon Sep 17 00:00:00 2001 From: Jesse Morgan Date: Sun, 31 Dec 2023 15:15:03 -0800 Subject: Implement Invoke, Yield, and Return ops Javascript functions can now return values. --- src/ion.rs | 2 +- src/js.rs | 16 +- src/main.rs | 12 +- src/runtime.rs | 679 +++++++++++++++++++++++++++++++-------------------------- 4 files changed, 392 insertions(+), 317 deletions(-) (limited to 'src') diff --git a/src/ion.rs b/src/ion.rs index cbfae24..65f5d23 100644 --- a/src/ion.rs +++ b/src/ion.rs @@ -18,7 +18,7 @@ pub enum IonType { Annotations = 0x0e, } -#[derive(PartialOrd, PartialEq)] +#[derive(PartialOrd, PartialEq, Clone)] pub struct IonValue(Vec); impl IonValue { diff --git a/src/js.rs b/src/js.rs index 8de188b..9249d30 100644 --- a/src/js.rs +++ b/src/js.rs @@ -108,6 +108,14 @@ impl JsCompiler { self.bytecode.push(OpCode::SwapPop.into()); } + fn push_yield(&mut self) { + self.bytecode.push(OpCode::Yield.into()); + } + + fn push_return(&mut self) { + self.bytecode.push(OpCode::Return.into()); + } + fn push_push(&mut self, value: &IonValue) { self.bytecode.push(OpCode::TypePush.into()); self.bytecode.extend(value.bytes()); @@ -595,7 +603,13 @@ impl JsCompiler { boa_ast::Statement::Switch(_) => todo!(), boa_ast::Statement::Continue(_) => todo!(), boa_ast::Statement::Break(_) => todo!(), - boa_ast::Statement::Return(_) => todo!(), + boa_ast::Statement::Return(ret) => { + if let Some(expr) = ret.target() { + self.compile_expression(expr); + self.push_yield(); + } + self.push_return(); + }, boa_ast::Statement::Labelled(_) => todo!(), boa_ast::Statement::Throw(_) => todo!(), boa_ast::Statement::Try(_) => todo!(), diff --git a/src/main.rs b/src/main.rs index 673c164..33da842 100644 --- a/src/main.rs +++ b/src/main.rs @@ -31,7 +31,8 @@ impl From for RelJsError { } } -fn main() -> Result<(), RelJsError> { +#[tokio::main] +async fn main() -> Result<(), RelJsError> { let src = Source::from_filepath(Path::new("demo/script.js"))?; let mut parser = Parser::new(src); let mut interner = Interner::new(); @@ -46,11 +47,10 @@ fn main() -> Result<(), RelJsError> { let function_id = runtime.to_symbol_id("main") .expect("script.js is missing a main function"); - let result = runtime.invoke(function_id, vec![]); - - for (i, v) in result.iter().enumerate() { - println!("Result {i}:"); - for b in v.bytes() { + let mut result = runtime.invoke(function_id, vec![]); + while let Some(value) = result.recv().await { + println!("Result:"); + for b in value.bytes() { print!("{b:02x} "); } println!("\n"); diff --git a/src/runtime.rs b/src/runtime.rs index 46b2d9f..dbb6222 100644 --- a/src/runtime.rs +++ b/src/runtime.rs @@ -1,6 +1,7 @@ -use std::{collections::{LinkedList, BTreeMap}, cmp::Ordering, sync::Arc, iter::{Copied, Rev}}; +use std::{collections::BTreeMap, cmp::Ordering, sync::Arc, iter::{Copied, Rev}}; use ion_rs::SymbolTable; +use tokio::sync::mpsc::{self, Sender}; use crate::ion::{IonReader, IonValue}; @@ -16,10 +17,25 @@ pub enum OpCode { Dup2 = 0x03, SwapPop = 0x04, + /// Invoke a function + /// operands: function id + /// stack: [arguments...] -> [return value?] Invoke = 0x05, - Yield = 0x06, - Return = 0x07, + /// Invoke a function and gather all results into a list. + /// operands: function id + /// stack: [arguments...] -> [list of return values] + InvokeGenerate = 0x06, + + /// Provide a return value. + /// operands: + /// stack: [value] -> [] + Yield = 0x07, + + /// Return control to the caller. + /// operands: + /// stack: + Return = 0x08, /// Push a typed Ion value onto the stack. /// operands: T and L @@ -246,15 +262,19 @@ impl From for u8 { } } -pub struct Runtime { +#[derive(Clone)] +pub struct Runtime(Arc); + +pub struct RuntimeInner { symbols: SymbolTable, bytecode: Arc, functions: BTreeMap, - stacks: LinkedList, + channel_buffer_size: usize, } pub enum ExecutionState { Continue, + Yield(IonValue), Halt, } @@ -269,352 +289,400 @@ pub struct Function { pub type ByteCode = Vec; +#[derive(Clone)] struct Stack(Vec); +#[derive(Clone)] pub struct StackFrame { + runtime: Runtime, bytecode: Arc, pc: usize, variables: Vec, stack: Stack, + tx: Sender, } -impl Runtime { +pub type ExecutionStream = mpsc::Receiver; + + +impl Runtime { pub fn new(symbols: SymbolTable, bytecode: ByteCode, functions: Vec) -> Runtime { - Runtime { + Runtime(Arc::new(RuntimeInner { symbols, functions: functions.into_iter().map(|f| (f.name_symbol, f)).collect(), bytecode: bytecode.into(), - stacks: LinkedList::new(), - } + channel_buffer_size: 1, + })) } pub fn to_symbol_id(&self, s: S) -> Option where S: AsRef { - self.symbols.sid_for(&s) + self.0.symbols.sid_for(&s) } pub fn resolve_symbol(&self, id: usize) -> Option<&str> { - self.symbols.text_for(id) + self.0.symbols.text_for(id) + } + + pub fn invoke(&mut self, fnref: usize, arguments: Vec) -> ExecutionStream { + let (tx, rx) = mpsc::channel::(self.0.channel_buffer_size); + let func = *self.0.functions.get(&fnref).expect("Undefined function"); + let frame = StackFrame::new(self.clone(), tx, &func, arguments); + execute_frame(frame); + rx } +} - pub fn invoke(&mut self, fnref: usize, arguments: Vec) -> Vec { - let func = *self.functions.get(&fnref).expect("Undefined function"); - let mut frame = StackFrame::new(self.bytecode.clone(), &func, arguments); +fn execute_frame(mut frame: StackFrame) { + tokio::spawn(async move { loop { - match self.execute(&mut frame) { + match execute(&mut frame).await { ExecutionState::Continue => (), + ExecutionState::Yield(value) => { + if frame.tx.send(value).await.is_err() { + break; + } + }, ExecutionState::Halt => { - //frame.variables.truncate(func.arguments.into()); - return frame.variables; + break; }, } } - } + }); +} - fn execute(&mut self, frame: &mut StackFrame) -> ExecutionState { - if frame.eof() { - return ExecutionState::Halt; - } +async fn execute(frame: &mut StackFrame) -> ExecutionState { + if frame.eof() { + return ExecutionState::Halt; + } - let op = frame.next_byte(); + let op = frame.next_byte(); - #[cfg(debugger)] - { - for x in &frame.stack.0 { - print!(" {x:02X}"); - } - println!(); - println!("PC: {:02X}, OP: {:02X}", frame.pc - 1, op); + #[cfg(debugger)] + { + for x in &frame.stack.0 { + print!(" {x:02X}"); } + println!(); + println!("PC: {:02X}, OP: {:02X}", frame.pc - 1, op); + } - match op { - 0x01 => { // OpType::Jump - let pc = frame.next_u32().try_into().unwrap(); - frame.jump(pc); - }, - 0x02 => { // OpType::Dup - let value1 = frame.stack.pop_value(); - frame.stack.push_value(&value1); - frame.stack.push_value(&value1); - }, - 0x03 => { // OpType::Dup2 - let value1 = frame.stack.pop_value(); - let value2 = frame.stack.pop_value(); - frame.stack.push_value(&value2); - frame.stack.push_value(&value1); - frame.stack.push_value(&value2); - frame.stack.push_value(&value1); - }, - 0x04 => { // OpType::SwapPop - let value1 = frame.stack.pop_value(); - frame.stack.drop_value(); - frame.stack.push_value(&value1); - }, - 0x10 => { // OpType::Push - let buf = &self.bytecode[frame.pc..]; - let mut reader = IonReader::new(buf.iter().copied(), 0); - let value = reader.next_value(); - frame.pc += reader.offset(); - frame.stack.push_value(&value); - }, - 0x11 => { // OpCode::TypePop - frame.stack.drop_value(); - }, - 0x12 => { // OpCode::TypeLoad - let var = frame.next_varuint(); - frame.stack.push_value(&frame.variables[var]); - }, - 0x13 => { // OpCode::TypeStore - let var = frame.next_varuint(); - frame.variables[var] = frame.stack.pop_value(); - }, - 0x14 => { // OpCode::TypeLength - let var = frame.next_varuint(); - let buf = frame.variables.get(var).expect("Undefined variable"); - let len = buf.len(); - frame.stack.push_usize(len); - }, - 0x15 => todo!(), // OpCode::BytesAppend - 0x16 => todo!(), // OpCode::ListAppend - 0x17 => todo!(), // OpCode::ListLoad - 0x18 => todo!(), // OpCode::FieldAppend - 0x19 => { // OpCode::Iterate - let (ion_type, end, pos) = { - let mut reader = frame.stack.peek_reader(); - let (ion_type, end) = reader.step_in(); - let pos = reader.offset(); - (ion_type, end, pos) - }; - - frame.stack.push_usize(ion_type as usize); - frame.stack.push_usize(end); - frame.stack.push_usize(pos); - - }, - 0x1A => { // OpCode::Next - let pos = frame.stack.pop_value().to_usize(); - let len = frame.stack.pop_value().to_usize(); - let ion_type = frame.stack.pop_value().to_usize(); - - let next = { - let mut reader = if ion_type == 0x0D { - frame.stack.peek_struct_reader_at(pos) - } else { - frame.stack.peek_reader_at(pos) - }; - reader.skip_value(); - reader.offset() - }; - - frame.stack.push_usize(ion_type); // TODO peek - frame.stack.push_usize(len); // TODO peek - frame.stack.push_usize(next); - }, - 0x1B => { // OpCode::StepIn - let pos = frame.stack.pop_value().to_usize(); - let len = frame.stack.pop_value().to_usize(); - let ion_type = frame.stack.pop_value().to_usize(); - - let (next_type, next_end, next_pos) = { - let mut reader = if ion_type == 0x0D { - frame.stack.peek_struct_reader_at(pos) - } else { - frame.stack.peek_reader_at(pos) - }; - let (next_type, next_end) = reader.step_in(); - let next_pos = reader.offset(); - (next_type, next_end, next_pos) - }; - - frame.stack.push_usize(ion_type); // TODO peek - frame.stack.push_usize(len); // TODO peek - frame.stack.push_usize(pos); // TODO peek - - frame.stack.push_usize(next_type as usize); - frame.stack.push_usize(next_end); - frame.stack.push_usize(next_pos); - }, - 0x1C => { // OpCode::StepOut - frame.stack.drop_value(); - frame.stack.drop_value(); - frame.stack.drop_value(); - }, - 0x1D => { // OpCode::LoadValue - let pos = frame.stack.pop_value().to_usize(); - let len = frame.stack.pop_value().to_usize(); - let ion_type = frame.stack.pop_value().to_usize(); - - let next_value = { - let mut reader = if ion_type == 0x0D { - frame.stack.peek_struct_reader_at(pos) - } else { - frame.stack.peek_reader_at(pos) - }; - reader.next_value() - }; - - frame.stack.push_usize(ion_type); // TODO peek - frame.stack.push_usize(len); // TODO peek - frame.stack.push_usize(pos); // TODO peek - - frame.stack.push_value(&next_value); - }, - 0x1E => { // OpCode::StructField - let pos = frame.stack.pop_value().to_usize(); - let len = frame.stack.pop_value().to_usize(); - let ion_type = frame.stack.pop_value().to_usize(); - - let field_id = { - let mut reader = if ion_type == 0x0D { - frame.stack.peek_struct_reader_at(pos) - } else { - frame.stack.peek_reader_at(pos) - }; - reader.skip_value(); - reader.field_id() + match op { + 0x01 => { // OpType::Jump + let pc = frame.next_u32().try_into().unwrap(); + frame.jump(pc); + }, + 0x02 => { // OpType::Dup + let value1 = frame.stack.pop_value(); + frame.stack.push_value(&value1); + frame.stack.push_value(&value1); + }, + 0x03 => { // OpType::Dup2 + let value1 = frame.stack.pop_value(); + let value2 = frame.stack.pop_value(); + frame.stack.push_value(&value2); + frame.stack.push_value(&value1); + frame.stack.push_value(&value2); + frame.stack.push_value(&value1); + }, + 0x04 => { // OpType::SwapPop + let value1 = frame.stack.pop_value(); + frame.stack.drop_value(); + frame.stack.push_value(&value1); + }, + 0x05 => { // OpType::Invoke + let function_id = frame.next_varuint(); + let function = frame.runtime.0.functions.get(&function_id) + .expect("Undefined function"); + let mut args = Vec::with_capacity(function.arguments as usize); + for _ in 0..function.arguments { + args.push(frame.stack.pop_value()); + } + let mut rx = frame.runtime.invoke(function_id, args); + let mut previous_ret = None; + while let Some(ret) = rx.recv().await { + if let Some(previous_ret) = previous_ret.take() { + let mut branch = frame.clone(); + branch.stack.push_value(&previous_ret); + execute_frame(branch); + } + previous_ret = Some(ret); + } + if let Some(ret) = previous_ret.take() { + frame.stack.push_value(&ret); + } + }, + 0x06 => { // OpType::InvokeGenerator + + }, + 0x07 => { // OpType::Yield + return ExecutionState::Yield(frame.stack.pop_value()); + }, + 0x08 => { // OpType::Return + return ExecutionState::Halt; + }, + 0x10 => { // OpType::Push + let buf = &frame.bytecode[frame.pc..]; + let mut reader = IonReader::new(buf.iter().copied(), 0); + let value = reader.next_value(); + frame.pc += reader.offset(); + frame.stack.push_value(&value); + }, + 0x11 => { // OpCode::TypePop + frame.stack.drop_value(); + }, + 0x12 => { // OpCode::TypeLoad + let var = frame.next_varuint(); + frame.stack.push_value(&frame.variables[var]); + }, + 0x13 => { // OpCode::TypeStore + let var = frame.next_varuint(); + frame.variables[var] = frame.stack.pop_value(); + }, + 0x14 => { // OpCode::TypeLength + let var = frame.next_varuint(); + let buf = frame.variables.get(var).expect("Undefined variable"); + let len = buf.len(); + frame.stack.push_usize(len); + }, + 0x15 => todo!(), // OpCode::BytesAppend + 0x16 => todo!(), // OpCode::ListAppend + 0x17 => todo!(), // OpCode::ListLoad + 0x18 => todo!(), // OpCode::FieldAppend + 0x19 => { // OpCode::Iterate + let (ion_type, end, pos) = { + let mut reader = frame.stack.peek_reader(); + let (ion_type, end) = reader.step_in(); + let pos = reader.offset(); + (ion_type, end, pos) + }; + + frame.stack.push_usize(ion_type as usize); + frame.stack.push_usize(end); + frame.stack.push_usize(pos); + + }, + 0x1A => { // OpCode::Next + let pos = frame.stack.pop_value().to_usize(); + let len = frame.stack.pop_value().to_usize(); + let ion_type = frame.stack.pop_value().to_usize(); + + let next = { + let mut reader = if ion_type == 0x0D { + frame.stack.peek_struct_reader_at(pos) + } else { + frame.stack.peek_reader_at(pos) }; - - frame.stack.push_usize(ion_type); // TODO peek - frame.stack.push_usize(len); // TODO peek - frame.stack.push_usize(pos); // TODO peek - - if let Some(field_id) = field_id { - frame.stack.push_symbol(field_id); + reader.skip_value(); + reader.offset() + }; + + frame.stack.push_usize(ion_type); // TODO peek + frame.stack.push_usize(len); // TODO peek + frame.stack.push_usize(next); + }, + 0x1B => { // OpCode::StepIn + let pos = frame.stack.pop_value().to_usize(); + let len = frame.stack.pop_value().to_usize(); + let ion_type = frame.stack.pop_value().to_usize(); + + let (next_type, next_end, next_pos) = { + let mut reader = if ion_type == 0x0D { + frame.stack.peek_struct_reader_at(pos) } else { - panic!("Not a struct"); - } - }, - 0x21 => self.int_add(frame), // OpCode::IntAdd - 0x22 => todo!(), // OpCode::IntSub - 0x23 => todo!(), // OpCode::IntMul - 0x24 => todo!(), // OpCode::IntDiv - 0x41 => todo!(), // OpCode::FloatAdd - 0x42 => todo!(), // OpCode::FloatSub - 0x43 => todo!(), // OpCode::FloatMul - 0x44 => todo!(), // OpCode::FloatDiv - 0x51 => todo!(), // OpCode::DecimalAdd - 0x52 => todo!(), // OpCode::DecimalSub - 0x53 => todo!(), // OpCode::DecimalMul - 0x54 => todo!(), // OpCode::DecimalDiv - 0x30 => todo!(), // OpCode::IfEq - 0x31 => todo!(), // OpCode::IfNe - 0x32 => todo!(), // OpCode::IfGe - 0x33 => todo!(), // OpCode::IfGt - 0x34 => todo!(), // OpCode::IfLe - 0x35 => todo!(), // OpCode::IfLt - 0x36 => { // OpCode::IfEq2 - let next_pc = frame.next_u32().try_into().unwrap(); - let value1 = frame.stack.pop_value(); - let value2 = frame.stack.pop_value(); - if value1 == value2 { - frame.pc = next_pc; - } - }, - 0x37 => { // OpCode::IfNe2 - let next_pc = frame.next_u32().try_into().unwrap(); - let value1 = frame.stack.pop_value(); - let value2 = frame.stack.pop_value(); - if value1 != value2 { - frame.pc = next_pc; - } - }, - 0x38 => { // OpCode::IfGe2 - let next_pc = frame.next_u32().try_into().unwrap(); - let value1 = frame.stack.pop_value(); - let value2 = frame.stack.pop_value(); - if value1 >= value2 { - frame.pc = next_pc; - } - }, - 0x39 => { // OpCode::IfGt2 - let next_pc = frame.next_u32().try_into().unwrap(); - let value1 = frame.stack.pop_value(); - let value2 = frame.stack.pop_value(); - if value1 > value2 { - frame.pc = next_pc; - } - }, - 0x3A => { // OpCode::IfLe2 - let next_pc = frame.next_u32().try_into().unwrap(); - let value1 = frame.stack.pop_value(); - let value2 = frame.stack.pop_value(); - if value1 <= value2 { - frame.pc = next_pc; - } - }, - 0x3B => { // OpCode::IfLt2 - let next_pc = frame.next_u32().try_into().unwrap(); - let value1 = frame.stack.pop_value(); - let value2 = frame.stack.pop_value(); - if value1 < value2 { - frame.pc = next_pc; - } - }, - - 0xB1 => { // OpCode::NewList - // TODO: Yuck - let len = frame.stack.pop_usize(); - let mut list = Vec::new(); - let mut sz = 0; - for _ in 0..len { - let value = frame.stack.pop_value(); - sz += value.len(); - list.push(value); - } - for v in list { - frame.stack.push_value(&v); - } - if sz >= 14 { - frame.stack.push_varuint(sz); - frame.stack.push_byte(0xBE); + frame.stack.peek_reader_at(pos) + }; + let (next_type, next_end) = reader.step_in(); + let next_pos = reader.offset(); + (next_type, next_end, next_pos) + }; + + frame.stack.push_usize(ion_type); // TODO peek + frame.stack.push_usize(len); // TODO peek + frame.stack.push_usize(pos); // TODO peek + + frame.stack.push_usize(next_type as usize); + frame.stack.push_usize(next_end); + frame.stack.push_usize(next_pos); + }, + 0x1C => { // OpCode::StepOut + frame.stack.drop_value(); + frame.stack.drop_value(); + frame.stack.drop_value(); + }, + 0x1D => { // OpCode::LoadValue + let pos = frame.stack.pop_value().to_usize(); + let len = frame.stack.pop_value().to_usize(); + let ion_type = frame.stack.pop_value().to_usize(); + + let next_value = { + let mut reader = if ion_type == 0x0D { + frame.stack.peek_struct_reader_at(pos) } else { - frame.stack.push_byte(0xB0 | (sz as u8)); - } - }, - - 0xD1 => { // OpCode::NewStruct - // TODO: Yuck - let len = frame.stack.pop_usize(); - let mut pairs = Vec::new(); - for _ in 0..len { - let sym = frame.stack.pop_value(); - let value = frame.stack.pop_value(); - pairs.push((sym, value)); - } - let mark = frame.stack.len(); - for (sym, v) in pairs { - frame.stack.push_value(&v); - frame.stack.push_varuint(sym.reader().next_symbol_id()); - } - let sz = frame.stack.len() - mark; - if sz >= 14 { - frame.stack.push_varuint(sz); - frame.stack.push_byte(0xDE); + frame.stack.peek_reader_at(pos) + }; + reader.next_value() + }; + + frame.stack.push_usize(ion_type); // TODO peek + frame.stack.push_usize(len); // TODO peek + frame.stack.push_usize(pos); // TODO peek + + frame.stack.push_value(&next_value); + }, + 0x1E => { // OpCode::StructField + let pos = frame.stack.pop_value().to_usize(); + let len = frame.stack.pop_value().to_usize(); + let ion_type = frame.stack.pop_value().to_usize(); + + let field_id = { + let mut reader = if ion_type == 0x0D { + frame.stack.peek_struct_reader_at(pos) } else { - frame.stack.push_byte(0xD0 | (sz as u8)); - } - }, - - _ => panic!("Invalid opcode {:02x} at {:02x}", op, frame.pc - 1), - } + frame.stack.peek_reader_at(pos) + }; + reader.skip_value(); + reader.field_id() + }; + + frame.stack.push_usize(ion_type); // TODO peek + frame.stack.push_usize(len); // TODO peek + frame.stack.push_usize(pos); // TODO peek + + if let Some(field_id) = field_id { + frame.stack.push_symbol(field_id); + } else { + panic!("Not a struct"); + } + }, + 0x21 => todo!(), // OpCode::IntAdd + 0x22 => todo!(), // OpCode::IntSub + 0x23 => todo!(), // OpCode::IntMul + 0x24 => todo!(), // OpCode::IntDiv + 0x41 => todo!(), // OpCode::FloatAdd + 0x42 => todo!(), // OpCode::FloatSub + 0x43 => todo!(), // OpCode::FloatMul + 0x44 => todo!(), // OpCode::FloatDiv + 0x51 => todo!(), // OpCode::DecimalAdd + 0x52 => todo!(), // OpCode::DecimalSub + 0x53 => todo!(), // OpCode::DecimalMul + 0x54 => todo!(), // OpCode::DecimalDiv + 0x30 => todo!(), // OpCode::IfEq + 0x31 => todo!(), // OpCode::IfNe + 0x32 => todo!(), // OpCode::IfGe + 0x33 => todo!(), // OpCode::IfGt + 0x34 => todo!(), // OpCode::IfLe + 0x35 => todo!(), // OpCode::IfLt + 0x36 => { // OpCode::IfEq2 + let next_pc = frame.next_u32().try_into().unwrap(); + let value1 = frame.stack.pop_value(); + let value2 = frame.stack.pop_value(); + if value1 == value2 { + frame.pc = next_pc; + } + }, + 0x37 => { // OpCode::IfNe2 + let next_pc = frame.next_u32().try_into().unwrap(); + let value1 = frame.stack.pop_value(); + let value2 = frame.stack.pop_value(); + if value1 != value2 { + frame.pc = next_pc; + } + }, + 0x38 => { // OpCode::IfGe2 + let next_pc = frame.next_u32().try_into().unwrap(); + let value1 = frame.stack.pop_value(); + let value2 = frame.stack.pop_value(); + if value1 >= value2 { + frame.pc = next_pc; + } + }, + 0x39 => { // OpCode::IfGt2 + let next_pc = frame.next_u32().try_into().unwrap(); + let value1 = frame.stack.pop_value(); + let value2 = frame.stack.pop_value(); + if value1 > value2 { + frame.pc = next_pc; + } + }, + 0x3A => { // OpCode::IfLe2 + let next_pc = frame.next_u32().try_into().unwrap(); + let value1 = frame.stack.pop_value(); + let value2 = frame.stack.pop_value(); + if value1 <= value2 { + frame.pc = next_pc; + } + }, + 0x3B => { // OpCode::IfLt2 + let next_pc = frame.next_u32().try_into().unwrap(); + let value1 = frame.stack.pop_value(); + let value2 = frame.stack.pop_value(); + if value1 < value2 { + frame.pc = next_pc; + } + }, + + 0xB1 => { // OpCode::NewList + // TODO: Yuck + let len = frame.stack.pop_usize(); + let mut list = Vec::new(); + let mut sz = 0; + for _ in 0..len { + let value = frame.stack.pop_value(); + sz += value.len(); + list.push(value); + } + for v in list { + frame.stack.push_value(&v); + } + if sz >= 14 { + frame.stack.push_varuint(sz); + frame.stack.push_byte(0xBE); + } else { + frame.stack.push_byte(0xB0 | (sz as u8)); + } + }, + + 0xD1 => { // OpCode::NewStruct + // TODO: Yuck + let len = frame.stack.pop_usize(); + let mut pairs = Vec::new(); + for _ in 0..len { + let sym = frame.stack.pop_value(); + let value = frame.stack.pop_value(); + pairs.push((sym, value)); + } + let mark = frame.stack.len(); + for (sym, v) in pairs { + frame.stack.push_value(&v); + frame.stack.push_varuint(sym.reader().next_symbol_id()); + } + let sz = frame.stack.len() - mark; + if sz >= 14 { + frame.stack.push_varuint(sz); + frame.stack.push_byte(0xDE); + } else { + frame.stack.push_byte(0xD0 | (sz as u8)); + } + }, - ExecutionState::Continue + _ => panic!("Invalid opcode {:02x} at {:02x}", op, frame.pc - 1), } - fn int_add(&self, frame: &mut StackFrame) { - todo!() - } + ExecutionState::Continue } impl StackFrame { - pub fn new(bytecode: Arc, func: &Function, arguments: Vec) -> StackFrame { + pub fn new(runtime: Runtime, tx: Sender, func: &Function, arguments: Vec) -> StackFrame { let stack = Stack::new(func.expected_stack_depth); let mut frame = StackFrame { - bytecode, + bytecode: runtime.0.bytecode.clone(), pc: func.pc, variables: arguments, stack, + tx, + runtime, }; for _ in func.arguments..func.variables { @@ -638,13 +706,6 @@ impl StackFrame { b } - fn next_bytes(&mut self, len: usize) -> &[u8] { - let end = self.pc + len; - let bytes = &self.bytecode[self.pc..end]; - self.pc = end; - bytes - } - fn next_u32(&mut self) -> u32 { let mut v: u32 = 0; for _ in 0..4 { -- cgit v1.2.3