diff --git a/src/build/compile_test.rs b/src/build/compile_test.rs index 8db95d8..92dbaa4 100644 --- a/src/build/compile_test.rs +++ b/src/build/compile_test.rs @@ -1,7 +1,8 @@ use super::{Builder, Val}; +use std; fn assert_build>(input: S, assert: &str) { - let mut b = Builder::new(); + let mut b = Builder::new(std::env::current_dir().unwrap()); b.build_file_string(input.into()).unwrap(); let result = b.eval_string(assert).unwrap(); if let &Val::Boolean(ok) = result.as_ref() { diff --git a/src/build/mod.rs b/src/build/mod.rs index 7a33b84..bf7e91a 100644 --- a/src/build/mod.rs +++ b/src/build/mod.rs @@ -23,7 +23,9 @@ use std::fmt::{Display, Formatter}; use std::fs::File; use std::io::Read; use std::ops::Deref; +use std::path::PathBuf; use std::rc::Rc; +use std::string::ToString; use ast::*; use error; @@ -35,6 +37,8 @@ impl MacroDef { /// Expands a ucg Macro using the given arguments into a new Tuple. pub fn eval( &self, + root: PathBuf, + env: Rc, mut args: Vec>, ) -> Result, Rc)>, Box> { // Error conditions. If the args don't match the length and types of the argdefs then this is @@ -54,7 +58,7 @@ impl MacroDef { for (i, arg) in args.drain(0..).enumerate() { scope.entry(self.argdefs[i].clone()).or_insert(arg.clone()); } - let b = Builder::new_with_scope(scope); + let b = Builder::new_with_env_and_scope(root, scope, env); let mut result: Vec<(Positioned, Rc)> = Vec::new(); for &(ref key, ref expr) in self.fields.iter() { // We clone the expressions here because this macro may be consumed @@ -272,6 +276,7 @@ type ValueMap = HashMap, Rc>; /// Handles building ucg code. pub struct Builder { + root: PathBuf, env: Rc, /// assets are other parsed files from import statements. They /// are keyed by the normalized import path. This acts as a cache @@ -344,21 +349,26 @@ impl Builder { } /// Constructs a new Builder. - pub fn new() -> Self { - Self::new_with_scope(HashMap::new()) + pub fn new>(root: P) -> Self { + Self::new_with_scope(root, HashMap::new()) } /// Constructs a new Builder with a provided scope. - pub fn new_with_scope(scope: ValueMap) -> Self { + pub fn new_with_scope>(root: P, scope: ValueMap) -> Self { let env_vars: Vec<(Positioned, Rc)> = env::vars() .map(|t| (Positioned::new(t.0, 0, 0), Rc::new(t.1.into()))) .collect(); - Self::new_with_env_and_scope(scope, Val::Tuple(env_vars)) + Self::new_with_env_and_scope(root, scope, Rc::new(Val::Tuple(env_vars))) } - pub fn new_with_env_and_scope(scope: ValueMap, env: Val) -> Self { + pub fn new_with_env_and_scope>( + root: P, + scope: ValueMap, + env: Rc, + ) -> Self { Builder { - env: Rc::new(env), + root: root.into(), + env: env, assets: HashMap::new(), files: HashSet::new(), out: scope, @@ -416,10 +426,13 @@ impl Builder { fn build_import(&mut self, def: &ImportDef) -> Result, Box> { let sym = &def.name; let positioned_sym = sym.into(); - if !self.files.contains(&def.path.fragment) { + let mut normalized = self.root.to_path_buf(); + normalized.push(&def.path.fragment); + let key = normalized.to_str().unwrap().to_string(); + if !self.files.contains(&key) { // Only parse the file once on import. if self.assets.get(&positioned_sym).is_none() { - let mut b = Self::new(); + let mut b = Self::new(normalized); try!(b.build_file(&def.path.fragment)); let fields: Vec<(Positioned, Rc)> = b.out.drain().collect(); let result = Rc::new(Val::Tuple(fields)); @@ -985,7 +998,7 @@ impl Builder { for arg in args.iter() { argvals.push(try!(self.eval_expr(arg))); } - let fields = try!(m.eval(argvals)); + let fields = try!(m.eval(self.root.clone(), self.env.clone(), argvals)); return Ok(Rc::new(Val::Tuple(fields))); } Err(Box::new(error::Error::new( @@ -1048,7 +1061,7 @@ impl Builder { let mut out = Vec::new(); for expr in l.iter() { let argvals = vec![try!(self.eval_expr(expr))]; - let fields = try!(macdef.eval(argvals)); + let fields = try!(macdef.eval(self.root.clone(), self.env.clone(), argvals)); if let Some(v) = Self::find_in_fieldlist(&def.field, &fields) { match def.typ { ListOpType::Map => { diff --git a/src/build/test.rs b/src/build/test.rs index b316ef4..8fa028e 100644 --- a/src/build/test.rs +++ b/src/build/test.rs @@ -1,5 +1,7 @@ use super::{Builder, CallDef, MacroDef, SelectDef, Val}; use ast::*; + +use std; use std::rc::Rc; fn test_expr_to_val(mut cases: Vec<(Expression, Val)>, b: Builder) { @@ -10,7 +12,7 @@ fn test_expr_to_val(mut cases: Vec<(Expression, Val)>, b: Builder) { #[test] fn test_eval_div_expr() { - let b = Builder::new(); + let b = Builder::new(std::env::current_dir().unwrap()); test_expr_to_val( vec![ ( @@ -39,7 +41,7 @@ fn test_eval_div_expr() { #[test] #[should_panic(expected = "Expected Float")] fn test_eval_div_expr_fail() { - let b = Builder::new(); + let b = Builder::new(std::env::current_dir().unwrap()); test_expr_to_val( vec![ ( @@ -58,7 +60,7 @@ fn test_eval_div_expr_fail() { #[test] fn test_eval_mul_expr() { - let b = Builder::new(); + let b = Builder::new(std::env::current_dir().unwrap()); test_expr_to_val( vec![ ( @@ -87,7 +89,7 @@ fn test_eval_mul_expr() { #[test] #[should_panic(expected = "Expected Float")] fn test_eval_mul_expr_fail() { - let b = Builder::new(); + let b = Builder::new(std::env::current_dir().unwrap()); test_expr_to_val( vec![ ( @@ -106,7 +108,7 @@ fn test_eval_mul_expr_fail() { #[test] fn test_eval_subtract_expr() { - let b = Builder::new(); + let b = Builder::new(std::env::current_dir().unwrap()); test_expr_to_val( vec![ ( @@ -135,7 +137,7 @@ fn test_eval_subtract_expr() { #[test] #[should_panic(expected = "Expected Float")] fn test_eval_subtract_expr_fail() { - let b = Builder::new(); + let b = Builder::new(std::env::current_dir().unwrap()); test_expr_to_val( vec![ ( @@ -154,7 +156,7 @@ fn test_eval_subtract_expr_fail() { #[test] fn test_eval_add_expr() { - let b = Builder::new(); + let b = Builder::new(std::env::current_dir().unwrap()); test_expr_to_val( vec![ ( @@ -222,7 +224,7 @@ fn test_eval_add_expr() { #[test] #[should_panic(expected = "Expected Float")] fn test_eval_add_expr_fail() { - let b = Builder::new(); + let b = Builder::new(std::env::current_dir().unwrap()); test_expr_to_val( vec![ ( @@ -271,13 +273,13 @@ fn test_eval_simple_expr() { ]), ), ], - Builder::new(), + Builder::new(std::env::current_dir().unwrap()), ); } #[test] fn test_eval_simple_lookup_expr() { - let mut b = Builder::new(); + let mut b = Builder::new(std::env::current_dir().unwrap()); b.out .entry(value_node!("var1".to_string(), 1, 0)) .or_insert(Rc::new(Val::Int(1))); @@ -294,7 +296,7 @@ fn test_eval_simple_lookup_expr() { #[test] fn test_eval_simple_lookup_error() { - let mut b = Builder::new(); + let mut b = Builder::new(std::env::current_dir().unwrap()); b.out .entry(value_node!("var1".to_string(), 1, 0)) .or_insert(Rc::new(Val::Int(1))); @@ -304,7 +306,7 @@ fn test_eval_simple_lookup_error() { #[test] fn test_eval_selector_expr() { - let mut b = Builder::new(); + let mut b = Builder::new(std::env::current_dir().unwrap()); b.out .entry(value_node!("var1".to_string(), 1, 0)) .or_insert(Rc::new(Val::Tuple(vec![ @@ -368,7 +370,7 @@ fn test_eval_selector_expr() { #[test] fn test_eval_selector_list_expr() { - let mut b = Builder::new(); + let mut b = Builder::new(std::env::current_dir().unwrap()); b.out .entry(value_node!("var1".to_string(), 1, 1)) .or_insert(Rc::new(Val::List(vec![ @@ -394,7 +396,7 @@ fn test_eval_selector_list_expr() { #[test] #[should_panic(expected = "Unable to find tpl1")] fn test_expr_copy_no_such_tuple() { - let b = Builder::new(); + let b = Builder::new(std::env::current_dir().unwrap()); test_expr_to_val( vec![ ( @@ -413,7 +415,7 @@ fn test_expr_copy_no_such_tuple() { #[test] #[should_panic(expected = "Expected Tuple got Int(1)")] fn test_expr_copy_not_a_tuple() { - let mut b = Builder::new(); + let mut b = Builder::new(std::env::current_dir().unwrap()); b.out .entry(value_node!("tpl1".to_string(), 1, 0)) .or_insert(Rc::new(Val::Int(1))); @@ -435,7 +437,7 @@ 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 mut b = Builder::new(); + let mut b = Builder::new(std::env::current_dir().unwrap()); b.out .entry(value_node!("tpl1".to_string(), 1, 0)) .or_insert(Rc::new(Val::Tuple(vec![ @@ -468,7 +470,7 @@ fn test_expr_copy_field_type_error() { #[test] fn test_expr_copy() { - let mut b = Builder::new(); + let mut b = Builder::new(std::env::current_dir().unwrap()); b.out .entry(value_node!("tpl1".to_string(), 1, 0)) .or_insert(Rc::new(Val::Tuple(vec![ @@ -539,7 +541,7 @@ fn test_expr_copy() { #[test] fn test_macro_call() { - let mut b = Builder::new(); + let mut b = Builder::new(std::env::current_dir().unwrap()); b.out .entry(value_node!("tstmac".to_string(), 1, 0)) .or_insert(Rc::new(Val::Macro(MacroDef { @@ -577,7 +579,7 @@ fn test_macro_call() { #[test] #[should_panic(expected = "Unable to find arg1")] fn test_macro_hermetic() { - let mut b = Builder::new(); + let mut b = Builder::new(std::env::current_dir().unwrap()); b.out .entry(value_node!("arg1".to_string(), 1, 0)) .or_insert(Rc::new(Val::String("bar".to_string()))); @@ -617,7 +619,7 @@ fn test_macro_hermetic() { #[test] fn test_select_expr() { - let mut b = Builder::new(); + let mut b = Builder::new(std::env::current_dir().unwrap()); b.out .entry(value_node!("foo".to_string(), 1, 0)) .or_insert(Rc::new(Val::String("bar".to_string()))); @@ -679,7 +681,7 @@ fn test_select_expr() { #[test] #[should_panic(expected = "Expected String but got Integer in Select expression")] fn test_select_expr_not_a_string() { - let mut b = Builder::new(); + let mut b = Builder::new(std::env::current_dir().unwrap()); b.out .entry(value_node!("foo".to_string(), 1, 0)) .or_insert(Rc::new(Val::Int(4))); @@ -714,7 +716,7 @@ fn test_select_expr_not_a_string() { #[test] fn test_let_statement() { - let mut b = Builder::new(); + let mut b = Builder::new(std::env::current_dir().unwrap()); let stmt = Statement::Let(LetDef { name: make_tok!("foo", 1, 1), value: Expression::Simple(Value::String(value_node!("bar".to_string(), 1, 1))), @@ -733,7 +735,7 @@ fn test_let_statement() { #[test] fn test_build_file_string() { - let mut b = Builder::new(); + let mut b = Builder::new(std::env::current_dir().unwrap()); b.build_file_string("let foo = 1;".to_string()).unwrap(); let key = value_node!("foo".to_string(), 1, 0); assert!(b.out.contains_key(&key)); @@ -741,7 +743,7 @@ fn test_build_file_string() { #[test] fn test_asset_symbol_lookups() { - let mut b = Builder::new(); + let mut b = Builder::new(std::env::current_dir().unwrap()); b.assets .entry(value_node!("foo".to_string(), 1, 0)) .or_insert(Rc::new(Val::Tuple(vec![ diff --git a/src/main.rs b/src/main.rs index c2fe76b..2be33ff 100644 --- a/src/main.rs +++ b/src/main.rs @@ -60,7 +60,7 @@ fn main() { let out = matches.value_of("out"); let sym = matches.value_of("sym"); let target = matches.value_of("target").unwrap(); - let mut builder = build::Builder::new(); + let mut builder = build::Builder::new(std::env::current_dir().unwrap()); match ConverterRunner::new(target) { Ok(converter) => { let result = builder.build_file(file); @@ -91,7 +91,7 @@ fn main() { } } else if let Some(matches) = app.subcommand_matches("validate") { let file = matches.value_of("INPUT").unwrap(); - let mut builder = build::Builder::new(); + let mut builder = build::Builder::new(std::env::current_dir().unwrap()); builder.build_file(file).unwrap(); println!("File Validates"); process::exit(0);