Skip to content

Commit

Permalink
Fixing an issue with implicit enum statement capture (#103)
Browse files Browse the repository at this point in the history
- Fixes an issue with implicit enum statement capture
- Fixes an issue when rule definitions are on a new line and are missing an assign operator

Signed-off-by: Matthew Johnson <matjoh@microsoft.com>

---------

Signed-off-by: Matthew Johnson <matjoh@microsoft.com>
  • Loading branch information
matajoh authored Jan 23, 2024
1 parent 3f3c517 commit 60058a7
Show file tree
Hide file tree
Showing 6 changed files with 128 additions and 7 deletions.
2 changes: 1 addition & 1 deletion include/rego/rego.hh
Original file line number Diff line number Diff line change
Expand Up @@ -708,7 +708,7 @@ namespace rego
inline const auto wf_pass_init =
wf_pass_simple_refs
| (UnifyBody <<= (Local | Literal | LiteralWith | LiteralEnum | LiteralNot | LiteralInit)++[1])
| (LiteralInit <<= VarSeq * VarSeq * AssignInfix)
| (LiteralInit <<= (Lhs >>= VarSeq) * (Rhs >>= VarSeq) * AssignInfix)
;
// clang-format on

Expand Down
1 change: 0 additions & 1 deletion src/parse.cc
Original file line number Diff line number Diff line change
@@ -1,5 +1,4 @@
#include "internal.hh"
#include "rego.hh"

namespace rego
{
Expand Down
74 changes: 70 additions & 4 deletions src/passes/enumerate.cc
Original file line number Diff line number Diff line change
Expand Up @@ -65,6 +65,64 @@ namespace
auto it = unifybody->find(local) + 1;
return find_enum(unifybody, it);
}

void vars_from(Node node, std::set<Location>& vars)
{
if (node->type() == Var)
{
vars.insert(node->location());
}

for (Node child : *node)
{
vars_from(child, vars);
}
}

// Determines which statements following an implicit enum statement are needed
// to instantiate the item sequence for that enum and adds them to the outside
// list. Otherwise they should be captured by the enum and are placed in the
// inside list.
void capture_statements(
const NodeRange tail,
Node itemseq,
std::vector<Node>& outside,
std::vector<Node>& inside)
{
std::set<Location> vars;
vars_from(itemseq, vars);
for (auto it = tail.first; it != tail.second; ++it)
{
Node stmt = *it;
if (stmt->type() == LiteralInit)
{
std::set<Location> init_vars;
vars_from(stmt / Lhs, init_vars);
vars_from(stmt / Rhs, init_vars);
std::set<Location> intersection;
std::set_intersection(
vars.begin(),
vars.end(),
init_vars.begin(),
init_vars.end(),
std::inserter(intersection, intersection.begin()));
if (intersection.empty())
{
inside.push_back(stmt);
}
else
{
// the item sequence depends on this init, so it must
// be outside the enum.
outside.push_back(stmt);
}
}
else
{
inside.push_back(stmt);
}
}
}
}

namespace rego
Expand Down Expand Up @@ -170,10 +228,14 @@ namespace rego
return err(idx, "Invalid index for enumeration");
}

std::vector<Node> outside;
std::vector<Node> inside;
capture_statements(_[Tail], _(ItemSeq), outside, inside);

auto temp = _.fresh({"enum"});
auto item = _.fresh({"item"});
return Seq
<< (Local << (Var ^ item) << Undefined)
<< outside << (Local << (Var ^ item) << Undefined)
<< (LiteralEnum
<< (Var ^ item) << _(ItemSeq)
<< (UnifyBody
Expand All @@ -197,7 +259,7 @@ namespace rego
<< (Var ^ item)
<< (RefArgBrack
<< (Scalar << (Int ^ "1"))))))))
<< _[Tail]));
<< inside));
},

In(UnifyBody) *
Expand Down Expand Up @@ -240,10 +302,14 @@ namespace rego
idx = Term << idx;
}

std::vector<Node> outside;
std::vector<Node> inside;
capture_statements(_[Tail], _(ItemSeq), outside, inside);

auto temp = _.fresh({"enum"});
auto item = _.fresh({"item"});
return Seq
<< (Local << (Var ^ item) << Undefined)
<< outside << (Local << (Var ^ item) << Undefined)
<< (LiteralEnum
<< (Var ^ item) << _(ItemSeq)
<< (UnifyBody
Expand All @@ -268,7 +334,7 @@ namespace rego
<< (RefArgBrack
<< (Scalar
<< (Int ^ "1")))))))))
<< _[Tail]));
<< inside));
},
}};
}
Expand Down
1 change: 0 additions & 1 deletion src/passes/init.cc
Original file line number Diff line number Diff line change
Expand Up @@ -3,7 +3,6 @@
#include <algorithm>
#include <cstddef>
#include <deque>
#include <stdexcept>

namespace
{
Expand Down
7 changes: 7 additions & 0 deletions src/passes/rules.cc
Original file line number Diff line number Diff line change
Expand Up @@ -317,6 +317,13 @@ namespace rego
return Seq << _[RuleRef];
},

In(Policy) * (T(Group) << T(Var)[Var]) *
(T(Group) << T(UnifyBody)[UnifyBody]) >>
[](Match& _) {
ACTION();
return Group << _(Var) << _(UnifyBody);
},

// errors

In(Policy) * T(Group)[Group] >>
Expand Down
50 changes: 50 additions & 0 deletions tests/regocpp.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -1122,3 +1122,53 @@ cases:
- 1
- 2
- 3
- note: regocpp/bug101
modules:
- |
package test
x = y {
y = [z |
z = a[_]
a = [1, 2, 3]
]
}
query: data.test.x = x
want_result:
- x:
- 1
- 2
- 3
- note: regocpp/non-monotone
modules:
- |
package test
ips_by_port := {
80: ["1.1.1.1", "1.1.1.2"],
443: ["2.2.2.1"],
}
default foo1 := false
default foo2 := false
foo1
{
port = 77;
a = [port | ips_by_port[port][_] == "2.2.2.1" ];
b = [port | ips_by_port[port][_] == "1.1.1.1" ];
a = b
}
foo2
{
a = [port | ips_by_port[port][_] == "2.2.2.1" ];
b = [port | ips_by_port[port][_] == "1.1.1.1" ];
a = b
}
query: [data.test.foo1, data.test.foo2] = x
want_result:
- x:
- true
- false

0 comments on commit 60058a7

Please sign in to comment.