From d7db62ba36e8ca9f65b549caec2834cfcb34f8da Mon Sep 17 00:00:00 2001 From: "Victor M. Alvarez" Date: Fri, 13 Sep 2024 09:42:24 +0200 Subject: [PATCH] fix: calling `Compiler.new_namespace` for a second time with the same name should not have effect When `Compiler.new_namespace` is called two consecutive times with the same namespace, the second call has not effect. --- lib/src/compiler/mod.rs | 16 +++++++++++++--- lib/src/compiler/tests/mod.rs | 12 ++++++++++++ 2 files changed, 25 insertions(+), 3 deletions(-) diff --git a/lib/src/compiler/mod.rs b/lib/src/compiler/mod.rs index 1d0c3174..84b08cf8 100644 --- a/lib/src/compiler/mod.rs +++ b/lib/src/compiler/mod.rs @@ -267,7 +267,7 @@ pub struct Compiler<'a> { /// Pool that contains all the identifiers used in the rules. Each /// identifier appears only once, even if they are used by multiple /// rules. For example, the pool contains a single copy of the common - /// identifier `$a`. Each identifier have an unique 32-bits [`IdentId`] + /// identifier `$a`. Each identifier have a unique 32-bits [`IdentId`] /// that can be used for retrieving the identifier from the pool. ident_pool: StringPool, @@ -611,7 +611,8 @@ impl<'a> Compiler<'a> { /// Creates a new namespace. /// /// Further calls to [`Compiler::add_source`] will put the rules under the - /// newly created namespace. + /// newly created namespace. If the current namespace is already named as + /// the current one, no new namespace is created. /// /// In the example below both rules `foo` and `bar` are put into the same /// namespace (the default namespace), therefore `bar` can use `foo` as @@ -643,7 +644,16 @@ impl<'a> Compiler<'a> { /// # Ok::<(), Box>(()) /// ``` pub fn new_namespace(&mut self, namespace: &str) -> &mut Self { - // Remove the symbol table corresponding to the previous namespace. + let current_namespace = self + .ident_pool + .get(self.current_namespace.ident_id) + .expect("expecting a namespace"); + // If the current namespace is already named as the new namespace + // this function has no effect. + if namespace == current_namespace { + return self; + } + // Remove the symbol table corresponding to the current namespace. self.symbol_table.pop().expect("expecting a namespace"); // Create a new namespace. The NamespaceId is simply the ID of the // previous namespace + 1. diff --git a/lib/src/compiler/tests/mod.rs b/lib/src/compiler/tests/mod.rs index 16ff5854..f11983e3 100644 --- a/lib/src/compiler/tests/mod.rs +++ b/lib/src/compiler/tests/mod.rs @@ -63,6 +63,18 @@ fn namespaces() { .new_namespace("bar") .add_source("rule bar {condition: foo}") .is_err()); + + let mut compiler = Compiler::new(); + + // `bar` can use `foo` because they are in the same namespace, the second + // call to `new_namespace` has no effect. + assert!(compiler + .new_namespace("foo") + .add_source("rule foo {condition: true}") + .unwrap() + .new_namespace("foo") + .add_source("rule bar {condition: foo}") + .is_ok()); } #[test]