mirror of
https://github.com/microsoft/regorus.git
synced 2026-08-05 02:16:11 +00:00
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:
committed by
GitHub
parent
a1d0f8576a
commit
72070a7061
3
.gitignore
vendored
3
.gitignore
vendored
@@ -8,3 +8,6 @@ Cargo.lock
|
||||
|
||||
# These are backup files generated by rustfmt
|
||||
**/*.rs.bk
|
||||
|
||||
# vscode files
|
||||
.vscode/
|
||||
217
src/ast.rs
217
src/ast.rs
@@ -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>;
|
||||
|
||||
@@ -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;
|
||||
|
||||
@@ -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, ¶ms[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)?;
|
||||
|
||||
|
||||
@@ -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)?;
|
||||
|
||||
|
||||
@@ -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)?;
|
||||
|
||||
|
||||
@@ -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"));
|
||||
}
|
||||
|
||||
@@ -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] {
|
||||
|
||||
@@ -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)?;
|
||||
|
||||
|
||||
@@ -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;
|
||||
|
||||
|
||||
@@ -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", ¶ms[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", ¶ms[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", ¶ms[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", ¶ms[0], &args[0].clone())?;
|
||||
let v2 = ensure_numeric("numbers.range", ¶ms[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", ¶ms[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, ¶ms[0], &args[0])?;
|
||||
|
||||
@@ -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, ¶ms[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, ¶ms[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, ¶ms[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, ¶ms[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, ¶ms[0], args[0].clone())?;
|
||||
|
||||
@@ -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, ¶ms[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, ¶ms[0], args[0].clone())?;
|
||||
|
||||
@@ -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, ¶ms[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, ¶ms[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, ¶ms[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, ¶ms[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, ¶ms[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, ¶ms[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, ¶ms[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, ¶ms[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, ¶ms[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, ¶ms[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, ¶ms[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, ¶ms[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, ¶ms[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, ¶ms[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, ¶ms[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, ¶ms[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, ¶ms[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, ¶ms[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, ¶ms[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, ¶ms[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, ¶ms[0], &args[0])?;
|
||||
|
||||
@@ -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)?;
|
||||
|
||||
|
||||
@@ -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, ¶ms[0], &args[0])?;
|
||||
|
||||
@@ -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()))
|
||||
}
|
||||
|
||||
@@ -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<()> {
|
||||
|
||||
@@ -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
61
src/lexer.rs
61
src/lexer.rs
@@ -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)
|
||||
}
|
||||
|
||||
@@ -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;
|
||||
|
||||
149
src/parser.rs
149
src/parser.rs
@@ -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 {
|
||||
|
||||
409
src/scheduler.rs
409
src/scheduler.rs
@@ -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(())
|
||||
}
|
||||
|
||||
29
src/utils.rs
29
src/utils.rs
@@ -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"),
|
||||
}
|
||||
|
||||
@@ -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)?;
|
||||
|
||||
@@ -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(()),
|
||||
|
||||
@@ -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, ®orus::Scope)> = schedule
|
||||
let schedule = analyzer.analyze(&modules)?;
|
||||
let mut scopes: Vec<(Ref<Query>, ®orus::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() {
|
||||
|
||||
@@ -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, &"")?)
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user