diff options
Diffstat (limited to 'src/runtime.rs')
-rw-r--r-- | src/runtime.rs | 61 |
1 files changed, 42 insertions, 19 deletions
diff --git a/src/runtime.rs b/src/runtime.rs index 97de85a..56b565e 100644 --- a/src/runtime.rs +++ b/src/runtime.rs @@ -37,6 +37,11 @@ pub enum OpCode { /// stack: Return = 0x08, + /// Invoke a function + /// operands: + /// stack: [arguments..., function id] -> [return value?] + InvokeDynamic = 0x09, + /// Push a typed Ion value onto the stack. /// operands: T and L /// length @@ -352,6 +357,29 @@ fn execute_frame(mut frame: StackFrame) { }); } +#[inline] +async fn invoke_function(frame: &mut StackFrame, function_id: usize) { + 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); + } +} + async fn execute(frame: &mut StackFrame) -> ExecutionState { if frame.eof() { return ExecutionState::Halt; @@ -393,25 +421,11 @@ async fn execute(frame: &mut StackFrame) -> ExecutionState { }, 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); - } + invoke_function(frame, function_id).await; + }, + 0x09 => { // OpType::InvokeDynamic + let function_id = frame.stack.pop_symbol(); + invoke_function(frame, function_id).await; }, 0x06 => { // OpType::InvokeGenerator let function_id = frame.next_varuint(); @@ -785,6 +799,15 @@ impl Stack { value } + pub fn pop_symbol(&mut self) -> usize { + let mut it = IonReader::new(self.0.iter().copied().rev(), 0); + let value = it.next_symbol_id(); + let offset = it.offset(); + self.0.truncate(self.0.len() - offset); + value + } + + #[inline] pub fn push_byte(&mut self, value: u8) { self.0.push(value); |