summaryrefslogtreecommitdiff
path: root/src
diff options
context:
space:
mode:
Diffstat (limited to 'src')
-rw-r--r--src/ion.rs2
-rw-r--r--src/js.rs16
-rw-r--r--src/main.rs12
-rw-r--r--src/runtime.rs679
4 files changed, 392 insertions, 317 deletions
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<u8>);
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<boa_parser::Error> 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<OpCode> for u8 {
}
}
-pub struct Runtime {
+#[derive(Clone)]
+pub struct Runtime(Arc<RuntimeInner>);
+
+pub struct RuntimeInner {
symbols: SymbolTable,
bytecode: Arc<ByteCode>,
functions: BTreeMap<usize, Function>,
- stacks: LinkedList<StackFrame>,
+ channel_buffer_size: usize,
}
pub enum ExecutionState {
Continue,
+ Yield(IonValue),
Halt,
}
@@ -269,352 +289,400 @@ pub struct Function {
pub type ByteCode = Vec<u8>;
+#[derive(Clone)]
struct Stack(Vec<u8>);
+#[derive(Clone)]
pub struct StackFrame {
+ runtime: Runtime,
bytecode: Arc<ByteCode>,
pc: usize,
variables: Vec<IonValue>,
stack: Stack,
+ tx: Sender<IonValue>,
}
-impl Runtime {
+pub type ExecutionStream = mpsc::Receiver<IonValue>;
+
+
+impl Runtime {
pub fn new(symbols: SymbolTable, bytecode: ByteCode, functions: Vec<Function>) -> 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<S>(&self, s: S) -> Option<usize>
where S: AsRef<str>
{
- 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<IonValue>) -> ExecutionStream {
+ let (tx, rx) = mpsc::channel::<IonValue>(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<IonValue>) -> Vec<IonValue> {
- 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<ByteCode>, func: &Function, arguments: Vec<IonValue>) -> StackFrame {
+ pub fn new(runtime: Runtime, tx: Sender<IonValue>, func: &Function, arguments: Vec<IonValue>) -> 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 {