mirror of
https://github.com/zaphar/ucg.git
synced 2025-07-22 18:19:54 -04:00
DEV: The beginnings of a runtime for the opcode vm.
This commit is contained in:
parent
fa2ad0c5a9
commit
a7aab10723
@ -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
44
src/build/opcode/cache.rs
Normal 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)
|
||||||
|
}
|
||||||
|
}
|
@ -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
156
src/build/opcode/runtime.rs
Normal 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")
|
||||||
|
}
|
||||||
|
}
|
@ -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);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -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)));
|
||||||
}
|
}
|
||||||
|
@ -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)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
Loading…
x
Reference in New Issue
Block a user