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:
Johan Fylling
2026-08-20 19:13:48 +02:00
committed by GitHub
parent 68b9bc35f2
commit 88f9e232ba
38 changed files with 239 additions and 496 deletions
+3 -1
View File
@@ -5006,7 +5006,9 @@
}
],
"future_keywords": [
"not"
"and",
"not",
"or"
],
"wasm_abi_versions": [
{
+4
View File
@@ -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",
},
},
}
+4
View File
@@ -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
View File
@@ -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
View File
@@ -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
View File
@@ -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
-1
View File
@@ -927,7 +927,6 @@ func TestPlannerLogicalOps(t *testing.T) {
}
parserOpts := ast.ParserOptions{
Capabilities: ast.CapabilitiesForThisVersion(ast.CapabilitiesExperimentalKeywords(true)),
FutureKeywords: []string{"and", "or", "not"},
}
-2
View File
@@ -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
View File
@@ -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()
+1 -22
View File
@@ -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 {
+16 -4
View File
@@ -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
View File
@@ -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{}
+5 -37
View File
@@ -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
View File
@@ -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)
-4
View File
@@ -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 }`,
+4 -17
View File
@@ -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:
- |
-6
View File
@@ -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:
- |
-13
View File
@@ -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:
- |
-13
View File
@@ -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:
- |
+1 -2
View File
@@ -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
View File
@@ -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"},
}