diff --git a/src/build/mod.rs b/src/build/mod.rs index 0266edf..ac522b7 100644 --- a/src/build/mod.rs +++ b/src/build/mod.rs @@ -90,6 +90,7 @@ where { pub environment: Rc>>, working_dir: PathBuf, + strict: bool, // FIXME(jwall): These need to be compiled and added to the op cache. // specifically in the environment. std: Rc>, @@ -114,6 +115,7 @@ where let environment = Environment::new_with_vars(stdout, stderr, env::vars().collect()); FileBuilder { environment: Rc::new(RefCell::new(environment)), + strict: false, // Our import stack is initialized with ourself. working_dir: working_dir.into(), std: Rc::new(stdlib::get_libs()), @@ -127,6 +129,7 @@ where pub fn clone_builder(&self) -> Self { FileBuilder { environment: self.environment.clone(), + strict: self.strict, working_dir: self.working_dir.clone(), std: self.std.clone(), import_path: self.import_path, @@ -136,6 +139,10 @@ where } } + pub fn set_strict(&mut self, strict: bool) { + self.strict = strict; + } + /// Builds a ucg file at the named path. pub fn build>(&mut self, file: P) -> BuildResult { let file = file.into(); @@ -187,7 +194,12 @@ where pub fn eval_stmts(&mut self, ast: Vec, path: Option) -> BuildResult { // We should probably stash this in an op_cache somewhere? let ops = translate::AST::translate(ast, &self.working_dir); - let mut vm = VM::new(Rc::new(ops), self.environment.clone(), &self.working_dir); + let mut vm = VM::new( + self.strict, + Rc::new(ops), + self.environment.clone(), + &self.working_dir, + ); if path.is_some() { vm.set_path(path.unwrap()); } @@ -207,6 +219,7 @@ where println!(""); // Initialize VM with an empty OpPointer let mut vm = VM::new( + self.strict, Rc::new(PositionMap::new()), self.environment.clone(), &self.working_dir, @@ -307,6 +320,7 @@ where &self.working_dir, ); let mut vm = VM::new( + self.strict, Rc::new(ops_map), self.environment.clone(), &self.working_dir, diff --git a/src/build/opcode/cache.rs b/src/build/opcode/cache.rs index e7eb73d..99d44fd 100644 --- a/src/build/opcode/cache.rs +++ b/src/build/opcode/cache.rs @@ -48,7 +48,7 @@ impl<'a> Entry<'a> { let cached = match self.0 { btree_map::Entry::Occupied(e) => e.get().clone(), btree_map::Entry::Vacant(e) => { - // TODO(jwall) Check a file cache for the opcodes before + // TODO(jwall) Check a file cache for the opcodes before let v = Rc::new(f()?); e.insert(v.clone()); v diff --git a/src/build/opcode/runtime.rs b/src/build/opcode/runtime.rs index 1523bcb..6aa629f 100644 --- a/src/build/opcode/runtime.rs +++ b/src/build/opcode/runtime.rs @@ -30,14 +30,16 @@ use Composite::{List, Tuple}; use Primitive::{Bool, Empty, Int, Str}; pub struct Builtins { + pub strict: bool, import_path: Vec, validate_mode: bool, } impl Builtins { - pub fn new() -> Self { + pub fn new(strict: bool) -> Self { // FIXME(jwall): This should probably be injected in. Self { + strict: strict, import_path: Vec::new(), validate_mode: false, } @@ -45,6 +47,7 @@ impl Builtins { pub fn clone(&self) -> Self { Self { + strict: self.strict, import_path: self.import_path.clone(), validate_mode: self.validate_mode, } @@ -213,9 +216,13 @@ impl Builtins { None => { let op_pointer = decorate_error!(path_pos => env.borrow_mut().get_ops_for_path(&normalized))?; // TODO(jwall): What if we don't have a base path? - let mut vm = - VM::with_pointer(op_pointer, env.clone(), normalized.parent().unwrap()) - .with_import_stack(import_stack.clone()); + let mut vm = VM::with_pointer( + self.strict, + op_pointer, + env.clone(), + normalized.parent().unwrap(), + ) + .with_import_stack(import_stack.clone()); vm.run()?; let result = Rc::new(vm.symbols_to_tuple(true)); env.borrow_mut().update_path_val(&path, result.clone()); @@ -510,7 +517,7 @@ impl Builtins { stack.push((e.clone(), e_pos.clone())); // call function and push it's result on the stack. let (result, result_pos) = decorate_call!(pos => - VM::fcall_impl(f, stack, env.clone(), import_stack))?; + VM::fcall_impl(f, self.strict, stack, env.clone(), import_stack))?; pos_elems.push(result_pos); result_elems.push(result); counter += 1; @@ -527,7 +534,7 @@ impl Builtins { stack.push((Rc::new(P(Str(name.clone()))), name_pos)); stack.push((val.clone(), val_pos)); let (result, result_pos) = decorate_call!(pos => - VM::fcall_impl(f, stack, env.clone(), import_stack))?; + VM::fcall_impl(f, self.strict, stack, env.clone(), import_stack))?; if let &C(List(ref fval, _)) = result.as_ref() { // we expect them to be a list of exactly 2 items. if fval.len() != 2 { @@ -559,7 +566,7 @@ impl Builtins { stack.push((Rc::new(P(Str(c.to_string()))), list_pos.clone())); // call function and push it's result on the stack. let (result, result_pos) = decorate_call!(pos => - VM::fcall_impl(f, stack, env.clone(), import_stack))?; + VM::fcall_impl(f, self.strict, stack, env.clone(), import_stack))?; if let &P(Str(ref s)) = result.as_ref() { buf.push_str(s); } else { @@ -622,7 +629,7 @@ impl Builtins { stack.push((e.clone(), e_pos.clone())); // call function and push it's result on the stack. let (condition, _) = decorate_call!(pos => - VM::fcall_impl(f, stack, env.clone(), import_stack))?; + VM::fcall_impl(f, self.strict, stack, env.clone(), import_stack))?; // Check for empty or boolean results and only push e back in // if they are non empty and true counter += 1; @@ -648,7 +655,7 @@ impl Builtins { stack.push((Rc::new(P(Str(name.clone()))), name_pos.clone())); stack.push((val.clone(), val_pos.clone())); let (condition, _) = decorate_call!(pos => - VM::fcall_impl(f, stack, env.clone(), import_stack))?; + VM::fcall_impl(f, self.strict, stack, env.clone(), import_stack))?; // Check for empty or boolean results and only push e back in // if they are non empty and true counter += 1; @@ -670,7 +677,7 @@ impl Builtins { stack.push((Rc::new(P(Str(c.to_string()))), list_pos.clone())); // call function and push it's result on the stack. let (condition, _) = decorate_call!(pos => - VM::fcall_impl(f, stack, env.clone(), import_stack))?; + VM::fcall_impl(f, self.strict, stack, env.clone(), import_stack))?; // Check for empty or boolean results and only push c back in // if they are non empty and true match condition.as_ref() { @@ -773,7 +780,7 @@ impl Builtins { stack.push((e.clone(), e_pos.clone())); // call function and push it's result on the stack. let (new_acc, new_acc_pos) = decorate_call!(pos => - VM::fcall_impl(f, stack, env.clone(), import_stack))?; + VM::fcall_impl(f, self.strict, stack, env.clone(), import_stack))?; acc = new_acc; acc_pos = new_acc_pos; counter += 1; @@ -790,7 +797,7 @@ impl Builtins { stack.push((val.clone(), val_pos)); // call function and push it's result on the stack. let (new_acc, new_acc_pos) = decorate_call!(pos => - VM::fcall_impl(f, stack, env.clone(), import_stack))?; + VM::fcall_impl(f, self.strict, stack, env.clone(), import_stack))?; acc = new_acc; acc_pos = new_acc_pos; counter += 1; @@ -803,7 +810,7 @@ impl Builtins { stack.push((Rc::new(P(Str(c.to_string()))), list_pos.clone())); // call function and push it's result on the stack. let (new_acc, new_acc_pos) = decorate_call!(pos => - VM::fcall_impl(f, stack, env.clone(), import_stack))?; + VM::fcall_impl(f, self.strict, stack, env.clone(), import_stack))?; acc = new_acc; acc_pos = new_acc_pos; } diff --git a/src/build/opcode/vm.rs b/src/build/opcode/vm.rs index 4920cb0..a2ae45d 100644 --- a/src/build/opcode/vm.rs +++ b/src/build/opcode/vm.rs @@ -64,14 +64,16 @@ where E: std::io::Write + Clone, { pub fn new>( + strict: bool, ops: Rc, env: Rc>>, working_dir: P, ) -> Self { - Self::with_pointer(OpPointer::new(ops), env, working_dir) + Self::with_pointer(strict, OpPointer::new(ops), env, working_dir) } pub fn with_pointer>( + strict: bool, ops: OpPointer, env: Rc>>, working_dir: P, @@ -81,7 +83,7 @@ where stack: Vec::new(), symbols: Stack::new(), import_stack: Vec::new(), - runtime: runtime::Builtins::new(), + runtime: runtime::Builtins::new(strict), ops: ops, env: env, last: None, @@ -177,7 +179,7 @@ where Op::InitTuple => self.push(Rc::new(C(Tuple(Vec::new(), Vec::new()))), pos)?, Op::Field => self.op_field()?, Op::Element => self.op_element()?, - Op::Index => self.op_index(false, pos)?, + 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)?, @@ -446,6 +448,7 @@ where pub fn fcall_impl( f: &Func, + strict: bool, stack: &mut Vec<(Rc, Position)>, env: Rc>>, import_stack: &Vec, @@ -456,7 +459,7 @@ where ref snapshot, } = f; // use the captured scope snapshot for the function. - let mut vm = Self::with_pointer(ptr.clone(), env, std::env::current_dir()?) + let mut vm = Self::with_pointer(strict, ptr.clone(), env, std::env::current_dir()?) .to_scoped(snapshot.clone()) .with_import_stack(import_stack.clone()); for nm in bindings.iter() { @@ -511,7 +514,7 @@ where } } let (val, _) = decorate_call!(f_pos => - Self::fcall_impl(f, &mut self.stack, self.env.clone(), &self.import_stack))?; + Self::fcall_impl(f, self.runtime.strict, &mut self.stack, self.env.clone(), &self.import_stack))?; self.push(val, pos.clone())?; } Ok(()) diff --git a/src/main.rs b/src/main.rs index d15f43b..4fe38c0 100644 --- a/src/main.rs +++ b/src/main.rs @@ -132,7 +132,7 @@ fn build_file<'a>( let out = StdoutWrapper::new(); let err = StderrWrapper::new(); let mut builder = build::FileBuilder::new(std::env::current_dir()?, import_paths, out, err); - // FIXME(jwall): builder.set_strict(strict); + builder.set_strict(strict); if validate { builder.enable_validate_mode(); } @@ -394,7 +394,7 @@ fn env_help() { ); } -fn do_repl(import_paths: &Vec) -> std::result::Result<(), Box> { +fn do_repl(import_paths: &Vec, strict: bool) -> std::result::Result<(), Box> { let config = rustyline::Config::builder(); let mut editor = rustyline::Editor::<()>::with_config( config @@ -432,13 +432,14 @@ fn do_repl(import_paths: &Vec) -> std::result::Result<(), Box) { - if let Err(e) = do_repl(import_paths) { +fn repl(import_paths: &Vec, strict: bool) { + if let Err(e) = do_repl(import_paths, strict) { eprintln!("{}", e); process::exit(1); } @@ -480,7 +481,7 @@ fn main() { } else if let Some(_) = app_matches.subcommand_matches("env") { env_help() } else if let Some(_) = app_matches.subcommand_matches("repl") { - repl(&import_paths) + repl(&import_paths, strict) } else if let Some(matches) = app_matches.subcommand_matches("fmt") { if let Err(e) = fmt_command(matches) { eprintln!("{}", e);