Repository: microsoft/regorus (language: python)

Issue:
Add --non-strict flag to regorus
By default, regorus runs in strict mode, detecting and raising errors.  Add the `--non-strict` mode that allows returning Undefined instead of raising some errors. With this flag

`regorus eval`  is equivalent to `opa eval --strict --strict-builtin-errors`
`regorus eval --non-strict` == `opa eval`


Discussion / hints:

Fix patch:
diff --git a/examples/regorus.rs b/examples/regorus.rs
index 23dd3e9e..89f6ee4f 100644
--- a/examples/regorus.rs
+++ b/examples/regorus.rs
@@ -10,10 +10,13 @@ fn rego_eval(
     input: Option<String>,
     query: String,
     enable_tracing: bool,
+    non_strict: bool,
 ) -> Result<()> {
     // Create engine.
     let mut engine = regorus::Engine::new();
 
+    engine.set_strict_builtin_errors(!non_strict);
+
     // Load files from given bundles.
     for dir in bundles.iter() {
         let entries =
@@ -130,6 +133,10 @@ enum RegorusCommand {
         /// Enable tracing.
         #[arg(long, short)]
         trace: bool,
+
+        // Non strict execution
+        #[arg(long, short)]
+        non_strict: bool,
     },
 
     /// Tokenize a Rego policy.
@@ -171,7 +178,8 @@ fn main() -> Result<()> {
             input,
             query,
             trace,
-        } => rego_eval(&bundles, &data, input, query, trace),
+            non_strict,
+        } => rego_eval(&bundles, &data, input, query, trace, non_strict),
         RegorusCommand::Lex { file, verbose } => rego_lex(file, verbose),
         RegorusCommand::Parse { file } => rego_parse(file),
     }
diff --git a/src/engine.rs b/src/engine.rs
index e94aaf0d..7183373b 100644
--- a/src/engine.rs
+++ b/src/engine.rs
@@ -121,10 +121,10 @@ impl Engine {
         self.prepare_for_eval(enable_tracing)?;
         self.interpreter.clean_internal_evaluation_state();
 
-        // Ensure that each module has an empty object
-        for m in &self.modules {
+        // Ensure that empty modules are created.
+        for m in self.modules.iter().filter(|m| m.policy.is_empty()) {
             let path = Parser::get_path_ref_components(&m.package.refr)?;
-            let path: Vec<&str> = path.iter().map(|s| *s.text()).collect();
+            let path: Vec<&str> = path.iter().map(|s| s.text()).collect();
             let vref =
                 Interpreter::make_or_get_value_mut(self.interpreter.get_data_mut(), &path[..])?;
             if *vref == Value::Undefined {
@@ -147,6 +147,16 @@ impl Engine {
             self.interpreter.set_current_module(prev_module)?;
         }
 
+        // Ensure that all modules are created.
+        for m in &self.modules {
+            let path = Parser::get_path_ref_components(&m.package.refr)?;
+            let path: Vec<&str> = path.iter().map(|s| s.text()).collect();
+            let vref =
+                Interpreter::make_or_get_value_mut(self.interpreter.get_data_mut(), &path[..])?;
+            if *vref == Value::Undefined {
+                *vref = Value::new_object();
+            }
+        }
         self.interpreter.create_rule_prefixes()?;
         Ok(self.interpreter.get_data_mut().clone())
     }
diff --git a/src/interpreter.rs b/src/interpreter.rs
index 2e68e408..bcd67610 100644
--- a/src/interpreter.rs
+++ b/src/interpreter.rs
@@ -268,13 +268,13 @@ impl Interpreter {
                 // Accumulate chained . field accesses.
                 Expr::RefDot { refr, field, .. } => {
                     expr = refr;
-                    path.push(*field.text());
+                    path.push(field.text());
                 }
                 Expr::RefBrack { refr, index, .. } => match index.as_ref() {
                     // refr["field"] is the same as refr.field
                     Expr::String(s) => {
                         expr = refr;
-                        path.push(*s.text());
+                        path.push(s.text());
                     }
                     // Handle other forms of refr.
                     // Note, we have the choice to evaluate a non-string index
@@ -758,7 +758,7 @@ impl Interpreter {
         let raise_error = is_last && type_match.get(expr).is_none();
 
         match (expr.as_ref(), value) {
-            (Expr::Var(ident), _) if ident.text().as_ref() == &"_" => Ok(true),
+            (Expr::Var(ident), _) if ident.text() == "_" => Ok(true),
             (Expr::Var(ident), _)
                 if check_existing_value
                     && self.lookup_local_var(&ident.source_str()) == Some(value.clone()) =>
@@ -1130,7 +1130,7 @@ impl Interpreter {
             // Apply with modifiers.
             for wm in &stmt.with_mods {
                 let path = Parser::get_path_ref_components(&wm.refr)?;
-                let path: Vec<&str> = path.iter().map(|s| *s.text()).collect();
+                let path: Vec<&str> = path.iter().map(|s| s.text()).collect();
                 let target = path.join(".");
 
                 let value = match self.eval_expr(&wm.r#as) {
@@ -2003,7 +2003,7 @@ impl Interpreter {
                     if allow_return_arg && self.lookup_local_var(&var.source_str()).is_none() =>
                 {
                     let value = self.eval_call_impl(span, fcn, &params[..params.len() - 1])?;
-                    if *var.text() != "_" {
+                    if var.text() != "_" {
                         self.add_variable(&var.source_str(), value)?;
                     }
                     Ok(Value::Bool(true))
@@ -2036,6 +2036,31 @@ impl Interpreter {
         None
     }
 
+    fn ensure_module_evaluated(&mut self, path: String) -> Result<()> {
+        for module in self.modules.clone() {
+            let module_path = get_path_string(&module.package.refr, Some("data"))?;
+            if module_path.starts_with(&path)
+                && (module_path.len() == path.len()
+                    || &module_path[path.len()..path.len() + 1] == ".")
+            {
+                // Ensure that the module is created.
+                {
+                    let path = Parser::get_path_ref_components(&module.package.refr)?;
+                    let path: Vec<&str> = path.iter().map(|s| s.text()).collect();
+                    let vref = Self::make_or_get_value_mut(&mut self.data, &path[..])?;
+                    if *vref == Value::Undefined {
+                        *vref = Value::new_object();
+                    }
+                }
+
+                for rule in &module.policy {
+                    self.eval_rule(&module, rule)?;
+                }
+            }
+        }
+        Ok(())
+    }
+
     fn ensure_rule_evaluated(&mut self, path: String) -> Result<()> {
         if let Some(rules) = self.rules.get(&path) {
             for r in rules.clone() {
@@ -2100,7 +2125,7 @@ impl Interpreter {
             // Find the rule to which the var being looked up corresponds to. This is the prefix for
             // which rules exist.
             let mut found = false;
-            for i in 1..fields.len() + 1 {
+            for i in (1..fields.len() + 1).rev() {
                 let path = "data.".to_owned() + &fields[0..i].join(".");
                 if self.rules.get(&path).is_some() || self.default_rules.get(&path).is_some() {
                     self.ensure_rule_evaluated(path)?;
@@ -2109,16 +2134,16 @@ impl Interpreter {
                 }
             }
 
-            // TODO: emit this error only if the var can belong to a rego module; not data specified via json/yaml.
-            //if !no_error && !found {
-            //    bail!(span.error("var is unsafe"));
-            //}
-            let _ = found;
+            if !found {
+                // This could be path to a module.
+                let path = "data.".to_owned() + &fields.join(".");
+                self.ensure_module_evaluated(path)?;
+            }
 
             Ok(Self::get_value_chained(self.data.clone(), fields))
         } else if !self.modules.is_empty() {
             let path = Parser::get_path_ref_components(&self.module.clone().unwrap().package.refr)?;
-            let mut path: Vec<&str> = path.iter().map(|s| *s.text()).collect();
+            let mut path: Vec<&str> = path.iter().map(|s| s.text()).collect();
             path.push(name.text());
 
             let v = Self::get_value_chained(self.data.clone(), &path);
@@ -2126,7 +2151,7 @@ impl Interpreter {
             // If the rule has already been evaluated or specified via a with modifier,
             // use that value.
             if v != Value::Undefined {
-                return Ok(v);
+                return Ok(Self::get_value_chained(v, fields));
             }
 
             // Ensure that all the rules having common prefix (name) are evaluated.
@@ -2139,7 +2164,26 @@ impl Interpreter {
                 bail!(span.error("var is unsafe"));
             }
 
-            self.ensure_rule_evaluated(rule_path)?;
+            // Find the rule to which the var being looked up corresponds to. This is the prefix for
+            // which rules exist.
+            let mut found = false;
+            for i in (0..fields.len() + 1).rev() {
+                let comps = &fields[0..i];
+                let path = if comps.is_empty() {
+                    rule_path.clone()
+                } else {
+                    rule_path.clone() + "." + &fields[0..i].join(".")
+                };
+
+                if self.rules.get(&path).is_some() || self.default_rules.get(&path).is_some() {
+                    self.ensure_rule_evaluated(path)?;
+                    found = true;
+                    break;
+                }
+            }
+
+            // TODO: Is found needed?
+            let _ = found;
 
             let value = Self::get_value_chained(self.data.clone(), &path[..]);
             Ok(Self::get_value_chained(value, fields))
@@ -2161,7 +2205,7 @@ impl Interpreter {
             Expr::True(_) => Ok(Value::Bool(true)),
             Expr::False(_) => Ok(Value::Bool(false)),
             Expr::Number(span) => {
-                let v = match Number::from_str(*span.text()) {
+                let v = match Number::from_str(span.text()) {
                     Ok(v) => Ok(Value::Number(v)),
                     Err(_) => Err(span
                         .source
@@ -2383,19 +2427,19 @@ impl Interpreter {
         while expr.is_some() {
             match expr {
                 Some(Expr::RefDot { refr, field, .. }) => {
-                    comps.push(*field.text());
+                    comps.push(field.text());
                     expr = Some(refr);
                 }
                 Some(Expr::RefBrack { refr, index, .. })
                     if matches!(index.as_ref(), Expr::String(_)) =>
                 {
                     if let Expr::String(s) = index.as_ref() {
-                        comps.push(*s.text());
+                        comps.push(s.text());
                         expr = Some(refr);
                     }
                 }
                 Some(Expr::Var(v)) => {
-                    comps.push(*v.text());
+                    comps.push(v.text());
                     expr = None;
                 }
                 _ => bail!(format!("internal error: not a simplee ref {expr:?}")),
@@ -2521,7 +2565,7 @@ impl Interpreter {
             };
 
             Parser::get_path_ref_components_into(refr, &mut path)?;
-            let paths: Vec<&str> = path.iter().map(|s| *s.text()).collect();
+            let paths: Vec<&str> = path.iter().map(|s| s.text()).collect();
 
             Self::check_default_value(value)?;
             let value = self.eval_expr(value)?;
@@ -2573,7 +2617,8 @@ impl Interpreter {
         if Self::get_value_chained(self.init_data.clone(), path) == Value::Undefined {
             Self::merge_rule_value(span, vref, value)
         } else {
-            Err(span.error("value for rule has already been specified in data document"))
+            // Retain specified value.
+            Ok(())
         }
     }
 
@@ -2636,7 +2681,7 @@ impl Interpreter {
                             v => v,
                         };
 
-                        let paths: Vec<&str> = path.iter().map(|s| *s.text()).collect();
+                        let paths: Vec<&str> = path.iter().map(|s| s.text()).collect();
 
                         if let RuleHead::Set { .. } = &rule_head {
                             // Ensure that sets are created as empty.
@@ -2655,7 +2700,7 @@ impl Interpreter {
                             Parser::get_path_ref_components(&self.current_module()?.package.refr)?;
 
                         Parser::get_path_ref_components_into(refr, &mut path)?;
-                        let path: Vec<&str> = path.iter().map(|s| *s.text()).collect();
+                        let path: Vec<&str> = path.iter().map(|s| s.text()).collect();
 
                         // Ensure that for functions with a nesting level (e.g: a.foo),
                         // `a` is created as an empty object.
@@ -2761,17 +2806,17 @@ impl Interpreter {
         loop {
             refr = match refr.as_ref() {
                 Expr::Var(v) => {
-                    components.push((*v.text().as_ref()).into());
+                    components.push(v.text().into());
                     break;
                 }
                 Expr::RefBrack { refr, index, .. } => {
                     if let Expr::String(s) = index.as_ref() {
-                        components.push((*s.text().as_ref()).into());
+                        components.push(s.text().into());
                     }
                     refr
                 }
                 Expr::RefDot { refr, field, .. } => {
-                    components.push((*field.text().as_ref()).into());
+                    components.push(field.text().into());
                     refr
                 }
                 _ => break,
@@ -2830,27 +2875,21 @@ impl Interpreter {
     }
 
     fn record_rule(&mut self, refr: &Ref<Expr>, rule: Ref<Rule>) -> Result<()> {
-        let path = get_root_var(refr)?;
-        let path = path.text();
-        let path = self.current_module_path.clone() + "." + path;
-        match self.rules.entry(path) {
-            Entry::Occupied(o) => {
-                o.into_mut().push(rule.clone());
-            }
-            Entry::Vacant(v) => {
-                v.insert(vec![rule.clone()]);
-            }
-        }
-        let path = Self::get_path_string(refr, None)?;
-        let path = self.current_module_path.clone() + "." + &path;
-        match self.rules.entry(path) {
-            Entry::Occupied(o) => {
-                o.into_mut().push(rule.clone());
-            }
-            Entry::Vacant(v) => {
-                v.insert(vec![rule.clone()]);
+        let comps = Parser::get_path_ref_components(refr)?;
+        let comps: Vec<&str> = comps.iter().map(|s| s.text()).collect();
+        for c in 0..comps.len() {
+            let path = self.current_module_path.clone() + "." + &comps[0..c + 1].join(".");
+
+            match self.rules.entry(path) {
+                Entry::Occupied(o) => {
+                    o.into_mut().push(rule.clone());
+                }
+                Entry::Vacant(v) => {
+                    v.insert(vec![rule.clone()]);
+                }
             }
         }
+
         Ok(())
     }
 
diff --git a/src/lexer.rs b/src/lexer.rs
index a95f2710..8d8dc6f4 100644
--- a/src/lexer.rs
+++ b/src/lexer.rs
@@ -186,8 +186,8 @@ pub struct Span {
 }
 
 impl Span {
-    pub fn text(&self) -> std::rc::Rc<&str> {
-        std::rc::Rc::new(&self.source.contents()[self.start as usize..self.end as usize])
+    pub fn text(&self) -> &str {
+        &self.source.contents()[self.start as usize..self.end as usize]
     }
 
     pub fn source_str(&self) -> SourceStr {
@@ -619,7 +619,7 @@ impl<'source> Lexer<'source> {
 	    _ if chr.is_ascii_digit() => self.read_number(),
 	    _ if chr.is_ascii_alphabetic() || chr == '_' => {
 		let mut ident = self.read_ident()?;
-		if *ident.1.text() == "set" && self.peek().1 == '(' {
+		if ident.1.text() == "set" && self.peek().1 == '(' {
 		    // set immediately followed by ( is treated as set( if
 		    // the next token is ).
 		    let state = (self.iter.clone(), self.line, self.col);
@@ -627,7 +627,7 @@ impl<'source> Lexer<'source> {
 
 		    // Check it next token is ).
 		    let next_tok = self.next_token()?;
-		    let is_setp = *next_tok.1.text() == ")";
+		    let is_setp = next_tok.1.text() == ")";
 
 		    // Restore state
 		    (self.iter, self.line, self.col) = state;
diff --git a/src/parser.rs b/src/parser.rs
index 2b82c0c5..20a3cafa 100644
--- a/src/parser.rs
+++ b/src/parser.rs
@@ -33,12 +33,12 @@ impl<'source> Parser<'source> {
         })
     }
 
-    pub fn token_text(&self) -> std::rc::Rc<&str> {
+    pub fn token_text(&self) -> &str {
         match self.tok.0 {
             TokenKind::Symbol | TokenKind::Number | TokenKind::Ident | TokenKind::Eof => {
                 self.tok.1.text()
             }
-            TokenKind::String | TokenKind::RawString => "".into(),
+            TokenKind::String | TokenKind::RawString => "",
         }
     }
 
@@ -50,7 +50,7 @@ impl<'source> Parser<'source> {
     }
 
     fn expect(&mut self, text: &str, context: &str) -> Result<()> {
-        if *self.token_text() == text {
+        if self.token_text() == text {
             self.next_token()
         } else {
             let msg = format!("expecting `{text}` {context}");
@@ -120,9 +120,9 @@ impl<'source> Parser<'source> {
     }
 
     fn handle_import_future_keywords(&mut self, comps: &[Span]) -> Result<bool> {
-        if comps.len() >= 2 && *comps[0].text() == "future" && *comps[1].text() == "keywords" {
+        if comps.len() >= 2 && comps[0].text() == "future" && comps[1].text() == "keywords" {
             match comps.len() - 2 {
-                1 => self.set_future_keyword(&comps[2].text(), &comps[2])?,
+                1 => self.set_future_keyword(comps[2].text(), &comps[2])?,
                 0 => {
                     let span = &comps[1];
                     for kw in FUTURE_KEYWORDS.iter() {
@@ -137,7 +137,7 @@ impl<'source> Parser<'source> {
                 }
             }
             Ok(true)
-        } else if !comps.is_empty() && *comps[0].text() == "future" {
+        } else if !comps.is_empty() && comps[0].text() == "future" {
             let s = &comps[0];
             Err(self
                 .source
@@ -153,7 +153,7 @@ impl<'source> Parser<'source> {
         is_optional: bool,
         context: &str,
     ) -> Result<()> {
-        if *self.token_text() == kw {
+        if self.token_text() == kw {
             match &self.future_keywords.get(kw) {
                 Some(_) => self.next_token(),
                 None => {
@@ -189,7 +189,7 @@ impl<'source> Parser<'source> {
     fn parse_ident(&mut self) -> Result<Span> {
         let span = self.tok.1.clone();
         match self.tok.0 {
-            TokenKind::Ident if self.is_keyword(*span.text()) => Err(self.source.error(
+            TokenKind::Ident if self.is_keyword(span.text()) => Err(self.source.error(
                 self.tok.1.line,
                 self.tok.1.col,
                 &format!("unexpected keyword `{}`", span.text()),
@@ -208,10 +208,10 @@ impl<'source> Parser<'source> {
         let span = self.tok.1.clone();
         match self.tok.0 {
             TokenKind::Ident
-                if self.is_keyword(*span.text())
-                    || (self.is_imported_future_keyword(*span.text())
+                if self.is_keyword(span.text())
+                    || (self.is_imported_future_keyword(span.text())
 		    // contains can be the name of a builtin even when a keyword
-		    && *span.text() != "contains") =>
+		    && span.text() != "contains") =>
             {
                 Err(self.source.error(
                     self.tok.1.line,
@@ -235,7 +235,7 @@ impl<'source> Parser<'source> {
             TokenKind::Number => Expr::Number(span),
             TokenKind::String => Expr::String(span),
             TokenKind::RawString => Expr::RawString(span),
-            TokenKind::Ident => match *self.token_text() {
+            TokenKind::Ident => match self.token_text() {
                 "null" => Expr::Null(span),
                 "true" => Expr::True(span),
                 "false" => Expr::False(span),
@@ -260,7 +260,7 @@ impl<'source> Parser<'source> {
 
         // Parse the first expression as a ref.
         let term = match self.parse_ref() {
-            Ok(e) if *self.token_text() == "|" => e,
+            Ok(e) if self.token_text() == "|" => e,
             _ => {
                 // Not a comprehension. Restore state.
                 *self = state;
@@ -305,11 +305,11 @@ impl<'source> Parser<'source> {
                 // No progress was made in parsing comprehension.
                 // Parse as array.
                 let mut items = vec![];
-                if *self.token_text() != "]" {
+                if self.token_text() != "]" {
                     items.push(Ref::new(self.parse_in_expr()?));
-                    while *self.token_text() == "," {
+                    while self.token_text() == "," {
                         self.next_token()?;
-                        match *self.token_text() {
+                        match self.token_text() {
                             "]" => break,
                             "" if self.tok.0 == TokenKind::Eof => break,
                             _ => items.push(Ref::new(self.parse_in_expr()?)),
@@ -348,7 +348,7 @@ impl<'source> Parser<'source> {
 
         // It could be a set, object or object comprehension.
         // In all the cases, the first expression must parse successfully.
-        if *self.token_text() == "}" {
+        if self.token_text() == "}" {
             self.next_token()?;
             span.end = self.end;
             return Ok(Expr::Object {
@@ -360,12 +360,12 @@ impl<'source> Parser<'source> {
         let mut item_span = self.tok.1.clone();
         let first = self.parse_in_expr()?;
 
-        if *self.token_text() != ":" {
+        if self.token_text() != ":" {
             // Parse as set.
             let mut items = vec![Ref::new(first)];
-            while *self.token_text() == "," {
+            while self.token_text() == "," {
                 self.next_token()?;
-                match *self.token_text() {
+                match self.token_text() {
                     "}" => break,
                     "" if self.tok.0 == TokenKind::Eof => break,
                     _ => items.push(Ref::new(self.parse_in_expr()?)),
@@ -405,10 +405,10 @@ impl<'source> Parser<'source> {
         item_span.end = self.end;
         items.push((item_span, Ref::new(first), Ref::new(value)));
 
-        while *self.token_text() == "," {
+        while self.token_text() == "," {
             self.next_token()?;
             let item_start = self.tok.1.start;
-            let key = match *self.token_text() {
+            let key = match self.token_text() {
                 "}" => break,
                 "" if self.tok.0 == TokenKind::Eof => break,
                 _ => self.parse_in_expr()?,
@@ -464,7 +464,7 @@ impl<'source> Parser<'source> {
 
     fn parse_ref(&mut self) -> Result<Expr> {
         let start = self.tok.1.start;
-        let mut term = match *self.token_text() {
+        let mut term = match self.token_text() {
             "[" if self.tok.0 == TokenKind::Symbol => self.parse_compr_or_array()?,
             "{" => self.parse_compr_set_or_object()?,
             "set(" => self.parse_empty_set()?,
@@ -494,7 +494,7 @@ impl<'source> Parser<'source> {
             let mut span = self.tok.1.clone();
             let sep_pos = span.start;
             span.start = start;
-            match *self.token_text() {
+            match self.token_text() {
                 "." | "[" if self.tok.1.start != self.end => {
                     if self.line != self.tok.1.line {
                         // Newline encountered. This could be a separate
@@ -552,11 +552,11 @@ impl<'source> Parser<'source> {
                 "(" if possible_fcn => {
                     self.next_token()?;
                     let mut args = vec![];
-                    if *self.token_text() != ")" {
+                    if self.token_text() != ")" {
                         args.push(Ref::new(self.parse_in_expr()?));
-                        while *self.token_text() == "," {
+                        while self.token_text() == "," {
                             self.next_token()?;
-                            match *self.token_text() {
+                            match self.token_text() {
                                 ")" => break,
                                 "" if self.tok.0 == TokenKind::Eof => break,
                                 _ => args.push(Ref::new(self.parse_in_expr()?)),
@@ -592,7 +592,7 @@ impl<'source> Parser<'source> {
         loop {
             let mut span = self.tok.1.clone();
             span.start = start;
-            let op = match *self.token_text() {
+            let op = match self.token_text() {
                 "*" => ArithOp::Mul,
                 "/" => ArithOp::Div,
                 "%" => ArithOp::Mod,
@@ -617,7 +617,7 @@ impl<'source> Parser<'source> {
         loop {
             let mut span = self.tok.1.clone();
             span.start = start;
-            let op = match *self.token_text() {
+            let op = match self.token_text() {
                 "+" => ArithOp::Add,
                 "-" => ArithOp::Sub,
                 _ => return Ok(expr),
@@ -638,7 +638,7 @@ impl<'source> Parser<'source> {
         let start = self.tok.1.start;
         let mut expr = self.parse_arith_expr()?;
 
-        while *self.token_text() == "&" {
+        while self.token_text() == "&" {
             let mut span = self.tok.1.clone();
             span.start = start;
             self.next_token()?;
@@ -658,7 +658,7 @@ impl<'source> Parser<'source> {
         let start = self.tok.1.start;
         let mut expr = self.parse_and_expr()?;
 
-        while *self.token_text() == "|" {
+        while self.token_text() == "|" {
             let mut span = self.tok.1.clone();
             span.start = start;
             self.next_token()?;
@@ -680,7 +680,7 @@ impl<'source> Parser<'source> {
         loop {
             let mut span = self.tok.1.clone();
             span.start = start;
-            let op = match *self.token_text() {
+            let op = match self.token_text() {
                 "<" => BoolOp::Lt,
                 "<=" => BoolOp::Le,
                 "==" => BoolOp::Eq,
@@ -726,7 +726,7 @@ impl<'source> Parser<'source> {
             };
             expr2 = None;
 
-            if *self.token_text() != "in" {
+            if self.token_text() != "in" {
                 break;
             }
         }
@@ -738,7 +738,7 @@ impl<'source> Parser<'source> {
         let start = self.tok.1.start;
         let mut expr = self.parse_bool_expr()?;
 
-        while *self.token_text() == "in" && self.future_keywords.get("in").is_some() {
+        while self.token_text() == "in" && self.future_keywords.get("in").is_some() {
             expr = self.parse_membership_tail(start, expr, None)?;
         }
 
@@ -749,13 +749,13 @@ impl<'source> Parser<'source> {
         let start = self.tok.1.start;
         let mut expr = self.parse_bool_expr()?;
 
-        if *self.token_text() == "," {
+        if self.token_text() == "," {
             self.next_token()?;
             let value = self.parse_bool_expr()?;
             expr = self.parse_membership_tail(start, expr, Some(value))?;
         }
 
-        while *self.token_text() == "in" && self.is_imported_future_keyword("in") {
+        while self.token_text() == "in" && self.is_imported_future_keyword("in") {
             expr = self.parse_membership_tail(start, expr, None)?;
         }
 
@@ -769,7 +769,7 @@ impl<'source> Parser<'source> {
 
         let mut span = self.tok.1.clone();
         span.start = start;
-        let op = match *self.token_text() {
+        let op = match self.token_text() {
             "=" => AssignOp::Eq,
             ":=" => AssignOp::ColEq,
             _ => {
@@ -791,7 +791,7 @@ impl<'source> Parser<'source> {
 
     fn parse_with_modifiers(&mut self) -> Result<Vec<WithModifier>> {
         let mut modifiers = vec![];
-        while *self.token_text() == "with" {
+        while self.token_text() == "with" {
             let mut span = self.tok.1.clone();
             self.next_token()?;
             let refr = self.parse_path_ref()?;
@@ -813,7 +813,7 @@ impl<'source> Parser<'source> {
         self.parse_future_keyword("every", false, context)?;
 
         let ident = self.parse_var()?;
-        let (key, value) = match *self.token_text() {
+        let (key, value) = match self.token_text() {
             "," => {
                 self.next_token()?;
                 match self.parse_var() {
@@ -854,7 +854,7 @@ impl<'source> Parser<'source> {
         let mut vars = vec![self.tok.1.clone()];
         let mut refs = vec![Ref::new(self.parse_ref()?)];
 
-        while *self.token_text() == "," {
+        while self.token_text() == "," {
             self.next_token()?;
             let mut span = self.tok.1.clone();
             refs.push(Ref::new(self.parse_ref()?));
@@ -862,8 +862,8 @@ impl<'source> Parser<'source> {
             vars.push(span);
         }
 
-        if *self.token_text() != "in" || !self.is_imported_future_keyword("in") {
-            if *self.token_text() == "in" {
+        if self.token_text() != "in" || !self.is_imported_future_keyword("in") {
+            if self.token_text() == "in" {
                 self.warn_future_keyword();
             }
             // All the refs must be identifiers
@@ -913,7 +913,7 @@ impl<'source> Parser<'source> {
     }
 
     fn parse_literal(&mut self) -> Result<Literal> {
-        match *self.token_text() {
+        match self.token_text() {
             "some" => return self.parse_some_stmt(),
             "every" => {
                 if self.future_keywords.get("every").is_some() {
@@ -924,7 +924,7 @@ impl<'source> Parser<'source> {
             _ => (),
         }
         let mut span = self.tok.1.clone();
-        let not_expr = if *self.token_text() == "not" {
+        let not_expr = if self.token_text() == "not" {
             self.next_token()?;
             true
         } else {
@@ -955,7 +955,7 @@ impl<'source> Parser<'source> {
 
     pub fn parse_query(&mut self, mut span: Span, end_delim: &str) -> Result<Query> {
         let state = self.clone();
-        let is_definite_query = matches!(*self.token_text(), "some" | "every");
+        let is_definite_query = matches!(self.token_text(), "some" | "every");
 
         // TODO: empty query?
         let mut literals = vec![];
@@ -971,7 +971,7 @@ impl<'source> Parser<'source> {
             }
         };
 
-        if *self.token_text() == "," {
+        if self.token_text() == "," {
             // This is likely an array or set.
             // Restore the state.
             *self = state;
@@ -981,7 +981,7 @@ impl<'source> Parser<'source> {
         literals.push(stmt);
 
         loop {
-            match *self.token_text() {
+            match self.token_text() {
                 t if t == end_delim => break,
                 "" if self.tok.0 == TokenKind::Eof => break,
                 ";" => self.next_token()?,
@@ -1009,7 +1009,7 @@ impl<'source> Parser<'source> {
     pub fn parse_rule_assign(&mut self) -> Result<Option<RuleAssign>> {
         let mut span = self.tok.1.clone();
 
-        let op = match *self.token_text() {
+        let op = match self.token_text() {
             "=" => {
                 self.next_token()?;
                 AssignOp::Eq
@@ -1039,14 +1039,14 @@ impl<'source> Parser<'source> {
             let mut span = self.tok.1.clone();
             let sep_pos = span.start;
             span.start = start;
-            match *self.token_text() {
+            match self.token_text() {
                 "." | "[" if self.tok.1.start != self.end => {
                     bail!(
                         "{}",
                         self.source.error(
                             self.tok.1.line,
                             self.tok.1.col - 1,
-                            format!("invalid whitespace before {}", *self.token_text()).as_str()
+                            format!("invalid whitespace before {}", self.token_text()).as_str()
                         )
                     );
                 }
@@ -1139,7 +1139,7 @@ impl<'source> Parser<'source> {
         loop {
             let mut span = self.tok.1.clone();
             span.start = start;
-            match *self.token_text() {
+            match self.token_text() {
                 // . and [ must not have any space between the previous token.
                 "." | "[" if self.tok.1.start != self.end => {
                     bail!(
@@ -1147,7 +1147,7 @@ impl<'source> Parser<'source> {
                         self.source.error(
                             self.tok.1.line,
                             self.tok.1.col - 1,
-                            format!("invalid whitespace before {}", *self.token_text()).as_str()
+                            format!("invalid whitespace before {}", self.token_text()).as_str()
                         )
                     );
                 }
@@ -1196,16 +1196,16 @@ impl<'source> Parser<'source> {
         let mut span = self.tok.1.clone();
 
         let rule_ref = Ref::new(self.parse_rule_ref()?);
-        match *self.token_text() {
+        match self.token_text() {
             "(" => {
                 self.check_rule_ref(&rule_ref)?;
                 self.next_token()?;
                 let mut args = vec![];
-                if *self.token_text() != ")" {
+                if self.token_text() != ")" {
                     args.push(Ref::new(self.parse_term()?));
-                    while *self.token_text() == "," {
+                    while self.token_text() == "," {
                         self.next_token()?;
-                        match *self.token_text() {
+                        match self.token_text() {
                             ")" => break,
                             "" if self.tok.0 == TokenKind::Eof => break,
                             _ => args.push(Ref::new(self.parse_term()?)),
@@ -1246,8 +1246,8 @@ impl<'source> Parser<'source> {
                 }
 
                 // Determine whether to create a set or a compr
-                let is_set_follower = !self.is_keyword(*self.token_text())
-                    && !self.is_imported_future_keyword(*self.token_text());
+                let is_set_follower = !self.is_keyword(self.token_text())
+                    && !self.is_imported_future_keyword(self.token_text());
                 if assign.is_none() && is_set_follower {
                     match rule_ref.as_ref() {
                         Expr::RefBrack { refr, index, .. }
@@ -1288,7 +1288,7 @@ impl<'source> Parser<'source> {
         let state = self.clone();
         let mut span = self.tok.1.clone();
 
-        if *self.token_text() == "{" {
+        if self.token_text() == "{" {
             self.next_token()?;
             let pos = self.end;
             match self.parse_query(span.clone(), "}") {
@@ -1313,7 +1313,7 @@ impl<'source> Parser<'source> {
         let mut bodies = vec![];
 
         let assign = None;
-        let has_query = match *self.token_text() {
+        let has_query = match self.token_text() {
             "if" if self.if_is_keyword() => {
                 self.next_token()?;
                 let query = Ref::new(self.parse_query_or_literal_stmt()?);
@@ -1343,7 +1343,7 @@ impl<'source> Parser<'source> {
             _ => false,
         };
 
-        match *self.token_text() {
+        match self.token_text() {
             "{" if has_query => self.parse_query_blocks(&mut bodies)?,
             "else" if has_query => self.parse_else_blocks(&mut bodies)?,
             _ => (),
@@ -1353,7 +1353,7 @@ impl<'source> Parser<'source> {
     }
 
     pub fn parse_query_blocks(&mut self, bodies: &mut Vec<RuleBody>) -> Result<()> {
-        while *self.token_text() == "{" {
+        while self.token_text() == "{" {
             let mut span = self.tok.1.clone();
             self.next_token()?;
             let query = Ref::new(self.parse_query(span.clone(), "}")?);
@@ -1371,7 +1371,7 @@ impl<'source> Parser<'source> {
         loop {
             let mut span = self.tok.1.clone();
 
-            match *self.token_text() {
+            match self.token_text() {
                 "{" => {
                     return Err(self.source.error(
                         self.tok.1.line,
@@ -1385,7 +1385,7 @@ impl<'source> Parser<'source> {
 
             let assign = self.parse_rule_assign()?;
 
-            match *self.token_text() {
+            match self.token_text() {
                 "if" if self.if_is_keyword() => {
                     self.next_token()?;
                     let query = Ref::new(self.parse_query_or_literal_stmt()?);
@@ -1407,7 +1407,7 @@ impl<'source> Parser<'source> {
                     });
                 }
                 _ if assign.is_none() => {
-                    if *self.token_text() == "if" {
+                    if self.token_text() == "if" {
                         self.warn_future_keyword();
                     }
                     return Err(self.source.error(
@@ -1428,16 +1428,16 @@ impl<'source> Parser<'source> {
         let rule_ref = Ref::new(self.parse_rule_ref()?);
 
         let mut args = vec![];
-        if *self.token_text() == "(" {
+        if self.token_text() == "(" {
             self.next_token()?;
-            if *self.token_text() != ")" {
+            if self.token_text() != ")" {
                 loop {
                     let arg = self.parse_ident()?;
-                    if *arg.text() != "_" && args.iter().any(|a: &Span| *a.text() == *arg.text()) {
+                    if arg.text() != "_" && args.iter().any(|a: &Span| *a.text() == *arg.text()) {
                         bail!(arg.error("repeating parameter name"));
                     }
                     args.push(arg);
-                    if *self.token_text() == ")" || self.tok.0 == TokenKind::Eof {
+                    if self.token_text() == ")" || self.tok.0 == TokenKind::Eof {
                         break;
                     }
                     self.expect(",", "while parsing default rule parameters")?;
@@ -1446,7 +1446,7 @@ impl<'source> Parser<'source> {
             self.expect(")", "while parsing default rule parameters")?;
         }
 
-        let op = match *self.token_text() {
+        let op = match self.token_text() {
             "=" => AssignOp::Eq,
             ":=" => AssignOp::ColEq,
             _ => {
@@ -1498,16 +1498,16 @@ impl<'source> Parser<'source> {
 
     fn check_and_add_import(&self, import: Import, imports: &mut Vec<Import>) -> Result<()> {
         let ref_comps = Self::get_path_ref_components(&import.refr)?;
-        let comps: Vec<std::rc::Rc<&str>> = ref_comps.iter().map(|s| s.text()).collect();
+        let comps: Vec<&str> = ref_comps.iter().map(|s| s.text()).collect();
 
-        if comps.len() >= 2 && comps[0].as_ref() == &"future" && comps[1].as_ref() == &"keywords" {
+        if comps.len() >= 2 && comps[0] == "future" && comps[1] == "keywords" {
             imports.push(import);
             return Ok(());
         }
 
         for imp in imports.iter() {
             let imp_comps = Self::get_path_ref_components(&imp.refr)?;
-            let imp_comps: Vec<std::rc::Rc<&str>> = imp_comps.iter().map(|s| s.text()).collect();
+            let imp_comps: Vec<&str> = imp_comps.iter().map(|s| s.text()).collect();
 
             let shadow = match (&imp.r#as, &import.r#as) {
                 (Some(i1), Some(i2)) if i1.text() == i2.text() => true,
@@ -1539,13 +1539,13 @@ impl<'source> Parser<'source> {
 
     fn parse_imports(&mut self) -> Result<Vec<Import>> {
         let mut imports = vec![];
-        while *self.token_text() == "import" {
+        while self.token_text() == "import" {
             let mut span = self.tok.1.clone();
             self.next_token()?;
             let refr = Ref::new(self.parse_path_ref()?);
 
             let comps = Self::get_path_ref_components(&refr)?;
-            if !matches!(*comps[0].text(), "data" | "future" | "input") {
+            if !matches!(comps[0].text(), "data" | "future" | "input") {
                 return Err(self.source.error(
                     comps[0].line,
                     comps[0].col,
@@ -1555,7 +1555,7 @@ impl<'source> Parser<'source> {
 
             let is_future_kw = self.handle_import_future_keywords(&comps)?;
 
-            let var = if *self.token_text() == "as" {
+            let var = if self.token_text() == "as" {
                 if is_future_kw {
                     return Err(self.source.error(
                         self.tok.1.line,
@@ -1566,7 +1566,7 @@ impl<'source> Parser<'source> {
 
                 self.next_token()?;
                 let var = self.parse_var()?;
-                if *var.text() == "_" {
+                if var.text() == "_" {
                     return Err(self.source.error(
                         var.line,
                         var.col,
diff --git a/src/scheduler.rs b/src/scheduler.rs
index 6579a692..762d46c8 100644
--- a/src/scheduler.rs
+++ b/src/scheduler.rs
@@ -298,7 +298,7 @@ fn gather_assigned_vars(
 ) -> Result<()> {
     traverse(expr, &mut |e| match e.as_ref() {
         // Ignore _, input, data.
-        Var(v) if matches!(*v.text(), "_" | "input" | "data") => Ok(false),
+        Var(v) if matches!(v.text(), "_" | "input" | "data") => Ok(false),
 
         // Record local var that can shadow input var.
         Var(v) if can_shadow => {
@@ -623,7 +623,7 @@ impl Analyzer {
         let mut used_vars = vec![];
         let mut comprs = vec![];
         traverse(expr, &mut |e| match e.as_ref() {
-            Var(v) if !matches!(*v.text(), "_" | "input" | "data") => {
+            Var(v) if !matches!(v.text(), "_" | "input" | "data") => {
                 let name = v.source_str();
                 let is_extra_arg = match assigned_vars {
                     Some(vars) => vars.contains(&v.source_str()),
diff --git a/src/utils.rs b/src/utils.rs
index b2fa956e..4670fde1 100644
--- a/src/utils.rs
+++ b/src/utils.rs
@@ -86,17 +86,17 @@ pub fn get_path_string(refr: &Expr, document: Option<&str>) -> Result<String> {
     while expr.is_some() {
         match expr {
             Some(Expr::RefDot { refr, field, .. }) => {
-                comps.push(&field.text());
+                comps.push(field.text());
                 expr = Some(refr);
             }
             Some(Expr::RefBrack { refr, index, .. }) => {
                 if let Expr::String(s) = index.as_ref() {
-                    comps.push(&s.text());
+                    comps.push(s.text());
                 }
                 expr = Some(refr);
             }
             Some(Expr::Var(v)) => {
-                comps.push(&v.text());
+                comps.push(v.text());
                 expr = None;
             }
             _ => bail!("internal error: not a simple ref {expr:?}"),


Test patch:
diff --git a/tests/interpreter/cases/data/tests.yaml b/tests/interpreter/cases/data/tests.yaml
index e8e5614c..5beb9d5e 100644
--- a/tests/interpreter/cases/data/tests.yaml
+++ b/tests/interpreter/cases/data/tests.yaml
@@ -37,7 +37,7 @@ cases:
         - 100
         - 200
         
-  - note: overriding refs in data produces error
+  - note: overriding refs in data produces no error
     data:
       test:
         rule1: 0
@@ -46,8 +46,8 @@ cases:
         package test
 
         rule1 = 6
-    query: data.test
-    error: value for rule has already been specified
+    query: data.test.rule1
+    want_result: 0
       
   - note: rule named data
     data:
diff --git a/tests/opa.passing b/tests/opa.passing
index f4662dd8..56116b95 100644
--- a/tests/opa.passing
+++ b/tests/opa.passing
@@ -50,6 +50,9 @@ intersection
 invalidkeyerror
 jsonfilter
 jsonfilteridempotent
+jsonremove
+jsonremoveidempotent
+jsonschema
 jwtencodesignheadererrors
 jwtencodesignpayloaderrors
 negation
@@ -96,5 +99,6 @@ typenamebuiltin
 undos
 union
 units
+uuid
 varreferences
 virtualdocs
\ No newline at end of file
diff --git a/tests/opa.rs b/tests/opa.rs
index 97e0f9c6..491c03fe 100644
--- a/tests/opa.rs
+++ b/tests/opa.rs
@@ -169,7 +169,8 @@ fn run_opa_tests(opa_tests_dir: String, folders: &[String]) -> Result<()> {
                 {
                     entry.0 += 1;
                 }
-                (Err(_), None) if case.want_error.is_some() => {
+                // TODO: Handle tests that specify both want_result and strict_error
+                (Err(_), _) if case.want_error.is_some() => {
                     // Expected failure.
                     entry.0 += 1;
                 }
diff --git a/tests/parser/mod.rs b/tests/parser/mod.rs
index 9344af87..7ffea6fd 100644
--- a/tests/parser/mod.rs
+++ b/tests/parser/mod.rs
@@ -27,7 +27,7 @@ fn match_span(s: &Span, v: &Value) -> Result<()> {
     match &v {
         Value::String(vs) => {
             my_assert_eq!(
-                *s.text(),
+                s.text(),
                 vs.as_ref(),
                 "{}",
                 s.source