FEATURE: Use UCG_IMPORT_PATH to identify the import paths.

fixes #9
This commit is contained in:
Jeremy Wall 2018-12-13 19:03:22 -06:00
parent f26e26d2ad
commit 2b47ca8617
5 changed files with 99 additions and 42 deletions

View File

@ -19,8 +19,9 @@ use super::assets::MemoryCache;
use super::Builder;
fn assert_build(input: &str) {
let i_paths = Vec::new();
let cache = MemoryCache::new();
let mut b = Builder::new("<Eval>", Rc::new(RefCell::new(cache)));
let mut b = Builder::new("<Eval>", &i_paths, Rc::new(RefCell::new(cache)));
b.enable_validate_mode();
b.eval_string(input).unwrap();
if !b.assert_collector.success {

View File

@ -93,9 +93,9 @@ pub struct AssertCollector {
}
/// Builder handles building ucg code for a single file.
pub struct Builder {
pub struct Builder<'a> {
file: PathBuf,
import_path: Vec<PathBuf>,
import_path: &'a Vec<PathBuf>,
validate_mode: bool,
pub assert_collector: AssertCollector,
strict: bool,
@ -139,24 +139,36 @@ macro_rules! eval_binary_expr {
};
}
impl Builder {
impl<'a> Builder<'a> {
/// Constructs a new Builder.
pub fn new<P: Into<PathBuf>>(file: P, cache: Rc<RefCell<assets::Cache>>) -> Self {
Self::new_with_scope(file, cache, HashMap::new())
pub fn new<P: Into<PathBuf>>(
file: P,
import_paths: &'a Vec<PathBuf>,
cache: Rc<RefCell<assets::Cache>>,
) -> Self {
Self::new_with_scope(file, import_paths, cache, HashMap::new())
}
/// Constructs a new Builder with a provided scope.
pub fn new_with_scope<P: Into<PathBuf>>(
root: P,
import_paths: &'a Vec<PathBuf>,
cache: Rc<RefCell<assets::Cache>>,
scope: ValueMap,
) -> Self {
let env_vars: Vec<(String, String)> = env::vars().collect();
Self::new_with_env_and_scope(root, cache, scope, Rc::new(Val::Env(env_vars)))
Self::new_with_env_and_scope(
root,
import_paths,
cache,
scope,
Rc::new(Val::Env(env_vars)),
)
}
pub fn new_with_env_and_scope<P: Into<PathBuf>>(
file: P,
import_paths: &'a Vec<PathBuf>,
cache: Rc<RefCell<assets::Cache>>,
scope: ValueMap,
env: Rc<Val>,
@ -166,7 +178,7 @@ impl Builder {
// Our import stack is initialized with ourself.
import_stack: vec![file.to_string_lossy().to_string()],
file: file,
import_path: Vec::new(),
import_path: import_paths,
validate_mode: false,
assert_collector: AssertCollector {
success: true,
@ -189,7 +201,7 @@ impl Builder {
// Our import stack is initialized with ourself.
import_stack: self.import_stack.clone(),
file: file.into(),
import_path: self.import_path.clone(),
import_path: self.import_path,
validate_mode: false,
assert_collector: AssertCollector {
success: true,
@ -215,10 +227,6 @@ impl Builder {
self.strict = to;
}
pub fn set_import_paths(&mut self, paths: Vec<PathBuf>) {
self.import_path = paths;
}
pub fn prepend_import_stack(&mut self, imports: &Vec<String>) {
let mut new_stack = self.import_stack.clone();
new_stack.append(imports.clone().as_mut());

View File

@ -28,8 +28,9 @@ fn test_expr_to_val(mut cases: Vec<(Expression, Val)>, mut b: Builder) {
#[test]
#[should_panic(expected = "Expected Float")]
fn test_eval_div_expr_fail() {
let i_paths = Vec::new();
let cache = Rc::new(RefCell::new(MemoryCache::new()));
let b = Builder::new(std::env::current_dir().unwrap(), cache);
let b = Builder::new(std::env::current_dir().unwrap(), &i_paths, cache);
test_expr_to_val(
vec![(
Expression::Binary(BinaryOpDef {
@ -53,8 +54,9 @@ fn test_eval_div_expr_fail() {
#[test]
#[should_panic(expected = "Expected Float")]
fn test_eval_mul_expr_fail() {
let i_paths = Vec::new();
let cache = Rc::new(RefCell::new(MemoryCache::new()));
let b = Builder::new(std::env::current_dir().unwrap(), cache);
let b = Builder::new(std::env::current_dir().unwrap(), &i_paths, cache);
test_expr_to_val(
vec![(
Expression::Binary(BinaryOpDef {
@ -78,8 +80,9 @@ fn test_eval_mul_expr_fail() {
#[test]
#[should_panic(expected = "Expected Float")]
fn test_eval_subtract_expr_fail() {
let i_paths = Vec::new();
let cache = Rc::new(RefCell::new(MemoryCache::new()));
let b = Builder::new(std::env::current_dir().unwrap(), cache);
let b = Builder::new(std::env::current_dir().unwrap(), &i_paths, cache);
test_expr_to_val(
vec![(
Expression::Binary(BinaryOpDef {
@ -102,8 +105,9 @@ fn test_eval_subtract_expr_fail() {
#[test]
#[should_panic(expected = "Expected Float")]
fn test_eval_add_expr_fail() {
let i_paths = Vec::new();
let cache = Rc::new(RefCell::new(MemoryCache::new()));
let b = Builder::new(std::env::current_dir().unwrap(), cache);
let b = Builder::new(std::env::current_dir().unwrap(), &i_paths, cache);
test_expr_to_val(
vec![(
Expression::Binary(BinaryOpDef {
@ -126,8 +130,9 @@ fn test_eval_add_expr_fail() {
#[test]
fn test_eval_simple_lookup_error() {
let i_paths = Vec::new();
let cache = Rc::new(RefCell::new(MemoryCache::new()));
let mut b = Builder::new(std::env::current_dir().unwrap(), cache);
let mut b = Builder::new(std::env::current_dir().unwrap(), &i_paths, cache);
b.build_output
.entry(value_node!("var1".to_string(), Position::new(1, 0, 0)))
.or_insert(Rc::new(Val::Int(1)));
@ -142,8 +147,9 @@ fn test_eval_simple_lookup_error() {
#[test]
#[should_panic(expected = "Unable to find binding tpl1")]
fn test_expr_copy_no_such_tuple() {
let i_paths = Vec::new();
let cache = Rc::new(RefCell::new(MemoryCache::new()));
let b = Builder::new(std::env::current_dir().unwrap(), cache);
let b = Builder::new(std::env::current_dir().unwrap(), &i_paths, cache);
test_expr_to_val(
vec![(
Expression::Copy(CopyDef {
@ -163,8 +169,9 @@ fn test_expr_copy_no_such_tuple() {
#[test]
#[should_panic(expected = "Expected Tuple or Module got Int(1)")]
fn test_expr_copy_not_a_tuple() {
let i_paths = Vec::new();
let cache = Rc::new(RefCell::new(MemoryCache::new()));
let mut b = Builder::new(std::env::current_dir().unwrap(), cache);
let mut b = Builder::new(std::env::current_dir().unwrap(), &i_paths, cache);
b.build_output
.entry(value_node!("tpl1".to_string(), Position::new(1, 0, 0)))
.or_insert(Rc::new(Val::Int(1)));
@ -187,8 +194,9 @@ fn test_expr_copy_not_a_tuple() {
#[test]
#[should_panic(expected = "Expected type Integer for field fld1 but got String")]
fn test_expr_copy_field_type_error() {
let i_paths = Vec::new();
let cache = Rc::new(RefCell::new(MemoryCache::new()));
let mut b = Builder::new(std::env::current_dir().unwrap(), cache);
let mut b = Builder::new(std::env::current_dir().unwrap(), &i_paths, cache);
b.build_output
.entry(value_node!("tpl1".to_string(), Position::new(1, 0, 0)))
.or_insert(Rc::new(Val::Tuple(vec![(
@ -223,8 +231,9 @@ fn test_expr_copy_field_type_error() {
#[test]
#[should_panic(expected = "Unable to find binding arg1")]
fn test_macro_hermetic() {
let i_paths = Vec::new();
let cache = Rc::new(RefCell::new(MemoryCache::new()));
let mut b = Builder::new(std::env::current_dir().unwrap(), cache);
let mut b = Builder::new(std::env::current_dir().unwrap(), &i_paths, cache);
b.build_output
.entry(value_node!("arg1".to_string(), Position::new(1, 0, 0)))
.or_insert(Rc::new(Val::Str("bar".to_string())));
@ -266,8 +275,9 @@ fn test_macro_hermetic() {
#[test]
#[should_panic(expected = "Expected String but got Integer in Select expression")]
fn test_select_expr_not_a_string() {
let i_paths = Vec::new();
let cache = Rc::new(RefCell::new(MemoryCache::new()));
let mut b = Builder::new(std::env::current_dir().unwrap(), cache);
let mut b = Builder::new(std::env::current_dir().unwrap(), &i_paths, cache);
b.build_output
.entry(value_node!("foo".to_string(), Position::new(1, 0, 0)))
.or_insert(Rc::new(Val::Int(4)));

View File

@ -205,8 +205,9 @@ mod exec_test {
#[test]
fn convert_just_command_test() {
let i_paths = Vec::new();
let cache = Rc::new(RefCell::new(MemoryCache::new()));
let mut b = Builder::new(std::env::current_dir().unwrap(), cache);
let mut b = Builder::new(std::env::current_dir().unwrap(), &i_paths, cache);
let conv = ExecConverter::new();
b.eval_string(
"let script = {
@ -226,8 +227,9 @@ mod exec_test {
#[test]
fn convert_command_with_env_test() {
let i_paths = Vec::new();
let cache = Rc::new(RefCell::new(MemoryCache::new()));
let mut b = Builder::new(std::env::current_dir().unwrap(), cache);
let mut b = Builder::new(std::env::current_dir().unwrap(), &i_paths, cache);
let conv = ExecConverter::new();
b.eval_string(
"let script = {
@ -254,8 +256,9 @@ mod exec_test {
#[test]
fn convert_command_with_arg_test() {
let i_paths = Vec::new();
let cache = Rc::new(RefCell::new(MemoryCache::new()));
let mut b = Builder::new(std::env::current_dir().unwrap(), cache);
let mut b = Builder::new(std::env::current_dir().unwrap(), &i_paths, cache);
let conv = ExecConverter::new();
b.eval_string(
"let script = {

View File

@ -72,17 +72,18 @@ fn run_converter(c: &traits::Converter, v: Rc<Val>, f: Option<&str>) -> traits::
c.convert(v, file.as_mut())
}
fn build_file(
file: &str,
fn build_file<'a>(
file: &'a str,
validate: bool,
strict: bool,
import_paths: &'a Vec<PathBuf>,
cache: Rc<RefCell<Cache>>,
) -> Result<build::Builder, Box<Error>> {
) -> Result<build::Builder<'a>, Box<Error>> {
let mut file_path_buf = PathBuf::from(file);
if file_path_buf.is_relative() {
file_path_buf = std::env::current_dir().unwrap().join(file_path_buf);
}
let mut builder = build::Builder::new(file_path_buf, cache);
let mut builder = build::Builder::new(file_path_buf, import_paths, cache);
builder.set_strict(strict);
if validate {
builder.enable_validate_mode();
@ -94,9 +95,14 @@ fn build_file(
Ok(builder)
}
fn do_validate(file: &str, strict: bool, cache: Rc<RefCell<Cache>>) -> bool {
fn do_validate(
file: &str,
strict: bool,
import_paths: &Vec<PathBuf>,
cache: Rc<RefCell<Cache>>,
) -> bool {
println!("Validating {}", file);
match build_file(file, true, strict, cache) {
match build_file(file, true, strict, import_paths, cache) {
Ok(b) => {
if b.assert_collector.success {
println!("File {} Pass\n", file);
@ -116,11 +122,12 @@ fn do_validate(file: &str, strict: bool, cache: Rc<RefCell<Cache>>) -> bool {
fn do_compile(
file: &str,
strict: bool,
import_paths: &Vec<PathBuf>,
cache: Rc<RefCell<Cache>>,
registry: &ConverterRegistry,
) -> bool {
println!("Building {}", file);
let builder = match build_file(file, false, strict, cache.clone()) {
let builder = match build_file(file, false, strict, import_paths, cache.clone()) {
Ok(builder) => builder,
Err(err) => {
eprintln!("{}", err);
@ -152,6 +159,7 @@ fn visit_ucg_files(
recurse: bool,
validate: bool,
strict: bool,
import_paths: &Vec<PathBuf>,
cache: Rc<RefCell<Cache>>,
registry: &ConverterRegistry,
) -> Result<bool, Box<Error>> {
@ -177,6 +185,7 @@ fn visit_ucg_files(
recurse,
validate,
strict,
import_paths,
cache.clone(),
registry,
) {
@ -185,28 +194,34 @@ fn visit_ucg_files(
}
} else {
if validate && path_as_string.ends_with("_test.ucg") {
if !do_validate(&path_as_string, strict, cache.clone()) {
if !do_validate(&path_as_string, strict, import_paths, cache.clone()) {
result = false;
summary.push_str(format!("{} - FAIL\n", path_as_string).as_str())
} else {
summary.push_str(format!("{} - PASS\n", path_as_string).as_str())
}
} else if !validate && path_as_string.ends_with(".ucg") {
if !do_compile(&path_as_string, strict, cache.clone(), registry) {
if !do_compile(
&path_as_string,
strict,
import_paths,
cache.clone(),
registry,
) {
result = false;
}
}
}
}
} else if validate && our_path.ends_with("_test.ucg") {
if !do_validate(&our_path, strict, cache) {
if !do_validate(&our_path, strict, import_paths, cache) {
result = false;
summary.push_str(format!("{} - FAIL\n", our_path).as_str());
} else {
summary.push_str(format!("{} - PASS\n", &our_path).as_str());
}
} else if !validate {
if !do_compile(&our_path, strict, cache, registry) {
if !do_compile(&our_path, strict, import_paths, cache, registry) {
result = false;
}
}
@ -219,6 +234,7 @@ fn visit_ucg_files(
fn inspect_command(
matches: &clap::ArgMatches,
import_paths: &Vec<PathBuf>,
cache: Rc<RefCell<Cache>>,
registry: &ConverterRegistry,
strict: bool,
@ -226,7 +242,7 @@ fn inspect_command(
let file = matches.value_of("INPUT").unwrap();
let sym = matches.value_of("sym");
let target = matches.value_of("target").unwrap();
let mut builder = build::Builder::new(file, cache);
let mut builder = build::Builder::new(file, import_paths, cache);
builder.set_strict(strict);
match registry.get_converter(target) {
Some(converter) => {
@ -262,6 +278,7 @@ fn inspect_command(
fn build_command(
matches: &clap::ArgMatches,
import_paths: &Vec<PathBuf>,
cache: Rc<RefCell<Cache>>,
registry: &ConverterRegistry,
strict: bool,
@ -276,6 +293,7 @@ fn build_command(
recurse,
false,
strict,
import_paths,
cache.clone(),
&registry,
);
@ -286,7 +304,15 @@ fn build_command(
}
for file in files.unwrap() {
let pb = PathBuf::from(file);
if let Ok(false) = visit_ucg_files(&pb, recurse, false, strict, cache.clone(), &registry) {
if let Ok(false) = visit_ucg_files(
&pb,
recurse,
false,
strict,
import_paths,
cache.clone(),
&registry,
) {
ok = false;
}
}
@ -297,6 +323,7 @@ fn build_command(
fn test_command(
matches: &clap::ArgMatches,
import_paths: &Vec<PathBuf>,
cache: Rc<RefCell<Cache>>,
registry: &ConverterRegistry,
strict: bool,
@ -310,6 +337,7 @@ fn test_command(
recurse,
true,
strict,
import_paths,
cache.clone(),
&registry,
);
@ -326,6 +354,7 @@ fn test_command(
recurse,
true,
strict,
import_paths,
cache.clone(),
&registry,
) {
@ -355,17 +384,23 @@ fn main() {
let app_matches = app.clone().get_matches();
let cache: Rc<RefCell<Cache>> = Rc::new(RefCell::new(MemoryCache::new()));
let registry = ConverterRegistry::make_registry();
let mut import_paths = Vec::new();
if let Ok(path_list_str) = std::env::var("UCG_IMPORT_PATH") {
for p in std::env::split_paths(&path_list_str) {
import_paths.push(p);
}
}
let strict = if app_matches.is_present("nostrict") {
false
} else {
true
};
if let Some(matches) = app_matches.subcommand_matches("inspect") {
inspect_command(matches, cache, &registry, strict);
inspect_command(matches, &import_paths, cache, &registry, strict);
} else if let Some(matches) = app_matches.subcommand_matches("build") {
build_command(matches, cache, &registry, strict);
build_command(matches, &import_paths, cache, &registry, strict);
} else if let Some(matches) = app_matches.subcommand_matches("test") {
test_command(matches, cache, &registry, strict);
test_command(matches, &import_paths, cache, &registry, strict);
} else if let Some(_) = app_matches.subcommand_matches("converters") {
converters_command(&registry)
} else {