Avoid dependency on `source lifetime. (#43)

This allows holding onto objects, caching results etc easily.
However it does introduce the overhead of ref counting.

Signed-off-by: Anand Krishnamoorthi <anakrish@microsoft.com>
This commit is contained in:
Anand Krishnamoorthi
2023-11-15 09:25:12 -08:00
committed by GitHub
parent a1d0f8576a
commit 72070a7061
29 changed files with 890 additions and 803 deletions

3
.gitignore vendored
View File

@@ -8,3 +8,6 @@ Cargo.lock
# These are backup files generated by rustfmt
**/*.rs.bk
# vscode files
.vscode/

View File

@@ -3,6 +3,8 @@
use crate::lexer::*;
use std::ops::Deref;
#[derive(Debug, PartialEq, Eq, Clone)]
pub enum BinOp {
And,
@@ -34,7 +36,67 @@ pub enum AssignOp {
ColEq,
}
#[derive(Debug, Clone)]
pub struct NodeRef<T> {
r: std::rc::Rc<T>,
}
impl<T> Clone for NodeRef<T> {
fn clone(&self) -> Self {
Self { r: self.r.clone() }
}
}
impl<T: std::fmt::Debug> std::fmt::Debug for NodeRef<T> {
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
self.r.as_ref().fmt(f)
}
}
impl<T> std::cmp::PartialEq for NodeRef<T> {
fn eq(&self, other: &Self) -> bool {
std::rc::Rc::as_ptr(&self.r).eq(&std::rc::Rc::as_ptr(&other.r))
}
}
impl<T> std::cmp::Eq for NodeRef<T> {}
impl<T> std::cmp::Ord for NodeRef<T> {
fn cmp(&self, other: &Self) -> std::cmp::Ordering {
std::rc::Rc::as_ptr(&self.r).cmp(&std::rc::Rc::as_ptr(&other.r))
}
}
impl<T> std::cmp::PartialOrd for NodeRef<T> {
fn partial_cmp(&self, other: &Self) -> Option<std::cmp::Ordering> {
Some(self.cmp(other))
}
}
impl<T> Deref for NodeRef<T> {
type Target = T;
fn deref(&self) -> &Self::Target {
&self.r
}
}
impl<T> AsRef<T> for NodeRef<T> {
fn as_ref(&self) -> &T {
self.deref()
}
}
impl<T> NodeRef<T> {
pub fn new(t: T) -> Self {
Self {
r: std::rc::Rc::new(t),
}
}
}
pub type Ref<T> = NodeRef<T>;
#[derive(Debug)]
pub enum Expr {
// Simple items that only have a span as content.
String(Span),
@@ -48,97 +110,97 @@ pub enum Expr {
// array
Array {
span: Span,
items: Vec<Expr>,
items: Vec<Ref<Expr>>,
},
// set
Set {
span: Span,
items: Vec<Expr>,
items: Vec<Ref<Expr>>,
},
Object {
span: Span,
fields: Vec<(Span, Expr, Expr)>,
fields: Vec<(Span, Ref<Expr>, Ref<Expr>)>,
},
// Comprehensions
ArrayCompr {
span: Span,
term: Box<Expr>,
query: Query,
term: Ref<Expr>,
query: Ref<Query>,
},
SetCompr {
span: Span,
term: Box<Expr>,
query: Query,
term: Ref<Expr>,
query: Ref<Query>,
},
ObjectCompr {
span: Span,
key: Box<Expr>,
value: Box<Expr>,
query: Query,
key: Ref<Expr>,
value: Ref<Expr>,
query: Ref<Query>,
},
Call {
span: Span,
fcn: Box<Expr>,
params: Vec<Expr>,
fcn: Ref<Expr>,
params: Vec<Ref<Expr>>,
},
UnaryExpr {
span: Span,
expr: Box<Expr>,
expr: Ref<Expr>,
},
// ref
RefDot {
span: Span,
refr: Box<Expr>,
refr: Ref<Expr>,
field: Span,
},
RefBrack {
span: Span,
refr: Box<Expr>,
index: Box<Expr>,
refr: Ref<Expr>,
index: Ref<Expr>,
},
// Infix expressions
BinExpr {
span: Span,
op: BinOp,
lhs: Box<Expr>,
rhs: Box<Expr>,
lhs: Ref<Expr>,
rhs: Ref<Expr>,
},
BoolExpr {
span: Span,
op: BoolOp,
lhs: Box<Expr>,
rhs: Box<Expr>,
lhs: Ref<Expr>,
rhs: Ref<Expr>,
},
ArithExpr {
span: Span,
op: ArithOp,
lhs: Box<Expr>,
rhs: Box<Expr>,
lhs: Ref<Expr>,
rhs: Ref<Expr>,
},
AssignExpr {
span: Span,
op: AssignOp,
lhs: Box<Expr>,
rhs: Box<Expr>,
lhs: Ref<Expr>,
rhs: Ref<Expr>,
},
Membership {
span: Span,
key: Box<Option<Expr>>,
value: Box<Expr>,
collection: Box<Expr>,
key: Option<Ref<Expr>>,
value: Ref<Expr>,
collection: Ref<Expr>,
},
}
@@ -166,7 +228,7 @@ impl Expr {
}
}
#[derive(Debug, Clone)]
#[derive(Debug)]
pub enum Literal {
SomeVars {
span: Span,
@@ -174,82 +236,82 @@ pub enum Literal {
},
SomeIn {
span: Span,
key: Option<Expr>,
value: Expr,
collection: Expr,
key: Option<Ref<Expr>>,
value: Ref<Expr>,
collection: Ref<Expr>,
},
Expr {
span: Span,
expr: Expr,
expr: Ref<Expr>,
},
NotExpr {
span: Span,
expr: Expr,
expr: Ref<Expr>,
},
Every {
span: Span,
key: Option<Span>,
value: Span,
domain: Expr,
query: Query,
domain: Ref<Expr>,
query: Ref<Query>,
},
}
#[derive(Debug, Clone)]
#[derive(Debug)]
pub struct WithModifier {
pub span: Span,
pub refr: Expr,
pub r#as: Expr,
pub refr: Ref<Expr>,
pub r#as: Ref<Expr>,
}
#[derive(Debug, Clone)]
#[derive(Debug)]
pub struct LiteralStmt {
pub span: Span,
pub literal: Literal,
pub with_mods: Vec<WithModifier>,
}
#[derive(Debug, Clone)]
#[derive(Debug)]
pub struct Query {
pub span: Span,
pub stmts: Vec<LiteralStmt>,
}
#[derive(Debug, Clone)]
#[derive(Debug)]
pub struct RuleAssign {
pub span: Span,
pub op: AssignOp,
pub value: Expr,
pub value: Ref<Expr>,
}
#[derive(Debug, Clone)]
#[derive(Debug)]
pub struct RuleBody {
pub span: Span,
pub assign: Option<RuleAssign>,
pub query: Query,
pub query: Ref<Query>,
}
#[derive(Debug, Clone)]
#[derive(Debug)]
pub enum RuleHead {
Compr {
span: Span,
refr: Expr,
refr: Ref<Expr>,
assign: Option<RuleAssign>,
},
Set {
span: Span,
refr: Expr,
key: Option<Expr>,
refr: Ref<Expr>,
key: Option<Ref<Expr>>,
},
Func {
span: Span,
refr: Expr,
args: Vec<Expr>,
refr: Ref<Expr>,
args: Vec<Ref<Expr>>,
assign: Option<RuleAssign>,
},
}
#[derive(Debug, Clone)]
#[derive(Debug)]
pub enum Rule {
Spec {
span: Span,
@@ -258,63 +320,30 @@ pub enum Rule {
},
Default {
span: Span,
refr: Expr,
refr: Ref<Expr>,
op: AssignOp,
value: Expr,
value: Ref<Expr>,
},
}
#[derive(Debug, Clone)]
#[derive(Debug)]
pub struct Package {
pub span: Span,
pub refr: Expr,
pub refr: Ref<Expr>,
}
#[derive(Debug, Clone)]
#[derive(Debug)]
pub struct Import {
pub span: Span,
pub refr: Expr,
pub refr: Ref<Expr>,
pub r#as: Option<Span>,
}
#[derive(Debug, Clone)]
#[derive(Debug)]
pub struct Module {
pub package: Package,
pub imports: Vec<Import>,
pub policy: Vec<Rule>,
pub policy: Vec<Ref<Rule>>,
}
#[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 {
(self.r as *const T).cmp(&(other.r as *const T))
}
}
pub type ExprRef = Ref<Expr>;

View File

@@ -1,7 +1,7 @@
// Copyright (c) Microsoft Corporation.
// Licensed under the MIT License.
use crate::ast::Expr;
use crate::ast::{Expr, Ref};
use crate::builtins;
use crate::builtins::utils::{ensure_args_count, ensure_numeric};
use crate::lexer::Span;
@@ -20,7 +20,7 @@ pub fn register(m: &mut HashMap<&'static str, builtins::BuiltinFcn>) {
m.insert("sum", (sum, 1));
}
fn count(span: &Span, params: &[Expr], args: &[Value]) -> Result<Value> {
fn count(span: &Span, params: &[Ref<Expr>], args: &[Value]) -> Result<Value> {
ensure_args_count(span, "count", params, args, 1)?;
Ok(Value::from_float(match &args[0] {
@@ -37,7 +37,7 @@ fn count(span: &Span, params: &[Expr], args: &[Value]) -> Result<Value> {
}))
}
fn max(span: &Span, params: &[Expr], args: &[Value]) -> Result<Value> {
fn max(span: &Span, params: &[Ref<Expr>], args: &[Value]) -> Result<Value> {
ensure_args_count(span, "max", params, args, 1)?;
Ok(match &args[0] {
@@ -52,7 +52,7 @@ fn max(span: &Span, params: &[Expr], args: &[Value]) -> Result<Value> {
})
}
fn min(span: &Span, params: &[Expr], args: &[Value]) -> Result<Value> {
fn min(span: &Span, params: &[Ref<Expr>], args: &[Value]) -> Result<Value> {
ensure_args_count(span, "min", params, args, 1)?;
Ok(match &args[0] {
@@ -67,7 +67,7 @@ fn min(span: &Span, params: &[Expr], args: &[Value]) -> Result<Value> {
})
}
fn product(span: &Span, params: &[Expr], args: &[Value]) -> Result<Value> {
fn product(span: &Span, params: &[Ref<Expr>], args: &[Value]) -> Result<Value> {
ensure_args_count(span, "product", params, args, 1)?;
let mut v = 1 as Float;
@@ -92,7 +92,7 @@ fn product(span: &Span, params: &[Expr], args: &[Value]) -> Result<Value> {
})
}
fn sort(span: &Span, params: &[Expr], args: &[Value]) -> Result<Value> {
fn sort(span: &Span, params: &[Ref<Expr>], args: &[Value]) -> Result<Value> {
ensure_args_count(span, "sort", params, args, 1)?;
Ok(match &args[0] {
Value::Array(a) => {
@@ -109,7 +109,7 @@ fn sort(span: &Span, params: &[Expr], args: &[Value]) -> Result<Value> {
})
}
fn sum(span: &Span, params: &[Expr], args: &[Value]) -> Result<Value> {
fn sum(span: &Span, params: &[Ref<Expr>], args: &[Value]) -> Result<Value> {
ensure_args_count(span, "sum", params, args, 1)?;
let mut v = 0 as Float;

View File

@@ -1,7 +1,7 @@
// Copyright (c) Microsoft Corporation.
// Licensed under the MIT License.
use crate::ast::Expr;
use crate::ast::{Expr, Ref};
use crate::builtins;
use crate::builtins::utils::{ensure_args_count, ensure_array, ensure_numeric};
use crate::lexer::Span;
@@ -18,7 +18,7 @@ pub fn register(m: &mut HashMap<&'static str, builtins::BuiltinFcn>) {
m.insert("array.slice", (slice, 3));
}
fn concat(span: &Span, params: &[Expr], args: &[Value]) -> Result<Value> {
fn concat(span: &Span, params: &[Ref<Expr>], args: &[Value]) -> Result<Value> {
let name = "array.concat";
ensure_args_count(span, name, params, args, 2)?;
let mut v1 = ensure_array(name, &params[0], args[0].clone())?;
@@ -28,7 +28,7 @@ fn concat(span: &Span, params: &[Expr], args: &[Value]) -> Result<Value> {
Ok(Value::Array(v1))
}
fn reverse(span: &Span, params: &[Expr], args: &[Value]) -> Result<Value> {
fn reverse(span: &Span, params: &[Ref<Expr>], args: &[Value]) -> Result<Value> {
let name = "array.reverse";
ensure_args_count(span, name, params, args, 1)?;
@@ -37,7 +37,7 @@ fn reverse(span: &Span, params: &[Expr], args: &[Value]) -> Result<Value> {
Ok(Value::Array(v1))
}
fn slice(span: &Span, params: &[Expr], args: &[Value]) -> Result<Value> {
fn slice(span: &Span, params: &[Ref<Expr>], args: &[Value]) -> Result<Value> {
let name = "array.slice";
ensure_args_count(span, name, params, args, 3)?;

View File

@@ -1,7 +1,7 @@
// Copyright (c) Microsoft Corporation.
// Licensed under the MIT License.
use crate::ast::Expr;
use crate::ast::{Expr, Ref};
use crate::builtins;
use crate::builtins::utils::{ensure_args_count, ensure_numeric};
@@ -21,7 +21,7 @@ pub fn register(m: &mut HashMap<&'static str, builtins::BuiltinFcn>) {
m.insert("bits.xor", (xor, 2));
}
fn and(span: &Span, params: &[Expr], args: &[Value]) -> Result<Value> {
fn and(span: &Span, params: &[Ref<Expr>], args: &[Value]) -> Result<Value> {
let name = "bits.and";
ensure_args_count(span, name, params, args, 2)?;
@@ -38,7 +38,7 @@ fn and(span: &Span, params: &[Expr], args: &[Value]) -> Result<Value> {
Ok(Value::from_float((v1 & v2) as Float))
}
fn lsh(span: &Span, params: &[Expr], args: &[Value]) -> Result<Value> {
fn lsh(span: &Span, params: &[Ref<Expr>], args: &[Value]) -> Result<Value> {
let name = "bits.lsh";
ensure_args_count(span, name, params, args, 2)?;
@@ -60,7 +60,7 @@ fn lsh(span: &Span, params: &[Expr], args: &[Value]) -> Result<Value> {
Ok(Value::from_float((v1 << v2) as Float))
}
fn negate(span: &Span, params: &[Expr], args: &[Value]) -> Result<Value> {
fn negate(span: &Span, params: &[Ref<Expr>], args: &[Value]) -> Result<Value> {
let name = "bits.negate";
ensure_args_count(span, name, params, args, 1)?;
@@ -75,7 +75,7 @@ fn negate(span: &Span, params: &[Expr], args: &[Value]) -> Result<Value> {
Ok(Value::from_float((!v) as Float))
}
fn or(span: &Span, params: &[Expr], args: &[Value]) -> Result<Value> {
fn or(span: &Span, params: &[Ref<Expr>], args: &[Value]) -> Result<Value> {
let name = "bits.or";
ensure_args_count(span, name, params, args, 2)?;
@@ -92,7 +92,7 @@ fn or(span: &Span, params: &[Expr], args: &[Value]) -> Result<Value> {
Ok(Value::from_float((v1 | v2) as Float))
}
fn rsh(span: &Span, params: &[Expr], args: &[Value]) -> Result<Value> {
fn rsh(span: &Span, params: &[Ref<Expr>], args: &[Value]) -> Result<Value> {
let name = "bits.rsh";
ensure_args_count(span, name, params, args, 2)?;
@@ -114,7 +114,7 @@ fn rsh(span: &Span, params: &[Expr], args: &[Value]) -> Result<Value> {
Ok(Value::from_float((v1 >> v2) as Float))
}
fn xor(span: &Span, params: &[Expr], args: &[Value]) -> Result<Value> {
fn xor(span: &Span, params: &[Ref<Expr>], args: &[Value]) -> Result<Value> {
let name = "bits.xor";
ensure_args_count(span, name, params, args, 2)?;

View File

@@ -1,7 +1,7 @@
// Copyright (c) Microsoft Corporation.
// Licensed under the MIT License.
use crate::ast::Expr;
use crate::ast::{Expr, Ref};
use crate::builtins;
use crate::builtins::utils::ensure_args_count;
use crate::lexer::Span;
@@ -15,7 +15,7 @@ pub fn register(m: &mut HashMap<&'static str, builtins::BuiltinFcn>) {
m.insert("to_number", (to_number, 1));
}
fn to_number(span: &Span, params: &[Expr], args: &[Value]) -> Result<Value> {
fn to_number(span: &Span, params: &[Ref<Expr>], args: &[Value]) -> Result<Value> {
let name = "to_number";
ensure_args_count(span, name, params, args, 1)?;

View File

@@ -1,7 +1,7 @@
// Copyright (c) Microsoft Corporation.
// Licensed under the MIT License.
use crate::ast::Expr;
use crate::ast::{Expr, Ref};
use crate::builtins;
use crate::lexer::Span;
use crate::value::Value;
@@ -20,7 +20,7 @@ pub fn register(m: &mut HashMap<&'static str, builtins::BuiltinFcn>) {
// Symbol analyzer must ensure that vars used by print are defined before
// the print statement. Scheduler must ensure the above constraint.
// Additionally interpreter must allow undefined inputs to print.
fn print(span: &Span, _params: &[Expr], args: &[Value]) -> Result<Value> {
fn print(span: &Span, _params: &[Ref<Expr>], args: &[Value]) -> Result<Value> {
if args.len() > MAX_ARGS as usize {
bail!(span.error("print supports up to 100 arguments"));
}

View File

@@ -1,7 +1,7 @@
// Copyright (c) Microsoft Corporation.
// Licensed under the MIT License.
use crate::ast::Expr;
use crate::ast::{Expr, Ref};
use crate::builtins::utils::ensure_args_count;
use crate::builtins::BuiltinFcn;
use crate::lexer::Span;
@@ -24,7 +24,7 @@ lazy_static! {
};
}
fn all(span: &Span, params: &[Expr], args: &[Value]) -> Result<Value> {
fn all(span: &Span, params: &[Ref<Expr>], args: &[Value]) -> Result<Value> {
ensure_args_count(span, "all", params, args, 1)?;
Ok(Value::Bool(match &args[0] {
@@ -37,7 +37,7 @@ fn all(span: &Span, params: &[Expr], args: &[Value]) -> Result<Value> {
}))
}
fn any(span: &Span, params: &[Expr], args: &[Value]) -> Result<Value> {
fn any(span: &Span, params: &[Ref<Expr>], args: &[Value]) -> Result<Value> {
ensure_args_count(span, "any", params, args, 1)?;
Ok(Value::Bool(match &args[0] {

View File

@@ -1,7 +1,7 @@
// Copyright (c) Microsoft Corporation.
// Licensed under the MIT License.
use crate::ast::Expr;
use crate::ast::{Expr, Ref};
use crate::builtins;
use crate::builtins::utils::{ensure_args_count, ensure_string};
use crate::lexer::Span;
@@ -16,7 +16,7 @@ pub fn register(m: &mut HashMap<&'static str, builtins::BuiltinFcn>) {
m.insert("base64.decode", (base64_decode, 1));
}
fn base64_decode(span: &Span, params: &[Expr], args: &[Value]) -> Result<Value> {
fn base64_decode(span: &Span, params: &[Ref<Expr>], args: &[Value]) -> Result<Value> {
let name = "base64.decode";
ensure_args_count(span, name, params, args, 1)?;

View File

@@ -18,7 +18,7 @@ mod tracing;
pub mod types;
mod utils;
use crate::ast::Expr;
use crate::ast::{Expr, Ref};
use crate::lexer::Span;
use crate::value::Value;
@@ -27,7 +27,7 @@ use std::collections::HashMap;
use anyhow::Result;
use lazy_static::lazy_static;
pub type BuiltinFcn = (fn(&Span, &[Expr], &[Value]) -> Result<Value>, u8);
pub type BuiltinFcn = (fn(&Span, &[Ref<Expr>], &[Value]) -> Result<Value>, u8);
pub use deprecated::DEPRECATED;

View File

@@ -1,7 +1,7 @@
// Copyright (c) Microsoft Corporation.
// Licensed under the MIT License.
use crate::ast::{ArithOp, Expr};
use crate::ast::{ArithOp, Expr, Ref};
use crate::builtins;
use crate::builtins::utils::{ensure_args_count, ensure_numeric, ensure_string};
use crate::lexer::Span;
@@ -45,28 +45,28 @@ pub fn arithmetic_operation(
}))
}
fn abs(span: &Span, params: &[Expr], args: &[Value]) -> Result<Value> {
fn abs(span: &Span, params: &[Ref<Expr>], args: &[Value]) -> Result<Value> {
ensure_args_count(span, "abs", params, args, 1)?;
Ok(Value::from_float(
ensure_numeric("abs", &params[0], &args[0])?.abs(),
))
}
fn ceil(span: &Span, params: &[Expr], args: &[Value]) -> Result<Value> {
fn ceil(span: &Span, params: &[Ref<Expr>], args: &[Value]) -> Result<Value> {
ensure_args_count(span, "ceil", params, args, 1)?;
Ok(Value::from_float(
ensure_numeric("ceil", &params[0], &args[0])?.ceil(),
))
}
fn floor(span: &Span, params: &[Expr], args: &[Value]) -> Result<Value> {
fn floor(span: &Span, params: &[Ref<Expr>], args: &[Value]) -> Result<Value> {
ensure_args_count(span, "floor", params, args, 1)?;
Ok(Value::from_float(
ensure_numeric("floor", &params[0], &args[0])?.floor(),
))
}
fn range(span: &Span, params: &[Expr], args: &[Value]) -> Result<Value> {
fn range(span: &Span, params: &[Ref<Expr>], args: &[Value]) -> Result<Value> {
ensure_args_count(span, "numbers.range", params, args, 2)?;
let v1 = ensure_numeric("numbers.range", &params[0], &args[0].clone())?;
let v2 = ensure_numeric("numbers.range", &params[1], &args[1].clone())?;
@@ -90,14 +90,14 @@ fn range(span: &Span, params: &[Expr], args: &[Value]) -> Result<Value> {
Ok(Value::from_array(values))
}
fn round(span: &Span, params: &[Expr], args: &[Value]) -> Result<Value> {
fn round(span: &Span, params: &[Ref<Expr>], args: &[Value]) -> Result<Value> {
ensure_args_count(span, "round", params, args, 1)?;
Ok(Value::from_float(
ensure_numeric("round", &params[0], &args[0])?.round(),
))
}
fn intn(span: &Span, params: &[Expr], args: &[Value]) -> Result<Value> {
fn intn(span: &Span, params: &[Ref<Expr>], args: &[Value]) -> Result<Value> {
let fcn = "rand.intn";
ensure_args_count(span, fcn, params, args, 2)?;
let _ = ensure_string(fcn, &params[0], &args[0])?;

View File

@@ -1,7 +1,7 @@
// Copyright (c) Microsoft Corporation.
// Licensed under the MIT License.
use crate::ast::Expr;
use crate::ast::{Expr, Ref};
use crate::builtins;
use crate::builtins::utils::{ensure_args_count, ensure_object};
use crate::lexer::Span;
@@ -121,7 +121,7 @@ fn merge_filters(
Ok(filters)
}
fn json_filter(span: &Span, params: &[Expr], args: &[Value]) -> Result<Value> {
fn json_filter(span: &Span, params: &[Ref<Expr>], args: &[Value]) -> Result<Value> {
let name = "json.filter";
ensure_args_count(span, name, params, args, 2)?;
ensure_object(name, &params[0], args[0].clone())?;
@@ -135,7 +135,7 @@ fn json_filter(span: &Span, params: &[Expr], args: &[Value]) -> Result<Value> {
Ok(json_filter_impl(&args[0], &filters))
}
fn filter(span: &Span, params: &[Expr], args: &[Value]) -> Result<Value> {
fn filter(span: &Span, params: &[Ref<Expr>], args: &[Value]) -> Result<Value> {
let name = "object.filter";
ensure_args_count(span, name, params, args, 2)?;
let mut obj = ensure_object(name, &params[0], args[0].clone())?;
@@ -153,7 +153,7 @@ fn filter(span: &Span, params: &[Expr], args: &[Value]) -> Result<Value> {
Ok(Value::Object(obj))
}
fn get(span: &Span, params: &[Expr], args: &[Value]) -> Result<Value> {
fn get(span: &Span, params: &[Ref<Expr>], args: &[Value]) -> Result<Value> {
let name = "object.get";
ensure_args_count(span, name, params, args, 3)?;
let obj = ensure_object(name, &params[0], args[0].clone())?;
@@ -178,14 +178,14 @@ fn get(span: &Span, params: &[Expr], args: &[Value]) -> Result<Value> {
})
}
fn keys(span: &Span, params: &[Expr], args: &[Value]) -> Result<Value> {
fn keys(span: &Span, params: &[Ref<Expr>], args: &[Value]) -> Result<Value> {
let name = "object.keys";
ensure_args_count(span, name, params, args, 1)?;
let obj = ensure_object(name, &params[0], args[0].clone())?;
Ok(Value::from_set(obj.keys().cloned().collect()))
}
fn remove(span: &Span, params: &[Expr], args: &[Value]) -> Result<Value> {
fn remove(span: &Span, params: &[Ref<Expr>], args: &[Value]) -> Result<Value> {
let name = "object.remove";
ensure_args_count(span, name, params, args, 2)?;
let mut obj = ensure_object(name, &params[0], args[0].clone())?;

View File

@@ -1,7 +1,7 @@
// Copyright (c) Microsoft Corporation.
// Licensed under the MIT License.
use crate::ast::Expr;
use crate::ast::{Expr, Ref};
use crate::builtins;
use crate::builtins::utils::{ensure_args_count, ensure_set};
use crate::lexer::Span;
@@ -34,7 +34,7 @@ pub fn difference(expr1: &Expr, expr2: &Expr, v1: Value, v2: Value) -> Result<Va
Ok(Value::from_set(s1.difference(&s2).cloned().collect()))
}
fn intersection_of_set_of_sets(span: &Span, params: &[Expr], args: &[Value]) -> Result<Value> {
fn intersection_of_set_of_sets(span: &Span, params: &[Ref<Expr>], args: &[Value]) -> Result<Value> {
let name = "intersection";
ensure_args_count(span, name, params, args, 1)?;
let set = ensure_set(name, &params[0], args[0].clone())?;
@@ -61,7 +61,7 @@ fn intersection_of_set_of_sets(span: &Span, params: &[Expr], args: &[Value]) ->
Ok(Value::from_set(res))
}
fn union_of_set_of_sets(span: &Span, params: &[Expr], args: &[Value]) -> Result<Value> {
fn union_of_set_of_sets(span: &Span, params: &[Ref<Expr>], args: &[Value]) -> Result<Value> {
let name = "union";
ensure_args_count(span, name, params, args, 1)?;
let set = ensure_set(name, &params[0], args[0].clone())?;

View File

@@ -1,7 +1,7 @@
// Copyright (c) Microsoft Corporation.
// Licensed under the MIT License.
use crate::ast::Expr;
use crate::ast::{Expr, Ref};
use crate::builtins;
use crate::builtins::utils::{
ensure_args_count, ensure_array, ensure_numeric, ensure_object, ensure_string,
@@ -41,7 +41,7 @@ pub fn register(m: &mut HashMap<&'static str, builtins::BuiltinFcn>) {
m.insert("upper", (upper, 1));
}
fn concat(span: &Span, params: &[Expr], args: &[Value]) -> Result<Value> {
fn concat(span: &Span, params: &[Ref<Expr>], args: &[Value]) -> Result<Value> {
let name = "concat";
ensure_args_count(span, name, params, args, 2)?;
let delimiter = ensure_string(name, &params[0], &args[0])?;
@@ -49,7 +49,7 @@ fn concat(span: &Span, params: &[Expr], args: &[Value]) -> Result<Value> {
Ok(Value::String(collection.join(&delimiter)))
}
fn contains(span: &Span, params: &[Expr], args: &[Value]) -> Result<Value> {
fn contains(span: &Span, params: &[Ref<Expr>], args: &[Value]) -> Result<Value> {
let name = "contains";
ensure_args_count(span, name, params, args, 2)?;
let s1 = ensure_string(name, &params[0], &args[0])?;
@@ -57,7 +57,7 @@ fn contains(span: &Span, params: &[Expr], args: &[Value]) -> Result<Value> {
Ok(Value::Bool(s1.contains(&s2)))
}
fn endswith(span: &Span, params: &[Expr], args: &[Value]) -> Result<Value> {
fn endswith(span: &Span, params: &[Ref<Expr>], args: &[Value]) -> Result<Value> {
let name = "endswith";
ensure_args_count(span, name, params, args, 2)?;
let s1 = ensure_string(name, &params[0], &args[0])?;
@@ -65,7 +65,7 @@ fn endswith(span: &Span, params: &[Expr], args: &[Value]) -> Result<Value> {
Ok(Value::Bool(s1.ends_with(&s2)))
}
fn format_int(span: &Span, params: &[Expr], args: &[Value]) -> Result<Value> {
fn format_int(span: &Span, params: &[Ref<Expr>], args: &[Value]) -> Result<Value> {
let name = "endswith";
ensure_args_count(span, name, params, args, 2)?;
let mut n = ensure_numeric(name, &params[0], &args[0])?;
@@ -88,7 +88,7 @@ fn format_int(span: &Span, params: &[Expr], args: &[Value]) -> Result<Value> {
))
}
fn indexof(span: &Span, params: &[Expr], args: &[Value]) -> Result<Value> {
fn indexof(span: &Span, params: &[Ref<Expr>], args: &[Value]) -> Result<Value> {
let name = "indexof";
ensure_args_count(span, name, params, args, 2)?;
let s1 = ensure_string(name, &params[0], &args[0])?;
@@ -100,7 +100,7 @@ fn indexof(span: &Span, params: &[Expr], args: &[Value]) -> Result<Value> {
}
#[allow(dead_code)]
fn indexof_n(span: &Span, params: &[Expr], args: &[Value]) -> Result<Value> {
fn indexof_n(span: &Span, params: &[Ref<Expr>], args: &[Value]) -> Result<Value> {
let name = "indexof_n";
ensure_args_count(span, name, params, args, 2)?;
let s1 = ensure_string(name, &params[0], &args[0])?;
@@ -119,14 +119,14 @@ fn indexof_n(span: &Span, params: &[Expr], args: &[Value]) -> Result<Value> {
Ok(Value::from_array(positions))
}
fn lower(span: &Span, params: &[Expr], args: &[Value]) -> Result<Value> {
fn lower(span: &Span, params: &[Ref<Expr>], args: &[Value]) -> Result<Value> {
let name = "lower";
ensure_args_count(span, name, params, args, 1)?;
let s = ensure_string(name, &params[0], &args[0])?;
Ok(Value::String(s.to_lowercase()))
}
fn replace(span: &Span, params: &[Expr], args: &[Value]) -> Result<Value> {
fn replace(span: &Span, params: &[Ref<Expr>], args: &[Value]) -> Result<Value> {
let name = "replace";
ensure_args_count(span, name, params, args, 3)?;
let s = ensure_string(name, &params[0], &args[0])?;
@@ -135,7 +135,7 @@ fn replace(span: &Span, params: &[Expr], args: &[Value]) -> Result<Value> {
Ok(Value::String(s.replace(&old, &new)))
}
fn split(span: &Span, params: &[Expr], args: &[Value]) -> Result<Value> {
fn split(span: &Span, params: &[Ref<Expr>], args: &[Value]) -> Result<Value> {
let name = "replace";
ensure_args_count(span, name, params, args, 2)?;
let s = ensure_string(name, &params[0], &args[0])?;
@@ -148,7 +148,7 @@ fn split(span: &Span, params: &[Expr], args: &[Value]) -> Result<Value> {
))
}
fn sprintf(span: &Span, params: &[Expr], args: &[Value]) -> Result<Value> {
fn sprintf(span: &Span, params: &[Ref<Expr>], args: &[Value]) -> Result<Value> {
let name = "sprintf";
ensure_args_count(span, name, params, args, 2)?;
let fmt = ensure_string(name, &params[0], &args[0])?;
@@ -315,7 +315,7 @@ fn sprintf(span: &Span, params: &[Expr], args: &[Value]) -> Result<Value> {
Ok(Value::String(s.to_string()))
}
fn any_prefix_match(span: &Span, params: &[Expr], args: &[Value]) -> Result<Value> {
fn any_prefix_match(span: &Span, params: &[Ref<Expr>], args: &[Value]) -> Result<Value> {
let name = "strings.any_prefix_match";
ensure_args_count(span, name, params, args, 2)?;
@@ -346,7 +346,7 @@ fn any_prefix_match(span: &Span, params: &[Expr], args: &[Value]) -> Result<Valu
))
}
fn any_suffix_match(span: &Span, params: &[Expr], args: &[Value]) -> Result<Value> {
fn any_suffix_match(span: &Span, params: &[Ref<Expr>], args: &[Value]) -> Result<Value> {
let name = "strings.any_suffix_match";
ensure_args_count(span, name, params, args, 2)?;
@@ -377,7 +377,7 @@ fn any_suffix_match(span: &Span, params: &[Expr], args: &[Value]) -> Result<Valu
))
}
fn startswith(span: &Span, params: &[Expr], args: &[Value]) -> Result<Value> {
fn startswith(span: &Span, params: &[Ref<Expr>], args: &[Value]) -> Result<Value> {
let name = "startswith";
ensure_args_count(span, name, params, args, 2)?;
let s1 = ensure_string(name, &params[0], &args[0])?;
@@ -385,7 +385,7 @@ fn startswith(span: &Span, params: &[Expr], args: &[Value]) -> Result<Value> {
Ok(Value::Bool(s1.starts_with(&s2)))
}
fn replace_n(span: &Span, params: &[Expr], args: &[Value]) -> Result<Value> {
fn replace_n(span: &Span, params: &[Ref<Expr>], args: &[Value]) -> Result<Value> {
let name = "trim";
ensure_args_count(span, name, params, args, 2)?;
let obj = ensure_object(name, &params[0], args[0].clone())?;
@@ -408,14 +408,14 @@ fn replace_n(span: &Span, params: &[Expr], args: &[Value]) -> Result<Value> {
Ok(Value::String(s))
}
fn reverse(span: &Span, params: &[Expr], args: &[Value]) -> Result<Value> {
fn reverse(span: &Span, params: &[Ref<Expr>], args: &[Value]) -> Result<Value> {
let name = "reverse";
ensure_args_count(span, name, params, args, 1)?;
let s = ensure_string(name, &params[0], &args[0])?;
Ok(Value::String(s.chars().rev().collect()))
}
fn substring(span: &Span, params: &[Expr], args: &[Value]) -> Result<Value> {
fn substring(span: &Span, params: &[Ref<Expr>], args: &[Value]) -> Result<Value> {
let name = "substring";
ensure_args_count(span, name, params, args, 3)?;
let s = ensure_string(name, &params[0], &args[0])?;
@@ -443,7 +443,7 @@ fn substring(span: &Span, params: &[Expr], args: &[Value]) -> Result<Value> {
Ok(Value::String(s[offset..offset + length].to_string()))
}
fn trim(span: &Span, params: &[Expr], args: &[Value]) -> Result<Value> {
fn trim(span: &Span, params: &[Ref<Expr>], args: &[Value]) -> Result<Value> {
let name = "trim";
ensure_args_count(span, name, params, args, 2)?;
let s1 = ensure_string(name, &params[0], &args[0])?;
@@ -453,7 +453,7 @@ fn trim(span: &Span, params: &[Expr], args: &[Value]) -> Result<Value> {
))
}
fn trim_left(span: &Span, params: &[Expr], args: &[Value]) -> Result<Value> {
fn trim_left(span: &Span, params: &[Ref<Expr>], args: &[Value]) -> Result<Value> {
let name = "trim_left";
ensure_args_count(span, name, params, args, 2)?;
let s1 = ensure_string(name, &params[0], &args[0])?;
@@ -463,7 +463,7 @@ fn trim_left(span: &Span, params: &[Expr], args: &[Value]) -> Result<Value> {
))
}
fn trim_prefix(span: &Span, params: &[Expr], args: &[Value]) -> Result<Value> {
fn trim_prefix(span: &Span, params: &[Ref<Expr>], args: &[Value]) -> Result<Value> {
let name = "trim_prefix";
ensure_args_count(span, name, params, args, 2)?;
let s1 = ensure_string(name, &params[0], &args[0])?;
@@ -474,7 +474,7 @@ fn trim_prefix(span: &Span, params: &[Expr], args: &[Value]) -> Result<Value> {
}))
}
fn trim_right(span: &Span, params: &[Expr], args: &[Value]) -> Result<Value> {
fn trim_right(span: &Span, params: &[Ref<Expr>], args: &[Value]) -> Result<Value> {
let name = "trim_right";
ensure_args_count(span, name, params, args, 2)?;
let s1 = ensure_string(name, &params[0], &args[0])?;
@@ -484,14 +484,14 @@ fn trim_right(span: &Span, params: &[Expr], args: &[Value]) -> Result<Value> {
))
}
fn trim_space(span: &Span, params: &[Expr], args: &[Value]) -> Result<Value> {
fn trim_space(span: &Span, params: &[Ref<Expr>], args: &[Value]) -> Result<Value> {
let name = "trim_space";
ensure_args_count(span, name, params, args, 1)?;
let s = ensure_string(name, &params[0], &args[0])?;
Ok(Value::String(s.trim().to_string()))
}
fn trim_suffix(span: &Span, params: &[Expr], args: &[Value]) -> Result<Value> {
fn trim_suffix(span: &Span, params: &[Ref<Expr>], args: &[Value]) -> Result<Value> {
let name = "trim_suffix";
ensure_args_count(span, name, params, args, 2)?;
let s1 = ensure_string(name, &params[0], &args[0])?;
@@ -502,7 +502,7 @@ fn trim_suffix(span: &Span, params: &[Expr], args: &[Value]) -> Result<Value> {
}))
}
fn upper(span: &Span, params: &[Expr], args: &[Value]) -> Result<Value> {
fn upper(span: &Span, params: &[Ref<Expr>], args: &[Value]) -> Result<Value> {
let name = "upper";
ensure_args_count(span, name, params, args, 1)?;
let s = ensure_string(name, &params[0], &args[0])?;

View File

@@ -1,7 +1,7 @@
// Copyright (c) Microsoft Corporation.
// Licensed under the MIT License.
use crate::ast::Expr;
use crate::ast::{Expr, Ref};
use crate::builtins;
use crate::builtins::utils::ensure_args_count;
use crate::lexer::Span;
@@ -16,7 +16,7 @@ pub fn register(m: &mut HashMap<&'static str, builtins::BuiltinFcn>) {
m.insert("time.now_ns", (now_ns, 0));
}
fn now_ns(span: &Span, params: &[Expr], args: &[Value]) -> Result<Value> {
fn now_ns(span: &Span, params: &[Ref<Expr>], args: &[Value]) -> Result<Value> {
let name = "time.now_ns";
ensure_args_count(span, name, params, args, 0)?;

View File

@@ -1,7 +1,7 @@
// Copyright (c) Microsoft Corporation.
// Licensed under the MIT License.
use crate::ast::Expr;
use crate::ast::{Expr, Ref};
use crate::builtins;
use crate::builtins::utils::{ensure_args_count, ensure_string};
use crate::lexer::Span;
@@ -17,7 +17,7 @@ pub fn register(m: &mut HashMap<&'static str, builtins::BuiltinFcn>) {
// Symbol analyzer must ensure that vars used by trace are defined before
// the trace statement. Scheduler must ensure the above constraint.
fn trace(span: &Span, params: &[Expr], args: &[Value]) -> Result<Value> {
fn trace(span: &Span, params: &[Ref<Expr>], args: &[Value]) -> Result<Value> {
let name = "trace";
ensure_args_count(span, name, params, args, 1)?;
let msg = ensure_string(name, &params[0], &args[0])?;

View File

@@ -1,7 +1,7 @@
// Copyright (c) Microsoft Corporation.
// Licensed under the MIT License.
use crate::ast::Expr;
use crate::ast::{Expr, Ref};
use crate::builtins;
use crate::builtins::utils::ensure_args_count;
use crate::lexer::Span;
@@ -22,37 +22,37 @@ pub fn register(m: &mut HashMap<&'static str, builtins::BuiltinFcn>) {
m.insert("type_name", (type_name, 1));
}
fn is_array(span: &Span, params: &[Expr], args: &[Value]) -> Result<Value> {
fn is_array(span: &Span, params: &[Ref<Expr>], args: &[Value]) -> Result<Value> {
ensure_args_count(span, "is_array", params, args, 1)?;
Ok(Value::Bool(matches!(&args[0], Value::Array(_))))
}
fn is_boolean(span: &Span, params: &[Expr], args: &[Value]) -> Result<Value> {
fn is_boolean(span: &Span, params: &[Ref<Expr>], args: &[Value]) -> Result<Value> {
ensure_args_count(span, "is_boolean", params, args, 1)?;
Ok(Value::Bool(matches!(&args[0], Value::Bool(_))))
}
fn is_null(span: &Span, params: &[Expr], args: &[Value]) -> Result<Value> {
fn is_null(span: &Span, params: &[Ref<Expr>], args: &[Value]) -> Result<Value> {
ensure_args_count(span, "is_null", params, args, 1)?;
Ok(Value::Bool(matches!(&args[0], Value::Null)))
}
fn is_number(span: &Span, params: &[Expr], args: &[Value]) -> Result<Value> {
fn is_number(span: &Span, params: &[Ref<Expr>], args: &[Value]) -> Result<Value> {
ensure_args_count(span, "is_number", params, args, 1)?;
Ok(Value::Bool(matches!(&args[0], Value::Number(_))))
}
fn is_object(span: &Span, params: &[Expr], args: &[Value]) -> Result<Value> {
fn is_object(span: &Span, params: &[Ref<Expr>], args: &[Value]) -> Result<Value> {
ensure_args_count(span, "is_object", params, args, 1)?;
Ok(Value::Bool(matches!(&args[0], Value::Object(_))))
}
fn is_set(span: &Span, params: &[Expr], args: &[Value]) -> Result<Value> {
fn is_set(span: &Span, params: &[Ref<Expr>], args: &[Value]) -> Result<Value> {
ensure_args_count(span, "is_set", params, args, 1)?;
Ok(Value::Bool(matches!(&args[0], Value::Set(_))))
}
fn is_string(span: &Span, params: &[Expr], args: &[Value]) -> Result<Value> {
fn is_string(span: &Span, params: &[Ref<Expr>], args: &[Value]) -> Result<Value> {
ensure_args_count(span, "is_string", params, args, 1)?;
Ok(Value::Bool(matches!(&args[0], Value::String(_))))
}
@@ -70,7 +70,7 @@ pub fn get_type(value: &Value) -> &str {
}
}
pub fn type_name(span: &Span, params: &[Expr], args: &[Value]) -> Result<Value> {
pub fn type_name(span: &Span, params: &[Ref<Expr>], args: &[Value]) -> Result<Value> {
ensure_args_count(span, "type_name", params, args, 1)?;
Ok(Value::String(get_type(&args[0]).to_string()))
}

View File

@@ -1,7 +1,7 @@
// Copyright (c) Microsoft Corporation.
// Licensed under the MIT License.
use crate::ast::Expr;
use crate::ast::{Expr, Ref};
use crate::lexer::Span;
use crate::value::{Float, Value};
@@ -13,7 +13,7 @@ use anyhow::{bail, Result};
pub fn ensure_args_count(
span: &Span,
fcn: &'static str,
params: &[Expr],
params: &[Ref<Expr>],
args: &[Value],
expected: usize,
) -> Result<()> {

View File

@@ -12,7 +12,7 @@ use anyhow::Result;
#[derive(Clone)]
pub struct Engine {
modules: Vec<std::rc::Rc<Module>>,
modules: Vec<Ref<Module>>,
input: Value,
data: Value,
}
@@ -35,14 +35,14 @@ impl Engine {
pub fn add_policy(&mut self, path: String, rego: String) -> Result<()> {
let source = Source::new(path, rego);
let mut parser = Parser::new(&source)?;
self.modules.push(std::rc::Rc::new(parser.parse()?));
self.modules.push(Ref::new(parser.parse()?));
Ok(())
}
pub fn add_policy_from_file(&mut self, path: String) -> Result<()> {
let source = Source::from_file(path)?;
let mut parser = Parser::new(&source)?;
self.modules.push(std::rc::Rc::new(parser.parse()?));
self.modules.push(Ref::new(parser.parse()?));
Ok(())
}
@@ -59,14 +59,12 @@ impl Engine {
}
pub fn eval_query(&self, query: String, enable_tracing: bool) -> Result<QueryResults> {
let modules_ref: Vec<&Module> = self.modules.iter().map(|m| &**m).collect();
// Analyze the modules and determine how statements must be scheduled.
let analyzer = Analyzer::new();
let schedule = analyzer.analyze(&modules_ref)?;
let schedule = analyzer.analyze(&self.modules)?;
// Create interpreter object.
let mut interpreter = Interpreter::new(&modules_ref)?;
let mut interpreter = Interpreter::new(&self.modules)?;
// Evaluate all the modules.
interpreter.eval(
@@ -87,8 +85,8 @@ impl Engine {
end: query_len as u16,
};
let mut parser = Parser::new(&query_source)?;
let query_node = parser.parse_query(query_span, "")?;
let query_schedule = Analyzer::new().analyze_query_snippet(&modules_ref, &query_node)?;
let query_node = Ref::new(parser.parse_query(query_span, "")?);
let query_schedule = Analyzer::new().analyze_query_snippet(&self.modules, &query_node)?;
let results = interpreter.eval_user_query(&query_node, &query_schedule, enable_tracing)?;
Ok(results)

File diff suppressed because it is too large Load Diff

View File

@@ -20,6 +20,63 @@ pub struct Source {
src: std::rc::Rc<SourceInternal>,
}
#[derive(Clone)]
pub struct SourceStr {
source: Source,
start: u16,
end: u16,
}
impl Debug for SourceStr {
fn fmt(&self, f: &mut Formatter<'_>) -> Result<(), std::fmt::Error> {
self.text().fmt(f)
}
}
impl std::fmt::Display for SourceStr {
fn fmt(&self, f: &mut Formatter<'_>) -> Result<(), std::fmt::Error> {
std::fmt::Display::fmt(&self.text(), f)
}
}
impl SourceStr {
pub fn new(source: Source, start: u16, end: u16) -> Self {
Self { source, start, end }
}
pub fn text(&self) -> &str {
&self.source.contents()[self.start as usize..self.end as usize]
}
pub fn clone_empty(&self) -> SourceStr {
Self {
source: self.source.clone(),
start: 0,
end: 0,
}
}
}
impl std::cmp::PartialEq for SourceStr {
fn eq(&self, other: &Self) -> bool {
self.text().eq(other.text())
}
}
impl std::cmp::Eq for SourceStr {}
impl std::cmp::PartialOrd for SourceStr {
fn partial_cmp(&self, other: &Self) -> Option<std::cmp::Ordering> {
Some(self.text().cmp(other.text()))
}
}
impl std::cmp::Ord for SourceStr {
fn cmp(&self, other: &Self) -> std::cmp::Ordering {
self.text().cmp(other.text())
}
}
impl Source {
pub fn new(file: String, contents: String) -> Source {
let mut lines = vec![];
@@ -126,6 +183,10 @@ impl Span {
std::rc::Rc::new(&self.source.contents()[self.start as usize..self.end as usize])
}
pub fn source_str(&self) -> SourceStr {
SourceStr::new(self.source.clone(), self.start, self.end)
}
pub fn message(&self, kind: &str, msg: &str) -> String {
self.source.message(self.line, self.col, kind, msg)
}

View File

@@ -2,7 +2,7 @@
// Licensed under the MIT License.
pub mod ast;
pub mod builtins;
mod builtins;
pub mod engine;
pub mod interpreter;
pub mod lexer;

View File

@@ -84,8 +84,8 @@ impl<'source> Parser<'source> {
}
}
pub fn get_path_ref_components_into(refr: &Expr, comps: &mut Vec<Span>) -> Result<()> {
match refr {
pub fn get_path_ref_components_into(refr: &Ref<Expr>, comps: &mut Vec<Span>) -> Result<()> {
match refr.as_ref() {
Expr::RefDot { refr, field, .. } => {
Self::get_path_ref_components_into(refr, comps)?;
comps.push(field.clone());
@@ -101,7 +101,7 @@ impl<'source> Parser<'source> {
Ok(())
}
pub fn get_path_ref_components(refr: &Expr) -> Result<Vec<Span>> {
pub fn get_path_ref_components(refr: &Ref<Expr>) -> Result<Vec<Span>> {
let mut comps = vec![];
Self::get_path_ref_components_into(refr, &mut comps)?;
Ok(comps)
@@ -283,8 +283,8 @@ impl<'source> Parser<'source> {
span.end = self.end;
Ok(Expr::ArrayCompr {
span,
term: Box::new(term),
query,
term: Ref::new(term),
query: Ref::new(query),
})
}
Err(_) if self.end == pos => {
@@ -292,13 +292,13 @@ impl<'source> Parser<'source> {
// Parse as array.
let mut items = vec![];
if *self.tok.1.text() != "]" {
items.push(self.parse_in_expr()?);
items.push(Ref::new(self.parse_in_expr()?));
while *self.tok.1.text() == "," {
self.next_token()?;
match *self.tok.1.text() {
"]" => break,
"" if self.tok.0 == TokenKind::Eof => break,
_ => items.push(self.parse_in_expr()?),
_ => items.push(Ref::new(self.parse_in_expr()?)),
}
}
}
@@ -320,8 +320,8 @@ impl<'source> Parser<'source> {
span.end = self.end;
return Ok(Expr::SetCompr {
span,
term: Box::new(term),
query,
term: Ref::new(term),
query: Ref::new(query),
});
}
Err(err) if self.end != pos => {
@@ -348,13 +348,13 @@ impl<'source> Parser<'source> {
if *self.tok.1.text() != ":" {
// Parse as set.
let mut items = vec![first];
let mut items = vec![Ref::new(first)];
while *self.tok.1.text() == "," {
self.next_token()?;
match *self.tok.1.text() {
"}" => break,
"" if self.tok.0 == TokenKind::Eof => break,
_ => items.push(self.parse_in_expr()?),
_ => items.push(Ref::new(self.parse_in_expr()?)),
}
}
self.expect("}", "while parsing set")?;
@@ -371,9 +371,9 @@ impl<'source> Parser<'source> {
span.end = self.end;
return Ok(Expr::ObjectCompr {
span,
key: Box::new(first),
value: Box::new(term),
query,
key: Ref::new(first),
value: Ref::new(term),
query: Ref::new(query),
});
}
Err(err) if self.end != pos => {
@@ -389,7 +389,7 @@ impl<'source> Parser<'source> {
let value = self.parse_in_expr()?;
item_span.end = self.end;
items.push((item_span, first, value));
items.push((item_span, Ref::new(first), Ref::new(value)));
while *self.tok.1.text() == "," {
self.next_token()?;
@@ -406,7 +406,7 @@ impl<'source> Parser<'source> {
let value = self.parse_in_expr()?;
item_span.end = self.end;
items.push((item_span, key, value));
items.push((item_span, Ref::new(key), Ref::new(value)));
}
self.expect("}", "while parsing object")?;
@@ -444,7 +444,7 @@ impl<'source> Parser<'source> {
span.end = self.end;
Ok(Expr::UnaryExpr {
span,
expr: Box::new(expr),
expr: Ref::new(expr),
})
}
@@ -500,7 +500,7 @@ impl<'source> Parser<'source> {
}
term = Expr::RefDot {
span,
refr: Box::new(term),
refr: Ref::new(term),
field,
};
}
@@ -516,21 +516,21 @@ impl<'source> Parser<'source> {
term = Expr::RefBrack {
span,
refr: Box::new(term),
index: Box::new(index),
refr: Ref::new(term),
index: Ref::new(index),
};
}
"(" if possible_fcn => {
self.next_token()?;
let mut args = vec![];
if *self.tok.1.text() != ")" {
args.push(self.parse_in_expr()?);
args.push(Ref::new(self.parse_in_expr()?));
while *self.tok.1.text() == "," {
self.next_token()?;
match *self.tok.1.text() {
")" => break,
"" if self.tok.0 == TokenKind::Eof => break,
_ => args.push(self.parse_in_expr()?),
_ => args.push(Ref::new(self.parse_in_expr()?)),
}
}
}
@@ -538,7 +538,7 @@ impl<'source> Parser<'source> {
span.end = self.end;
term = Expr::Call {
span,
fcn: Box::new(term),
fcn: Ref::new(term),
params: args,
};
@@ -575,8 +575,8 @@ impl<'source> Parser<'source> {
expr = Expr::ArithExpr {
span,
op,
lhs: Box::new(expr),
rhs: Box::new(right),
lhs: Ref::new(expr),
rhs: Ref::new(right),
};
}
}
@@ -599,8 +599,8 @@ impl<'source> Parser<'source> {
expr = Expr::ArithExpr {
span,
op,
lhs: Box::new(expr),
rhs: Box::new(right),
lhs: Ref::new(expr),
rhs: Ref::new(right),
};
}
}
@@ -618,8 +618,8 @@ impl<'source> Parser<'source> {
expr = Expr::BinExpr {
span,
op: BinOp::And,
lhs: Box::new(expr),
rhs: Box::new(right),
lhs: Ref::new(expr),
rhs: Ref::new(right),
};
}
Ok(expr)
@@ -638,8 +638,8 @@ impl<'source> Parser<'source> {
expr = Expr::BinExpr {
span,
op: BinOp::Or,
lhs: Box::new(expr),
rhs: Box::new(right),
lhs: Ref::new(expr),
rhs: Ref::new(right),
};
}
Ok(expr)
@@ -666,8 +666,8 @@ impl<'source> Parser<'source> {
expr = Expr::BoolExpr {
span,
op,
lhs: Box::new(expr),
rhs: Box::new(right),
lhs: Ref::new(expr),
rhs: Ref::new(right),
};
}
Ok(expr)
@@ -686,14 +686,14 @@ impl<'source> Parser<'source> {
let expr3 = self.parse_bool_expr()?;
span.end = self.end;
let (key, value) = match expr2 {
Some(e) => (Box::new(Some(expr1)), Box::new(e)),
None => (Box::new(None), Box::new(expr1)),
Some(e) => (Some(Ref::new(expr1)), Ref::new(e)),
None => (None, Ref::new(expr1)),
};
expr1 = Expr::Membership {
span,
key,
value,
collection: Box::new(expr3),
collection: Ref::new(expr3),
};
expr2 = None;
@@ -755,8 +755,8 @@ impl<'source> Parser<'source> {
Ok(Expr::AssignExpr {
span,
op,
lhs: Box::new(expr),
rhs: Box::new(right),
lhs: Ref::new(expr),
rhs: Ref::new(right),
})
}
@@ -769,7 +769,11 @@ impl<'source> Parser<'source> {
self.expect("as", "while parsing with-modifier expression")?;
let r#as = self.parse_in_expr()?;
span.end = self.end;
modifiers.push(WithModifier { span, refr, r#as });
modifiers.push(WithModifier {
span,
refr: Ref::new(refr),
r#as: Ref::new(r#as),
});
}
Ok(modifiers)
}
@@ -798,10 +802,10 @@ impl<'source> Parser<'source> {
};
self.parse_future_keyword("in", false, context)?;
let domain = self.parse_bool_expr()?;
let domain = Ref::new(self.parse_bool_expr()?);
let query_span = self.tok.1.clone();
self.expect("{", context)?;
let query = self.parse_query(query_span, "}")?;
let query = Ref::new(self.parse_query(query_span, "}")?);
span.end = self.end;
Ok(Literal::Every {
@@ -819,12 +823,12 @@ impl<'source> Parser<'source> {
// parse any vars.
let mut vars = vec![self.tok.1.clone()];
let mut refs = vec![self.parse_ref()?];
let mut refs = vec![Ref::new(self.parse_ref()?)];
while *self.tok.1.text() == "," {
self.next_token()?;
let mut span = self.tok.1.clone();
refs.push(self.parse_ref()?);
refs.push(Ref::new(self.parse_ref()?));
span.end = self.end;
vars.push(span);
}
@@ -836,7 +840,7 @@ impl<'source> Parser<'source> {
// All the refs must be identifiers
for (idx, ref_expr) in refs.iter().enumerate() {
let span = &vars[idx];
match ref_expr {
match ref_expr.as_ref() {
Expr::Var(_) => (),
_ => {
return Err(anyhow!(
@@ -870,7 +874,7 @@ impl<'source> Parser<'source> {
};
self.parse_future_keyword("in", false, "while parsing some-decl")?;
let collection = self.parse_bool_expr()?; // TODO: check this
let collection = Ref::new(self.parse_bool_expr()?); // TODO: check this
Ok(Literal::SomeIn {
span,
key,
@@ -898,7 +902,7 @@ impl<'source> Parser<'source> {
false
};
let expr = self.parse_assign_expr()?;
let expr = Ref::new(self.parse_assign_expr()?);
span.end = self.end;
if not_expr {
Ok(Literal::NotExpr { span, expr })
@@ -988,7 +992,7 @@ impl<'source> Parser<'source> {
_ => return Ok(None),
};
let expr = self.parse_membership_expr()?;
let expr = Ref::new(self.parse_membership_expr()?);
span.end = self.end;
Ok(Some(RuleAssign {
span,
@@ -1036,7 +1040,7 @@ impl<'source> Parser<'source> {
}
refr = Expr::RefDot {
span,
refr: Box::new(refr),
refr: Ref::new(refr),
field,
};
}
@@ -1057,8 +1061,8 @@ impl<'source> Parser<'source> {
span.end = self.end;
refr = Expr::RefBrack {
span,
refr: Box::new(refr),
index: Box::new(index),
refr: Ref::new(refr),
index: Ref::new(index),
};
}
_ => break,
@@ -1137,7 +1141,7 @@ impl<'source> Parser<'source> {
}
term = Expr::RefDot {
span,
refr: Box::new(term),
refr: Ref::new(term),
field,
};
}
@@ -1148,8 +1152,8 @@ impl<'source> Parser<'source> {
self.expect("]", "while parsing bracketed reference")?;
term = Expr::RefBrack {
span,
refr: Box::new(term),
index: Box::new(index),
refr: Ref::new(term),
index: Ref::new(index),
};
}
_ => break,
@@ -1162,20 +1166,20 @@ impl<'source> Parser<'source> {
pub fn parse_rule_head(&mut self) -> Result<RuleHead> {
let mut span = self.tok.1.clone();
let rule_ref = self.parse_rule_ref()?;
let rule_ref = Ref::new(self.parse_rule_ref()?);
match *self.tok.1.text() {
"(" => {
self.check_rule_ref(&rule_ref)?;
self.next_token()?;
let mut args = vec![];
if *self.tok.1.text() != ")" {
args.push(self.parse_term()?);
args.push(Ref::new(self.parse_term()?));
while *self.tok.1.text() == "," {
self.next_token()?;
match *self.tok.1.text() {
")" => break,
"" if self.tok.0 == TokenKind::Eof => break,
_ => args.push(self.parse_term()?),
_ => args.push(Ref::new(self.parse_term()?)),
}
}
}
@@ -1193,7 +1197,7 @@ impl<'source> Parser<'source> {
"contains" => {
self.check_rule_ref(&rule_ref)?;
self.next_token()?;
let key = self.parse_membership_expr()?;
let key = Ref::new(self.parse_membership_expr()?);
span.end = self.end;
Ok(RuleHead::Set {
span,
@@ -1206,7 +1210,7 @@ impl<'source> Parser<'source> {
span.end = self.end;
// Ensure that only the last term can be non-string.
match &rule_ref {
match rule_ref.as_ref() {
Expr::RefBrack { refr, .. } => self.check_rule_ref(refr)?,
Expr::RefDot { refr, .. } => self.check_rule_ref(refr)?,
_ => (),
@@ -1216,14 +1220,14 @@ impl<'source> Parser<'source> {
let is_set_follower = !self.is_keyword(*self.tok.1.text())
&& !self.is_imported_future_keyword(*self.tok.1.text());
if assign.is_none() && is_set_follower {
match &rule_ref {
match rule_ref.as_ref() {
Expr::RefBrack { refr, index, .. }
if matches!(refr.as_ref(), Expr::Var(_)) =>
{
return Ok(RuleHead::Set {
span,
refr: refr.as_ref().clone(),
key: Some(index.as_ref().clone()),
refr: refr.clone(),
key: Some(index.clone()),
});
}
Expr::RefDot { refr, .. } if matches!(refr.as_ref(), Expr::Var(_)) => {
@@ -1283,7 +1287,7 @@ impl<'source> Parser<'source> {
let has_query = match *self.tok.1.text() {
"if" if self.if_is_keyword() => {
self.next_token()?;
let query = self.parse_query_or_literal_stmt()?;
let query = Ref::new(self.parse_query_or_literal_stmt()?);
span.end = self.end;
bodies.push(RuleBody {
span,
@@ -1298,7 +1302,7 @@ impl<'source> Parser<'source> {
}
"{" => {
self.next_token()?;
let query = self.parse_query(span.clone(), "}")?;
let query = Ref::new(self.parse_query(span.clone(), "}")?);
span.end = self.end;
bodies.push(RuleBody {
span,
@@ -1323,7 +1327,7 @@ impl<'source> Parser<'source> {
while *self.tok.1.text() == "{" {
let mut span = self.tok.1.clone();
self.next_token()?;
let query = self.parse_query(span.clone(), "}")?;
let query = Ref::new(self.parse_query(span.clone(), "}")?);
span.end = self.end;
bodies.push(RuleBody {
span,
@@ -1355,7 +1359,7 @@ impl<'source> Parser<'source> {
match *self.tok.1.text() {
"if" if self.if_is_keyword() => {
self.next_token()?;
let query = self.parse_query_or_literal_stmt()?;
let query = Ref::new(self.parse_query_or_literal_stmt()?);
span.end = self.end;
bodies.push(RuleBody {
span,
@@ -1365,7 +1369,7 @@ impl<'source> Parser<'source> {
}
"{" => {
self.next_token()?;
let query = self.parse_query(span.clone(), "}")?;
let query = Ref::new(self.parse_query(span.clone(), "}")?);
span.end = self.end;
bodies.push(RuleBody {
span,
@@ -1392,7 +1396,7 @@ impl<'source> Parser<'source> {
pub fn parse_default_rule(&mut self) -> Result<Rule> {
let mut span = self.tok.1.clone();
self.expect("default", "while parsing default rule")?;
let rule_ref = self.parse_rule_ref()?;
let rule_ref = Ref::new(self.parse_rule_ref()?);
let op = match *self.tok.1.text() {
"=" => AssignOp::Eq,
@@ -1407,7 +1411,7 @@ impl<'source> Parser<'source> {
// todo: Rego errors for binary expressions here, but they are
// somehow valid in a comprehension
let value = self.parse_term()?;
let value = Ref::new(self.parse_term()?);
span.end = self.end;
Ok(Rule::Default {
span,
@@ -1437,7 +1441,10 @@ impl<'source> Parser<'source> {
self.expect("package", "Missing package declaration.")?;
let name = self.parse_path_ref()?;
span.end = self.end;
Ok(Package { span, refr: name })
Ok(Package {
span,
refr: Ref::new(name),
})
}
fn check_and_add_import(&self, import: Import, imports: &mut Vec<Import>) -> Result<()> {
@@ -1481,7 +1488,7 @@ impl<'source> Parser<'source> {
while *self.tok.1.text() == "import" {
let mut span = self.tok.1.clone();
self.next_token()?;
let refr = self.parse_path_ref()?;
let refr = Ref::new(self.parse_path_ref()?);
let comps = Self::get_path_ref_components(&refr)?;
if !matches!(*comps[0].text(), "data" | "future" | "input") {
@@ -1539,7 +1546,7 @@ impl<'source> Parser<'source> {
let mut policy = vec![];
while self.tok.0 != TokenKind::Eof {
policy.push(self.parse_rule()?);
policy.push(Ref::new(self.parse_rule()?));
}
Ok(Module {

View File

@@ -3,7 +3,7 @@
use crate::ast::Expr::*;
use crate::ast::*;
use crate::lexer::Span;
use crate::lexer::*;
use crate::utils::*;
use std::collections::{BTreeMap, BTreeSet, VecDeque};
@@ -12,22 +12,22 @@ use std::string::String;
use anyhow::{bail, Result};
#[derive(Debug)]
pub struct Definition<'a> {
pub struct Definition<Str: Clone + std::cmp::Ord> {
// The variable being defined.
// This can be an empty string to indicate that
// no variable is being defined.
pub var: &'a str,
pub var: Str,
// Other variables in the same scope used to compute
// the value of this variable.
pub used_vars: Vec<&'a str>,
pub used_vars: Vec<Str>,
}
#[derive(Debug)]
pub struct StmtInfo<'a> {
pub struct StmtInfo<Str: Clone + std::cmp::Ord> {
// A statement can define multiple variables.
// A variable can also be defined by multiple statement.
pub definitions: Vec<Definition<'a>>,
pub definitions: Vec<Definition<Str>>,
}
#[derive(Debug)]
@@ -38,17 +38,21 @@ pub enum SortResult {
Cycle(String, Vec<usize>),
}
pub fn schedule<'a>(infos: &mut [StmtInfo<'a>]) -> Result<SortResult> {
pub fn schedule<Str: Clone + std::cmp::Ord + std::fmt::Debug>(
infos: &mut [StmtInfo<Str>],
empty: &Str,
) -> Result<SortResult> {
let num_statements = infos.len();
// Mapping from each var to the list of statements that define it.
let mut defining_stmts: BTreeMap<&'a str, Vec<usize>> = BTreeMap::new();
let mut defining_stmts: BTreeMap<Str, Vec<usize>> = BTreeMap::new();
// For each statement, interate through its definitions and add the
// statement (index) to the var's defining-statements list.
for (idx, info) in infos.iter().enumerate() {
for defn in &info.definitions {
defining_stmts.entry(defn.var).or_default().push(idx);
let varc = defn.var.clone();
defining_stmts.entry(varc).or_default().push(idx);
}
}
@@ -63,7 +67,7 @@ pub fn schedule<'a>(infos: &mut [StmtInfo<'a>]) -> Result<SortResult> {
let mut scheduled = vec![false; infos.len()];
// List of vars to be processed.
let mut vars_to_process: Vec<&'a str> = defining_stmts.keys().cloned().collect();
let mut vars_to_process: Vec<Str> = defining_stmts.keys().cloned().collect();
let mut tmp = vec![];
let mut queue = VecDeque::new();
@@ -104,7 +108,7 @@ pub fn schedule<'a>(infos: &mut [StmtInfo<'a>]) -> Result<SortResult> {
.iter()
.all(|uv| defined_vars.contains(uv) || defined_in_stmt.contains(uv))
{
defined_in_stmt.insert(defn.var);
defined_in_stmt.insert(defn.var.clone());
} else {
// The definiton must be processed again.
queue.push_back(defn);
@@ -129,7 +133,7 @@ pub fn schedule<'a>(infos: &mut [StmtInfo<'a>]) -> Result<SortResult> {
// For each definition in the statement, mark its var as defined.
for defn in &infos[stmt_idx].definitions {
defined_vars.insert(defn.var);
defined_vars.insert(defn.var.clone());
}
Some(true)
} else {
@@ -167,7 +171,7 @@ pub fn schedule<'a>(infos: &mut [StmtInfo<'a>]) -> Result<SortResult> {
// Loop through each unscheduled var.
for var in tmp.iter().cloned() {
let (stmt_scheduled, reprocess_var) = process_var(var);
let (stmt_scheduled, reprocess_var) = process_var(var.clone());
if stmt_scheduled {
done = false;
@@ -177,7 +181,7 @@ pub fn schedule<'a>(infos: &mut [StmtInfo<'a>]) -> Result<SortResult> {
// to see if any statements that depend on var can be scheduled.
// Doing so allows statements like `x > 10` to be scheduled immediately after x has been defined.
// TODO: Also schedule statements like `y = x > 10` immediately.
process_var("");
process_var(empty.clone());
}
if reprocess_var {
@@ -187,7 +191,7 @@ pub fn schedule<'a>(infos: &mut [StmtInfo<'a>]) -> Result<SortResult> {
}
if order.len() != num_statements {
bail!("could not schedule all statements {order:?} {num_statements} {tmp:?}");
bail!("could not schedule all statements {order:?} {num_statements}");
}
// TODO: determine cycles.
@@ -195,16 +199,16 @@ pub fn schedule<'a>(infos: &mut [StmtInfo<'a>]) -> Result<SortResult> {
}
#[derive(Clone, Default, Debug)]
pub struct Scope<'a> {
pub locals: BTreeSet<&'a str>,
pub inputs: BTreeSet<&'a str>,
pub struct Scope {
pub locals: BTreeSet<SourceStr>,
pub inputs: BTreeSet<SourceStr>,
}
fn traverse<'a>(expr: &'a Expr, f: &mut dyn FnMut(&'a Expr) -> Result<bool>) -> Result<()> {
fn traverse(expr: &Ref<Expr>, f: &mut dyn FnMut(&Ref<Expr>) -> Result<bool>) -> Result<()> {
if !f(expr)? {
return Ok(());
}
match expr {
match expr.as_ref() {
String(_) | RawString(_) | Number(_) | True(_) | False(_) | Null(_) | Var(_) => (),
Array { items, .. } | Set { items, .. } => {
@@ -260,35 +264,35 @@ fn traverse<'a>(expr: &'a Expr, f: &mut dyn FnMut(&'a Expr) -> Result<bool>) ->
Ok(())
}
fn var_exists<'a>(name: &'a str, parent_scopes: &[Scope<'a>]) -> bool {
fn var_exists(name: &SourceStr, parent_scopes: &[Scope]) -> bool {
parent_scopes.iter().rev().any(|s| s.locals.contains(name))
}
fn gather_assigned_vars<'a>(
expr: &'a Expr,
fn gather_assigned_vars(
expr: &Ref<Expr>,
can_shadow: bool,
parent_scopes: &[Scope<'a>],
scope: &mut Scope<'a>,
parent_scopes: &[Scope],
scope: &mut Scope,
) -> Result<()> {
traverse(expr, &mut |e| match e {
traverse(expr, &mut |e| match e.as_ref() {
// Ignore _, input, data.
Var(v) if matches!(*v.text(), "_" | "input" | "data") => Ok(false),
// Record local var that can shadow input var.
Var(v) if can_shadow => {
scope.locals.insert(*v.text());
scope.locals.insert(v.source_str());
Ok(false)
}
// Record input vars.
Var(v) if var_exists(*v.text(), parent_scopes) => {
scope.inputs.insert(*v.text());
Var(v) if var_exists(&v.source_str(), parent_scopes) => {
scope.inputs.insert(v.source_str());
Ok(false)
}
// Record local var.
Var(v) => {
scope.locals.insert(*v.text());
scope.locals.insert(v.source_str());
Ok(false)
}
@@ -298,16 +302,12 @@ fn gather_assigned_vars<'a>(
})
}
fn gather_input_vars<'a>(
expr: &'a Expr,
parent_scopes: &[Scope<'a>],
scope: &mut Scope<'a>,
) -> Result<()> {
traverse(expr, &mut |e| match e {
Var(v) if var_exists(*v.text(), parent_scopes) => {
let var = v.text();
if !scope.locals.contains(&*var) {
scope.inputs.insert(*var);
fn gather_input_vars(expr: &Ref<Expr>, parent_scopes: &[Scope], scope: &mut Scope) -> Result<()> {
traverse(expr, &mut |e| match e.as_ref() {
Var(v) if var_exists(&v.source_str(), parent_scopes) => {
let var = v.source_str();
if !scope.locals.contains(&var) {
scope.inputs.insert(var);
}
Ok(false)
}
@@ -315,20 +315,16 @@ fn gather_input_vars<'a>(
})
}
fn gather_loop_vars<'a>(
expr: &'a Expr,
parent_scopes: &[Scope<'a>],
scope: &mut Scope<'a>,
) -> Result<()> {
traverse(expr, &mut |e| match e {
Var(v) if var_exists(*v.text(), parent_scopes) => Ok(false),
fn gather_loop_vars(expr: &Ref<Expr>, parent_scopes: &[Scope], scope: &mut Scope) -> Result<()> {
traverse(expr, &mut |e| match e.as_ref() {
Var(v) if var_exists(&v.source_str(), parent_scopes) => Ok(false),
RefBrack { index, .. } => {
if let Var(v) = index.as_ref() {
if !matches!(*v.text(), "_" | "input" | "data")
&& !var_exists(*v.text(), parent_scopes)
&& !var_exists(&v.source_str(), parent_scopes)
{
// Treat this as an index var.
scope.locals.insert(*v.text());
scope.locals.insert(v.source_str());
}
}
Ok(true)
@@ -343,15 +339,15 @@ fn gather_loop_vars<'a>(
// t = {"k": 5}
// {k:y} = t
// Try inlining value of t
fn gather_vars<'a>(
expr: &'a Expr,
fn gather_vars(
expr: &Ref<Expr>,
can_shadow: bool,
parent_scopes: &[Scope<'a>],
scope: &mut Scope<'a>,
parent_scopes: &[Scope],
scope: &mut Scope,
) -> Result<()> {
// Process assignment expressions to gather vars that are defined/assigned
// in current scope.
if let AssignExpr { op, lhs, rhs, .. } = expr {
if let AssignExpr { op, lhs, rhs, .. } = expr.as_ref() {
gather_assigned_vars(lhs, *op == AssignOp::ColEq, parent_scopes, scope)?;
gather_assigned_vars(rhs, false, parent_scopes, scope)?;
} else {
@@ -364,29 +360,29 @@ fn gather_vars<'a>(
gather_loop_vars(expr, parent_scopes, scope)
}
pub struct Analyzer<'a> {
packages: BTreeMap<String, Scope<'a>>,
locals: BTreeMap<Ref<'a, Query>, Scope<'a>>,
scopes: Vec<Scope<'a>>,
order: BTreeMap<Ref<'a, Query>, Vec<u16>>,
functions: FunctionTable<'a>,
pub struct Analyzer {
packages: BTreeMap<String, Scope>,
locals: BTreeMap<Ref<Query>, Scope>,
scopes: Vec<Scope>,
order: BTreeMap<Ref<Query>, Vec<u16>>,
functions: FunctionTable,
current_module_path: String,
}
#[derive(Clone)]
pub struct Schedule<'a> {
pub scopes: BTreeMap<Ref<'a, Query>, Scope<'a>>,
pub order: BTreeMap<Ref<'a, Query>, Vec<u16>>,
pub struct Schedule {
pub scopes: BTreeMap<Ref<Query>, Scope>,
pub order: BTreeMap<Ref<Query>, Vec<u16>>,
}
impl<'a> Default for Analyzer<'a> {
impl Default for Analyzer {
fn default() -> Self {
Self::new()
}
}
impl<'a> Analyzer<'a> {
pub fn new() -> Analyzer<'a> {
impl Analyzer {
pub fn new() -> Analyzer {
Analyzer {
packages: BTreeMap::new(),
locals: BTreeMap::new(),
@@ -397,7 +393,7 @@ impl<'a> Analyzer<'a> {
}
}
pub fn analyze(mut self, modules: &'a [&'a Module]) -> Result<Schedule> {
pub fn analyze(mut self, modules: &[Ref<Module>]) -> Result<Schedule> {
self.add_rules(modules)?;
self.functions = gather_functions(modules)?;
@@ -413,9 +409,9 @@ impl<'a> Analyzer<'a> {
pub fn analyze_query_snippet(
mut self,
modules: &'a [&'a Module],
query: &'a Query,
) -> Result<Schedule<'a>> {
modules: &[Ref<Module>],
query: &Ref<Query>,
) -> Result<Schedule> {
self.add_rules(modules)?;
self.analyze_query(None, None, query, Scope::default())?;
@@ -425,12 +421,12 @@ impl<'a> Analyzer<'a> {
})
}
fn add_rules(&mut self, modules: &'a [&'a Module]) -> Result<()> {
fn add_rules(&mut self, modules: &[Ref<Module>]) -> Result<()> {
for m in modules {
let path = get_path_string(&m.package.refr, Some("data"))?;
let scope: &mut Scope = self.packages.entry(path).or_default();
for r in &m.policy {
let var = match r {
let var = match r.as_ref() {
Rule::Default { refr, .. }
| Rule::Spec {
head:
@@ -447,7 +443,7 @@ impl<'a> Analyzer<'a> {
Ok(())
}
fn analyze_module(&mut self, m: &'a Module) -> Result<()> {
fn analyze_module(&mut self, m: &Module) -> Result<()> {
let path = get_path_string(&m.package.refr, Some("data"))?;
let scope = match self.packages.get(&path) {
Some(s) => s,
@@ -463,8 +459,8 @@ impl<'a> Analyzer<'a> {
Ok(())
}
fn analyze_rule(&mut self, r: &'a Rule) -> Result<()> {
match r {
fn analyze_rule(&mut self, r: &Ref<Rule>) -> Result<()> {
match r.as_ref() {
Rule::Spec { head, bodies, .. } => {
let (key, value, scope) = self.analyze_rule_head(head)?;
// Push arg scope if any.
@@ -472,12 +468,12 @@ impl<'a> Analyzer<'a> {
// scheduling.
self.scopes.push(scope);
for b in bodies {
self.analyze_query(key, value, &b.query, Scope::default())?;
self.analyze_query(key.clone(), value.clone(), &b.query, Scope::default())?;
}
if bodies.is_empty() {
if let Some(value) = value {
self.analyze_value_expr(value)?;
self.analyze_value_expr(&value)?;
}
}
@@ -488,25 +484,25 @@ impl<'a> Analyzer<'a> {
}
}
fn analyze_value_expr(&mut self, expr: &'a Expr) -> Result<()> {
fn analyze_value_expr(&mut self, expr: &Ref<Expr>) -> Result<()> {
let mut comprs = vec![];
traverse(expr, &mut |e| match e {
traverse(expr, &mut |e| match e.as_ref() {
ArrayCompr { .. } | SetCompr { .. } | ObjectCompr { .. } => {
comprs.push(e);
comprs.push(e.clone());
Ok(false)
}
_ => Ok(true),
})?;
for compr in comprs {
match compr {
match compr.as_ref() {
Expr::ArrayCompr { query, term, .. } | Expr::SetCompr { query, term, .. } => {
self.analyze_query(None, Some(term), query, Scope::default())?;
self.analyze_query(None, Some(term.clone()), query, Scope::default())?;
}
Expr::ObjectCompr {
query, key, value, ..
} => self.analyze_query(
Some(key.as_ref()),
Some(value.as_ref()),
Some(key.clone()),
Some(value.clone()),
query,
Scope::default(),
)?,
@@ -518,35 +514,37 @@ impl<'a> Analyzer<'a> {
fn analyze_rule_head(
&mut self,
head: &'a RuleHead,
) -> Result<(Option<&'a Expr>, Option<&'a Expr>, Scope<'a>)> {
head: &RuleHead,
) -> Result<(Option<ExprRef>, Option<ExprRef>, Scope)> {
let mut scope = Scope::default();
Ok(match head {
RuleHead::Compr { assign, .. } => (None, assign.as_ref().map(|a| &a.value), scope),
RuleHead::Set { key, .. } => (key.as_ref(), None, scope),
RuleHead::Compr { assign, .. } => {
(None, assign.as_ref().map(|a| a.value.clone()), scope)
}
RuleHead::Set { key, .. } => (key.clone(), None, scope),
RuleHead::Func { args, assign, .. } => {
for a in args.iter() {
if let Var(v) = a {
scope.locals.insert(*v.text());
if let Var(v) = a.as_ref() {
scope.locals.insert(v.source_str());
}
}
(None, assign.as_ref().map(|a| &a.value), scope)
(None, assign.as_ref().map(|a| a.value.clone()), scope)
}
})
}
fn gather_local_vars(
&mut self,
key: Option<&'a Expr>,
value: Option<&'a Expr>,
query: &'a Query,
scope: &mut Scope<'a>,
key: Option<Ref<Expr>>,
value: Option<Ref<Expr>>,
query: &Query,
scope: &mut Scope,
) -> Result<()> {
// First process assign, some expressions and gather local vars.
for stmt in &query.stmts {
match &stmt.literal {
Literal::SomeVars { vars, .. } => vars.iter().for_each(|v| {
scope.locals.insert(*v.text());
scope.locals.insert(v.source_str());
}),
Literal::SomeIn {
key,
@@ -562,7 +560,7 @@ impl<'a> Analyzer<'a> {
gather_loop_vars(collection, &self.scopes, scope)?;
}
Literal::Expr { expr, .. } | Literal::NotExpr { expr, .. } => {
if let AssignExpr { .. } = expr {
if let AssignExpr { .. } = expr.as_ref() {
gather_vars(expr, false, &self.scopes, scope)?;
} else {
gather_input_vars(expr, &self.scopes, scope)?;
@@ -577,10 +575,10 @@ impl<'a> Analyzer<'a> {
}
}
if let Some(key) = key {
if let Some(key) = &key {
gather_vars(key, false, &self.scopes, scope)?;
}
if let Some(value) = value {
if let Some(value) = &value {
gather_vars(value, false, &self.scopes, scope)?;
}
@@ -593,23 +591,23 @@ impl<'a> Analyzer<'a> {
}
fn gather_used_vars_comprs_index_vars(
expr: &'a Expr,
scope: &mut Scope<'a>,
first_use: &mut BTreeMap<&'a str, Span>,
definitions: &mut Vec<Definition<'a>>,
expr: &Ref<Expr>,
scope: &mut Scope,
first_use: &mut BTreeMap<SourceStr, Span>,
definitions: &mut Vec<Definition<SourceStr>>,
return_arg: &Option<Ref<Expr>>,
) -> Result<(Vec<&'a str>, Vec<&'a Expr>)> {
) -> Result<(Vec<SourceStr>, Vec<Ref<Expr>>)> {
let mut used_vars = vec![];
let mut comprs = vec![];
traverse(expr, &mut |e| match e {
traverse(expr, &mut |e| match e.as_ref() {
Var(v) if !matches!(*v.text(), "_" | "input" | "data") => {
let name = *v.text();
if scope.locals.contains(name)
let name = v.source_str();
if scope.locals.contains(&name)
/*|| scope.inputs.contains(name) */
{
used_vars.push(name);
used_vars.push(name.clone());
first_use.entry(name).or_insert(v.clone());
} else if !scope.inputs.contains(name) && Some(Ref::make(e)) != *return_arg {
} else if !scope.inputs.contains(&name) && Some(e.clone()) != *return_arg {
bail!(v.error(format!("use of undefined variable `{name}` is unsafe").as_str()));
}
Ok(false)
@@ -617,8 +615,8 @@ impl<'a> Analyzer<'a> {
RefBrack { refr, index, .. } => {
if let Var(v) = index.as_ref() {
let var = *v.text();
if scope.locals.contains(var) {
let var = v.source_str();
if scope.locals.contains(&var) {
let (rb_used_vars, rb_comprs) = Self::gather_used_vars_comprs_index_vars(
refr,
scope,
@@ -627,7 +625,7 @@ impl<'a> Analyzer<'a> {
return_arg,
)?;
definitions.push(Definition {
var,
var: var.clone(),
used_vars: rb_used_vars.clone(),
});
used_vars.extend(rb_used_vars);
@@ -640,7 +638,7 @@ impl<'a> Analyzer<'a> {
}
ArrayCompr { .. } | SetCompr { .. } | ObjectCompr { .. } => {
comprs.push(e);
comprs.push(e.clone());
Ok(false)
}
@@ -651,29 +649,29 @@ impl<'a> Analyzer<'a> {
fn process_comprs(
&mut self,
comprs: &[&'a Expr],
scope: &mut Scope<'a>,
first_use: &mut BTreeMap<&'a str, Span>,
used_vars: &mut Vec<&'a str>,
comprs: &[Ref<Expr>],
scope: &mut Scope,
first_use: &mut BTreeMap<SourceStr, Span>,
used_vars: &mut Vec<SourceStr>,
) -> Result<()> {
self.scopes.push(scope.clone());
for compr in comprs {
let compr_scope = match compr {
let compr_scope = match compr.as_ref() {
Expr::ArrayCompr { query, term, .. } | Expr::SetCompr { query, term, .. } => {
self.analyze_query(None, Some(term), query, Scope::default())?;
self.locals.get(&Ref::make(query))
self.analyze_query(None, Some(term.clone()), query, Scope::default())?;
self.locals.get(query)
}
Expr::ObjectCompr {
query, key, value, ..
} => {
self.analyze_query(
Some(key.as_ref()),
Some(value.as_ref()),
Some(key.clone()),
Some(value.clone()),
query,
Scope::default(),
)?;
self.locals.get(&Ref::make(query))
self.locals.get(query)
}
_ => break,
};
@@ -683,11 +681,11 @@ impl<'a> Analyzer<'a> {
for iv in &compr_scope.inputs {
if scope.locals.contains(iv) {
// Record possible first use of current scope's local var.
first_use.entry(iv).or_insert(compr.span().clone());
used_vars.push(iv);
first_use.entry(iv.clone()).or_insert(compr.span().clone());
used_vars.push(iv.clone());
} else {
// If the var is not a local var, then add it to the set of input vars.
scope.inputs.insert(iv);
scope.inputs.insert(iv.clone());
}
}
}
@@ -699,16 +697,16 @@ impl<'a> Analyzer<'a> {
fn gather_assigned_vars(
&self,
expr: &'a Expr,
scope: &Scope<'a>,
expr: &Ref<Expr>,
scope: &Scope,
check_first_use: bool,
first_use: &BTreeMap<&'a str, Span>,
) -> Result<Vec<&'a str>> {
first_use: &BTreeMap<SourceStr, Span>,
) -> Result<Vec<SourceStr>> {
let mut vars = vec![];
traverse(expr, &mut |e| match e {
traverse(expr, &mut |e| match e.as_ref() {
Var(v) => {
let var = *v.text();
if scope.locals.contains(var) {
let var = v.source_str();
if scope.locals.contains(&var) {
if check_first_use {
Self::check_first_use(v, first_use)?;
}
@@ -726,13 +724,14 @@ impl<'a> Analyzer<'a> {
fn process_assign_expr(
&mut self,
op: &AssignOp,
lhs: &'a Expr,
rhs: &'a Expr,
scope: &mut Scope<'a>,
first_use: &mut BTreeMap<&'a str, Span>,
definitions: &mut Vec<Definition<'a>>,
lhs: &Ref<Expr>,
rhs: &Ref<Expr>,
scope: &mut Scope,
first_use: &mut BTreeMap<SourceStr, Span>,
definitions: &mut Vec<Definition<SourceStr>>,
) -> Result<()> {
match (lhs, rhs) {
let empty_str = lhs.span().source_str().clone_empty();
match (lhs.as_ref(), rhs.as_ref()) {
(
Array {
items: lhs_items, ..
@@ -775,13 +774,13 @@ impl<'a> Analyzer<'a> {
for var in &assigned_vars {
definitions.push(Definition {
var,
var: var.clone(),
used_vars: used_vars.clone(),
});
}
if assigned_vars.is_empty() {
definitions.push(Definition {
var: "",
var: empty_str.clone(),
used_vars: used_vars.clone(),
});
}
@@ -800,13 +799,13 @@ impl<'a> Analyzer<'a> {
self.gather_assigned_vars(rhs, scope, check_first_use, first_use)?;
for var in &assigned_vars {
definitions.push(Definition {
var,
var: var.clone(),
used_vars: used_vars.clone(),
});
}
if assigned_vars.is_empty() {
definitions.push(Definition {
var: "",
var: empty_str.clone(),
used_vars: used_vars.clone(),
});
}
@@ -819,12 +818,12 @@ impl<'a> Analyzer<'a> {
fn process_expr(
&mut self,
expr: &'a Expr,
scope: &mut Scope<'a>,
first_use: &mut BTreeMap<&'a str, Span>,
definitions: &mut Vec<Definition<'a>>,
expr: &Ref<Expr>,
scope: &mut Scope,
first_use: &mut BTreeMap<SourceStr, Span>,
definitions: &mut Vec<Definition<SourceStr>>,
) -> Result<()> {
match expr {
match expr.as_ref() {
AssignExpr { op, lhs, rhs, .. } => {
self.process_assign_expr(op, lhs, rhs, scope, first_use, definitions)
}
@@ -837,15 +836,18 @@ impl<'a> Analyzer<'a> {
&None,
)?;
self.process_comprs(&comprs[..], scope, first_use, &mut used_vars)?;
definitions.push(Definition { var: "", used_vars });
definitions.push(Definition {
var: expr.span().source_str().clone(),
used_vars,
});
Ok(())
}
}
}
fn check_first_use(var: &Span, first_use: &BTreeMap<&'a str, Span>) -> Result<()> {
let name = *var.text();
if let Some(r#use) = first_use.get(name) {
fn check_first_use(var: &Span, first_use: &BTreeMap<SourceStr, Span>) -> Result<()> {
let name = var.source_str();
if let Some(r#use) = first_use.get(&name) {
if r#use.line < var.line || (r#use.line == var.line && r#use.col < var.col) {
bail!(r#use.error(
format!(
@@ -860,21 +862,21 @@ impl<'a> Analyzer<'a> {
}
fn gather_some_vars(
expr: &'a Expr,
scope: &Scope<'a>,
_first_use: &BTreeMap<&'a str, Span>,
vars: &mut Vec<&'a str>,
non_vars: &mut Vec<&'a Expr>,
expr: &Ref<Expr>,
scope: &Scope,
_first_use: &BTreeMap<SourceStr, Span>,
vars: &mut Vec<SourceStr>,
non_vars: &mut Vec<Ref<Expr>>,
) -> Result<()> {
traverse(expr, &mut |e| match e {
Var(v) if scope.locals.contains(*v.text()) => {
vars.push(*v.text());
traverse(expr, &mut |e| match e.as_ref() {
Var(v) if scope.locals.contains(&v.source_str()) => {
vars.push(v.source_str());
Ok(false)
}
// TODO: Object key/value
Array { .. } | Object { .. } => Ok(true),
_ => {
non_vars.push(e);
non_vars.push(e.clone());
Ok(false)
}
})
@@ -882,11 +884,12 @@ impl<'a> Analyzer<'a> {
fn analyze_query(
&mut self,
key: Option<&'a Expr>,
value: Option<&'a Expr>,
query: &'a Query,
mut scope: Scope<'a>,
key: Option<Ref<Expr>>,
value: Option<Ref<Expr>>,
query: &Ref<Query>,
mut scope: Scope,
) -> Result<()> {
let empty_str = query.span.source_str().clone_empty();
self.gather_local_vars(key, value, query, &mut scope)?;
let mut infos = vec![];
@@ -945,7 +948,7 @@ impl<'a> Analyzer<'a> {
// Add dependency between some-vars and vars used in collection.
for var in &some_vars {
definitions.push(Definition {
var,
var: var.clone(),
used_vars: col_used_vars.clone(),
})
}
@@ -954,7 +957,7 @@ impl<'a> Analyzer<'a> {
for e in non_vars {
let mut definitions = vec![];
let (uv, comprs) = Self::gather_used_vars_comprs_index_vars(
e,
&e,
&mut scope,
&mut first_use,
&mut definitions,
@@ -971,7 +974,10 @@ impl<'a> Analyzer<'a> {
&mut used_vars,
)?;
}
definitions.push(Definition { var: "", used_vars });
definitions.push(Definition {
var: empty_str.clone(),
used_vars,
});
// TODO: vars in compr
}
Literal::Expr { expr, .. } => {
@@ -980,33 +986,32 @@ impl<'a> Analyzer<'a> {
Some(self.current_module_path.as_str()),
&self.functions,
);
if let Some(ra @ Expr::Var(return_arg)) = &extra_arg {
let (mut used_vars, comprs) = Self::gather_used_vars_comprs_index_vars(
expr,
&mut scope,
&mut first_use,
&mut definitions,
&Some(Ref::make(ra)),
)?;
let var = if *return_arg.text() != "_" {
// The var in the return argument slot would have been processed as
// an used var. Remove it from used vars and add it as the variable being
// defined.
used_vars.pop();
return_arg.text()
} else {
std::rc::Rc::new("")
};
self.process_comprs(
&comprs[..],
&mut scope,
&mut first_use,
&mut used_vars,
)?;
definitions.push(Definition {
var: *var,
used_vars,
});
if let Some(ref ea) = extra_arg {
if let Expr::Var(return_arg) = ea.as_ref() {
let (mut used_vars, comprs) = Self::gather_used_vars_comprs_index_vars(
expr,
&mut scope,
&mut first_use,
&mut definitions,
&extra_arg,
)?;
let var = if *return_arg.text() != "_" {
// The var in the return argument slot would have been processed as
// an used var. Remove it from used vars and add it as the variable being
// defined.
used_vars.pop();
return_arg.source_str()
} else {
empty_str.clone()
};
self.process_comprs(
&comprs[..],
&mut scope,
&mut first_use,
&mut used_vars,
)?;
definitions.push(Definition { var, used_vars });
}
} else {
self.process_expr(expr, &mut scope, &mut first_use, &mut definitions)?;
}
@@ -1031,16 +1036,16 @@ impl<'a> Analyzer<'a> {
)?;
self.process_comprs(&comprs[..], &mut scope, &mut first_use, &mut uv)?;
definitions.push(Definition {
var: "",
var: empty_str.clone(),
used_vars: uv,
});
self.scopes.push(scope.clone());
let mut e_scope = Scope::default();
if let Some(key) = key {
e_scope.locals.insert(*key.text());
e_scope.locals.insert(key.source_str());
}
e_scope.locals.insert(*value.text());
e_scope.locals.insert(value.source_str());
self.scopes.push(e_scope);
// TODO: mark first use of key, value so that they cannot be := assigned
@@ -1057,24 +1062,24 @@ impl<'a> Analyzer<'a> {
// binding the "" var so that these statements get scheduled first.
if definitions.is_empty() {
definitions.push(Definition {
var: "",
var: empty_str.clone(),
used_vars: vec![],
});
}
infos.push(StmtInfo { definitions });
}
let res = schedule(&mut infos[..]);
let res = schedule(&mut infos[..], &query.span.source_str().clone_empty());
match res {
Ok(SortResult::Order(ord)) => {
self.order.insert(Ref::make(query), ord);
self.order.insert(query.clone(), ord);
}
Err(err) => {
bail!(query.span.error(&err.to_string()))
}
_ => (),
}
self.locals.insert(Ref::make(query), scope);
self.locals.insert(query.clone(), scope);
Ok(())
}

View File

@@ -3,6 +3,7 @@
use crate::ast::*;
use crate::builtins::*;
use crate::lexer::*;
use std::collections::BTreeMap;
@@ -37,13 +38,13 @@ pub fn get_path_string(refr: &Expr, document: Option<&str>) -> Result<String> {
Ok(comps.join("."))
}
pub type FunctionTable<'a> = BTreeMap<String, (Vec<&'a Rule>, u8)>;
pub type FunctionTable = BTreeMap<String, (Vec<Ref<Rule>>, u8)>;
fn get_extra_arg_impl<'a>(
expr: &'a Expr,
fn get_extra_arg_impl(
expr: &Expr,
module: Option<&str>,
functions: &FunctionTable,
) -> Result<Option<&'a Expr>> {
) -> Result<Option<Ref<Expr>>> {
if let Expr::Call { fcn, params, .. } = expr {
let full_path = get_path_string(fcn, module)?;
let n_args = if let Some((_, n_args)) = functions.get(&full_path) {
@@ -59,24 +60,24 @@ fn get_extra_arg_impl<'a>(
}
};
if (n_args as usize) + 1 == params.len() {
return Ok(params.last());
return Ok(params.last().cloned());
}
}
Ok(None)
}
pub fn get_extra_arg<'a>(
expr: &'a Expr,
pub fn get_extra_arg(
expr: &Expr,
module: Option<&str>,
functions: &FunctionTable,
) -> Option<&'a Expr> {
) -> Option<Ref<Expr>> {
match get_extra_arg_impl(expr, module, functions) {
Ok(a) => a,
_ => None,
}
}
pub fn gather_functions<'a>(modules: &[&'a Module]) -> Result<FunctionTable<'a>> {
pub fn gather_functions(modules: &[Ref<Module>]) -> Result<FunctionTable> {
let mut table = FunctionTable::new();
for module in modules {
@@ -86,7 +87,7 @@ pub fn gather_functions<'a>(modules: &[&'a Module]) -> Result<FunctionTable<'a>>
span,
head: RuleHead::Func { refr, args, .. },
..
} = rule
} = rule.as_ref()
{
let full_path = get_path_string(refr, Some(module_path.as_str()))?;
@@ -97,9 +98,9 @@ pub fn gather_functions<'a>(modules: &[&'a Module]) -> Result<FunctionTable<'a>>
.as_str()
));
}
functions.push(rule);
functions.push(rule.clone());
} else {
table.insert(full_path, (vec![rule], args.len() as u8));
table.insert(full_path, (vec![rule.clone()], args.len() as u8));
}
}
}
@@ -107,10 +108,10 @@ pub fn gather_functions<'a>(modules: &[&'a Module]) -> Result<FunctionTable<'a>>
Ok(table)
}
pub fn get_root_var(mut expr: &Expr) -> Result<&str> {
pub fn get_root_var(mut expr: &Expr) -> Result<SourceStr> {
loop {
match expr {
Expr::Var(v) => return Ok(*v.text()),
Expr::Var(v) => return Ok(v.source_str()),
Expr::RefDot { refr, .. } | Expr::RefBrack { refr, .. } => expr = refr,
_ => bail!("internal error: analyzer: could not get rule prefix"),
}

View File

@@ -196,7 +196,6 @@ pub fn eval_file(
let mut files = vec![];
let mut sources = vec![];
let mut modules = vec![];
let mut modules_ref = vec![];
for (idx, _) in regos.iter().enumerate() {
files.push(format!("rego_{idx}"));
@@ -209,11 +208,7 @@ pub fn eval_file(
for source in &sources {
let mut parser = Parser::new(source)?;
modules.push(parser.parse()?);
}
for m in &modules {
modules_ref.push(m);
modules.push(Ref::new(parser.parse()?));
}
let query_source = regorus::Source::new("<query.rego".to_string(), query.to_string());
@@ -225,14 +220,13 @@ pub fn eval_file(
end: query.len() as u16,
};
let mut parser = regorus::Parser::new(&query_source)?;
let query_node = parser.parse_query(query_span, "")?;
let query_schedule =
regorus::Analyzer::new().analyze_query_snippet(&modules_ref, &query_node)?;
let query_node = Ref::new(parser.parse_query(query_span, "")?);
let query_schedule = regorus::Analyzer::new().analyze_query_snippet(&modules, &query_node)?;
let analyzer = Analyzer::new();
let schedule = analyzer.analyze(&modules_ref)?;
let schedule = analyzer.analyze(&modules)?;
let mut interpreter = interpreter::Interpreter::new(&modules_ref)?;
let mut interpreter = interpreter::Interpreter::new(&modules)?;
if let Some(input) = input_opt {
// if inputs are defined then first the evaluation if prepared
interpreter.prepare_for_eval(Some(schedule), &data_opt)?;

View File

@@ -56,7 +56,7 @@ fn match_span_opt(s: &Span, v: &Value) -> Result<()> {
}
}
fn match_vec(s: &Span, vec: &Vec<Expr>, v: &Value) -> Result<()> {
fn match_vec(s: &Span, vec: &Vec<Ref<Expr>>, v: &Value) -> Result<()> {
if v.as_object().is_ok() {
match_span_opt(s, &v["span"])?;
return match_vec(s, vec, &v["values"]);
@@ -79,7 +79,7 @@ fn match_vec(s: &Span, vec: &Vec<Expr>, v: &Value) -> Result<()> {
Ok(())
}
fn match_object(s: &Span, fields: &Vec<(Span, Expr, Expr)>, v: &Value) -> Result<()> {
fn match_object(s: &Span, fields: &Vec<(Span, Ref<Expr>, Ref<Expr>)>, v: &Value) -> Result<()> {
if skip_value(v) {
return Ok(());
}
@@ -299,7 +299,7 @@ fn match_query(q: &Query, v: &Value) -> Result<()> {
Ok(())
}
fn match_expr_opt(s: &Span, e: &Option<Expr>, v: &Value) -> Result<()> {
fn match_expr_opt(s: &Span, e: &Option<Ref<Expr>>, v: &Value) -> Result<()> {
match (e, v) {
(Some(e), v) => match_expr(e, v),
(None, Value::Undefined) => Ok(()),

View File

@@ -27,7 +27,7 @@ struct YamlTest {
cases: Vec<TestCase>,
}
fn to_string_set(s: &BTreeSet<&str>) -> BTreeSet<String> {
fn to_string_set(s: &BTreeSet<SourceStr>) -> BTreeSet<String> {
s.iter().map(|s| s.to_string()).collect()
}
@@ -40,16 +40,15 @@ fn analyze_file(regos: &[String], expected_scopes: &[Scope]) -> Result<()> {
for source in &sources {
let mut parser = Parser::new(source)?;
modules.push(parser.parse()?);
modules.push(Ref::new(parser.parse()?));
}
let modules_ref: Vec<&Module> = modules.iter().collect();
let analyzer = Analyzer::new();
let schedule = analyzer.analyze(&modules_ref)?;
let mut scopes: Vec<(&Query, &regorus::Scope)> = schedule
let schedule = analyzer.analyze(&modules)?;
let mut scopes: Vec<(Ref<Query>, &regorus::Scope)> = schedule
.scopes
.iter()
.map(|(r, s)| (r.inner(), s))
.map(|(r, s)| (r.clone(), s))
.collect();
scopes.sort_by(|a, b| a.0.span.line.cmp(&b.0.span.line));
for (idx, (_, scope)) in scopes.iter().enumerate() {

View File

@@ -7,7 +7,7 @@ use regorus::scheduler::*;
mod analyzer;
fn make_info<'a>(definitions: &[(&'a str, &[&'a str])]) -> StmtInfo<'a> {
fn make_info(definitions: &[(&'static str, &[&'static str])]) -> StmtInfo<&'static str> {
StmtInfo {
definitions: definitions
.iter()
@@ -29,6 +29,9 @@ fn check_result(stmts: &[&str], expected: &[&str], r: SortResult) -> Result<()>
match r {
SortResult::Order(order) => {
print_stmts(stmts, &order);
for (i, o) in order.iter().cloned().enumerate() {
println!("{:30}{}", stmts[o as usize], expected[i]);
}
for (i, o) in order.iter().cloned().enumerate() {
assert_eq!(stmts[o as usize], expected[i]);
}
@@ -69,8 +72,7 @@ fn case1() -> Result<()> {
make_info(&[("x", &[])]),
make_info(&[("v", &[])]),
];
check_result(&stmts[..], &expected[..], schedule(&mut infos)?)
check_result(&stmts[..], &expected[..], schedule(&mut infos, &"")?)
}
#[test]
@@ -92,7 +94,7 @@ fn case2() -> Result<()> {
make_info(&[("y", &[])]),
];
check_result(&stmts[..], &expected[..], schedule(&mut infos)?)
check_result(&stmts[..], &expected[..], schedule(&mut infos, &"")?)
}
#[test]
@@ -115,7 +117,7 @@ fn case2_rewritten() -> Result<()> {
make_info(&[("y", &[])]),
];
check_result(&stmts[..], &expected[..], schedule(&mut infos)?)
check_result(&stmts[..], &expected[..], schedule(&mut infos, &"")?)
}
#[test]
@@ -139,7 +141,7 @@ fn case3() -> Result<()> {
make_info(&[("y", &[])]),
];
check_result(&stmts[..], &expected[..], schedule(&mut infos)?)
check_result(&stmts[..], &expected[..], schedule(&mut infos, &"")?)
}
#[test]
@@ -163,7 +165,7 @@ fn case4_cycle() -> Result<()> {
];
// TODO: check cycle
check_result(&stmts[..], &expected[..], schedule(&mut infos)?)
check_result(&stmts[..], &expected[..], schedule(&mut infos, &"")?)
}
#[test]
@@ -186,7 +188,7 @@ fn case4_no_cycle() -> Result<()> {
];
// TODO: check cycle
check_result(&stmts[..], &expected[..], schedule(&mut infos)?)
check_result(&stmts[..], &expected[..], schedule(&mut infos, &"")?)
}
#[test]
@@ -215,5 +217,5 @@ fn case4_cycle_removed_via_split_multi_assign() -> Result<()> {
];
// TODO: check cycle
check_result(&stmts[..], &expected[..], schedule(&mut infos)?)
check_result(&stmts[..], &expected[..], schedule(&mut infos, &"")?)
}