mirror of
https://github.com/microsoft/regorus.git
synced 2026-08-05 02:16:11 +00:00
fix: Implement RVM set ops correctly
- treat set subtraction in RVM the same as the interpreter by supporting Value::Set operands in sub_values - emit internal-only builtin names for set union/intersection and register handlers so compiled bytecode resolves without exposing new Rego builtins - add regression coverage for literal set difference/intersection (x/y from failure.rego) in tests/rvm/rego/cases/sets.yaml Signed-off-by: Anand Krishnamoorthi <anakrish@microsoft.com>
This commit is contained in:
@@ -15,6 +15,8 @@ use anyhow::{bail, Result};
|
||||
pub fn register(m: &mut builtins::BuiltinsMap<&'static str, builtins::BuiltinFcn>) {
|
||||
m.insert("intersection", (intersection_of_set_of_sets, 1));
|
||||
m.insert("union", (union_of_set_of_sets, 1));
|
||||
m.insert("__builtin_sets.union", (binary_set_union, 2));
|
||||
m.insert("__builtin_sets.intersection", (binary_set_intersection, 2));
|
||||
}
|
||||
|
||||
pub fn intersection(expr1: &Expr, expr2: &Expr, v1: Value, v2: Value) -> Result<Value> {
|
||||
@@ -35,6 +37,34 @@ pub fn difference(expr1: &Expr, expr2: &Expr, v1: Value, v2: Value) -> Result<Va
|
||||
Ok(Value::from_set(s1.difference(&s2).cloned().collect()))
|
||||
}
|
||||
|
||||
fn binary_set_union(
|
||||
span: &Span,
|
||||
params: &[Ref<Expr>],
|
||||
args: &[Value],
|
||||
_strict: bool,
|
||||
) -> Result<Value> {
|
||||
let name = "__builtin_sets.union";
|
||||
ensure_args_count(span, name, params, args, 2)?;
|
||||
let left = ensure_set(name, ¶ms[0], args[0].clone())?;
|
||||
let right = ensure_set(name, ¶ms[1], args[1].clone())?;
|
||||
Ok(Value::from_set(left.union(&right).cloned().collect()))
|
||||
}
|
||||
|
||||
fn binary_set_intersection(
|
||||
span: &Span,
|
||||
params: &[Ref<Expr>],
|
||||
args: &[Value],
|
||||
_strict: bool,
|
||||
) -> Result<Value> {
|
||||
let name = "__builtin_sets.intersection";
|
||||
ensure_args_count(span, name, params, args, 2)?;
|
||||
let left = ensure_set(name, ¶ms[0], args[0].clone())?;
|
||||
let right = ensure_set(name, ¶ms[1], args[1].clone())?;
|
||||
Ok(Value::from_set(
|
||||
left.intersection(&right).cloned().collect(),
|
||||
))
|
||||
}
|
||||
|
||||
fn intersection_of_set_of_sets(
|
||||
span: &Span,
|
||||
params: &[Ref<Expr>],
|
||||
|
||||
@@ -142,7 +142,7 @@ impl<'a> Compiler<'a> {
|
||||
|
||||
match op {
|
||||
BinOp::Union => {
|
||||
let builtin_index = self.get_builtin_index("sets.union")?;
|
||||
let builtin_index = self.get_builtin_index("__builtin_sets.union")?;
|
||||
let params = BuiltinCallParams {
|
||||
dest,
|
||||
builtin_index,
|
||||
@@ -156,7 +156,7 @@ impl<'a> Compiler<'a> {
|
||||
self.emit_instruction(Instruction::BuiltinCall { params_index }, span);
|
||||
}
|
||||
BinOp::Intersection => {
|
||||
let builtin_index = self.get_builtin_index("sets.intersection")?;
|
||||
let builtin_index = self.get_builtin_index("__builtin_sets.intersection")?;
|
||||
let params = BuiltinCallParams {
|
||||
dest,
|
||||
builtin_index,
|
||||
|
||||
@@ -1,6 +1,8 @@
|
||||
// Copyright (c) Microsoft Corporation.
|
||||
// Licensed under the MIT License.
|
||||
|
||||
use alloc::collections::BTreeSet;
|
||||
|
||||
use crate::number::Number;
|
||||
use crate::value::Value;
|
||||
|
||||
@@ -23,6 +25,10 @@ impl RegoVM {
|
||||
pub(super) fn sub_values(&self, a: &Value, b: &Value) -> Result<Value> {
|
||||
match (a, b) {
|
||||
(Value::Number(x), Value::Number(y)) => Ok(Value::from(x.sub(y)?)),
|
||||
(Value::Set(left), Value::Set(right)) => {
|
||||
let diff: BTreeSet<Value> = left.difference(right).cloned().collect();
|
||||
Ok(Value::from_set(diff))
|
||||
}
|
||||
_ => Err(VmError::InvalidSubtraction {
|
||||
left: a.clone(),
|
||||
right: b.clone(),
|
||||
|
||||
@@ -67,3 +67,23 @@ cases:
|
||||
- set!: [1, 2]
|
||||
- set!: [3, 4]
|
||||
- set!: ["a", "b"]
|
||||
|
||||
- note: set_difference_literals
|
||||
data: {}
|
||||
modules:
|
||||
- |
|
||||
package test
|
||||
x := {2, 3} - {4, 2}
|
||||
query: data.test.x
|
||||
want_result:
|
||||
set!: [3]
|
||||
|
||||
- note: set_intersection_literals
|
||||
data: {}
|
||||
modules:
|
||||
- |
|
||||
package test
|
||||
y := {2, 3} & {4, 2}
|
||||
query: data.test.y
|
||||
want_result:
|
||||
set!: [2]
|
||||
|
||||
Reference in New Issue
Block a user