DEV: respect strict in our bytecode interpreter

This commit is contained in:
Jeremy Wall 2019-11-09 15:07:46 -06:00
parent aecb1d571e
commit 27011769dd
5 changed files with 50 additions and 25 deletions

View File

@ -90,6 +90,7 @@ where
{
pub environment: Rc<RefCell<Environment<Stdout, Stderr>>>,
working_dir: PathBuf,
strict: bool,
// FIXME(jwall): These need to be compiled and added to the op cache.
// specifically in the environment.
std: Rc<HashMap<String, &'static str>>,
@ -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<P: Into<PathBuf>>(&mut self, file: P) -> BuildResult {
let file = file.into();
@ -187,7 +194,12 @@ where
pub fn eval_stmts(&mut self, ast: Vec<Statement>, path: Option<PathBuf>) -> 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,

View File

@ -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

View File

@ -30,14 +30,16 @@ use Composite::{List, Tuple};
use Primitive::{Bool, Empty, Int, Str};
pub struct Builtins {
pub strict: bool,
import_path: Vec<PathBuf>,
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;
}

View File

@ -64,14 +64,16 @@ where
E: std::io::Write + Clone,
{
pub fn new<P: Into<PathBuf>>(
strict: bool,
ops: Rc<PositionMap>,
env: Rc<RefCell<Environment<O, E>>>,
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<P: Into<PathBuf>>(
strict: bool,
ops: OpPointer,
env: Rc<RefCell<Environment<O, E>>>,
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<Value>, Position)>,
env: Rc<RefCell<Environment<O, E>>>,
import_stack: &Vec<String>,
@ -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(())

View File

@ -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<PathBuf>) -> std::result::Result<(), Box<dyn Error>> {
fn do_repl(import_paths: &Vec<PathBuf>, strict: bool) -> std::result::Result<(), Box<dyn Error>> {
let config = rustyline::Config::builder();
let mut editor = rustyline::Editor::<()>::with_config(
config
@ -432,13 +432,14 @@ fn do_repl(import_paths: &Vec<PathBuf>) -> std::result::Result<(), Box<dyn Error
StdoutWrapper::new(),
StderrWrapper::new(),
);
builder.set_strict(strict);
builder.repl(editor, config_home)?;
Ok(())
}
fn repl(import_paths: &Vec<PathBuf>) {
if let Err(e) = do_repl(import_paths) {
fn repl(import_paths: &Vec<PathBuf>, 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);