mirror of
https://github.com/microsoft/regorus.git
synced 2026-08-05 02:16:11 +00:00
Implement comparison operators. Formalize semantics.
Rename compare.rs to comparison.rs to match OPA documentation of builtins. Also update loop handling to ensure that the current scope is restored after each iteration of the loop so as to undo side effects of the iteration. Signed-off-by: Anand Krishnamoorthi <anakrish@microsoft.com>
This commit is contained in:
@@ -1,30 +0,0 @@
|
||||
// Copyright (c) Microsoft Corporation.
|
||||
// Licensed under the MIT License.
|
||||
|
||||
use crate::ast::*;
|
||||
use crate::value::{Value::*, *};
|
||||
|
||||
pub fn eq(v1: &Value, v2: &Value) -> Value {
|
||||
match (v1, v2) {
|
||||
(Undefined, _) | (_, Undefined) => Undefined,
|
||||
_ => Bool(v1 == v2),
|
||||
}
|
||||
}
|
||||
|
||||
pub fn ne(v1: &Value, v2: &Value) -> Value {
|
||||
match (v1, v2) {
|
||||
(Undefined, _) | (_, Undefined) => Undefined,
|
||||
_ => Bool(v1 != v2),
|
||||
}
|
||||
}
|
||||
|
||||
pub fn compare(op: &BoolOp, v1: &Value, v2: &Value) -> Value {
|
||||
match op {
|
||||
BoolOp::Eq => eq(v1, v2),
|
||||
BoolOp::Ne => ne(v1, v2),
|
||||
BoolOp::Ge => Bool(v1 >= v2),
|
||||
BoolOp::Gt => Bool(v1 > v2),
|
||||
BoolOp::Le => Bool(v1 <= v2),
|
||||
BoolOp::Lt => Bool(v1 < v2),
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,60 @@
|
||||
// Copyright (c) Microsoft Corporation.
|
||||
// Licensed under the MIT License.
|
||||
|
||||
use crate::ast::BoolOp;
|
||||
use crate::value::Value;
|
||||
|
||||
use anyhow::Result;
|
||||
|
||||
/// compare two values
|
||||
///
|
||||
/// When comparing values of different kinds, the following order is honored.
|
||||
/// That is, null is less than all other kinds of values. bool is greater than
|
||||
/// null, but less than other kinds of values, and so on.
|
||||
///
|
||||
/// 1. null
|
||||
/// 2. bool
|
||||
/// 3. number
|
||||
/// 4. string
|
||||
/// 5. Array
|
||||
/// 6. Object
|
||||
/// 7. Set
|
||||
///
|
||||
/// Scalar types like null, bool, number, string follow ordering same as what is seen in other languages when compared with values of the same kind.
|
||||
///
|
||||
/// When comparing arrays, each item from the first array is compared with the corresponding item from the second array. The ordering is determined by
|
||||
// the ordering of the first non-equal items. In case all the compared items
|
||||
/// are equal, the ordering is determined by comparing the length of the first array
|
||||
/// with the length of the second array. The smaller array is 'Less' than the larger array.
|
||||
///
|
||||
/// Sets compare similar to arrays.
|
||||
///
|
||||
/// When comparing objects, each entry (key, value) from the first object is compared with the corresponding
|
||||
/// entry from the second object. The ordering is determined by the ordering of the first non-equal entries. In case all the compared entries are equal,
|
||||
/// the ordering is determined by comparing the length of the first object with the length of the second object. The smaller object is 'Less' then the larger object.
|
||||
///
|
||||
/// Undefined values are a special case. Comparing an Undefined value with
|
||||
/// any other value results in Undefined.
|
||||
///
|
||||
/// # Arguments
|
||||
/// * `op` - The comparison operation to perform.
|
||||
/// * `v1` - The first value.
|
||||
/// * `v2` - The second value.
|
||||
pub fn compare(op: &BoolOp, v1: &Value, v2: &Value) -> Result<Value> {
|
||||
// Handle undefined values.
|
||||
if v1 == &Value::Undefined || v2 == &Value::Undefined {
|
||||
return Ok(Value::Undefined);
|
||||
}
|
||||
|
||||
// Rely on generated comparison operators.
|
||||
// The variants of Value enum are specified in the order necessary to
|
||||
// obtain the desired semantics.
|
||||
Ok(Value::Bool(match op {
|
||||
BoolOp::Eq => v1 == v2,
|
||||
BoolOp::Ne => v1 != v2,
|
||||
BoolOp::Lt => v1 < v2,
|
||||
BoolOp::Le => v1 <= v2,
|
||||
BoolOp::Gt => v1 > v2,
|
||||
BoolOp::Ge => v1 >= v2,
|
||||
}))
|
||||
}
|
||||
+2
-2
@@ -1,6 +1,6 @@
|
||||
// Copyright (c) Microsoft Corporation.
|
||||
// Licensed under the MIT License.
|
||||
|
||||
mod compare;
|
||||
mod comparison;
|
||||
|
||||
pub use self::compare::*;
|
||||
pub use self::comparison::*;
|
||||
|
||||
+28
-6
@@ -262,7 +262,7 @@ impl<'source> Interpreter<'source> {
|
||||
) -> Result<Value> {
|
||||
let lhs = self.eval_expr(lhs_expr)?;
|
||||
let rhs = self.eval_expr(rhs_expr)?;
|
||||
Ok(builtins::compare(op, &lhs, &rhs))
|
||||
builtins::compare(op, &lhs, &rhs)
|
||||
}
|
||||
|
||||
fn eval_bin_expr(
|
||||
@@ -531,10 +531,23 @@ impl<'source> Interpreter<'source> {
|
||||
if loops.is_empty() {
|
||||
if !stmts.is_empty() {
|
||||
// Evaluate the current statement whose loop expressions have been hoisted.
|
||||
if !self.eval_stmt(&stmts[0])? {
|
||||
return Ok(false);
|
||||
}
|
||||
self.eval_stmts(&stmts[1..])
|
||||
// Save the current scope and restore it after evaluating the statements so
|
||||
// that the effects of the current loop iteration are cleared.
|
||||
let scope_saved = match self.scopes.last() {
|
||||
Some(scope) => scope.clone(),
|
||||
_ => bail!("internal error: missing scope"),
|
||||
};
|
||||
let result = if self.eval_stmt(&stmts[0])? {
|
||||
self.eval_stmts(&stmts[1..])
|
||||
} else {
|
||||
Ok(false)
|
||||
};
|
||||
|
||||
match self.scopes.last_mut() {
|
||||
Some(scope) => *scope = scope_saved,
|
||||
_ => bail!("internal error: missing scope"),
|
||||
};
|
||||
result
|
||||
} else {
|
||||
self.eval_stmts(stmts)
|
||||
}
|
||||
@@ -568,7 +581,7 @@ impl<'source> Interpreter<'source> {
|
||||
));
|
||||
}
|
||||
}
|
||||
self.loop_var_values.remove(loop_expr.expr);
|
||||
|
||||
// Return true if at least on iteration returned true
|
||||
Ok(result)
|
||||
}
|
||||
@@ -1617,6 +1630,15 @@ impl<'source> Interpreter<'source> {
|
||||
if let Some(data) = data {
|
||||
self.data = data.clone();
|
||||
}
|
||||
// Ensure that each module has an empty object
|
||||
for m in &self.modules {
|
||||
let path = Parser::get_path_ref_components(&m.package.refr)?;
|
||||
let path: Vec<&str> = path.iter().map(|s| s.text()).collect();
|
||||
let vref = Self::make_or_get_value_mut(&mut self.data, &path[..])?;
|
||||
if *vref == Value::Undefined {
|
||||
*vref = Value::new_object();
|
||||
}
|
||||
}
|
||||
|
||||
self.check_default_rules()?;
|
||||
self.update_function_table()?;
|
||||
|
||||
+1
-1
@@ -87,8 +87,8 @@ pub enum Value {
|
||||
// Json data types. serde will automatically map json to these variants.
|
||||
Null,
|
||||
Bool(bool),
|
||||
String(String),
|
||||
Number(Number),
|
||||
String(String),
|
||||
Array(Rc<Vec<Value>>),
|
||||
Object(Rc<BTreeMap<Value, Value>>),
|
||||
|
||||
|
||||
@@ -2,233 +2,568 @@
|
||||
# Licensed under the MIT License.
|
||||
|
||||
cases:
|
||||
- note: number-equals
|
||||
- note: undefined
|
||||
data: {}
|
||||
modules:
|
||||
- |
|
||||
package test
|
||||
import future.keywords.if
|
||||
# All the following rules will be undefined.
|
||||
x if false
|
||||
|
||||
v = 1
|
||||
r = [
|
||||
# Comparison with number
|
||||
v == 1,
|
||||
v == 2,
|
||||
|
||||
# Comparison with primitives
|
||||
v == null,
|
||||
v == "hello",
|
||||
v == true,
|
||||
v == false,
|
||||
|
||||
# Comparison with arrays
|
||||
v == [],
|
||||
v == [v],
|
||||
|
||||
# Comparison with sets
|
||||
v == set(),
|
||||
v == { v },
|
||||
|
||||
# Comparison with objects
|
||||
v == {},
|
||||
v == { "a": v},
|
||||
]
|
||||
sort_bindings: false
|
||||
v1 = x == 1
|
||||
v2 = 1 == x
|
||||
|
||||
v3 = x != 1
|
||||
v4 = 1 != x
|
||||
|
||||
v5 = x < 1
|
||||
v6 = 1 < x
|
||||
|
||||
v7 = x <= 1
|
||||
v8 = 1 <= x
|
||||
|
||||
v9 = x > 1
|
||||
v10 = 1 > x
|
||||
|
||||
v11 = x >= 1
|
||||
v12 = 1 >= x
|
||||
query: data.test
|
||||
want_result:
|
||||
v: 1
|
||||
r: [ true, false, false, false, false, false,
|
||||
false, false, false, false, false, false]
|
||||
|
||||
- note: null-equals
|
||||
want_result: {}
|
||||
|
||||
- note: eq
|
||||
data: {}
|
||||
modules:
|
||||
- |
|
||||
package test
|
||||
|
||||
v = null
|
||||
r = [
|
||||
# Comparison with number
|
||||
v == 1,
|
||||
v == 2,
|
||||
|
||||
# Comparison with primitives
|
||||
v == null,
|
||||
v == "hello",
|
||||
v == true,
|
||||
v == false,
|
||||
|
||||
# Comparison with arrays
|
||||
v == [],
|
||||
v == [v],
|
||||
|
||||
# Comparison with sets
|
||||
v == set(),
|
||||
v == { v },
|
||||
|
||||
# Comparison with objects
|
||||
v == {},
|
||||
v == { "a": v},
|
||||
]
|
||||
sort_bindings: false
|
||||
query: data.test
|
||||
want_result:
|
||||
v: null
|
||||
r: [ false, false, true, false, false, false,
|
||||
false, false, false, false, false, false]
|
||||
|
||||
- note: string-equals
|
||||
data: {}
|
||||
modules:
|
||||
- |
|
||||
package test
|
||||
|
||||
v = "hello"
|
||||
r = [
|
||||
# Comparison with number
|
||||
v == 1,
|
||||
v == 2,
|
||||
|
||||
# Comparison with primitives
|
||||
v == null,
|
||||
v == "hello",
|
||||
v == true,
|
||||
v == false,
|
||||
|
||||
# Comparison with arrays
|
||||
v == [],
|
||||
v == [v],
|
||||
|
||||
# Comparison with sets
|
||||
v == set(),
|
||||
v == { v },
|
||||
|
||||
# Comparison with objects
|
||||
v == {},
|
||||
v == { "a": v},
|
||||
]
|
||||
sort_bindings: false
|
||||
query: data.test
|
||||
want_result:
|
||||
v: "hello"
|
||||
r: [ false, false, false, true, false, false,
|
||||
false, false, false, false, false, false]
|
||||
|
||||
- note: true-equals
|
||||
data: {}
|
||||
modules:
|
||||
- |
|
||||
package test
|
||||
|
||||
v = true
|
||||
r = [
|
||||
# Comparison with number
|
||||
v == 1,
|
||||
v == 2,
|
||||
|
||||
# Comparison with primitives
|
||||
v == null,
|
||||
v == "hello",
|
||||
v == true,
|
||||
v == false,
|
||||
|
||||
# Comparison with arrays
|
||||
v == [],
|
||||
v == [v],
|
||||
|
||||
# Comparison with sets
|
||||
v == set(),
|
||||
v == { v },
|
||||
|
||||
# Comparison with objects
|
||||
v == {},
|
||||
v == { "a": v},
|
||||
]
|
||||
sort_bindings: false
|
||||
query: data.test
|
||||
want_result:
|
||||
v: true
|
||||
r: [ false, false, false, false, true, false,
|
||||
false, false, false, false, false, false]
|
||||
|
||||
|
||||
- note: false-equals
|
||||
data: {}
|
||||
modules:
|
||||
- |
|
||||
package test
|
||||
|
||||
v = false
|
||||
r = [
|
||||
# Comparison with number
|
||||
v == 1, # true
|
||||
v == 1, # false
|
||||
|
||||
# Comparison with primitives
|
||||
v == null,
|
||||
v == "hello",
|
||||
v == true,
|
||||
v == false,
|
||||
|
||||
# Comparison with arrays
|
||||
v == [],
|
||||
v == [v],
|
||||
|
||||
# Comparison with sets
|
||||
v == set(),
|
||||
v == { v },
|
||||
|
||||
# Comparison with objects
|
||||
v == {},
|
||||
v == { "a": v},
|
||||
]
|
||||
sort_bindings: false
|
||||
query: data.test
|
||||
want_result:
|
||||
v: false
|
||||
r: [ false, false, false, false, false, true,
|
||||
false, false, false, false, false, false]
|
||||
|
||||
- note: undefined-equals
|
||||
data: {}
|
||||
modules:
|
||||
- |
|
||||
package test
|
||||
import future.keywords
|
||||
|
||||
v = 1 if false
|
||||
r = [
|
||||
# Comparison with number
|
||||
v == 1,
|
||||
v == 2,
|
||||
|
||||
# Comparison with primitives
|
||||
v == null,
|
||||
v == "hello",
|
||||
v == true,
|
||||
v == false,
|
||||
|
||||
# Comparison with arrays
|
||||
v == [],
|
||||
v == [v],
|
||||
|
||||
# Comparison with sets
|
||||
v == set(),
|
||||
v == { v },
|
||||
|
||||
# Comparison with objects
|
||||
v == {},
|
||||
v == { "a": v},
|
||||
# true
|
||||
values = [
|
||||
1,
|
||||
-1,
|
||||
null,
|
||||
"hello",
|
||||
`hello`,
|
||||
true,
|
||||
false,
|
||||
[],
|
||||
[1, 2, 3],
|
||||
[4,"abc", null],
|
||||
set(),
|
||||
{1, 2, 3},
|
||||
{4, "abc", null},
|
||||
{},
|
||||
{"a" : 1},
|
||||
]
|
||||
|
||||
r2 = 1 if v
|
||||
|
||||
# This variable should appear in output since it is not undefined.
|
||||
ok = true
|
||||
|
||||
sort_bindings: false
|
||||
query: data.test
|
||||
values_1 = values
|
||||
# Evaluate rule so that rule[x] = [ values equal to x ]
|
||||
results[x] = y {
|
||||
x = values[_]
|
||||
y = [ z |
|
||||
z := values_1[_]
|
||||
x == z
|
||||
]
|
||||
}
|
||||
query: data.test.results
|
||||
want_result:
|
||||
ok: true
|
||||
object!:
|
||||
- key: 1
|
||||
value: [ 1 ]
|
||||
- key: -1
|
||||
value: [ -1 ]
|
||||
- key: null
|
||||
value: [null]
|
||||
- key: "hello"
|
||||
value: ["hello", "hello"]
|
||||
- key: true
|
||||
value: [true]
|
||||
- key: false
|
||||
value: [false]
|
||||
- key: []
|
||||
value: [[]]
|
||||
- key: [1, 2, 3]
|
||||
value: [[1, 2, 3]]
|
||||
- key: [4, "abc", null]
|
||||
value: [[4, "abc", null]]
|
||||
- key:
|
||||
set!: []
|
||||
value:
|
||||
- set!: []
|
||||
- key:
|
||||
set!: [ 1, 2, 3]
|
||||
value:
|
||||
- set!: [1, 2, 3]
|
||||
- key:
|
||||
set!: [4, "abc", null]
|
||||
value:
|
||||
- set!: [4, "abc", null]
|
||||
- key:
|
||||
object!: []
|
||||
value:
|
||||
- object!: []
|
||||
- key:
|
||||
object!:
|
||||
- key: a
|
||||
value: 1
|
||||
value:
|
||||
- a: 1
|
||||
|
||||
|
||||
|
||||
- note: eq-undefined
|
||||
data: {}
|
||||
modules:
|
||||
- |
|
||||
package test
|
||||
import future.keywords.if
|
||||
# All the following rules will be undefined.
|
||||
x if false
|
||||
y = x == 1
|
||||
z = 1 == x
|
||||
query: data.test
|
||||
want_result: {}
|
||||
|
||||
- note: ne
|
||||
data: {}
|
||||
modules:
|
||||
- |
|
||||
package test
|
||||
|
||||
# true
|
||||
values = [
|
||||
1,
|
||||
-1,
|
||||
null,
|
||||
"hello",
|
||||
`hello`,
|
||||
true,
|
||||
false,
|
||||
[],
|
||||
[1, 2, 3],
|
||||
[4,"abc", null],
|
||||
set(),
|
||||
{1, 2, 3},
|
||||
{4, "abc", null},
|
||||
{},
|
||||
{"a" : 1},
|
||||
]
|
||||
|
||||
values_1 = values
|
||||
# Evaluate rule so that rule[x] = [ values equal to x ]
|
||||
results[x] = y {
|
||||
x = values[_]
|
||||
y = [ z |
|
||||
z := values_1[_]
|
||||
# Use != and ne
|
||||
not x != z
|
||||
]
|
||||
}
|
||||
query: data.test.results
|
||||
want_result:
|
||||
object!:
|
||||
- key: 1
|
||||
value: [ 1 ]
|
||||
- key: -1
|
||||
value: [ -1 ]
|
||||
- key: null
|
||||
value: [null]
|
||||
- key: "hello"
|
||||
value: ["hello", "hello"]
|
||||
- key: true
|
||||
value: [true]
|
||||
- key: false
|
||||
value: [false]
|
||||
- key: []
|
||||
value: [[]]
|
||||
- key: [1, 2, 3]
|
||||
value: [[1, 2, 3]]
|
||||
- key: [4, "abc", null]
|
||||
value: [[4, "abc", null]]
|
||||
- key:
|
||||
set!: []
|
||||
value:
|
||||
- set!: []
|
||||
- key:
|
||||
set!: [ 1, 2, 3]
|
||||
value:
|
||||
- set!: [1, 2, 3]
|
||||
- key:
|
||||
set!: [4, "abc", null]
|
||||
value:
|
||||
- set!: [4, "abc", null]
|
||||
- key:
|
||||
object!: []
|
||||
value:
|
||||
- object!: []
|
||||
- key:
|
||||
object!:
|
||||
- key: a
|
||||
value: 1
|
||||
value:
|
||||
- a: 1
|
||||
|
||||
|
||||
- note: order
|
||||
data: {}
|
||||
modules:
|
||||
- |
|
||||
package test
|
||||
|
||||
v = [
|
||||
null,
|
||||
false,
|
||||
0,
|
||||
"",
|
||||
[],
|
||||
{},
|
||||
set()
|
||||
]
|
||||
|
||||
results = {
|
||||
"lt" : { x : y |
|
||||
x = v[_]
|
||||
y = [z | z = v[_]; x < z]
|
||||
},
|
||||
"le" : { x : y |
|
||||
x = v[_]
|
||||
y = [z | z = v[_]; x <= z]
|
||||
},
|
||||
"gt" : { x : y |
|
||||
x = v[_]
|
||||
y = [z | z = v[_]; x > z]
|
||||
},
|
||||
"ge" : { x : y |
|
||||
x = v[_]
|
||||
y = [z | z = v[_]; x >= z]
|
||||
}
|
||||
}
|
||||
query: data.test.results
|
||||
want_result:
|
||||
lt:
|
||||
object!:
|
||||
- key: null
|
||||
value: [false, 0, "", [], {}, {"set!":[]}]
|
||||
- key: false
|
||||
value: [0, "", [], {}, {"set!":[]}]
|
||||
- key: 0
|
||||
value: ["", [], {}, {"set!":[]}]
|
||||
- key: ""
|
||||
value: [[], {}, {"set!":[]}]
|
||||
- key: []
|
||||
value: [{}, {"set!":[]}]
|
||||
- key: {}
|
||||
value: [{"set!":[]}]
|
||||
- key: {"set!":[]}
|
||||
value: []
|
||||
le:
|
||||
object!:
|
||||
- key: null
|
||||
value: [null, false, 0, "", [], {}, {"set!":[]}]
|
||||
- key: false
|
||||
value: [false, 0, "", [], {}, {"set!":[]}]
|
||||
- key: 0
|
||||
value: [0, "", [], {}, {"set!":[]}]
|
||||
- key: ""
|
||||
value: ["", [], {}, {"set!":[]}]
|
||||
- key: []
|
||||
value: [[], {}, {"set!":[]}]
|
||||
- key: {}
|
||||
value: [{}, {"set!":[]}]
|
||||
- key: {"set!":[]}
|
||||
value: [{"set!":[]}]
|
||||
gt:
|
||||
object!:
|
||||
- key: null
|
||||
value: []
|
||||
- key: false
|
||||
value: [null]
|
||||
- key: 0
|
||||
value: [null, false]
|
||||
- key: ""
|
||||
value: [null, false, 0]
|
||||
- key: []
|
||||
value: [null, false, 0, ""]
|
||||
- key: {}
|
||||
value: [null, false, 0, "", []]
|
||||
- key: {"set!":[]}
|
||||
value: [null, false, 0, "", [], {}]
|
||||
ge:
|
||||
object!:
|
||||
- key: null
|
||||
value: [null]
|
||||
- key: false
|
||||
value: [null, false]
|
||||
- key: 0
|
||||
value: [null, false, 0]
|
||||
- key: ""
|
||||
value: [null, false, 0, ""]
|
||||
- key: []
|
||||
value: [null, false, 0, "", []]
|
||||
- key: {}
|
||||
value: [null, false, 0, "", [], {}]
|
||||
- key: {"set!":[]}
|
||||
value: [null, false, 0, "", [], {}, {"set!":[]}]
|
||||
|
||||
- note: arrays
|
||||
data: {}
|
||||
modules:
|
||||
- |
|
||||
package test
|
||||
|
||||
v = [ [], [1, 2], [0, 1, 2], [1, 2, 3]]
|
||||
|
||||
results = {
|
||||
"lt" : { x : y |
|
||||
x = v[_]
|
||||
y = [z | z = v[_]; x < z]
|
||||
},
|
||||
"le" : { x : y |
|
||||
x = v[_]
|
||||
y = [z | z = v[_]; x <= z]
|
||||
},
|
||||
"gt" : { x : y |
|
||||
x = v[_]
|
||||
y = [z | z = v[_]; x > z]
|
||||
},
|
||||
"ge" : { x : y |
|
||||
x = v[_]
|
||||
y = [z | z = v[_]; x >= z]
|
||||
}
|
||||
}
|
||||
query: data.test.results
|
||||
want_result:
|
||||
lt:
|
||||
object!:
|
||||
- key: []
|
||||
value: [[1,2], [0, 1, 2], [1, 2, 3]]
|
||||
- key: [1, 2]
|
||||
value: [[1, 2, 3]]
|
||||
- key: [0, 1, 2]
|
||||
value: [ [1,2], [1, 2, 3]]
|
||||
- key: [1, 2, 3]
|
||||
value: []
|
||||
le:
|
||||
object!:
|
||||
- key: []
|
||||
value: [[], [1,2], [0, 1, 2], [1, 2, 3]]
|
||||
- key: [1, 2]
|
||||
value: [[1, 2], [1, 2, 3]]
|
||||
- key: [0, 1, 2]
|
||||
value: [[1,2], [0, 1, 2], [1, 2, 3]]
|
||||
- key: [1, 2, 3]
|
||||
value: [[1, 2, 3]]
|
||||
gt:
|
||||
object!:
|
||||
- key: []
|
||||
value: []
|
||||
- key: [1, 2]
|
||||
value: [[], [0, 1, 2]]
|
||||
- key: [0, 1, 2]
|
||||
value: [[]]
|
||||
- key: [1, 2, 3]
|
||||
value: [[], [1, 2], [0, 1, 2]]
|
||||
ge:
|
||||
object!:
|
||||
- key: []
|
||||
value: [[]]
|
||||
- key: [1, 2]
|
||||
value: [[], [1, 2], [0, 1, 2]]
|
||||
- key: [0, 1, 2]
|
||||
value: [[], [0, 1, 2]]
|
||||
- key: [1, 2, 3]
|
||||
value: [[], [1, 2], [0, 1, 2], [1, 2, 3]]
|
||||
|
||||
- note: sets
|
||||
data: {}
|
||||
modules:
|
||||
- |
|
||||
package test
|
||||
|
||||
v = [ set(), {1, 2}, {0, 1, 2}, {1, 2, 3}]
|
||||
|
||||
results = {
|
||||
"lt" : { x : y |
|
||||
x = v[_]
|
||||
y = [z | z = v[_]; x < z]
|
||||
},
|
||||
"le" : { x : y |
|
||||
x = v[_]
|
||||
y = [z | z = v[_]; x <= z]
|
||||
},
|
||||
"gt" : { x : y |
|
||||
x = v[_]
|
||||
y = [z | z = v[_]; x > z]
|
||||
},
|
||||
"ge" : { x : y |
|
||||
x = v[_]
|
||||
y = [z | z = v[_]; x >= z]
|
||||
}
|
||||
}
|
||||
query: data.test.results
|
||||
want_result:
|
||||
lt:
|
||||
object!:
|
||||
- key:
|
||||
set!: []
|
||||
value:
|
||||
- set!: [1,2]
|
||||
- set!: [0, 1, 2]
|
||||
- set!: [1, 2, 3]
|
||||
- key:
|
||||
set!: [1, 2]
|
||||
value:
|
||||
- set!: [1, 2, 3]
|
||||
- key:
|
||||
set!: [0, 1, 2]
|
||||
value:
|
||||
- set!: [1,2]
|
||||
- set!: [1, 2, 3]
|
||||
- key:
|
||||
set!: [1, 2, 3]
|
||||
value: []
|
||||
le:
|
||||
object!:
|
||||
- key:
|
||||
set!: []
|
||||
value:
|
||||
- set!: []
|
||||
- set!: [1,2]
|
||||
- set!: [0, 1, 2]
|
||||
- set!: [1, 2, 3]
|
||||
- key:
|
||||
set!: [1, 2]
|
||||
value:
|
||||
- set!: [1, 2]
|
||||
- set!: [1, 2, 3]
|
||||
- key:
|
||||
set!: [0, 1, 2]
|
||||
value:
|
||||
- set!: [1,2]
|
||||
- set!: [0, 1, 2]
|
||||
- set!: [1, 2, 3]
|
||||
- key:
|
||||
set!: [1, 2, 3]
|
||||
value:
|
||||
- set!: [1, 2, 3]
|
||||
gt:
|
||||
object!:
|
||||
- key:
|
||||
set!: []
|
||||
value: []
|
||||
- key:
|
||||
set!: [1, 2]
|
||||
value:
|
||||
- set!: []
|
||||
- set!: [0, 1, 2]
|
||||
- key:
|
||||
set!: [0, 1, 2]
|
||||
value:
|
||||
- set!: []
|
||||
- key:
|
||||
set!: [1, 2, 3]
|
||||
value:
|
||||
- set!: []
|
||||
- set!: [1, 2]
|
||||
- set!: [0, 1, 2]
|
||||
ge:
|
||||
object!:
|
||||
- key:
|
||||
set!: []
|
||||
value:
|
||||
- set!: []
|
||||
- key:
|
||||
set!: [1, 2]
|
||||
value:
|
||||
- set!: []
|
||||
- set!: [1, 2]
|
||||
- set!: [0, 1, 2]
|
||||
- key:
|
||||
set!: [0, 1, 2]
|
||||
value:
|
||||
- set!: []
|
||||
- set!: [0, 1, 2]
|
||||
- key:
|
||||
set!: [1, 2, 3]
|
||||
value:
|
||||
- set!: []
|
||||
- set!: [1, 2]
|
||||
- set!: [0, 1, 2]
|
||||
- set!: [1, 2, 3]
|
||||
|
||||
- note: objects
|
||||
data: {}
|
||||
modules:
|
||||
- |
|
||||
package test
|
||||
|
||||
v = [{}, {"a":1}, {"a":2}, {"a":1, "b":0}, {"b":0}]
|
||||
|
||||
results = {
|
||||
"lt" : { x : y |
|
||||
x = v[_]
|
||||
y = [z | z = v[_]; x < z]
|
||||
},
|
||||
"le" : { x : y |
|
||||
x = v[_]
|
||||
y = [z | z = v[_]; x <= z]
|
||||
},
|
||||
"gt" : { x : y |
|
||||
x = v[_]
|
||||
y = [z | z = v[_]; x > z]
|
||||
},
|
||||
"ge" : { x : y |
|
||||
x = v[_]
|
||||
y = [z | z = v[_]; x >= z]
|
||||
}
|
||||
}
|
||||
query: data.test.results
|
||||
want_result:
|
||||
lt:
|
||||
object!:
|
||||
- key: {}
|
||||
value: [ {"a":1}, {"a":2}, {"a":1, "b":0}, {"b":0}]
|
||||
- key: {"a":1}
|
||||
value: [{"a":2}, {"a":1, "b":0}, {"b":0}]
|
||||
- key: {"a":2}
|
||||
value: [{"b":0}]
|
||||
- key: {"a":1, "b":0}
|
||||
value: [{"a":2}, {"b":0}]
|
||||
- key: {"b":0}
|
||||
value: []
|
||||
le:
|
||||
object!:
|
||||
- key: {}
|
||||
value: [ {}, {"a":1}, {"a":2}, {"a":1, "b":0}, {"b":0}]
|
||||
- key: {"a":1}
|
||||
value: [{"a":1}, {"a":2}, {"a":1, "b":0}, {"b":0}]
|
||||
- key: {"a":2}
|
||||
value: [{"a":2}, {"b":0}]
|
||||
- key: {"a":1, "b":0}
|
||||
value: [{"a":2}, {"a":1, "b":0}, {"b":0}]
|
||||
- key: {"b":0}
|
||||
value: [{"b":0}]
|
||||
gt:
|
||||
object!:
|
||||
- key: {}
|
||||
value: []
|
||||
- key: {"a":1}
|
||||
value: [{}]
|
||||
- key: {"a":2}
|
||||
value: [{}, {"a":1}, {"a":1, "b":0}]
|
||||
- key: {"a":1, "b":0}
|
||||
value: [{}, {"a":1}]
|
||||
- key: {"b":0}
|
||||
value: [ {}, {"a":1}, {"a":2}, {"a":1, "b":0}]
|
||||
ge:
|
||||
object!:
|
||||
- key: {}
|
||||
value: [{}]
|
||||
- key: {"a":1}
|
||||
value: [{}, {"a":1}]
|
||||
- key: {"a":2}
|
||||
value: [{}, {"a":1}, {"a":2}, {"a":1, "b":0}]
|
||||
- key: {"a":1, "b":0}
|
||||
value: [{}, {"a":1}, {"a":1, "b":0}]
|
||||
- key: {"b":0}
|
||||
value: [ {}, {"a":1}, {"a":2}, {"a":1, "b":0}, {"b":0}]
|
||||
|
||||
|
||||
|
||||
Reference in New Issue
Block a user