mirror of
https://github.com/zaphar/ucg.git
synced 2025-07-22 18:19:54 -04:00
DEV: respect strict in our bytecode interpreter
This commit is contained in:
parent
aecb1d571e
commit
27011769dd
@ -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,
|
||||
|
@ -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
|
||||
|
@ -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;
|
||||
}
|
||||
|
@ -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(())
|
||||
|
11
src/main.rs
11
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<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);
|
||||
|
Loading…
x
Reference in New Issue
Block a user