DEV: The beginnings of a runtime for the opcode vm.

This commit is contained in:
Jeremy Wall 2019-07-17 18:54:19 -05:00
parent fa2ad0c5a9
commit a7aab10723
7 changed files with 437 additions and 189 deletions

View File

@ -102,6 +102,31 @@ pub struct AssertCollector {
pub failures: String, pub failures: String,
} }
impl AssertCollector {
pub fn new() -> Self {
Self {
counter: 0,
success: true,
summary: String::new(),
failures: String::new(),
}
}
fn record_assert_result(&mut self, msg: &str, is_success: bool) {
if !is_success {
let msg = format!("{} - NOT OK: {}\n", self.counter, msg);
self.summary.push_str(&msg);
self.failures.push_str(&msg);
self.success = false;
} else {
let msg = format!("{} - OK: {}\n", self.counter, msg);
self.summary.push_str(&msg);
}
self.counter += 1;
}
}
/// Builder handles building ucg code for a single file. /// Builder handles building ucg code for a single file.
pub struct FileBuilder<'a, C> pub struct FileBuilder<'a, C>
where where
@ -169,12 +194,7 @@ where
std: Rc::new(stdlib::get_libs()), std: Rc::new(stdlib::get_libs()),
import_path: import_paths, import_path: import_paths,
validate_mode: false, validate_mode: false,
assert_collector: AssertCollector { assert_collector: AssertCollector::new(),
counter: 0,
success: true,
summary: String::new(),
failures: String::new(),
},
scope: scope, scope: scope,
import_registry: ImporterRegistry::make_registry(), import_registry: ImporterRegistry::make_registry(),
converter_registry: converter_registry, converter_registry: converter_registry,
@ -1686,19 +1706,6 @@ where
}; };
} }
fn record_assert_result(&mut self, msg: &str, is_success: bool) {
if !is_success {
let msg = format!("{} - NOT OK: {}\n", self.assert_collector.counter, msg);
self.assert_collector.summary.push_str(&msg);
self.assert_collector.failures.push_str(&msg);
self.assert_collector.success = false;
} else {
let msg = format!("{} - OK: {}\n", self.assert_collector.counter, msg);
self.assert_collector.summary.push_str(&msg);
}
self.assert_collector.counter += 1;
}
fn eval_assert(&mut self, expr: &Expression, scope: &Scope) -> Result<Rc<Val>, Box<dyn Error>> { fn eval_assert(&mut self, expr: &Expression, scope: &Scope) -> Result<Rc<Val>, Box<dyn Error>> {
if !self.validate_mode { if !self.validate_mode {
// we are not in validate_mode so build_asserts are noops. // we are not in validate_mode so build_asserts are noops.
@ -1715,7 +1722,7 @@ where
Err(e) => { Err(e) => {
// failure! // failure!
let msg = format!("CompileError: {}\nfor expression:\n{}\n", e, expr_pretty); let msg = format!("CompileError: {}\nfor expression:\n{}\n", e, expr_pretty);
self.record_assert_result(&msg, false); self.assert_collector.record_assert_result(&msg, false);
return Ok(Rc::new(Val::Empty)); return Ok(Rc::new(Val::Empty));
} }
}; };
@ -1730,7 +1737,7 @@ where
"TYPE FAIL - Expected Boolean field ok in tuple {}, line: {}, column: {}", "TYPE FAIL - Expected Boolean field ok in tuple {}, line: {}, column: {}",
ok.as_ref(), expr.pos().line, expr.pos().column ok.as_ref(), expr.pos().line, expr.pos().column
); );
self.record_assert_result(&msg, false); self.assert_collector.record_assert_result(&msg, false);
return Ok(Rc::new(Val::Empty)); return Ok(Rc::new(Val::Empty));
} }
}, },
@ -1739,7 +1746,7 @@ where
"TYPE FAIL - Expected Boolean field ok in tuple {}, line: {}, column: {}", "TYPE FAIL - Expected Boolean field ok in tuple {}, line: {}, column: {}",
ok.as_ref(), expr.pos().line, expr.pos().column ok.as_ref(), expr.pos().line, expr.pos().column
); );
self.record_assert_result(&msg, false); self.assert_collector.record_assert_result(&msg, false);
return Ok(Rc::new(Val::Empty)); return Ok(Rc::new(Val::Empty));
} }
}; };
@ -1751,7 +1758,7 @@ where
"TYPE FAIL - Expected String field desc in tuple {} line: {}, column: {}", "TYPE FAIL - Expected String field desc in tuple {} line: {}, column: {}",
ok, expr.pos().line, expr.pos().column ok, expr.pos().line, expr.pos().column
); );
self.record_assert_result(&msg, false); self.assert_collector.record_assert_result(&msg, false);
return Ok(Rc::new(Val::Empty)); return Ok(Rc::new(Val::Empty));
} }
}, },
@ -1760,11 +1767,11 @@ where
"TYPE FAIL - Expected String field desc in tuple {} line: {}, column: {}\n", "TYPE FAIL - Expected String field desc in tuple {} line: {}, column: {}\n",
ok, expr.pos().line, expr.pos().column ok, expr.pos().line, expr.pos().column
); );
self.record_assert_result(&msg, false); self.assert_collector.record_assert_result(&msg, false);
return Ok(Rc::new(Val::Empty)); return Ok(Rc::new(Val::Empty));
} }
}; };
self.record_assert_result(&desc, ok_field); self.assert_collector.record_assert_result(&desc, ok_field);
} }
&Val::Empty &Val::Empty
| &Val::Boolean(_) | &Val::Boolean(_)
@ -1780,7 +1787,7 @@ where
"TYPE FAIL - Expected tuple with ok and desc fields got {} at line: {} column: {}\n", "TYPE FAIL - Expected tuple with ok and desc fields got {} at line: {} column: {}\n",
ok, expr.pos().line, expr.pos().column ok, expr.pos().line, expr.pos().column
); );
self.record_assert_result(&msg, false); self.assert_collector.record_assert_result(&msg, false);
return Ok(Rc::new(Val::Empty)); return Ok(Rc::new(Val::Empty));
} }
} }

44
src/build/opcode/cache.rs Normal file
View File

@ -0,0 +1,44 @@
// Copyright 2019 Jeremy Wall
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
// http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.
use std::collections::btree_map;
use std::collections::BTreeMap;
use std::rc::Rc;
use super::{Op, OpPointer};
/// A Cache of Op codes.
pub struct Ops {
ops: BTreeMap<String, Rc<Vec<Op>>>,
}
impl Ops {
pub fn new() -> Self {
Self {
ops: BTreeMap::new(),
}
}
pub fn entry<'a, S: Into<String>>(&'a mut self, path: S) -> Entry<'a> {
Entry(self.ops.entry(path.into()))
}
}
pub struct Entry<'a>(btree_map::Entry<'a, String, Rc<Vec<Op>>>);
impl<'a> Entry<'a> {
pub fn get_pointer_or_else<F: FnOnce() -> Vec<Op>>(self, f: F) -> OpPointer {
let cached = self.0.or_insert_with(|| Rc::new(f())).clone();
OpPointer::new(cached)
}
}

View File

@ -11,7 +11,11 @@
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and // See the License for the specific language governing permissions and
// limitations under the License. // limitations under the License.
use std::rc::Rc;
mod cache;
pub mod pointer; pub mod pointer;
mod runtime;
pub mod scope; pub mod scope;
mod vm; mod vm;
@ -32,8 +36,8 @@ pub enum Primitive {
#[derive(Debug, PartialEq, Clone)] #[derive(Debug, PartialEq, Clone)]
pub enum Composite { pub enum Composite {
List(Vec<Value>), List(Vec<Rc<Value>>),
Tuple(Vec<(String, Value)>), Tuple(Vec<(String, Rc<Value>)>),
} }
#[derive(Debug, PartialEq, Clone)] #[derive(Debug, PartialEq, Clone)]
@ -47,7 +51,7 @@ pub struct Func {
pub struct Module { pub struct Module {
ptr: OpPointer, ptr: OpPointer,
result_ptr: Option<usize>, result_ptr: Option<usize>,
flds: Vec<(String, Value)>, flds: Vec<(String, Rc<Value>)>,
} }
#[derive(Debug, PartialEq, Clone)] #[derive(Debug, PartialEq, Clone)]
@ -66,6 +70,18 @@ pub enum Value {
M(Module), M(Module),
} }
#[derive(Debug, PartialEq, Clone)]
pub enum Hook {
Map,
Include,
Filter,
Reduce,
Import,
Out,
Assert,
Convert,
}
#[derive(Debug, PartialEq, Clone)] #[derive(Debug, PartialEq, Clone)]
pub enum Op { pub enum Op {
// Stack and Name manipulation. // Stack and Name manipulation.
@ -115,13 +131,7 @@ pub enum Op {
// Calls // Calls
FCall, FCall,
// Runtime hooks // Runtime hooks
// - Map, Runtime(Hook),
// - Filter,
// - Reduce,
// - Import,
// - Out,
// - Assert,
// - Convert,
} }
#[derive(Debug)] #[derive(Debug)]

156
src/build/opcode/runtime.rs Normal file
View File

@ -0,0 +1,156 @@
// Copyright 2019 Jeremy Wall
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
// http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.
use std::collections::BTreeMap;
use std::rc::Rc;
use super::cache;
use super::VM;
use super::{Composite, Error, Hook, Primitive, Value};
use crate::build::AssertCollector;
use Composite::Tuple;
use Primitive::{Bool, Str};
pub struct Builtins {
op_cache: cache::Ops,
val_cache: BTreeMap<String, Rc<Value>>,
assert_results: AssertCollector,
// TODO(jwall): IO sink for stderr
// TODO(jwall): IO sink for stdout
}
impl Builtins {
pub fn new() -> Self {
Self {
op_cache: cache::Ops::new(),
val_cache: BTreeMap::new(),
assert_results: AssertCollector::new(),
}
}
pub fn handle(&mut self, h: Hook, stack: &mut Vec<Rc<Value>>) -> Result<(), Error> {
match h {
Hook::Import => self.import(stack),
Hook::Include => self.include(stack),
Hook::Assert => self.assert(stack),
Hook::Convert => self.convert(stack),
Hook::Out => self.out(stack),
Hook::Map => self.map(stack),
Hook::Filter => self.filter(stack),
Hook::Reduce => self.reduce(stack),
}
}
fn import(&mut self, stack: &mut Vec<Rc<Value>>) -> Result<(), Error> {
let path = stack.pop();
if let Some(val) = path {
if let &Value::P(Str(ref path)) = val.as_ref() {
if self.val_cache.contains_key(path) {
stack.push(self.val_cache[path].clone());
} else {
let op_pointer = self.op_cache.entry(path).get_pointer_or_else(|| {
// TODO(jwall): import
unimplemented!("Compiling paths are not implemented yet");
});
let mut vm = VM::with_pointer(op_pointer);
vm.run()?;
let result = Rc::new(vm.symbols_to_tuple(true));
self.val_cache.insert(path.clone(), result.clone());
stack.push(result);
}
return Ok(());
}
}
return Err(Error {});
}
fn include(&self, stack: &mut Vec<Rc<Value>>) -> Result<(), Error> {
// TODO(jwall): include
let path = stack.pop();
if let Some(val) = path {
if let &Value::P(Str(ref path)) = val.as_ref() {}
unimplemented!("TODO(jwall): Includes are not implemented yet")
}
return Err(Error {});
}
fn assert(&mut self, stack: &mut Vec<Rc<Value>>) -> Result<(), Error> {
// TODO(jwall): assert
let tuple = stack.pop();
if let Some(val) = tuple.clone() {
if let &Value::C(Tuple(ref tuple)) = val.as_ref() {
// look for the description field
let mut desc = None;
// look for the ok field.
let mut ok = None;
for &(ref name, ref val) in tuple.iter() {
if name == "description" {
desc = Some(val.clone());
}
if name == "ok" {
ok = Some(val.clone());
}
}
if let (Some(ok), Some(desc)) = (ok, desc) {
if let (&Value::P(Bool(ref b)), &Value::P(Str(ref desc))) =
(ok.as_ref(), desc.as_ref())
{
self.assert_results.record_assert_result(desc, *b);
return Ok(());
}
}
}
}
let msg = format!(
"TYPE FAIL - Expected tuple with ok and desc fields got {:?} at line: {} column: {}\n",
tuple, "TODO", "TODO"
);
self.assert_results.record_assert_result(&msg, false);
return Ok(());
}
fn convert(&self, stack: &mut Vec<Rc<Value>>) -> Result<(), Error> {
// TODO(jwall): convert
let val = stack.pop();
if let Some(val) = val {
unimplemented!("TODO(jwall): Conversions are not implemented yet")
} else {
Err(Error {})
}
}
fn out(&self, stack: &mut Vec<Rc<Value>>) -> Result<(), Error> {
// TODO(jwall): out
let val = stack.pop();
if let Some(val) = val {
unimplemented!("TODO(jwall): Out expressions are not implemented yet")
} else {
Err(Error {})
}
}
fn map(&self, stack: &mut Vec<Rc<Value>>) -> Result<(), Error> {
// TODO(jwall): map (combine these into one?)
unimplemented!("TODO(jwall): Map expressions are not implemented yet")
}
fn filter(&self, stack: &mut Vec<Rc<Value>>) -> Result<(), Error> {
// TODO(jwall): filter
unimplemented!("TODO(jwall): Filter expressions are not implemented yet")
}
fn reduce(&self, stack: &mut Vec<Rc<Value>>) -> Result<(), Error> {
// TODO(jwall): reduce
unimplemented!("TODO(jwall): Reduce expressions are not implemented yet")
}
}

View File

@ -13,13 +13,14 @@
// limitations under the License. // limitations under the License.
use std::collections::{BTreeMap, BTreeSet}; use std::collections::{BTreeMap, BTreeSet};
use std::iter::FromIterator; use std::iter::FromIterator;
use std::rc::Rc;
use super::{Error, Value}; use super::{Error, Value};
#[derive(Clone, PartialEq, Debug)] #[derive(Clone, PartialEq, Debug)]
pub enum Bindings { pub enum Bindings {
Sealed(BTreeMap<String, Value>), Sealed(BTreeMap<String, Rc<Value>>),
Open(BTreeMap<String, Value>), Open(BTreeMap<String, Rc<Value>>),
} }
use Bindings::{Open, Sealed}; use Bindings::{Open, Sealed};
@ -42,14 +43,14 @@ impl Bindings {
} }
} }
pub fn get(&self, name: &str) -> Option<&Value> { pub fn get(&self, name: &str) -> Option<Rc<Value>> {
match self { match self {
Open(flds) => flds.get(name), Open(flds) => flds.get(name).cloned(),
Sealed(flds) => flds.get(name), Sealed(flds) => flds.get(name).cloned(),
} }
} }
pub fn add(&mut self, name: String, val: Value) { pub fn add(&mut self, name: String, val: Rc<Value>) {
match self { match self {
Sealed(flds) => flds.insert(name, val), Sealed(flds) => flds.insert(name, val),
Open(flds) => flds.insert(name, val), Open(flds) => flds.insert(name, val),
@ -78,26 +79,17 @@ impl Stack {
} }
} }
pub fn get(&self, name: &str) -> Option<&Value> { pub fn get(&self, name: &str) -> Option<Rc<Value>> {
match &self.curr { match &self.curr {
Sealed(flds) => flds.get(name), Sealed(flds) => flds.get(name).cloned(),
Open(flds) => { Open(flds) => {
if let Some(v) = flds.get(name) { if let Some(v) = flds.get(name) {
return Some(v); return Some(v.clone());
} else { } else {
for b in self.prev.iter() { for b in self.prev.iter() {
match b { match b {
Sealed(bflds) => { Sealed(bflds) => return bflds.get(name).cloned(),
if let Some(v) = bflds.get(name) { Open(bflds) => return bflds.get(name).cloned(),
return Some(v);
}
return None;
}
Open(bflds) => {
if let Some(v) = bflds.get(name) {
return Some(v);
}
}
} }
} }
} }
@ -132,7 +124,7 @@ impl Stack {
} }
} }
pub fn add(&mut self, name: String, val: Value) { pub fn add(&mut self, name: String, val: Rc<Value>) {
self.curr.add(name, val); self.curr.add(name, val);
} }

View File

@ -29,7 +29,7 @@ macro_rules! assert_cases {
for case in $cases.drain(0..) { for case in $cases.drain(0..) {
let mut vm = VM::new(Rc::new(case.0)); let mut vm = VM::new(Rc::new(case.0));
vm.run().unwrap(); vm.run().unwrap();
assert_eq!(dbg!(vm.pop()).unwrap(), case.1); assert_eq!(dbg!(vm.pop()).unwrap(), Rc::new(case.1));
} }
}; };
@ -92,7 +92,7 @@ fn test_bind_op() {
vm.run().unwrap(); vm.run().unwrap();
let (name, result) = case.1; let (name, result) = case.1;
let v = vm.get_binding(name).unwrap(); let v = vm.get_binding(name).unwrap();
assert_eq!(&result, v); assert_eq!(&result, v.as_ref());
} }
} }
@ -100,8 +100,8 @@ fn test_bind_op() {
fn test_list_ops() { fn test_list_ops() {
assert_cases!( assert_cases!(
vec![InitList] => C(List(Vec::new())), vec![InitList] => C(List(Vec::new())),
vec![InitList, Val(Int(1)), Element] => C(List(vec![P(Int(1))])), vec![InitList, Val(Int(1)), Element] => C(List(vec![Rc::new(P(Int(1)))])),
vec![InitList, Val(Int(2)), Element, Val(Int(1)), Element] => C(List(vec![P(Int(2)), P(Int(1))])), vec![InitList, Val(Int(2)), Element, Val(Int(1)), Element] => C(List(vec![Rc::new(P(Int(2))), Rc::new(P(Int(1)))])),
vec![ vec![
InitList, InitList,
Val(Int(1)), Val(Int(1)),
@ -110,7 +110,7 @@ fn test_list_ops() {
Val(Int(1)), Val(Int(1)),
Add, Add,
Element, Element,
] => C(List(vec![P(Int(1)), P(Int(2))])), ] => C(List(vec![Rc::new(P(Int(1))), Rc::new(P(Int(2)))])),
); );
} }
@ -118,7 +118,14 @@ fn test_list_ops() {
fn test_tuple_ops() { fn test_tuple_ops() {
assert_cases!( assert_cases!(
vec![InitTuple] => C(Tuple(Vec::new())), vec![InitTuple] => C(Tuple(Vec::new())),
vec![InitTuple, Val(Str("foo".to_owned())), Val(Int(1)), Field] => C(Tuple(vec![("foo".to_owned(), P(Int(1)))])), vec![
InitTuple,
Val(Str("foo".to_owned())),
Val(Int(1)),
Field,
] => C(Tuple(vec![
("foo".to_owned(), Rc::new(P(Int(1)))),
])),
vec![ vec![
InitTuple, InitTuple,
Sym("bar".to_owned()), Sym("bar".to_owned()),
@ -128,8 +135,8 @@ fn test_tuple_ops() {
Val(Int(1)), Val(Int(1)),
Field, Field,
] => C(Tuple(vec![ ] => C(Tuple(vec![
("bar".to_owned(), P(Str("quux".to_owned()))), ("bar".to_owned(), Rc::new(P(Str("quux".to_owned())))),
("foo".to_owned(), P(Int(1))), ("foo".to_owned(), Rc::new(P(Int(1)))),
])), ])),
vec![ vec![
InitTuple, InitTuple,
@ -143,8 +150,8 @@ fn test_tuple_ops() {
Val(Int(2)), Val(Int(2)),
Field, Field,
] => C(Tuple(vec![ ] => C(Tuple(vec![
("bar".to_owned(), P(Str("quux".to_owned()))), ("bar".to_owned(), Rc::new(P(Str("quux".to_owned())))),
("foo".to_owned(), P(Int(2))), ("foo".to_owned(), Rc::new(P(Int(2)))),
])), ])),
vec![ vec![
InitTuple, InitTuple,
@ -160,8 +167,8 @@ fn test_tuple_ops() {
Val(Int(2)), Val(Int(2)),
Field, Field,
] => C(Tuple(vec![ ] => C(Tuple(vec![
("bar".to_owned(), P(Str("quux".to_owned()))), ("bar".to_owned(), Rc::new(P(Str("quux".to_owned())))),
("foo".to_owned(), P(Int(2))), ("foo".to_owned(), Rc::new(P(Int(2)))),
])), ])),
vec![ vec![
InitTuple, // Override tuple InitTuple, // Override tuple
@ -179,8 +186,8 @@ fn test_tuple_ops() {
Field, Field,
Cp, // Do the tuple copy operation Cp, // Do the tuple copy operation
] => C(Tuple(vec![ ] => C(Tuple(vec![
("bar".to_owned(), P(Str("quux".to_owned()))), ("bar".to_owned(), Rc::new(P(Str("quux".to_owned())))),
("foo".to_owned(), P(Int(2))), ("foo".to_owned(), Rc::new(P(Int(2)))),
])), ])),
); );
} }
@ -368,10 +375,10 @@ fn test_module_call() {
] => C(Tuple(vec![ ] => C(Tuple(vec![
( (
"foo".to_owned(), "foo".to_owned(),
C(Tuple(vec![ Rc::new(C(Tuple(vec![
("one".to_owned(), P(Int(11))), ("one".to_owned(), Rc::new(P(Int(11)))),
("two".to_owned(), P(Int(2))), ("two".to_owned(), Rc::new(P(Int(2)))),
])) ])))
), ),
])), ])),
vec![ vec![
@ -486,12 +493,12 @@ fn test_index_operation() {
#[test] #[test]
fn test_scope_stacks() { fn test_scope_stacks() {
let mut stack = Stack::new(); let mut stack = Stack::new();
stack.add("one".to_owned(), P(Int(1))); stack.add("one".to_owned(), Rc::new(P(Int(1))));
let mut val = stack.get("one").unwrap(); let mut val = stack.get("one").unwrap();
assert_eq!(val, &P(Int(1))); assert_eq!(val.as_ref(), &P(Int(1)));
stack.push(); stack.push();
assert!(stack.get("one").is_none()); assert!(stack.get("one").is_none());
stack.to_open(); stack.to_open();
val = stack.get("one").unwrap(); val = stack.get("one").unwrap();
assert_eq!(val, &P(Int(1))); assert_eq!(val.as_ref(), &P(Int(1)));
} }

View File

@ -1,30 +1,34 @@
// Copyright 2019 Jeremy Wall // Copyright 2019 Jeremy Wall
// //
// Licensed under the Apache License, Version 2.0 (the "License"); // Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License. // you may not use this file except in compliance with the License.
// You may obtain a copy of the License at // You may obtain a copy of the License at
// //
// http://www.apache.org/licenses/LICENSE-2.0 // http://www.apache.org/licenses/LICENSE-2.0
// //
// Unless required by applicable law or agreed to in writing, software // Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS, // distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and // See the License for the specific language governing permissions and
// limitations under the License. // limitations under the License.
use std::cell::RefCell;
use std::rc::Rc; use std::rc::Rc;
use super::{Value, Op, Primitive, Error};
use super::scope::{Stack};
use super::pointer::OpPointer; use super::pointer::OpPointer;
use super::runtime;
use super::scope::Stack;
use super::{Error, Op, Primitive, Value};
use super::Value::{C, F, M, T, S, P};
use super::Primitive::{Int, Str, Float, Bool};
use super::Composite::{List, Tuple}; use super::Composite::{List, Tuple};
use super::Hook;
use super::Primitive::{Bool, Float, Int, Str};
use super::Value::{C, F, M, P, S, T};
use super::{Func, Module}; use super::{Func, Module};
pub struct VM { pub struct VM {
stack: Vec<Value>, stack: Vec<Rc<Value>>,
symbols: Stack, symbols: Stack,
runtime: Rc<RefCell<runtime::Builtins>>,
ops: OpPointer, ops: OpPointer,
} }
@ -37,6 +41,7 @@ impl<'a> VM {
Self { Self {
stack: Vec::new(), stack: Vec::new(),
symbols: Stack::new(), symbols: Stack::new(),
runtime: Rc::new(RefCell::new(runtime::Builtins::new())),
ops: ops, ops: ops,
} }
} }
@ -45,10 +50,21 @@ impl<'a> VM {
Self { Self {
stack: Vec::new(), stack: Vec::new(),
symbols: symbols, symbols: symbols,
runtime: self.runtime.clone(),
ops: self.ops.clone(), ops: self.ops.clone(),
} }
} }
pub fn symbols_to_tuple(&self, include_mod: bool) -> Value {
let mut flds = Vec::new();
for sym in self.symbols.symbol_list() {
if include_mod || sym != "mod" {
flds.push((sym.clone(), self.symbols.get(sym).unwrap().clone()));
}
}
return C(Tuple(flds));
}
pub fn run(&mut self) -> Result<(), Error> { pub fn run(&mut self) -> Result<(), Error> {
loop { loop {
let op = if let Some(op) = dbg!(self.ops.next()) { let op = if let Some(op) = dbg!(self.ops.next()) {
@ -58,8 +74,8 @@ impl<'a> VM {
}; };
let idx = self.ops.idx()?; let idx = self.ops.idx()?;
match op { match op {
Op::Val(p) => self.push(dbg!(P(p.clone())))?, Op::Val(p) => self.push(Rc::new(dbg!(P(p.clone()))))?,
Op::Sym(s) => self.push(dbg!(S(s.clone())))?, Op::Sym(s) => self.push(Rc::new(dbg!(S(s.clone()))))?,
Op::DeRef(s) => self.op_deref(s.clone())?, Op::DeRef(s) => self.op_deref(s.clone())?,
Op::Add => self.op_add()?, Op::Add => self.op_add()?,
Op::Sub => self.op_sub()?, Op::Sub => self.op_sub()?,
@ -72,9 +88,9 @@ impl<'a> VM {
Op::GtEq => self.op_gteq()?, Op::GtEq => self.op_gteq()?,
Op::LtEq => self.op_lteq()?, Op::LtEq => self.op_lteq()?,
// Add a Composite list value to the stack // Add a Composite list value to the stack
Op::InitList => self.push(C(List(Vec::new())))?, Op::InitList => self.push(Rc::new(C(List(Vec::new()))))?,
// Add a composite tuple value to the stack // Add a composite tuple value to the stack
Op::InitTuple => self.push(C(Tuple(Vec::new())))?, Op::InitTuple => self.push(Rc::new(C(Tuple(Vec::new()))))?,
Op::Field => self.op_field()?, Op::Field => self.op_field()?,
Op::Element => self.op_element()?, Op::Element => self.op_element()?,
Op::Index => self.op_index()?, Op::Index => self.op_index()?,
@ -96,6 +112,7 @@ impl<'a> VM {
Op::Pop => { Op::Pop => {
self.pop()?; self.pop()?;
} }
Op::Runtime(h) => self.op_runtime(h)?,
}; };
} }
Ok(()) Ok(())
@ -117,7 +134,8 @@ impl<'a> VM {
} }
fn op_jump_if_true(&mut self, jp: i32) -> Result<(), Error> { fn op_jump_if_true(&mut self, jp: i32) -> Result<(), Error> {
if let P(Bool(cond)) = self.pop()? { let cond = self.pop()?;
if let &P(Bool(cond)) = cond.as_ref() {
if cond { if cond {
self.op_jump(jp)?; self.op_jump(jp)?;
} }
@ -126,7 +144,8 @@ impl<'a> VM {
} }
fn op_jump_if_false(&mut self, jp: i32) -> Result<(), Error> { fn op_jump_if_false(&mut self, jp: i32) -> Result<(), Error> {
if let P(Bool(cond)) = self.pop()? { let cond = self.pop()?;
if let &P(Bool(cond)) = cond.as_ref() {
if !cond { if !cond {
self.op_jump(jp)?; self.op_jump(jp)?;
} }
@ -150,11 +169,13 @@ impl<'a> VM {
} }
fn op_module(&'a mut self, idx: usize, jptr: usize) -> Result<(), Error> { fn op_module(&'a mut self, idx: usize, jptr: usize) -> Result<(), Error> {
let (result_ptr, flds) = match self.pop()? { let mod_val = self.pop()?;
C(Tuple(flds)) => (None, flds), let (result_ptr, flds) = match mod_val.as_ref() {
T(ptr) => { &C(Tuple(ref flds)) => (None, flds.clone()),
if let C(Tuple(flds)) = self.pop()? { &T(ptr) => {
(Some(ptr), flds) let tpl_val = self.pop()?;
if let &C(Tuple(ref flds)) = tpl_val.as_ref() {
(Some(ptr), flds.clone())
} else { } else {
return dbg!(Err(Error {})); return dbg!(Err(Error {}));
} }
@ -165,11 +186,11 @@ impl<'a> VM {
}; };
let mut ops = self.ops.clone(); let mut ops = self.ops.clone();
ops.jump(idx)?; ops.jump(idx)?;
self.push(M(Module { self.push(Rc::new(M(Module {
ptr: dbg!(ops), ptr: dbg!(ops),
result_ptr: result_ptr, result_ptr: result_ptr,
flds: dbg!(flds), flds: dbg!(flds),
}))?; })))?;
self.ops.jump(dbg!(jptr)) self.ops.jump(dbg!(jptr))
} }
@ -181,10 +202,11 @@ impl<'a> VM {
eprintln!("Defining a new function"); eprintln!("Defining a new function");
let mut bindings = Vec::new(); let mut bindings = Vec::new();
// get imported symbols from stack // get imported symbols from stack
if let C(List(elems)) = self.pop()? { let list_val = self.pop()?;
if let &C(List(ref elems)) = list_val.as_ref() {
for e in elems { for e in elems {
if let S(sym) = e { if let &S(ref sym) = e.as_ref() {
bindings.push(sym); bindings.push(sym.clone());
} else { } else {
return dbg!(Err(Error {})); return dbg!(Err(Error {}));
} }
@ -195,29 +217,29 @@ impl<'a> VM {
eprintln!("Pushing function definition on stack"); eprintln!("Pushing function definition on stack");
let mut ops = self.ops.clone(); let mut ops = self.ops.clone();
ops.jump(idx)?; ops.jump(idx)?;
self.push(dbg!(F(Func { self.push(Rc::new(dbg!(F(Func {
ptr: ops, // where the function starts. ptr: ops, // where the function starts.
bindings: bindings, bindings: bindings,
snapshot: scope_snapshot, snapshot: scope_snapshot,
})))?; }))))?;
eprintln!("Jumping to {} past the function body", jptr); eprintln!("Jumping to {} past the function body", jptr);
self.ops.jump(jptr) self.ops.jump(jptr)
} }
fn op_fcall(&mut self) -> Result<(), Error> { fn op_fcall(&mut self) -> Result<(), Error> {
let f = self.pop()?; let f = self.pop()?;
if let F(Func { if let &F(Func {
ptr, ref ptr,
bindings, ref bindings,
snapshot, ref snapshot,
}) = f }) = f.as_ref()
{ {
// use the captured scope snapshot for the function. // use the captured scope snapshot for the function.
let mut vm = Self::with_pointer(ptr).to_scoped(snapshot); let mut vm = Self::with_pointer(ptr.clone()).to_scoped(snapshot.clone());
for nm in bindings { for nm in bindings.iter() {
// now put each argument on our scope stack as a binding. // now put each argument on our scope stack as a binding.
let val = self.pop()?; let val = self.pop()?;
vm.binding_push(nm, val)?; vm.binding_push(nm.clone(), val)?;
} }
// proceed to the function body // proceed to the function body
vm.run()?; vm.run()?;
@ -229,26 +251,26 @@ impl<'a> VM {
} }
fn op_thunk(&mut self, idx: usize, jp: i32) -> Result<(), Error> { fn op_thunk(&mut self, idx: usize, jp: i32) -> Result<(), Error> {
self.push(dbg!(T(idx)))?; self.push(Rc::new(dbg!(T(idx))))?;
self.op_jump(jp) self.op_jump(jp)
} }
fn op_equal(&mut self) -> Result<(), Error> { fn op_equal(&mut self) -> Result<(), Error> {
let left = self.pop()?; let left = self.pop()?;
let right = self.pop()?; let right = self.pop()?;
self.push(P(Bool(left == right)))?; self.push(Rc::new(P(Bool(left == right))))?;
Ok(()) Ok(())
} }
fn op_gt(&mut self) -> Result<(), Error> { fn op_gt(&mut self) -> Result<(), Error> {
let left = self.pop()?; let left = self.pop()?;
let right = self.pop()?; let right = self.pop()?;
match (left, right) { match (left.as_ref(), right.as_ref()) {
(P(Int(i)), P(Int(ii))) => { (&P(Int(i)), &P(Int(ii))) => {
self.push(P(Bool(i > ii)))?; self.push(Rc::new(P(Bool(i > ii))))?;
} }
(P(Float(f)), P(Float(ff))) => { (&P(Float(f)), &P(Float(ff))) => {
self.push(P(Bool(f > ff)))?; self.push(Rc::new(P(Bool(f > ff))))?;
} }
_ => return Err(Error {}), _ => return Err(Error {}),
} }
@ -258,12 +280,12 @@ impl<'a> VM {
fn op_lt(&mut self) -> Result<(), Error> { fn op_lt(&mut self) -> Result<(), Error> {
let left = self.pop()?; let left = self.pop()?;
let right = self.pop()?; let right = self.pop()?;
match (left, right) { match (left.as_ref(), right.as_ref()) {
(P(Int(i)), P(Int(ii))) => { (&P(Int(i)), &P(Int(ii))) => {
self.push(P(Bool(i < ii)))?; self.push(Rc::new(P(Bool(i < ii))))?;
} }
(P(Float(f)), P(Float(ff))) => { (&P(Float(f)), &P(Float(ff))) => {
self.push(P(Bool(f < ff)))?; self.push(Rc::new(P(Bool(f < ff))))?;
} }
_ => return Err(Error {}), _ => return Err(Error {}),
} }
@ -273,12 +295,12 @@ impl<'a> VM {
fn op_lteq(&mut self) -> Result<(), Error> { fn op_lteq(&mut self) -> Result<(), Error> {
let left = self.pop()?; let left = self.pop()?;
let right = self.pop()?; let right = self.pop()?;
match (left, right) { match (left.as_ref(), right.as_ref()) {
(P(Int(i)), P(Int(ii))) => { (&P(Int(i)), &P(Int(ii))) => {
self.push(P(Bool(i <= ii)))?; self.push(Rc::new(P(Bool(i <= ii))))?;
} }
(P(Float(f)), P(Float(ff))) => { (&P(Float(f)), &P(Float(ff))) => {
self.push(P(Bool(f <= ff)))?; self.push(Rc::new(P(Bool(f <= ff))))?;
} }
_ => return Err(Error {}), _ => return Err(Error {}),
} }
@ -288,12 +310,12 @@ impl<'a> VM {
fn op_gteq(&mut self) -> Result<(), Error> { fn op_gteq(&mut self) -> Result<(), Error> {
let left = self.pop()?; let left = self.pop()?;
let right = self.pop()?; let right = self.pop()?;
match (left, right) { match (left.as_ref(), right.as_ref()) {
(P(Int(i)), P(Int(ii))) => { (&P(Int(i)), &P(Int(ii))) => {
self.push(P(Bool(i >= ii)))?; self.push(Rc::new(P(Bool(i >= ii))))?;
} }
(P(Float(f)), P(Float(ff))) => { (&P(Float(f)), &P(Float(ff))) => {
self.push(P(Bool(f >= ff)))?; self.push(Rc::new(P(Bool(f >= ff))))?;
} }
_ => return Err(Error {}), _ => return Err(Error {}),
} }
@ -305,7 +327,7 @@ impl<'a> VM {
let left = self.pop()?; let left = self.pop()?;
let right = self.pop()?; let right = self.pop()?;
// Then pushes the result onto the stack. // Then pushes the result onto the stack.
self.push(P(self.add(left, right)?))?; self.push(Rc::new(P(self.add(&left, &right)?)))?;
Ok(()) Ok(())
} }
@ -314,7 +336,7 @@ impl<'a> VM {
let left = self.pop()?; let left = self.pop()?;
let right = self.pop()?; let right = self.pop()?;
// Then pushes the result onto the stack. // Then pushes the result onto the stack.
self.push(P(self.sub(left, right)?))?; self.push(Rc::new(P(self.sub(&left, &right)?)))?;
Ok(()) Ok(())
} }
@ -323,7 +345,7 @@ impl<'a> VM {
let left = self.pop()?; let left = self.pop()?;
let right = self.pop()?; let right = self.pop()?;
// Then pushes the result onto the stack. // Then pushes the result onto the stack.
self.push(P(self.mul(left, right)?))?; self.push(Rc::new(P(self.mul(&left, &right)?)))?;
Ok(()) Ok(())
} }
@ -332,7 +354,7 @@ impl<'a> VM {
let left = self.pop()?; let left = self.pop()?;
let right = self.pop()?; let right = self.pop()?;
// Then pushes the result onto the stack. // Then pushes the result onto the stack.
self.push(P(self.div(left, right)?))?; self.push(Rc::new(P(self.div(&left, &right)?)))?;
Ok(()) Ok(())
} }
@ -341,8 +363,8 @@ impl<'a> VM {
let val = dbg!(self.pop())?; let val = dbg!(self.pop())?;
// pop name off stack. // pop name off stack.
let name = dbg!(self.pop())?; let name = dbg!(self.pop())?;
if let S(name) = name { if let &S(ref name) = name.as_ref() {
self.binding_push(name, val)?; self.binding_push(name.clone(), val)?;
} else { } else {
return Err(Error {}); return Err(Error {});
} }
@ -354,18 +376,22 @@ impl<'a> VM {
// get value from stack // get value from stack
let val = self.pop()?; let val = self.pop()?;
// get name from stack. // get name from stack.
let name = if let S(s) | P(Str(s)) = self.pop()? { let name_val = self.pop()?;
let name = if let &S(ref s) | &P(Str(ref s)) = name_val.as_ref() {
s s
} else { } else {
return Err(Error {}); return Err(Error {});
}; };
// get composite tuple from stack // get composite tuple from stack
let tpl = self.pop()?; let tpl = self.pop()?;
if let C(Tuple(mut flds)) = tpl { if let &C(Tuple(ref flds)) = tpl.as_ref() {
// add name and value to tuple // add name and value to tuple
self.merge_field_into_tuple(&mut flds, name, val)?; // TODO(jwall): This is probably memory inefficient and we should
// optimize it a bit.
let mut flds = flds.clone();
self.merge_field_into_tuple(&mut flds, name.clone(), val)?;
// place composite tuple back on stack // place composite tuple back on stack
self.push(C(Tuple(flds)))?; self.push(Rc::new(C(Tuple(flds))))?;
} else { } else {
return Err(Error {}); return Err(Error {});
}; };
@ -377,20 +403,23 @@ impl<'a> VM {
let val = self.pop()?; let val = self.pop()?;
// get next value. It should be a Composite list. // get next value. It should be a Composite list.
let tpl = self.pop()?; let tpl = self.pop()?;
if let C(List(mut elems)) = tpl { if let &C(List(ref elems)) = tpl.as_ref() {
// add value to list // add value to list
// TODO(jwall): This is probably memory inefficient and we should
// optimize it a bit.
let mut elems = elems.clone();
elems.push(val); elems.push(val);
// Add that value to the list and put list back on stack. // Add that value to the list and put list back on stack.
self.push(C(List(elems)))?; self.push(Rc::new(C(List(elems))))?;
} else { } else {
return Err(Error {}); return Err(Error {});
}; };
Ok(()) Ok(())
} }
fn find_in_list(&self, index: Value, elems: Vec<Value>) -> Result<Value, Error> { fn find_in_list(&self, index: &Value, elems: &Vec<Rc<Value>>) -> Result<Rc<Value>, Error> {
let idx = match index { let idx = match index {
P(Int(i)) => i, P(Int(i)) => i.clone(),
_ => return dbg!(Err(Error {})), _ => return dbg!(Err(Error {})),
}; };
match elems.get(idx as usize) { match elems.get(idx as usize) {
@ -399,21 +428,21 @@ impl<'a> VM {
} }
} }
fn find_in_flds(&self, index: Value, flds: Vec<(String, Value)>) -> Result<Value, Error> { fn find_in_flds(&self, index: &Value, flds: &Vec<(String, Rc<Value>)>) -> Result<Rc<Value>, Error> {
let idx = match index { let idx = match index {
S(p) => p, S(p) => p,
P(Str(p)) => p, P(Str(p)) => p,
_ => return dbg!(Err(Error {})), _ => return dbg!(Err(Error {})),
}; };
for f in flds.iter() { for f in flds.iter() {
if idx == f.0 { if idx == &f.0 {
return Ok(f.1.clone()); return Ok(f.1.clone());
} }
} }
Err(Error {}) Err(Error {})
} }
fn find_in_value(&self, index: Value, target: Value) -> Result<Value, Error> { fn find_in_value(&self, index: &Value, target: &Value) -> Result<Rc<Value>, Error> {
match target { match target {
C(Tuple(flds)) => self.find_in_flds(index, flds), C(Tuple(flds)) => self.find_in_flds(index, flds),
C(List(elements)) => self.find_in_list(index, elements), C(List(elements)) => self.find_in_list(index, elements),
@ -422,17 +451,19 @@ impl<'a> VM {
} }
fn op_index(&mut self) -> Result<(), Error> { fn op_index(&mut self) -> Result<(), Error> {
let path = if let C(List(elems)) = self.pop()? { let path_val = self.pop()?;
elems let path = if let &C(List(ref elems)) = path_val.as_ref() {
elems.clone()
} else { } else {
return dbg!(Err(Error {})); return dbg!(Err(Error {}));
}; };
match self.pop()? { let target_val = self.pop()?;
P(_) | S(_) | T(_) | F(_) | M(_) => return dbg!(Err(Error {})), match target_val.as_ref() {
val => { &P(_) | &S(_) | &T(_) | &F(_) | &M(_) => return dbg!(Err(Error {})),
let mut out = val; _ => {
let mut out = target_val.clone();
for p in path { for p in path {
let tgt = self.find_in_value(p, out)?; let tgt = self.find_in_value(&p, &out)?;
out = tgt; out = tgt;
} }
self.push(out)?; self.push(out)?;
@ -446,50 +477,47 @@ impl<'a> VM {
// get next value. It should be a Module or Tuple. // get next value. It should be a Module or Tuple.
let tgt = dbg!(self.pop())?; let tgt = dbg!(self.pop())?;
// This value should always be a tuple // This value should always be a tuple
let overrides = if let C(Tuple(oflds)) = self.pop()? { let override_val = self.pop()?;
oflds let overrides = if let &C(Tuple(ref oflds)) = override_val.as_ref() {
oflds.clone()
} else { } else {
return dbg!(Err(Error {})); return dbg!(Err(Error {}));
}; };
match tgt { match tgt.as_ref() {
C(Tuple(mut flds)) => { &C(Tuple(ref flds)) => {
let mut flds = flds.clone();
for (name, val) in overrides { for (name, val) in overrides {
dbg!(self.merge_field_into_tuple(&mut flds, name, val))?; dbg!(self.merge_field_into_tuple(&mut flds, name, val))?;
} }
// Put the copy on the Stack // Put the copy on the Stack
self.push(C(Tuple(flds)))?; self.push(Rc::new(C(Tuple(flds))))?;
} }
M(Module { &M(Module {
ptr, ref ptr,
result_ptr, ref result_ptr,
mut flds, ref flds,
}) => { }) => {
//let this = M(Module { //let this = M(Module {
// ptr: ptr.clone(), // ptr: ptr.clone(),
// result_ptr: result_ptr.clone(), // result_ptr: result_ptr.clone(),
// flds: flds.clone(), // flds: flds.clone(),
//}); //});
let mut flds = flds.clone();
for (name, val) in overrides { for (name, val) in overrides {
self.merge_field_into_tuple(&mut flds, name, val)?; self.merge_field_into_tuple(&mut flds, name, val)?;
} }
// FIXME(jwall): We need to populate the pkg key for modules. // FIXME(jwall): We need to populate the pkg key for modules.
//self.merge_field_into_tuple(&mut flds, "this".to_owned(), this)?; //self.merge_field_into_tuple(&mut flds, "this".to_owned(), this)?;
let mut vm = Self::with_pointer(ptr); let mut vm = Self::with_pointer(ptr.clone());
vm.push(S("mod".to_owned()))?; vm.push(Rc::new(S("mod".to_owned())))?;
vm.push(C(Tuple(dbg!(flds))))?; vm.push(Rc::new(C(Tuple(dbg!(flds)))))?;
vm.run()?; vm.run()?;
let mut flds = Vec::new();
if let Some(ptr) = dbg!(result_ptr) { if let Some(ptr) = dbg!(result_ptr) {
vm.ops.jump(ptr)?; vm.ops.jump(ptr.clone())?;
vm.run()?; vm.run()?;
self.push(vm.pop()?)?; self.push(vm.pop()?)?;
} else { } else {
for sym in vm.symbols.symbol_list() { self.push(dbg!(Rc::new(vm.symbols_to_tuple(false))))?;
if sym != "mod" {
flds.push((sym.clone(), vm.symbols.get(sym).unwrap().clone()));
}
}
self.push(dbg!(C(Tuple(flds))))?;
} }
} }
_ => { _ => {
@ -501,9 +529,9 @@ impl<'a> VM {
fn merge_field_into_tuple( fn merge_field_into_tuple(
&self, &self,
src_fields: &'a mut Vec<(String, Value)>, src_fields: &'a mut Vec<(String, Rc<Value>)>,
name: String, name: String,
value: Value, value: Rc<Value>,
) -> Result<(), Error> { ) -> Result<(), Error> {
for fld in src_fields.iter_mut() { for fld in src_fields.iter_mut() {
if fld.0 == name { if fld.0 == name {
@ -515,12 +543,12 @@ impl<'a> VM {
Ok(()) Ok(())
} }
fn push(&mut self, p: Value) -> Result<(), Error> { fn push(&mut self, p: Rc<Value>) -> Result<(), Error> {
self.stack.push(p); self.stack.push(p);
Ok(()) Ok(())
} }
fn binding_push(&mut self, name: String, val: Value) -> Result<(), Error> { fn binding_push(&mut self, name: String, val: Rc<Value>) -> Result<(), Error> {
if self.symbols.is_bound(&name) { if self.symbols.is_bound(&name) {
return Err(Error {}); return Err(Error {});
} }
@ -528,21 +556,21 @@ impl<'a> VM {
Ok(()) Ok(())
} }
pub fn get_binding(&'a self, name: &str) -> Result<&Value, Error> { pub fn get_binding(&'a self, name: &str) -> Result<Rc<Value>, Error> {
match self.symbols.get(name) { match self.symbols.get(name) {
Some(v) => Ok(v), Some(v) => Ok(v),
None => Err(Error {}), None => Err(Error {}),
} }
} }
pub fn pop(&mut self) -> Result<Value, Error> { pub fn pop(&mut self) -> Result<Rc<Value>, Error> {
match self.stack.pop() { match self.stack.pop() {
Some(v) => Ok(v), Some(v) => Ok(v),
None => Err(Error {}), None => Err(Error {}),
} }
} }
fn mul(&self, left: Value, right: Value) -> Result<Primitive, Error> { fn mul(&self, left: &Value, right: &Value) -> Result<Primitive, Error> {
Ok(match (left, right) { Ok(match (left, right) {
(P(Int(i)), P(Int(ii))) => Int(i * ii), (P(Int(i)), P(Int(ii))) => Int(i * ii),
(P(Float(f)), P(Float(ff))) => Float(f * ff), (P(Float(f)), P(Float(ff))) => Float(f * ff),
@ -550,7 +578,7 @@ impl<'a> VM {
}) })
} }
fn div(&self, left: Value, right: Value) -> Result<Primitive, Error> { fn div(&self, left: &Value, right: &Value) -> Result<Primitive, Error> {
Ok(match (left, right) { Ok(match (left, right) {
(P(Int(i)), P(Int(ii))) => Int(i / ii), (P(Int(i)), P(Int(ii))) => Int(i / ii),
(P(Float(f)), P(Float(ff))) => Float(f / ff), (P(Float(f)), P(Float(ff))) => Float(f / ff),
@ -558,7 +586,7 @@ impl<'a> VM {
}) })
} }
fn sub(&self, left: Value, right: Value) -> Result<Primitive, Error> { fn sub(&self, left: &Value, right: &Value) -> Result<Primitive, Error> {
Ok(match (left, right) { Ok(match (left, right) {
(P(Int(i)), Value::P(Int(ii))) => Int(i - ii), (P(Int(i)), Value::P(Int(ii))) => Int(i - ii),
(P(Float(f)), Value::P(Float(ff))) => Float(f - ff), (P(Float(f)), Value::P(Float(ff))) => Float(f - ff),
@ -566,7 +594,7 @@ impl<'a> VM {
}) })
} }
fn add(&self, left: Value, right: Value) -> Result<Primitive, Error> { fn add(&self, left: &Value, right: &Value) -> Result<Primitive, Error> {
Ok(match (left, right) { Ok(match (left, right) {
(P(Int(i)), Value::P(Int(ii))) => Int(i + ii), (P(Int(i)), Value::P(Int(ii))) => Int(i + ii),
(P(Float(f)), Value::P(Float(ff))) => Float(f + ff), (P(Float(f)), Value::P(Float(ff))) => Float(f + ff),
@ -579,4 +607,8 @@ impl<'a> VM {
_ => return Err(Error {}), _ => return Err(Error {}),
}) })
} }
}
fn op_runtime(&mut self, h: Hook) -> Result<(), Error> {
self.runtime.borrow_mut().handle(h, &mut self.stack)
}
}