mirror of
https://github.com/open-policy-agent/opa.git
synced 2026-08-28 03:05:04 -06:00
ast: Enable and/or keywords (#9054)
Promoting `and`/`or` future keywords out of their experimental status; enabling them in default capabilities. Signed-off-by: Johan Fylling <johan.dev@fylling.se>
This commit is contained in:
+3
-1
@@ -5006,7 +5006,9 @@
|
||||
}
|
||||
],
|
||||
"future_keywords": [
|
||||
"not"
|
||||
"and",
|
||||
"not",
|
||||
"or"
|
||||
],
|
||||
"wasm_abi_versions": [
|
||||
{
|
||||
|
||||
@@ -162,7 +162,9 @@ func TestCapabilitiesCurrent(t *testing.T) {
|
||||
ast.FeatureTemplateStrings,
|
||||
},
|
||||
expFutureKeywords: []string{
|
||||
"and",
|
||||
"not",
|
||||
"or",
|
||||
},
|
||||
},
|
||||
{
|
||||
@@ -176,11 +178,13 @@ func TestCapabilitiesCurrent(t *testing.T) {
|
||||
ast.FeatureKeywordsInRefs,
|
||||
},
|
||||
expFutureKeywords: []string{
|
||||
"and",
|
||||
"in",
|
||||
"every",
|
||||
"contains",
|
||||
"if",
|
||||
"not",
|
||||
"or",
|
||||
},
|
||||
},
|
||||
}
|
||||
|
||||
@@ -163,6 +163,8 @@ func TestCapabilitiesCurrent(t *testing.T) {
|
||||
},
|
||||
expFutureKeywords: []string{
|
||||
"not",
|
||||
"and",
|
||||
"or",
|
||||
},
|
||||
},
|
||||
{
|
||||
@@ -181,6 +183,8 @@ func TestCapabilitiesCurrent(t *testing.T) {
|
||||
"contains",
|
||||
"if",
|
||||
"not",
|
||||
"and",
|
||||
"or",
|
||||
},
|
||||
},
|
||||
}
|
||||
|
||||
+11
-51
@@ -1346,9 +1346,7 @@ foo["if"]["else"] := true
|
||||
}
|
||||
}
|
||||
|
||||
// Experimental future keywords are hidden from the default capabilities, so
|
||||
// formatting a module that imports one requires --capabilities to list it.
|
||||
func TestFmtFormatExperimentalKeywords(t *testing.T) {
|
||||
func TestFmtFormatLogicalKeywords(t *testing.T) {
|
||||
unformatted := `package test
|
||||
|
||||
import future.keywords.and
|
||||
@@ -1365,36 +1363,22 @@ import future.keywords.or
|
||||
p if input.a and input.b or input.c
|
||||
`
|
||||
|
||||
experimental := func() fmtCommandParams {
|
||||
params := newFmtCommandParams()
|
||||
params.capabilitiesFlag.C = ast.CapabilitiesForThisVersion(
|
||||
ast.CapabilitiesRegoVersion(ast.RegoV1),
|
||||
ast.CapabilitiesExperimentalKeywords(true))
|
||||
return *params
|
||||
}
|
||||
|
||||
cases := []struct {
|
||||
note string
|
||||
params fmtCommandParams
|
||||
expected string
|
||||
expectedErr string
|
||||
note string
|
||||
params fmtCommandParams
|
||||
expected string
|
||||
}{
|
||||
{
|
||||
note: "default capabilities",
|
||||
params: *newFmtCommandParams(),
|
||||
expectedErr: "rego_parse_error: unexpected keyword, must be one of [contains every if in not]",
|
||||
},
|
||||
{
|
||||
note: "capabilities listing the keywords",
|
||||
params: experimental(),
|
||||
note: "default capabilities",
|
||||
params: *newFmtCommandParams(),
|
||||
expected: formatted,
|
||||
},
|
||||
{
|
||||
note: "capabilities listing the keywords, --check-result",
|
||||
note: "default capabilities, --check-result",
|
||||
params: func() fmtCommandParams {
|
||||
params := experimental()
|
||||
params := newFmtCommandParams()
|
||||
params.checkResult = true
|
||||
return params
|
||||
return *params
|
||||
}(),
|
||||
expected: formatted,
|
||||
},
|
||||
@@ -1413,19 +1397,7 @@ p if input.a and input.b or input.c
|
||||
t.Fatalf("Unexpected error: %s", err)
|
||||
}
|
||||
|
||||
err = formatFile(&tc.params, &stdout, policyFile, info, err)
|
||||
|
||||
if tc.expectedErr != "" {
|
||||
if err == nil {
|
||||
t.Fatalf("Expected error but got: %s", stdout.String())
|
||||
}
|
||||
if !strings.Contains(err.Error(), tc.expectedErr) {
|
||||
t.Fatalf("Expected error to contain:\n\n%s\n\nGot:\n\n%s", tc.expectedErr, err.Error())
|
||||
}
|
||||
return
|
||||
}
|
||||
|
||||
if err != nil {
|
||||
if err := formatFile(&tc.params, &stdout, policyFile, info, err); err != nil {
|
||||
t.Fatalf("Unexpected error: %s", err)
|
||||
}
|
||||
if actual := stdout.String(); actual != tc.expected {
|
||||
@@ -1437,19 +1409,7 @@ p if input.a and input.b or input.c
|
||||
t.Run("stdin, "+tc.note, func(t *testing.T) {
|
||||
var stdout bytes.Buffer
|
||||
|
||||
err := formatStdin(&tc.params, bytes.NewReader([]byte(unformatted)), &stdout)
|
||||
|
||||
if tc.expectedErr != "" {
|
||||
if err == nil {
|
||||
t.Fatalf("Expected error but got: %s", stdout.String())
|
||||
}
|
||||
if !strings.Contains(err.Error(), tc.expectedErr) {
|
||||
t.Fatalf("Expected error to contain:\n\n%s\n\nGot:\n\n%s", tc.expectedErr, err.Error())
|
||||
}
|
||||
return
|
||||
}
|
||||
|
||||
if err != nil {
|
||||
if err := formatStdin(&tc.params, bytes.NewReader([]byte(unformatted)), &stdout); err != nil {
|
||||
t.Fatalf("Unexpected error: %s", err)
|
||||
}
|
||||
if actual := stdout.String(); actual != tc.expected {
|
||||
|
||||
+16
-10
@@ -9,6 +9,7 @@ import (
|
||||
"fmt"
|
||||
"path"
|
||||
"reflect"
|
||||
"slices"
|
||||
"strings"
|
||||
"testing"
|
||||
|
||||
@@ -152,7 +153,7 @@ q = true`)
|
||||
|
||||
// The oracle parses the stdin buffer itself, so keywords that are gated behind
|
||||
// capabilities must reach it through the --capabilities flag.
|
||||
func TestOracleFindDefinitionExperimentalKeywords(t *testing.T) {
|
||||
func TestOracleFindDefinitionCapabilities(t *testing.T) {
|
||||
module := `package test
|
||||
|
||||
import future.keywords.or
|
||||
@@ -165,7 +166,12 @@ q := 1
|
||||
|
||||
r := 2`
|
||||
|
||||
capabilities, err := json.Marshal(ast.CapabilitiesForThisVersion(ast.CapabilitiesExperimentalKeywords(true)))
|
||||
restricted := ast.CapabilitiesForThisVersion()
|
||||
restricted.FutureKeywords = slices.DeleteFunc(restricted.FutureKeywords, func(kw string) bool {
|
||||
return kw == "or"
|
||||
})
|
||||
|
||||
capabilities, err := json.Marshal(restricted)
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
@@ -191,9 +197,11 @@ r := 2`
|
||||
stdout := bytes.NewBuffer(nil)
|
||||
|
||||
err = dofindDefinition(params, bytes.NewBufferString(module), stdout, []string{arg})
|
||||
if err == nil || !strings.Contains(err.Error(), "rego_parse_error") {
|
||||
t.Fatal("expected parse error without capabilities but got:", err, "result:", stdout.String())
|
||||
}
|
||||
expectJSON(t, err, stdout, fmt.Sprintf(`{"result": {
|
||||
"file": %q,
|
||||
"row": 9,
|
||||
"col": 1
|
||||
}}`, path.Join(rootDir, "test.rego")))
|
||||
|
||||
if err := params.capabilities.Set(path.Join(rootDir, "capabilities.json")); err != nil {
|
||||
t.Fatal(err)
|
||||
@@ -202,11 +210,9 @@ r := 2`
|
||||
stdout.Reset()
|
||||
|
||||
err = dofindDefinition(params, bytes.NewBufferString(module), stdout, []string{arg})
|
||||
expectJSON(t, err, stdout, fmt.Sprintf(`{"result": {
|
||||
"file": %q,
|
||||
"row": 9,
|
||||
"col": 1
|
||||
}}`, path.Join(rootDir, "test.rego")))
|
||||
if err == nil || !strings.Contains(err.Error(), "rego_parse_error") {
|
||||
t.Fatal("expected parse error with restricted capabilities but got:", err, "result:", stdout.String())
|
||||
}
|
||||
}
|
||||
|
||||
// The rego-version must be left undefined unless explicitly asked for, so that the
|
||||
|
||||
+16
-10
@@ -9,6 +9,7 @@ import (
|
||||
"fmt"
|
||||
"path"
|
||||
"reflect"
|
||||
"slices"
|
||||
"strings"
|
||||
"testing"
|
||||
|
||||
@@ -152,7 +153,7 @@ q = true`)
|
||||
|
||||
// The oracle parses the stdin buffer itself, so keywords that are gated behind
|
||||
// capabilities must reach it through the --capabilities flag.
|
||||
func TestOracleFindDefinitionExperimentalKeywords(t *testing.T) {
|
||||
func TestOracleFindDefinitionCapabilities(t *testing.T) {
|
||||
module := `package test
|
||||
|
||||
import future.keywords.or
|
||||
@@ -165,7 +166,12 @@ q := 1
|
||||
|
||||
r := 2`
|
||||
|
||||
capabilities, err := json.Marshal(ast.CapabilitiesForThisVersion(ast.CapabilitiesExperimentalKeywords(true)))
|
||||
restricted := ast.CapabilitiesForThisVersion()
|
||||
restricted.FutureKeywords = slices.DeleteFunc(restricted.FutureKeywords, func(kw string) bool {
|
||||
return kw == "or"
|
||||
})
|
||||
|
||||
capabilities, err := json.Marshal(restricted)
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
@@ -191,9 +197,11 @@ r := 2`
|
||||
stdout := bytes.NewBuffer(nil)
|
||||
|
||||
err = dofindDefinition(params, bytes.NewBufferString(module), stdout, []string{arg})
|
||||
if err == nil || !strings.Contains(err.Error(), "rego_parse_error") {
|
||||
t.Fatal("expected parse error without capabilities but got:", err, "result:", stdout.String())
|
||||
}
|
||||
expectJSON(t, err, stdout, fmt.Sprintf(`{"result": {
|
||||
"file": %q,
|
||||
"row": 9,
|
||||
"col": 1
|
||||
}}`, path.Join(rootDir, "test.rego")))
|
||||
|
||||
if err := params.capabilities.Set(path.Join(rootDir, "capabilities.json")); err != nil {
|
||||
t.Fatal(err)
|
||||
@@ -202,11 +210,9 @@ r := 2`
|
||||
stdout.Reset()
|
||||
|
||||
err = dofindDefinition(params, bytes.NewBufferString(module), stdout, []string{arg})
|
||||
expectJSON(t, err, stdout, fmt.Sprintf(`{"result": {
|
||||
"file": %q,
|
||||
"row": 9,
|
||||
"col": 1
|
||||
}}`, path.Join(rootDir, "test.rego")))
|
||||
if err == nil || !strings.Contains(err.Error(), "rego_parse_error") {
|
||||
t.Fatal("expected parse error with restricted capabilities but got:", err, "result:", stdout.String())
|
||||
}
|
||||
}
|
||||
|
||||
// The rego-version must be left undefined unless explicitly asked for, so that the
|
||||
|
||||
@@ -927,7 +927,6 @@ func TestPlannerLogicalOps(t *testing.T) {
|
||||
}
|
||||
|
||||
parserOpts := ast.ParserOptions{
|
||||
Capabilities: ast.CapabilitiesForThisVersion(ast.CapabilitiesExperimentalKeywords(true)),
|
||||
FutureKeywords: []string{"and", "or", "not"},
|
||||
}
|
||||
|
||||
|
||||
@@ -1216,7 +1216,6 @@ func (c *Compiler) buildRequiredCapabilities() {
|
||||
if c.moduleIsRegoV1(c.Modules[name]) {
|
||||
for kw := range futureKeywords {
|
||||
// Don't output experimental keywords for wildcard imports
|
||||
// TODO: Remove on and/or release
|
||||
if _, internal := experimentalFutureKeywords[kw]; internal {
|
||||
continue
|
||||
}
|
||||
@@ -1224,7 +1223,6 @@ func (c *Compiler) buildRequiredCapabilities() {
|
||||
}
|
||||
} else {
|
||||
for kw := range allFutureKeywords {
|
||||
// TODO: Remove on and/or release
|
||||
if _, internal := experimentalFutureKeywords[kw]; internal {
|
||||
continue
|
||||
}
|
||||
|
||||
+5
-30
@@ -1607,7 +1607,6 @@ func TestCompilerCheckSafetyBodyReordering(t *testing.T) {
|
||||
for i, tc := range tests {
|
||||
t.Run(tc.note, func(t *testing.T) {
|
||||
opts := ParserOptions{
|
||||
Capabilities: CapabilitiesForThisVersion(CapabilitiesExperimentalKeywords(true)),
|
||||
AllFutureKeywords: true,
|
||||
}
|
||||
c := NewCompiler()
|
||||
@@ -1815,7 +1814,6 @@ func TestCompilerCheckSafetyBodyErrors(t *testing.T) {
|
||||
|
||||
// Compile test module.
|
||||
opts := ParserOptions{
|
||||
Capabilities: CapabilitiesForThisVersion(CapabilitiesExperimentalKeywords(true)),
|
||||
FutureKeywords: []string{"and", "or"},
|
||||
}
|
||||
|
||||
@@ -3894,10 +3892,6 @@ func runStrictnessTestCase(t *testing.T, cases []strictnessTestCase, assertLocat
|
||||
compiler.Modules = map[string]*Module{
|
||||
"test": MustParseModuleWithOpts(tc.module, ParserOptions{
|
||||
RegoVersion: RegoV0,
|
||||
Capabilities: CapabilitiesForThisVersion(
|
||||
CapabilitiesRegoVersion(RegoV0),
|
||||
CapabilitiesExperimentalKeywords(true),
|
||||
),
|
||||
}),
|
||||
}
|
||||
compileStages(compiler, "")
|
||||
@@ -8201,16 +8195,7 @@ func TestCompilerRewriteTemplateStrings(t *testing.T) {
|
||||
exp string
|
||||
}
|
||||
|
||||
caps := CapabilitiesForThisVersion(CapabilitiesExperimentalKeywords(true))
|
||||
|
||||
opts := CompileOpts{
|
||||
ParserOptions: ParserOptions{
|
||||
Capabilities: caps,
|
||||
},
|
||||
}
|
||||
|
||||
popts := func(options ParserOptions) ParserOptions {
|
||||
options.Capabilities = caps
|
||||
options.AllFutureKeywords = true
|
||||
return options
|
||||
}
|
||||
@@ -8223,7 +8208,7 @@ func TestCompilerRewriteTemplateStrings(t *testing.T) {
|
||||
t.Run(tc.note, func(t *testing.T) {
|
||||
t.Parallel()
|
||||
t.Helper()
|
||||
c := MustCompileModulesWithOpts(map[string]string{"test.rego": tc.module}, opts)
|
||||
c := MustCompileModules(map[string]string{"test.rego": tc.module})
|
||||
if exp, act := module(tc.exp, popts), c.Modules["test.rego"]; !exp.Equal(act) {
|
||||
t.Fatalf("Expected:\n\n%v\n\nGot:\n\n%v", exp, act)
|
||||
}
|
||||
@@ -11376,7 +11361,7 @@ func TestCompilerBuildRequiredCapabilities(t *testing.T) {
|
||||
import future.keywords
|
||||
`,
|
||||
opts: CompileOpts{ParserOptions: ParserOptions{RegoVersion: RegoV0}},
|
||||
keywords: []string{"contains", "every", "if", "in", "not"},
|
||||
keywords: []string{"and", "contains", "every", "if", "in", "not", "or"},
|
||||
},
|
||||
{
|
||||
note: "future.keywords wildcard, v1 module",
|
||||
@@ -11387,7 +11372,7 @@ func TestCompilerBuildRequiredCapabilities(t *testing.T) {
|
||||
`,
|
||||
opts: CompileOpts{ParserOptions: ParserOptions{RegoVersion: RegoV1}},
|
||||
features: []string{"rego_v1"},
|
||||
keywords: []string{"not"},
|
||||
keywords: []string{"and", "not", "or"},
|
||||
},
|
||||
{
|
||||
note: "future.keywords wildcard, default rego-version module (v1)",
|
||||
@@ -11397,7 +11382,7 @@ func TestCompilerBuildRequiredCapabilities(t *testing.T) {
|
||||
import future.keywords
|
||||
`,
|
||||
features: []string{"rego_v1"},
|
||||
keywords: []string{"not"},
|
||||
keywords: []string{"and", "not", "or"},
|
||||
},
|
||||
{
|
||||
note: "future.keywords specific, v0 module",
|
||||
@@ -14918,11 +14903,7 @@ func TestCompilerAndOrRegoVersionParity(t *testing.T) {
|
||||
for _, tc := range tests {
|
||||
t.Run(tc.note, func(t *testing.T) {
|
||||
popts := ParserOptions{
|
||||
RegoVersion: tc.regoVersion,
|
||||
Capabilities: CapabilitiesForThisVersion(
|
||||
CapabilitiesRegoVersion(tc.regoVersion),
|
||||
CapabilitiesExperimentalKeywords(true),
|
||||
),
|
||||
RegoVersion: tc.regoVersion,
|
||||
FutureKeywords: []string{"and", "or"},
|
||||
}
|
||||
|
||||
@@ -14943,7 +14924,6 @@ func TestCompilerAndOrRegoVersionParity(t *testing.T) {
|
||||
|
||||
func TestCompilerAndOrImports(t *testing.T) {
|
||||
popts := ParserOptions{
|
||||
Capabilities: CapabilitiesForThisVersion(CapabilitiesExperimentalKeywords(true)),
|
||||
FutureKeywords: []string{"and", "or"},
|
||||
}
|
||||
|
||||
@@ -15917,7 +15897,6 @@ func TestCompilerAndOrImports(t *testing.T) {
|
||||
}
|
||||
}
|
||||
`, ParserOptions{
|
||||
Capabilities: CapabilitiesForThisVersion(CapabilitiesExperimentalKeywords(true)),
|
||||
FutureKeywords: []string{"and", "or", "not"},
|
||||
}),
|
||||
},
|
||||
@@ -15942,7 +15921,6 @@ func TestCompilerAndOrImports(t *testing.T) {
|
||||
}
|
||||
}
|
||||
`, ParserOptions{
|
||||
Capabilities: CapabilitiesForThisVersion(CapabilitiesExperimentalKeywords(true)),
|
||||
FutureKeywords: []string{"and", "or", "not"},
|
||||
}),
|
||||
},
|
||||
@@ -16145,7 +16123,6 @@ func TestCompilerAndOrImports(t *testing.T) {
|
||||
not (input.a or input.b)
|
||||
}
|
||||
`, ParserOptions{
|
||||
Capabilities: CapabilitiesForThisVersion(CapabilitiesExperimentalKeywords(true)),
|
||||
FutureKeywords: []string{"and", "or", "not"},
|
||||
}),
|
||||
},
|
||||
@@ -16232,7 +16209,6 @@ func TestCompilerAndOrImports(t *testing.T) {
|
||||
|
||||
func TestCompilerLogicalGroupRewrites(t *testing.T) {
|
||||
popts := ParserOptions{
|
||||
Capabilities: CapabilitiesForThisVersion(CapabilitiesExperimentalKeywords(true)),
|
||||
FutureKeywords: []string{"and", "or", "not"},
|
||||
}
|
||||
|
||||
@@ -16311,7 +16287,6 @@ func TestCompilerLogicalGroupRewrites(t *testing.T) {
|
||||
|
||||
func TestQueryCompilerAndOrImports(t *testing.T) {
|
||||
popts := ParserOptions{
|
||||
Capabilities: CapabilitiesForThisVersion(CapabilitiesExperimentalKeywords(true)),
|
||||
AllFutureKeywords: true,
|
||||
}
|
||||
c := NewCompiler()
|
||||
|
||||
@@ -15,13 +15,8 @@ import (
|
||||
// from the module before parsing, and its byte offset becomes the query position.
|
||||
const cursorMarker = "‸"
|
||||
|
||||
func experimentalCapabilities() *ast.Capabilities {
|
||||
return ast.CapabilitiesForThisVersion(ast.CapabilitiesExperimentalKeywords(true))
|
||||
}
|
||||
|
||||
func logicalParserOpts() ast.ParserOptions {
|
||||
return ast.ParserOptions{
|
||||
Capabilities: experimentalCapabilities(),
|
||||
FutureKeywords: []string{"and", "or", "not"},
|
||||
}
|
||||
}
|
||||
@@ -288,7 +283,7 @@ r := 2`,
|
||||
},
|
||||
{
|
||||
note: "keywords activated by future import",
|
||||
opts: &ast.ParserOptions{Capabilities: experimentalCapabilities()},
|
||||
opts: &ast.ParserOptions{},
|
||||
modules: map[string]string{
|
||||
"buffer.rego": `package test
|
||||
|
||||
@@ -397,22 +392,6 @@ q := 1
|
||||
r := 2`,
|
||||
exp: errors.New("rego_parse_error"),
|
||||
},
|
||||
{
|
||||
note: "buffer parse error - future import not in capabilities",
|
||||
opts: &ast.ParserOptions{},
|
||||
buffer: `package test
|
||||
|
||||
import future.keywords.and
|
||||
|
||||
p if {
|
||||
‸q and r
|
||||
}
|
||||
|
||||
q := 1
|
||||
|
||||
r := 2`,
|
||||
exp: errors.New("unexpected keyword, must be one of"),
|
||||
},
|
||||
}
|
||||
|
||||
for _, tc := range cases {
|
||||
|
||||
@@ -2,6 +2,7 @@ package oracle
|
||||
|
||||
import (
|
||||
"errors"
|
||||
"slices"
|
||||
"strings"
|
||||
"testing"
|
||||
|
||||
@@ -1190,10 +1191,7 @@ r := 2`
|
||||
|
||||
t.Run("capabilities from compiler", func(t *testing.T) {
|
||||
t.Parallel()
|
||||
capabilities := ast.CapabilitiesForThisVersion(ast.CapabilitiesExperimentalKeywords(true))
|
||||
o := New().WithCompiler(ast.NewCompiler().WithCapabilities(capabilities))
|
||||
|
||||
_, module, err := o.compileUpto("SetRuleTree", DefinitionQuery{
|
||||
_, module, err := New().compileUpto("SetRuleTree", DefinitionQuery{
|
||||
Buffer: []byte(logicalModule),
|
||||
Filename: "test.rego",
|
||||
})
|
||||
@@ -1203,6 +1201,20 @@ r := 2`
|
||||
if !module.Rules[0].Body[0].IsAnd() {
|
||||
t.Fatal("expected logical and expression but got:", module.Rules[0].Body[0])
|
||||
}
|
||||
|
||||
// The compiler's capabilities gate the keywords available to the buffer.
|
||||
capabilities := ast.CapabilitiesForThisVersion()
|
||||
capabilities.FutureKeywords = slices.DeleteFunc(capabilities.FutureKeywords, func(kw string) bool {
|
||||
return kw == "and"
|
||||
})
|
||||
o := New().WithCompiler(ast.NewCompiler().WithCapabilities(capabilities))
|
||||
|
||||
if _, _, err := o.compileUpto("SetRuleTree", DefinitionQuery{
|
||||
Buffer: []byte(logicalModule),
|
||||
Filename: "test.rego",
|
||||
}); err == nil {
|
||||
t.Fatal("expected parse error")
|
||||
}
|
||||
})
|
||||
}
|
||||
|
||||
|
||||
+2
-5
@@ -3893,11 +3893,8 @@ var allFutureKeywords map[string]tokens.Token
|
||||
// experimentalFutureKeywords are future keywords that exist in the parser but are
|
||||
// intentionally hidden from the default capabilities advertisement.
|
||||
// They are only activated when a policy imports them AND the active
|
||||
// capabilities explicitly list them.
|
||||
var experimentalFutureKeywords = map[string]struct{}{
|
||||
"and": {},
|
||||
"or": {},
|
||||
}
|
||||
// capabilities explicitly list them. There are currently none.
|
||||
var experimentalFutureKeywords = map[string]struct{}{}
|
||||
|
||||
var allFutureKeywordTokens map[tokens.Token]struct{}
|
||||
|
||||
|
||||
@@ -8,10 +8,8 @@ import (
|
||||
)
|
||||
|
||||
func logicalParserOpts(extraFuture ...string) ParserOptions {
|
||||
caps := CapabilitiesForThisVersion(CapabilitiesExperimentalKeywords(true))
|
||||
fk := append([]string{"and", "or"}, extraFuture...)
|
||||
return ParserOptions{
|
||||
Capabilities: caps,
|
||||
FutureKeywords: fk,
|
||||
}
|
||||
}
|
||||
@@ -19,7 +17,6 @@ func logicalParserOpts(extraFuture ...string) ParserOptions {
|
||||
func logicalParserOptsForVersion(v RegoVersion, extraFuture ...string) ParserOptions {
|
||||
opts := logicalParserOpts(extraFuture...)
|
||||
opts.RegoVersion = v
|
||||
opts.Capabilities = CapabilitiesForThisVersion(CapabilitiesRegoVersion(v), CapabilitiesExperimentalKeywords(true))
|
||||
return opts
|
||||
}
|
||||
|
||||
@@ -457,29 +454,9 @@ func TestParseLogical_RefsContainingAndOr(t *testing.T) {
|
||||
}
|
||||
}
|
||||
|
||||
func TestParseLogical_NoLeakageOnImport(t *testing.T) {
|
||||
t.Run("import error does not leak keyword names", func(t *testing.T) {
|
||||
opts := ParserOptions{Capabilities: CapabilitiesForThisVersion()}
|
||||
input := `package x
|
||||
import future.keywords.and
|
||||
`
|
||||
_, _, err := ParseStatementsWithOpts("", input, opts)
|
||||
if err == nil {
|
||||
t.Fatal("expected parse error for import of and without experimental caps")
|
||||
}
|
||||
// Error message is of the form "unexpected keyword, must be one of
|
||||
// [...]". The bracketed list must not include `and` or `or`.
|
||||
msg := err.Error()
|
||||
for _, leaked := range []string{"[and ", " and]", " and ", "[or ", " or]", " or "} {
|
||||
if strings.Contains(msg, leaked) {
|
||||
t.Errorf("error leaks internal keyword existence (%q present in %q)", leaked, msg)
|
||||
}
|
||||
}
|
||||
})
|
||||
|
||||
t.Run("import accepted with experimental caps", func(t *testing.T) {
|
||||
func TestParseLogical_KeywordImport(t *testing.T) {
|
||||
t.Run("import accepted", func(t *testing.T) {
|
||||
opts := ParserOptions{
|
||||
Capabilities: CapabilitiesForThisVersion(CapabilitiesExperimentalKeywords(true)),
|
||||
FutureKeywords: []string{"and"},
|
||||
}
|
||||
input := `package x
|
||||
@@ -529,8 +506,7 @@ func TestParseLogical_NoLeakageOnImport(t *testing.T) {
|
||||
},
|
||||
}
|
||||
opts := ParserOptions{
|
||||
RegoVersion: RegoV1,
|
||||
Capabilities: CapabilitiesForThisVersion(CapabilitiesExperimentalKeywords(true)),
|
||||
RegoVersion: RegoV1,
|
||||
}
|
||||
for _, tc := range tests {
|
||||
t.Run(tc.note, func(t *testing.T) {
|
||||
@@ -575,8 +551,7 @@ func TestParseLogical_NoLeakageOnImport(t *testing.T) {
|
||||
},
|
||||
}
|
||||
opts := ParserOptions{
|
||||
RegoVersion: RegoV1,
|
||||
Capabilities: CapabilitiesForThisVersion(CapabilitiesExperimentalKeywords(true)),
|
||||
RegoVersion: RegoV1,
|
||||
}
|
||||
for _, tc := range tests {
|
||||
t.Run(tc.note, func(t *testing.T) {
|
||||
@@ -591,8 +566,6 @@ func TestParseLogical_NoLeakageOnImport(t *testing.T) {
|
||||
// TestParseLogical_PartialActivation exercises the case where one of `and` /
|
||||
// `or` is enabled in the scanner but the other is not.
|
||||
func TestParseLogical_PartialActivation(t *testing.T) {
|
||||
caps := CapabilitiesForThisVersion(CapabilitiesExperimentalKeywords(true))
|
||||
|
||||
tests := []struct {
|
||||
note string
|
||||
enable []string
|
||||
@@ -649,7 +622,6 @@ func TestParseLogical_PartialActivation(t *testing.T) {
|
||||
for _, tc := range tests {
|
||||
t.Run(tc.note, func(t *testing.T) {
|
||||
opts := ParserOptions{
|
||||
Capabilities: caps,
|
||||
FutureKeywords: tc.enable,
|
||||
}
|
||||
body, err := ParseBodyWithOpts(tc.input, opts)
|
||||
@@ -902,11 +874,7 @@ func TestParseLogical_InnerExprHasLocation(t *testing.T) {
|
||||
}
|
||||
`
|
||||
|
||||
popts := ParserOptions{
|
||||
Capabilities: CapabilitiesForThisVersion(CapabilitiesExperimentalKeywords(true)),
|
||||
}
|
||||
|
||||
mod, err := ParseModuleWithOpts("test.rego", module, popts)
|
||||
mod, err := ParseModuleWithOpts("test.rego", module, ParserOptions{})
|
||||
if err != nil {
|
||||
t.Fatalf("unexpected parse error: %v", err)
|
||||
}
|
||||
|
||||
+20
-28
@@ -2909,7 +2909,7 @@ func TestImport(t *testing.T) {
|
||||
func TestFutureImports(t *testing.T) {
|
||||
assertParseErrorContains(t, "future", "import future", "invalid import, must be `future.keywords`")
|
||||
assertParseErrorContains(t, "future.a", "import future.a", "invalid import, must be `future.keywords`")
|
||||
assertParseErrorContains(t, "unknown keyword", "import future.keywords.xyz", "unexpected keyword, must be one of [contains every if in not]")
|
||||
assertParseErrorContains(t, "unknown keyword", "import future.keywords.xyz", "unexpected keyword, must be one of [and contains every if in not or]")
|
||||
assertParseErrorContains(t, "all keyword import + alias", "import future.keywords as xyz", "`future` imports cannot be aliased")
|
||||
assertParseErrorContains(t, "keyword import + alias", "import future.keywords.in as xyz", "`future` imports cannot be aliased")
|
||||
|
||||
@@ -2940,11 +2940,10 @@ func TestFutureAndRegoV1ImportsExtraction(t *testing.T) {
|
||||
// These tests assert that "import future..." and "import rego.v1" statements in policies cause
|
||||
// the proper keywords to be added to the parser's list of known keywords, and that they don't add any others.
|
||||
tests := []struct {
|
||||
note, imp string
|
||||
regoVersion RegoVersion
|
||||
capabilities *Capabilities
|
||||
exp map[string]tokens.Token
|
||||
absent []string
|
||||
note, imp string
|
||||
regoVersion RegoVersion
|
||||
exp map[string]tokens.Token
|
||||
absent []string
|
||||
}{
|
||||
{
|
||||
note: "simple import",
|
||||
@@ -2991,11 +2990,10 @@ func TestFutureAndRegoV1ImportsExtraction(t *testing.T) {
|
||||
absent: []string{"in", "every", "contains", "if"},
|
||||
},
|
||||
{
|
||||
note: "not imported in v0 does not enable experimental future keywords",
|
||||
regoVersion: RegoV0,
|
||||
capabilities: CapabilitiesForThisVersion(CapabilitiesExperimentalKeywords(true)),
|
||||
imp: "import future.keywords.not",
|
||||
absent: []string{"and", "or"},
|
||||
note: "not imported in v0 does not enable the logical future keywords",
|
||||
regoVersion: RegoV0,
|
||||
imp: "import future.keywords.not",
|
||||
absent: []string{"and", "or"},
|
||||
},
|
||||
{
|
||||
note: "in imported in v0 does not enable the other v0 future keywords",
|
||||
@@ -3005,24 +3003,21 @@ func TestFutureAndRegoV1ImportsExtraction(t *testing.T) {
|
||||
absent: []string{"every", "contains", "if"},
|
||||
},
|
||||
{
|
||||
note: "not imported does not enable experimental keywords",
|
||||
capabilities: CapabilitiesForThisVersion(CapabilitiesExperimentalKeywords(true)),
|
||||
imp: "import future.keywords.not",
|
||||
absent: []string{"and", "or"},
|
||||
note: "not imported does not enable the logical keywords",
|
||||
imp: "import future.keywords.not",
|
||||
absent: []string{"and", "or"},
|
||||
},
|
||||
{
|
||||
note: "in imported does not enable experimental keywords",
|
||||
capabilities: CapabilitiesForThisVersion(CapabilitiesExperimentalKeywords(true)),
|
||||
imp: "import future.keywords.in",
|
||||
exp: map[string]tokens.Token{"in": tokens.In},
|
||||
absent: []string{"and", "or"},
|
||||
note: "in imported does not enable the logical keywords",
|
||||
imp: "import future.keywords.in",
|
||||
exp: map[string]tokens.Token{"in": tokens.In},
|
||||
absent: []string{"and", "or"},
|
||||
},
|
||||
{
|
||||
note: "and imported does not enable or",
|
||||
capabilities: CapabilitiesForThisVersion(CapabilitiesExperimentalKeywords(true)),
|
||||
imp: "import future.keywords.and",
|
||||
exp: map[string]tokens.Token{"and": tokens.LogicalAnd},
|
||||
absent: []string{"or"},
|
||||
note: "and imported does not enable or",
|
||||
imp: "import future.keywords.and",
|
||||
exp: map[string]tokens.Token{"and": tokens.LogicalAnd},
|
||||
absent: []string{"or"},
|
||||
},
|
||||
}
|
||||
for _, tc := range tests {
|
||||
@@ -3031,9 +3026,6 @@ func TestFutureAndRegoV1ImportsExtraction(t *testing.T) {
|
||||
if tc.regoVersion != RegoUndefined {
|
||||
parser = parser.WithRegoVersion(tc.regoVersion)
|
||||
}
|
||||
if tc.capabilities != nil {
|
||||
parser = parser.WithCapabilities(tc.capabilities)
|
||||
}
|
||||
_, _, errs := parser.Parse()
|
||||
if exp, act := 0, len(errs); exp != act {
|
||||
t.Fatalf("expected %d errors, got %d: %v", exp, act, errs)
|
||||
|
||||
@@ -160,7 +160,6 @@ r = true`,
|
||||
{
|
||||
name: "and, implicit",
|
||||
node: ast.MustParseExprWithOpts("x and y", ast.ParserOptions{
|
||||
Capabilities: ast.CapabilitiesForThisVersion(ast.CapabilitiesExperimentalKeywords(true)),
|
||||
AllFutureKeywords: true,
|
||||
}),
|
||||
want: `x and y`,
|
||||
@@ -184,7 +183,6 @@ r = true`,
|
||||
{
|
||||
name: "and, explicit",
|
||||
node: ast.MustParseExprWithOpts("{ x } and { y }", ast.ParserOptions{
|
||||
Capabilities: ast.CapabilitiesForThisVersion(ast.CapabilitiesExperimentalKeywords(true)),
|
||||
AllFutureKeywords: true,
|
||||
}),
|
||||
want: `{ x } and { y }`,
|
||||
@@ -192,7 +190,6 @@ r = true`,
|
||||
{
|
||||
name: "or, implicit",
|
||||
node: ast.MustParseExprWithOpts("x or y", ast.ParserOptions{
|
||||
Capabilities: ast.CapabilitiesForThisVersion(ast.CapabilitiesExperimentalKeywords(true)),
|
||||
AllFutureKeywords: true,
|
||||
}),
|
||||
want: `x or y`,
|
||||
@@ -216,7 +213,6 @@ r = true`,
|
||||
{
|
||||
name: "or, explicit",
|
||||
node: ast.MustParseExprWithOpts("{ x } or { y }", ast.ParserOptions{
|
||||
Capabilities: ast.CapabilitiesForThisVersion(ast.CapabilitiesExperimentalKeywords(true)),
|
||||
AllFutureKeywords: true,
|
||||
}),
|
||||
want: `{ x } or { y }`,
|
||||
|
||||
@@ -100,13 +100,6 @@ func TestFormatSourceError(t *testing.T) {
|
||||
}
|
||||
}
|
||||
|
||||
// TODO: Remove once `and`/`or` are no longer experimental keywords.
|
||||
func experimentalKeywordCapabilities(v ast.RegoVersion) *ast.Capabilities {
|
||||
return ast.CapabilitiesForThisVersion(
|
||||
ast.CapabilitiesRegoVersion(v),
|
||||
ast.CapabilitiesExperimentalKeywords(true))
|
||||
}
|
||||
|
||||
func TestFormatV0Source(t *testing.T) {
|
||||
regoFiles, err := filepath.Glob("testfiles/v0/*.rego")
|
||||
if err != nil {
|
||||
@@ -126,8 +119,7 @@ func TestFormatV0Source(t *testing.T) {
|
||||
}
|
||||
|
||||
popts := ast.ParserOptions{
|
||||
RegoVersion: ast.RegoV0,
|
||||
Capabilities: experimentalKeywordCapabilities(ast.RegoV0),
|
||||
RegoVersion: ast.RegoV0,
|
||||
}
|
||||
opts := Opts{
|
||||
RegoVersion: ast.RegoV0,
|
||||
@@ -187,8 +179,7 @@ func TestFormatV1Source(t *testing.T) {
|
||||
}
|
||||
|
||||
popts := ast.ParserOptions{
|
||||
RegoVersion: ast.RegoV1,
|
||||
Capabilities: experimentalKeywordCapabilities(ast.RegoV1),
|
||||
RegoVersion: ast.RegoV1,
|
||||
}
|
||||
opts := Opts{
|
||||
RegoVersion: ast.RegoV1,
|
||||
@@ -931,7 +922,6 @@ p if {
|
||||
}`,
|
||||
ast.ParserOptions{
|
||||
FutureKeywords: []string{"and"},
|
||||
Capabilities: experimentalKeywordCapabilities(ast.RegoV1),
|
||||
}),
|
||||
expected: `package test
|
||||
|
||||
@@ -950,7 +940,6 @@ p {
|
||||
}`,
|
||||
ast.ParserOptions{
|
||||
FutureKeywords: []string{"and"},
|
||||
Capabilities: experimentalKeywordCapabilities(ast.RegoV1),
|
||||
}),
|
||||
expected: `package test
|
||||
|
||||
@@ -969,7 +958,6 @@ p if {
|
||||
}`,
|
||||
ast.ParserOptions{
|
||||
FutureKeywords: []string{"or"},
|
||||
Capabilities: experimentalKeywordCapabilities(ast.RegoV1),
|
||||
}),
|
||||
expected: `package test
|
||||
|
||||
@@ -988,7 +976,6 @@ p {
|
||||
}`,
|
||||
ast.ParserOptions{
|
||||
FutureKeywords: []string{"or"},
|
||||
Capabilities: experimentalKeywordCapabilities(ast.RegoV1),
|
||||
}),
|
||||
expected: `package test
|
||||
|
||||
@@ -1355,7 +1342,7 @@ func TestFormatKeywordsInRefs(t *testing.T) {
|
||||
t.Fatalf("Failed to read rego source: %v", err)
|
||||
}
|
||||
|
||||
caps := experimentalKeywordCapabilities(regoVersion)
|
||||
caps := ast.CapabilitiesForThisVersion(ast.CapabilitiesRegoVersion(regoVersion))
|
||||
feats := make([]string, 0, len(caps.Features))
|
||||
for _, f := range caps.Features {
|
||||
if f != ast.FeatureKeywordsInRefs {
|
||||
@@ -1368,7 +1355,7 @@ func TestFormatKeywordsInRefs(t *testing.T) {
|
||||
RegoVersion: regoVersion,
|
||||
// The source is parsed with keywords in refs allowed; it is
|
||||
// only the formatting of refs that drops the feature.
|
||||
Capabilities: experimentalKeywordCapabilities(regoVersion),
|
||||
Capabilities: ast.CapabilitiesForThisVersion(ast.CapabilitiesRegoVersion(regoVersion)),
|
||||
}
|
||||
opts := Opts{
|
||||
RegoVersion: regoVersion,
|
||||
|
||||
@@ -1,7 +1,6 @@
|
||||
---
|
||||
cases:
|
||||
- note: "logic_op/and/basic: both operands true"
|
||||
experimental_keywords: true
|
||||
query: data.test.p = x
|
||||
modules:
|
||||
- |
|
||||
@@ -14,7 +13,6 @@ cases:
|
||||
want_result:
|
||||
- x: true
|
||||
- note: "logic_op/and/basic: lhs false"
|
||||
experimental_keywords: true
|
||||
query: data.test.p = x
|
||||
modules:
|
||||
- |
|
||||
@@ -26,7 +24,6 @@ cases:
|
||||
}
|
||||
want_result: []
|
||||
- note: "logic_op/and/basic: rhs false"
|
||||
experimental_keywords: true
|
||||
query: data.test.p = x
|
||||
modules:
|
||||
- |
|
||||
@@ -38,7 +35,6 @@ cases:
|
||||
}
|
||||
want_result: []
|
||||
- note: "logic_op/and/basic: both false"
|
||||
experimental_keywords: true
|
||||
query: data.test.p = x
|
||||
modules:
|
||||
- |
|
||||
@@ -50,7 +46,6 @@ cases:
|
||||
}
|
||||
want_result: []
|
||||
- note: "logic_op/and/basic: both succeed via input"
|
||||
experimental_keywords: true
|
||||
query: data.test.p = x
|
||||
modules:
|
||||
- |
|
||||
@@ -66,7 +61,6 @@ cases:
|
||||
want_result:
|
||||
- x: true
|
||||
- note: "logic_op/and/basic: lhs undefined ref"
|
||||
experimental_keywords: true
|
||||
query: data.test.p = x
|
||||
modules:
|
||||
- |
|
||||
@@ -80,7 +74,6 @@ cases:
|
||||
"y": 2
|
||||
want_result: []
|
||||
- note: "logic_op/and/basic: rhs undefined ref"
|
||||
experimental_keywords: true
|
||||
query: data.test.p = x
|
||||
modules:
|
||||
- |
|
||||
@@ -94,7 +87,6 @@ cases:
|
||||
x: 1
|
||||
want_result: []
|
||||
- note: "logic_op/and/basic: virtual rule refs on both sides"
|
||||
experimental_keywords: true
|
||||
query: data.test.p = x
|
||||
modules:
|
||||
- |
|
||||
@@ -113,7 +105,6 @@ cases:
|
||||
want_result:
|
||||
- x: true
|
||||
- note: "logic_op/and/basic: virtual rule ref, rhs fails"
|
||||
experimental_keywords: true
|
||||
query: data.test.p = x
|
||||
modules:
|
||||
- |
|
||||
@@ -131,7 +122,6 @@ cases:
|
||||
"y": 0
|
||||
want_result: []
|
||||
- note: "logic_op/and/basic: dotted data refs both defined"
|
||||
experimental_keywords: true
|
||||
query: data.test.p = x
|
||||
modules:
|
||||
- |
|
||||
@@ -148,7 +138,6 @@ cases:
|
||||
want_result:
|
||||
- x: true
|
||||
- note: "logic_op/and/basic: indexed data refs"
|
||||
experimental_keywords: true
|
||||
query: data.test.p = x
|
||||
modules:
|
||||
- |
|
||||
|
||||
@@ -1,7 +1,6 @@
|
||||
---
|
||||
cases:
|
||||
- note: "logic_op/and/explicit-body: explicit lhs, implicit rhs"
|
||||
experimental_keywords: true
|
||||
query: data.test.p = x
|
||||
modules:
|
||||
- |
|
||||
@@ -16,7 +15,6 @@ cases:
|
||||
want_result:
|
||||
- x: true
|
||||
- note: "logic_op/and/explicit-body: implicit lhs, explicit rhs"
|
||||
experimental_keywords: true
|
||||
query: data.test.p = x
|
||||
modules:
|
||||
- |
|
||||
@@ -31,7 +29,6 @@ cases:
|
||||
want_result:
|
||||
- x: true
|
||||
- note: "logic_op/and/explicit-body: both explicit"
|
||||
experimental_keywords: true
|
||||
query: data.test.p = x
|
||||
modules:
|
||||
- |
|
||||
@@ -44,7 +41,6 @@ cases:
|
||||
want_result:
|
||||
- x: true
|
||||
- note: "logic_op/and/explicit-body: multi-expr operand body"
|
||||
experimental_keywords: true
|
||||
query: data.test.p = x
|
||||
modules:
|
||||
- |
|
||||
@@ -59,7 +55,6 @@ cases:
|
||||
want_result:
|
||||
- x: true
|
||||
- note: "logic_op/and/explicit-body: multi-expr operand body fails on second expr"
|
||||
experimental_keywords: true
|
||||
query: data.test.p = x
|
||||
modules:
|
||||
- |
|
||||
@@ -73,7 +68,6 @@ cases:
|
||||
a: 100
|
||||
want_result: []
|
||||
- note: "logic_op/and/explicit-body: each operand has its own scope"
|
||||
experimental_keywords: true
|
||||
query: data.test.p = x
|
||||
modules:
|
||||
- |
|
||||
@@ -87,7 +81,6 @@ cases:
|
||||
want_result:
|
||||
- x: true
|
||||
- note: "logic_op/and/explicit-body: some-binding inside operand body"
|
||||
experimental_keywords: true
|
||||
query: data.test.p = x
|
||||
modules:
|
||||
- |
|
||||
|
||||
@@ -4,7 +4,6 @@
|
||||
# *not* evaluated when the LHS already failed.
|
||||
cases:
|
||||
- note: "logic_op/and/short-circuit: lhs fails, rhs builtin not evaluated"
|
||||
experimental_keywords: true
|
||||
strict_error: true
|
||||
query: data.test.p = x
|
||||
modules:
|
||||
@@ -19,7 +18,6 @@ cases:
|
||||
x: 0
|
||||
want_result: []
|
||||
- note: "logic_op/and/short-circuit: lhs succeeds, rhs builtin error surfaces"
|
||||
experimental_keywords: true
|
||||
strict_error: true
|
||||
query: data.test.p = x
|
||||
modules:
|
||||
@@ -35,7 +33,6 @@ cases:
|
||||
want_error_code: eval_builtin_error
|
||||
want_error: to_number
|
||||
- note: "logic_op/and/short-circuit: guarded type access"
|
||||
experimental_keywords: true
|
||||
strict_error: true
|
||||
query: data.test.p = x
|
||||
modules:
|
||||
|
||||
@@ -1,7 +1,6 @@
|
||||
---
|
||||
cases:
|
||||
- note: "logic_op/builtin_calls: and with builtins on both sides"
|
||||
experimental_keywords: true
|
||||
query: data.test.p = x
|
||||
modules:
|
||||
- |
|
||||
@@ -17,7 +16,6 @@ cases:
|
||||
want_result:
|
||||
- x: true
|
||||
- note: "logic_op/builtin_calls: and with builtins, rhs fails"
|
||||
experimental_keywords: true
|
||||
query: data.test.p = x
|
||||
modules:
|
||||
- |
|
||||
@@ -32,7 +30,6 @@ cases:
|
||||
s: "no-leading-slash"
|
||||
want_result: []
|
||||
- note: "logic_op/builtin_calls: or with builtins on both sides"
|
||||
experimental_keywords: true
|
||||
query: data.test.p = x
|
||||
modules:
|
||||
- |
|
||||
@@ -48,7 +45,6 @@ cases:
|
||||
want_result:
|
||||
- x: true
|
||||
- note: "logic_op/builtin_calls: nested builtin call, distinct result temporaries"
|
||||
experimental_keywords: true
|
||||
query: data.test.p = x
|
||||
modules:
|
||||
- |
|
||||
@@ -64,7 +60,6 @@ cases:
|
||||
want_result:
|
||||
- x: true
|
||||
- note: "logic_op/builtin_calls: comprehension in builtin, or branch"
|
||||
experimental_keywords: true
|
||||
query: data.test.p = x
|
||||
modules:
|
||||
- |
|
||||
|
||||
@@ -1,7 +1,6 @@
|
||||
---
|
||||
cases:
|
||||
- note: "logic_op/chained: a and b and c, all true"
|
||||
experimental_keywords: true
|
||||
query: data.test.p = x
|
||||
modules:
|
||||
- |
|
||||
@@ -18,7 +17,6 @@ cases:
|
||||
want_result:
|
||||
- x: true
|
||||
- note: "logic_op/chained: a and b and c, middle false"
|
||||
experimental_keywords: true
|
||||
query: data.test.p = x
|
||||
modules:
|
||||
- |
|
||||
@@ -34,7 +32,6 @@ cases:
|
||||
c: true
|
||||
want_result: []
|
||||
- note: "logic_op/chained: a or b or c, only middle true"
|
||||
experimental_keywords: true
|
||||
query: data.test.p = x
|
||||
modules:
|
||||
- |
|
||||
@@ -51,7 +48,6 @@ cases:
|
||||
want_result:
|
||||
- x: true
|
||||
- note: "logic_op/chained: a or b or c, all false"
|
||||
experimental_keywords: true
|
||||
query: data.test.p = x
|
||||
modules:
|
||||
- |
|
||||
@@ -67,7 +63,6 @@ cases:
|
||||
c: false
|
||||
want_result: []
|
||||
- note: "logic_op/chained: a and b or c and d, right side wins"
|
||||
experimental_keywords: true
|
||||
query: data.test.p = x
|
||||
modules:
|
||||
- |
|
||||
@@ -87,7 +82,6 @@ cases:
|
||||
want_result:
|
||||
- x: true
|
||||
- note: "logic_op/chained: a or b and c or d, b-and-c is the only true conjunct"
|
||||
experimental_keywords: true
|
||||
query: data.test.p = x
|
||||
modules:
|
||||
- |
|
||||
@@ -107,7 +101,6 @@ cases:
|
||||
want_result:
|
||||
- x: true
|
||||
- note: "logic_op/chained: deeply nested explicit bodies"
|
||||
experimental_keywords: true
|
||||
query: data.test.p = x
|
||||
modules:
|
||||
- |
|
||||
|
||||
@@ -1,7 +1,6 @@
|
||||
---
|
||||
cases:
|
||||
- note: "logic_op/comprehension: array, and as filter"
|
||||
experimental_keywords: true
|
||||
query: data.test.p = x
|
||||
modules:
|
||||
- |
|
||||
@@ -18,7 +17,6 @@ cases:
|
||||
want_result:
|
||||
- x: [5, 3]
|
||||
- note: "logic_op/comprehension: array, or as filter"
|
||||
experimental_keywords: true
|
||||
query: data.test.p = x
|
||||
modules:
|
||||
- |
|
||||
@@ -34,7 +32,6 @@ cases:
|
||||
want_result:
|
||||
- x: [-1, 12]
|
||||
- note: "logic_op/comprehension: set with and (dedup)"
|
||||
experimental_keywords: true
|
||||
query: data.test.p = x
|
||||
modules:
|
||||
- |
|
||||
@@ -52,7 +49,6 @@ cases:
|
||||
want_result:
|
||||
- x: [1, 2, 3]
|
||||
- note: "logic_op/comprehension: object with or"
|
||||
experimental_keywords: true
|
||||
query: data.test.p = x
|
||||
modules:
|
||||
- |
|
||||
@@ -73,7 +69,6 @@ cases:
|
||||
a: 5
|
||||
c: -20
|
||||
- note: "logic_op/comprehension: nested comprehension with and"
|
||||
experimental_keywords: true
|
||||
query: data.test.p = x
|
||||
modules:
|
||||
- |
|
||||
@@ -94,7 +89,6 @@ cases:
|
||||
want_result:
|
||||
- x: [[1, 5], [3]]
|
||||
- note: "logic_op/comprehension: walk-bound iteration with and as filter"
|
||||
experimental_keywords: true
|
||||
query: data.test.p = x
|
||||
modules:
|
||||
- |
|
||||
@@ -115,7 +109,6 @@ cases:
|
||||
want_result:
|
||||
- x: ["hello", "nested"]
|
||||
- note: "logic_op/comprehension: walk-bound iteration with or as filter"
|
||||
experimental_keywords: true
|
||||
query: data.test.p = x
|
||||
modules:
|
||||
- |
|
||||
|
||||
@@ -1,7 +1,6 @@
|
||||
---
|
||||
cases:
|
||||
- note: "logic_op/default: default returns when or body fails"
|
||||
experimental_keywords: true
|
||||
query: data.test.p = x
|
||||
modules:
|
||||
- |
|
||||
@@ -17,7 +16,6 @@ cases:
|
||||
want_result:
|
||||
- x: false
|
||||
- note: "logic_op/default: default skipped when or body succeeds"
|
||||
experimental_keywords: true
|
||||
query: data.test.p = x
|
||||
modules:
|
||||
- |
|
||||
@@ -33,7 +31,6 @@ cases:
|
||||
want_result:
|
||||
- x: true
|
||||
- note: "logic_op/default: default returns when and body fails"
|
||||
experimental_keywords: true
|
||||
query: data.test.p = x
|
||||
modules:
|
||||
- |
|
||||
@@ -49,7 +46,6 @@ cases:
|
||||
want_result:
|
||||
- x: "fallback"
|
||||
- note: "logic_op/else: else fires when and body fails"
|
||||
experimental_keywords: true
|
||||
query: data.test.p = x
|
||||
modules:
|
||||
- |
|
||||
@@ -64,7 +60,6 @@ cases:
|
||||
want_result:
|
||||
- x: "fallback"
|
||||
- note: "logic_op/else: else skipped when or body succeeds"
|
||||
experimental_keywords: true
|
||||
query: data.test.p = x
|
||||
modules:
|
||||
- |
|
||||
@@ -79,7 +74,6 @@ cases:
|
||||
want_result:
|
||||
- x: "ok"
|
||||
- note: "logic_op/else: chained else with or in primary branch"
|
||||
experimental_keywords: true
|
||||
query: data.test.p = x
|
||||
modules:
|
||||
- |
|
||||
|
||||
@@ -1,7 +1,6 @@
|
||||
---
|
||||
cases:
|
||||
- note: "logic_op/every: and inside every body, all succeed"
|
||||
experimental_keywords: true
|
||||
query: data.test.p = x
|
||||
modules:
|
||||
- |
|
||||
@@ -18,7 +17,6 @@ cases:
|
||||
want_result:
|
||||
- x: true
|
||||
- note: "logic_op/every: and inside every body, one fails"
|
||||
experimental_keywords: true
|
||||
query: data.test.p = x
|
||||
modules:
|
||||
- |
|
||||
@@ -34,7 +32,6 @@ cases:
|
||||
xs: [1, 2, 100]
|
||||
want_result: []
|
||||
- note: "logic_op/every: or inside every body, all match at least one branch"
|
||||
experimental_keywords: true
|
||||
query: data.test.p = x
|
||||
modules:
|
||||
- |
|
||||
@@ -51,7 +48,6 @@ cases:
|
||||
want_result:
|
||||
- x: true
|
||||
- note: "logic_op/every: or inside every body, one matches neither branch"
|
||||
experimental_keywords: true
|
||||
query: data.test.p = x
|
||||
modules:
|
||||
- |
|
||||
@@ -67,7 +63,6 @@ cases:
|
||||
xs: [-3, 0, 5]
|
||||
want_result: []
|
||||
- note: "logic_op/every: not (or) inside every body"
|
||||
experimental_keywords: true
|
||||
query: data.test.p = x
|
||||
modules:
|
||||
- |
|
||||
@@ -85,7 +80,6 @@ cases:
|
||||
want_result:
|
||||
- x: true
|
||||
- note: "logic_op/every: scoped local var inside operand body"
|
||||
experimental_keywords: true
|
||||
query: data.test.p = x
|
||||
modules:
|
||||
- |
|
||||
|
||||
@@ -1,7 +1,6 @@
|
||||
---
|
||||
cases:
|
||||
- note: "logic_op/grouping: a and (b or c) short-circuits when a is false"
|
||||
experimental_keywords: true
|
||||
query: data.test.p = x
|
||||
modules:
|
||||
- |
|
||||
@@ -18,7 +17,6 @@ cases:
|
||||
c: true
|
||||
want_result: []
|
||||
- note: "logic_op/grouping: no parens, a and b or c"
|
||||
experimental_keywords: true
|
||||
query: data.test.p = x
|
||||
modules:
|
||||
- |
|
||||
@@ -36,7 +34,6 @@ cases:
|
||||
want_result:
|
||||
- x: true
|
||||
- note: "logic_op/grouping: a and (b or c)"
|
||||
experimental_keywords: true
|
||||
query: data.test.p = x
|
||||
modules:
|
||||
- |
|
||||
@@ -55,7 +52,6 @@ cases:
|
||||
- x: true
|
||||
|
||||
- note: "logic_op/grouping: (a or b) and c"
|
||||
experimental_keywords: true
|
||||
query: data.test.p = x
|
||||
modules:
|
||||
- |
|
||||
@@ -73,7 +69,6 @@ cases:
|
||||
want_result:
|
||||
- x: true
|
||||
- note: "logic_op/grouping: (a or b) and c, short-circuit"
|
||||
experimental_keywords: true
|
||||
query: data.test.p = x
|
||||
modules:
|
||||
- |
|
||||
@@ -91,7 +86,6 @@ cases:
|
||||
want_result: []
|
||||
|
||||
- note: "logic_op/grouping: (a or b) and (c or d) parity with braces"
|
||||
experimental_keywords: true
|
||||
query: data.test.p = x
|
||||
modules:
|
||||
- |
|
||||
@@ -110,7 +104,6 @@ cases:
|
||||
want_result:
|
||||
- x: true
|
||||
- note: "logic_op/grouping: { a or b } and { c or d } parity with parens"
|
||||
experimental_keywords: true
|
||||
query: data.test.p = x
|
||||
modules:
|
||||
- |
|
||||
@@ -130,7 +123,6 @@ cases:
|
||||
- x: true
|
||||
|
||||
- note: "logic_op/grouping: (a and (b or c)) and d"
|
||||
experimental_keywords: true
|
||||
query: data.test.p = x
|
||||
modules:
|
||||
- |
|
||||
@@ -150,7 +142,6 @@ cases:
|
||||
- x: true
|
||||
|
||||
- note: "logic_op/grouping: redundant parens (((a or b)))"
|
||||
experimental_keywords: true
|
||||
query: data.test.p = x
|
||||
modules:
|
||||
- |
|
||||
@@ -167,7 +158,6 @@ cases:
|
||||
- x: true
|
||||
|
||||
- note: "logic_op/grouping: not (a or b), neither true"
|
||||
experimental_keywords: true
|
||||
query: data.test.p = x
|
||||
modules:
|
||||
- |
|
||||
@@ -184,7 +174,6 @@ cases:
|
||||
want_result:
|
||||
- x: true
|
||||
- note: "logic_op/grouping: not (a or b), one true"
|
||||
experimental_keywords: true
|
||||
query: data.test.p = x
|
||||
modules:
|
||||
- |
|
||||
@@ -201,7 +190,6 @@ cases:
|
||||
want_result: []
|
||||
|
||||
- note: "logic_op/grouping: (a with ...) and b, with scoped to operand"
|
||||
experimental_keywords: true
|
||||
query: data.test.p = x
|
||||
modules:
|
||||
- |
|
||||
@@ -217,7 +205,6 @@ cases:
|
||||
- x: true
|
||||
|
||||
- note: "logic_op/grouping: (a or b with ...) binds with to whole group"
|
||||
experimental_keywords: true
|
||||
query: data.test.p = x
|
||||
modules:
|
||||
- |
|
||||
|
||||
@@ -2,7 +2,6 @@
|
||||
# Operand bodies with internal enumeration.
|
||||
cases:
|
||||
- note: "logic_op/iteration: and"
|
||||
experimental_keywords: true
|
||||
query: data.test.p = x
|
||||
modules:
|
||||
- |
|
||||
@@ -15,7 +14,6 @@ cases:
|
||||
want_result:
|
||||
- x: true
|
||||
- note: "logic_op/iteration: and lhs would yield multiple successes, comprehension emits once"
|
||||
experimental_keywords: true
|
||||
query: data.test.p = x
|
||||
modules:
|
||||
- |
|
||||
@@ -28,7 +26,6 @@ cases:
|
||||
want_result:
|
||||
- x: [1]
|
||||
- note: "logic_op/iteration: and rhs would yield multiple successes, comprehension emits once"
|
||||
experimental_keywords: true
|
||||
query: data.test.p = x
|
||||
modules:
|
||||
- |
|
||||
@@ -41,7 +38,6 @@ cases:
|
||||
want_result:
|
||||
- x: [1]
|
||||
- note: "logic_op/iteration: and lhs+rhs would yield multiple successes, comprehension emits once"
|
||||
experimental_keywords: true
|
||||
query: data.test.p = x
|
||||
modules:
|
||||
- |
|
||||
@@ -54,7 +50,6 @@ cases:
|
||||
want_result:
|
||||
- x: [1]
|
||||
- note: "logic_op/iteration: or lhs would yield multiple successes, comprehension emits once"
|
||||
experimental_keywords: true
|
||||
query: data.test.p = x
|
||||
modules:
|
||||
- |
|
||||
@@ -67,7 +62,6 @@ cases:
|
||||
want_result:
|
||||
- x: [1]
|
||||
- note: "logic_op/iteration: or rhs would yield multiple successes, comprehension emits once"
|
||||
experimental_keywords: true
|
||||
query: data.test.p = x
|
||||
modules:
|
||||
- |
|
||||
@@ -80,7 +74,6 @@ cases:
|
||||
want_result:
|
||||
- x: [1]
|
||||
- note: "logic_op/iteration: enumeration inside operand body, no fail-and-retry"
|
||||
experimental_keywords: true
|
||||
query: data.test.p = x
|
||||
modules:
|
||||
- |
|
||||
@@ -94,7 +87,6 @@ cases:
|
||||
want_result:
|
||||
- x: [1]
|
||||
- note: "logic_op/iteration: enumeration inside operand body, all fail"
|
||||
experimental_keywords: true
|
||||
query: data.test.p = x
|
||||
modules:
|
||||
- |
|
||||
@@ -108,7 +100,6 @@ cases:
|
||||
want_result:
|
||||
- x: []
|
||||
- note: "logic_op/iteration: not around or with iteration"
|
||||
experimental_keywords: true
|
||||
query: data.test.p = x
|
||||
modules:
|
||||
- |
|
||||
@@ -125,7 +116,6 @@ cases:
|
||||
want_result:
|
||||
- x: true
|
||||
- note: "logic_op/iteration: not around or with iteration, one element matches"
|
||||
experimental_keywords: true
|
||||
query: data.test.p = x
|
||||
modules:
|
||||
- |
|
||||
@@ -140,7 +130,6 @@ cases:
|
||||
xs: [0, 5, 200]
|
||||
want_result: []
|
||||
- note: "logic_op/iteration: not around and with iteration"
|
||||
experimental_keywords: true
|
||||
query: data.test.p = x
|
||||
modules:
|
||||
- |
|
||||
@@ -157,7 +146,6 @@ cases:
|
||||
want_result:
|
||||
- x: true
|
||||
- note: "logic_op/iteration: not around and with iteration, one element matches"
|
||||
experimental_keywords: true
|
||||
query: data.test.p = x
|
||||
modules:
|
||||
- |
|
||||
|
||||
@@ -1,7 +1,6 @@
|
||||
---
|
||||
cases:
|
||||
- note: "logic_op/local_collision: same name in both and-operand bodies"
|
||||
experimental_keywords: true
|
||||
query: data.test.p = x
|
||||
modules:
|
||||
- |
|
||||
@@ -14,7 +13,6 @@ cases:
|
||||
want_result:
|
||||
- x: true
|
||||
- note: "logic_op/local_collision: same name in both or-operand bodies"
|
||||
experimental_keywords: true
|
||||
query: data.test.p = x
|
||||
modules:
|
||||
- |
|
||||
@@ -27,7 +25,6 @@ cases:
|
||||
want_result:
|
||||
- x: true
|
||||
- note: "logic_op/local_collision: same name across and-body and outer scope"
|
||||
experimental_keywords: true
|
||||
query: data.test.p = x
|
||||
modules:
|
||||
- |
|
||||
@@ -43,7 +40,6 @@ cases:
|
||||
want_result:
|
||||
- x: true
|
||||
- note: "logic_op/local_collision: same `some` iter name in both operand bodies"
|
||||
experimental_keywords: true
|
||||
query: data.test.p = x
|
||||
modules:
|
||||
- |
|
||||
@@ -56,7 +52,6 @@ cases:
|
||||
want_result:
|
||||
- x: true
|
||||
- note: "logic_op/local_collision: nested explicit body re-uses same name"
|
||||
experimental_keywords: true
|
||||
query: data.test.p = x
|
||||
modules:
|
||||
- |
|
||||
|
||||
@@ -1,7 +1,6 @@
|
||||
---
|
||||
cases:
|
||||
- note: "logic_op/negation: not {x and y}, de Morgan equivalent"
|
||||
experimental_keywords: true
|
||||
query: data.test.p = x
|
||||
modules:
|
||||
- |
|
||||
@@ -18,7 +17,6 @@ cases:
|
||||
want_result:
|
||||
- x: true
|
||||
- note: "logic_op/negation: not {x and y}, both true"
|
||||
experimental_keywords: true
|
||||
query: data.test.p = x
|
||||
modules:
|
||||
- |
|
||||
@@ -34,7 +32,6 @@ cases:
|
||||
"y": true
|
||||
want_result: []
|
||||
- note: "logic_op/negation: not {x or y}, neither true"
|
||||
experimental_keywords: true
|
||||
query: data.test.p = x
|
||||
modules:
|
||||
- |
|
||||
@@ -51,7 +48,6 @@ cases:
|
||||
want_result:
|
||||
- x: true
|
||||
- note: "logic_op/negation: not {x or y}, one true"
|
||||
experimental_keywords: true
|
||||
query: data.test.p = x
|
||||
modules:
|
||||
- |
|
||||
@@ -67,7 +63,6 @@ cases:
|
||||
"y": true
|
||||
want_result: []
|
||||
- note: "logic_op/negation: not x and not y, inner negation"
|
||||
experimental_keywords: true
|
||||
query: data.test.p = x
|
||||
modules:
|
||||
- |
|
||||
@@ -83,7 +78,6 @@ cases:
|
||||
want_result:
|
||||
- x: true
|
||||
- note: "logic_op/negation: not x or not y, inner negation"
|
||||
experimental_keywords: true
|
||||
query: data.test.p = x
|
||||
modules:
|
||||
- |
|
||||
@@ -99,7 +93,6 @@ cases:
|
||||
want_result:
|
||||
- x: true
|
||||
- note: "logic_op/negation: not {not x or not y}, double negation"
|
||||
experimental_keywords: true
|
||||
query: data.test.p = x
|
||||
modules:
|
||||
- |
|
||||
@@ -116,7 +109,6 @@ cases:
|
||||
want_result:
|
||||
- x: true
|
||||
- note: "logic_op/negation: not {x and not y}, mixed"
|
||||
experimental_keywords: true
|
||||
query: data.test.p = x
|
||||
modules:
|
||||
- |
|
||||
|
||||
@@ -1,7 +1,6 @@
|
||||
---
|
||||
cases:
|
||||
- note: "logic_op/nesting: explicit {a or b} and {c or d}, all true"
|
||||
experimental_keywords: true
|
||||
query: data.test.p = x
|
||||
modules:
|
||||
- |
|
||||
@@ -20,7 +19,6 @@ cases:
|
||||
want_result:
|
||||
- x: true
|
||||
- note: "logic_op/nesting: explicit {a or b} and {c or d}, one branch fails"
|
||||
experimental_keywords: true
|
||||
query: data.test.p = x
|
||||
modules:
|
||||
- |
|
||||
@@ -38,7 +36,6 @@ cases:
|
||||
d: true
|
||||
want_result: []
|
||||
- note: "logic_op/nesting: a or {b and {c or d}}, three-deep"
|
||||
experimental_keywords: true
|
||||
query: data.test.p = x
|
||||
modules:
|
||||
- |
|
||||
@@ -57,7 +54,6 @@ cases:
|
||||
want_result:
|
||||
- x: true
|
||||
- note: "logic_op/nesting: a or {b and {c or d}}, top-level lhs short-circuits"
|
||||
experimental_keywords: true
|
||||
query: data.test.p = x
|
||||
modules:
|
||||
- |
|
||||
@@ -76,7 +72,6 @@ cases:
|
||||
want_result:
|
||||
- x: true
|
||||
- note: "logic_op/nesting: x and {y or {z and w}}, mixed"
|
||||
experimental_keywords: true
|
||||
query: data.test.p = x
|
||||
modules:
|
||||
- |
|
||||
|
||||
@@ -1,7 +1,6 @@
|
||||
---
|
||||
cases:
|
||||
- note: "logic_op/or/basic: lhs true"
|
||||
experimental_keywords: true
|
||||
query: data.test.p = x
|
||||
modules:
|
||||
- |
|
||||
@@ -14,7 +13,6 @@ cases:
|
||||
want_result:
|
||||
- x: true
|
||||
- note: "logic_op/or/basic: rhs true"
|
||||
experimental_keywords: true
|
||||
query: data.test.p = x
|
||||
modules:
|
||||
- |
|
||||
@@ -27,7 +25,6 @@ cases:
|
||||
want_result:
|
||||
- x: true
|
||||
- note: "logic_op/or/basic: both true"
|
||||
experimental_keywords: true
|
||||
query: data.test.p = x
|
||||
modules:
|
||||
- |
|
||||
@@ -40,7 +37,6 @@ cases:
|
||||
want_result:
|
||||
- x: true
|
||||
- note: "logic_op/or/basic: both false"
|
||||
experimental_keywords: true
|
||||
query: data.test.p = x
|
||||
modules:
|
||||
- |
|
||||
@@ -52,7 +48,6 @@ cases:
|
||||
}
|
||||
want_result: []
|
||||
- note: "logic_op/or/basic: lhs succeeds via input"
|
||||
experimental_keywords: true
|
||||
query: data.test.p = x
|
||||
modules:
|
||||
- |
|
||||
@@ -67,7 +62,6 @@ cases:
|
||||
want_result:
|
||||
- x: true
|
||||
- note: "logic_op/or/basic: rhs succeeds via input"
|
||||
experimental_keywords: true
|
||||
query: data.test.p = x
|
||||
modules:
|
||||
- |
|
||||
@@ -82,7 +76,6 @@ cases:
|
||||
want_result:
|
||||
- x: true
|
||||
- note: "logic_op/or/basic: neither side succeeds via input"
|
||||
experimental_keywords: true
|
||||
query: data.test.p = x
|
||||
modules:
|
||||
- |
|
||||
@@ -96,7 +89,6 @@ cases:
|
||||
role: "guest"
|
||||
want_result: []
|
||||
- note: "logic_op/or/basic: lhs undefined ref, rhs true"
|
||||
experimental_keywords: true
|
||||
query: data.test.p = x
|
||||
modules:
|
||||
- |
|
||||
@@ -109,7 +101,6 @@ cases:
|
||||
want_result:
|
||||
- x: true
|
||||
- note: "logic_op/or/basic: virtual rule refs, lhs succeeds"
|
||||
experimental_keywords: true
|
||||
query: data.test.p = x
|
||||
modules:
|
||||
- |
|
||||
@@ -128,7 +119,6 @@ cases:
|
||||
want_result:
|
||||
- x: true
|
||||
- note: "logic_op/or/basic: virtual rule refs, rhs succeeds"
|
||||
experimental_keywords: true
|
||||
query: data.test.p = x
|
||||
modules:
|
||||
- |
|
||||
@@ -147,7 +137,6 @@ cases:
|
||||
want_result:
|
||||
- x: true
|
||||
- note: "logic_op/or/basic: virtual rule refs, neither succeeds"
|
||||
experimental_keywords: true
|
||||
query: data.test.p = x
|
||||
modules:
|
||||
- |
|
||||
@@ -165,7 +154,6 @@ cases:
|
||||
"y": 0
|
||||
want_result: []
|
||||
- note: "logic_op/or/basic: dotted data refs, only one defined"
|
||||
experimental_keywords: true
|
||||
query: data.test.p = x
|
||||
modules:
|
||||
- |
|
||||
@@ -181,7 +169,6 @@ cases:
|
||||
want_result:
|
||||
- x: true
|
||||
- note: "logic_op/or/basic: indexed data refs"
|
||||
experimental_keywords: true
|
||||
query: data.test.p = x
|
||||
modules:
|
||||
- |
|
||||
|
||||
@@ -1,7 +1,6 @@
|
||||
---
|
||||
cases:
|
||||
- note: "logic_op/or/explicit-body: explicit lhs, implicit rhs"
|
||||
experimental_keywords: true
|
||||
query: data.test.p = x
|
||||
modules:
|
||||
- |
|
||||
@@ -16,7 +15,6 @@ cases:
|
||||
want_result:
|
||||
- x: true
|
||||
- note: "logic_op/or/explicit-body: implicit lhs, explicit rhs"
|
||||
experimental_keywords: true
|
||||
query: data.test.p = x
|
||||
modules:
|
||||
- |
|
||||
@@ -31,7 +29,6 @@ cases:
|
||||
want_result:
|
||||
- x: true
|
||||
- note: "logic_op/or/explicit-body: both explicit, lhs succeeds"
|
||||
experimental_keywords: true
|
||||
query: data.test.p = x
|
||||
modules:
|
||||
- |
|
||||
@@ -44,7 +41,6 @@ cases:
|
||||
want_result:
|
||||
- x: true
|
||||
- note: "logic_op/or/explicit-body: both explicit, rhs succeeds"
|
||||
experimental_keywords: true
|
||||
query: data.test.p = x
|
||||
modules:
|
||||
- |
|
||||
@@ -57,7 +53,6 @@ cases:
|
||||
want_result:
|
||||
- x: true
|
||||
- note: "logic_op/or/explicit-body: both explicit, both fail"
|
||||
experimental_keywords: true
|
||||
query: data.test.p = x
|
||||
modules:
|
||||
- |
|
||||
@@ -69,7 +64,6 @@ cases:
|
||||
}
|
||||
want_result: []
|
||||
- note: "logic_op/or/explicit-body: multi-expr operand body"
|
||||
experimental_keywords: true
|
||||
query: data.test.p = x
|
||||
modules:
|
||||
- |
|
||||
@@ -82,7 +76,6 @@ cases:
|
||||
want_result:
|
||||
- x: true
|
||||
- note: "logic_op/or/explicit-body: some-binding inside operand body"
|
||||
experimental_keywords: true
|
||||
query: data.test.p = x
|
||||
modules:
|
||||
- |
|
||||
|
||||
@@ -4,7 +4,6 @@
|
||||
# *not* evaluated when the LHS already succeeded.
|
||||
cases:
|
||||
- note: "logic_op/or/short-circuit: lhs succeeds, rhs builtin not evaluated"
|
||||
experimental_keywords: true
|
||||
strict_error: true
|
||||
query: data.test.p = x
|
||||
modules:
|
||||
@@ -20,7 +19,6 @@ cases:
|
||||
want_result:
|
||||
- x: true
|
||||
- note: "logic_op/or/short-circuit: lhs fails, rhs builtin error surfaces"
|
||||
experimental_keywords: true
|
||||
strict_error: true
|
||||
query: data.test.p = x
|
||||
modules:
|
||||
@@ -36,7 +34,6 @@ cases:
|
||||
want_error_code: eval_builtin_error
|
||||
want_error: to_number
|
||||
- note: "logic_op/or/short-circuit: lhs fails, rhs evaluates and succeeds"
|
||||
experimental_keywords: true
|
||||
strict_error: true
|
||||
query: data.test.p = x
|
||||
modules:
|
||||
|
||||
@@ -1,7 +1,6 @@
|
||||
---
|
||||
cases:
|
||||
- note: "logic_op/or/single-result: both operands succeed contributes one element"
|
||||
experimental_keywords: true
|
||||
query: data.test.p = x
|
||||
modules:
|
||||
- |
|
||||
@@ -16,7 +15,6 @@ cases:
|
||||
want_result:
|
||||
- x: [1]
|
||||
- note: "logic_op/or/single-result: nested or, all branches succeed contributes one element"
|
||||
experimental_keywords: true
|
||||
query: data.test.p = x
|
||||
modules:
|
||||
- |
|
||||
@@ -29,7 +27,6 @@ cases:
|
||||
want_result:
|
||||
- x: [1]
|
||||
- note: "logic_op/or/single-result: inside iterating comprehension, one entry per outer binding"
|
||||
experimental_keywords: true
|
||||
query: data.test.p = x
|
||||
modules:
|
||||
- |
|
||||
|
||||
@@ -1,7 +1,6 @@
|
||||
---
|
||||
cases:
|
||||
- note: "logic_op/precedence: `not x or y` parses as `(not x) or y`"
|
||||
experimental_keywords: true
|
||||
query: data.test.p = x
|
||||
modules:
|
||||
- |
|
||||
@@ -20,7 +19,6 @@ cases:
|
||||
want_result:
|
||||
- x: true
|
||||
- note: "logic_op/precedence: `x or y and z` parses as `x or (y and z)`"
|
||||
experimental_keywords: true
|
||||
query: data.test.p = x
|
||||
modules:
|
||||
- |
|
||||
@@ -41,7 +39,6 @@ cases:
|
||||
want_result:
|
||||
- x: true
|
||||
- note: "logic_op/precedence: `x and y or z and w` parses as `(x and y) or (z and w)`"
|
||||
experimental_keywords: true
|
||||
query: data.test.p = x
|
||||
modules:
|
||||
- |
|
||||
@@ -63,7 +60,6 @@ cases:
|
||||
want_result:
|
||||
- x: true
|
||||
- note: "logic_op/precedence: `not x and not y or z` parses as `((not x) and (not y)) or z`"
|
||||
experimental_keywords: true
|
||||
query: data.test.p = x
|
||||
modules:
|
||||
- |
|
||||
|
||||
@@ -1,7 +1,6 @@
|
||||
---
|
||||
cases:
|
||||
- note: "logic_op/rule_head: and under if-head, both true"
|
||||
experimental_keywords: true
|
||||
query: data.test.p = x
|
||||
modules:
|
||||
- |
|
||||
@@ -15,7 +14,6 @@ cases:
|
||||
want_result:
|
||||
- x: true
|
||||
- note: "logic_op/rule_head: and under if-head, lhs false"
|
||||
experimental_keywords: true
|
||||
query: data.test.p = x
|
||||
modules:
|
||||
- |
|
||||
@@ -28,7 +26,6 @@ cases:
|
||||
"y": 2
|
||||
want_result: []
|
||||
- note: "logic_op/rule_head: or under if-head, lhs true"
|
||||
experimental_keywords: true
|
||||
query: data.test.p = x
|
||||
modules:
|
||||
- |
|
||||
@@ -42,7 +39,6 @@ cases:
|
||||
want_result:
|
||||
- x: true
|
||||
- note: "logic_op/rule_head: or under if-head, both false"
|
||||
experimental_keywords: true
|
||||
query: data.test.p = x
|
||||
modules:
|
||||
- |
|
||||
@@ -55,7 +51,6 @@ cases:
|
||||
"y": 0
|
||||
want_result: []
|
||||
- note: "logic_op/rule_head: and under assignment head"
|
||||
experimental_keywords: true
|
||||
query: data.test.p = x
|
||||
modules:
|
||||
- |
|
||||
@@ -69,7 +64,6 @@ cases:
|
||||
want_result:
|
||||
- x: 1
|
||||
- note: "logic_op/rule_head: or under assignment head"
|
||||
experimental_keywords: true
|
||||
query: data.test.p = x
|
||||
modules:
|
||||
- |
|
||||
@@ -83,7 +77,6 @@ cases:
|
||||
want_result:
|
||||
- x: "matched"
|
||||
- note: "logic_op/rule_head: and in function body"
|
||||
experimental_keywords: true
|
||||
query: data.test.p = x
|
||||
modules:
|
||||
- |
|
||||
@@ -96,7 +89,6 @@ cases:
|
||||
want_result:
|
||||
- x: true
|
||||
- note: "logic_op/rule_head: and in function body, fails"
|
||||
experimental_keywords: true
|
||||
query: data.test.p = x
|
||||
modules:
|
||||
- |
|
||||
@@ -108,7 +100,6 @@ cases:
|
||||
p if in_range(42)
|
||||
want_result: []
|
||||
- note: "logic_op/rule_head: or in function body"
|
||||
experimental_keywords: true
|
||||
query: data.test.p = x
|
||||
modules:
|
||||
- |
|
||||
|
||||
@@ -1,7 +1,6 @@
|
||||
---
|
||||
cases:
|
||||
- note: "logic_op/with: outer with on and propagates to both operand bodies"
|
||||
experimental_keywords: true
|
||||
query: data.test.p = x
|
||||
modules:
|
||||
- |
|
||||
@@ -14,7 +13,6 @@ cases:
|
||||
want_result:
|
||||
- x: true
|
||||
- note: "logic_op/with: with on lhs only, scoped to lhs"
|
||||
experimental_keywords: true
|
||||
query: data.test.p = x
|
||||
modules:
|
||||
- |
|
||||
@@ -29,7 +27,6 @@ cases:
|
||||
want_result:
|
||||
- x: true
|
||||
- note: "logic_op/with: with on lhs only, scoped to lhs, but falls through to called scope"
|
||||
experimental_keywords: true
|
||||
query: data.test.p = x
|
||||
modules:
|
||||
- |
|
||||
@@ -48,7 +45,6 @@ cases:
|
||||
want_result:
|
||||
- x: true
|
||||
- note: "logic_op/with: outer with on or, both operands see modified input"
|
||||
experimental_keywords: true
|
||||
query: data.test.p = x
|
||||
modules:
|
||||
- |
|
||||
|
||||
@@ -44,10 +44,9 @@ func touchCount(label string) int {
|
||||
return int(counter.(*atomic.Int64).Load())
|
||||
}
|
||||
|
||||
// logicalParserOptions opts in to the experimental `and` / `or` keywords.
|
||||
// logicalParserOptions opts in to the `and` / `or` keywords.
|
||||
func logicalParserOptions() ast.ParserOptions {
|
||||
return ast.ParserOptions{
|
||||
Capabilities: ast.CapabilitiesForThisVersion(ast.CapabilitiesExperimentalKeywords(true)),
|
||||
FutureKeywords: []string{"and", "or"},
|
||||
}
|
||||
}
|
||||
|
||||
+131
-134
@@ -41,7 +41,7 @@ func TestTopDownPartialEval(t *testing.T) {
|
||||
wantSupport []string
|
||||
wantSupportASTs []*ast.Module
|
||||
ignoreOrder bool
|
||||
experimentalKeywords bool // opt in to experimental and/or keywords
|
||||
logicalKeywords bool // opt in to the and/or keywords
|
||||
}{
|
||||
{
|
||||
note: "empty",
|
||||
@@ -4353,9 +4353,9 @@ q if { input.x = 7 }`},
|
||||
// and/or baseline (no unknowns: truth-table)
|
||||
|
||||
{
|
||||
note: "and: no unknowns, both true",
|
||||
experimentalKeywords: true,
|
||||
query: "data.test.p",
|
||||
note: "and: no unknowns, both true",
|
||||
logicalKeywords: true,
|
||||
query: "data.test.p",
|
||||
modules: []string{`package test
|
||||
p if {
|
||||
true and true
|
||||
@@ -4363,9 +4363,9 @@ q if { input.x = 7 }`},
|
||||
wantQueries: []string{""}, // unconditionally true
|
||||
},
|
||||
{
|
||||
note: "and: no unknowns, lhs false",
|
||||
experimentalKeywords: true,
|
||||
query: "data.test.p",
|
||||
note: "and: no unknowns, lhs false",
|
||||
logicalKeywords: true,
|
||||
query: "data.test.p",
|
||||
modules: []string{`package test
|
||||
p if {
|
||||
false and true
|
||||
@@ -4373,9 +4373,9 @@ q if { input.x = 7 }`},
|
||||
wantQueries: []string{}, // unconditionally false
|
||||
},
|
||||
{
|
||||
note: "and: no unknowns, rhs false",
|
||||
experimentalKeywords: true,
|
||||
query: "data.test.p",
|
||||
note: "and: no unknowns, rhs false",
|
||||
logicalKeywords: true,
|
||||
query: "data.test.p",
|
||||
modules: []string{`package test
|
||||
p if {
|
||||
true and false
|
||||
@@ -4383,9 +4383,9 @@ q if { input.x = 7 }`},
|
||||
wantQueries: []string{}, // unconditionally false
|
||||
},
|
||||
{
|
||||
note: "or: no unknowns, lhs true",
|
||||
experimentalKeywords: true,
|
||||
query: "data.test.p",
|
||||
note: "or: no unknowns, lhs true",
|
||||
logicalKeywords: true,
|
||||
query: "data.test.p",
|
||||
modules: []string{`package test
|
||||
p if {
|
||||
true or false
|
||||
@@ -4393,9 +4393,9 @@ q if { input.x = 7 }`},
|
||||
wantQueries: []string{""}, // unconditionally true
|
||||
},
|
||||
{
|
||||
note: "or: no unknowns, rhs true",
|
||||
experimentalKeywords: true,
|
||||
query: "data.test.p",
|
||||
note: "or: no unknowns, rhs true",
|
||||
logicalKeywords: true,
|
||||
query: "data.test.p",
|
||||
modules: []string{`package test
|
||||
p if {
|
||||
false or true
|
||||
@@ -4403,9 +4403,9 @@ q if { input.x = 7 }`},
|
||||
wantQueries: []string{""}, // unconditionally true
|
||||
},
|
||||
{
|
||||
note: "or: no unknowns, both true (single result)",
|
||||
experimentalKeywords: true,
|
||||
query: "data.test.p",
|
||||
note: "or: no unknowns, both true (single result)",
|
||||
logicalKeywords: true,
|
||||
query: "data.test.p",
|
||||
modules: []string{`package test
|
||||
p if {
|
||||
true or true
|
||||
@@ -4413,9 +4413,9 @@ q if { input.x = 7 }`},
|
||||
wantQueries: []string{""}, // unconditionally true
|
||||
},
|
||||
{
|
||||
note: "or: no unknowns, both false",
|
||||
experimentalKeywords: true,
|
||||
query: "data.test.p",
|
||||
note: "or: no unknowns, both false",
|
||||
logicalKeywords: true,
|
||||
query: "data.test.p",
|
||||
modules: []string{`package test
|
||||
p if {
|
||||
false or false
|
||||
@@ -4427,9 +4427,9 @@ q if { input.x = 7 }`},
|
||||
// TODO: PE optimization in #8680
|
||||
|
||||
{
|
||||
note: "and: unknown lhs only",
|
||||
experimentalKeywords: true,
|
||||
query: "data.test.p = true",
|
||||
note: "and: unknown lhs only",
|
||||
logicalKeywords: true,
|
||||
query: "data.test.p = true",
|
||||
modules: []string{`package test
|
||||
p if {
|
||||
input.x > 0 and true
|
||||
@@ -4437,9 +4437,9 @@ q if { input.x = 7 }`},
|
||||
wantQueries: []string{`{__local0__1 = input.x; gt(__local0__1, 0)} and true`},
|
||||
},
|
||||
{
|
||||
note: "and: unknown rhs only",
|
||||
experimentalKeywords: true,
|
||||
query: "data.test.p = true",
|
||||
note: "and: unknown rhs only",
|
||||
logicalKeywords: true,
|
||||
query: "data.test.p = true",
|
||||
modules: []string{`package test
|
||||
p if {
|
||||
true and input.y > 0
|
||||
@@ -4447,9 +4447,9 @@ q if { input.x = 7 }`},
|
||||
wantQueries: []string{`true and {__local0__1 = input.y; gt(__local0__1, 0)}`},
|
||||
},
|
||||
{
|
||||
note: "and: unknowns in both",
|
||||
experimentalKeywords: true,
|
||||
query: "data.test.p = true",
|
||||
note: "and: unknowns in both",
|
||||
logicalKeywords: true,
|
||||
query: "data.test.p = true",
|
||||
modules: []string{`package test
|
||||
p if {
|
||||
input.x > 0 and input.y > 0
|
||||
@@ -4457,9 +4457,9 @@ q if { input.x = 7 }`},
|
||||
wantQueries: []string{`{__local0__1 = input.x; gt(__local0__1, 0)} and {__local1__1 = input.y; gt(__local1__1, 0)}`},
|
||||
},
|
||||
{
|
||||
note: "or: unknown lhs only",
|
||||
experimentalKeywords: true,
|
||||
query: "data.test.p = true",
|
||||
note: "or: unknown lhs only",
|
||||
logicalKeywords: true,
|
||||
query: "data.test.p = true",
|
||||
modules: []string{`package test
|
||||
p if {
|
||||
input.x > 0 or false
|
||||
@@ -4467,9 +4467,9 @@ q if { input.x = 7 }`},
|
||||
wantQueries: []string{`{__local0__1 = input.x; gt(__local0__1, 0)} or false`},
|
||||
},
|
||||
{
|
||||
note: "or: unknown rhs only",
|
||||
experimentalKeywords: true,
|
||||
query: "data.test.p = true",
|
||||
note: "or: unknown rhs only",
|
||||
logicalKeywords: true,
|
||||
query: "data.test.p = true",
|
||||
modules: []string{`package test
|
||||
p if {
|
||||
false or input.y > 0
|
||||
@@ -4477,9 +4477,9 @@ q if { input.x = 7 }`},
|
||||
wantQueries: []string{`false or {__local0__1 = input.y; gt(__local0__1, 0)}`},
|
||||
},
|
||||
{
|
||||
note: "or: unknowns in both",
|
||||
experimentalKeywords: true,
|
||||
query: "data.test.p = true",
|
||||
note: "or: unknowns in both",
|
||||
logicalKeywords: true,
|
||||
query: "data.test.p = true",
|
||||
modules: []string{`package test
|
||||
p if {
|
||||
input.x > 0 or input.y > 0
|
||||
@@ -4488,9 +4488,9 @@ q if { input.x = 7 }`},
|
||||
},
|
||||
// Baseline does NOT simplify even when one operand is statically true
|
||||
{
|
||||
note: "or: unknown lhs, rhs known-true (no simplification at this layer)",
|
||||
experimentalKeywords: true,
|
||||
query: "data.test.p = true",
|
||||
note: "or: unknown lhs, rhs known-true (no simplification at this layer)",
|
||||
logicalKeywords: true,
|
||||
query: "data.test.p = true",
|
||||
modules: []string{`package test
|
||||
p if {
|
||||
input.x > 0 or true
|
||||
@@ -4498,9 +4498,9 @@ q if { input.x = 7 }`},
|
||||
wantQueries: []string{`{__local0__1 = input.x; gt(__local0__1, 0)} or true`},
|
||||
},
|
||||
{
|
||||
note: "and: unknown lhs, rhs known-true (no simplification at this layer)",
|
||||
experimentalKeywords: true,
|
||||
query: "data.test.p = true",
|
||||
note: "and: unknown lhs, rhs known-true (no simplification at this layer)",
|
||||
logicalKeywords: true,
|
||||
query: "data.test.p = true",
|
||||
modules: []string{`package test
|
||||
p if {
|
||||
input.x > 0 and true
|
||||
@@ -4510,9 +4510,9 @@ q if { input.x = 7 }`},
|
||||
|
||||
// nested chains, data-ref unknowns, multi-expr explicit bodies
|
||||
{
|
||||
note: "and: nested left-leaning, all unknown",
|
||||
experimentalKeywords: true,
|
||||
query: "data.test.p = true",
|
||||
note: "and: nested left-leaning, all unknown",
|
||||
logicalKeywords: true,
|
||||
query: "data.test.p = true",
|
||||
modules: []string{`package test
|
||||
p if {
|
||||
input.a > 0 and input.b > 0 and input.c > 0
|
||||
@@ -4529,9 +4529,9 @@ q if { input.x = 7 }`},
|
||||
}`},
|
||||
},
|
||||
{
|
||||
note: "or: nested left-leaning, all unknown",
|
||||
experimentalKeywords: true,
|
||||
query: "data.test.p = true",
|
||||
note: "or: nested left-leaning, all unknown",
|
||||
logicalKeywords: true,
|
||||
query: "data.test.p = true",
|
||||
modules: []string{`package test
|
||||
p if {
|
||||
input.a > 0 or input.b > 0 or input.c > 0
|
||||
@@ -4548,10 +4548,10 @@ q if { input.x = 7 }`},
|
||||
}`},
|
||||
},
|
||||
{
|
||||
note: "and: mixed data and input unknowns",
|
||||
experimentalKeywords: true,
|
||||
unknowns: []string{"input", "data.foo"},
|
||||
query: "data.test.p = true",
|
||||
note: "and: mixed data and input unknowns",
|
||||
logicalKeywords: true,
|
||||
unknowns: []string{"input", "data.foo"},
|
||||
query: "data.test.p = true",
|
||||
modules: []string{`package test
|
||||
p if {
|
||||
data.foo.x > 0 and input.y > 0
|
||||
@@ -4565,9 +4565,9 @@ q if { input.x = 7 }`},
|
||||
}`},
|
||||
},
|
||||
{
|
||||
note: "and: explicit body multi-expr, unknowns inside",
|
||||
experimentalKeywords: true,
|
||||
query: "data.test.p = true",
|
||||
note: "and: explicit body multi-expr, unknowns inside",
|
||||
logicalKeywords: true,
|
||||
query: "data.test.p = true",
|
||||
modules: []string{`package test
|
||||
p if {
|
||||
{ input.x > 0; input.x < 10 } and true
|
||||
@@ -4576,9 +4576,9 @@ q if { input.x = 7 }`},
|
||||
},
|
||||
|
||||
{
|
||||
note: "and (every): unknown inside",
|
||||
experimentalKeywords: true,
|
||||
query: "data.test.p = true",
|
||||
note: "and (every): unknown inside",
|
||||
logicalKeywords: true,
|
||||
query: "data.test.p = true",
|
||||
modules: []string{`package test
|
||||
p if {
|
||||
{ x := input.x; every i in x { i in x; i < input.y } } and true
|
||||
@@ -4594,9 +4594,9 @@ q if { input.x = 7 }`},
|
||||
} and true`},
|
||||
},
|
||||
{
|
||||
note: "or (every): unknown inside",
|
||||
experimentalKeywords: true,
|
||||
query: "data.test.p = true",
|
||||
note: "or (every): unknown inside",
|
||||
logicalKeywords: true,
|
||||
query: "data.test.p = true",
|
||||
modules: []string{`package test
|
||||
p if {
|
||||
{ x := input.x; every i in x { i in x; i < input.y } } or true
|
||||
@@ -4614,9 +4614,9 @@ q if { input.x = 7 }`},
|
||||
|
||||
// comprehensions inside and/or operand bodies
|
||||
{
|
||||
note: "and: rhs set comp, cross-scope vars",
|
||||
experimentalKeywords: true,
|
||||
query: "data.test.p = true",
|
||||
note: "and: rhs set comp, cross-scope vars",
|
||||
logicalKeywords: true,
|
||||
query: "data.test.p = true",
|
||||
modules: []string{`package test
|
||||
p if {
|
||||
x := input.x
|
||||
@@ -4633,9 +4633,9 @@ q if { input.x = 7 }`},
|
||||
__local0__1 = input.x`},
|
||||
},
|
||||
{
|
||||
note: "and: lhs set comp, cross-scope vars",
|
||||
experimentalKeywords: true,
|
||||
query: "data.test.p = true",
|
||||
note: "and: lhs set comp, cross-scope vars",
|
||||
logicalKeywords: true,
|
||||
query: "data.test.p = true",
|
||||
modules: []string{`package test
|
||||
p if {
|
||||
x := input.x
|
||||
@@ -4652,9 +4652,9 @@ q if { input.x = 7 }`},
|
||||
__local0__1 = input.x`},
|
||||
},
|
||||
{
|
||||
note: "or: rhs set comp, cross-scope vars",
|
||||
experimentalKeywords: true,
|
||||
query: "data.test.p = true",
|
||||
note: "or: rhs set comp, cross-scope vars",
|
||||
logicalKeywords: true,
|
||||
query: "data.test.p = true",
|
||||
modules: []string{`package test
|
||||
p if {
|
||||
x := input.x
|
||||
@@ -4671,9 +4671,9 @@ q if { input.x = 7 }`},
|
||||
__local0__1 = input.x`},
|
||||
},
|
||||
{
|
||||
note: "or: lhs set comp, cross-scope vars",
|
||||
experimentalKeywords: true,
|
||||
query: "data.test.p = true",
|
||||
note: "or: lhs set comp, cross-scope vars",
|
||||
logicalKeywords: true,
|
||||
query: "data.test.p = true",
|
||||
modules: []string{`package test
|
||||
p if {
|
||||
x := input.x
|
||||
@@ -4690,9 +4690,9 @@ q if { input.x = 7 }`},
|
||||
__local0__1 = input.x`},
|
||||
},
|
||||
{
|
||||
note: "and: rhs array comp, cross-scope vars",
|
||||
experimentalKeywords: true,
|
||||
query: "data.test.p = true",
|
||||
note: "and: rhs array comp, cross-scope vars",
|
||||
logicalKeywords: true,
|
||||
query: "data.test.p = true",
|
||||
modules: []string{`package test
|
||||
p if {
|
||||
x := input.x
|
||||
@@ -4709,9 +4709,9 @@ q if { input.x = 7 }`},
|
||||
__local0__1 = input.x`},
|
||||
},
|
||||
{
|
||||
note: "or: lhs object comp, cross-scope vars",
|
||||
experimentalKeywords: true,
|
||||
query: "data.test.p = true",
|
||||
note: "or: lhs object comp, cross-scope vars",
|
||||
logicalKeywords: true,
|
||||
query: "data.test.p = true",
|
||||
modules: []string{`package test
|
||||
p if {
|
||||
x := input.x
|
||||
@@ -4730,9 +4730,9 @@ q if { input.x = 7 }`},
|
||||
|
||||
// and/or nested inside other outer constructs
|
||||
{
|
||||
note: "every: body contains and with unknowns",
|
||||
experimentalKeywords: true,
|
||||
query: "data.test.p = true",
|
||||
note: "every: body contains and with unknowns",
|
||||
logicalKeywords: true,
|
||||
query: "data.test.p = true",
|
||||
modules: []string{`package test
|
||||
p if {
|
||||
every x in [1, 2, 3] { x > 0 and x > input }
|
||||
@@ -4742,25 +4742,25 @@ q if { input.x = 7 }`},
|
||||
}`},
|
||||
},
|
||||
{
|
||||
note: "array comprehension: body contains or with unknowns",
|
||||
experimentalKeywords: true,
|
||||
query: "data.test.p = x",
|
||||
note: "array comprehension: body contains or with unknowns",
|
||||
logicalKeywords: true,
|
||||
query: "data.test.p = x",
|
||||
modules: []string{`package test
|
||||
p := [n | n = input.xs[i]; n > 0 or n < 0]`},
|
||||
wantQueries: []string{`x = [n1 | n1 = input.xs[i1]; gt(n1, 0) or lt(n1, 0)]`},
|
||||
},
|
||||
{
|
||||
note: "set comprehension: body contains or with unknowns",
|
||||
experimentalKeywords: true,
|
||||
query: "data.test.p = x",
|
||||
note: "set comprehension: body contains or with unknowns",
|
||||
logicalKeywords: true,
|
||||
query: "data.test.p = x",
|
||||
modules: []string{`package test
|
||||
p := {n | n = input.xs[i]; n > 0 or n < 0}`},
|
||||
wantQueries: []string{`x = {n1 | n1 = input.xs[i1]; gt(n1, 0) or lt(n1, 0)}`},
|
||||
},
|
||||
{
|
||||
note: "object comprehension: body contains and with unknowns",
|
||||
experimentalKeywords: true,
|
||||
query: "data.test.p = x",
|
||||
note: "object comprehension: body contains and with unknowns",
|
||||
logicalKeywords: true,
|
||||
query: "data.test.p = x",
|
||||
modules: []string{`package test
|
||||
p := {k: v | v := input[k]; v > 0 and v < 10}`},
|
||||
wantQueries: []string{`x = {k1: __local0__1 | __local0__1 = input[k1]; gt(__local0__1, 0) and lt(__local0__1, 10)}`},
|
||||
@@ -4768,9 +4768,9 @@ q if { input.x = 7 }`},
|
||||
|
||||
// copy-propagation
|
||||
{
|
||||
note: "copy propagation: and safety needs extra expr",
|
||||
experimentalKeywords: true,
|
||||
query: `data.test.p = true`,
|
||||
note: "copy propagation: and safety needs extra expr",
|
||||
logicalKeywords: true,
|
||||
query: `data.test.p = true`,
|
||||
modules: []string{
|
||||
`package test
|
||||
|
||||
@@ -4786,9 +4786,9 @@ q if { input.x = 7 }`},
|
||||
},
|
||||
},
|
||||
{
|
||||
note: "copy propagation: or safety needs extra expr",
|
||||
experimentalKeywords: true,
|
||||
query: `data.test.p = true`,
|
||||
note: "copy propagation: or safety needs extra expr",
|
||||
logicalKeywords: true,
|
||||
query: `data.test.p = true`,
|
||||
modules: []string{
|
||||
`package test
|
||||
|
||||
@@ -4807,9 +4807,9 @@ q if { input.x = 7 }`},
|
||||
},
|
||||
},
|
||||
{
|
||||
note: "copy propagation: and safety needs extra expr - no live var overlap",
|
||||
experimentalKeywords: true,
|
||||
query: `data.test.p = true`,
|
||||
note: "copy propagation: and safety needs extra expr - no live var overlap",
|
||||
logicalKeywords: true,
|
||||
query: `data.test.p = true`,
|
||||
modules: []string{
|
||||
`package test
|
||||
|
||||
@@ -4830,8 +4830,7 @@ q if { input.x = 7 }`},
|
||||
|
||||
for _, tc := range tests {
|
||||
popts := ast.ParserOptions{}
|
||||
if tc.experimentalKeywords {
|
||||
popts.Capabilities = ast.CapabilitiesForThisVersion(ast.CapabilitiesExperimentalKeywords(true))
|
||||
if tc.logicalKeywords {
|
||||
popts.FutureKeywords = []string{"and", "or"}
|
||||
}
|
||||
|
||||
@@ -4949,7 +4948,7 @@ func TestTopDownPartialEvalNegation(t *testing.T) {
|
||||
wantSupportASTs []*ast.Module
|
||||
ignoreOrder bool
|
||||
notBodyOnly bool
|
||||
experimentalKeywords bool // opt in to experimental and/or keywords
|
||||
logicalKeywords bool // opt in to the and/or keywords
|
||||
}{
|
||||
{
|
||||
note: "with+builtin+negation: when replacement has no unknowns (args, defs), save negated expr without replacement",
|
||||
@@ -6667,10 +6666,10 @@ func TestTopDownPartialEvalNegation(t *testing.T) {
|
||||
// TODO: PE optimization in #8680
|
||||
|
||||
{
|
||||
note: "not (and): unknown inside",
|
||||
experimentalKeywords: true,
|
||||
notBodyOnly: true,
|
||||
query: "data.test.p = true",
|
||||
note: "not (and): unknown inside",
|
||||
logicalKeywords: true,
|
||||
notBodyOnly: true,
|
||||
query: "data.test.p = true",
|
||||
modules: []string{`package test
|
||||
p if {
|
||||
not { input.x > 0 and true }
|
||||
@@ -6680,10 +6679,10 @@ func TestTopDownPartialEvalNegation(t *testing.T) {
|
||||
}`},
|
||||
},
|
||||
{
|
||||
note: "not (or): unknowns in both operands",
|
||||
experimentalKeywords: true,
|
||||
notBodyOnly: true,
|
||||
query: "data.test.p = true",
|
||||
note: "not (or): unknowns in both operands",
|
||||
logicalKeywords: true,
|
||||
notBodyOnly: true,
|
||||
query: "data.test.p = true",
|
||||
modules: []string{`package test
|
||||
p if {
|
||||
not { input.x > 0 or input.y > 0 }
|
||||
@@ -6693,10 +6692,10 @@ func TestTopDownPartialEvalNegation(t *testing.T) {
|
||||
}`},
|
||||
},
|
||||
{
|
||||
note: "not (and): unknown lhs, rhs static false ",
|
||||
experimentalKeywords: true,
|
||||
notBodyOnly: true,
|
||||
query: "data.test.p = true",
|
||||
note: "not (and): unknown lhs, rhs static false ",
|
||||
logicalKeywords: true,
|
||||
notBodyOnly: true,
|
||||
query: "data.test.p = true",
|
||||
modules: []string{`package test
|
||||
p if {
|
||||
not { input.x > 0 and false }
|
||||
@@ -6706,10 +6705,10 @@ func TestTopDownPartialEvalNegation(t *testing.T) {
|
||||
}`},
|
||||
},
|
||||
{
|
||||
note: "not (or): unknown rhs, lhs static true",
|
||||
experimentalKeywords: true,
|
||||
notBodyOnly: true,
|
||||
query: "data.test.p = true",
|
||||
note: "not (or): unknown rhs, lhs static true",
|
||||
logicalKeywords: true,
|
||||
notBodyOnly: true,
|
||||
query: "data.test.p = true",
|
||||
modules: []string{`package test
|
||||
p if {
|
||||
not {true or input.y > 0}
|
||||
@@ -6719,10 +6718,10 @@ func TestTopDownPartialEvalNegation(t *testing.T) {
|
||||
}`},
|
||||
},
|
||||
{
|
||||
note: "and (not): unknown inside",
|
||||
experimentalKeywords: true,
|
||||
notBodyOnly: true,
|
||||
query: "data.test.p = true",
|
||||
note: "and (not): unknown inside",
|
||||
logicalKeywords: true,
|
||||
notBodyOnly: true,
|
||||
query: "data.test.p = true",
|
||||
modules: []string{`package test
|
||||
p if {
|
||||
{ x := input.x; not x > 0 } and true
|
||||
@@ -6730,10 +6729,10 @@ func TestTopDownPartialEvalNegation(t *testing.T) {
|
||||
wantQueries: []string{`{ __local0__1 = input.x; not gt(__local0__1, 0) } and true`},
|
||||
},
|
||||
{
|
||||
note: "or (not): unknown inside",
|
||||
experimentalKeywords: true,
|
||||
notBodyOnly: true,
|
||||
query: "data.test.p = true",
|
||||
note: "or (not): unknown inside",
|
||||
logicalKeywords: true,
|
||||
notBodyOnly: true,
|
||||
query: "data.test.p = true",
|
||||
modules: []string{`package test
|
||||
p if {
|
||||
{ x := input.x; not x > 0 } or true
|
||||
@@ -6761,8 +6760,7 @@ func TestTopDownPartialEvalNegation(t *testing.T) {
|
||||
}
|
||||
|
||||
casePopts := popts
|
||||
if tc.experimentalKeywords {
|
||||
casePopts.Capabilities = ast.CapabilitiesForThisVersion(ast.CapabilitiesExperimentalKeywords(true))
|
||||
if tc.logicalKeywords {
|
||||
casePopts.FutureKeywords = append(append([]string{}, popts.FutureKeywords...), "and", "or")
|
||||
}
|
||||
|
||||
@@ -6872,7 +6870,6 @@ func TestTopDownPartialEvalLogicalRoundTrip(t *testing.T) {
|
||||
t.Parallel()
|
||||
|
||||
popts := ast.ParserOptions{
|
||||
Capabilities: ast.CapabilitiesForThisVersion(ast.CapabilitiesExperimentalKeywords(true)),
|
||||
FutureKeywords: []string{"and", "or"},
|
||||
}
|
||||
|
||||
|
||||
Reference in New Issue
Block a user