mirror of
https://github.com/zaphar/ucg.git
synced 2025-07-21 18:10:42 -04:00
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.
This commit is contained in:
parent
9f787972ac
commit
c1414bdde4
@ -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<u8> = Vec::new();
|
||||
let err_buffer: Vec<u8> = Vec::new();
|
||||
let mut b = FileBuilder::new("<Eval>", &i_paths, out_buffer, err_buffer);
|
||||
let env = RefCell::new(Environment::new(out_buffer, err_buffer));
|
||||
let mut b = FileBuilder::new("<Eval>", &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<Regex>) {
|
||||
let i_paths = Vec::new();
|
||||
let out_buffer: Vec<u8> = Vec::new();
|
||||
let err_buffer: Vec<u8> = Vec::new();
|
||||
let mut b = FileBuilder::new("<Eval>", &i_paths, out_buffer, err_buffer);
|
||||
let env = RefCell::new(Environment::new(out_buffer, err_buffer));
|
||||
let mut b = FileBuilder::new("<Eval>", &i_paths, &env);
|
||||
b.enable_validate_mode();
|
||||
let err = b.eval_string(input);
|
||||
match err {
|
||||
|
@ -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<RefCell<Environment<Stdout, Stderr>>>,
|
||||
pub environment: &'a RefCell<Environment<Stdout, Stderr>>,
|
||||
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<P: Into<PathBuf>>(
|
||||
working_dir: P,
|
||||
import_paths: &'a Vec<PathBuf>,
|
||||
stdout: Stdout,
|
||||
stderr: Stderr,
|
||||
environment: &'a RefCell<Environment<Stdout, Stderr>>,
|
||||
) -> 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()?));
|
||||
}
|
||||
|
@ -51,7 +51,7 @@ impl<Stdout: Write + Clone, Stderr: Write + Clone> Environment<Stdout, Stderr> {
|
||||
}
|
||||
|
||||
pub fn new_with_vars(out: Stdout, err: Stderr, vars: BTreeMap<String, String>) -> Self {
|
||||
Self {
|
||||
let mut me = Self {
|
||||
val_cache: BTreeMap::new(),
|
||||
env_vars: vars,
|
||||
op_cache: cache::Ops::new(),
|
||||
@ -61,7 +61,9 @@ impl<Stdout: Write + Clone, Stderr: Write + Clone> Environment<Stdout, Stderr> {
|
||||
stdout: out,
|
||||
stderr: err,
|
||||
out_lock: BTreeSet::new(),
|
||||
}
|
||||
};
|
||||
me.populate_stdlib();
|
||||
return me
|
||||
}
|
||||
|
||||
pub fn get_cached_path_val(&self, path: &String) -> Option<Rc<Value>> {
|
||||
@ -119,7 +121,7 @@ impl<Stdout: Write + Clone, Stderr: Write + Clone> Environment<Stdout, Stderr> {
|
||||
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.
|
||||
|
@ -57,12 +57,12 @@ impl Builtins {
|
||||
self.validate_mode = true;
|
||||
}
|
||||
|
||||
pub fn handle<P, WP, O, E>(
|
||||
pub fn handle<'a, P, WP, O, E>(
|
||||
&mut self,
|
||||
path: Option<P>,
|
||||
h: Hook,
|
||||
stack: &mut Vec<(Rc<Value>, Position)>,
|
||||
env: Rc<RefCell<Environment<O, E>>>,
|
||||
env: &'a RefCell<Environment<O, E>>,
|
||||
import_stack: &mut Vec<String>,
|
||||
working_dir: WP,
|
||||
pos: Position,
|
||||
@ -178,11 +178,11 @@ impl Builtins {
|
||||
Ok(contents)
|
||||
}
|
||||
|
||||
fn import<P, O, E>(
|
||||
fn import<'a, P, O, E>(
|
||||
&mut self,
|
||||
base_path: P,
|
||||
stack: &mut Vec<(Rc<Value>, Position)>,
|
||||
env: Rc<RefCell<Environment<O, E>>>,
|
||||
env: &'a RefCell<Environment<O, E>>,
|
||||
import_stack: &mut Vec<String>,
|
||||
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<P, O, E>(
|
||||
fn include<'a, P, O, E>(
|
||||
&self,
|
||||
base_path: P,
|
||||
stack: &mut Vec<(Rc<Value>, Position)>,
|
||||
env: Rc<RefCell<Environment<O, E>>>,
|
||||
env: &'a RefCell<Environment<O, E>>,
|
||||
pos: Position,
|
||||
) -> Result<(), Error>
|
||||
where
|
||||
@ -307,10 +306,10 @@ impl Builtins {
|
||||
Ok(())
|
||||
}
|
||||
|
||||
fn assert<O, E>(
|
||||
fn assert<'a, O, E>(
|
||||
&mut self,
|
||||
stack: &mut Vec<(Rc<Value>, Position)>,
|
||||
env: Rc<RefCell<Environment<O, E>>>,
|
||||
env: &'a RefCell<Environment<O, E>>,
|
||||
) -> Result<(), Error>
|
||||
where
|
||||
O: std::io::Write + Clone,
|
||||
@ -365,11 +364,11 @@ impl Builtins {
|
||||
return Ok(());
|
||||
}
|
||||
|
||||
fn out<P, O, E>(
|
||||
fn out<'a, P, O, E>(
|
||||
&self,
|
||||
path: Option<P>,
|
||||
stack: &mut Vec<(Rc<Value>, Position)>,
|
||||
env: Rc<RefCell<Environment<O, E>>>,
|
||||
env: &'a RefCell<Environment<O, E>>,
|
||||
pos: Position,
|
||||
) -> Result<(), Error>
|
||||
where
|
||||
@ -432,10 +431,10 @@ impl Builtins {
|
||||
unreachable!();
|
||||
}
|
||||
|
||||
fn convert<O, E>(
|
||||
fn convert<'a, O, E>(
|
||||
&self,
|
||||
stack: &mut Vec<(Rc<Value>, Position)>,
|
||||
env: Rc<RefCell<Environment<O, E>>>,
|
||||
env: &'a RefCell<Environment<O, E>>,
|
||||
pos: Position,
|
||||
) -> Result<(), Error>
|
||||
where
|
||||
@ -477,10 +476,10 @@ impl Builtins {
|
||||
unreachable!()
|
||||
}
|
||||
|
||||
fn map<O, E>(
|
||||
fn map<'a, O, E>(
|
||||
&self,
|
||||
stack: &mut Vec<(Rc<Value>, Position)>,
|
||||
env: Rc<RefCell<Environment<O, E>>>,
|
||||
env: &'a RefCell<Environment<O, E>>,
|
||||
import_stack: &Vec<String>,
|
||||
pos: Position,
|
||||
) -> Result<(), Error>
|
||||
@ -589,10 +588,10 @@ impl Builtins {
|
||||
Ok(())
|
||||
}
|
||||
|
||||
fn filter<O, E>(
|
||||
fn filter<'a, O, E>(
|
||||
&self,
|
||||
stack: &mut Vec<(Rc<Value>, Position)>,
|
||||
env: Rc<RefCell<Environment<O, E>>>,
|
||||
env: &'a RefCell<Environment<O, E>>,
|
||||
import_stack: &Vec<String>,
|
||||
pos: Position,
|
||||
) -> Result<(), Error>
|
||||
@ -735,10 +734,10 @@ impl Builtins {
|
||||
Ok(())
|
||||
}
|
||||
|
||||
fn reduce<O, E>(
|
||||
fn reduce<'a, O, E>(
|
||||
&self,
|
||||
stack: &mut Vec<(Rc<Value>, Position)>,
|
||||
env: Rc<RefCell<Environment<O, E>>>,
|
||||
env: &'a RefCell<Environment<O, E>>,
|
||||
import_stack: &Vec<String>,
|
||||
pos: Position,
|
||||
) -> Result<(), Error>
|
||||
@ -875,11 +874,11 @@ impl Builtins {
|
||||
Ok(())
|
||||
}
|
||||
|
||||
fn trace<O, E>(
|
||||
fn trace<'a, O, E>(
|
||||
&mut self,
|
||||
stack: &mut Vec<(Rc<Value>, Position)>,
|
||||
pos: Position,
|
||||
env: Rc<RefCell<Environment<O, E>>>,
|
||||
env: &'a RefCell<Environment<O, E>>,
|
||||
) -> Result<(), Error>
|
||||
where
|
||||
O: std::io::Write + Clone,
|
||||
|
@ -42,41 +42,30 @@ fn construct_reserved_word_set() -> BTreeSet<&'static str> {
|
||||
words
|
||||
}
|
||||
|
||||
pub struct VM<O, E>
|
||||
where
|
||||
O: std::io::Write + Clone,
|
||||
E: std::io::Write + Clone,
|
||||
{
|
||||
pub struct VM {
|
||||
working_dir: PathBuf,
|
||||
stack: Vec<(Rc<Value>, Position)>,
|
||||
symbols: Stack,
|
||||
import_stack: Vec<String>,
|
||||
runtime: runtime::Builtins,
|
||||
ops: OpPointer,
|
||||
pub env: Rc<RefCell<Environment<O, E>>>,
|
||||
pub last: Option<(Rc<Value>, Position)>,
|
||||
self_stack: Vec<(Rc<Value>, Position)>,
|
||||
reserved_words: BTreeSet<&'static str>,
|
||||
}
|
||||
|
||||
impl<'a, O, E> VM<O, E>
|
||||
where
|
||||
O: std::io::Write + Clone,
|
||||
E: std::io::Write + Clone,
|
||||
{
|
||||
impl VM {
|
||||
pub fn new<P: Into<PathBuf>>(
|
||||
strict: bool,
|
||||
ops: Rc<PositionMap>,
|
||||
env: Rc<RefCell<Environment<O, E>>>,
|
||||
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<P: Into<PathBuf>>(
|
||||
strict: bool,
|
||||
ops: OpPointer,
|
||||
env: Rc<RefCell<Environment<O, E>>>,
|
||||
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<Environment<O, E>>) -> 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<Value>, Position)>,
|
||||
env: Rc<RefCell<Environment<O, E>>>,
|
||||
env: &'a RefCell<Environment<O, E>>,
|
||||
import_stack: &Vec<String>,
|
||||
) -> Result<(Rc<Value>, Position), Error> {
|
||||
) -> Result<(Rc<Value>, 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<O, E>(&mut self, jp: i32, ptr: OpPointer, env: &RefCell<Environment<O, E>>) -> 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<O, E>(&mut self, pos: Position, env: &RefCell<Environment<O, E>>) -> 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<O, E>(&mut self, pos: Position, env: &RefCell<Environment<O, E>>) -> 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<Value>)>,
|
||||
pos_fields: &'a mut Vec<(Position, Position)>,
|
||||
src_fields: &mut Vec<(String, Rc<Value>)>,
|
||||
pos_fields: &mut Vec<(Position, Position)>,
|
||||
name: String,
|
||||
name_pos: &Position,
|
||||
value: Rc<Value>,
|
||||
@ -1069,7 +1076,7 @@ where
|
||||
}
|
||||
|
||||
pub fn get_binding(
|
||||
&'a self,
|
||||
&self,
|
||||
name: &str,
|
||||
pos: &Position,
|
||||
) -> Result<(Rc<Value>, Position), Error> {
|
||||
@ -1189,12 +1196,16 @@ where
|
||||
})
|
||||
}
|
||||
|
||||
fn op_runtime(&mut self, h: Hook, pos: Position) -> Result<(), Error> {
|
||||
fn op_runtime<O, E>(&mut self, h: Hook, pos: Position, env: &RefCell<Environment<O, E>>) -> 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,
|
||||
|
@ -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<u8> = Vec::new();
|
||||
let err: Vec<u8> = 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<u8> = Vec::new();
|
||||
let err: Vec<u8> = 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<u8> = Vec::new();
|
||||
let err: Vec<u8> = 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<u8> = Vec::new();
|
||||
let err: Vec<u8> = 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<u8> = Vec::new();
|
||||
let err: Vec<u8> = 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 {
|
||||
|
@ -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<u8> = Vec::new();
|
||||
let err: Vec<u8> = 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<u8> = Vec::new();
|
||||
let err: Vec<u8> = 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<u8> = Vec::new();
|
||||
let err: Vec<u8> = 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 = {
|
||||
|
67
src/main.rs
67
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<PathBuf>,
|
||||
env: &'a RefCell<Environment<StdoutWrapper, StderrWrapper>>,
|
||||
) -> Result<build::FileBuilder<'a, StdoutWrapper, StderrWrapper>, Box<dyn Error>> {
|
||||
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<PathBuf>) -> bool {
|
||||
fn do_validate<'a>(
|
||||
file: &'a str,
|
||||
strict: bool,
|
||||
import_paths: &'a Vec<PathBuf>,
|
||||
env: &'a RefCell<Environment<StdoutWrapper, StderrWrapper>>,
|
||||
) -> 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<PathBuf>) -> bool {
|
||||
return true;
|
||||
}
|
||||
|
||||
fn do_compile(file: &str, strict: bool, import_paths: &Vec<PathBuf>) -> bool {
|
||||
fn do_compile<'a>(
|
||||
file: &'a str,
|
||||
strict: bool,
|
||||
import_paths: &'a Vec<PathBuf>,
|
||||
env: &'a RefCell<Environment<StdoutWrapper, StderrWrapper>>,
|
||||
) -> 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<PathBuf>,
|
||||
env: &RefCell<Environment<StdoutWrapper, StderrWrapper>>,
|
||||
) -> Result<bool, Box<dyn Error>> {
|
||||
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<PathBuf>, strict: bool) {
|
||||
fn build_command(
|
||||
matches: &clap::ArgMatches,
|
||||
import_paths: &Vec<PathBuf>,
|
||||
strict: bool,
|
||||
env: &RefCell<Environment<StdoutWrapper, StderrWrapper>>,
|
||||
) {
|
||||
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<PathBuf>, 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<dyn Er
|
||||
Ok(())
|
||||
}
|
||||
|
||||
fn test_command(matches: &clap::ArgMatches, import_paths: &Vec<PathBuf>, strict: bool) {
|
||||
fn test_command(
|
||||
matches: &clap::ArgMatches,
|
||||
import_paths: &Vec<PathBuf>,
|
||||
strict: bool,
|
||||
env: &RefCell<Environment<StdoutWrapper, StderrWrapper>>,
|
||||
) {
|
||||
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<PathBuf>, 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<PathBuf>, 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") {
|
||||
|
Loading…
x
Reference in New Issue
Block a user