DEV: Extract the environmentally shared pieces out

This commit is contained in:
Jeremy Wall 2019-08-17 12:57:40 -05:00
parent 946a112eb4
commit 3dd0cc6794
6 changed files with 246 additions and 105 deletions

View File

@ -0,0 +1,48 @@
// 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::io::Write;
use std::rc::Rc;
use super::cache;
use super::Value;
use crate::convert::{ConverterRegistry, ImporterRegistry};
// Shared Environmental between VM's for runtime usage.
pub struct Environment<Stdout, Stderr>
where
Stdout: Write,
Stderr: Write,
{
pub val_cache: BTreeMap<String, Rc<Value>>,
pub op_cache: cache::Ops, // Shared environment
pub converter_registry: ConverterRegistry, // Shared environment
pub importer_registry: ImporterRegistry, // Shared environment
pub stdout: Stdout, // Shared environment
pub stderr: Stderr, // Shared environment
// TODO(jwall): Environment Variables
}
impl<Stdout: Write, Stderr: Write> Environment<Stdout, Stderr> {
pub fn new(out: Stdout, err: Stderr) -> Self {
Self {
val_cache: BTreeMap::new(),
op_cache: cache::Ops::new(),
converter_registry: ConverterRegistry::make_registry(),
importer_registry: ImporterRegistry::make_registry(),
stdout: out,
stderr: err,
}
}
}

View File

@ -15,6 +15,7 @@ use std::convert::{TryFrom, TryInto};
use std::rc::Rc; use std::rc::Rc;
mod cache; mod cache;
mod environment;
mod error; mod error;
pub mod pointer; pub mod pointer;
mod runtime; mod runtime;

View File

@ -11,87 +11,75 @@
// 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::collections::BTreeMap; use std::cell::RefCell;
use std::convert::TryFrom; use std::convert::{TryFrom, TryInto};
use std::convert::TryInto;
use std::fs::File; use std::fs::File;
use std::io::{Read, Write}; use std::io::Read;
use std::path::{Path, PathBuf}; use std::path::{Path, PathBuf};
use std::rc::Rc; use std::rc::Rc;
use regex::Regex; use regex::Regex;
use super::cache; use super::environment::Environment;
use super::Value::{C, F, P}; use super::Value::{C, F, P};
use super::VM; use super::VM;
use super::{Composite, Error, Hook, Primitive, Value}; use super::{Composite, Error, Hook, Primitive, Value};
use crate::ast::Position; use crate::ast::Position;
use crate::build::ir::Val; use crate::build::ir::Val;
use crate::build::AssertCollector; use crate::build::AssertCollector;
use crate::convert::{ConverterRegistry, ImporterRegistry};
use Composite::{List, Tuple}; use Composite::{List, Tuple};
use Primitive::{Bool, Empty, Int, Str}; use Primitive::{Bool, Empty, Int, Str};
pub struct Builtins<Out: Write, Err: Write> { pub struct Builtins {
op_cache: cache::Ops,
val_cache: BTreeMap<String, Rc<Value>>,
assert_results: AssertCollector, assert_results: AssertCollector,
converter_registry: ConverterRegistry,
importer_registry: ImporterRegistry,
working_dir: PathBuf, working_dir: PathBuf,
import_path: Vec<PathBuf>, import_path: Vec<PathBuf>,
stdout: Out,
stderr: Err,
} }
type ByteSink = Vec<u8>; impl Builtins {
pub fn new() -> Self {
impl<Out: Write, Err: Write> Builtins<Out, Err> { Self::with_working_dir(std::env::current_dir().unwrap())
pub fn new(out: Out, err: Err) -> Self {
Self::with_working_dir(std::env::current_dir().unwrap(), out, err)
} }
pub fn with_working_dir<P: Into<PathBuf>>(path: P, out: Out, err: Err) -> Self { pub fn with_working_dir<P: Into<PathBuf>>(path: P) -> Self {
Self { Self {
op_cache: cache::Ops::new(),
val_cache: BTreeMap::new(),
assert_results: AssertCollector::new(), assert_results: AssertCollector::new(),
converter_registry: ConverterRegistry::make_registry(),
importer_registry: ImporterRegistry::make_registry(),
// FIXME(jwall): This should move into the VM and not in the Runtime.
working_dir: path.into(), working_dir: path.into(),
import_path: Vec::new(), import_path: Vec::new(),
stdout: out,
stderr: err,
} }
} }
pub fn get_stdout(&self) -> &Out { pub fn clone(&self) -> Self {
&self.stdout Self {
assert_results: AssertCollector::new(),
working_dir: self.working_dir.clone(),
import_path: self.import_path.clone(),
}
} }
pub fn get_stderr(&self) -> &Err { pub fn handle<P: AsRef<Path>, O, E>(
&self.stderr
}
pub fn handle<P: AsRef<Path>>(
&mut self, &mut self,
path: P, path: P,
h: Hook, h: Hook,
stack: &mut Vec<Rc<Value>>, stack: &mut Vec<Rc<Value>>,
) -> Result<(), Error> { env: Rc<RefCell<Environment<O, E>>>,
) -> Result<(), Error>
where
O: std::io::Write,
E: std::io::Write,
{
match h { match h {
Hook::Import => self.import(stack), Hook::Import => self.import(stack, env),
Hook::Include => self.include(stack), Hook::Include => self.include(stack, env),
Hook::Assert => self.assert(stack), Hook::Assert => self.assert(stack),
Hook::Convert => self.convert(stack), Hook::Convert => self.convert(stack, env),
Hook::Out => self.out(path, stack), Hook::Out => self.out(path, stack, env),
Hook::Map => self.map(path, stack), Hook::Map => self.map(path, stack, env),
Hook::Filter => self.filter(path, stack), Hook::Filter => self.filter(path, stack, env),
Hook::Reduce => self.reduce(path, stack), Hook::Reduce => self.reduce(path, stack, env),
Hook::Regex => self.regex(stack), Hook::Regex => self.regex(stack),
Hook::Range => self.range(stack), Hook::Range => self.range(stack),
Hook::Trace(pos) => self.trace(stack, pos), Hook::Trace(pos) => self.trace(stack, pos, env),
} }
} }
@ -142,21 +130,35 @@ impl<Out: Write, Err: Write> Builtins<Out, Err> {
Ok(contents) Ok(contents)
} }
fn import(&mut self, stack: &mut Vec<Rc<Value>>) -> Result<(), Error> { fn import<O, E>(
&mut self,
stack: &mut Vec<Rc<Value>>,
env: Rc<RefCell<Environment<O, E>>>,
) -> Result<(), Error>
where
O: std::io::Write,
E: std::io::Write,
{
let path = stack.pop(); let path = stack.pop();
if let Some(val) = path { if let Some(val) = path {
if let &Value::P(Str(ref path)) = val.as_ref() { if let &Value::P(Str(ref path)) = val.as_ref() {
if self.val_cache.contains_key(path) { let mut borrowed_env = env.borrow_mut();
stack.push(self.val_cache[path].clone()); let val_cache = &mut borrowed_env.val_cache;
if val_cache.contains_key(path) {
stack.push(val_cache[path].clone());
} else { } else {
let op_pointer = self.op_cache.entry(path).get_pointer_or_else(|| { let op_pointer =
// FIXME(jwall): import env.borrow_mut()
unimplemented!("Compiling paths are not implemented yet"); .op_cache
}); .entry(path)
let mut vm = VM::with_pointer(path, op_pointer); .get_pointer_or_else(|| {
// FIXME(jwall): import
unimplemented!("Compiling paths are not implemented yet");
});
let mut vm = VM::with_pointer(path, op_pointer, env.clone());
vm.run()?; vm.run()?;
let result = Rc::new(vm.symbols_to_tuple(true)); let result = Rc::new(vm.symbols_to_tuple(true));
self.val_cache.insert(path.clone(), result.clone()); val_cache.insert(path.clone(), result.clone());
stack.push(result); stack.push(result);
} }
return Ok(()); return Ok(());
@ -165,7 +167,15 @@ impl<Out: Write, Err: Write> Builtins<Out, Err> {
return Err(dbg!(Error {})); return Err(dbg!(Error {}));
} }
fn include(&self, stack: &mut Vec<Rc<Value>>) -> Result<(), Error> { fn include<O, E>(
&self,
stack: &mut Vec<Rc<Value>>,
env: Rc<RefCell<Environment<O, E>>>,
) -> Result<(), Error>
where
O: std::io::Write,
E: std::io::Write,
{
// TODO(jwall): include // TODO(jwall): include
let path = stack.pop(); let path = stack.pop();
let typ = stack.pop(); let typ = stack.pop();
@ -190,21 +200,23 @@ impl<Out: Write, Err: Write> Builtins<Out, Err> {
if typ == "str" { if typ == "str" {
stack.push(Rc::new(P(Str(self.get_file_as_string(&path)?)))); stack.push(Rc::new(P(Str(self.get_file_as_string(&path)?))));
} else { } else {
stack.push(Rc::new(match self.importer_registry.get_importer(&typ) { stack.push(Rc::new(
Some(importer) => { match env.borrow().importer_registry.get_importer(&typ) {
let contents = self.get_file_as_string(&path)?; Some(importer) => {
if contents.len() == 0 { let contents = self.get_file_as_string(&path)?;
eprintln!("including an empty file. Use NULL as the result"); if contents.len() == 0 {
P(Empty) eprintln!("including an empty file. Use NULL as the result");
} else { P(Empty)
match importer.import(contents.as_bytes()) { } else {
Ok(v) => v.try_into()?, match importer.import(contents.as_bytes()) {
Err(_e) => return Err(dbg!(Error {})), Ok(v) => v.try_into()?,
Err(_e) => return Err(dbg!(Error {})),
}
} }
} }
} None => return Err(dbg!(Error {})),
None => return Err(dbg!(Error {})), },
})); ));
} }
return Err(dbg!(Error {})); return Err(dbg!(Error {}));
} }
@ -243,13 +255,22 @@ impl<Out: Write, Err: Write> Builtins<Out, Err> {
return Ok(()); return Ok(());
} }
fn out<P: AsRef<Path>>(&self, path: P, stack: &mut Vec<Rc<Value>>) -> Result<(), Error> { fn out<P: AsRef<Path>, O, E>(
&self,
path: P,
stack: &mut Vec<Rc<Value>>,
env: Rc<RefCell<Environment<O, E>>>,
) -> Result<(), Error>
where
O: std::io::Write,
E: std::io::Write,
{
let val = stack.pop(); let val = stack.pop();
if let Some(val) = val { if let Some(val) = val {
let val = val.try_into()?; let val = val.try_into()?;
if let Some(c_type_val) = stack.pop() { if let Some(c_type_val) = stack.pop() {
if let &Value::S(ref c_type) = c_type_val.as_ref() { if let &Value::S(ref c_type) = c_type_val.as_ref() {
if let Some(c) = self.converter_registry.get_converter(c_type) { if let Some(c) = env.borrow().converter_registry.get_converter(c_type) {
match c.convert(Rc::new(val), &mut File::create(path)?) { match c.convert(Rc::new(val), &mut File::create(path)?) {
Ok(_) => { Ok(_) => {
// noop // noop
@ -264,13 +285,21 @@ impl<Out: Write, Err: Write> Builtins<Out, Err> {
return Err(dbg!(Error {})); return Err(dbg!(Error {}));
} }
fn convert(&self, stack: &mut Vec<Rc<Value>>) -> Result<(), Error> { fn convert<O, E>(
&self,
stack: &mut Vec<Rc<Value>>,
env: Rc<RefCell<Environment<O, E>>>,
) -> Result<(), Error>
where
O: std::io::Write,
E: std::io::Write,
{
let val = stack.pop(); let val = stack.pop();
if let Some(val) = val { if let Some(val) = val {
let val = val.try_into()?; let val = val.try_into()?;
if let Some(c_type_val) = stack.pop() { if let Some(c_type_val) = stack.pop() {
if let &Value::S(ref c_type) = c_type_val.as_ref() { if let &Value::S(ref c_type) = c_type_val.as_ref() {
if let Some(c) = self.converter_registry.get_converter(c_type) { if let Some(c) = env.borrow().converter_registry.get_converter(c_type) {
let mut buf: Vec<u8> = Vec::new(); let mut buf: Vec<u8> = Vec::new();
match c.convert(Rc::new(val), &mut buf) { match c.convert(Rc::new(val), &mut buf) {
Ok(_) => { Ok(_) => {
@ -289,7 +318,16 @@ impl<Out: Write, Err: Write> Builtins<Out, Err> {
return Err(dbg!(Error {})); return Err(dbg!(Error {}));
} }
fn map<P: AsRef<Path>>(&self, path: P, stack: &mut Vec<Rc<Value>>) -> Result<(), Error> { fn map<P: AsRef<Path>, O, E>(
&self,
path: P,
stack: &mut Vec<Rc<Value>>,
env: Rc<RefCell<Environment<O, E>>>,
) -> Result<(), Error>
where
O: std::io::Write,
E: std::io::Write,
{
// get the list from the stack // get the list from the stack
let list = if let Some(list) = stack.pop() { let list = if let Some(list) = stack.pop() {
list list
@ -326,13 +364,27 @@ impl<Out: Write, Err: Write> Builtins<Out, Err> {
// push function argument on the stack. // push function argument on the stack.
stack.push(e.clone()); stack.push(e.clone());
// call function and push it's result on the stack. // call function and push it's result on the stack.
result_elems.push(VM::fcall_impl(path.as_ref().to_owned(), f, stack)?); result_elems.push(VM::fcall_impl(
path.as_ref().to_owned(),
f,
stack,
env.clone(),
)?);
} }
stack.push(Rc::new(C(List(result_elems)))); stack.push(Rc::new(C(List(result_elems))));
Ok(()) Ok(())
} }
fn filter<P: AsRef<Path>>(&self, path: P, stack: &mut Vec<Rc<Value>>) -> Result<(), Error> { fn filter<P: AsRef<Path>, O, E>(
&self,
path: P,
stack: &mut Vec<Rc<Value>>,
env: Rc<RefCell<Environment<O, E>>>,
) -> Result<(), Error>
where
O: std::io::Write,
E: std::io::Write,
{
// get the list from the stack // get the list from the stack
let list = if let Some(list) = stack.pop() { let list = if let Some(list) = stack.pop() {
list list
@ -369,7 +421,7 @@ impl<Out: Write, Err: Write> Builtins<Out, Err> {
// push function argument on the stack. // push function argument on the stack.
stack.push(e.clone()); stack.push(e.clone());
// call function and push it's result on the stack. // call function and push it's result on the stack.
let condition = VM::fcall_impl(path.as_ref().to_owned(), f, stack)?; let condition = VM::fcall_impl(path.as_ref().to_owned(), f, stack, env.clone())?;
// Check for empty or boolean results and only push e back in // Check for empty or boolean results and only push e back in
// if they are non empty and true // if they are non empty and true
match condition.as_ref() { match condition.as_ref() {
@ -412,7 +464,16 @@ impl<Out: Write, Err: Write> Builtins<Out, Err> {
Ok(()) Ok(())
} }
fn reduce<P: AsRef<Path>>(&self, path: P, stack: &mut Vec<Rc<Value>>) -> Result<(), Error> { fn reduce<P: AsRef<Path>, O, E>(
&self,
path: P,
stack: &mut Vec<Rc<Value>>,
env: Rc<RefCell<Environment<O, E>>>,
) -> Result<(), Error>
where
O: std::io::Write,
E: std::io::Write,
{
// get the list from the stack // get the list from the stack
let list = if let Some(list) = stack.pop() { let list = if let Some(list) = stack.pop() {
list list
@ -455,7 +516,7 @@ impl<Out: Write, Err: Write> Builtins<Out, Err> {
stack.push(e.clone()); stack.push(e.clone());
stack.push(acc.clone()); stack.push(acc.clone());
// call function and push it's result on the stack. // call function and push it's result on the stack.
acc = VM::fcall_impl(path.as_ref().to_owned(), f, stack)?; acc = VM::fcall_impl(path.as_ref().to_owned(), f, stack, env.clone())?;
// Check for empty or boolean results and only push e back in // Check for empty or boolean results and only push e back in
// if they are non empty and true // if they are non empty and true
} }
@ -505,7 +566,16 @@ impl<Out: Write, Err: Write> Builtins<Out, Err> {
Ok(()) Ok(())
} }
fn trace(&mut self, mut stack: &mut Vec<Rc<Value>>, pos: Position) -> Result<(), Error> { fn trace<O, E>(
&mut self,
stack: &mut Vec<Rc<Value>>,
pos: Position,
env: Rc<RefCell<Environment<O, E>>>,
) -> Result<(), Error>
where
O: std::io::Write,
E: std::io::Write,
{
let val = if let Some(val) = dbg!(stack.pop()) { let val = if let Some(val) = dbg!(stack.pop()) {
val val
} else { } else {
@ -521,9 +591,11 @@ impl<Out: Write, Err: Write> Builtins<Out, Err> {
}; };
let writable_val: Val = TryFrom::try_from(val.clone())?; let writable_val: Val = TryFrom::try_from(val.clone())?;
if let Err(_) = writeln!( if let Err(_) = writeln!(
&mut self.stderr, &mut env.borrow_mut().stderr,
"TRACE: {} = {} at {}", "TRACE: {} = {} at {}",
expr_pretty, writable_val, pos expr_pretty,
writable_val,
pos
) { ) {
return Err(dbg!(Error {})); return Err(dbg!(Error {}));
}; };

View File

@ -11,8 +11,10 @@
// 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::environment::Environment;
use super::scope::Stack; use super::scope::Stack;
use super::Composite::{List, Tuple}; use super::Composite::{List, Tuple};
use super::Op::{ use super::Op::{
@ -27,7 +29,8 @@ use super::VM;
macro_rules! assert_cases { macro_rules! assert_cases {
(__impl__ $cases:expr) => { (__impl__ $cases:expr) => {
for case in $cases.drain(0..) { for case in $cases.drain(0..) {
let mut vm = VM::new("foo.ucg", Rc::new(case.0)); let env = Rc::new(RefCell::new(Environment::new(Vec::new(), Vec::new())));
let mut vm = VM::new("foo.ucg", Rc::new(case.0), env);
vm.run().unwrap(); vm.run().unwrap();
assert_eq!(dbg!(vm.pop()).unwrap(), Rc::new(case.1)); assert_eq!(dbg!(vm.pop()).unwrap(), Rc::new(case.1));
} }
@ -116,7 +119,8 @@ fn bind_op() {
)]; )];
for case in cases.drain(0..) { for case in cases.drain(0..) {
let mut vm = VM::new("bar.ucg", Rc::new(case.0)); let env = Rc::new(RefCell::new(Environment::new(Vec::new(), Vec::new())));
let mut vm = VM::new("bar.ucg", Rc::new(case.0), env);
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();
@ -577,7 +581,8 @@ macro_rules! assert_parse_cases {
// TODO(jwall): preprocessor // TODO(jwall): preprocessor
let ops = Rc::new(translate::AST::translate(stmts)); let ops = Rc::new(translate::AST::translate(stmts));
assert!(ops.len() > 0); assert!(ops.len() > 0);
let mut vm = VM::new("foo.ucg", ops.clone()); let env = Rc::new(RefCell::new(Environment::new(Vec::new(), Vec::new())));
let mut vm = VM::new("foo.ucg", ops.clone(), env);
vm.run().unwrap(); vm.run().unwrap();
assert_eq!(vm.pop().unwrap(), Rc::new(case.1)); assert_eq!(vm.pop().unwrap(), Rc::new(case.1));
} }
@ -760,11 +765,11 @@ fn simple_trace() {
let stmts = parse(OffsetStrIter::from(dbg!("TRACE 1+1;")), None).unwrap(); let stmts = parse(OffsetStrIter::from(dbg!("TRACE 1+1;")), None).unwrap();
let ops = Rc::new(translate::AST::translate(stmts)); let ops = Rc::new(translate::AST::translate(stmts));
assert!(ops.len() > 0); assert!(ops.len() > 0);
let mut vm = VM::new("foo.ucg", ops.clone()); let env = Rc::new(RefCell::new(Environment::new(Vec::new(), Vec::new())));
let mut vm = VM::new("foo.ucg", ops.clone(), env);
vm.run().unwrap(); vm.run().unwrap();
assert_eq!(vm.pop().unwrap(), Rc::new(P(Int(2)))); assert_eq!(vm.pop().unwrap(), Rc::new(P(Int(2))));
let runtime = vm.get_runtime(); let err_out = &vm.env.borrow().stderr;
let err_out = runtime.get_stderr();
assert_eq!( assert_eq!(
String::from_utf8_lossy(err_out).to_owned(), String::from_utf8_lossy(err_out).to_owned(),
"TRACE: 1 + 1 = 2 at line: 1 column: 1\n" "TRACE: 1 + 1 = 2 at line: 1 column: 1\n"

View File

@ -12,10 +12,10 @@
// 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 crate::ast::{BinaryExprType, Expression, FormatArgs, Statement, Value}; use crate::ast::{BinaryExprType, Expression, FormatArgs, Statement, Value};
use crate::ast::{FuncOpDef, Position, TemplatePart}; use crate::ast::{FuncOpDef, TemplatePart};
use crate::build::format::{ExpressionTemplate, SimpleTemplate, TemplateParser}; use crate::build::format::{ExpressionTemplate, SimpleTemplate, TemplateParser};
use crate::build::opcode::Primitive; use crate::build::opcode::Primitive;
use crate::build::opcode::{Func, Hook, Op}; use crate::build::opcode::{Hook, Op};
pub struct AST(); pub struct AST();

View File

@ -11,11 +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::cell::Ref;
use std::cell::RefCell; use std::cell::RefCell;
use std::path::PathBuf; use std::path::PathBuf;
use std::rc::Rc; use std::rc::Rc;
use super::environment::Environment;
use super::pointer::OpPointer; use super::pointer::OpPointer;
use super::runtime; use super::runtime;
use super::scope::Stack; use super::scope::Stack;
@ -26,35 +26,48 @@ use super::Value::{C, F, M, P, S, T};
use super::{Error, Op, Primitive, Value}; use super::{Error, Op, Primitive, Value};
use super::{Func, Module}; use super::{Func, Module};
pub struct VM { pub struct VM<O, E>
where
O: std::io::Write,
E: std::io::Write,
{
stack: Vec<Rc<Value>>, stack: Vec<Rc<Value>>,
symbols: Stack, symbols: Stack,
// FIXME(jwall): This should be parameterized. runtime: runtime::Builtins,
runtime: Rc<RefCell<runtime::Builtins<Vec<u8>, Vec<u8>>>>,
ops: OpPointer, ops: OpPointer,
// TODO(jwall): This should be optional // TODO(jwall): This should be optional
path: PathBuf, path: PathBuf,
pub env: Rc<RefCell<Environment<O, E>>>,
} }
impl<'a> VM { impl<'a, O, E> VM<O, E>
pub fn new<P: Into<PathBuf>>(path: P, ops: Rc<Vec<Op>>) -> Self { where
Self::with_pointer(path, OpPointer::new(ops)) O: std::io::Write,
E: std::io::Write,
{
pub fn new<P: Into<PathBuf>>(
path: P,
ops: Rc<Vec<Op>>,
env: Rc<RefCell<Environment<O, E>>>,
) -> Self {
Self::with_pointer(path, OpPointer::new(ops), env)
} }
pub fn with_pointer<P: Into<PathBuf>>(path: P, ops: OpPointer) -> Self { pub fn with_pointer<P: Into<PathBuf>>(
path: P,
ops: OpPointer,
env: Rc<RefCell<Environment<O, E>>>,
) -> Self {
Self { Self {
stack: Vec::new(), stack: Vec::new(),
symbols: Stack::new(), symbols: Stack::new(),
runtime: Rc::new(RefCell::new(runtime::Builtins::new(Vec::new(), Vec::new()))), runtime: runtime::Builtins::new(),
ops: ops, ops: ops,
path: path.into(), path: path.into(),
env: env,
} }
} }
pub fn get_runtime(&self) -> Ref<runtime::Builtins<Vec<u8>, Vec<u8>>> {
self.runtime.as_ref().borrow()
}
pub fn to_scoped(self, symbols: Stack) -> Self { pub fn to_scoped(self, symbols: Stack) -> Self {
Self { Self {
stack: Vec::new(), stack: Vec::new(),
@ -62,6 +75,7 @@ impl<'a> VM {
runtime: self.runtime.clone(), runtime: self.runtime.clone(),
ops: self.ops.clone(), ops: self.ops.clone(),
path: self.path.clone(), path: self.path.clone(),
env: self.env.clone(),
} }
} }
@ -304,6 +318,7 @@ impl<'a> VM {
path: P, path: P,
f: &Func, f: &Func,
stack: &mut Vec<Rc<Value>>, stack: &mut Vec<Rc<Value>>,
env: Rc<RefCell<Environment<O, E>>>,
) -> Result<Rc<Value>, Error> { ) -> Result<Rc<Value>, Error> {
let Func { let Func {
ref ptr, ref ptr,
@ -311,7 +326,7 @@ impl<'a> VM {
ref snapshot, ref snapshot,
} = f; } = f;
// use the captured scope snapshot for the function. // use the captured scope snapshot for the function.
let mut vm = Self::with_pointer(path, ptr.clone()).to_scoped(snapshot.clone()); let mut vm = Self::with_pointer(path, ptr.clone(), env).to_scoped(snapshot.clone());
for nm in bindings.iter() { 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.
// TODO(jwall): This should do a better error if there is // TODO(jwall): This should do a better error if there is
@ -327,7 +342,8 @@ impl<'a> VM {
fn op_new_scope(&mut self, jp: i32, ptr: OpPointer) -> Result<(), Error> { fn op_new_scope(&mut self, jp: i32, ptr: OpPointer) -> Result<(), Error> {
let scope_snapshot = self.symbols.snapshot(); let scope_snapshot = self.symbols.snapshot();
dbg!(&ptr); dbg!(&ptr);
let mut vm = Self::with_pointer(&self.path, ptr).to_scoped(scope_snapshot); let mut vm =
Self::with_pointer(&self.path, ptr, self.env.clone()).to_scoped(scope_snapshot);
dbg!(&vm.stack); dbg!(&vm.stack);
vm.run()?; vm.run()?;
dbg!(&vm.stack); dbg!(&vm.stack);
@ -339,7 +355,7 @@ impl<'a> VM {
fn op_fcall(&mut self) -> Result<(), Error> { fn op_fcall(&mut self) -> Result<(), Error> {
let f = dbg!(self.pop())?; let f = dbg!(self.pop())?;
if let &F(ref f) = f.as_ref() { if let &F(ref f) = f.as_ref() {
let val = Self::fcall_impl(&self.path, f, &mut self.stack)?; let val = Self::fcall_impl(&self.path, f, &mut self.stack, self.env.clone())?;
self.push(dbg!(val))?; self.push(dbg!(val))?;
} }
Ok(()) Ok(())
@ -641,7 +657,7 @@ impl<'a> VM {
} }
// 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(self.path.clone(), ptr.clone()); let mut vm = Self::with_pointer(self.path.clone(), ptr.clone(), self.env.clone());
vm.push(Rc::new(S("mod".to_owned())))?; vm.push(Rc::new(S("mod".to_owned())))?;
vm.push(Rc::new(C(Tuple(flds))))?; vm.push(Rc::new(C(Tuple(flds))))?;
vm.run()?; vm.run()?;
@ -757,8 +773,7 @@ impl<'a> VM {
fn op_runtime(&mut self, h: Hook) -> Result<(), Error> { fn op_runtime(&mut self, h: Hook) -> Result<(), Error> {
self.runtime self.runtime
.borrow_mut() .handle(&self.path, h, &mut self.stack, self.env.clone())
.handle(&self.path, h, &mut self.stack)
} }
fn op_render(&mut self) -> Result<(), Error> { fn op_render(&mut self) -> Result<(), Error> {