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