Use Ref for storing ast nodes in collections. (#37)

cmp, eq is done as pointer comparison which makes retrieval super fast.

Signed-off-by: Anand Krishnamoorthi <anakrish@microsoft.com>
This commit is contained in:
Anand Krishnamoorthi
2023-11-05 22:32:00 -08:00
committed by GitHub
parent d3fd0a3a78
commit a751cd69e1
7 changed files with 137 additions and 116 deletions

View File

@@ -24,3 +24,7 @@ walkdir = "2.3.2"
[build-dependencies]
anyhow = "1.0.66"
[profile.release]
debug = true

View File

@@ -3,13 +3,13 @@
use crate::lexer::*;
#[derive(Debug, PartialEq, Eq, PartialOrd, Ord, Clone)]
#[derive(Debug, PartialEq, Eq, Clone)]
pub enum BinOp {
And,
Or,
}
#[derive(Debug, PartialEq, Eq, PartialOrd, Ord, Clone)]
#[derive(Debug, PartialEq, Eq, Clone)]
pub enum ArithOp {
Add,
Sub,
@@ -18,7 +18,7 @@ pub enum ArithOp {
Mod,
}
#[derive(Debug, PartialEq, Eq, PartialOrd, Ord, Clone)]
#[derive(Debug, PartialEq, Eq, Clone)]
pub enum BoolOp {
Lt,
Le,
@@ -28,13 +28,13 @@ pub enum BoolOp {
Ne,
}
#[derive(Debug, PartialEq, Eq, PartialOrd, Ord, Clone)]
#[derive(Debug, PartialEq, Eq, Clone)]
pub enum AssignOp {
Eq,
ColEq,
}
#[derive(Debug, PartialEq, Eq, PartialOrd, Ord, Clone)]
#[derive(Debug, Clone)]
pub enum Expr<'source> {
// Simple items that only have a span as content.
String(Span<'source>),
@@ -166,7 +166,7 @@ impl<'source> Expr<'source> {
}
}
#[derive(Debug, PartialEq, Eq, PartialOrd, Ord, Clone)]
#[derive(Debug, Clone)]
pub enum Literal<'source> {
SomeVars {
span: Span<'source>,
@@ -195,41 +195,41 @@ pub enum Literal<'source> {
},
}
#[derive(Debug, PartialEq, Eq, PartialOrd, Ord, Clone)]
#[derive(Debug, Clone)]
pub struct WithModifier<'source> {
pub span: Span<'source>,
pub refr: Expr<'source>,
pub r#as: Expr<'source>,
}
#[derive(Debug, PartialEq, Eq, PartialOrd, Ord, Clone)]
#[derive(Debug, Clone)]
pub struct LiteralStmt<'source> {
pub span: Span<'source>,
pub literal: Literal<'source>,
pub with_mods: Vec<WithModifier<'source>>,
}
#[derive(Debug, PartialEq, Eq, PartialOrd, Ord, Clone)]
#[derive(Debug, Clone)]
pub struct Query<'source> {
pub span: Span<'source>,
pub stmts: Vec<LiteralStmt<'source>>,
}
#[derive(Debug, PartialEq, Eq, PartialOrd, Ord, Clone)]
#[derive(Debug, Clone)]
pub struct RuleAssign<'source> {
pub span: Span<'source>,
pub op: AssignOp,
pub value: Expr<'source>,
}
#[derive(Debug, PartialEq, Eq, PartialOrd, Ord, Clone)]
#[derive(Debug, Clone)]
pub struct RuleBody<'source> {
pub span: Span<'source>,
pub assign: Option<RuleAssign<'source>>,
pub query: Query<'source>,
}
#[derive(Debug, PartialEq, Eq, PartialOrd, Ord, Clone)]
#[derive(Debug, Clone)]
pub enum RuleHead<'source> {
Compr {
span: Span<'source>,
@@ -249,7 +249,7 @@ pub enum RuleHead<'source> {
},
}
#[derive(Debug, PartialEq, Eq, PartialOrd, Ord, Clone)]
#[derive(Debug, Clone)]
pub enum Rule<'source> {
Spec {
span: Span<'source>,
@@ -264,22 +264,58 @@ pub enum Rule<'source> {
},
}
#[derive(Debug, PartialEq, Eq, PartialOrd, Ord, Clone)]
#[derive(Debug, Clone)]
pub struct Package<'source> {
pub span: Span<'source>,
pub refr: Expr<'source>,
}
#[derive(Debug, PartialEq, Eq, PartialOrd, Ord, Clone)]
#[derive(Debug, Clone)]
pub struct Import<'source> {
pub span: Span<'source>,
pub refr: Expr<'source>,
pub r#as: Option<Span<'source>>,
}
#[derive(Debug, PartialEq, Eq, PartialOrd, Ord, Clone)]
#[derive(Debug, Clone)]
pub struct Module<'source> {
pub package: Package<'source>,
pub imports: Vec<Import<'source>>,
pub policy: Vec<Rule<'source>>,
}
#[derive(Debug, Clone)]
pub struct Ref<'a, T> {
r: &'a T,
}
impl<'a, T> Ref<'a, T> {
pub fn make(r: &'a T) -> Self {
Self { r }
}
pub fn inner(&self) -> &'a T {
self.r
}
}
impl<'a, T> Eq for Ref<'a, T> {}
impl<'a, T> PartialEq for Ref<'a, T> {
fn eq(&self, other: &Self) -> bool {
std::ptr::eq(self.r, other.r)
}
}
impl<'a, T> PartialOrd for Ref<'a, T> {
fn partial_cmp(&self, other: &Self) -> Option<std::cmp::Ordering> {
Some(self.cmp(other))
}
}
impl<'a, T> Ord for Ref<'a, T> {
fn cmp(&self, other: &Self) -> std::cmp::Ordering {
//std::ptr::from_ref(self.r).partial_cmp(std::ptr::from_ref(other.r))
(self.r as *const T).cmp(&(other.r as *const T))
}
}

View File

@@ -29,12 +29,12 @@ pub struct Interpreter<'source> {
with_document: Value,
scopes: Vec<Scope>,
// TODO: handle recursive calls where same expr could have different values.
loop_var_values: BTreeMap<&'source Expr<'source>, Value>,
loop_var_values: BTreeMap<Ref<'source, Expr<'source>>, Value>,
contexts: Vec<Context<'source>>,
functions: FunctionTable<'source>,
rules: HashMap<String, Vec<&'source Rule<'source>>>,
default_rules: HashMap<String, Vec<(&'source Rule<'source>, Option<String>)>>,
processed: BTreeSet<&'source Rule<'source>>,
processed: BTreeSet<Ref<'source, Rule<'source>>>,
active_rules: Vec<&'source Rule<'source>>,
builtins_cache: BTreeMap<(&'static str, Vec<Value>), Value>,
no_rules_lookup: bool,
@@ -205,7 +205,7 @@ impl<'source> Interpreter<'source> {
// Collect a chaing of '.field' or '["field"]'
let mut path = vec![];
loop {
if let Some(v) = self.loop_var_values.get(expr) {
if let Some(v) = self.loop_var_values.get(&Ref::make(expr)) {
path.reverse();
return Ok(Self::get_value_chained(v.clone(), &path[..]));
}
@@ -444,7 +444,7 @@ impl<'source> Interpreter<'source> {
// TODO: Check this
// Allow variable overwritten inside a loop
if !matches!(var, Value::Undefined)
&& self.loop_var_values.get(rhs).is_none()
&& self.loop_var_values.get(&Ref::make(rhs)).is_none()
{
return self.eval_bool_expr(&BoolOp::Eq, lhs, rhs);
}
@@ -457,7 +457,7 @@ impl<'source> Interpreter<'source> {
// TODO: Check this
// Allow variable overwritten inside a loop
if !matches!(var, Value::Undefined)
&& self.loop_var_values.get(lhs).is_none()
&& self.loop_var_values.get(&Ref::make(lhs)).is_none()
{
return self.eval_bool_expr(&BoolOp::Eq, lhs, rhs);
}
@@ -477,7 +477,8 @@ impl<'source> Interpreter<'source> {
// TODO: Check this
// Allow variable overwritten inside a loop
if self.lookup_local_var(name).is_some() && self.loop_var_values.get(rhs).is_none()
if self.lookup_local_var(name).is_some()
&& self.loop_var_values.get(&Ref::make(rhs)).is_none()
{
bail!(rhs
.span()
@@ -573,14 +574,14 @@ impl<'source> Interpreter<'source> {
fn lookup_or_eval_expr(
&mut self,
cache: &mut BTreeMap<&'source Expr<'source>, Value>,
cache: &mut BTreeMap<Ref<'source, Expr<'source>>, Value>,
expr: &'source Expr<'source>,
) -> Result<Value> {
match cache.get(expr) {
match cache.get(&Ref::make(expr)) {
Some(v) => Ok(v.clone()),
_ => {
let v = self.eval_expr(expr)?;
cache.insert(expr, v.clone());
cache.insert(Ref::make(expr), v.clone());
Ok(v)
}
}
@@ -589,8 +590,8 @@ impl<'source> Interpreter<'source> {
fn make_bindings_impl(
&mut self,
is_last: bool,
type_match: &mut BTreeSet<&'source Expr<'source>>,
cache: &mut BTreeMap<&'source Expr<'source>, Value>,
type_match: &mut BTreeSet<Ref<'source, Expr<'source>>>,
cache: &mut BTreeMap<Ref<'source, Expr<'source>>, Value>,
expr: &'source Expr<'source>,
value: &Value,
) -> Result<bool> {
@@ -599,7 +600,7 @@ impl<'source> Interpreter<'source> {
return Ok(false);
}
let span = expr.span();
let raise_error = is_last && type_match.get(expr).is_none();
let raise_error = is_last && type_match.get(&Ref::make(expr)).is_none();
match (expr, value) {
(Expr::Var(ident), _) => {
@@ -622,7 +623,7 @@ impl<'source> Interpreter<'source> {
}
return Ok(false);
}
type_match.insert(expr);
type_match.insert(Ref::make(expr));
let mut r = false;
for (idx, item) in items.iter().enumerate() {
@@ -658,7 +659,7 @@ impl<'source> Interpreter<'source> {
field_value,
)?;
}
type_match.insert(expr);
type_match.insert(Ref::make(expr));
Ok(r)
}
@@ -677,7 +678,7 @@ impl<'source> Interpreter<'source> {
format!("Cannot bind pattern of type `{expr_t}` with value of type `{value_t}`. Value is {value}.").as_str()));
}
}
type_match.insert(expr);
type_match.insert(Ref::make(expr));
Ok(&expr_value == value)
}
@@ -687,8 +688,8 @@ impl<'source> Interpreter<'source> {
fn make_bindings(
&mut self,
is_last: bool,
type_match: &mut BTreeSet<&'source Expr<'source>>,
cache: &mut BTreeMap<&'source Expr<'source>, Value>,
type_match: &mut BTreeSet<Ref<'source, Expr<'source>>>,
cache: &mut BTreeMap<Ref<'source, Expr<'source>>, Value>,
expr: &'source Expr<'source>,
value: &Value,
) -> Result<bool> {
@@ -702,8 +703,8 @@ impl<'source> Interpreter<'source> {
fn make_key_value_bindings(
&mut self,
is_last: bool,
type_match: &mut BTreeSet<&'source Expr<'source>>,
cache: &mut BTreeMap<&'source Expr<'source>, Value>,
type_match: &mut BTreeSet<Ref<'source, Expr<'source>>>,
cache: &mut BTreeMap<Ref<'source, Expr<'source>>, Value>,
exprs: (&'source Option<Expr<'source>>, &'source Expr<'source>),
values: (&Value, &Value),
) -> Result<bool> {
@@ -1027,11 +1028,12 @@ impl<'source> Interpreter<'source> {
match loop_expr_value {
Value::Array(items) => {
for (idx, v) in items.iter().enumerate() {
self.loop_var_values.insert(loop_expr.expr, v.clone());
self.loop_var_values
.insert(Ref::make(loop_expr.expr), v.clone());
self.add_variable(loop_expr.index, Value::from_float(idx as Float))?;
result = self.eval_stmts_in_loop(stmts, &loops[1..])? || result;
self.loop_var_values.remove(loop_expr.expr);
self.loop_var_values.remove(&Ref::make(loop_expr.expr));
*self.current_scope_mut()? = scope_saved.clone();
if let Some(ctx) = self.contexts.last_mut() {
ctx.result = query_result.clone();
@@ -1040,11 +1042,12 @@ impl<'source> Interpreter<'source> {
}
Value::Set(items) => {
for v in items.iter() {
self.loop_var_values.insert(loop_expr.expr, v.clone());
self.loop_var_values
.insert(Ref::make(loop_expr.expr), v.clone());
// For sets, index is also the value.
self.add_variable(loop_expr.index, v.clone())?;
result = self.eval_stmts_in_loop(stmts, &loops[1..])? || result;
self.loop_var_values.remove(loop_expr.expr);
self.loop_var_values.remove(&Ref::make(loop_expr.expr));
*self.current_scope_mut()? = scope_saved.clone();
if let Some(ctx) = self.contexts.last_mut() {
ctx.result = query_result.clone();
@@ -1053,17 +1056,21 @@ impl<'source> Interpreter<'source> {
}
Value::Object(obj) => {
for (k, v) in obj.iter() {
self.loop_var_values.insert(loop_expr.expr, v.clone());
self.loop_var_values
.insert(Ref::make(loop_expr.expr), v.clone());
// For objects, index is key.
self.add_variable(loop_expr.index, k.clone())?;
result = self.eval_stmts_in_loop(stmts, &loops[1..])? || result;
self.loop_var_values.remove(loop_expr.expr);
self.loop_var_values.remove(&Ref::make(loop_expr.expr));
*self.current_scope_mut()? = scope_saved.clone();
if let Some(ctx) = self.contexts.last_mut() {
ctx.result = query_result.clone();
}
}
}
Value::Undefined => {
result = false;
}
_ => {
return Err(loop_expr.span.source.error(
loop_expr.span.line,
@@ -1163,19 +1170,22 @@ impl<'source> Interpreter<'source> {
match self.eval_expr(loop_expr.value)? {
Value::Array(items) => {
for v in items.iter() {
self.loop_var_values.insert(loop_expr.expr, v.clone());
self.loop_var_values
.insert(Ref::make(loop_expr.expr), v.clone());
result = self.eval_output_expr_in_loop(&loops[1..])? || result;
}
}
Value::Set(items) => {
for v in items.iter() {
self.loop_var_values.insert(loop_expr.expr, v.clone());
self.loop_var_values
.insert(Ref::make(loop_expr.expr), v.clone());
result = self.eval_output_expr_in_loop(&loops[1..])? || result;
}
}
Value::Object(obj) => {
for (_, v) in obj.iter() {
self.loop_var_values.insert(loop_expr.expr, v.clone());
self.loop_var_values
.insert(Ref::make(loop_expr.expr), v.clone());
result = self.eval_output_expr_in_loop(&loops[1..])? || result;
}
}
@@ -1187,7 +1197,7 @@ impl<'source> Interpreter<'source> {
));
}
}
self.loop_var_values.remove(loop_expr.expr);
self.loop_var_values.remove(&Ref::make(loop_expr.expr));
Ok(result)
}
@@ -1265,7 +1275,7 @@ impl<'source> Interpreter<'source> {
self.scopes.push(Scope::new());
let ordered_stmts: Vec<&'source LiteralStmt<'source>> =
if let Some(schedule) = &self.schedule {
match schedule.order.get(query) {
match schedule.order.get(&Ref::make(query)) {
Some(ord) => ord.iter().map(|i| &query.stmts[*i as usize]).collect(),
// TODO
_ => bail!(query
@@ -1550,7 +1560,8 @@ impl<'source> Interpreter<'source> {
for (idx, a) in args.iter().enumerate() {
let a = match a {
Expr::Var(s) => s.text(),
_ => unimplemented!("destructuring function arguments"),
_ => continue,
// _ => unimplemented!("destructuring function arguments"),
};
//TODO: check call in params
args_scope.insert(a.to_string(), self.eval_expr(&params[idx])?);
@@ -1665,7 +1676,7 @@ impl<'source> Interpreter<'source> {
fn ensure_rule_evaluated(&mut self, path: String) -> Result<()> {
if let Some(rules) = self.rules.get(&path) {
for r in rules.clone() {
if !self.processed.contains(r) {
if !self.processed.contains(&Ref::make(r)) {
let module = self.get_rule_module(r)?;
self.eval_rule(module, r)?;
}
@@ -1674,7 +1685,7 @@ impl<'source> Interpreter<'source> {
// Evaluate the associated default rules after non-default rules
if let Some(rules) = self.default_rules.get(&path) {
for (r, _) in rules.clone() {
if !self.processed.contains(r) {
if !self.processed.contains(&Ref::make(r)) {
let module = self.get_rule_module(r)?;
let prev_module = self.set_current_module(Some(module))?;
self.eval_default_rule(r)?;
@@ -1852,7 +1863,7 @@ impl<'source> Interpreter<'source> {
fn get_rule_module(&self, rule: &'source Rule<'source>) -> Result<&'source Module<'source>> {
for m in &self.modules {
if m.policy.contains(rule) {
if m.policy.iter().any(|r| Ref::make(r) == Ref::make(rule)) {
return Ok(m);
}
}
@@ -2013,46 +2024,6 @@ impl<'source> Interpreter<'source> {
Ok(m)
}
/* pub fn update_function_table(&mut self) -> Result<()> {
for module in self.modules.clone() {
let prev_module = self.set_current_module(Some(module))?;
let module_path =
Self::get_path_string(&self.current_module()?.package.refr, Some("data"))?;
for rule in &module.policy {
if let Rule::Spec {
head: RuleHead::Func { refr, .. },
..
} = rule
{
let mut path =
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();
if path.len() > 1 {
let value =
Self::make_or_get_value_mut(&mut self.data, &path[0..path.len() - 1])?;
if value == &Value::Undefined {
*value = Value::new_object();
}
}
let full_path = Self::get_path_string(refr, Some(module_path.as_str()))?;
if let Some(functions) = self.functions.get_mut(&full_path) {
// TODO: check function arity.
functions.push(rule);
} else {
self.functions.insert(full_path, vec![rule]);
}
}
}
self.set_current_module(prev_module)?;
}
Ok(())
}*/
fn get_rule_refr(rule: &'source Rule<'source>) -> &'source Expr<'source> {
match rule {
Rule::Spec { head, .. } => match &head {
@@ -2122,7 +2093,7 @@ impl<'source> Interpreter<'source> {
fn eval_default_rule(&mut self, rule: &'source Rule<'source>) -> Result<()> {
// Skip reprocessing rule.
if self.processed.contains(rule) {
if self.processed.contains(&Ref::make(rule)) {
return Ok(());
}
@@ -2172,7 +2143,7 @@ impl<'source> Interpreter<'source> {
}
};
self.processed.insert(rule);
self.processed.insert(Ref::make(rule));
}
Ok(())
@@ -2184,7 +2155,7 @@ impl<'source> Interpreter<'source> {
rule: &'source Rule<'source>,
) -> Result<()> {
// Skip reprocessing rule
if self.processed.contains(rule) {
if self.processed.contains(&Ref::make(rule)) {
return Ok(());
}
@@ -2194,7 +2165,13 @@ impl<'source> Interpreter<'source> {
}
self.active_rules.push(rule);
if self.active_rules.iter().filter(|&r| r == &rule).count() == 2 {
if self
.active_rules
.iter()
.filter(|&r| Ref::make(*r) == Ref::make(rule))
.count()
== 2
{
let mut msg = String::default();
for r in &self.active_rules {
let refr = Self::get_rule_refr(r);
@@ -2215,6 +2192,7 @@ impl<'source> Interpreter<'source> {
}
let prev_module = self.set_current_module(Some(module))?;
match rule {
Rule::Spec {
span,
@@ -2241,7 +2219,7 @@ impl<'source> Interpreter<'source> {
Self::merge_value(span, vref, value)?;
}
self.processed.insert(rule);
self.processed.insert(Ref::make(rule));
} else if let RuleHead::Func { refr, .. } = rule_head {
let mut path =
Parser::get_path_ref_components(&self.current_module()?.package.refr)?;
@@ -2264,7 +2242,7 @@ impl<'source> Interpreter<'source> {
}
self.set_current_module(prev_module)?;
match self.active_rules.pop() {
Some(r) if r == rule => Ok(()),
Some(r) if Ref::make(r) == Ref::make(rule) => Ok(()),
_ => bail!("internal error: current rule not active"),
}
}
@@ -2349,7 +2327,6 @@ impl<'source> Interpreter<'source> {
self.eval_rule(module, rule)?;
}
}
// Defer the evaluation of the default rules to here
for module in self.modules.clone() {
let prev_module = self.set_current_module(Some(module))?;
@@ -2387,7 +2364,7 @@ impl<'source> Interpreter<'source> {
// Add schedules for queries.
if let Some(self_schedule) = &mut self.schedule {
for (k, v) in schedule.order.iter() {
self_schedule.order.insert(k, v.clone());
self_schedule.order.insert(k.clone(), v.clone());
}
}
@@ -2414,7 +2391,7 @@ impl<'source> Interpreter<'source> {
// Restore schedules.
if let Some(self_schedule) = &mut self.schedule {
for (k, ord) in schedule.order.iter() {
if k == &query {
if k == &Ref::make(query) {
for idx in 0..results.result.len() {
let mut ordered_expressions = vec![Value::Undefined; ord.len()];
for (expr_idx, value) in results.result[idx].expressions.iter().enumerate()

View File

@@ -8,7 +8,7 @@ use core::str::CharIndices;
use crate::value::Value;
use anyhow::{anyhow, bail, Result};
#[derive(PartialEq, Eq, PartialOrd, Ord, Clone)]
#[derive(Clone)]
pub struct Source<'source> {
pub file: &'source str,
pub contents: &'source str,
@@ -48,7 +48,7 @@ impl<'source> Source<'source> {
}
}
#[derive(PartialEq, Eq, PartialOrd, Ord, Clone)]
#[derive(Clone)]
pub struct Span<'source> {
pub source: &'source Source<'source>,
pub line: u16,
@@ -98,7 +98,7 @@ pub enum TokenKind {
Eof,
}
#[derive(Debug, PartialEq, Eq, Clone)]
#[derive(Debug, Clone)]
pub struct Token<'source>(pub TokenKind, pub Span<'source>);
#[derive(Clone)]

View File

@@ -377,16 +377,16 @@ fn get_rule_prefix<'a>(expr: &Expr<'a>) -> Result<&'a str> {
pub struct Analyzer<'a> {
packages: BTreeMap<String, Scope<'a>>,
locals: BTreeMap<&'a Query<'a>, Scope<'a>>,
locals: BTreeMap<Ref<'a, Query<'a>>, Scope<'a>>,
scopes: Vec<Scope<'a>>,
order: BTreeMap<&'a Query<'a>, Vec<u16>>,
order: BTreeMap<Ref<'a, Query<'a>>, Vec<u16>>,
functions: FunctionTable<'a>,
}
#[derive(Clone)]
pub struct Schedule<'a> {
pub scopes: BTreeMap<&'a Query<'a>, Scope<'a>>,
pub order: BTreeMap<&'a Query<'a>, Vec<u16>>,
pub scopes: BTreeMap<Ref<'a, Query<'a>>, Scope<'a>>,
pub order: BTreeMap<Ref<'a, Query<'a>>, Vec<u16>>,
}
impl<'a> Default for Analyzer<'a> {
@@ -535,11 +535,8 @@ impl<'a> Analyzer<'a> {
RuleHead::Set { key, .. } => (key.as_ref(), None, scope),
RuleHead::Func { args, assign, .. } => {
for a in args.iter() {
match a {
Var(v) => {
scope.locals.insert(v.text());
}
_ => unimplemented!("non var arguments"),
if let Var(v) = a {
scope.locals.insert(v.text());
}
}
(None, assign.as_ref().map(|a| &a.value), scope)
@@ -672,7 +669,7 @@ impl<'a> Analyzer<'a> {
let compr_scope = match compr {
Expr::ArrayCompr { query, term, .. } | Expr::SetCompr { query, term, .. } => {
self.analyze_query(None, Some(term), query, Scope::default())?;
self.locals.get(query)
self.locals.get(&Ref::make(query))
}
Expr::ObjectCompr {
query, key, value, ..
@@ -683,7 +680,7 @@ impl<'a> Analyzer<'a> {
query,
Scope::default(),
)?;
self.locals.get(query)
self.locals.get(&Ref::make(query))
}
_ => break,
};
@@ -1041,14 +1038,14 @@ impl<'a> Analyzer<'a> {
let res = schedule(&mut infos[..]);
match res {
Ok(SortResult::Order(ord)) => {
self.order.insert(query, ord);
self.order.insert(Ref::make(query), ord);
}
Err(err) => {
bail!(query.span.error(&err.to_string()))
}
_ => (),
}
self.locals.insert(query, scope);
self.locals.insert(Ref::make(query), scope);
Ok(())
}

View File

@@ -558,6 +558,7 @@ fn run_opa_tests() -> Result<()> {
if !Path::new(&a).is_dir() {
continue;
}
for entry in WalkDir::new(a)
.sort_by_file_name()
.into_iter()

View File

@@ -56,7 +56,13 @@ fn analyze_file(regos: &[String], expected_scopes: &[Scope]) -> Result<()> {
let analyzer = Analyzer::new();
let schedule = analyzer.analyze(&modules_ref)?;
for (idx, (_, scope)) in schedule.scopes.iter().enumerate() {
let mut scopes: Vec<(&Query, &regorus::Scope)> = schedule
.scopes
.iter()
.map(|(r, s)| (r.inner(), s))
.collect();
scopes.sort_by(|a, b| a.0.span.line.cmp(&b.0.span.line));
for (idx, (_, scope)) in scopes.iter().enumerate() {
if idx > expected_scopes.len() {
bail!("extra scope generated.")
}