mirror of
https://github.com/zaphar/ucg.git
synced 2025-07-22 18:19:54 -04:00
DEV: Integration tests all pass now.
This commit is contained in:
parent
2b64c2b4e0
commit
b3fd37a6b5
@ -69,4 +69,15 @@ let name = "foo";
|
|||||||
assert t.ok{
|
assert t.ok{
|
||||||
test = (name) in {foo="foo"},
|
test = (name) in {foo="foo"},
|
||||||
desc = "bareword collisions with field names still works for `in` operator",
|
desc = "bareword collisions with field names still works for `in` operator",
|
||||||
|
};
|
||||||
|
|
||||||
|
assert t.ok{
|
||||||
|
test = "foo" in ["foo"],
|
||||||
|
desc = "List presence checks work",
|
||||||
|
};
|
||||||
|
|
||||||
|
let foo_string = "foo";
|
||||||
|
assert t.ok{
|
||||||
|
test = foo_string in ["foo"],
|
||||||
|
desc = "List presence checks work",
|
||||||
};
|
};
|
@ -190,7 +190,7 @@ where
|
|||||||
pub fn eval_stmts(&mut self, ast: Vec<Statement>) -> BuildResult {
|
pub fn eval_stmts(&mut self, ast: Vec<Statement>) -> 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());
|
let mut vm = VM::new(Rc::new(ops), self.environment.clone(), &self.working_dir);
|
||||||
if self.validate_mode {
|
if self.validate_mode {
|
||||||
vm.enable_validate_mode();
|
vm.enable_validate_mode();
|
||||||
}
|
}
|
||||||
@ -227,7 +227,11 @@ where
|
|||||||
&mut ops_map,
|
&mut ops_map,
|
||||||
&self.working_dir,
|
&self.working_dir,
|
||||||
);
|
);
|
||||||
let mut vm = VM::new(Rc::new(ops_map), self.environment.clone());
|
let mut vm = VM::new(
|
||||||
|
Rc::new(ops_map),
|
||||||
|
self.environment.clone(),
|
||||||
|
&self.working_dir,
|
||||||
|
);
|
||||||
if self.validate_mode {
|
if self.validate_mode {
|
||||||
vm.enable_validate_mode();
|
vm.enable_validate_mode();
|
||||||
}
|
}
|
||||||
|
@ -22,7 +22,7 @@ use super::OpPointer;
|
|||||||
|
|
||||||
/// A Cache of Op codes.
|
/// A Cache of Op codes.
|
||||||
pub struct Ops {
|
pub struct Ops {
|
||||||
ops: BTreeMap<String, Rc<PositionMap>>,
|
ops: BTreeMap<PathBuf, Rc<PositionMap>>,
|
||||||
}
|
}
|
||||||
|
|
||||||
impl Ops {
|
impl Ops {
|
||||||
@ -32,12 +32,12 @@ impl Ops {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn entry<'a, S: Into<String>>(&'a mut self, path: S) -> Entry<'a> {
|
pub fn entry<'a, P: Into<PathBuf>>(&'a mut self, path: P) -> Entry<'a> {
|
||||||
Entry(self.ops.entry(path.into()))
|
Entry(self.ops.entry(path.into()))
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
pub struct Entry<'a>(btree_map::Entry<'a, String, Rc<PositionMap>>);
|
pub struct Entry<'a>(btree_map::Entry<'a, PathBuf, Rc<PositionMap>>);
|
||||||
|
|
||||||
impl<'a> Entry<'a> {
|
impl<'a> Entry<'a> {
|
||||||
pub fn get_pointer_or_else<F: FnOnce() -> Result<PositionMap, Error>, P: Into<PathBuf>>(
|
pub fn get_pointer_or_else<F: FnOnce() -> Result<PositionMap, Error>, P: Into<PathBuf>>(
|
||||||
|
@ -70,14 +70,18 @@ impl<Stdout: Write, Stderr: Write> Environment<Stdout, Stderr> {
|
|||||||
self.val_cache.insert(path.clone(), val);
|
self.val_cache.insert(path.clone(), val);
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn get_ops_for_path(&mut self, path: &String) -> Result<OpPointer, Error> {
|
pub fn get_ops_for_path<P>(&mut self, path: P) -> Result<OpPointer, Error>
|
||||||
self.op_cache.entry(path).get_pointer_or_else(
|
where
|
||||||
|
P: Into<PathBuf> + Clone,
|
||||||
|
{
|
||||||
|
let path_copy = path.clone();
|
||||||
|
self.op_cache.entry(path.clone()).get_pointer_or_else(
|
||||||
|| {
|
|| {
|
||||||
// FIXME(jwall): We need to do proper error handling here.
|
// FIXME(jwall): We need to do proper error handling here.
|
||||||
let p = PathBuf::from(&path);
|
let p = path.into();
|
||||||
let root = p.parent().unwrap();
|
let root = p.parent().unwrap();
|
||||||
// first we read in the file
|
// first we read in the file
|
||||||
let mut f = File::open(&path)?;
|
let mut f = File::open(&p)?;
|
||||||
// then we parse it
|
// then we parse it
|
||||||
let mut contents = String::new();
|
let mut contents = String::new();
|
||||||
f.read_to_string(&mut contents)?;
|
f.read_to_string(&mut contents)?;
|
||||||
@ -88,7 +92,7 @@ impl<Stdout: Write, Stderr: Write> Environment<Stdout, Stderr> {
|
|||||||
let ops = super::translate::AST::translate(stmts, &root);
|
let ops = super::translate::AST::translate(stmts, &root);
|
||||||
Ok(ops)
|
Ok(ops)
|
||||||
},
|
},
|
||||||
&path,
|
path_copy,
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -58,7 +58,6 @@ macro_rules! decorate_call {
|
|||||||
match $result {
|
match $result {
|
||||||
Ok(v) => Ok(v),
|
Ok(v) => Ok(v),
|
||||||
Err(mut e) => {
|
Err(mut e) => {
|
||||||
dbg!(&$pos);
|
|
||||||
e.push_call_stack($pos.clone());
|
e.push_call_stack($pos.clone());
|
||||||
Err(e)
|
Err(e)
|
||||||
}
|
}
|
||||||
|
@ -16,6 +16,7 @@ use std::fs::File;
|
|||||||
use std::io::Read;
|
use std::io::Read;
|
||||||
use std::path::{Path, PathBuf};
|
use std::path::{Path, PathBuf};
|
||||||
use std::rc::Rc;
|
use std::rc::Rc;
|
||||||
|
use std::fmt::Debug;
|
||||||
|
|
||||||
use regex::Regex;
|
use regex::Regex;
|
||||||
|
|
||||||
@ -29,7 +30,6 @@ use Composite::{List, Tuple};
|
|||||||
use Primitive::{Bool, Empty, Int, Str};
|
use Primitive::{Bool, Empty, Int, Str};
|
||||||
|
|
||||||
pub struct Builtins {
|
pub struct Builtins {
|
||||||
working_dir: PathBuf,
|
|
||||||
import_path: Vec<PathBuf>,
|
import_path: Vec<PathBuf>,
|
||||||
validate_mode: bool,
|
validate_mode: bool,
|
||||||
}
|
}
|
||||||
@ -37,12 +37,7 @@ pub struct Builtins {
|
|||||||
impl Builtins {
|
impl Builtins {
|
||||||
pub fn new() -> Self {
|
pub fn new() -> Self {
|
||||||
// FIXME(jwall): This should probably be injected in.
|
// FIXME(jwall): This should probably be injected in.
|
||||||
Self::with_working_dir(std::env::current_dir().unwrap())
|
|
||||||
}
|
|
||||||
|
|
||||||
pub fn with_working_dir<P: Into<PathBuf>>(path: P) -> Self {
|
|
||||||
Self {
|
Self {
|
||||||
working_dir: path.into(),
|
|
||||||
import_path: Vec::new(),
|
import_path: Vec::new(),
|
||||||
validate_mode: false,
|
validate_mode: false,
|
||||||
}
|
}
|
||||||
@ -50,7 +45,6 @@ impl Builtins {
|
|||||||
|
|
||||||
pub fn clone(&self) -> Self {
|
pub fn clone(&self) -> Self {
|
||||||
Self {
|
Self {
|
||||||
working_dir: self.working_dir.clone(),
|
|
||||||
import_path: self.import_path.clone(),
|
import_path: self.import_path.clone(),
|
||||||
validate_mode: self.validate_mode,
|
validate_mode: self.validate_mode,
|
||||||
}
|
}
|
||||||
@ -60,22 +54,25 @@ impl Builtins {
|
|||||||
self.validate_mode = true;
|
self.validate_mode = true;
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn handle<P: AsRef<Path>, O, E>(
|
pub fn handle<P, WP, O, E>(
|
||||||
&mut self,
|
&mut self,
|
||||||
path: Option<P>,
|
path: Option<P>,
|
||||||
h: Hook,
|
h: Hook,
|
||||||
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: &mut Vec<String>,
|
import_stack: &mut Vec<String>,
|
||||||
|
working_dir: WP,
|
||||||
pos: Position,
|
pos: Position,
|
||||||
) -> Result<(), Error>
|
) -> Result<(), Error>
|
||||||
where
|
where
|
||||||
|
P: AsRef<Path>,
|
||||||
|
WP: Into<PathBuf> + Clone + Debug,
|
||||||
O: std::io::Write,
|
O: std::io::Write,
|
||||||
E: std::io::Write,
|
E: std::io::Write,
|
||||||
{
|
{
|
||||||
match h {
|
match h {
|
||||||
Hook::Import => self.import(stack, env, import_stack, pos),
|
Hook::Import => self.import(working_dir, stack, env, import_stack, pos),
|
||||||
Hook::Include => self.include(stack, env, pos),
|
Hook::Include => self.include(working_dir, stack, env, pos),
|
||||||
Hook::Assert => self.assert(stack, env),
|
Hook::Assert => self.assert(stack, env),
|
||||||
Hook::Convert => self.convert(stack, env, pos),
|
Hook::Convert => self.convert(stack, env, pos),
|
||||||
Hook::Out => self.out(path, stack, env, pos),
|
Hook::Out => self.out(path, stack, env, pos),
|
||||||
@ -88,15 +85,23 @@ impl Builtins {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
fn find_file<P: Into<PathBuf>>(
|
fn normalize_path<P, BP>(
|
||||||
&self,
|
&self,
|
||||||
path: P,
|
base_path: BP,
|
||||||
use_import_path: bool,
|
use_import_path: bool,
|
||||||
pos: Position,
|
path: P,
|
||||||
) -> Result<PathBuf, Error> {
|
) -> Result<PathBuf, Error>
|
||||||
|
where
|
||||||
|
BP: Into<PathBuf>,
|
||||||
|
P: Into<PathBuf>,
|
||||||
|
{
|
||||||
// Try a relative path first.
|
// Try a relative path first.
|
||||||
let path = path.into();
|
let path = path.into();
|
||||||
let mut normalized = self.working_dir.clone();
|
// stdlib paths are special
|
||||||
|
if path.starts_with("std/") {
|
||||||
|
return Ok(path);
|
||||||
|
}
|
||||||
|
let mut normalized = base_path.into();
|
||||||
if path.is_relative() {
|
if path.is_relative() {
|
||||||
normalized.push(&path);
|
normalized.push(&path);
|
||||||
// First see if the normalized file exists or not.
|
// First see if the normalized file exists or not.
|
||||||
@ -115,6 +120,23 @@ impl Builtins {
|
|||||||
} else {
|
} else {
|
||||||
normalized = path;
|
normalized = path;
|
||||||
}
|
}
|
||||||
|
Ok(normalized.canonicalize()?)
|
||||||
|
}
|
||||||
|
|
||||||
|
fn find_file<P, BP>(
|
||||||
|
&self,
|
||||||
|
base_path: BP,
|
||||||
|
path: P,
|
||||||
|
use_import_path: bool,
|
||||||
|
pos: Position,
|
||||||
|
) -> Result<PathBuf, Error>
|
||||||
|
where
|
||||||
|
P: Into<PathBuf>,
|
||||||
|
BP: Into<PathBuf>,
|
||||||
|
{
|
||||||
|
// Try a relative path first.
|
||||||
|
// FIXME(jwall): Use import paths if desired.
|
||||||
|
let normalized = self.normalize_path(base_path, use_import_path, path)?;
|
||||||
match normalized.canonicalize() {
|
match normalized.canonicalize() {
|
||||||
Ok(p) => Ok(p),
|
Ok(p) => Ok(p),
|
||||||
Err(_e) => Err(Error::new(
|
Err(_e) => Err(Error::new(
|
||||||
@ -124,10 +146,11 @@ impl Builtins {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
fn get_file_as_string(&self, path: &str, pos: Position) -> Result<String, Error> {
|
fn get_file_as_string<P: Into<PathBuf>>(&self, base_path: P, path: &str, pos: Position) -> Result<String, Error> {
|
||||||
let sep = format!("{}", std::path::MAIN_SEPARATOR);
|
let sep = format!("{}", std::path::MAIN_SEPARATOR);
|
||||||
let raw_path = path.replace("/", &sep);
|
let raw_path = path.replace("/", &sep);
|
||||||
let normalized = self.find_file(raw_path, false, pos)?;
|
// FIXME(jwall): import paths?
|
||||||
|
let normalized = self.find_file(base_path, raw_path, false, pos)?;
|
||||||
// TODO(jwall): Proper error here
|
// TODO(jwall): Proper error here
|
||||||
let mut f = File::open(normalized)?;
|
let mut f = File::open(normalized)?;
|
||||||
let mut contents = String::new();
|
let mut contents = String::new();
|
||||||
@ -136,8 +159,9 @@ impl Builtins {
|
|||||||
Ok(contents)
|
Ok(contents)
|
||||||
}
|
}
|
||||||
|
|
||||||
fn import<O, E>(
|
fn import<P, O, E>(
|
||||||
&mut self,
|
&mut self,
|
||||||
|
base_path: P,
|
||||||
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: &mut Vec<String>,
|
import_stack: &mut Vec<String>,
|
||||||
@ -146,31 +170,37 @@ impl Builtins {
|
|||||||
where
|
where
|
||||||
O: std::io::Write,
|
O: std::io::Write,
|
||||||
E: std::io::Write,
|
E: std::io::Write,
|
||||||
|
P: Into<PathBuf> + Clone + Debug,
|
||||||
{
|
{
|
||||||
let path = stack.pop();
|
let path = stack.pop();
|
||||||
if let Some((val, path_pos)) = path {
|
if let Some((val, path_pos)) = path {
|
||||||
if let &Value::P(Str(ref path)) = val.as_ref() {
|
if let &Value::P(Str(ref path)) = val.as_ref() {
|
||||||
|
// TODO(jwall): A bit hacky we should probably change import stacks to be pathbufs.
|
||||||
|
let normalized = decorate_error!(path_pos => self.normalize_path(base_path, false, path))?;
|
||||||
|
let path = normalized.to_string_lossy().to_string();
|
||||||
if import_stack
|
if import_stack
|
||||||
.iter()
|
.iter()
|
||||||
.find(|p| *p == path)
|
.find(|p| *p == &path)
|
||||||
.is_some() {
|
.is_some() {
|
||||||
return Err(Error::new(
|
return Err(Error::new(
|
||||||
format!("You can only have one output per file"),
|
format!("Import cycle detected: {} in {:?}", path, import_stack),
|
||||||
pos));
|
pos));
|
||||||
}
|
}
|
||||||
import_stack.push(path.clone());
|
let val = {
|
||||||
let mut borrowed_env = env.borrow_mut();
|
env.borrow_mut().get_cached_path_val(&path)
|
||||||
match borrowed_env.get_cached_path_val(path) {
|
};
|
||||||
|
match val {
|
||||||
Some(v) => {
|
Some(v) => {
|
||||||
stack.push((v, path_pos));
|
stack.push((v, path_pos));
|
||||||
}
|
}
|
||||||
None => {
|
None => {
|
||||||
let op_pointer =
|
let op_pointer =
|
||||||
decorate_error!(path_pos => borrowed_env.get_ops_for_path(path))?;
|
decorate_error!(path_pos => env.borrow_mut().get_ops_for_path(&normalized))?;
|
||||||
let mut vm = VM::with_pointer(op_pointer, env.clone());
|
// TODO(jwall): What if we don't have a base path?
|
||||||
|
let mut vm = VM::with_pointer(op_pointer, env.clone(), normalized.parent().unwrap());
|
||||||
vm.run()?;
|
vm.run()?;
|
||||||
let result = Rc::new(vm.symbols_to_tuple(true));
|
let result = Rc::new(vm.symbols_to_tuple(true));
|
||||||
borrowed_env.update_path_val(&path, result.clone());
|
env.borrow_mut().update_path_val(&path, result.clone());
|
||||||
stack.push((result, pos));
|
stack.push((result, pos));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -181,8 +211,9 @@ impl Builtins {
|
|||||||
unreachable!();
|
unreachable!();
|
||||||
}
|
}
|
||||||
|
|
||||||
fn include<O, E>(
|
fn include<P, O, E>(
|
||||||
&self,
|
&self,
|
||||||
|
base_path: P,
|
||||||
stack: &mut Vec<(Rc<Value>, Position)>,
|
stack: &mut Vec<(Rc<Value>, Position)>,
|
||||||
env: Rc<RefCell<Environment<O, E>>>,
|
env: Rc<RefCell<Environment<O, E>>>,
|
||||||
pos: Position,
|
pos: Position,
|
||||||
@ -190,6 +221,7 @@ impl Builtins {
|
|||||||
where
|
where
|
||||||
O: std::io::Write,
|
O: std::io::Write,
|
||||||
E: std::io::Write,
|
E: std::io::Write,
|
||||||
|
P: Into<PathBuf> + Clone + Debug,
|
||||||
{
|
{
|
||||||
let path = stack.pop();
|
let path = stack.pop();
|
||||||
let typ = stack.pop();
|
let typ = stack.pop();
|
||||||
@ -216,14 +248,14 @@ impl Builtins {
|
|||||||
};
|
};
|
||||||
if typ == "str" {
|
if typ == "str" {
|
||||||
stack.push((
|
stack.push((
|
||||||
Rc::new(P(Str(self.get_file_as_string(&path, pos.clone())?))),
|
Rc::new(P(Str(self.get_file_as_string(base_path, &path, pos.clone())?))),
|
||||||
pos.clone(),
|
pos.clone(),
|
||||||
));
|
));
|
||||||
} else {
|
} else {
|
||||||
stack.push((
|
stack.push((
|
||||||
Rc::new(match env.borrow().importer_registry.get_importer(&typ) {
|
Rc::new(match env.borrow().importer_registry.get_importer(&typ) {
|
||||||
Some(importer) => {
|
Some(importer) => {
|
||||||
let contents = self.get_file_as_string(&path, pos.clone())?;
|
let contents = self.get_file_as_string(base_path, &path, pos.clone())?;
|
||||||
if contents.len() == 0 {
|
if contents.len() == 0 {
|
||||||
eprintln!("including an empty file. Use NULL as the result");
|
eprintln!("including an empty file. Use NULL as the result");
|
||||||
P(Empty)
|
P(Empty)
|
||||||
|
@ -13,7 +13,10 @@
|
|||||||
// limitations under the License.
|
// limitations under the License.
|
||||||
use std::path::Path;
|
use std::path::Path;
|
||||||
|
|
||||||
use crate::ast::{BinaryExprType, Expression, FormatArgs, Position, Statement, Token, Value};
|
use crate::ast::{
|
||||||
|
BinaryExprType, BinaryOpDef, Expression, FormatArgs, Position, PositionedItem, SelectDef,
|
||||||
|
Statement, Token, TokenType, Value,
|
||||||
|
};
|
||||||
use crate::ast::{FuncOpDef, TemplatePart};
|
use crate::ast::{FuncOpDef, TemplatePart};
|
||||||
use crate::build::format::{ExpressionTemplate, SimpleTemplate, TemplateParser};
|
use crate::build::format::{ExpressionTemplate, SimpleTemplate, TemplateParser};
|
||||||
use crate::build::opcode::Primitive;
|
use crate::build::opcode::Primitive;
|
||||||
@ -186,18 +189,38 @@ impl AST {
|
|||||||
ops.push(Op::Mod, def.pos);
|
ops.push(Op::Mod, def.pos);
|
||||||
}
|
}
|
||||||
BinaryExprType::IN => {
|
BinaryExprType::IN => {
|
||||||
// Dot expressions expect the left side to be pushed first
|
// Dot expressions expect the right side to be pushed first
|
||||||
Self::translate_expr(*def.right, &mut ops, root);
|
Self::translate_expr(*def.right.clone(), &mut ops, root);
|
||||||
// Symbols on the left side should be converted to strings to satisfy
|
// Symbols on the left side should be converted to strings to satisfy
|
||||||
// the Index operation contract.
|
// the Index operation contract.
|
||||||
// FIXME(jwall): List checks.
|
// FIXME(jwall): List checks should not use symbol translation.
|
||||||
match *def.left {
|
match *def.left.clone() {
|
||||||
Expression::Simple(Value::Symbol(name)) => {
|
Expression::Simple(Value::Symbol(name)) => {
|
||||||
Self::translate_expr(
|
// We really just want an expression that turns a symbol
|
||||||
Expression::Simple(Value::Str(name)),
|
// into a name if the subject is a tuple and doesn't
|
||||||
&mut ops,
|
// otherwise
|
||||||
root,
|
let new_expr = Expression::Select(SelectDef {
|
||||||
);
|
val: Box::new(Expression::Binary(BinaryOpDef {
|
||||||
|
kind: BinaryExprType::IS,
|
||||||
|
right: Box::new(Expression::Simple(Value::Str(
|
||||||
|
PositionedItem::new(
|
||||||
|
"tuple".to_owned(),
|
||||||
|
def.left.pos().clone(),
|
||||||
|
),
|
||||||
|
))),
|
||||||
|
left: def.right.clone(),
|
||||||
|
pos: def.left.pos().clone(),
|
||||||
|
})),
|
||||||
|
default: Some(Box::new(Expression::Simple(Value::Symbol(
|
||||||
|
name.clone(),
|
||||||
|
)))),
|
||||||
|
tuple: vec![(
|
||||||
|
Token::new("true", TokenType::BAREWORD, def.right.pos()),
|
||||||
|
Expression::Simple(Value::Str(name)),
|
||||||
|
)],
|
||||||
|
pos: def.left.pos().clone(),
|
||||||
|
});
|
||||||
|
Self::translate_expr(new_expr, &mut ops, root);
|
||||||
}
|
}
|
||||||
expr => {
|
expr => {
|
||||||
Self::translate_expr(expr, &mut ops, root);
|
Self::translate_expr(expr, &mut ops, root);
|
||||||
|
@ -13,6 +13,7 @@
|
|||||||
// limitations under the License.
|
// limitations under the License.
|
||||||
use std::cell::RefCell;
|
use std::cell::RefCell;
|
||||||
use std::collections::BTreeSet;
|
use std::collections::BTreeSet;
|
||||||
|
use std::path::PathBuf;
|
||||||
use std::rc::Rc;
|
use std::rc::Rc;
|
||||||
|
|
||||||
use crate::ast::Position;
|
use crate::ast::Position;
|
||||||
@ -45,6 +46,7 @@ where
|
|||||||
O: std::io::Write,
|
O: std::io::Write,
|
||||||
E: std::io::Write,
|
E: std::io::Write,
|
||||||
{
|
{
|
||||||
|
working_dir: PathBuf,
|
||||||
stack: Vec<(Rc<Value>, Position)>,
|
stack: Vec<(Rc<Value>, Position)>,
|
||||||
symbols: Stack,
|
symbols: Stack,
|
||||||
import_stack: Vec<String>,
|
import_stack: Vec<String>,
|
||||||
@ -54,7 +56,6 @@ where
|
|||||||
pub last: Option<(Rc<Value>, Position)>,
|
pub last: Option<(Rc<Value>, Position)>,
|
||||||
self_stack: Vec<(Rc<Value>, Position)>,
|
self_stack: Vec<(Rc<Value>, Position)>,
|
||||||
reserved_words: BTreeSet<&'static str>,
|
reserved_words: BTreeSet<&'static str>,
|
||||||
out_lock: bool,
|
|
||||||
}
|
}
|
||||||
|
|
||||||
impl<'a, O, E> VM<O, E>
|
impl<'a, O, E> VM<O, E>
|
||||||
@ -62,12 +63,21 @@ where
|
|||||||
O: std::io::Write,
|
O: std::io::Write,
|
||||||
E: std::io::Write,
|
E: std::io::Write,
|
||||||
{
|
{
|
||||||
pub fn new(ops: Rc<PositionMap>, env: Rc<RefCell<Environment<O, E>>>) -> Self {
|
pub fn new<P: Into<PathBuf>>(
|
||||||
Self::with_pointer(OpPointer::new(ops), env)
|
ops: Rc<PositionMap>,
|
||||||
|
env: Rc<RefCell<Environment<O, E>>>,
|
||||||
|
working_dir: P,
|
||||||
|
) -> Self {
|
||||||
|
Self::with_pointer(OpPointer::new(ops), env, working_dir)
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn with_pointer(ops: OpPointer, env: Rc<RefCell<Environment<O, E>>>) -> Self {
|
pub fn with_pointer<P: Into<PathBuf>>(
|
||||||
|
ops: OpPointer,
|
||||||
|
env: Rc<RefCell<Environment<O, E>>>,
|
||||||
|
working_dir: P,
|
||||||
|
) -> Self {
|
||||||
Self {
|
Self {
|
||||||
|
working_dir: working_dir.into(),
|
||||||
stack: Vec::new(),
|
stack: Vec::new(),
|
||||||
symbols: Stack::new(),
|
symbols: Stack::new(),
|
||||||
import_stack: Vec::new(),
|
import_stack: Vec::new(),
|
||||||
@ -77,9 +87,14 @@ where
|
|||||||
last: None,
|
last: None,
|
||||||
self_stack: Vec::new(),
|
self_stack: Vec::new(),
|
||||||
reserved_words: construct_reserved_word_set(),
|
reserved_words: construct_reserved_word_set(),
|
||||||
out_lock: false,
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
pub fn to_new_pointer(mut self, ops: OpPointer) -> Self {
|
||||||
|
self.ops = ops;
|
||||||
|
self
|
||||||
|
}
|
||||||
|
|
||||||
pub fn with_import_stack(mut self, imports: Vec<String>) -> Self {
|
pub fn with_import_stack(mut self, imports: Vec<String>) -> Self {
|
||||||
self.import_stack = imports;
|
self.import_stack = imports;
|
||||||
self
|
self
|
||||||
@ -89,21 +104,26 @@ where
|
|||||||
self.runtime.enable_validate_mode();
|
self.runtime.enable_validate_mode();
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn to_scoped(self, symbols: Stack) -> Self {
|
pub fn clean_copy(&self) -> Self {
|
||||||
Self {
|
Self {
|
||||||
|
working_dir: self.working_dir.clone(),
|
||||||
stack: Vec::new(),
|
stack: Vec::new(),
|
||||||
symbols: symbols,
|
symbols: Stack::new(),
|
||||||
import_stack: self.import_stack.clone(),
|
import_stack: Vec::new(),
|
||||||
runtime: self.runtime.clone(),
|
runtime: self.runtime.clone(),
|
||||||
ops: self.ops.clone(),
|
ops: self.ops.clone(),
|
||||||
env: self.env.clone(),
|
env: self.env.clone(),
|
||||||
last: self.last,
|
last: None,
|
||||||
self_stack: self.self_stack,
|
self_stack: self.self_stack.clone(),
|
||||||
reserved_words: self.reserved_words,
|
reserved_words: self.reserved_words.clone(),
|
||||||
out_lock: self.out_lock,
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
pub fn to_scoped(mut self, symbols: Stack) -> Self {
|
||||||
|
self.symbols = symbols;
|
||||||
|
self
|
||||||
|
}
|
||||||
|
|
||||||
pub fn symbols_to_tuple(&self, include_mod: bool) -> Value {
|
pub fn symbols_to_tuple(&self, include_mod: bool) -> Value {
|
||||||
let mut flds = Vec::new();
|
let mut flds = Vec::new();
|
||||||
let mut pos_list = Vec::new();
|
let mut pos_list = Vec::new();
|
||||||
@ -183,6 +203,9 @@ where
|
|||||||
Op::PopSelf => self.op_pop_self()?,
|
Op::PopSelf => self.op_pop_self()?,
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
if let Some(p) = self.ops.path.as_ref() {
|
||||||
|
self.import_stack.push(p.to_string_lossy().to_string());
|
||||||
|
}
|
||||||
Ok(())
|
Ok(())
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -425,7 +448,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)
|
let mut vm = Self::with_pointer(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() {
|
||||||
@ -442,7 +465,9 @@ where
|
|||||||
|
|
||||||
fn op_new_scope(&mut self, jp: i32, ptr: OpPointer) -> Result<(), Error> {
|
fn op_new_scope(&mut self, jp: i32, ptr: OpPointer) -> Result<(), Error> {
|
||||||
let scope_snapshot = self.symbols.snapshot();
|
let scope_snapshot = self.symbols.snapshot();
|
||||||
let mut vm = Self::with_pointer(ptr, self.env.clone())
|
let mut vm = self
|
||||||
|
.clean_copy()
|
||||||
|
.to_new_pointer(ptr)
|
||||||
.to_scoped(scope_snapshot)
|
.to_scoped(scope_snapshot)
|
||||||
.with_import_stack(self.import_stack.clone());
|
.with_import_stack(self.import_stack.clone());
|
||||||
vm.run()?;
|
vm.run()?;
|
||||||
@ -809,7 +834,7 @@ where
|
|||||||
}
|
}
|
||||||
&C(List(ref elems, _)) => {
|
&C(List(ref elems, _)) => {
|
||||||
for e in elems {
|
for e in elems {
|
||||||
if e == &right {
|
if dbg!(e) == dbg!(&right) {
|
||||||
self.push(Rc::new(P(Bool(true))), pos)?;
|
self.push(Rc::new(P(Bool(true))), pos)?;
|
||||||
return Ok(());
|
return Ok(());
|
||||||
}
|
}
|
||||||
@ -905,7 +930,9 @@ where
|
|||||||
&val_pos,
|
&val_pos,
|
||||||
)?;
|
)?;
|
||||||
if let Some(ptr) = pkg_ptr {
|
if let Some(ptr) = pkg_ptr {
|
||||||
let mut pkg_vm = Self::with_pointer(ptr.clone(), self.env.clone())
|
let mut pkg_vm = self
|
||||||
|
.clean_copy()
|
||||||
|
.to_new_pointer(ptr.clone())
|
||||||
.with_import_stack(self.import_stack.clone());
|
.with_import_stack(self.import_stack.clone());
|
||||||
pkg_vm.run()?;
|
pkg_vm.run()?;
|
||||||
let (pkg_func, val_pos) = pkg_vm.pop()?;
|
let (pkg_func, val_pos) = pkg_vm.pop()?;
|
||||||
@ -919,8 +946,9 @@ where
|
|||||||
)?;
|
)?;
|
||||||
}
|
}
|
||||||
|
|
||||||
// TODO(jwall): We should have a notion of a call stack here.
|
let mut vm = self
|
||||||
let mut vm = Self::with_pointer(ptr.clone(), self.env.clone())
|
.clean_copy()
|
||||||
|
.to_new_pointer(ptr.clone())
|
||||||
.with_import_stack(self.import_stack.clone());
|
.with_import_stack(self.import_stack.clone());
|
||||||
vm.push(Rc::new(S("mod".to_owned())), pos.clone())?;
|
vm.push(Rc::new(S("mod".to_owned())), pos.clone())?;
|
||||||
vm.push(Rc::new(C(Tuple(flds, flds_pos_list))), pos.clone())?;
|
vm.push(Rc::new(C(Tuple(flds, flds_pos_list))), pos.clone())?;
|
||||||
@ -1137,6 +1165,7 @@ where
|
|||||||
&mut self.stack,
|
&mut self.stack,
|
||||||
self.env.clone(),
|
self.env.clone(),
|
||||||
&mut self.import_stack,
|
&mut self.import_stack,
|
||||||
|
&self.working_dir,
|
||||||
pos,
|
pos,
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
@ -38,7 +38,7 @@ assert t.equal{
|
|||||||
|
|
||||||
assert t.ok{
|
assert t.ok{
|
||||||
test = tpl.has_fields{tpl={foo=1, bar=2}, fields=["foo", "bar"]},
|
test = tpl.has_fields{tpl={foo=1, bar=2}, fields=["foo", "bar"]},
|
||||||
desc = "tuple has fields has foo and bar fields",
|
desc = "tuple has foo and bar fields",
|
||||||
};
|
};
|
||||||
|
|
||||||
assert t.not_ok{
|
assert t.not_ok{
|
||||||
|
Loading…
x
Reference in New Issue
Block a user