diff options
author | Jesse Morgan <jesse@jesterpm.net> | 2024-01-01 19:41:30 -0800 |
---|---|---|
committer | Jesse Morgan <jesse@jesterpm.net> | 2024-01-01 19:41:30 -0800 |
commit | 40ce26ce1e97cf46c598c7a510fa9c8a2162b5fa (patch) | |
tree | 05f78878174c7bf4fd1f26d61cc575713ef57c52 /src/runtime.rs | |
parent | 76420739e01cb925eca57845bb4704e97d6c816a (diff) |
So far this only works if the function is defined before it is called.
Otherwise, it fails in confusing ways. The problem is that I currently
assume identifiers are always variables, but functions are currently
never variables. Functions are currently treated as special case when
they are declared. I'll need to rethink that...
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); |