diff --git a/src/build/mod.rs b/src/build/mod.rs index 20e2df5..628fa39 100644 --- a/src/build/mod.rs +++ b/src/build/mod.rs @@ -102,6 +102,31 @@ pub struct AssertCollector { 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. pub struct FileBuilder<'a, C> where @@ -169,12 +194,7 @@ where std: Rc::new(stdlib::get_libs()), import_path: import_paths, validate_mode: false, - assert_collector: AssertCollector { - counter: 0, - success: true, - summary: String::new(), - failures: String::new(), - }, + assert_collector: AssertCollector::new(), scope: scope, import_registry: ImporterRegistry::make_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, Box> { if !self.validate_mode { // we are not in validate_mode so build_asserts are noops. @@ -1715,7 +1722,7 @@ where Err(e) => { // failure! 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)); } }; @@ -1730,7 +1737,7 @@ where "TYPE FAIL - Expected Boolean field ok in tuple {}, line: {}, 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)); } }, @@ -1739,7 +1746,7 @@ where "TYPE FAIL - Expected Boolean field ok in tuple {}, line: {}, 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)); } }; @@ -1751,7 +1758,7 @@ where "TYPE FAIL - Expected String field desc in tuple {} line: {}, 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)); } }, @@ -1760,11 +1767,11 @@ where "TYPE FAIL - Expected String field desc in tuple {} line: {}, column: {}\n", 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)); } }; - self.record_assert_result(&desc, ok_field); + self.assert_collector.record_assert_result(&desc, ok_field); } &Val::Empty | &Val::Boolean(_) @@ -1780,7 +1787,7 @@ where "TYPE FAIL - Expected tuple with ok and desc fields got {} at line: {} column: {}\n", 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)); } } diff --git a/src/build/opcode/cache.rs b/src/build/opcode/cache.rs new file mode 100644 index 0000000..fec5b04 --- /dev/null +++ b/src/build/opcode/cache.rs @@ -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>>, +} + +impl Ops { + pub fn new() -> Self { + Self { + ops: BTreeMap::new(), + } + } + + pub fn entry<'a, S: Into>(&'a mut self, path: S) -> Entry<'a> { + Entry(self.ops.entry(path.into())) + } +} + +pub struct Entry<'a>(btree_map::Entry<'a, String, Rc>>); + +impl<'a> Entry<'a> { + pub fn get_pointer_or_else Vec>(self, f: F) -> OpPointer { + let cached = self.0.or_insert_with(|| Rc::new(f())).clone(); + OpPointer::new(cached) + } +} diff --git a/src/build/opcode/mod.rs b/src/build/opcode/mod.rs index ab5c26a..73e6ada 100644 --- a/src/build/opcode/mod.rs +++ b/src/build/opcode/mod.rs @@ -11,7 +11,11 @@ // 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::rc::Rc; + +mod cache; pub mod pointer; +mod runtime; pub mod scope; mod vm; @@ -32,8 +36,8 @@ pub enum Primitive { #[derive(Debug, PartialEq, Clone)] pub enum Composite { - List(Vec), - Tuple(Vec<(String, Value)>), + List(Vec>), + Tuple(Vec<(String, Rc)>), } #[derive(Debug, PartialEq, Clone)] @@ -47,7 +51,7 @@ pub struct Func { pub struct Module { ptr: OpPointer, result_ptr: Option, - flds: Vec<(String, Value)>, + flds: Vec<(String, Rc)>, } #[derive(Debug, PartialEq, Clone)] @@ -66,6 +70,18 @@ pub enum Value { M(Module), } +#[derive(Debug, PartialEq, Clone)] +pub enum Hook { + Map, + Include, + Filter, + Reduce, + Import, + Out, + Assert, + Convert, +} + #[derive(Debug, PartialEq, Clone)] pub enum Op { // Stack and Name manipulation. @@ -115,13 +131,7 @@ pub enum Op { // Calls FCall, // Runtime hooks - // - Map, - // - Filter, - // - Reduce, - // - Import, - // - Out, - // - Assert, - // - Convert, + Runtime(Hook), } #[derive(Debug)] diff --git a/src/build/opcode/runtime.rs b/src/build/opcode/runtime.rs new file mode 100644 index 0000000..476caff --- /dev/null +++ b/src/build/opcode/runtime.rs @@ -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>, + 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>) -> 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>) -> 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>) -> 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>) -> 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>) -> 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>) -> 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>) -> Result<(), Error> { + // TODO(jwall): map (combine these into one?) + unimplemented!("TODO(jwall): Map expressions are not implemented yet") + } + + fn filter(&self, stack: &mut Vec>) -> Result<(), Error> { + // TODO(jwall): filter + unimplemented!("TODO(jwall): Filter expressions are not implemented yet") + } + + fn reduce(&self, stack: &mut Vec>) -> Result<(), Error> { + // TODO(jwall): reduce + unimplemented!("TODO(jwall): Reduce expressions are not implemented yet") + } +} diff --git a/src/build/opcode/scope.rs b/src/build/opcode/scope.rs index e34c05a..2ea6f93 100644 --- a/src/build/opcode/scope.rs +++ b/src/build/opcode/scope.rs @@ -13,13 +13,14 @@ // limitations under the License. use std::collections::{BTreeMap, BTreeSet}; use std::iter::FromIterator; +use std::rc::Rc; use super::{Error, Value}; #[derive(Clone, PartialEq, Debug)] pub enum Bindings { - Sealed(BTreeMap), - Open(BTreeMap), + Sealed(BTreeMap>), + Open(BTreeMap>), } 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> { match self { - Open(flds) => flds.get(name), - Sealed(flds) => flds.get(name), + Open(flds) => flds.get(name).cloned(), + Sealed(flds) => flds.get(name).cloned(), } } - pub fn add(&mut self, name: String, val: Value) { + pub fn add(&mut self, name: String, val: Rc) { match self { Sealed(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> { match &self.curr { - Sealed(flds) => flds.get(name), + Sealed(flds) => flds.get(name).cloned(), Open(flds) => { if let Some(v) = flds.get(name) { - return Some(v); + return Some(v.clone()); } else { for b in self.prev.iter() { match b { - Sealed(bflds) => { - if let Some(v) = bflds.get(name) { - return Some(v); - } - return None; - } - Open(bflds) => { - if let Some(v) = bflds.get(name) { - return Some(v); - } - } + Sealed(bflds) => return bflds.get(name).cloned(), + Open(bflds) => return bflds.get(name).cloned(), } } } @@ -132,7 +124,7 @@ impl Stack { } } - pub fn add(&mut self, name: String, val: Value) { + pub fn add(&mut self, name: String, val: Rc) { self.curr.add(name, val); } diff --git a/src/build/opcode/test.rs b/src/build/opcode/test.rs index 31168f0..13b94dc 100644 --- a/src/build/opcode/test.rs +++ b/src/build/opcode/test.rs @@ -29,7 +29,7 @@ macro_rules! assert_cases { for case in $cases.drain(0..) { let mut vm = VM::new(Rc::new(case.0)); 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(); let (name, result) = case.1; 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() { assert_cases!( vec![InitList] => C(List(Vec::new())), - vec![InitList, Val(Int(1)), Element] => C(List(vec![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(1)), Element] => C(List(vec![Rc::new(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![ InitList, Val(Int(1)), @@ -110,7 +110,7 @@ fn test_list_ops() { Val(Int(1)), Add, 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() { assert_cases!( 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![ InitTuple, Sym("bar".to_owned()), @@ -128,8 +135,8 @@ fn test_tuple_ops() { Val(Int(1)), Field, ] => C(Tuple(vec![ - ("bar".to_owned(), P(Str("quux".to_owned()))), - ("foo".to_owned(), P(Int(1))), + ("bar".to_owned(), Rc::new(P(Str("quux".to_owned())))), + ("foo".to_owned(), Rc::new(P(Int(1)))), ])), vec![ InitTuple, @@ -143,8 +150,8 @@ fn test_tuple_ops() { Val(Int(2)), Field, ] => C(Tuple(vec![ - ("bar".to_owned(), P(Str("quux".to_owned()))), - ("foo".to_owned(), P(Int(2))), + ("bar".to_owned(), Rc::new(P(Str("quux".to_owned())))), + ("foo".to_owned(), Rc::new(P(Int(2)))), ])), vec![ InitTuple, @@ -160,8 +167,8 @@ fn test_tuple_ops() { Val(Int(2)), Field, ] => C(Tuple(vec![ - ("bar".to_owned(), P(Str("quux".to_owned()))), - ("foo".to_owned(), P(Int(2))), + ("bar".to_owned(), Rc::new(P(Str("quux".to_owned())))), + ("foo".to_owned(), Rc::new(P(Int(2)))), ])), vec![ InitTuple, // Override tuple @@ -179,8 +186,8 @@ fn test_tuple_ops() { Field, Cp, // Do the tuple copy operation ] => C(Tuple(vec![ - ("bar".to_owned(), P(Str("quux".to_owned()))), - ("foo".to_owned(), P(Int(2))), + ("bar".to_owned(), Rc::new(P(Str("quux".to_owned())))), + ("foo".to_owned(), Rc::new(P(Int(2)))), ])), ); } @@ -368,10 +375,10 @@ fn test_module_call() { ] => C(Tuple(vec![ ( "foo".to_owned(), - C(Tuple(vec![ - ("one".to_owned(), P(Int(11))), - ("two".to_owned(), P(Int(2))), - ])) + Rc::new(C(Tuple(vec![ + ("one".to_owned(), Rc::new(P(Int(11)))), + ("two".to_owned(), Rc::new(P(Int(2)))), + ]))) ), ])), vec![ @@ -486,12 +493,12 @@ fn test_index_operation() { #[test] fn test_scope_stacks() { 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(); - assert_eq!(val, &P(Int(1))); + assert_eq!(val.as_ref(), &P(Int(1))); stack.push(); assert!(stack.get("one").is_none()); stack.to_open(); val = stack.get("one").unwrap(); - assert_eq!(val, &P(Int(1))); + assert_eq!(val.as_ref(), &P(Int(1))); } diff --git a/src/build/opcode/vm.rs b/src/build/opcode/vm.rs index 1e50aad..235e81b 100644 --- a/src/build/opcode/vm.rs +++ b/src/build/opcode/vm.rs @@ -1,30 +1,34 @@ // 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::cell::RefCell; use std::rc::Rc; -use super::{Value, Op, Primitive, Error}; -use super::scope::{Stack}; 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::Hook; +use super::Primitive::{Bool, Float, Int, Str}; +use super::Value::{C, F, M, P, S, T}; use super::{Func, Module}; pub struct VM { - stack: Vec, + stack: Vec>, symbols: Stack, + runtime: Rc>, ops: OpPointer, } @@ -37,6 +41,7 @@ impl<'a> VM { Self { stack: Vec::new(), symbols: Stack::new(), + runtime: Rc::new(RefCell::new(runtime::Builtins::new())), ops: ops, } } @@ -45,10 +50,21 @@ impl<'a> VM { Self { stack: Vec::new(), symbols: symbols, + runtime: self.runtime.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> { loop { let op = if let Some(op) = dbg!(self.ops.next()) { @@ -58,8 +74,8 @@ impl<'a> VM { }; let idx = self.ops.idx()?; match op { - Op::Val(p) => self.push(dbg!(P(p.clone())))?, - Op::Sym(s) => self.push(dbg!(S(s.clone())))?, + Op::Val(p) => self.push(Rc::new(dbg!(P(p.clone()))))?, + Op::Sym(s) => self.push(Rc::new(dbg!(S(s.clone()))))?, Op::DeRef(s) => self.op_deref(s.clone())?, Op::Add => self.op_add()?, Op::Sub => self.op_sub()?, @@ -72,9 +88,9 @@ impl<'a> VM { Op::GtEq => self.op_gteq()?, Op::LtEq => self.op_lteq()?, // 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 - Op::InitTuple => self.push(C(Tuple(Vec::new())))?, + Op::InitTuple => self.push(Rc::new(C(Tuple(Vec::new()))))?, Op::Field => self.op_field()?, Op::Element => self.op_element()?, Op::Index => self.op_index()?, @@ -96,6 +112,7 @@ impl<'a> VM { Op::Pop => { self.pop()?; } + Op::Runtime(h) => self.op_runtime(h)?, }; } Ok(()) @@ -117,7 +134,8 @@ impl<'a> VM { } 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 { self.op_jump(jp)?; } @@ -126,7 +144,8 @@ impl<'a> VM { } 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 { self.op_jump(jp)?; } @@ -150,11 +169,13 @@ impl<'a> VM { } fn op_module(&'a mut self, idx: usize, jptr: usize) -> Result<(), Error> { - let (result_ptr, flds) = match self.pop()? { - C(Tuple(flds)) => (None, flds), - T(ptr) => { - if let C(Tuple(flds)) = self.pop()? { - (Some(ptr), flds) + let mod_val = self.pop()?; + let (result_ptr, flds) = match mod_val.as_ref() { + &C(Tuple(ref flds)) => (None, flds.clone()), + &T(ptr) => { + let tpl_val = self.pop()?; + if let &C(Tuple(ref flds)) = tpl_val.as_ref() { + (Some(ptr), flds.clone()) } else { return dbg!(Err(Error {})); } @@ -165,11 +186,11 @@ impl<'a> VM { }; let mut ops = self.ops.clone(); ops.jump(idx)?; - self.push(M(Module { + self.push(Rc::new(M(Module { ptr: dbg!(ops), result_ptr: result_ptr, flds: dbg!(flds), - }))?; + })))?; self.ops.jump(dbg!(jptr)) } @@ -181,10 +202,11 @@ impl<'a> VM { eprintln!("Defining a new function"); let mut bindings = Vec::new(); // 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 { - if let S(sym) = e { - bindings.push(sym); + if let &S(ref sym) = e.as_ref() { + bindings.push(sym.clone()); } else { return dbg!(Err(Error {})); } @@ -195,29 +217,29 @@ impl<'a> VM { eprintln!("Pushing function definition on stack"); let mut ops = self.ops.clone(); ops.jump(idx)?; - self.push(dbg!(F(Func { + self.push(Rc::new(dbg!(F(Func { ptr: ops, // where the function starts. bindings: bindings, snapshot: scope_snapshot, - })))?; + }))))?; eprintln!("Jumping to {} past the function body", jptr); self.ops.jump(jptr) } fn op_fcall(&mut self) -> Result<(), Error> { let f = self.pop()?; - if let F(Func { - ptr, - bindings, - snapshot, - }) = f + if let &F(Func { + ref ptr, + ref bindings, + ref snapshot, + }) = f.as_ref() { // use the captured scope snapshot for the function. - let mut vm = Self::with_pointer(ptr).to_scoped(snapshot); - for nm in bindings { + let mut vm = Self::with_pointer(ptr.clone()).to_scoped(snapshot.clone()); + for nm in bindings.iter() { // now put each argument on our scope stack as a binding. let val = self.pop()?; - vm.binding_push(nm, val)?; + vm.binding_push(nm.clone(), val)?; } // proceed to the function body vm.run()?; @@ -229,26 +251,26 @@ impl<'a> VM { } 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) } fn op_equal(&mut self) -> Result<(), Error> { let left = self.pop()?; let right = self.pop()?; - self.push(P(Bool(left == right)))?; + self.push(Rc::new(P(Bool(left == right))))?; Ok(()) } fn op_gt(&mut self) -> Result<(), Error> { let left = self.pop()?; let right = self.pop()?; - match (left, right) { - (P(Int(i)), P(Int(ii))) => { - self.push(P(Bool(i > ii)))?; + match (left.as_ref(), right.as_ref()) { + (&P(Int(i)), &P(Int(ii))) => { + self.push(Rc::new(P(Bool(i > ii))))?; } - (P(Float(f)), P(Float(ff))) => { - self.push(P(Bool(f > ff)))?; + (&P(Float(f)), &P(Float(ff))) => { + self.push(Rc::new(P(Bool(f > ff))))?; } _ => return Err(Error {}), } @@ -258,12 +280,12 @@ impl<'a> VM { fn op_lt(&mut self) -> Result<(), Error> { let left = self.pop()?; let right = self.pop()?; - match (left, right) { - (P(Int(i)), P(Int(ii))) => { - self.push(P(Bool(i < ii)))?; + match (left.as_ref(), right.as_ref()) { + (&P(Int(i)), &P(Int(ii))) => { + self.push(Rc::new(P(Bool(i < ii))))?; } - (P(Float(f)), P(Float(ff))) => { - self.push(P(Bool(f < ff)))?; + (&P(Float(f)), &P(Float(ff))) => { + self.push(Rc::new(P(Bool(f < ff))))?; } _ => return Err(Error {}), } @@ -273,12 +295,12 @@ impl<'a> VM { fn op_lteq(&mut self) -> Result<(), Error> { let left = self.pop()?; let right = self.pop()?; - match (left, right) { - (P(Int(i)), P(Int(ii))) => { - self.push(P(Bool(i <= ii)))?; + match (left.as_ref(), right.as_ref()) { + (&P(Int(i)), &P(Int(ii))) => { + self.push(Rc::new(P(Bool(i <= ii))))?; } - (P(Float(f)), P(Float(ff))) => { - self.push(P(Bool(f <= ff)))?; + (&P(Float(f)), &P(Float(ff))) => { + self.push(Rc::new(P(Bool(f <= ff))))?; } _ => return Err(Error {}), } @@ -288,12 +310,12 @@ impl<'a> VM { fn op_gteq(&mut self) -> Result<(), Error> { let left = self.pop()?; let right = self.pop()?; - match (left, right) { - (P(Int(i)), P(Int(ii))) => { - self.push(P(Bool(i >= ii)))?; + match (left.as_ref(), right.as_ref()) { + (&P(Int(i)), &P(Int(ii))) => { + self.push(Rc::new(P(Bool(i >= ii))))?; } - (P(Float(f)), P(Float(ff))) => { - self.push(P(Bool(f >= ff)))?; + (&P(Float(f)), &P(Float(ff))) => { + self.push(Rc::new(P(Bool(f >= ff))))?; } _ => return Err(Error {}), } @@ -305,7 +327,7 @@ impl<'a> VM { let left = self.pop()?; let right = self.pop()?; // Then pushes the result onto the stack. - self.push(P(self.add(left, right)?))?; + self.push(Rc::new(P(self.add(&left, &right)?)))?; Ok(()) } @@ -314,7 +336,7 @@ impl<'a> VM { let left = self.pop()?; let right = self.pop()?; // Then pushes the result onto the stack. - self.push(P(self.sub(left, right)?))?; + self.push(Rc::new(P(self.sub(&left, &right)?)))?; Ok(()) } @@ -323,7 +345,7 @@ impl<'a> VM { let left = self.pop()?; let right = self.pop()?; // Then pushes the result onto the stack. - self.push(P(self.mul(left, right)?))?; + self.push(Rc::new(P(self.mul(&left, &right)?)))?; Ok(()) } @@ -332,7 +354,7 @@ impl<'a> VM { let left = self.pop()?; let right = self.pop()?; // Then pushes the result onto the stack. - self.push(P(self.div(left, right)?))?; + self.push(Rc::new(P(self.div(&left, &right)?)))?; Ok(()) } @@ -341,8 +363,8 @@ impl<'a> VM { let val = dbg!(self.pop())?; // pop name off stack. let name = dbg!(self.pop())?; - if let S(name) = name { - self.binding_push(name, val)?; + if let &S(ref name) = name.as_ref() { + self.binding_push(name.clone(), val)?; } else { return Err(Error {}); } @@ -354,18 +376,22 @@ impl<'a> VM { // get value from stack let val = self.pop()?; // 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 } else { return Err(Error {}); }; // get composite tuple from stack 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 - 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 - self.push(C(Tuple(flds)))?; + self.push(Rc::new(C(Tuple(flds))))?; } else { return Err(Error {}); }; @@ -377,20 +403,23 @@ impl<'a> VM { let val = self.pop()?; // get next value. It should be a Composite list. let tpl = self.pop()?; - if let C(List(mut elems)) = tpl { + if let &C(List(ref elems)) = tpl.as_ref() { // 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); // 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 { return Err(Error {}); }; Ok(()) } - fn find_in_list(&self, index: Value, elems: Vec) -> Result { + fn find_in_list(&self, index: &Value, elems: &Vec>) -> Result, Error> { let idx = match index { - P(Int(i)) => i, + P(Int(i)) => i.clone(), _ => return dbg!(Err(Error {})), }; 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 { + fn find_in_flds(&self, index: &Value, flds: &Vec<(String, Rc)>) -> Result, Error> { let idx = match index { S(p) => p, P(Str(p)) => p, _ => return dbg!(Err(Error {})), }; for f in flds.iter() { - if idx == f.0 { + if idx == &f.0 { return Ok(f.1.clone()); } } Err(Error {}) } - fn find_in_value(&self, index: Value, target: Value) -> Result { + fn find_in_value(&self, index: &Value, target: &Value) -> Result, Error> { match target { C(Tuple(flds)) => self.find_in_flds(index, flds), C(List(elements)) => self.find_in_list(index, elements), @@ -422,17 +451,19 @@ impl<'a> VM { } fn op_index(&mut self) -> Result<(), Error> { - let path = if let C(List(elems)) = self.pop()? { - elems + let path_val = self.pop()?; + let path = if let &C(List(ref elems)) = path_val.as_ref() { + elems.clone() } else { return dbg!(Err(Error {})); }; - match self.pop()? { - P(_) | S(_) | T(_) | F(_) | M(_) => return dbg!(Err(Error {})), - val => { - let mut out = val; + let target_val = self.pop()?; + match target_val.as_ref() { + &P(_) | &S(_) | &T(_) | &F(_) | &M(_) => return dbg!(Err(Error {})), + _ => { + let mut out = target_val.clone(); for p in path { - let tgt = self.find_in_value(p, out)?; + let tgt = self.find_in_value(&p, &out)?; out = tgt; } self.push(out)?; @@ -446,50 +477,47 @@ impl<'a> VM { // get next value. It should be a Module or Tuple. let tgt = dbg!(self.pop())?; // This value should always be a tuple - let overrides = if let C(Tuple(oflds)) = self.pop()? { - oflds + let override_val = self.pop()?; + let overrides = if let &C(Tuple(ref oflds)) = override_val.as_ref() { + oflds.clone() } else { return dbg!(Err(Error {})); }; - match tgt { - C(Tuple(mut flds)) => { + match tgt.as_ref() { + &C(Tuple(ref flds)) => { + let mut flds = flds.clone(); for (name, val) in overrides { dbg!(self.merge_field_into_tuple(&mut flds, name, val))?; } // Put the copy on the Stack - self.push(C(Tuple(flds)))?; + self.push(Rc::new(C(Tuple(flds))))?; } - M(Module { - ptr, - result_ptr, - mut flds, + &M(Module { + ref ptr, + ref result_ptr, + ref flds, }) => { //let this = M(Module { // ptr: ptr.clone(), // result_ptr: result_ptr.clone(), // flds: flds.clone(), //}); + let mut flds = flds.clone(); for (name, val) in overrides { self.merge_field_into_tuple(&mut flds, name, val)?; } // FIXME(jwall): We need to populate the pkg key for modules. //self.merge_field_into_tuple(&mut flds, "this".to_owned(), this)?; - let mut vm = Self::with_pointer(ptr); - vm.push(S("mod".to_owned()))?; - vm.push(C(Tuple(dbg!(flds))))?; + let mut vm = Self::with_pointer(ptr.clone()); + vm.push(Rc::new(S("mod".to_owned())))?; + vm.push(Rc::new(C(Tuple(dbg!(flds)))))?; vm.run()?; - let mut flds = Vec::new(); if let Some(ptr) = dbg!(result_ptr) { - vm.ops.jump(ptr)?; + vm.ops.jump(ptr.clone())?; vm.run()?; self.push(vm.pop()?)?; } else { - for sym in vm.symbols.symbol_list() { - if sym != "mod" { - flds.push((sym.clone(), vm.symbols.get(sym).unwrap().clone())); - } - } - self.push(dbg!(C(Tuple(flds))))?; + self.push(dbg!(Rc::new(vm.symbols_to_tuple(false))))?; } } _ => { @@ -501,9 +529,9 @@ impl<'a> VM { fn merge_field_into_tuple( &self, - src_fields: &'a mut Vec<(String, Value)>, + src_fields: &'a mut Vec<(String, Rc)>, name: String, - value: Value, + value: Rc, ) -> Result<(), Error> { for fld in src_fields.iter_mut() { if fld.0 == name { @@ -515,12 +543,12 @@ impl<'a> VM { Ok(()) } - fn push(&mut self, p: Value) -> Result<(), Error> { + fn push(&mut self, p: Rc) -> Result<(), Error> { self.stack.push(p); Ok(()) } - fn binding_push(&mut self, name: String, val: Value) -> Result<(), Error> { + fn binding_push(&mut self, name: String, val: Rc) -> Result<(), Error> { if self.symbols.is_bound(&name) { return Err(Error {}); } @@ -528,21 +556,21 @@ impl<'a> VM { Ok(()) } - pub fn get_binding(&'a self, name: &str) -> Result<&Value, Error> { + pub fn get_binding(&'a self, name: &str) -> Result, Error> { match self.symbols.get(name) { Some(v) => Ok(v), None => Err(Error {}), } } - pub fn pop(&mut self) -> Result { + pub fn pop(&mut self) -> Result, Error> { match self.stack.pop() { Some(v) => Ok(v), None => Err(Error {}), } } - fn mul(&self, left: Value, right: Value) -> Result { + fn mul(&self, left: &Value, right: &Value) -> Result { Ok(match (left, right) { (P(Int(i)), P(Int(ii))) => Int(i * ii), (P(Float(f)), P(Float(ff))) => Float(f * ff), @@ -550,7 +578,7 @@ impl<'a> VM { }) } - fn div(&self, left: Value, right: Value) -> Result { + fn div(&self, left: &Value, right: &Value) -> Result { Ok(match (left, right) { (P(Int(i)), P(Int(ii))) => Int(i / ii), (P(Float(f)), P(Float(ff))) => Float(f / ff), @@ -558,7 +586,7 @@ impl<'a> VM { }) } - fn sub(&self, left: Value, right: Value) -> Result { + fn sub(&self, left: &Value, right: &Value) -> Result { Ok(match (left, right) { (P(Int(i)), Value::P(Int(ii))) => Int(i - ii), (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 { + fn add(&self, left: &Value, right: &Value) -> Result { Ok(match (left, right) { (P(Int(i)), Value::P(Int(ii))) => Int(i + ii), (P(Float(f)), Value::P(Float(ff))) => Float(f + ff), @@ -579,4 +607,8 @@ impl<'a> VM { _ => return Err(Error {}), }) } -} \ No newline at end of file + + fn op_runtime(&mut self, h: Hook) -> Result<(), Error> { + self.runtime.borrow_mut().handle(h, &mut self.stack) + } +}