mirror of
https://github.com/microsoft/regorus.git
synced 2026-08-05 02:16:11 +00:00
feat!: Indexes for nodes in the AST (#414)
Indexes allow associating extra data with nodes in the AST using an array and then quickly looking up the array to fetch the extra data. - Index eidx for expressions - Index sidx for statements - Index qidx for queries. AST nodes are not cloneable. Therefore once a module is created, it is not possible to accidentally create two nodes with the same index inadvertently via clone. Also added IndexChecker in debug builds. When a module is parsed, it will assert that indexes have been constructed correctly. AST Cleanup - Make literal expressions (null, val, number, string etc) also structs to match all other expressions - Merge True and False nodes into a single Bool node. Also update dependencies. Signed-off-by: Anand Krishnamoorthi <anakrish@microsoft.com>
This commit is contained in:
committed by
GitHub
parent
620f8a4547
commit
444b2970a1
+126
-28
@@ -101,23 +101,27 @@ fn match_expr_impl(e: &Expr, v: &Value) -> Result<()> {
|
||||
if skip_value(v) {
|
||||
return Ok(());
|
||||
}
|
||||
|
||||
match e {
|
||||
Expr::String(s) => match_span(&s.0, &v["string"]),
|
||||
Expr::RawString(s) => match_span(&s.0, &v["rawstring"]),
|
||||
Expr::Number(s) => match_span(&s.0, &v["number"]),
|
||||
Expr::True(s) => match_span(s, v),
|
||||
Expr::False(s) => match_span(s, v),
|
||||
Expr::Null(s) => match_span(s, v),
|
||||
Expr::Var(s) => match_span(&s.0, &v["var"]),
|
||||
Expr::Array { span, items } => match_vec(span, items, &v["array"]),
|
||||
Expr::Set { span, items } => match_vec(span, items, &v["set"]),
|
||||
Expr::Object { span, fields } => match_object(span, fields, &v["object"]),
|
||||
Expr::ArrayCompr { span, term, query } => {
|
||||
Expr::String { span: s, .. } => match_span(s, &v["string"]),
|
||||
Expr::RawString { span: s, .. } => match_span(s, &v["rawstring"]),
|
||||
Expr::Number { span: s, .. } => match_span(s, &v["number"]),
|
||||
Expr::Bool { span: s, .. } => match_span(s, &v["bool"]),
|
||||
Expr::Null { span: s, .. } => match_span(s, &v["null"]),
|
||||
Expr::Var { span: s, .. } => match_span(s, &v["var"]),
|
||||
Expr::Array { span, items, .. } => match_vec(span, items, &v["array"]),
|
||||
Expr::Set { span, items, .. } => match_vec(span, items, &v["set"]),
|
||||
Expr::Object { span, fields, .. } => match_object(span, fields, &v["object"]),
|
||||
Expr::ArrayCompr {
|
||||
span, term, query, ..
|
||||
} => {
|
||||
match_span_opt(span, &v["arraycompr"]["span"])?;
|
||||
match_expr(term, &v["arraycompr"]["term"])?;
|
||||
match_query(query, &v["arraycompr"]["query"])
|
||||
}
|
||||
Expr::SetCompr { span, term, query } => {
|
||||
Expr::SetCompr {
|
||||
span, term, query, ..
|
||||
} => {
|
||||
match_span_opt(span, &v["setcompr"]["span"])?;
|
||||
match_expr(term, &v["setcompr"]["term"])?;
|
||||
match_query(query, &v["setcompr"]["query"])
|
||||
@@ -127,28 +131,35 @@ fn match_expr_impl(e: &Expr, v: &Value) -> Result<()> {
|
||||
key,
|
||||
value,
|
||||
query,
|
||||
..
|
||||
} => {
|
||||
match_span_opt(span, &v["objectcompr"]["span"])?;
|
||||
match_expr(key, &v["objectcompr"]["key"])?;
|
||||
match_expr(value, &v["objectcompr"]["value"])?;
|
||||
match_query(query, &v["objectcompr"]["query"])
|
||||
}
|
||||
Expr::Call { span, fcn, params } => {
|
||||
Expr::Call {
|
||||
span, fcn, params, ..
|
||||
} => {
|
||||
match_span_opt(span, &v["call"]["span"])?;
|
||||
match_expr(fcn, &v["call"]["fcn"])?;
|
||||
match_vec(span /*dummy*/, params, &v["call"]["params"])
|
||||
}
|
||||
Expr::RefDot { span, refr, field } => {
|
||||
Expr::RefDot {
|
||||
span, refr, field, ..
|
||||
} => {
|
||||
match_span_opt(span, &v["refdot"]["span"])?;
|
||||
match_expr(refr, &v["refdot"]["refr"])?;
|
||||
match_span(&field.0, &v["refdot"]["field"])
|
||||
}
|
||||
Expr::RefBrack { span, refr, index } => {
|
||||
Expr::RefBrack {
|
||||
span, refr, index, ..
|
||||
} => {
|
||||
match_span_opt(span, &v["refbrack"]["span"])?;
|
||||
match_expr(refr, &v["refbrack"]["refr"])?;
|
||||
match_expr(index, &v["refbrack"]["index"])
|
||||
}
|
||||
Expr::UnaryExpr { span, expr } => {
|
||||
Expr::UnaryExpr { span, expr, .. } => {
|
||||
match_span_opt(span, &v["span"])?;
|
||||
my_assert_eq!(
|
||||
&Value::String("-".into()),
|
||||
@@ -163,25 +174,33 @@ fn match_expr_impl(e: &Expr, v: &Value) -> Result<()> {
|
||||
);
|
||||
match_expr(expr, &v["expr"])
|
||||
}
|
||||
Expr::BinExpr { span, op, lhs, rhs } => {
|
||||
Expr::BinExpr {
|
||||
span, op, lhs, rhs, ..
|
||||
} => {
|
||||
match_span_opt(span, &v["binexpr"]["span"])?;
|
||||
match_bin_op(span, op, &v["binexpr"]["op"])?;
|
||||
match_expr(lhs, &v["binexpr"]["lhs"])?;
|
||||
match_expr(rhs, &v["binexpr"]["rhs"])
|
||||
}
|
||||
Expr::ArithExpr { span, op, lhs, rhs } => {
|
||||
Expr::ArithExpr {
|
||||
span, op, lhs, rhs, ..
|
||||
} => {
|
||||
match_span_opt(span, &v["arithexpr"]["span"])?;
|
||||
match_arith_op(span, op, &v["arithexpr"]["op"])?;
|
||||
match_expr(lhs, &v["arithexpr"]["lhs"])?;
|
||||
match_expr(rhs, &v["arithexpr"]["rhs"])
|
||||
}
|
||||
Expr::BoolExpr { span, op, lhs, rhs } => {
|
||||
Expr::BoolExpr {
|
||||
span, op, lhs, rhs, ..
|
||||
} => {
|
||||
match_span_opt(span, &v["boolexpr"]["span"])?;
|
||||
match_bool_op(span, op, &v["boolexpr"]["op"])?;
|
||||
match_expr(lhs, &v["boolexpr"]["lhs"])?;
|
||||
match_expr(rhs, &v["boolexpr"]["rhs"])
|
||||
}
|
||||
Expr::AssignExpr { span, op, lhs, rhs } => {
|
||||
Expr::AssignExpr {
|
||||
span, op, lhs, rhs, ..
|
||||
} => {
|
||||
match_span_opt(span, &v["assignexpr"]["span"])?;
|
||||
match_assign_op(span, op, &v["assignexpr"]["op"])?;
|
||||
match_expr(lhs, &v["assignexpr"]["lhs"])?;
|
||||
@@ -192,6 +211,7 @@ fn match_expr_impl(e: &Expr, v: &Value) -> Result<()> {
|
||||
key,
|
||||
value,
|
||||
collection,
|
||||
..
|
||||
} => {
|
||||
match_span_opt(span, &v["inexpr"]["span"])?;
|
||||
match_expr_opt(span, key, &v["inexpr"]["key"])?;
|
||||
@@ -200,22 +220,45 @@ fn match_expr_impl(e: &Expr, v: &Value) -> Result<()> {
|
||||
}
|
||||
|
||||
#[cfg(feature = "rego-extensions")]
|
||||
Expr::OrExpr { span, lhs, rhs } => {
|
||||
Expr::OrExpr { span, lhs, rhs, .. } => {
|
||||
match_span_opt(span, &v["orexpr"]["span"])?;
|
||||
match_expr(lhs, &v["orexpr"]["lhs"])?;
|
||||
match_expr(rhs, &v["orexpr"]["rhs"])
|
||||
}
|
||||
}?;
|
||||
|
||||
match (e.eidx(), &v["eidx"]) {
|
||||
(eidx, Value::Number(n)) if n.as_u64() == Some(eidx as u64) => Ok(()),
|
||||
_ => {
|
||||
bail!(
|
||||
"{}",
|
||||
e.span().message(
|
||||
"mismatch-error",
|
||||
format!(
|
||||
"eidx mismatch: expected {:?}, got {:?}",
|
||||
v["eidx"],
|
||||
e.eidx(),
|
||||
)
|
||||
.as_str()
|
||||
)
|
||||
);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
#[allow(clippy::let_and_return)]
|
||||
fn match_expr(expr: &Expr, v: &Value) -> Result<()> {
|
||||
match match_expr_impl(expr, v) {
|
||||
Ok(()) => Ok(()),
|
||||
Err(e) => bail!(
|
||||
"{e}\nexpr = {expr:#?}\nv={}\n-----------------------\n",
|
||||
serde_json::to_string_pretty(v)?
|
||||
),
|
||||
}
|
||||
let r = match_expr_impl(expr, v);
|
||||
|
||||
// Uncomment the following lines to print mismatch at each expression
|
||||
// nesting level.
|
||||
// if let Err(e) = &r {
|
||||
// bail!(
|
||||
// "{e}\nexpr = {expr:#?}\nv={}\n-----------------------\n",
|
||||
// serde_json::to_string_pretty(v)?
|
||||
// );
|
||||
// }
|
||||
r
|
||||
}
|
||||
|
||||
fn match_with_mod(m: &WithModifier, v: &Value) -> Result<()> {
|
||||
@@ -231,6 +274,20 @@ fn match_literal_stmt(ls: &LiteralStmt, v: &Value) -> Result<()> {
|
||||
if skip_value(v) {
|
||||
return Ok(());
|
||||
}
|
||||
|
||||
match &v["sidx"] {
|
||||
Value::Number(n) if n.as_u64() == Some(ls.sidx as u64) => (),
|
||||
_ => {
|
||||
bail!(
|
||||
"{}",
|
||||
ls.span.message(
|
||||
"mismatch-error",
|
||||
format!("sidx mismatch: expected {:?}, got {:?}", v["sidx"], ls.sidx).as_str()
|
||||
)
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
match_span_opt(&ls.span, &v["span"])?;
|
||||
match_literal(&ls.literal, &v["literal"])?;
|
||||
|
||||
@@ -273,6 +330,19 @@ fn match_literal_stmt(ls: &LiteralStmt, v: &Value) -> Result<()> {
|
||||
}
|
||||
|
||||
fn match_query(q: &Query, v: &Value) -> Result<()> {
|
||||
match &v["qidx"] {
|
||||
Value::Number(n) if n.as_u64() == Some(q.qidx as u64) => (),
|
||||
_ => {
|
||||
bail!(
|
||||
"{}",
|
||||
q.span.message(
|
||||
"mismatch-error",
|
||||
format!("qidx mismatch: expected {:?}, got {:?}", v["qidx"], q.qidx).as_str()
|
||||
)
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
match_span_opt(&q.span, &v["span"])?;
|
||||
let stmts = &v["stmts"].as_array();
|
||||
let stmts = match &stmts {
|
||||
@@ -622,6 +692,15 @@ struct TestCase {
|
||||
imports: Option<Vec<Value>>,
|
||||
policy: Option<Vec<Value>>,
|
||||
error: Option<String>,
|
||||
|
||||
#[serde(default)]
|
||||
num_expressions: u32,
|
||||
|
||||
#[serde(default)]
|
||||
num_statements: u32,
|
||||
|
||||
#[serde(default)]
|
||||
num_queries: u32,
|
||||
}
|
||||
|
||||
#[derive(Serialize, Deserialize, PartialEq, Debug)]
|
||||
@@ -644,6 +723,25 @@ fn yaml_test_impl(file: &str) -> Result<()> {
|
||||
if let Some(e) = &case.error {
|
||||
bail!("error `{}` not raised by parser.", e);
|
||||
}
|
||||
|
||||
my_assert_eq!(
|
||||
module.num_expressions,
|
||||
case.num_expressions,
|
||||
"mismatch in num_expressions"
|
||||
);
|
||||
|
||||
my_assert_eq!(
|
||||
module.num_statements,
|
||||
case.num_statements,
|
||||
"mismatch in num_statements"
|
||||
);
|
||||
|
||||
my_assert_eq!(
|
||||
module.num_queries,
|
||||
case.num_queries,
|
||||
"mismatch in num_queries"
|
||||
);
|
||||
|
||||
if let Some(p) = &case.package {
|
||||
match_package(&module.package, p)?;
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user