aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--src/compiler.rs3
-rw-r--r--src/lib.rs12
-rw-r--r--src/vm.rs41
3 files changed, 53 insertions, 3 deletions
diff --git a/src/compiler.rs b/src/compiler.rs
index ec78118..361d93a 100644
--- a/src/compiler.rs
+++ b/src/compiler.rs
@@ -917,6 +917,9 @@ impl Compiler {
if let Entry::Occupied(entry) = self.unkowns.entry(String::from(name)) {
let (_, (slot, _)) = entry.remove_entry();
self.constants[slot] = self.constants.pop().unwrap();
+ add_op(self, block, Op::Link(slot));
+ } else {
+ add_op(self, block, Op::Link(self.constants.len() - 1));
}
return;
}
diff --git a/src/lib.rs b/src/lib.rs
index 8821710..b39b4bb 100644
--- a/src/lib.rs
+++ b/src/lib.rs
@@ -480,6 +480,12 @@ pub enum Op {
/// Does not affect the stack.
Define(usize),
+ /// Links the upvalues for the given constant
+ /// function. This updates the constant stack.
+ ///
+ /// Does not affect the stack.
+ Link(usize),
+
/// Calls "something" with the given number
/// of arguments. The callable value is
/// then replaced with the result.
@@ -1275,11 +1281,11 @@ f :: fn -> fn -> {
g := f()
g()
-q <=> 3
+q <=> 1
g()
-q <=> 4
+q <=> 2
g()
-q <=> 5
+q <=> 3
",
);
diff --git a/src/vm.rs b/src/vm.rs
index b292a79..f5c1cf0 100644
--- a/src/vm.rs
+++ b/src/vm.rs
@@ -258,6 +258,34 @@ impl VM {
self.push(value);
}
+ Op::Link(slot) => {
+ let offset = self.frame().stack_offset;
+ let constant = self.constant(slot).clone();
+ let constant = match constant {
+ Value::Function(_, block) => {
+ let mut ups = Vec::new();
+ for (slot, is_up, _) in block.borrow().upvalues.iter() {
+ let up = if *is_up {
+ if let Value::Function(local_ups, _) = &self.stack[offset] {
+ Rc::clone(&local_ups[*slot])
+ } else {
+ unreachable!()
+ }
+ } else {
+ let slot = self.frame().stack_offset + slot;
+ Rc::clone(self.find_upvalue(slot))
+ };
+ ups.push(up);
+ }
+ Value::Function(ups, block)
+ },
+ value => error!(self,
+ ErrorKind::RuntimeTypeError(op, vec![value.clone()]),
+ format!("Not a function {:?}.", value)),
+ };
+ self.constants[slot] = constant;
+ }
+
Op::Index => {
let slot = self.stack.pop().unwrap();
let val = self.stack.pop().unwrap();
@@ -638,6 +666,19 @@ impl VM {
}
}
+ Op::Link(slot) => {
+ println!("{:?}", self.constants);
+ println!("{:?} - {}", self.constant(slot), slot);
+ match self.constant(slot).clone() {
+ Value::Function(_, _) => {}
+ value => {
+ error!(self,
+ ErrorKind::TypeError(op, vec![Type::from(&value)]),
+ format!("Cannot link non-function {:?}.", value));
+ }
+ };
+ }
+
Op::Call(num_args) => {
let new_base = self.stack.len() - 1 - num_args;
match self.stack[new_base].clone() {