From 1d5f0319f3f38ab43fe804be7ba126c8e753fe74 Mon Sep 17 00:00:00 2001 From: Jeremy Wall Date: Wed, 28 Nov 2018 21:12:09 -0600 Subject: [PATCH] FEATURE: Detect import cycles. --- example_errors/import_cycle1.ucg | 1 + example_errors/import_cycle2.ucg | 1 + example_errors/import_cycle3.ucg | 1 + src/build/mod.rs | 32 +++++++++++++++++++++++++++++--- 4 files changed, 32 insertions(+), 3 deletions(-) create mode 100644 example_errors/import_cycle1.ucg create mode 100644 example_errors/import_cycle2.ucg create mode 100644 example_errors/import_cycle3.ucg diff --git a/example_errors/import_cycle1.ucg b/example_errors/import_cycle1.ucg new file mode 100644 index 0000000..c3da14e --- /dev/null +++ b/example_errors/import_cycle1.ucg @@ -0,0 +1 @@ +import "import_cycle2.ucg" as cycle2; \ No newline at end of file diff --git a/example_errors/import_cycle2.ucg b/example_errors/import_cycle2.ucg new file mode 100644 index 0000000..48a90e7 --- /dev/null +++ b/example_errors/import_cycle2.ucg @@ -0,0 +1 @@ +import "import_cycle3.ucg" as cycle3; \ No newline at end of file diff --git a/example_errors/import_cycle3.ucg b/example_errors/import_cycle3.ucg new file mode 100644 index 0000000..5e2b4c4 --- /dev/null +++ b/example_errors/import_cycle3.ucg @@ -0,0 +1 @@ +import "import_cycle1.ucg" as cycle1; \ No newline at end of file diff --git a/src/build/mod.rs b/src/build/mod.rs index 97a3c1b..f32cd54 100644 --- a/src/build/mod.rs +++ b/src/build/mod.rs @@ -114,6 +114,7 @@ pub struct Builder { /// build_output is our built output. build_output: ValueMap, /// last is the result of the last statement. + import_stack: Vec, pub stack: Option>>, pub is_module: bool, pub last: Option>, @@ -154,13 +155,16 @@ impl Builder { } pub fn new_with_env_and_scope>( - root: P, + file: P, cache: Rc>, scope: ValueMap, env: Rc, ) -> Self { + let file = file.into(); Builder { - file: root.into(), + // Our import stack is initialized with ourself. + import_stack: vec![file.to_string_lossy().to_string()], + file: file, validate_mode: false, assert_collector: AssertCollector { success: true, @@ -182,6 +186,13 @@ impl Builder { self.strict = to; } + pub fn prepend_import_stack(&mut self, imports: &Vec) { + let mut new_stack = self.import_stack.clone(); + new_stack.append(imports.clone().as_mut()); + eprintln!("import stack: {:?}", new_stack); + self.import_stack = new_stack; + } + // TOOD(jwall): This needs some unit tests. fn tuple_to_val(&mut self, fields: &Vec<(Token, Expression)>) -> Result, Box> { let mut new_fields = Vec::<(PositionedItem, Rc)>::new(); @@ -306,9 +317,12 @@ impl Builder { } } + fn detect_import_cycle(&self, path: &str) -> bool { + self.import_stack.iter().find(|p| *p == path).is_some() + } + fn eval_import(&mut self, def: &ImportDef) -> Result, Box> { let sym = &def.name; - // TODO(jwall): Enforce reserved word restriction here. if Self::check_reserved_word(&sym.fragment) { return Err(Box::new(error::BuildError::new( format!( @@ -327,6 +341,17 @@ impl Builder { normalized = import_path; } normalized = try!(normalized.canonicalize()); + if self.detect_import_cycle(normalized.to_string_lossy().as_ref()) { + return Err(Box::new(error::BuildError::new( + format!( + "Import Cycle Detected!!!! {} is already in import stack: {:?}", + normalized.to_string_lossy(), + self.import_stack, + ), + error::ErrorType::Unsupported, + sym.pos.clone(), + ))); + } eprintln!("processing import for {}", normalized.to_string_lossy()); // Introduce a scope so the above borrow is dropped before we modify // the cache below. @@ -336,6 +361,7 @@ impl Builder { Some(v) => v.clone(), None => { let mut b = Self::new(normalized.clone(), self.assets.clone()); + b.prepend_import_stack(&self.import_stack); try!(b.build()); b.get_outputs_as_val() }