diff --git a/.gitignore b/.gitignore index 088ba6ba..d5d3532a 100644 --- a/.gitignore +++ b/.gitignore @@ -8,3 +8,6 @@ Cargo.lock # These are backup files generated by rustfmt **/*.rs.bk + +# vscode files +.vscode/ \ No newline at end of file diff --git a/src/ast.rs b/src/ast.rs index be96ff0f..a66dfea0 100644 --- a/src/ast.rs +++ b/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 { + r: std::rc::Rc, +} + +impl Clone for NodeRef { + fn clone(&self) -> Self { + Self { r: self.r.clone() } + } +} + +impl std::fmt::Debug for NodeRef { + fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result { + self.r.as_ref().fmt(f) + } +} + +impl std::cmp::PartialEq for NodeRef { + fn eq(&self, other: &Self) -> bool { + std::rc::Rc::as_ptr(&self.r).eq(&std::rc::Rc::as_ptr(&other.r)) + } +} + +impl std::cmp::Eq for NodeRef {} + +impl std::cmp::Ord for NodeRef { + fn cmp(&self, other: &Self) -> std::cmp::Ordering { + std::rc::Rc::as_ptr(&self.r).cmp(&std::rc::Rc::as_ptr(&other.r)) + } +} + +impl std::cmp::PartialOrd for NodeRef { + fn partial_cmp(&self, other: &Self) -> Option { + Some(self.cmp(other)) + } +} + +impl Deref for NodeRef { + type Target = T; + + fn deref(&self) -> &Self::Target { + &self.r + } +} + +impl AsRef for NodeRef { + fn as_ref(&self) -> &T { + self.deref() + } +} + +impl NodeRef { + pub fn new(t: T) -> Self { + Self { + r: std::rc::Rc::new(t), + } + } +} + +pub type Ref = NodeRef; + +#[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, + items: Vec>, }, // set Set { span: Span, - items: Vec, + items: Vec>, }, Object { span: Span, - fields: Vec<(Span, Expr, Expr)>, + fields: Vec<(Span, Ref, Ref)>, }, // Comprehensions ArrayCompr { span: Span, - term: Box, - query: Query, + term: Ref, + query: Ref, }, SetCompr { span: Span, - term: Box, - query: Query, + term: Ref, + query: Ref, }, ObjectCompr { span: Span, - key: Box, - value: Box, - query: Query, + key: Ref, + value: Ref, + query: Ref, }, Call { span: Span, - fcn: Box, - params: Vec, + fcn: Ref, + params: Vec>, }, UnaryExpr { span: Span, - expr: Box, + expr: Ref, }, // ref RefDot { span: Span, - refr: Box, + refr: Ref, field: Span, }, RefBrack { span: Span, - refr: Box, - index: Box, + refr: Ref, + index: Ref, }, // Infix expressions BinExpr { span: Span, op: BinOp, - lhs: Box, - rhs: Box, + lhs: Ref, + rhs: Ref, }, BoolExpr { span: Span, op: BoolOp, - lhs: Box, - rhs: Box, + lhs: Ref, + rhs: Ref, }, ArithExpr { span: Span, op: ArithOp, - lhs: Box, - rhs: Box, + lhs: Ref, + rhs: Ref, }, AssignExpr { span: Span, op: AssignOp, - lhs: Box, - rhs: Box, + lhs: Ref, + rhs: Ref, }, Membership { span: Span, - key: Box>, - value: Box, - collection: Box, + key: Option>, + value: Ref, + collection: Ref, }, } @@ -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, - value: Expr, - collection: Expr, + key: Option>, + value: Ref, + collection: Ref, }, Expr { span: Span, - expr: Expr, + expr: Ref, }, NotExpr { span: Span, - expr: Expr, + expr: Ref, }, Every { span: Span, key: Option, value: Span, - domain: Expr, - query: Query, + domain: Ref, + query: Ref, }, } -#[derive(Debug, Clone)] +#[derive(Debug)] pub struct WithModifier { pub span: Span, - pub refr: Expr, - pub r#as: Expr, + pub refr: Ref, + pub r#as: Ref, } -#[derive(Debug, Clone)] +#[derive(Debug)] pub struct LiteralStmt { pub span: Span, pub literal: Literal, pub with_mods: Vec, } -#[derive(Debug, Clone)] +#[derive(Debug)] pub struct Query { pub span: Span, pub stmts: Vec, } -#[derive(Debug, Clone)] +#[derive(Debug)] pub struct RuleAssign { pub span: Span, pub op: AssignOp, - pub value: Expr, + pub value: Ref, } -#[derive(Debug, Clone)] +#[derive(Debug)] pub struct RuleBody { pub span: Span, pub assign: Option, - pub query: Query, + pub query: Ref, } -#[derive(Debug, Clone)] +#[derive(Debug)] pub enum RuleHead { Compr { span: Span, - refr: Expr, + refr: Ref, assign: Option, }, Set { span: Span, - refr: Expr, - key: Option, + refr: Ref, + key: Option>, }, Func { span: Span, - refr: Expr, - args: Vec, + refr: Ref, + args: Vec>, assign: Option, }, } -#[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, op: AssignOp, - value: Expr, + value: Ref, }, } -#[derive(Debug, Clone)] +#[derive(Debug)] pub struct Package { pub span: Span, - pub refr: Expr, + pub refr: Ref, } -#[derive(Debug, Clone)] +#[derive(Debug)] pub struct Import { pub span: Span, - pub refr: Expr, + pub refr: Ref, pub r#as: Option, } -#[derive(Debug, Clone)] +#[derive(Debug)] pub struct Module { pub package: Package, pub imports: Vec, - pub policy: Vec, -} - -#[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 - } + pub policy: Vec>, } -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 { - 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; diff --git a/src/builtins/aggregates.rs b/src/builtins/aggregates.rs index a44a05ea..dbd8a553 100644 --- a/src/builtins/aggregates.rs +++ b/src/builtins/aggregates.rs @@ -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 { +fn count(span: &Span, params: &[Ref], args: &[Value]) -> Result { 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 { })) } -fn max(span: &Span, params: &[Expr], args: &[Value]) -> Result { +fn max(span: &Span, params: &[Ref], args: &[Value]) -> Result { 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 { }) } -fn min(span: &Span, params: &[Expr], args: &[Value]) -> Result { +fn min(span: &Span, params: &[Ref], args: &[Value]) -> Result { 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 { }) } -fn product(span: &Span, params: &[Expr], args: &[Value]) -> Result { +fn product(span: &Span, params: &[Ref], args: &[Value]) -> Result { 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 { }) } -fn sort(span: &Span, params: &[Expr], args: &[Value]) -> Result { +fn sort(span: &Span, params: &[Ref], args: &[Value]) -> Result { 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 { }) } -fn sum(span: &Span, params: &[Expr], args: &[Value]) -> Result { +fn sum(span: &Span, params: &[Ref], args: &[Value]) -> Result { ensure_args_count(span, "sum", params, args, 1)?; let mut v = 0 as Float; diff --git a/src/builtins/arrays.rs b/src/builtins/arrays.rs index d9a8294b..39a694d1 100644 --- a/src/builtins/arrays.rs +++ b/src/builtins/arrays.rs @@ -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 { +fn concat(span: &Span, params: &[Ref], args: &[Value]) -> Result { 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 { Ok(Value::Array(v1)) } -fn reverse(span: &Span, params: &[Expr], args: &[Value]) -> Result { +fn reverse(span: &Span, params: &[Ref], args: &[Value]) -> Result { 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 { Ok(Value::Array(v1)) } -fn slice(span: &Span, params: &[Expr], args: &[Value]) -> Result { +fn slice(span: &Span, params: &[Ref], args: &[Value]) -> Result { let name = "array.slice"; ensure_args_count(span, name, params, args, 3)?; diff --git a/src/builtins/bitwise.rs b/src/builtins/bitwise.rs index 5597fcee..e1b3e055 100644 --- a/src/builtins/bitwise.rs +++ b/src/builtins/bitwise.rs @@ -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 { +fn and(span: &Span, params: &[Ref], args: &[Value]) -> Result { 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 { Ok(Value::from_float((v1 & v2) as Float)) } -fn lsh(span: &Span, params: &[Expr], args: &[Value]) -> Result { +fn lsh(span: &Span, params: &[Ref], args: &[Value]) -> Result { 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 { Ok(Value::from_float((v1 << v2) as Float)) } -fn negate(span: &Span, params: &[Expr], args: &[Value]) -> Result { +fn negate(span: &Span, params: &[Ref], args: &[Value]) -> Result { 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 { Ok(Value::from_float((!v) as Float)) } -fn or(span: &Span, params: &[Expr], args: &[Value]) -> Result { +fn or(span: &Span, params: &[Ref], args: &[Value]) -> Result { 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 { Ok(Value::from_float((v1 | v2) as Float)) } -fn rsh(span: &Span, params: &[Expr], args: &[Value]) -> Result { +fn rsh(span: &Span, params: &[Ref], args: &[Value]) -> Result { 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 { Ok(Value::from_float((v1 >> v2) as Float)) } -fn xor(span: &Span, params: &[Expr], args: &[Value]) -> Result { +fn xor(span: &Span, params: &[Ref], args: &[Value]) -> Result { let name = "bits.xor"; ensure_args_count(span, name, params, args, 2)?; diff --git a/src/builtins/conversions.rs b/src/builtins/conversions.rs index 88aac5fd..6855df95 100644 --- a/src/builtins/conversions.rs +++ b/src/builtins/conversions.rs @@ -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 { +fn to_number(span: &Span, params: &[Ref], args: &[Value]) -> Result { let name = "to_number"; ensure_args_count(span, name, params, args, 1)?; diff --git a/src/builtins/debugging.rs b/src/builtins/debugging.rs index 3c76fcfc..0c0a582c 100644 --- a/src/builtins/debugging.rs +++ b/src/builtins/debugging.rs @@ -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 { +fn print(span: &Span, _params: &[Ref], args: &[Value]) -> Result { if args.len() > MAX_ARGS as usize { bail!(span.error("print supports up to 100 arguments")); } diff --git a/src/builtins/deprecated.rs b/src/builtins/deprecated.rs index d5017b84..20881c99 100644 --- a/src/builtins/deprecated.rs +++ b/src/builtins/deprecated.rs @@ -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 { +fn all(span: &Span, params: &[Ref], args: &[Value]) -> Result { 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 { })) } -fn any(span: &Span, params: &[Expr], args: &[Value]) -> Result { +fn any(span: &Span, params: &[Ref], args: &[Value]) -> Result { ensure_args_count(span, "any", params, args, 1)?; Ok(Value::Bool(match &args[0] { diff --git a/src/builtins/encoding.rs b/src/builtins/encoding.rs index 938f4700..0d8ea8b5 100644 --- a/src/builtins/encoding.rs +++ b/src/builtins/encoding.rs @@ -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 { +fn base64_decode(span: &Span, params: &[Ref], args: &[Value]) -> Result { let name = "base64.decode"; ensure_args_count(span, name, params, args, 1)?; diff --git a/src/builtins/mod.rs b/src/builtins/mod.rs index 9589f014..927a46b0 100644 --- a/src/builtins/mod.rs +++ b/src/builtins/mod.rs @@ -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, u8); +pub type BuiltinFcn = (fn(&Span, &[Ref], &[Value]) -> Result, u8); pub use deprecated::DEPRECATED; diff --git a/src/builtins/numbers.rs b/src/builtins/numbers.rs index 7f65c770..7b48eae6 100644 --- a/src/builtins/numbers.rs +++ b/src/builtins/numbers.rs @@ -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 { +fn abs(span: &Span, params: &[Ref], args: &[Value]) -> Result { 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 { +fn ceil(span: &Span, params: &[Ref], args: &[Value]) -> Result { 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 { +fn floor(span: &Span, params: &[Ref], args: &[Value]) -> Result { 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 { +fn range(span: &Span, params: &[Ref], args: &[Value]) -> Result { 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 { Ok(Value::from_array(values)) } -fn round(span: &Span, params: &[Expr], args: &[Value]) -> Result { +fn round(span: &Span, params: &[Ref], args: &[Value]) -> Result { 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 { +fn intn(span: &Span, params: &[Ref], args: &[Value]) -> Result { let fcn = "rand.intn"; ensure_args_count(span, fcn, params, args, 2)?; let _ = ensure_string(fcn, ¶ms[0], &args[0])?; diff --git a/src/builtins/objects.rs b/src/builtins/objects.rs index f88aadcc..f5e70fd2 100644 --- a/src/builtins/objects.rs +++ b/src/builtins/objects.rs @@ -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 { +fn json_filter(span: &Span, params: &[Ref], args: &[Value]) -> Result { 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 { Ok(json_filter_impl(&args[0], &filters)) } -fn filter(span: &Span, params: &[Expr], args: &[Value]) -> Result { +fn filter(span: &Span, params: &[Ref], args: &[Value]) -> Result { 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 { Ok(Value::Object(obj)) } -fn get(span: &Span, params: &[Expr], args: &[Value]) -> Result { +fn get(span: &Span, params: &[Ref], args: &[Value]) -> Result { 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 { }) } -fn keys(span: &Span, params: &[Expr], args: &[Value]) -> Result { +fn keys(span: &Span, params: &[Ref], args: &[Value]) -> Result { 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 { +fn remove(span: &Span, params: &[Ref], args: &[Value]) -> Result { let name = "object.remove"; ensure_args_count(span, name, params, args, 2)?; let mut obj = ensure_object(name, ¶ms[0], args[0].clone())?; diff --git a/src/builtins/sets.rs b/src/builtins/sets.rs index d62fd448..8eca717f 100644 --- a/src/builtins/sets.rs +++ b/src/builtins/sets.rs @@ -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 Result { +fn intersection_of_set_of_sets(span: &Span, params: &[Ref], args: &[Value]) -> Result { 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 { +fn union_of_set_of_sets(span: &Span, params: &[Ref], args: &[Value]) -> Result { let name = "union"; ensure_args_count(span, name, params, args, 1)?; let set = ensure_set(name, ¶ms[0], args[0].clone())?; diff --git a/src/builtins/strings.rs b/src/builtins/strings.rs index add681af..0bc8f35b 100644 --- a/src/builtins/strings.rs +++ b/src/builtins/strings.rs @@ -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 { +fn concat(span: &Span, params: &[Ref], args: &[Value]) -> Result { 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 { Ok(Value::String(collection.join(&delimiter))) } -fn contains(span: &Span, params: &[Expr], args: &[Value]) -> Result { +fn contains(span: &Span, params: &[Ref], args: &[Value]) -> Result { 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 { Ok(Value::Bool(s1.contains(&s2))) } -fn endswith(span: &Span, params: &[Expr], args: &[Value]) -> Result { +fn endswith(span: &Span, params: &[Ref], args: &[Value]) -> Result { 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 { Ok(Value::Bool(s1.ends_with(&s2))) } -fn format_int(span: &Span, params: &[Expr], args: &[Value]) -> Result { +fn format_int(span: &Span, params: &[Ref], args: &[Value]) -> Result { 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 { )) } -fn indexof(span: &Span, params: &[Expr], args: &[Value]) -> Result { +fn indexof(span: &Span, params: &[Ref], args: &[Value]) -> Result { 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 { } #[allow(dead_code)] -fn indexof_n(span: &Span, params: &[Expr], args: &[Value]) -> Result { +fn indexof_n(span: &Span, params: &[Ref], args: &[Value]) -> Result { 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 { Ok(Value::from_array(positions)) } -fn lower(span: &Span, params: &[Expr], args: &[Value]) -> Result { +fn lower(span: &Span, params: &[Ref], args: &[Value]) -> Result { 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 { +fn replace(span: &Span, params: &[Ref], args: &[Value]) -> Result { 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 { Ok(Value::String(s.replace(&old, &new))) } -fn split(span: &Span, params: &[Expr], args: &[Value]) -> Result { +fn split(span: &Span, params: &[Ref], args: &[Value]) -> Result { 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 { )) } -fn sprintf(span: &Span, params: &[Expr], args: &[Value]) -> Result { +fn sprintf(span: &Span, params: &[Ref], args: &[Value]) -> Result { 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 { Ok(Value::String(s.to_string())) } -fn any_prefix_match(span: &Span, params: &[Expr], args: &[Value]) -> Result { +fn any_prefix_match(span: &Span, params: &[Ref], args: &[Value]) -> Result { 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 Result { +fn any_suffix_match(span: &Span, params: &[Ref], args: &[Value]) -> Result { 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 Result { +fn startswith(span: &Span, params: &[Ref], args: &[Value]) -> Result { 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 { Ok(Value::Bool(s1.starts_with(&s2))) } -fn replace_n(span: &Span, params: &[Expr], args: &[Value]) -> Result { +fn replace_n(span: &Span, params: &[Ref], args: &[Value]) -> Result { 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 { Ok(Value::String(s)) } -fn reverse(span: &Span, params: &[Expr], args: &[Value]) -> Result { +fn reverse(span: &Span, params: &[Ref], args: &[Value]) -> Result { 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 { +fn substring(span: &Span, params: &[Ref], args: &[Value]) -> Result { 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 { Ok(Value::String(s[offset..offset + length].to_string())) } -fn trim(span: &Span, params: &[Expr], args: &[Value]) -> Result { +fn trim(span: &Span, params: &[Ref], args: &[Value]) -> Result { 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 { )) } -fn trim_left(span: &Span, params: &[Expr], args: &[Value]) -> Result { +fn trim_left(span: &Span, params: &[Ref], args: &[Value]) -> Result { 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 { )) } -fn trim_prefix(span: &Span, params: &[Expr], args: &[Value]) -> Result { +fn trim_prefix(span: &Span, params: &[Ref], args: &[Value]) -> Result { 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 { })) } -fn trim_right(span: &Span, params: &[Expr], args: &[Value]) -> Result { +fn trim_right(span: &Span, params: &[Ref], args: &[Value]) -> Result { 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 { )) } -fn trim_space(span: &Span, params: &[Expr], args: &[Value]) -> Result { +fn trim_space(span: &Span, params: &[Ref], args: &[Value]) -> Result { 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 { +fn trim_suffix(span: &Span, params: &[Ref], args: &[Value]) -> Result { 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 { })) } -fn upper(span: &Span, params: &[Expr], args: &[Value]) -> Result { +fn upper(span: &Span, params: &[Ref], args: &[Value]) -> Result { let name = "upper"; ensure_args_count(span, name, params, args, 1)?; let s = ensure_string(name, ¶ms[0], &args[0])?; diff --git a/src/builtins/time.rs b/src/builtins/time.rs index 18b8f925..ac310ab8 100644 --- a/src/builtins/time.rs +++ b/src/builtins/time.rs @@ -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 { +fn now_ns(span: &Span, params: &[Ref], args: &[Value]) -> Result { let name = "time.now_ns"; ensure_args_count(span, name, params, args, 0)?; diff --git a/src/builtins/tracing.rs b/src/builtins/tracing.rs index d63cc302..9a8dc3bd 100644 --- a/src/builtins/tracing.rs +++ b/src/builtins/tracing.rs @@ -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 { +fn trace(span: &Span, params: &[Ref], args: &[Value]) -> Result { let name = "trace"; ensure_args_count(span, name, params, args, 1)?; let msg = ensure_string(name, ¶ms[0], &args[0])?; diff --git a/src/builtins/types.rs b/src/builtins/types.rs index 9b70f827..09a9f3b5 100644 --- a/src/builtins/types.rs +++ b/src/builtins/types.rs @@ -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 { +fn is_array(span: &Span, params: &[Ref], args: &[Value]) -> Result { 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 { +fn is_boolean(span: &Span, params: &[Ref], args: &[Value]) -> Result { 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 { +fn is_null(span: &Span, params: &[Ref], args: &[Value]) -> Result { 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 { +fn is_number(span: &Span, params: &[Ref], args: &[Value]) -> Result { 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 { +fn is_object(span: &Span, params: &[Ref], args: &[Value]) -> Result { 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 { +fn is_set(span: &Span, params: &[Ref], args: &[Value]) -> Result { 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 { +fn is_string(span: &Span, params: &[Ref], args: &[Value]) -> Result { 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 { +pub fn type_name(span: &Span, params: &[Ref], args: &[Value]) -> Result { ensure_args_count(span, "type_name", params, args, 1)?; Ok(Value::String(get_type(&args[0]).to_string())) } diff --git a/src/builtins/utils.rs b/src/builtins/utils.rs index 4f7cbca5..eb5d6ca0 100644 --- a/src/builtins/utils.rs +++ b/src/builtins/utils.rs @@ -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], args: &[Value], expected: usize, ) -> Result<()> { diff --git a/src/engine.rs b/src/engine.rs index 96b87001..623d8aca 100644 --- a/src/engine.rs +++ b/src/engine.rs @@ -12,7 +12,7 @@ use anyhow::Result; #[derive(Clone)] pub struct Engine { - modules: Vec>, + modules: Vec>, 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 { - 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) diff --git a/src/interpreter.rs b/src/interpreter.rs index 8ecc270f..97b549ac 100644 --- a/src/interpreter.rs +++ b/src/interpreter.rs @@ -3,7 +3,7 @@ use crate::ast::*; use crate::builtins::{self, BuiltinFcn}; -use crate::lexer::Span; +use crate::lexer::*; use crate::parser::Parser; use crate::scheduler::*; use crate::utils::*; @@ -15,12 +15,15 @@ use serde::Serialize; use std::collections::{hash_map::Entry, BTreeMap, BTreeSet, HashMap}; use std::rc::Rc; -type Scope = BTreeMap; +type Scope = BTreeMap; -pub struct Interpreter<'source> { - modules: Vec<&'source Module>, - module: Option<&'source Module>, - schedule: Option>, +type DefaultRuleInfo = (Ref, Option); +type ContextExprs = (Option>, Option>); + +pub struct Interpreter { + modules: Vec>, + module: Option>, + schedule: Option, current_module_path: String, prepared: bool, input: Value, @@ -30,13 +33,13 @@ pub struct Interpreter<'source> { with_functions: BTreeMap, scopes: Vec, // TODO: handle recursive calls where same expr could have different values. - loop_var_values: BTreeMap, Value>, - contexts: Vec>, - functions: FunctionTable<'source>, - rules: HashMap>, - default_rules: HashMap)>>, - processed: BTreeSet>, - active_rules: Vec<&'source Rule>, + loop_var_values: BTreeMap, + contexts: Vec, + functions: FunctionTable, + rules: HashMap>>, + default_rules: HashMap>, + processed: BTreeSet>, + active_rules: Vec>, builtins_cache: BTreeMap<(&'static str, Vec), Value>, no_rules_lookup: bool, traces: Option>, @@ -66,24 +69,24 @@ pub struct QueryResults { } #[derive(Debug, Clone)] -struct Context<'source> { - key_expr: Option<&'source Expr>, - output_expr: Option<&'source Expr>, +struct Context { + key_expr: Option, + output_expr: Option, value: Value, result: Option, results: QueryResults, } #[derive(Debug)] -struct LoopExpr<'source> { - span: &'source Span, - expr: &'source Expr, - value: &'source Expr, - index: &'source str, +struct LoopExpr { + span: Span, + expr: ExprRef, + value: ExprRef, + index: SourceStr, } -impl<'source> Interpreter<'source> { - pub fn new(modules: &[&'source Module]) -> Result> { +impl Interpreter { + pub fn new(modules: &[Ref]) -> Result { let mut with_document = Value::new_object(); *Self::make_or_get_value_mut(&mut with_document, &["data"])? = Value::new_object(); *Self::make_or_get_value_mut(&mut with_document, &["input"])? = Value::new_object(); @@ -113,7 +116,7 @@ impl<'source> Interpreter<'source> { }) } - pub fn get_modules(&mut self) -> &mut Vec<&'source Module> { + pub fn get_modules(&mut self) -> &mut Vec> { &mut self.modules } @@ -151,8 +154,9 @@ impl<'source> Interpreter<'source> { Ok(()) } - fn current_module(&self) -> Result<&'source Module> { + fn current_module(&self) -> Result> { self.module + .clone() .ok_or_else(|| anyhow!("internal error: current module not set")) } @@ -169,20 +173,18 @@ impl<'source> Interpreter<'source> { } #[inline(always)] - fn add_variable(&mut self, name: &str, value: Value) -> Result<()> { - let name = name.to_string(); - + fn add_variable(&mut self, name: &SourceStr, value: Value) -> Result<()> { // Only add the variable if the key is not "_" - if name != "_" { - self.current_scope_mut()?.insert(name, value); + if name.text() != "_" { + self.current_scope_mut()?.insert(name.clone(), value); } Ok(()) } - fn add_variable_or(&mut self, name: &str) -> Result { + fn add_variable_or(&mut self, name: &SourceStr) -> Result { for scope in self.scopes.iter().rev() { - if let Some(variable) = scope.get(&name.to_string()) { + if let Some(variable) = scope.get(name) { return Ok(variable.clone()); } } @@ -192,26 +194,26 @@ impl<'source> Interpreter<'source> { } // TODO: optimize this - fn variables_assignment(&mut self, name: &str, value: &Value) -> Result<()> { + fn variables_assignment(&mut self, name: &SourceStr, value: &Value) -> Result<()> { if let Some(variable) = self.current_scope_mut()?.get_mut(name) { *variable = value.clone(); Ok(()) - } else if name == "_" { + } else if name.text() == "_" { Ok(()) } else { bail!("variable {} is undefined", name) } } - fn eval_chained_ref_dot_or_brack(&mut self, mut expr: &'source Expr) -> Result { + fn eval_chained_ref_dot_or_brack(&mut self, mut expr: &ExprRef) -> Result { // Collect a chaing of '.field' or '["field"]' let mut path = vec![]; loop { - if let Some(v) = self.loop_var_values.get(&Ref::make(expr)) { + if let Some(v) = self.loop_var_values.get(expr) { path.reverse(); return Ok(Self::get_value_chained(v.clone(), &path[..])); } - match expr { + match expr.as_ref() { // Stop path collection upon encountering the leading variable. Expr::Var(v) => { path.reverse(); @@ -240,7 +242,7 @@ impl<'source> Interpreter<'source> { // if a matching key exists. if v == Value::Undefined && matches!(index, Value::Number(_)) - && get_root_var(refr)? == "data" + && get_root_var(refr)?.text() == "data" { let index = index.to_string(); v = obj[&index].clone(); @@ -256,9 +258,9 @@ impl<'source> Interpreter<'source> { } } - fn is_loop_index_var(&self, ident: &str) -> bool { + fn is_loop_index_var(&self, ident: &SourceStr) -> bool { // TODO: check for vars that are declared using some-vars - match ident { + match ident.text() { "_" => true, _ => match self.lookup_local_var(ident) { // Vars declared using `some v` can be loop vars. @@ -269,28 +271,30 @@ impl<'source> Interpreter<'source> { Some(_) => false, None => { // Check if ident is a rule. - let path = self.current_module_path.clone() + "." + ident; + let path = self.current_module_path.clone() + "." + ident.text(); self.rules.get(&path).is_none() } }, } } - fn hoist_loops_impl(&self, expr: &'source Expr, loops: &mut Vec>) { + fn hoist_loops_impl(&self, expr: &ExprRef, loops: &mut Vec) { use Expr::*; - match expr { + match expr.as_ref() { RefBrack { refr, index, span } => { // First hoist any loops in refr self.hoist_loops_impl(refr, loops); // Then hoist the current bracket operation. match index.as_ref() { - Var(ident) if self.is_loop_index_var(*ident.text()) => loops.push(LoopExpr { - span, - expr, - value: refr, - index: *ident.text(), - }), + Var(ident) if self.is_loop_index_var(&ident.source_str()) => { + loops.push(LoopExpr { + span: span.clone(), + expr: expr.clone(), + value: refr.clone(), + index: ident.source_str(), + }) + } _ => { // hoist any loops in index expression. self.hoist_loops_impl(index, loops); @@ -347,7 +351,7 @@ impl<'source> Interpreter<'source> { } } - fn hoist_loops(&self, literal: &'source Literal) -> Vec> { + fn hoist_loops(&self, literal: &Literal) -> Vec { let mut loops = vec![]; use Literal::*; match literal { @@ -375,8 +379,8 @@ impl<'source> Interpreter<'source> { fn eval_bool_expr( &mut self, op: &BoolOp, - lhs_expr: &'source Expr, - rhs_expr: &'source Expr, + lhs_expr: &ExprRef, + rhs_expr: &ExprRef, ) -> Result { let lhs = self.eval_expr(lhs_expr)?; let rhs = self.eval_expr(rhs_expr)?; @@ -388,12 +392,7 @@ impl<'source> Interpreter<'source> { builtins::comparison::compare(op, &lhs, &rhs) } - fn eval_bin_expr( - &mut self, - op: &BinOp, - lhs: &'source Expr, - rhs: &'source Expr, - ) -> Result { + fn eval_bin_expr(&mut self, op: &BinOp, lhs: &ExprRef, rhs: &ExprRef) -> Result { let lhs_value = self.eval_expr(lhs)?; let rhs_value = self.eval_expr(rhs)?; @@ -407,12 +406,7 @@ impl<'source> Interpreter<'source> { } } - fn eval_arith_expr( - &mut self, - op: &ArithOp, - lhs: &'source Expr, - rhs: &'source Expr, - ) -> Result { + fn eval_arith_expr(&mut self, op: &ArithOp, lhs: &ExprRef, rhs: &ExprRef) -> Result { let lhs_value = self.eval_expr(lhs)?; let rhs_value = self.eval_expr(rhs)?; @@ -428,18 +422,13 @@ impl<'source> Interpreter<'source> { } } - fn eval_assign_expr( - &mut self, - op: &AssignOp, - lhs: &'source Expr, - rhs: &'source Expr, - ) -> Result { + fn eval_assign_expr(&mut self, op: &AssignOp, lhs: &ExprRef, rhs: &ExprRef) -> Result { let (name, value) = match op { AssignOp::Eq => { - match (lhs, rhs) { + match (lhs.as_ref(), rhs.as_ref()) { (Expr::Var(lhs_span), Expr::Var(rhs_span)) => { - let (lhs_name, lhs_var) = (lhs_span.text(), self.eval_expr(lhs)?); - let (rhs_name, rhs_var) = (rhs_span.text(), self.eval_expr(rhs)?); + let (lhs_name, lhs_var) = (lhs_span.source_str(), self.eval_expr(lhs)?); + let (rhs_name, rhs_var) = (rhs_span.source_str(), self.eval_expr(rhs)?); match (&lhs_var, &rhs_var) { (Value::Undefined, Value::Undefined) => { @@ -452,12 +441,12 @@ impl<'source> Interpreter<'source> { } } (Expr::Var(lhs_span), _) => { - let (name, var) = (lhs_span.text(), self.eval_expr(lhs)?); + let (name, var) = (lhs_span.source_str(), self.eval_expr(lhs)?); // TODO: Check this // Allow variable overwritten inside a loop if !matches!(var, Value::Undefined) - && self.loop_var_values.get(&Ref::make(rhs)).is_none() + && self.loop_var_values.get(rhs).is_none() { return self.eval_bool_expr(&BoolOp::Eq, lhs, rhs); } @@ -465,12 +454,12 @@ impl<'source> Interpreter<'source> { (name, self.eval_expr(rhs)?) } (_, Expr::Var(rhs_span)) => { - let (name, var) = (rhs_span.text(), self.eval_expr(rhs)?); + let (name, var) = (rhs_span.source_str(), self.eval_expr(rhs)?); // TODO: Check this // Allow variable overwritten inside a loop if !matches!(var, Value::Undefined) - && self.loop_var_values.get(&Ref::make(lhs)).is_none() + && self.loop_var_values.get(lhs).is_none() { return self.eval_bool_expr(&BoolOp::Eq, lhs, rhs); } @@ -482,16 +471,17 @@ impl<'source> Interpreter<'source> { } } AssignOp::ColEq => { - let name = if let Expr::Var(span) = lhs { - span.text() + let name = if let Expr::Var(span) = lhs.as_ref() { + span.source_str() } else { bail!("internal error: unexpected"); }; // TODO: Check this // Allow variable overwritten inside a loop - if self.lookup_local_var(*name).is_some() - && self.loop_var_values.get(&Ref::make(rhs)).is_none() + let lhs_val = self.lookup_local_var(&name); + if !matches!(lhs_val, None | Some(Value::Undefined)) + && self.loop_var_values.get(rhs).is_none() { bail!(rhs .span() @@ -507,10 +497,10 @@ impl<'source> Interpreter<'source> { return Ok(Value::Bool(false)); } - self.add_variable_or(*name)?; + self.add_variable_or(&name)?; // TODO: optimize this - self.variables_assignment(*name, &value)?; + self.variables_assignment(&name, &value)?; info!( "eval_assign_expr before, op: {:?}, lhs: {:?}, rhs: {:?}", @@ -522,11 +512,11 @@ impl<'source> Interpreter<'source> { fn eval_every( &mut self, - _span: &'source Span, - key: &'source Option, - value: &'source Span, - domain: &'source Expr, - query: &'source Query, + _span: &Span, + key: &Option, + value: &Span, + domain: &ExprRef, + query: &Ref, ) -> Result { let domain = self.eval_expr(domain)?; @@ -542,9 +532,9 @@ impl<'source> Interpreter<'source> { match domain { Value::Array(a) => { for (idx, v) in a.iter().enumerate() { - self.add_variable(*value.text(), v.clone())?; + self.add_variable(&value.source_str(), v.clone())?; if let Some(key) = key { - self.add_variable(*key.text(), Value::from_float(idx as Float))?; + self.add_variable(&key.source_str(), Value::from_float(idx as Float))?; } if !self.eval_query(query)? { r = false; @@ -554,9 +544,9 @@ impl<'source> Interpreter<'source> { } Value::Set(s) => { for v in s.iter() { - self.add_variable(*value.text(), v.clone())?; + self.add_variable(&value.source_str(), v.clone())?; if let Some(key) = key { - self.add_variable(*key.text(), v.clone())?; + self.add_variable(&key.source_str(), v.clone())?; } if !self.eval_query(query)? { r = false; @@ -566,9 +556,9 @@ impl<'source> Interpreter<'source> { } Value::Object(o) => { for (k, v) in o.iter() { - self.add_variable(*value.text(), v.clone())?; + self.add_variable(&value.source_str(), v.clone())?; if let Some(key) = key { - self.add_variable(*key.text(), k.clone())?; + self.add_variable(&key.source_str(), k.clone())?; } if !self.eval_query(query)? { r = false; @@ -587,14 +577,14 @@ impl<'source> Interpreter<'source> { fn lookup_or_eval_expr( &mut self, - cache: &mut BTreeMap, Value>, - expr: &'source Expr, + cache: &mut BTreeMap, + expr: &ExprRef, ) -> Result { - match cache.get(&Ref::make(expr)) { + match cache.get(expr) { Some(v) => Ok(v.clone()), _ => { let v = self.eval_expr(expr)?; - cache.insert(Ref::make(expr), v.clone()); + cache.insert(expr.clone(), v.clone()); Ok(v) } } @@ -603,9 +593,9 @@ impl<'source> Interpreter<'source> { fn make_bindings_impl( &mut self, is_last: bool, - type_match: &mut BTreeSet>, - cache: &mut BTreeMap, Value>, - expr: &'source Expr, + type_match: &mut BTreeSet, + cache: &mut BTreeMap, + expr: &ExprRef, value: &Value, ) -> Result { // Propagate undefined. @@ -613,11 +603,11 @@ impl<'source> Interpreter<'source> { return Ok(false); } let span = expr.span(); - let raise_error = is_last && type_match.get(&Ref::make(expr)).is_none(); + let raise_error = is_last && type_match.get(expr).is_none(); - match (expr, value) { + match (expr.as_ref(), value) { (Expr::Var(ident), _) => { - self.add_variable(*ident.text(), value.clone())?; + self.add_variable(&ident.source_str(), value.clone())?; Ok(true) } @@ -636,7 +626,7 @@ impl<'source> Interpreter<'source> { } return Ok(false); } - type_match.insert(Ref::make(expr)); + type_match.insert(expr.clone()); let mut r = false; for (idx, item) in items.iter().enumerate() { @@ -672,7 +662,7 @@ impl<'source> Interpreter<'source> { field_value, )?; } - type_match.insert(Ref::make(expr)); + type_match.insert(expr.clone()); Ok(r) } @@ -691,7 +681,7 @@ impl<'source> Interpreter<'source> { format!("Cannot bind pattern of type `{expr_t}` with value of type `{value_t}`. Value is {value}.").as_str())); } } - type_match.insert(Ref::make(expr)); + type_match.insert(expr.clone()); Ok(&expr_value == value) } @@ -701,9 +691,9 @@ impl<'source> Interpreter<'source> { fn make_bindings( &mut self, is_last: bool, - type_match: &mut BTreeSet>, - cache: &mut BTreeMap, Value>, - expr: &'source Expr, + type_match: &mut BTreeSet, + cache: &mut BTreeMap, + expr: &ExprRef, value: &Value, ) -> Result { let prev = self.no_rules_lookup; @@ -716,9 +706,9 @@ impl<'source> Interpreter<'source> { fn make_key_value_bindings( &mut self, is_last: bool, - type_match: &mut BTreeSet>, - cache: &mut BTreeMap, Value>, - exprs: (&'source Option, &'source Expr), + type_match: &mut BTreeSet, + cache: &mut BTreeMap, + exprs: (&Option, &ExprRef), values: (&Value, &Value), ) -> Result { let (key_expr, value_expr) = exprs; @@ -733,11 +723,11 @@ impl<'source> Interpreter<'source> { fn eval_some_in( &mut self, - _span: &'source Span, - key_expr: &'source Option, - value_expr: &'source Expr, - collection: &'source Expr, - stmts: &[&'source LiteralStmt], + _span: &Span, + key_expr: &Option, + value_expr: &ExprRef, + collection: &ExprRef, + stmts: &[&LiteralStmt], ) -> Result { let scope_saved = self.current_scope()?.clone(); let mut type_match = BTreeSet::new(); @@ -832,14 +822,10 @@ impl<'source> Interpreter<'source> { Value::from_map(expr) } - fn eval_stmt_impl( - &mut self, - stmt: &'source LiteralStmt, - stmts: &[&'source LiteralStmt], - ) -> Result { + fn eval_stmt_impl(&mut self, stmt: &LiteralStmt, stmts: &[&LiteralStmt]) -> Result { Ok(match &stmt.literal { Literal::Expr { span, expr, .. } => { - let value = match expr { + let value = match expr.as_ref() { Expr::Call { span, fcn, params } => self.eval_call( span, fcn, @@ -872,7 +858,7 @@ impl<'source> Interpreter<'source> { } } Literal::NotExpr { span, expr, .. } => { - let value = match expr { + let value = match expr.as_ref() { // Extra parameter is allowed; but a return argument is not allowed. Expr::Call { span, fcn, params } => self.eval_call( span, @@ -899,8 +885,8 @@ impl<'source> Interpreter<'source> { } Literal::SomeVars { span, vars, .. } => { for var in vars { - let name = var.text(); - if let Ok(variable) = self.add_variable_or(*name) { + let name = var.source_str(); + if let Ok(variable) = self.add_variable_or(&name) { if variable != Value::Undefined { return Err(anyhow!( "duplicated definition of local variable {}", @@ -952,11 +938,7 @@ impl<'source> Interpreter<'source> { }) } - fn eval_stmt( - &mut self, - stmt: &'source LiteralStmt, - stmts: &[&'source LiteralStmt], - ) -> Result { + fn eval_stmt(&mut self, stmt: &LiteralStmt, stmts: &[&LiteralStmt]) -> Result { let mut skip_exec = false; let saved_state = if !stmt.with_mods.is_empty() { // Save state; @@ -1039,11 +1021,7 @@ impl<'source> Interpreter<'source> { r } - fn eval_stmts_in_loop( - &mut self, - stmts: &[&'source LiteralStmt], - loops: &[LoopExpr<'source>], - ) -> Result { + fn eval_stmts_in_loop(&mut self, stmts: &[&LiteralStmt], loops: &[LoopExpr]) -> Result { if loops.is_empty() { if !stmts.is_empty() { // Evaluate the current statement whose loop expressions have been hoisted. @@ -1063,12 +1041,12 @@ impl<'source> Interpreter<'source> { let loop_expr = &loops[0]; let mut result = false; - let loop_expr_value = self.eval_expr(loop_expr.value)?; + let loop_expr_value = self.eval_expr(&loop_expr.value)?; // If the loop's index variable has already been assigned a value // (this can happen if the same index is used for two different collections), // then evaluate statements only if the index applies to this collection. - if let Some(idx) = self.lookup_local_var(loop_expr.index) { + if let Some(idx) = self.lookup_local_var(&loop_expr.index) { if loop_expr_value[&idx] != Value::Undefined { result = self.eval_stmts_in_loop(stmts, &loops[1..])? || result; return Ok(result); @@ -1084,11 +1062,11 @@ impl<'source> Interpreter<'source> { Value::Array(items) => { for (idx, v) in items.iter().enumerate() { self.loop_var_values - .insert(Ref::make(loop_expr.expr), v.clone()); - self.add_variable(loop_expr.index, Value::from_float(idx as Float))?; + .insert(loop_expr.expr.clone(), v.clone()); + self.add_variable(&loop_expr.index, Value::from_float(idx as Float))?; result = self.eval_stmts_in_loop(stmts, &loops[1..])? || result; - self.loop_var_values.remove(&Ref::make(loop_expr.expr)); + self.loop_var_values.remove(&loop_expr.expr); *self.current_scope_mut()? = scope_saved.clone(); if let Some(ctx) = self.contexts.last_mut() { ctx.result = query_result.clone(); @@ -1098,11 +1076,11 @@ impl<'source> Interpreter<'source> { Value::Set(items) => { for v in items.iter() { self.loop_var_values - .insert(Ref::make(loop_expr.expr), v.clone()); + .insert(loop_expr.expr.clone(), v.clone()); // For sets, index is also the value. - self.add_variable(loop_expr.index, v.clone())?; + self.add_variable(&loop_expr.index, v.clone())?; result = self.eval_stmts_in_loop(stmts, &loops[1..])? || result; - self.loop_var_values.remove(&Ref::make(loop_expr.expr)); + self.loop_var_values.remove(&loop_expr.expr); *self.current_scope_mut()? = scope_saved.clone(); if let Some(ctx) = self.contexts.last_mut() { ctx.result = query_result.clone(); @@ -1112,11 +1090,11 @@ impl<'source> Interpreter<'source> { Value::Object(obj) => { for (k, v) in obj.iter() { self.loop_var_values - .insert(Ref::make(loop_expr.expr), v.clone()); + .insert(loop_expr.expr.clone(), v.clone()); // For objects, index is key. - self.add_variable(loop_expr.index, k.clone())?; + self.add_variable(&loop_expr.index, k.clone())?; result = self.eval_stmts_in_loop(stmts, &loops[1..])? || result; - self.loop_var_values.remove(&Ref::make(loop_expr.expr)); + self.loop_var_values.remove(&loop_expr.expr); *self.current_scope_mut()? = scope_saved.clone(); if let Some(ctx) = self.contexts.last_mut() { ctx.result = query_result.clone(); @@ -1140,14 +1118,14 @@ impl<'source> Interpreter<'source> { } } - fn eval_output_expr_in_loop(&mut self, loops: &[LoopExpr<'source>]) -> Result { + fn eval_output_expr_in_loop(&mut self, loops: &[LoopExpr]) -> Result { if loops.is_empty() { let (key_expr, output_expr) = self.get_exprs_from_context()?; match (key_expr, output_expr) { (Some(ke), Some(oe)) => { - let key = self.eval_expr(ke)?; - let value = self.eval_expr(oe)?; + let key = self.eval_expr(&ke)?; + let value = self.eval_expr(&oe)?; let ctx = self.contexts.last_mut().unwrap(); if key != Value::Undefined && value != Value::Undefined { @@ -1177,7 +1155,7 @@ impl<'source> Interpreter<'source> { }; } (None, Some(oe)) => { - let output = self.eval_expr(oe)?; + let output = self.eval_expr(&oe)?; let ctx = self.contexts.last_mut().unwrap(); if output != Value::Undefined { match &mut ctx.value { @@ -1222,25 +1200,25 @@ impl<'source> Interpreter<'source> { // Try out values in current loop expr. let loop_expr = &loops[0]; let mut result = false; - match self.eval_expr(loop_expr.value)? { + match self.eval_expr(&loop_expr.value)? { Value::Array(items) => { for v in items.iter() { self.loop_var_values - .insert(Ref::make(loop_expr.expr), v.clone()); + .insert(loop_expr.expr.clone(), v.clone()); result = self.eval_output_expr_in_loop(&loops[1..])? || result; } } Value::Set(items) => { for v in items.iter() { self.loop_var_values - .insert(Ref::make(loop_expr.expr), v.clone()); + .insert(loop_expr.expr.clone(), v.clone()); result = self.eval_output_expr_in_loop(&loops[1..])? || result; } } Value::Object(obj) => { for (_, v) in obj.iter() { self.loop_var_values - .insert(Ref::make(loop_expr.expr), v.clone()); + .insert(loop_expr.expr.clone(), v.clone()); result = self.eval_output_expr_in_loop(&loops[1..])? || result; } } @@ -1252,20 +1230,20 @@ impl<'source> Interpreter<'source> { )); } } - self.loop_var_values.remove(&Ref::make(loop_expr.expr)); + self.loop_var_values.remove(&loop_expr.expr); Ok(result) } - fn get_current_context(&self) -> Result<&Context<'source>> { + fn get_current_context(&self) -> Result<&Context> { match self.contexts.last() { Some(ctx) => Ok(ctx), _ => bail!("internal error: no active context found"), } } - fn get_exprs_from_context(&self) -> Result<(Option<&'source Expr>, Option<&'source Expr>)> { + fn get_exprs_from_context(&self) -> Result { let ctx = self.get_current_context()?; - Ok((ctx.key_expr, ctx.output_expr)) + Ok((ctx.key_expr.clone(), ctx.output_expr.clone())) } fn eval_output_expr(&mut self) -> Result { @@ -1284,7 +1262,7 @@ impl<'source> Interpreter<'source> { self.eval_output_expr_in_loop(&loops[..])?; let ctx = self.get_current_context()?; - if let Some(_oe) = ctx.output_expr { + if let Some(_oe) = &ctx.output_expr { // Ensure that at least one output was generated. Ok(ctx.value != Value::Undefined) } else { @@ -1292,7 +1270,7 @@ impl<'source> Interpreter<'source> { } } - fn eval_stmts(&mut self, stmts: &[&'source LiteralStmt]) -> Result { + fn eval_stmts(&mut self, stmts: &[&LiteralStmt]) -> Result { let mut result = true; for (idx, stmt) in stmts.iter().enumerate() { @@ -1315,16 +1293,31 @@ impl<'source> Interpreter<'source> { if result { result = self.eval_output_expr()?; + } else { + // If a query snippet is being run, gather results. + let ctx = self.contexts.last_mut().expect("no current context"); + if let Some(result) = &ctx.result { + let mut result = result.clone(); + if let Some(scope) = self.scopes.last() { + for (name, value) in scope.iter() { + result + .bindings + .as_object_mut()? + .insert(Value::String(name.to_string()), value.clone()); + } + } + ctx.results.result.push(result); + } } Ok(result) } - fn eval_query(&mut self, query: &'source Query) -> Result { + fn eval_query(&mut self, query: &Ref) -> Result { // Execute the query in a new scope self.scopes.push(Scope::new()); - let ordered_stmts: Vec<&'source LiteralStmt> = if let Some(schedule) = &self.schedule { - match schedule.order.get(&Ref::make(query)) { + let ordered_stmts: Vec<&LiteralStmt> = if let Some(schedule) = &self.schedule { + match schedule.order.get(query) { Some(ord) => ord.iter().map(|i| &query.stmts[*i as usize]).collect(), // TODO _ => bail!(query @@ -1340,7 +1333,7 @@ impl<'source> Interpreter<'source> { r } - fn eval_array(&mut self, items: &'source Vec) -> Result { + fn eval_array(&mut self, items: &Vec) -> Result { let mut array = Vec::new(); for item in items { @@ -1355,7 +1348,7 @@ impl<'source> Interpreter<'source> { Ok(Value::from_array(array)) } - fn eval_object(&mut self, fields: &'source Vec<(Span, Expr, Expr)>) -> Result { + fn eval_object(&mut self, fields: &Vec<(Span, ExprRef, ExprRef)>) -> Result { let mut object = BTreeMap::new(); for (_, key, value) in fields { @@ -1371,7 +1364,7 @@ impl<'source> Interpreter<'source> { Ok(Value::from_map(object)) } - fn eval_set(&mut self, items: &'source Vec) -> Result { + fn eval_set(&mut self, items: &Vec) -> Result { let mut set = BTreeSet::new(); for item in items { @@ -1387,9 +1380,9 @@ impl<'source> Interpreter<'source> { fn eval_membership( &mut self, - key: &'source Option, - value: &'source Expr, - collection: &'source Expr, + key: &Option, + value: &ExprRef, + collection: &ExprRef, ) -> Result { let value = self.eval_expr(value)?; let collection = self.eval_expr(collection)?; @@ -1427,11 +1420,11 @@ impl<'source> Interpreter<'source> { Ok(Value::Bool(result)) } - fn eval_array_compr(&mut self, term: &'source Expr, query: &'source Query) -> Result { + fn eval_array_compr(&mut self, term: &ExprRef, query: &Ref) -> Result { // Push new context self.contexts.push(Context { key_expr: None, - output_expr: Some(term), + output_expr: Some(term.clone()), value: Value::new_array(), result: None, results: QueryResults::default(), @@ -1446,11 +1439,11 @@ impl<'source> Interpreter<'source> { } } - fn eval_set_compr(&mut self, term: &'source Expr, query: &'source Query) -> Result { + fn eval_set_compr(&mut self, term: &ExprRef, query: &Ref) -> Result { // Push new context self.contexts.push(Context { key_expr: None, - output_expr: Some(term), + output_expr: Some(term.clone()), value: Value::new_set(), result: None, results: QueryResults::default(), @@ -1466,14 +1459,14 @@ impl<'source> Interpreter<'source> { fn eval_object_compr( &mut self, - key: &'source Expr, - value: &'source Expr, - query: &'source Query, + key: &ExprRef, + value: &ExprRef, + query: &Ref, ) -> Result { // Push new context self.contexts.push(Context { - key_expr: Some(key), - output_expr: Some(value), + key_expr: Some(key.clone()), + output_expr: Some(value.clone()), value: Value::new_object(), result: None, results: QueryResults::default(), @@ -1487,7 +1480,7 @@ impl<'source> Interpreter<'source> { } } - fn lookup_function_by_name(&self, path: &str) -> Option<&Vec<&'source Rule>> { + fn lookup_function_by_name(&self, path: &str) -> Option<&Vec>> { let mut path = path.to_owned(); if !path.starts_with("data.") { path = self.current_module_path.clone() + "." + &path; @@ -1501,10 +1494,10 @@ impl<'source> Interpreter<'source> { fn eval_builtin_call( &mut self, - span: &'source Span, + span: &Span, name: &str, builtin: builtins::BuiltinFcn, - params: &'source [Expr], + params: &[ExprRef], ) -> Result { let mut args = vec![]; let allow_undefined = name == "print"; // TODO: with modifier @@ -1538,7 +1531,7 @@ impl<'source> Interpreter<'source> { Ok(v) } - fn lookup_builtin(&self, span: &'source Span, path: &str) -> Result> { + fn lookup_builtin(&self, span: &Span, path: &str) -> Result> { Ok(if let Some(builtin) = builtins::BUILTINS.get(path) { Some(builtin) } else if let Some(builtin) = builtins::DEPRECATED.get(path) { @@ -1551,12 +1544,7 @@ impl<'source> Interpreter<'source> { }) } - fn eval_call_impl( - &mut self, - span: &'source Span, - fcn: &'source Expr, - params: &'source [Expr], - ) -> Result { + fn eval_call_impl(&mut self, span: &Span, fcn: &ExprRef, params: &[ExprRef]) -> Result { let fcn_path = match get_path_string(fcn, None) { Ok(p) => p, _ => bail!(span.error("invalid function expression")), @@ -1590,12 +1578,12 @@ impl<'source> Interpreter<'source> { let mut results: Vec = Vec::new(); let mut errors: Vec = Vec::new(); for fcn_rule in fcns { - let (args, output_expr, bodies) = match fcn_rule { + let (args, output_expr, bodies) = match fcn_rule.as_ref() { Rule::Spec { head: RuleHead::Func { args, assign, .. }, bodies, .. - } => (args, assign.as_ref().map(|a| &a.value), bodies), + } => (args, assign.as_ref().map(|a| a.value.clone()), bodies), _ => bail!("internal error not a function"), }; @@ -1614,18 +1602,18 @@ impl<'source> Interpreter<'source> { let mut args_scope = Scope::new(); for (idx, a) in args.iter().enumerate() { - let a = match a { - Expr::Var(s) => s.text(), + let a = match a.as_ref() { + Expr::Var(s) => s.source_str(), _ => continue, // _ => unimplemented!("destructuring function arguments"), }; //TODO: check call in params - args_scope.insert(a.to_string(), self.eval_expr(¶ms[idx])?); + args_scope.insert(a, self.eval_expr(¶ms[idx])?); } let ctx = Context { key_expr: None, - output_expr, + output_expr: output_expr.clone(), value: Value::new_set(), result: None, results: QueryResults::default(), @@ -1698,33 +1686,36 @@ impl<'source> Interpreter<'source> { fn eval_call( &mut self, - span: &'source Span, - fcn: &'source Expr, - params: &'source Vec, - extra_arg: Option<&'source Expr>, + span: &Span, + fcn: &ExprRef, + params: &Vec, + extra_arg: Option, allow_return_arg: bool, ) -> Result { // TODO: global var check; interop with `some var` - match extra_arg { - Some(Expr::Var(var)) - if allow_return_arg && self.lookup_local_var(*var.text()).is_none() => - { - let value = self.eval_call_impl(span, fcn, ¶ms[..params.len() - 1])?; - if *var.text() != "_" { - self.add_variable(*var.text(), value)?; + if let Some(ea) = extra_arg { + match ea.as_ref() { + Expr::Var(var) + if allow_return_arg && self.lookup_local_var(&var.source_str()).is_none() => + { + let value = self.eval_call_impl(span, fcn, ¶ms[..params.len() - 1])?; + if *var.text() != "_" { + self.add_variable(&var.source_str(), value)?; + } + Ok(Value::Bool(true)) + } + _ => { + let ret_value = self.eval_call_impl(span, fcn, ¶ms[..params.len() - 1])?; + let value = self.eval_expr(&ea)?; + Ok(Value::Bool(ret_value == value)) } - Ok(Value::Bool(true)) - } - Some(expr) => { - let ret_value = self.eval_call_impl(span, fcn, ¶ms[..params.len() - 1])?; - let value = self.eval_expr(expr)?; - Ok(Value::Bool(ret_value == value)) } - None => self.eval_call_impl(span, fcn, params), + } else { + self.eval_call_impl(span, fcn, params) } } - fn lookup_local_var(&self, name: &str) -> Option { + fn lookup_local_var(&self, name: &SourceStr) -> Option { // Lookup local variables and arguments. for scope in self.scopes.iter().rev() { if let Some(v) = scope.get(name) { @@ -1737,19 +1728,20 @@ impl<'source> Interpreter<'source> { fn ensure_rule_evaluated(&mut self, path: String) -> Result<()> { if let Some(rules) = self.rules.get(&path) { for r in rules.clone() { - if !self.processed.contains(&Ref::make(r)) { - let module = self.get_rule_module(r)?; - self.eval_rule(module, r)?; + if !self.processed.contains(&r) { + let module = self.get_rule_module(&r)?; + self.eval_rule(&module, &r)?; } } } // Evaluate the associated default rules after non-default rules if let Some(rules) = self.default_rules.get(&path) { + dbg!(&path); for (r, _) in rules.clone() { - if !self.processed.contains(&Ref::make(r)) { - let module = self.get_rule_module(r)?; + if !self.processed.contains(&r) { + let module = self.get_rule_module(&r)?; let prev_module = self.set_current_module(Some(module))?; - self.eval_default_rule(r)?; + self.eval_default_rule(&r)?; self.set_current_module(prev_module)?; } } @@ -1757,16 +1749,16 @@ impl<'source> Interpreter<'source> { Ok(()) } - fn lookup_var(&mut self, span: &'source Span, fields: &[&str]) -> Result { - let name = span.text(); + fn lookup_var(&mut self, span: &Span, fields: &[&str]) -> Result { + let name = span.source_str(); // Return local variable/argument. - if let Some(v) = self.lookup_local_var(*name) { + if let Some(v) = self.lookup_local_var(&name) { return Ok(Self::get_value_chained(v, fields)); } // Handle input. - if *name == "input" { + if name.text() == "input" { return Ok(Self::get_value_chained(self.input.clone(), fields)); } @@ -1776,7 +1768,7 @@ impl<'source> Interpreter<'source> { } // Ensure that rules are evaluated - if *name == "data" { + if name.text() == "data" { let v = Self::get_value_chained(self.data.clone(), fields); // If the rule has already been evaluated or specified via a with modifier, @@ -1796,9 +1788,9 @@ impl<'source> Interpreter<'source> { Ok(Self::get_value_chained(self.data.clone(), fields)) } else if !self.modules.is_empty() { - let path = Parser::get_path_ref_components(&self.module.unwrap().package.refr)?; + let path = Parser::get_path_ref_components(&self.module.clone().unwrap().package.refr)?; let mut path: Vec<&str> = path.iter().map(|s| *s.text()).collect(); - path.push(*name); + path.push(name.text()); let v = Self::get_value_chained(self.data.clone(), &path); @@ -1811,7 +1803,7 @@ impl<'source> Interpreter<'source> { // Add module prefix and ensure that any matching rule is evaluated. let module_path = Self::get_path_string(&self.current_module()?.package.refr, Some("data"))?; - let rule_path = module_path + "." + *name; + let rule_path = module_path + "." + name.text(); self.ensure_rule_evaluated(rule_path)?; @@ -1822,8 +1814,8 @@ impl<'source> Interpreter<'source> { } } - fn eval_expr(&mut self, expr: &'source Expr) -> Result { - match expr { + fn eval_expr(&mut self, expr: &ExprRef) -> Result { + match expr.as_ref() { Expr::Null(_) => Ok(Value::Null), Expr::True(_) => Ok(Value::Bool(true)), Expr::False(_) => Ok(Value::Bool(false)), @@ -1872,15 +1864,15 @@ impl<'source> Interpreter<'source> { } } - fn make_rule_context(&self, head: &'source RuleHead) -> Result<(Context<'source>, Vec)> { - let mut path = Parser::get_path_ref_components(&self.module.unwrap().package.refr)?; + fn make_rule_context(&self, head: &RuleHead) -> Result<(Context, Vec)> { + let mut path = Parser::get_path_ref_components(&self.module.clone().unwrap().package.refr)?; match head { RuleHead::Compr { refr, assign, .. } => { - let output_expr = assign.as_ref().map(|assign| &assign.value); - let (refr, key_expr, value) = match refr { + let output_expr = assign.as_ref().map(|assign| assign.value.clone()); + let (refr, key_expr, value) = match refr.as_ref() { Expr::RefBrack { refr, index, .. } => { - (refr.as_ref(), Some(index.as_ref()), Value::new_object()) + (refr, Some(index.clone()), Value::new_object()) } _ => (refr, None, Value::new_array()), }; @@ -1903,7 +1895,7 @@ impl<'source> Interpreter<'source> { Ok(( Context { key_expr: None, - output_expr: key.as_ref(), + output_expr: key.clone(), value: Value::new_set(), result: None, results: QueryResults::default(), @@ -1915,10 +1907,10 @@ impl<'source> Interpreter<'source> { } } - fn get_rule_module(&self, rule: &'source Rule) -> Result<&'source Module> { + fn get_rule_module(&self, rule: &Ref) -> Result> { for m in &self.modules { - if m.policy.iter().any(|r| Ref::make(r) == Ref::make(rule)) { - return Ok(m); + if m.policy.iter().any(|r| r == rule) { + return Ok(m.clone()); } } bail!("internal error: could not find module for rule"); @@ -1926,9 +1918,9 @@ impl<'source> Interpreter<'source> { fn eval_rule_bodies( &mut self, - ctx: Context<'source>, - span: &'source Span, - bodies: &'source Vec, + ctx: Context, + span: &Span, + bodies: &Vec, ) -> Result { let n_scopes = self.scopes.len(); let result = if bodies.is_empty() { @@ -1941,7 +1933,7 @@ impl<'source> Interpreter<'source> { self.contexts.push(ctx.clone()); } else { self.contexts.pop(); - let output_expr = body.assign.as_ref().map(|e| &e.value); + let output_expr = body.assign.as_ref().map(|e| e.value.clone()); self.contexts.push(Context { key_expr: None, output_expr, @@ -2066,19 +2058,16 @@ impl<'source> Interpreter<'source> { Ok(comps.join(".")) } - fn set_current_module( - &mut self, - module: Option<&'source Module>, - ) -> Result> { - let m = self.module; - if let Some(m) = module { + fn set_current_module(&mut self, module: Option>) -> Result>> { + let m = self.module.clone(); + if let Some(m) = &module { self.current_module_path = Self::get_path_string(&m.package.refr, Some("data"))?; } self.module = module; - Ok(m) + Ok(m.clone()) } - fn get_rule_refr(rule: &'source Rule) -> &'source Expr { + fn get_rule_refr(rule: &Rule) -> &ExprRef { match rule { Rule::Spec { head, .. } => match &head { RuleHead::Compr { refr, .. } @@ -2089,9 +2078,9 @@ impl<'source> Interpreter<'source> { } } - fn check_default_value(expr: &'source Expr) -> Result<()> { + fn check_default_value(expr: &ExprRef) -> Result<()> { use Expr::*; - let (kind, span) = match expr { + let (kind, span) = match expr.as_ref() { // Scalars are supported String(_) | RawString(_) | Number(_) | True(_) | False(_) | Null(_) => return Ok(()), @@ -2137,7 +2126,7 @@ impl<'source> Interpreter<'source> { fn check_default_rules(&self) -> Result<()> { for module in &self.modules { for rule in &module.policy { - if let Rule::Default { value, .. } = rule { + if let Rule::Default { value, .. } = rule.as_ref() { Self::check_default_value(value)?; } } @@ -2145,20 +2134,21 @@ impl<'source> Interpreter<'source> { Ok(()) } - fn eval_default_rule(&mut self, rule: &'source Rule) -> Result<()> { + fn eval_default_rule(&mut self, rule: &Ref) -> Result<()> { // Skip reprocessing rule. - if self.processed.contains(&Ref::make(rule)) { + if self.processed.contains(rule) { return Ok(()); } if let Rule::Default { span, refr, value, .. - } = rule + } = rule.as_ref() { - let mut path = Parser::get_path_ref_components(&self.module.unwrap().package.refr)?; + let mut path = + Parser::get_path_ref_components(&self.module.clone().unwrap().package.refr)?; - let (refr, index) = match refr { - Expr::RefBrack { refr, index, .. } => (refr.as_ref(), Some(index.as_ref())), + let (refr, index) = match refr.as_ref() { + Expr::RefBrack { refr, index, .. } => (refr, Some(index.clone())), Expr::Var(_) => (refr, None), _ => bail!(refr.span().error(&format!( "invalid token {:?} with the default keyword", @@ -2177,7 +2167,7 @@ impl<'source> Interpreter<'source> { // 1. The corresponding variable does not have value yet // 2. The corresponding index in the object does not have value yet if let Some(index) = index { - let index = self.eval_expr(index)?; + let index = self.eval_expr(&index)?; let mut object = Value::new_object(); object.as_object_mut()?.insert(index.clone(), value); @@ -2197,7 +2187,7 @@ impl<'source> Interpreter<'source> { } }; - self.processed.insert(Ref::make(rule)); + self.processed.insert(rule.clone()); } Ok(()) @@ -2222,25 +2212,19 @@ impl<'source> Interpreter<'source> { } } - fn eval_rule(&mut self, module: &'source Module, rule: &'source Rule) -> Result<()> { + fn eval_rule(&mut self, module: &Ref, rule: &Ref) -> Result<()> { // Skip reprocessing rule - if self.processed.contains(&Ref::make(rule)) { + if self.processed.contains(rule) { return Ok(()); } // Skip default rules - if let Rule::Default { .. } = rule { + if let Rule::Default { .. } = rule.as_ref() { return Ok(()); } - self.active_rules.push(rule); - if self - .active_rules - .iter() - .filter(|&r| Ref::make(*r) == Ref::make(rule)) - .count() - == 2 - { + self.active_rules.push(rule.clone()); + if self.active_rules.iter().filter(|&r| r == rule).count() == 2 { let mut msg = String::default(); for r in &self.active_rules { let refr = Self::get_rule_refr(r); @@ -2260,9 +2244,12 @@ impl<'source> Interpreter<'source> { )); } - let prev_module = self.set_current_module(Some(module))?; + // Back up local variables of current function and empty + // the local variables of callee function. + let scopes = std::mem::take(&mut self.scopes); + let prev_module = self.set_current_module(Some(module.clone()))?; - match rule { + match rule.as_ref() { Rule::Spec { span, head: rule_head, @@ -2272,7 +2259,7 @@ impl<'source> Interpreter<'source> { RuleHead::Compr { refr, .. } | RuleHead::Set { refr, .. } => { let (ctx, mut path) = self.make_rule_context(rule_head)?; let special_set = - matches!((ctx.output_expr, &ctx.value), (None, Value::Set(_))); + matches!((&ctx.output_expr, &ctx.value), (None, Value::Set(_))); let value = match self.eval_rule_bodies(ctx, span, rule_body)? { Value::Set(_) if special_set => { let entry = path[path.len() - 1].text(); @@ -2286,7 +2273,7 @@ impl<'source> Interpreter<'source> { let paths: Vec<&str> = path.iter().map(|s| *s.text()).collect(); self.update_data(span, refr, &paths[..], value)?; - self.processed.insert(Ref::make(rule)); + self.processed.insert(rule.clone()); } RuleHead::Func { refr, .. } => { let mut path = @@ -2311,16 +2298,17 @@ impl<'source> Interpreter<'source> { _ => bail!("internal error: unexpected"), } self.set_current_module(prev_module)?; + self.scopes = scopes; match self.active_rules.pop() { - Some(r) if Ref::make(r) == Ref::make(rule) => Ok(()), + Some(ref r) if r == rule => Ok(()), _ => bail!("internal error: current rule not active"), } } pub fn eval_rule_with_input( &mut self, - module: &'source Module, - rule: &'source Rule, + module: &Ref, + rule: &Ref, input: &Option, enable_tracing: bool, ) -> Result { @@ -2334,7 +2322,7 @@ impl<'source> Interpreter<'source> { pub fn prepare_for_eval( &mut self, - schedule: Option>, + schedule: Option, data: &Option, ) -> Result<()> { self.schedule = schedule; @@ -2370,12 +2358,12 @@ impl<'source> Interpreter<'source> { self.check_default_rules()?; for module in self.modules.clone() { for rule in &module.policy { - self.eval_rule(module, rule)?; + self.eval_rule(&module, rule)?; } } // Defer the evaluation of the default rules to here for module in self.modules.clone() { - let prev_module = self.set_current_module(Some(module))?; + let prev_module = self.set_current_module(Some(module.clone()))?; for rule in &module.policy { self.eval_default_rule(rule)?; } @@ -2390,7 +2378,7 @@ impl<'source> Interpreter<'source> { data: &Option, input: &Option, enable_tracing: bool, - schedule: Option>, + schedule: Option, ) -> Result { self.prepare_for_eval(schedule, data)?; self.eval_modules(input, enable_tracing) @@ -2398,8 +2386,8 @@ impl<'source> Interpreter<'source> { pub fn eval_user_query( &mut self, - query: &'source Query, - schedule: &Schedule<'source>, + query: &Ref, + schedule: &Schedule, enable_tracing: bool, ) -> Result { self.traces = match enable_tracing { @@ -2424,7 +2412,7 @@ impl<'source> Interpreter<'source> { results: QueryResults::default(), }); - let prev_module = self.set_current_module(self.modules.last().copied())?; + let prev_module = self.set_current_module(self.modules.last().cloned())?; // Eval the query. let query_r = self.eval_query(query); @@ -2437,7 +2425,7 @@ impl<'source> Interpreter<'source> { // Restore schedules. if let Some(self_schedule) = &mut self.schedule { for (k, ord) in schedule.order.iter() { - if k == &Ref::make(query) { + if k == query { for idx in 0..results.result.len() { let mut ordered_expressions = vec![Value::Undefined; ord.len()]; for (expr_idx, value) in results.result[idx].expressions.iter().enumerate() @@ -2462,13 +2450,13 @@ impl<'source> Interpreter<'source> { fn gather_rules(&mut self) -> Result<()> { for module in self.modules.clone() { - let prev_module = self.set_current_module(Some(module))?; + let prev_module = self.set_current_module(Some(module.clone()))?; for rule in &module.policy { let refr = Self::get_rule_refr(rule); - if let Rule::Spec { .. } = rule { + if let Rule::Spec { .. } = rule.as_ref() { // Adjust refr to ensure simple ref. // TODO: refactor. - let refr = match refr { + let refr = match refr.as_ref() { Expr::RefBrack { index, .. } if matches!(index.as_ref(), Expr::String(_)) => { @@ -2481,14 +2469,14 @@ impl<'source> Interpreter<'source> { let path = self.current_module_path.clone() + "." + &path; match self.rules.entry(path) { Entry::Occupied(o) => { - o.into_mut().push(rule); + o.into_mut().push(rule.clone()); } Entry::Vacant(v) => { - v.insert(vec![rule]); + v.insert(vec![rule.clone()]); } } - } else if let Rule::Default { .. } = rule { - let (refr, index) = match refr { + } else if let Rule::Default { .. } = rule.as_ref() { + let (refr, index) = match refr.as_ref() { // TODO: Validate the index Expr::RefBrack { refr, index, .. } => { if !matches!( @@ -2501,7 +2489,7 @@ impl<'source> Interpreter<'source> { let index = self.eval_expr(index)?; - (refr.as_ref(), Some(index.to_string())) + (refr, Some(index.to_string())) } _ => (refr, None), }; @@ -2523,10 +2511,10 @@ impl<'source> Interpreter<'source> { .error("conflict type with the default rules")); } } - o.into_mut().push((rule, index)); + o.into_mut().push((rule.clone(), index)); } Entry::Vacant(v) => { - v.insert(vec![(rule, index)]); + v.insert(vec![(rule.clone(), index)]); } } } diff --git a/src/lexer.rs b/src/lexer.rs index b639df23..aad4232d 100644 --- a/src/lexer.rs +++ b/src/lexer.rs @@ -20,6 +20,63 @@ pub struct Source { src: std::rc::Rc, } +#[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 { + 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) } diff --git a/src/lib.rs b/src/lib.rs index 34d3bf38..d7dac774 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -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; diff --git a/src/parser.rs b/src/parser.rs index 54a043dc..07b303ae 100644 --- a/src/parser.rs +++ b/src/parser.rs @@ -84,8 +84,8 @@ impl<'source> Parser<'source> { } } - pub fn get_path_ref_components_into(refr: &Expr, comps: &mut Vec) -> Result<()> { - match refr { + pub fn get_path_ref_components_into(refr: &Ref, comps: &mut Vec) -> 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> { + pub fn get_path_ref_components(refr: &Ref) -> Result> { 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 { 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 { 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) -> 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 { diff --git a/src/scheduler.rs b/src/scheduler.rs index 93b66aa9..735d85f3 100644 --- a/src/scheduler.rs +++ b/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 { // 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, } #[derive(Debug)] -pub struct StmtInfo<'a> { +pub struct StmtInfo { // A statement can define multiple variables. // A variable can also be defined by multiple statement. - pub definitions: Vec>, + pub definitions: Vec>, } #[derive(Debug)] @@ -38,17 +38,21 @@ pub enum SortResult { Cycle(String, Vec), } -pub fn schedule<'a>(infos: &mut [StmtInfo<'a>]) -> Result { +pub fn schedule( + infos: &mut [StmtInfo], + empty: &Str, +) -> Result { 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> = BTreeMap::new(); + let mut defining_stmts: BTreeMap> = 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 { 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 = 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 { .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 { // 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 { // 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 { // 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 { } 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 { } #[derive(Clone, Default, Debug)] -pub struct Scope<'a> { - pub locals: BTreeSet<&'a str>, - pub inputs: BTreeSet<&'a str>, +pub struct Scope { + pub locals: BTreeSet, + pub inputs: BTreeSet, } -fn traverse<'a>(expr: &'a Expr, f: &mut dyn FnMut(&'a Expr) -> Result) -> Result<()> { +fn traverse(expr: &Ref, f: &mut dyn FnMut(&Ref) -> Result) -> 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) -> 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, 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, 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, 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, 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>, - locals: BTreeMap, Scope<'a>>, - scopes: Vec>, - order: BTreeMap, Vec>, - functions: FunctionTable<'a>, +pub struct Analyzer { + packages: BTreeMap, + locals: BTreeMap, Scope>, + scopes: Vec, + order: BTreeMap, Vec>, + functions: FunctionTable, current_module_path: String, } #[derive(Clone)] -pub struct Schedule<'a> { - pub scopes: BTreeMap, Scope<'a>>, - pub order: BTreeMap, Vec>, +pub struct Schedule { + pub scopes: BTreeMap, Scope>, + pub order: BTreeMap, Vec>, } -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 { + pub fn analyze(mut self, modules: &[Ref]) -> Result { 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> { + modules: &[Ref], + query: &Ref, + ) -> Result { 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]) -> 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) -> 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) -> 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, Option, 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>, + value: Option>, + 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>, + expr: &Ref, + scope: &mut Scope, + first_use: &mut BTreeMap, + definitions: &mut Vec>, return_arg: &Option>, - ) -> Result<(Vec<&'a str>, Vec<&'a Expr>)> { + ) -> Result<(Vec, Vec>)> { 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], + scope: &mut Scope, + first_use: &mut BTreeMap, + used_vars: &mut Vec, ) -> 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, + scope: &Scope, check_first_use: bool, - first_use: &BTreeMap<&'a str, Span>, - ) -> Result> { + first_use: &BTreeMap, + ) -> Result> { 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>, + lhs: &Ref, + rhs: &Ref, + scope: &mut Scope, + first_use: &mut BTreeMap, + definitions: &mut Vec>, ) -> 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>, + expr: &Ref, + scope: &mut Scope, + first_use: &mut BTreeMap, + definitions: &mut Vec>, ) -> 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) -> 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, + scope: &Scope, + _first_use: &BTreeMap, + vars: &mut Vec, + non_vars: &mut Vec>, ) -> 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>, + value: Option>, + query: &Ref, + 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(()) } diff --git a/src/utils.rs b/src/utils.rs index e2524807..f3085361 100644 --- a/src/utils.rs +++ b/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 { Ok(comps.join(".")) } -pub type FunctionTable<'a> = BTreeMap, u8)>; +pub type FunctionTable = BTreeMap>, u8)>; -fn get_extra_arg_impl<'a>( - expr: &'a Expr, +fn get_extra_arg_impl( + expr: &Expr, module: Option<&str>, functions: &FunctionTable, -) -> Result> { +) -> Result>> { 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> { match get_extra_arg_impl(expr, module, functions) { Ok(a) => a, _ => None, } } -pub fn gather_functions<'a>(modules: &[&'a Module]) -> Result> { +pub fn gather_functions(modules: &[Ref]) -> Result { let mut table = FunctionTable::new(); for module in modules { @@ -86,7 +87,7 @@ pub fn gather_functions<'a>(modules: &[&'a Module]) -> Result> 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> .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> Ok(table) } -pub fn get_root_var(mut expr: &Expr) -> Result<&str> { +pub fn get_root_var(mut expr: &Expr) -> Result { 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"), } diff --git a/tests/interpreter/mod.rs b/tests/interpreter/mod.rs index f103a78f..c5af5ab9 100644 --- a/tests/interpreter/mod.rs +++ b/tests/interpreter/mod.rs @@ -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(" Result<()> { } } -fn match_vec(s: &Span, vec: &Vec, v: &Value) -> Result<()> { +fn match_vec(s: &Span, vec: &Vec>, 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, 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, Ref)>, 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, v: &Value) -> Result<()> { +fn match_expr_opt(s: &Span, e: &Option>, v: &Value) -> Result<()> { match (e, v) { (Some(e), v) => match_expr(e, v), (None, Value::Undefined) => Ok(()), diff --git a/tests/scheduler/analyzer/mod.rs b/tests/scheduler/analyzer/mod.rs index 26f5a936..cda57cfa 100644 --- a/tests/scheduler/analyzer/mod.rs +++ b/tests/scheduler/analyzer/mod.rs @@ -27,7 +27,7 @@ struct YamlTest { cases: Vec, } -fn to_string_set(s: &BTreeSet<&str>) -> BTreeSet { +fn to_string_set(s: &BTreeSet) -> BTreeSet { 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, ®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() { diff --git a/tests/scheduler/mod.rs b/tests/scheduler/mod.rs index c3bc2467..a8d3e072 100644 --- a/tests/scheduler/mod.rs +++ b/tests/scheduler/mod.rs @@ -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, &"")?) }