Avoid dependency on `source lifetime. (#43)

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

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

View File

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

View File

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

View File

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

View File

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