From c1414bdde4f6cb1c5050fcf37bd167a881cfa6e4 Mon Sep 17 00:00:00 2001 From: Jeremy Wall Date: Sat, 4 Jan 2020 09:10:25 -0600 Subject: [PATCH] DEV: Removing gratuitous use of Rc. It was unnecessary once I better understood the ownership model and it had a significant performance cost. Removing it brought the runtime for the integration tests down from an average of 6 seconds to less than a second on my laptop. --- src/build/compile_test.rs | 9 +++- src/build/mod.rs | 19 +++---- src/build/opcode/environment.rs | 8 +-- src/build/opcode/runtime.rs | 43 ++++++++------- src/build/opcode/vm.rs | 93 ++++++++++++++++++--------------- src/build/test.rs | 23 +++++--- src/convert/exec.rs | 12 +++-- src/main.rs | 67 ++++++++++++++++-------- 8 files changed, 160 insertions(+), 114 deletions(-) diff --git a/src/build/compile_test.rs b/src/build/compile_test.rs index ea7e030..a2d3f0a 100644 --- a/src/build/compile_test.rs +++ b/src/build/compile_test.rs @@ -12,16 +12,20 @@ // See the License for the specific language governing permissions and // limitations under the License. +use std::cell::RefCell; + use regex::Regex; //TODO(jwall): use super::assets::MemoryCache; use super::FileBuilder; +use crate::build::opcode::Environment; fn assert_build(input: &str) { let i_paths = Vec::new(); let out_buffer: Vec = Vec::new(); let err_buffer: Vec = Vec::new(); - let mut b = FileBuilder::new("", &i_paths, out_buffer, err_buffer); + let env = RefCell::new(Environment::new(out_buffer, err_buffer)); + let mut b = FileBuilder::new("", &i_paths, &env); b.enable_validate_mode(); b.eval_string(input).unwrap(); let env = b.environment.borrow(); @@ -34,7 +38,8 @@ fn assert_build_failure(input: &str, expect: Vec) { let i_paths = Vec::new(); let out_buffer: Vec = Vec::new(); let err_buffer: Vec = Vec::new(); - let mut b = FileBuilder::new("", &i_paths, out_buffer, err_buffer); + let env = RefCell::new(Environment::new(out_buffer, err_buffer)); + let mut b = FileBuilder::new("", &i_paths, &env); b.enable_validate_mode(); let err = b.eval_string(input); match err { diff --git a/src/build/mod.rs b/src/build/mod.rs index 0f883f2..d2384fd 100644 --- a/src/build/mod.rs +++ b/src/build/mod.rs @@ -16,7 +16,6 @@ use std::cell::RefCell; use std::collections::HashMap; use std::convert::TryInto; -use std::env; use std::error::Error; use std::fs::File; use std::io::Read; @@ -91,7 +90,7 @@ where Stdout: std::io::Write + Clone, Stderr: std::io::Write + Clone, { - pub environment: Rc>>, + pub environment: &'a RefCell>, working_dir: PathBuf, strict: bool, // FIXME(jwall): These need to be compiled and added to the op cache. @@ -112,13 +111,10 @@ where pub fn new>( working_dir: P, import_paths: &'a Vec, - stdout: Stdout, - stderr: Stderr, + environment: &'a RefCell>, ) -> Self { - let mut environment = Environment::new_with_vars(stdout, stderr, env::vars().collect()); - environment.populate_stdlib(); FileBuilder { - environment: Rc::new(RefCell::new(environment)), + environment: environment, strict: false, // Our import stack is initialized with ourself. working_dir: working_dir.into(), @@ -201,7 +197,6 @@ where let mut vm = VM::new( self.strict, Rc::new(ops), - self.environment.clone(), &self.working_dir, ); if path.is_some() { @@ -210,7 +205,7 @@ where if self.validate_mode { vm.enable_validate_mode(); } - vm.run()?; + vm.run(self.environment)?; self.out = Some(Rc::new(vm.symbols_to_tuple(false).into())); Ok(()) } @@ -227,7 +222,6 @@ where let mut vm = VM::new( self.strict, Rc::new(PositionMap::new()), - self.environment.clone(), &self.working_dir, ); loop { @@ -286,7 +280,7 @@ where let stmts = parse(OffsetStrIter::new(&stmt), None)?; let ops = translate::AST::translate(stmts, &self.working_dir); vm = vm.to_new_pointer(OpPointer::new(Rc::new(ops))); - match vm.run() { + match vm.run(self.environment) { // print the result Err(e) => eprintln!("{}", e), Ok(_) => { @@ -346,13 +340,12 @@ where let mut vm = VM::new( self.strict, Rc::new(ops_map), - self.environment.clone(), &self.working_dir, ); if self.validate_mode { vm.enable_validate_mode(); } - vm.run()?; + vm.run(self.environment)?; if let Some((val, _)) = vm.last.clone() { return Ok(Rc::new(val.try_into()?)); } diff --git a/src/build/opcode/environment.rs b/src/build/opcode/environment.rs index a67da97..18bb64e 100644 --- a/src/build/opcode/environment.rs +++ b/src/build/opcode/environment.rs @@ -51,7 +51,7 @@ impl Environment { } pub fn new_with_vars(out: Stdout, err: Stderr, vars: BTreeMap) -> Self { - Self { + let mut me = Self { val_cache: BTreeMap::new(), env_vars: vars, op_cache: cache::Ops::new(), @@ -61,7 +61,9 @@ impl Environment { stdout: out, stderr: err, out_lock: BTreeSet::new(), - } + }; + me.populate_stdlib(); + return me } pub fn get_cached_path_val(&self, path: &String) -> Option> { @@ -119,7 +121,7 @@ impl Environment { Ok(()) } - pub fn populate_stdlib(&mut self) { + fn populate_stdlib(&mut self) { for (p, s) in stdlib::get_libs().drain() { // We unwrap the error here since we expect stdlibs to // always compile. diff --git a/src/build/opcode/runtime.rs b/src/build/opcode/runtime.rs index a943dca..c8b8341 100644 --- a/src/build/opcode/runtime.rs +++ b/src/build/opcode/runtime.rs @@ -57,12 +57,12 @@ impl Builtins { self.validate_mode = true; } - pub fn handle( + pub fn handle<'a, P, WP, O, E>( &mut self, path: Option

, h: Hook, stack: &mut Vec<(Rc, Position)>, - env: Rc>>, + env: &'a RefCell>, import_stack: &mut Vec, working_dir: WP, pos: Position, @@ -178,11 +178,11 @@ impl Builtins { Ok(contents) } - fn import( + fn import<'a, P, O, E>( &mut self, base_path: P, stack: &mut Vec<(Rc, Position)>, - env: Rc>>, + env: &'a RefCell>, import_stack: &mut Vec, pos: Position, ) -> Result<(), Error> @@ -220,11 +220,10 @@ impl Builtins { let mut vm = VM::with_pointer( self.strict, op_pointer, - env.clone(), normalized.parent().unwrap(), ) .with_import_stack(import_stack.clone()); - vm.run()?; + vm.run(env)?; let result = Rc::new(vm.symbols_to_tuple(true)); env.borrow_mut().update_path_val(&path, result.clone()); stack.push((result, pos)); @@ -238,11 +237,11 @@ impl Builtins { unreachable!(); } - fn include( + fn include<'a, P, O, E>( &self, base_path: P, stack: &mut Vec<(Rc, Position)>, - env: Rc>>, + env: &'a RefCell>, pos: Position, ) -> Result<(), Error> where @@ -307,10 +306,10 @@ impl Builtins { Ok(()) } - fn assert( + fn assert<'a, O, E>( &mut self, stack: &mut Vec<(Rc, Position)>, - env: Rc>>, + env: &'a RefCell>, ) -> Result<(), Error> where O: std::io::Write + Clone, @@ -365,11 +364,11 @@ impl Builtins { return Ok(()); } - fn out( + fn out<'a, P, O, E>( &self, path: Option

, stack: &mut Vec<(Rc, Position)>, - env: Rc>>, + env: &'a RefCell>, pos: Position, ) -> Result<(), Error> where @@ -432,10 +431,10 @@ impl Builtins { unreachable!(); } - fn convert( + fn convert<'a, O, E>( &self, stack: &mut Vec<(Rc, Position)>, - env: Rc>>, + env: &'a RefCell>, pos: Position, ) -> Result<(), Error> where @@ -477,10 +476,10 @@ impl Builtins { unreachable!() } - fn map( + fn map<'a, O, E>( &self, stack: &mut Vec<(Rc, Position)>, - env: Rc>>, + env: &'a RefCell>, import_stack: &Vec, pos: Position, ) -> Result<(), Error> @@ -589,10 +588,10 @@ impl Builtins { Ok(()) } - fn filter( + fn filter<'a, O, E>( &self, stack: &mut Vec<(Rc, Position)>, - env: Rc>>, + env: &'a RefCell>, import_stack: &Vec, pos: Position, ) -> Result<(), Error> @@ -735,10 +734,10 @@ impl Builtins { Ok(()) } - fn reduce( + fn reduce<'a, O, E>( &self, stack: &mut Vec<(Rc, Position)>, - env: Rc>>, + env: &'a RefCell>, import_stack: &Vec, pos: Position, ) -> Result<(), Error> @@ -875,11 +874,11 @@ impl Builtins { Ok(()) } - fn trace( + fn trace<'a, O, E>( &mut self, stack: &mut Vec<(Rc, Position)>, pos: Position, - env: Rc>>, + env: &'a RefCell>, ) -> Result<(), Error> where O: std::io::Write + Clone, diff --git a/src/build/opcode/vm.rs b/src/build/opcode/vm.rs index 17f05ca..19f7ce5 100644 --- a/src/build/opcode/vm.rs +++ b/src/build/opcode/vm.rs @@ -42,41 +42,30 @@ fn construct_reserved_word_set() -> BTreeSet<&'static str> { words } -pub struct VM -where - O: std::io::Write + Clone, - E: std::io::Write + Clone, -{ +pub struct VM { working_dir: PathBuf, stack: Vec<(Rc, Position)>, symbols: Stack, import_stack: Vec, runtime: runtime::Builtins, ops: OpPointer, - pub env: Rc>>, pub last: Option<(Rc, Position)>, self_stack: Vec<(Rc, Position)>, reserved_words: BTreeSet<&'static str>, } -impl<'a, O, E> VM -where - O: std::io::Write + Clone, - E: std::io::Write + Clone, -{ +impl VM { pub fn new>( strict: bool, ops: Rc, - env: Rc>>, working_dir: P, ) -> Self { - Self::with_pointer(strict, OpPointer::new(ops), env, working_dir) + Self::with_pointer(strict, OpPointer::new(ops), working_dir) } pub fn with_pointer>( strict: bool, ops: OpPointer, - env: Rc>>, working_dir: P, ) -> Self { Self { @@ -86,7 +75,6 @@ where import_stack: Vec::new(), runtime: runtime::Builtins::new(strict), ops: ops, - env: env, last: None, self_stack: Vec::new(), reserved_words: construct_reserved_word_set(), @@ -119,7 +107,6 @@ where import_stack: Vec::new(), runtime: self.runtime.clone(), ops: self.ops.clone(), - env: self.env.clone(), last: None, self_stack: self.self_stack.clone(), reserved_words: self.reserved_words.clone(), @@ -148,7 +135,11 @@ where self.symbols.remove_symbol(sym) } - pub fn run(&mut self) -> Result<(), Error> { + pub fn run<'a, O, E>(&mut self, env: &'a RefCell>) -> Result<(), Error> + where + O: std::io::Write + Clone, + E: std::io::Write + Clone, + { loop { let op = if let Some(op) = self.ops.next() { op.clone() @@ -184,7 +175,7 @@ where Op::Index => self.op_index(!self.runtime.strict, pos)?, Op::SafeIndex => self.op_index(true, pos)?, Op::Exist => self.op_exist(pos)?, - Op::Cp => self.op_copy(pos)?, + Op::Cp => self.op_copy(pos, env)?, //FIXME(jwall): Should this take a user provided message? Op::Bang => self.op_bang()?, Op::InitThunk(jp) => self.op_thunk(idx, jp, pos)?, @@ -199,8 +190,8 @@ where Op::Or(jp) => self.op_or(jp, pos)?, Op::Module(mptr) => self.op_module(idx, mptr, pos)?, Op::Func(jptr) => self.op_func(idx, jptr, pos)?, - Op::FCall => self.op_fcall(pos)?, - Op::NewScope(jp) => self.op_new_scope(jp, self.ops.clone())?, + Op::FCall => self.op_fcall(pos, env)?, + Op::NewScope(jp) => self.op_new_scope(jp, self.ops.clone(), env)?, Op::Return => { &self.stack; return Ok(()); @@ -209,7 +200,7 @@ where self.pop()?; } Op::Typ => self.op_typ()?, - Op::Runtime(h) => self.op_runtime(h, pos)?, + Op::Runtime(h) => self.op_runtime(h, pos, env)?, Op::Render => self.op_render()?, Op::PushSelf => self.op_push_self()?, Op::PopSelf => self.op_pop_self()?, @@ -345,7 +336,7 @@ where Ok(()) } - fn op_select_jump(&'a mut self, jp: i32) -> Result<(), Error> { + fn op_select_jump(&mut self, jp: i32) -> Result<(), Error> { // pop field value off let (field_name, _) = self.pop()?; // pop search value off @@ -372,7 +363,7 @@ where Ok(()) } - fn op_module(&'a mut self, idx: usize, jptr: i32, pos: Position) -> Result<(), Error> { + fn op_module(&mut self, idx: usize, jptr: i32, pos: Position) -> Result<(), Error> { let (mod_val, mod_val_pos) = self.pop()?; let (result_ptr, flds, pos_list) = match mod_val.as_ref() { &C(Tuple(ref flds, ref pos_list)) => (None, flds.clone(), pos_list.clone()), @@ -467,20 +458,24 @@ where self.op_jump(jptr) } - pub fn fcall_impl( + pub fn fcall_impl<'a, O, E>( f: &Func, strict: bool, stack: &mut Vec<(Rc, Position)>, - env: Rc>>, + env: &'a RefCell>, import_stack: &Vec, - ) -> Result<(Rc, Position), Error> { + ) -> Result<(Rc, Position), Error> + where + O: std::io::Write + Clone, + E: std::io::Write + Clone, + { let Func { ref ptr, ref bindings, ref snapshot, } = f; // use the captured scope snapshot for the function. - let mut vm = Self::with_pointer(strict, ptr.clone(), env, std::env::current_dir()?) + let mut vm = Self::with_pointer(strict, ptr.clone(), std::env::current_dir()?) .to_scoped(snapshot.clone()) .with_import_stack(import_stack.clone()); for nm in bindings.iter() { @@ -491,25 +486,33 @@ where vm.binding_push(nm.clone(), val, false, &pos, &pos)?; } // proceed to the function body - vm.run()?; + vm.run(env)?; return vm.pop(); } - fn op_new_scope(&mut self, jp: i32, ptr: OpPointer) -> Result<(), Error> { + fn op_new_scope(&mut self, jp: i32, ptr: OpPointer, env: &RefCell>) -> Result<(), Error> + where + O: std::io::Write + Clone, + E: std::io::Write + Clone, + { let scope_snapshot = self.symbols.snapshot(); let mut vm = self .clean_copy() .to_new_pointer(ptr) .to_scoped(scope_snapshot) .with_import_stack(self.import_stack.clone()); - vm.run()?; + vm.run(env)?; let result = vm.pop()?; self.push(result.0, result.1)?; self.op_jump(jp)?; Ok(()) } - fn op_fcall(&mut self, pos: Position) -> Result<(), Error> { + fn op_fcall(&mut self, pos: Position, env: &RefCell>) -> Result<(), Error> + where + O: std::io::Write + Clone, + E: std::io::Write + Clone, + { let (f, f_pos) = self.pop()?; let (arg_length, _) = self.pop()?; if let &F(ref f) = f.as_ref() { @@ -535,7 +538,7 @@ where } } let (val, _) = decorate_call!(f_pos => - Self::fcall_impl(f, self.runtime.strict, &mut self.stack, self.env.clone(), &self.import_stack))?; + Self::fcall_impl(f, self.runtime.strict, &mut self.stack, env.clone(), &self.import_stack))?; self.push(val, pos.clone())?; } else { return Err(Error::new(format!("Not a function! {:?}", f,), pos)); @@ -888,7 +891,11 @@ where Ok(()) } - fn op_copy(&mut self, pos: Position) -> Result<(), Error> { + fn op_copy(&mut self, pos: Position, env: &RefCell>) -> Result<(), Error> + where + O: std::io::Write + Clone, + E: std::io::Write + Clone, + { // This value should always be a tuple let (override_val, val_pos) = self.pop()?; // get target value. It should be a Module or Tuple. @@ -965,7 +972,7 @@ where .clean_copy() .to_new_pointer(ptr.clone()) .with_import_stack(self.import_stack.clone()); - pkg_vm.run()?; + pkg_vm.run(env)?; let (pkg_func, val_pos) = pkg_vm.pop()?; self.merge_field_into_tuple( &mut flds, @@ -983,10 +990,10 @@ where .with_import_stack(self.import_stack.clone()); vm.push(Rc::new(S("mod".to_owned())), pos.clone())?; vm.push(Rc::new(C(Tuple(flds, flds_pos_list))), pos.clone())?; - decorate_call!(pos => vm.run())?; + decorate_call!(pos => vm.run(env))?; if let Some(ptr) = result_ptr { vm.ops.jump(ptr.clone())?; - vm.run()?; + vm.run(env)?; let (result_val, result_pos) = vm.pop()?; self.push(result_val, result_pos)?; } else { @@ -1005,8 +1012,8 @@ where fn merge_field_into_tuple( &self, - src_fields: &'a mut Vec<(String, Rc)>, - pos_fields: &'a mut Vec<(Position, Position)>, + src_fields: &mut Vec<(String, Rc)>, + pos_fields: &mut Vec<(Position, Position)>, name: String, name_pos: &Position, value: Rc, @@ -1069,7 +1076,7 @@ where } pub fn get_binding( - &'a self, + &self, name: &str, pos: &Position, ) -> Result<(Rc, Position), Error> { @@ -1189,12 +1196,16 @@ where }) } - fn op_runtime(&mut self, h: Hook, pos: Position) -> Result<(), Error> { + fn op_runtime(&mut self, h: Hook, pos: Position, env: &RefCell>) -> Result<(), Error> + where + O: std::io::Write + Clone, + E: std::io::Write + Clone, + { self.runtime.handle( self.ops.path.as_ref(), h, &mut self.stack, - self.env.clone(), + env, &mut self.import_stack, &self.working_dir, pos, diff --git a/src/build/test.rs b/src/build/test.rs index f05698b..126c37d 100644 --- a/src/build/test.rs +++ b/src/build/test.rs @@ -11,11 +11,13 @@ // 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 super::{FileBuilder, Val}; -use crate::ast::*; - use std; use std::rc::Rc; +use std::cell::RefCell; + +use super::{FileBuilder, Val}; +use crate::ast::*; +use crate::build::Environment; fn test_expr_to_val<'a, O, E>(mut cases: Vec<(Expression, Val)>, mut b: FileBuilder<'a, O, E>) where @@ -33,7 +35,8 @@ fn test_eval_div_expr_fail() { let i_paths = Vec::new(); let out: Vec = Vec::new(); let err: Vec = Vec::new(); - let b = FileBuilder::new(std::env::current_dir().unwrap(), &i_paths, out, err); + let env = RefCell::new(Environment::new(out, err)); + let b = FileBuilder::new(std::env::current_dir().unwrap(), &i_paths, &env); test_expr_to_val( vec![( Expression::Binary(BinaryOpDef { @@ -60,7 +63,8 @@ fn test_eval_mul_expr_fail() { let i_paths = Vec::new(); let out: Vec = Vec::new(); let err: Vec = Vec::new(); - let b = FileBuilder::new(std::env::current_dir().unwrap(), &i_paths, out, err); + let env = RefCell::new(Environment::new(out, err)); + let b = FileBuilder::new(std::env::current_dir().unwrap(), &i_paths, &env); test_expr_to_val( vec![( Expression::Binary(BinaryOpDef { @@ -87,7 +91,8 @@ fn test_eval_subtract_expr_fail() { let i_paths = Vec::new(); let out: Vec = Vec::new(); let err: Vec = Vec::new(); - let b = FileBuilder::new(std::env::current_dir().unwrap(), &i_paths, out, err); + let env = RefCell::new(Environment::new(out, err)); + let b = FileBuilder::new(std::env::current_dir().unwrap(), &i_paths, &env); test_expr_to_val( vec![( Expression::Binary(BinaryOpDef { @@ -113,7 +118,8 @@ fn test_eval_add_expr_fail() { let i_paths = Vec::new(); let out: Vec = Vec::new(); let err: Vec = Vec::new(); - let b = FileBuilder::new(std::env::current_dir().unwrap(), &i_paths, out, err); + let env = RefCell::new(Environment::new(out, err)); + let b = FileBuilder::new(std::env::current_dir().unwrap(), &i_paths, &env); test_expr_to_val( vec![( Expression::Binary(BinaryOpDef { @@ -141,7 +147,8 @@ fn test_expr_copy_no_such_tuple() { let i_paths = Vec::new(); let out: Vec = Vec::new(); let err: Vec = Vec::new(); - let b = FileBuilder::new(std::env::current_dir().unwrap(), &i_paths, out, err); + let env = RefCell::new(Environment::new(out, err)); + let b = FileBuilder::new(std::env::current_dir().unwrap(), &i_paths, &env); test_expr_to_val( vec![( Expression::Copy(CopyDef { diff --git a/src/convert/exec.rs b/src/convert/exec.rs index e99ec03..dd74b09 100644 --- a/src/convert/exec.rs +++ b/src/convert/exec.rs @@ -193,9 +193,12 @@ impl Converter for ExecConverter { #[cfg(test)] mod exec_test { + use std::cell::RefCell; + use super::*; use crate::build::FileBuilder; use crate::convert::traits::Converter; + use crate::build::opcode::Environment; use std; use std::io::Cursor; @@ -205,7 +208,8 @@ mod exec_test { let i_paths = Vec::new(); let out: Vec = Vec::new(); let err: Vec = Vec::new(); - let mut b = FileBuilder::new(std::env::current_dir().unwrap(), &i_paths, out, err); + let env = RefCell::new(Environment::new(out, err)); + let mut b = FileBuilder::new(std::env::current_dir().unwrap(), &i_paths, &env); let conv = ExecConverter::new(); b.eval_string( "let script = { @@ -228,7 +232,8 @@ mod exec_test { let i_paths = Vec::new(); let out: Vec = Vec::new(); let err: Vec = Vec::new(); - let mut b = FileBuilder::new(std::env::current_dir().unwrap(), &i_paths, out, err); + let env = RefCell::new(Environment::new(out, err)); + let mut b = FileBuilder::new(std::env::current_dir().unwrap(), &i_paths, &env); let conv = ExecConverter::new(); b.eval_string( "let script = { @@ -258,7 +263,8 @@ mod exec_test { let i_paths = Vec::new(); let out: Vec = Vec::new(); let err: Vec = Vec::new(); - let mut b = FileBuilder::new(std::env::current_dir().unwrap(), &i_paths, out, err); + let env = RefCell::new(Environment::new(out, err)); + let mut b = FileBuilder::new(std::env::current_dir().unwrap(), &i_paths, &env); let conv = ExecConverter::new(); b.eval_string( "let script = { diff --git a/src/main.rs b/src/main.rs index 4fe38c0..36e3ff2 100644 --- a/src/main.rs +++ b/src/main.rs @@ -17,6 +17,7 @@ extern crate dirs; extern crate rustyline; extern crate ucglib; +use std::cell::RefCell; use std::collections::BTreeMap; use std::error::Error; use std::fs::File; @@ -26,6 +27,7 @@ use std::path::{Path, PathBuf}; use std::process; use ucglib::build; +use ucglib::build::opcode::Environment; use ucglib::convert::{ConverterRegistry, ImporterRegistry}; use ucglib::iter::OffsetStrIter; use ucglib::parse::parse; @@ -124,14 +126,13 @@ fn build_file<'a>( validate: bool, strict: bool, import_paths: &'a Vec, + env: &'a RefCell>, ) -> Result, Box> { let mut file_path_buf = PathBuf::from(file); if file_path_buf.is_relative() { file_path_buf = std::env::current_dir()?.join(file_path_buf); } - let out = StdoutWrapper::new(); - let err = StderrWrapper::new(); - let mut builder = build::FileBuilder::new(std::env::current_dir()?, import_paths, out, err); +let mut builder = build::FileBuilder::new(std::env::current_dir()?, import_paths, env); builder.set_strict(strict); if validate { builder.enable_validate_mode(); @@ -143,9 +144,14 @@ fn build_file<'a>( Ok(builder) } -fn do_validate(file: &str, strict: bool, import_paths: &Vec) -> bool { +fn do_validate<'a>( + file: &'a str, + strict: bool, + import_paths: &'a Vec, + env: &'a RefCell>, +) -> bool { println!("Validating {}", file); - match build_file(file, true, strict, import_paths) { + match build_file(file, true, strict, import_paths, env) { Ok(b) => { if b.assert_results() { println!("File {} Pass\n", file); @@ -162,9 +168,14 @@ fn do_validate(file: &str, strict: bool, import_paths: &Vec) -> bool { return true; } -fn do_compile(file: &str, strict: bool, import_paths: &Vec) -> bool { +fn do_compile<'a>( + file: &'a str, + strict: bool, + import_paths: &'a Vec, + env: &'a RefCell>, +) -> bool { println!("Building {}", file); - let builder = match build_file(file, false, strict, import_paths) { + let builder = match build_file(file, false, strict, import_paths, env) { Ok(builder) => builder, Err(err) => { eprintln!("{}", err); @@ -183,6 +194,7 @@ fn visit_ucg_files( validate: bool, strict: bool, import_paths: &Vec, + env: &RefCell>, ) -> Result> { let our_path = String::from(path.to_string_lossy()); let mut result = true; @@ -200,35 +212,35 @@ fn visit_ucg_files( let next_path = next_item.path(); let path_as_string = String::from(next_path.to_string_lossy()); if next_path.is_dir() && recurse { - if let Err(e) = visit_ucg_files(&next_path, recurse, validate, strict, import_paths) + if let Err(e) = visit_ucg_files(&next_path, recurse, validate, strict, import_paths, env) { eprintln!("{}", e); result = false; } } else { if validate && path_as_string.ends_with("_test.ucg") { - if !do_validate(&path_as_string, strict, import_paths) { + if !do_validate(&path_as_string, strict, import_paths, env) { result = false; summary.push_str(format!("{} - FAIL\n", path_as_string).as_str()) } else { summary.push_str(format!("{} - PASS\n", path_as_string).as_str()) } } else if !validate && path_as_string.ends_with(".ucg") { - if !do_compile(&path_as_string, strict, import_paths) { + if !do_compile(&path_as_string, strict, import_paths, env) { result = false; } } } } } else if validate && our_path.ends_with("_test.ucg") { - if !do_validate(&our_path, strict, import_paths) { + if !do_validate(&our_path, strict, import_paths, env) { result = false; summary.push_str(format!("{} - FAIL\n", our_path).as_str()); } else { summary.push_str(format!("{} - PASS\n", &our_path).as_str()); } } else if !validate { - if !do_compile(&our_path, strict, import_paths) { + if !do_compile(&our_path, strict, import_paths, env) { result = false; } } @@ -239,13 +251,18 @@ fn visit_ucg_files( Ok(result) } -fn build_command(matches: &clap::ArgMatches, import_paths: &Vec, strict: bool) { +fn build_command( + matches: &clap::ArgMatches, + import_paths: &Vec, + strict: bool, + env: &RefCell>, +) { let files = matches.values_of("INPUT"); let recurse = matches.is_present("recurse"); let mut ok = true; if files.is_none() { let curr_dir = std::env::current_dir().unwrap(); - let ok = visit_ucg_files(curr_dir.as_path(), recurse, false, strict, import_paths); + let ok = visit_ucg_files(curr_dir.as_path(), recurse, false, strict, import_paths, env); if let Ok(false) = ok { process::exit(1) } @@ -253,7 +270,7 @@ fn build_command(matches: &clap::ArgMatches, import_paths: &Vec, strict } for file in files.unwrap() { let pb = PathBuf::from(file); - if let Ok(false) = visit_ucg_files(&pb, recurse, false, strict, import_paths) { + if let Ok(false) = visit_ucg_files(&pb, recurse, false, strict, import_paths, env) { ok = false; } } @@ -325,12 +342,17 @@ fn fmt_command(matches: &clap::ArgMatches) -> std::result::Result<(), Box, strict: bool) { +fn test_command( + matches: &clap::ArgMatches, + import_paths: &Vec, + strict: bool, + env: &RefCell>, +) { let files = matches.values_of("INPUT"); let recurse = matches.is_present("recurse"); if files.is_none() { let curr_dir = std::env::current_dir().unwrap(); - let ok = visit_ucg_files(curr_dir.as_path(), recurse, true, strict, import_paths); + let ok = visit_ucg_files(curr_dir.as_path(), recurse, true, strict, import_paths, env); if let Ok(false) = ok { process::exit(1) } @@ -339,7 +361,7 @@ fn test_command(matches: &clap::ArgMatches, import_paths: &Vec, strict: for file in files.unwrap() { let pb = PathBuf::from(file); //if pb.is_dir() { - if let Ok(false) = visit_ucg_files(pb.as_path(), recurse, true, strict, import_paths) { + if let Ok(false) = visit_ucg_files(pb.as_path(), recurse, true, strict, import_paths, env) { ok = false; } } @@ -426,11 +448,11 @@ fn do_repl(import_paths: &Vec, strict: bool) -> std::result::Result<(), } } } + let env = std::cell::RefCell::new(build::opcode::Environment::new(StdoutWrapper::new(), StderrWrapper::new())); let mut builder = build::FileBuilder::new( std::env::current_dir()?, import_paths, - StdoutWrapper::new(), - StderrWrapper::new(), + &env, ); builder.set_strict(strict); @@ -451,6 +473,7 @@ fn main() { // FIXME(jwall): Do we want these to be shared or not? let registry = ConverterRegistry::make_registry(); let mut import_paths = Vec::new(); + let env = RefCell::new(Environment::new(StdoutWrapper::new(), StderrWrapper::new())); if let Some(mut p) = dirs::home_dir() { p.push(".ucg"); // Attempt to create directory if it doesn't exist. @@ -470,9 +493,9 @@ fn main() { true }; if let Some(matches) = app_matches.subcommand_matches("build") { - build_command(matches, &import_paths, strict); + build_command(matches, &import_paths, strict, &env); } else if let Some(matches) = app_matches.subcommand_matches("test") { - test_command(matches, &import_paths, strict); + test_command(matches, &import_paths, strict, &env); } else if let Some(matches) = app_matches.subcommand_matches("converters") { converters_command(matches, ®istry) } else if let Some(_) = app_matches.subcommand_matches("importers") {