summaryrefslogtreecommitdiff
path: root/src/runtime.rs
diff options
context:
space:
mode:
authorJesse Morgan <jesse@jesterpm.net>2024-01-01 19:41:30 -0800
committerJesse Morgan <jesse@jesterpm.net>2024-01-01 19:41:30 -0800
commit40ce26ce1e97cf46c598c7a510fa9c8a2162b5fa (patch)
tree05f78878174c7bf4fd1f26d61cc575713ef57c52 /src/runtime.rs
parent76420739e01cb925eca57845bb4704e97d6c816a (diff)
Add support for calling functions.HEADmaster
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.rs61
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);