From 299606cdac995e195e4029dcd048a0ac487c38a4 Mon Sep 17 00:00:00 2001 From: Torin Sandall Date: Wed, 4 May 2016 15:54:02 -0700 Subject: [PATCH] Rename the language to Rego Rego: Latin verb for rule/govern/control. --- .gitignore | 2 +- Makefile | 2 +- {opalog => ast}/parser_ext.go | 6 +- {opalog => ast}/parser_test.go | 2 +- {opalog => ast}/policy.go | 4 +- {opalog => ast}/policy_test.go | 2 +- opalog/opalog.peg => ast/rego.peg | 2 +- {opalog => ast}/term.go | 10 +- {opalog => ast}/term_test.go | 4 +- docs/CONCEPTS.md | 16 +- docs/DEVELOPMENT.md | 4 +- docs/LANGUAGE.md | 92 ++++----- eval/hashmap.go | 22 +-- eval/hashmap_test.go | 30 +-- eval/index.go | 28 +-- eval/storage.go | 20 +- eval/storage_test.go | 10 +- eval/topdown.go | 310 +++++++++++++++--------------- eval/topdown_test.go | 52 ++--- main.go | 6 +- runtime/repl.go | 38 ++-- runtime/repl_test.go | 6 +- 22 files changed, 334 insertions(+), 334 deletions(-) rename {opalog => ast}/parser_ext.go (96%) rename {opalog => ast}/parser_test.go (99%) rename {opalog => ast}/policy.go (98%) rename {opalog => ast}/policy_test.go (99%) rename opalog/opalog.peg => ast/rego.peg (99%) rename {opalog => ast}/term.go (97%) rename {opalog => ast}/term_test.go (99%) diff --git a/.gitignore b/.gitignore index 1ac6c25d6e..cd33ccefa2 100644 --- a/.gitignore +++ b/.gitignore @@ -1,5 +1,5 @@ .DS_Store .vscode opa -opalog/parser.go +ast/parser.go coverage diff --git a/Makefile b/Makefile index ef79f69ad7..8b3c5c164b 100644 --- a/Makefile +++ b/Makefile @@ -3,9 +3,9 @@ # license that can be found in the LICENSE file. PACKAGES := \ + github.com/open-policy-agent/opa/ast/.../ \ github.com/open-policy-agent/opa/cmd/.../ \ github.com/open-policy-agent/opa/eval/.../ \ - github.com/open-policy-agent/opa/opalog/.../ \ github.com/open-policy-agent/opa/runtime/.../ BUILD_COMMIT := $(shell ./build/get-build-commit.sh) diff --git a/opalog/parser_ext.go b/ast/parser_ext.go similarity index 96% rename from opalog/parser_ext.go rename to ast/parser_ext.go index 8153d99d60..c2fada7130 100644 --- a/opalog/parser_ext.go +++ b/ast/parser_ext.go @@ -2,13 +2,13 @@ // Use of this source code is governed by an Apache2 // license that can be found in the LICENSE file. -// This file contains extra functions for parsing Opalog. +// This file contains extra functions for parsing Rego. // Most of the parsing is handled by the auto-generated code in // parser.go, however, there are additional utilities that are -// helpful for dealing with Opalog source inputs (e.g., REPL +// helpful for dealing with Rego source inputs (e.g., REPL // statements, source files, etc.) -package opalog +package ast import "fmt" diff --git a/opalog/parser_test.go b/ast/parser_test.go similarity index 99% rename from opalog/parser_test.go rename to ast/parser_test.go index eca7777d92..c63e2c5788 100644 --- a/opalog/parser_test.go +++ b/ast/parser_test.go @@ -2,7 +2,7 @@ // Use of this source code is governed by an Apache2 // license that can be found in the LICENSE file. -package opalog +package ast import ( "fmt" diff --git a/opalog/policy.go b/ast/policy.go similarity index 98% rename from opalog/policy.go rename to ast/policy.go index b5b6950e33..4c58fac2e1 100644 --- a/opalog/policy.go +++ b/ast/policy.go @@ -2,7 +2,7 @@ // Use of this source code is governed by an Apache2 // license that can be found in the LICENSE file. -package opalog +package ast import "fmt" import "strings" @@ -43,7 +43,7 @@ type ( Alias Var } - // Rule represents a rule as defined by Opalog. Rules define the + // Rule represents a rule as defined in the language. Rules define the // content of documents that represent policy decisions. Rule struct { Location *Location diff --git a/opalog/policy_test.go b/ast/policy_test.go similarity index 99% rename from opalog/policy_test.go rename to ast/policy_test.go index 5868079802..3879a6c0f3 100644 --- a/opalog/policy_test.go +++ b/ast/policy_test.go @@ -2,7 +2,7 @@ // Use of this source code is governed by an Apache2 // license that can be found in the LICENSE file. -package opalog +package ast import "testing" diff --git a/opalog/opalog.peg b/ast/rego.peg similarity index 99% rename from opalog/opalog.peg rename to ast/rego.peg index cc7e99d17b..8b432307de 100644 --- a/opalog/opalog.peg +++ b/ast/rego.peg @@ -1,5 +1,5 @@ { -package opalog +package ast // // BUGS: the escaped forward solidus (`\/`) is not currently handled for strings. diff --git a/opalog/term.go b/ast/term.go similarity index 97% rename from opalog/term.go rename to ast/term.go index 9fabd9ce80..8a42169fda 100644 --- a/opalog/term.go +++ b/ast/term.go @@ -2,7 +2,7 @@ // Use of this source code is governed by an Apache2 // license that can be found in the LICENSE file. -package opalog +package ast import "fmt" import "regexp" @@ -205,7 +205,7 @@ func (str String) Hash() int { return stringHash(string(str)) } -// Var represents a variable as defined by Opalog. +// Var represents a variable as defined by the language. type Var string // VarTerm creates a new Term with a Variable value. @@ -238,7 +238,7 @@ func (variable Var) String() string { return string(variable) } -// Ref represents a reference as defined by Opalog. +// Ref represents a reference as defined by the language. type Ref []*Term // EmptyRef returns a new, empty reference. @@ -353,7 +353,7 @@ func (ref Ref) Underlying() ([]interface{}, error) { // QueryIterator defines the interface for querying AST documents with references. type QueryIterator func(map[Var]Value, Value) error -// Array represents an array as defined by Opalog. Arrays are similar to the +// Array represents an array as defined by the language. Arrays are similar to the // same types as defined by JSON with the exception that they can contain Vars // and References. type Array []*Term @@ -423,7 +423,7 @@ func (arr Array) queryRec(ref Ref, keys map[Var]Value, iter QueryIterator) error } } -// Object represents an object as defined by Opalog. Objects are similar to +// Object represents an object as defined by the language. Objects are similar to // the same types as defined by JSON with the exception that they can contain // Vars and References. type Object [][2]*Term diff --git a/opalog/term_test.go b/ast/term_test.go similarity index 99% rename from opalog/term_test.go rename to ast/term_test.go index 758c3b0d7d..e6b6a4641d 100644 --- a/opalog/term_test.go +++ b/ast/term_test.go @@ -2,7 +2,7 @@ // Use of this source code is governed by an Apache2 // license that can be found in the LICENSE file. -package opalog +package ast import ( "fmt" @@ -38,7 +38,7 @@ func TestQuery(t *testing.T) { {"object nested", `e[100]`, []string{`["true"]`, "[{}]"}}, {"vars", `a[i][j][k]`, []string{`[[4], "d"]`, `[{i:0, j:1, k:"b"}, {i:0, j:2, k:"c"}]`}}, {"vars/mixed", `a[0][j][k]`, []string{`[[4], "d"]`, `[{j:1, k:"b"}, {j:2, k:"c"}]`}}, - {"array bad index type", `a["0"]`, fmt.Errorf(`unexpected non-numeric index in ["0"]: "0" (opalog.String)`)}, + {"array bad index type", `a["0"]`, fmt.Errorf(`unexpected non-numeric index in ["0"]: "0" (ast.String)`)}, {"array bad index value", "a[1]", fmt.Errorf(`unexpected index in [1]: out of bounds: 1`)}, {"array bad element type", "a[0][0][1]", fmt.Errorf(`unexpected non-composite at [0][1]: true`)}, {"object bad key", `e["hello"]`, fmt.Errorf(`missing key "hello": ["hello"]`)}, diff --git a/docs/CONCEPTS.md b/docs/CONCEPTS.md index d063cae058..a86e57650c 100644 --- a/docs/CONCEPTS.md +++ b/docs/CONCEPTS.md @@ -53,7 +53,7 @@ Conceptually, OPA is a collection of algorithms that answer questions about poli At a high level, using OPA involves: - Deploying OPA on servers alongside applications. -- Writing policies a declarative language ("Opalog") and loading them into OPA. +- Writing policies a declarative language ("Rego") and loading them into OPA. - Pushing application state that is relevant to policy into OPA. - Executing queries via OPA's APIs to answer questions about operations governed by policy. - Reacting to notifications delivered by OPA when policy is violated. @@ -188,17 +188,17 @@ Conceptually, there are two kinds of documents in OPA: -When defining policies, rules are written which contain expressions that reference documents. The language that rules are written in ("Opalog") lets you reference base documents and virtual documents in exactly the same way. +When defining policies, rules are written which contain expressions that reference documents. The language that rules are written in ("Rego") lets you reference base documents and virtual documents in exactly the same way. ## Policies -Policies are defined in OPA's native query language: Opalog. +Policies are defined in OPA's native query language: Rego. -Opalog is a declarative language based on [Datalog](https://en.wikipedia.org/wiki/Datalog). Opalog allows policy writers to define modules which contain rules. Rules contain expressions which assert facts about the expected state of documents stored in OPA. The documents referenced in rules may be base documents pushed by applications integrated with OPA or virtual documents defined by other rules. +Rego is a declarative language based on [Datalog](https://en.wikipedia.org/wiki/Datalog). Rego allows policy writers to define modules which contain rules. Rules contain expressions which assert facts about the expected state of documents stored in OPA. The documents referenced in rules may be base documents pushed by applications integrated with OPA or virtual documents defined by other rules. -To support document-oriented models such as JSON, Opalog has rich support for referencing nested documents (i.e., documents inside arrays or objects). The syntax for referencing nested documents is based on dictionary and array access in languages like Python as well as JSON Path. +To support document-oriented models such as JSON, Rego has rich support for referencing nested documents (i.e., documents inside arrays or objects). The syntax for referencing nested documents is based on dictionary and array access in languages like Python as well as JSON Path. Let's look at an example. @@ -236,7 +236,7 @@ Content-Type: application/json We can write a rule which enumerates servers that expose HTTP (but not HTTPS) and are connected to public networks. These represent violations of policy. -```opalog +```rego package opa.examples # this policy belongs the opa.examples package import data.servers # import the data.servers document to refer to it as "servers" instead of "data.servers" @@ -255,7 +255,7 @@ public_servers[server] :- # a server exists in the public_ networks[j].public = true # and the network is public ``` -The key aspects of Opalog are illustrated by this example: +The key aspects of Rego are illustrated by this example: - Rules define the content of virtual documents. In this case, we create two virtual documents: `violations` and `public_servers`. @@ -286,4 +286,4 @@ Content-Type: application/json ## What's Next -For more information on how to write policy definitions and queries, see [Opalog: OPA's Query Language](./LANGUAGE.md). \ No newline at end of file +For more information on how to write policy definitions and queries, see [Rego: OPA's Query Language](./LANGUAGE.md). diff --git a/docs/DEVELOPMENT.md b/docs/DEVELOPMENT.md index b6128577a8..af2b87b25e 100644 --- a/docs/DEVELOPMENT.md +++ b/docs/DEVELOPMENT.md @@ -106,6 +106,6 @@ If you need to update the dependencies: 1. Commit the changes to the glide.lock file and any files under the vendor directory. -## Opalog +## Rego -If you need to modify the Opalog syntax you must update opalog/opalog.peg. Both `make build` and `make test` will re-generate the parser but if you want to test the parser generation explicitly you can run `make generate`. +If you need to modify the Rego syntax you must update ast/rego.peg. Both `make build` and `make test` will re-generate the parser but if you want to test the parser generation explicitly you can run `make generate`. diff --git a/docs/LANGUAGE.md b/docs/LANGUAGE.md index 2d1a8216d7..c7a6ecdfaf 100644 --- a/docs/LANGUAGE.md +++ b/docs/LANGUAGE.md @@ -1,28 +1,28 @@ -# Opalog: OPA's Query Language +# Rego: OPA's Query Language -OPA includes a policy engine that is purpose built for reasoning about information represented in structured documents such as JSON. Data stored in in the policy engine can be queried using OPA's native query language: Opalog. +OPA includes a policy engine that is purpose built for reasoning about information represented in structured documents such as JSON. Data stored in in the policy engine can be queried using OPA's native query language: Rego. -## What is Opalog? +## What is Rego? -Opalog was inspired by [Datalog](https://en.wikipedia.org/wiki/Datalog), which is a well understood, decades old query language. Opalog extends Datalog to support structured document models such as JSON. +Rego was inspired by [Datalog](https://en.wikipedia.org/wiki/Datalog), which is a well understood, decades old query language. Rego extends Datalog to support structured document models such as JSON. -Opalog queries are assertions on data stored in OPA. These queries can be used to define policies that enumerate instances of data that violate the expected state of the system. +Rego queries are assertions on data stored in OPA. These queries can be used to define policies that enumerate instances of data that violate the expected state of the system. -## Why use Opalog? +## Why use Rego? -Use Opalog for defining policy that is easy to read and write. +Use Rego for defining policy that is easy to read and write. -Opalog focuses on providing powerful support for referencing nested documents and ensuring that queries are correct and unambiguous. +Rego focuses on providing powerful support for referencing nested documents and ensuring that queries are correct and unambiguous. -Opalog is declarative so policy authors can focus on what queries should return rather than how queries should be executed. These queries are simpler and more concise than the equivalent in an imperative language. Like other applications which support declarative query languages, OPA is able to optimize queries to improve performance, e.g., indexing, concurrent evaluation, reordering, etc. +Rego is declarative so policy authors can focus on what queries should return rather than how queries should be executed. These queries are simpler and more concise than the equivalent in an imperative language. Like other applications which support declarative query languages, OPA is able to optimize queries to improve performance, e.g., indexing, concurrent evaluation, reordering, etc. ## The Basics -This section introduces the main aspsects of Opalog. +This section introduces the main aspsects of Rego. The simplest rule is a single expression and is defined in terms of a [Scalar Value](#scalar-values): -```opalog +```rego pi = 3.14159 ``` @@ -35,7 +35,7 @@ pi Rules can also be defined in terms of [Composite Values](#composite-values): -```opalog +```rego rect = {"width": 2, "height": 4} ``` @@ -48,7 +48,7 @@ rect Many expressions are defined in terms of [Equality](#equality). These expressions can be thought of as assertions. The simplest example of a rule containing an equality expression involves two scalar values: -```opalog +```rego v :- 42 = "the meaning of life" ``` @@ -61,7 +61,7 @@ v The order of operands in an equality expression does not matter: -```opalog +```rego u :- "the meaning of life" = 42 ``` @@ -74,7 +74,7 @@ u We can define rules in terms of [Variables](#variables) as well: -```opalog +```rego t :- x = 42, y = 41, x > y ``` @@ -89,7 +89,7 @@ t The order of expressions in a rule does not affect the document's content: -```opalog +```rego s :- x > y, y = 41, x = 42 ``` @@ -100,9 +100,9 @@ s # true ``` -Opalog supports [References](#references) to nested documents. For example: +Rego supports [References](#references) to nested documents. For example: -```opalog +```rego sites = [{"name": "prod"}, {"name": "smoke1"}, {"name": "dev"}] r :- sites[i].name = "prod" ``` @@ -118,7 +118,7 @@ r We can generalize the example above with a rule that defines a set document instead of a boolean document: -```opalog +```rego sites = [{"name": "prod"}, {"name": "smoke1"}, {"name": "dev"}] q[name] :- sites[i].name = name ``` @@ -132,7 +132,7 @@ q We can re-write the rule "r" from above to make use of "q". We will call the new rule "p": -```opalog +```rego p :- q["prod"] ``` @@ -154,17 +154,17 @@ q["dev"] ``` If you made it this far, congratulations. This section introduced the main -aspects of Opalog. The rest of this document describes the individual aspects of Opalog in detail and is useful as a reference when reading and writing policy. Opalog's syntax is defined at the end of this document in the [Opalog Grammar](#grammar) section. +aspects of Rego. The rest of this document describes the individual aspects of Rego in detail and is useful as a reference when reading and writing policy. Rego's syntax is defined at the end of this document in the [Rego Grammar](#grammar) section. ## Scalar Values -Scalar values are the simplest type of term in Opalog. Scalar values can be +Scalar values are the simplest type of term in Rego. Scalar values can be strings, numbers, booleans, or null. Documents can be defined solely in terms of scalar values. This is useful for defining constants that are referenced in multiple places. For example: -```opalog +```rego greeting = "Hello" max_height = 42 pi = 3.14159 @@ -196,7 +196,7 @@ sentinel Composite values define collections. In simple cases, composite values can be treated as constants like [Scalar Values](#scalar-values): -```opalog +```rego cube = {"width": 3, "height": 4, "depth": 5} ``` @@ -210,7 +210,7 @@ cube.width Composite values can also be defined in terms of [Variables](#variables) or [References](#references). For example: -```opalog +```rego p[x] :- foo = 42, bar = false, @@ -230,15 +230,15 @@ define abstractions over raw data and other rules. ## Variables -Variables are another kind of term in Opalog. They can appear in both the +Variables are another kind of term in Rego. They can appear in both the head and body of rules. Variables appearing in the head of a rule can be thought of as input and -output of the rule. Unlike many programming languages, where a variable is either an input or an output, in Opalog a variable is simultaneously an input and an output. If a query supplies a value for a variable, that variable is an input, and if the query does not supply a value for a variable, that variable is an output. +output of the rule. Unlike many programming languages, where a variable is either an input or an output, in Rego a variable is simultaneously an input and an output. If a query supplies a value for a variable, that variable is an input, and if the query does not supply a value for a variable, that variable is an output. For example: -```opalog +```rego sites = [{"name": "prod"}, {"name": "smoke1"}, {"name": "dev"}] q[name] :- sites[i].name = name ``` @@ -340,7 +340,7 @@ The underscore is special because it cannot be referred to by other parts of the Rules are often written in terms of multiple expressions that contain references to documents. In the following example, the rule defines a set of tuples where each tuple contains an application name and a hostname of a server where the application is deployed. -```opalog +```rego apps_and_hostnames[pair] :- apps[i].name = name, apps[i].servers[_] = server, @@ -369,13 +369,13 @@ Don't worry about understanding everything in this example right now. There are 1. Several variables appear more than once in the body. When a variable is used in multiple locations, OPA will only produce documents for the rule with the variable bound to the same value in all expressions. -2. The rule is joining the "apps" and "sites" documents implicitly. In Opalog (and other languages based on Datalog) joins are implicit. +2. The rule is joining the "apps" and "sites" documents implicitly. In Rego (and other languages based on Datalog) joins are implicit. ### Self-Joins Using a different key on the same array or object provides the equivalent of self-join in SQL. For example, the following rule defines a document containing apps deployed on the same site as "mysql": -```opalog +```rego same_site[name] :- apps[i].name = "mysql", apps[i].servers[_] = server, @@ -406,7 +406,7 @@ in the [Examples](#examples) section. The following rule documents a set containing the hostnames of all servers: -```opalog +```rego hostnames[name] :- sites[_].servers[_].hostname = name ``` @@ -426,7 +426,7 @@ hostnames # ] ``` -This example introduces a few important aspects of Opalog. +This example introduces a few important aspects of Rego. First, the rule defines a set document where the contents are defined by the variable "name". We know this rule defines a set document because the head only includes a key. All rules have the following form (where key, value, and body are all optional): @@ -435,7 +435,7 @@ variable "name". We know this rule defines a set document because the head only ? ? ? ``` -For a more formal definition of the rule syntax, see the [Opalog Grammar](#grammar) section at the end of this document. +For a more formal definition of the rule syntax, see the [Rego Grammar](#grammar) section at the end of this document. > Set documents are collections of values without keys. OPA represents set documents as arrays when serializing to JSON or other formats which do not support a set data type. The important distinction between sets and arrays or objects is that sets are unkeyed while arrays and objects are keyed, i.e., you cannot refer to the index of an element within a set. @@ -447,7 +447,7 @@ Third, the `sites[_].servers[_].hostname = name` expression binds the value of t Rules that define objects are very similar to rules that define sets. -```opalog +```rego apps_by_hostname[hostname] = app :- sites[_].servers[_] = server, server.hostname = hostname, @@ -477,7 +477,7 @@ rule is the union of the document content for each of the individual rules. For example, we can write a rule that abstracts over our "servers" and "containers" data as "instances": -```opalog +```rego instances[instance] :- sites[_].servers[_] = server, instance = {"address": server.hostname, "name": server.name} @@ -502,7 +502,7 @@ For safety, a variable appearing in a negated expression must also appear in ano The simplest use of negation involves only scalar values or variables and is equivalent to complementing the operator: -```opalog +```rego t :- 42 = x, not x = "the meaning of life" ``` @@ -520,7 +520,7 @@ collection. I.e., complementing the operator in an expression such as `p[_] = For example, we can write a rule that defines a document containing names of apps not deployed on the "prod" site: -```opalog +```rego not_in_production[name] :- apps[i].name = name, not prod_server_names[name] @@ -539,7 +539,7 @@ not_in_production ## Modules -In Opalog, policies are defined inside *modules*. Modules consist of: +In Rego, policies are defined inside *modules*. Modules consist of: - Exactly one [Package](#packages) declaration. - Zero or more [Import](#imports) statements. @@ -564,7 +564,7 @@ The rules defined in a module are automatically exported. I.e., they can be queried under OPA's [Data API](CONCEPTS.md#data-api) provided the appropriate package is given, e.g., given the following module: -```opalog +```rego package opa.examples pi = 3.14159 @@ -588,7 +588,7 @@ Modules use the same syntax to declare dependencies on [Base Documents](./CONCEPTS.md#data-model) and [Virtual Documents](./CONCEPTS.md#data-model). -```opalog +```rego package opa.examples import data.servers @@ -601,7 +601,7 @@ http_servers[server] :- Imports can include an optional `alias` statement to handle namespacing issues: -```opalog +```rego package opa.examples import data.servers as my_servers @@ -648,7 +648,7 @@ deployment environment. These documents are referenced in other sections above. If you are experimenting with OPA, you can copy-paste the content below into an OPA CLI session and reference it when following along above. -```opalog +```rego sites :- [ { "region": "east", @@ -731,9 +731,9 @@ containers :- [ ] ``` -## Opalog Grammar +## Rego Grammar -Opalog's syntax is defined by the following grammar: +Rego's syntax is defined by the following grammar: ``` module = package { import } policy @@ -774,4 +774,4 @@ FALSE JSON false NULL JSON null ALPHA ASCII characters A-Z and a-z DIGIT ASCII characters 0-9 -``` \ No newline at end of file +``` diff --git a/eval/hashmap.go b/eval/hashmap.go index cde248ba1f..00dfb247ac 100644 --- a/eval/hashmap.go +++ b/eval/hashmap.go @@ -7,11 +7,11 @@ package eval import "fmt" import "strings" -import "github.com/open-policy-agent/opa/opalog" +import "github.com/open-policy-agent/opa/ast" type hashEntry struct { - k opalog.Value - v opalog.Value + k ast.Value + v ast.Value next *hashEntry } @@ -26,7 +26,7 @@ func newHashMap() *hashMap { func (hm *hashMap) Copy() *hashMap { cpy := newHashMap() - hm.Iter(func(k, v opalog.Value) bool { + hm.Iter(func(k, v ast.Value) bool { cpy.Put(k, v) return false }) @@ -37,7 +37,7 @@ func (hm *hashMap) Equal(other *hashMap) bool { if hm.Len() != other.Len() { return false } - return !hm.Iter(func(k, v opalog.Value) bool { + return !hm.Iter(func(k, v ast.Value) bool { ov := other.Get(k) if ov == nil { return true @@ -46,7 +46,7 @@ func (hm *hashMap) Equal(other *hashMap) bool { }) } -func (hm *hashMap) Get(k opalog.Value) opalog.Value { +func (hm *hashMap) Get(k ast.Value) ast.Value { hash := k.Hash() for entry := hm.table[hash]; entry != nil; entry = entry.next { if entry.k.Equal(k) { @@ -58,7 +58,7 @@ func (hm *hashMap) Get(k opalog.Value) opalog.Value { func (hm *hashMap) Hash() int { var hash int - hm.Iter(func(k, v opalog.Value) bool { + hm.Iter(func(k, v ast.Value) bool { hash += k.Hash() + v.Hash() return false }) @@ -69,7 +69,7 @@ func (hm *hashMap) Hash() int { // If the iter function returns true, iteration stops and the return value is true. // If the iter function never returns true, iteration proceeds through all elements // and the return value is false. -func (hm *hashMap) Iter(iter func(opalog.Value, opalog.Value) bool) bool { +func (hm *hashMap) Iter(iter func(ast.Value, ast.Value) bool) bool { for _, entry := range hm.table { for ; entry != nil; entry = entry.next { if iter(entry.k, entry.v) { @@ -84,7 +84,7 @@ func (hm *hashMap) Len() int { return hm.size } -func (hm *hashMap) Put(k opalog.Value, v opalog.Value) { +func (hm *hashMap) Put(k ast.Value, v ast.Value) { hash := k.Hash() head := hm.table[hash] for entry := head; entry != nil; entry = entry.next { @@ -99,7 +99,7 @@ func (hm *hashMap) Put(k opalog.Value, v opalog.Value) { func (hm *hashMap) String() string { var buf []string - hm.Iter(func(k opalog.Value, v opalog.Value) bool { + hm.Iter(func(k ast.Value, v ast.Value) bool { buf = append(buf, fmt.Sprintf("%v: %v", k, v)) return false }) @@ -111,7 +111,7 @@ func (hm *hashMap) String() string { // from the other hashMap overwrites the value from this hashMap. func (hm *hashMap) Update(other *hashMap) *hashMap { updated := hm.Copy() - other.Iter(func(k, v opalog.Value) bool { + other.Iter(func(k, v ast.Value) bool { updated.Put(k, v) return false }) diff --git a/eval/hashmap_test.go b/eval/hashmap_test.go index 99cc491fe2..9f6d09b11d 100644 --- a/eval/hashmap_test.go +++ b/eval/hashmap_test.go @@ -9,14 +9,14 @@ import ( "reflect" "testing" - "github.com/open-policy-agent/opa/opalog" + "github.com/open-policy-agent/opa/ast" ) func TestHashmapOverwrite(t *testing.T) { m := newHashMap() - key := opalog.String("hello") - expected := opalog.String("goodbye") - m.Put(key, opalog.String("world")) + key := ast.String("hello") + expected := ast.String("goodbye") + m.Put(key, ast.String("world")) m.Put(key, expected) result := m.Get(key) if result != expected { @@ -26,8 +26,8 @@ func TestHashmapOverwrite(t *testing.T) { func TestHashmapIter(t *testing.T) { m := newHashMap() - keys := []opalog.Number{opalog.Number(1), opalog.Number(2), opalog.Number(1.4)} - value := opalog.Null{} + keys := []ast.Number{ast.Number(1), ast.Number(2), ast.Number(1.4)} + value := ast.Null{} for _, k := range keys { m.Put(k, value) } @@ -35,15 +35,15 @@ func TestHashmapIter(t *testing.T) { if len(m.table) != 2 { panic(fmt.Sprintf("Expected collision: %v", m)) } - results := map[opalog.Value]opalog.Value{} - m.Iter(func(k opalog.Value, v opalog.Value) bool { + results := map[ast.Value]ast.Value{} + m.Iter(func(k ast.Value, v ast.Value) bool { results[k] = v return false }) - expected := map[opalog.Value]opalog.Value{ - opalog.Number(1): value, - opalog.Number(2): value, - opalog.Number(1.4): value, + expected := map[ast.Value]ast.Value{ + ast.Number(1): value, + ast.Number(2): value, + ast.Number(1.4): value, } if !reflect.DeepEqual(results, expected) { t.Errorf("Expected %v but got %v", expected, results) @@ -53,9 +53,9 @@ func TestHashmapIter(t *testing.T) { func TestHashmapCompare(t *testing.T) { m := newHashMap() n := newHashMap() - k1 := opalog.String("k1") - k2 := opalog.String("k2") - k3 := opalog.String("k3") + k1 := ast.String("k1") + k2 := ast.String("k2") + k3 := ast.String("k3") v1 := parseTerm(`[{"a": 1, "b": 2}, {"c": 3}]`).Value v2 := parseTerm(`[{"a": 1, "b": 2}, {"c": 4}]`).Value m.Put(k1, v1) diff --git a/eval/index.go b/eval/index.go index e1c889d56b..b214ccec1a 100644 --- a/eval/index.go +++ b/eval/index.go @@ -8,7 +8,7 @@ import ( "fmt" "strings" - "github.com/open-policy-agent/opa/opalog" + "github.com/open-policy-agent/opa/ast" ) // Indices contains a mapping of non-ground references to values to sets of bindings. @@ -34,7 +34,7 @@ type Indices struct { } type indicesNode struct { - key opalog.Ref + key ast.Ref val *Index next *indicesNode } @@ -48,9 +48,9 @@ func NewIndices() *Indices { // Build initializes the references' index by walking the store for the reference and // creating the index that maps values to bindings. -func (ind *Indices) Build(store *Storage, ref opalog.Ref) error { +func (ind *Indices) Build(store *Storage, ref ast.Ref) error { index := NewIndex() - err := iterStorage(store, ref, opalog.EmptyRef(), newHashMap(), func(bindings *hashMap, val interface{}) { + err := iterStorage(store, ref, ast.EmptyRef(), newHashMap(), func(bindings *hashMap, val interface{}) { index.Add(val, bindings) }) if err != nil { @@ -68,7 +68,7 @@ func (ind *Indices) Build(store *Storage, ref opalog.Ref) error { } // Drop removes the index for the reference. -func (ind *Indices) Drop(ref opalog.Ref) { +func (ind *Indices) Drop(ref ast.Ref) { hashCode := ref.Hash() var prev *indicesNode for entry := ind.table[hashCode]; entry != nil; entry = entry.next { @@ -84,7 +84,7 @@ func (ind *Indices) Drop(ref opalog.Ref) { } // Get returns the reference's index. -func (ind *Indices) Get(ref opalog.Ref) *Index { +func (ind *Indices) Get(ref ast.Ref) *Index { node := ind.getNode(ref) if node != nil { return node.val @@ -93,7 +93,7 @@ func (ind *Indices) Get(ref opalog.Ref) *Index { } // Iter calls the iter function for each of the indices. -func (ind *Indices) Iter(iter func(opalog.Ref, *Index) error) error { +func (ind *Indices) Iter(iter func(ast.Ref, *Index) error) error { for _, head := range ind.table { for entry := head; entry != nil; entry = entry.next { if err := iter(entry.key, entry.val); err != nil { @@ -115,7 +115,7 @@ func (ind *Indices) String() string { return "{" + strings.Join(buf, ", ") + "}" } -func (ind *Indices) getNode(ref opalog.Ref) *indicesNode { +func (ind *Indices) getNode(ref ast.Ref) *indicesNode { hashCode := ref.Hash() for entry := ind.table[hashCode]; entry != nil; entry = entry.next { if entry.key.Equal(ref) { @@ -292,7 +292,7 @@ func hash(v interface{}) int { panic(fmt.Sprintf("illegal argument: %v (%T)", v, v)) } -func iterStorage(store *Storage, ref opalog.Ref, path opalog.Ref, bindings *hashMap, iter func(*hashMap, interface{})) error { +func iterStorage(store *Storage, ref ast.Ref, path ast.Ref, bindings *hashMap, iter func(*hashMap, interface{})) error { if len(ref) == 0 { @@ -315,7 +315,7 @@ func iterStorage(store *Storage, ref opalog.Ref, path opalog.Ref, bindings *hash head := ref[0] tail := ref[1:] - headVar, isVar := head.Value.(opalog.Var) + headVar, isVar := head.Value.(ast.Var) if !isVar || len(path) == 0 { path = append(path, head) @@ -337,9 +337,9 @@ func iterStorage(store *Storage, ref opalog.Ref, path opalog.Ref, bindings *hash switch node := node.(type) { case map[string]interface{}: for key := range node { - path = append(path, opalog.StringTerm(key)) + path = append(path, ast.StringTerm(key)) cpy := bindings.Copy() - cpy.Put(headVar, opalog.String(key)) + cpy.Put(headVar, ast.String(key)) err := iterStorage(store, tail, path, cpy, iter) if err != nil { return err @@ -348,9 +348,9 @@ func iterStorage(store *Storage, ref opalog.Ref, path opalog.Ref, bindings *hash } case []interface{}: for i := range node { - path = append(path, opalog.NumberTerm(float64(i))) + path = append(path, ast.NumberTerm(float64(i))) cpy := bindings.Copy() - cpy.Put(headVar, opalog.Number(float64(i))) + cpy.Put(headVar, ast.Number(float64(i))) err := iterStorage(store, tail, path, cpy, iter) if err != nil { return err diff --git a/eval/storage.go b/eval/storage.go index 36836251e9..98af7cb07f 100644 --- a/eval/storage.go +++ b/eval/storage.go @@ -9,7 +9,7 @@ import ( "fmt" "os" - "github.com/open-policy-agent/opa/opalog" + "github.com/open-policy-agent/opa/ast" ) // StorageErrorCode represents the collection of error types that can be @@ -163,9 +163,9 @@ func (store *Storage) Patch(op StorageOp, path []interface{}, value interface{}) // Drop the indices that are affected by this patch. This is inefficient for mixed read-write // access patterns, but it's easy and simple for now. Once we have more information about // the use cases, we can optimize this. - r := []opalog.Ref{} + r := []ast.Ref{} - err := store.Indices.Iter(func(ref opalog.Ref, index *Index) error { + err := store.Indices.Iter(func(ref ast.Ref, index *Index) error { if !commonPrefix(ref, path) { return nil } @@ -202,28 +202,28 @@ func (store *Storage) String() string { // commonPrefix returns true the reference is a prefix of the path or vice versa. // The shorter value is the prefix of the other if all of the ground elements // are equal to the elements at the same indices in the other. -func commonPrefix(ref opalog.Ref, path []interface{}) bool { +func commonPrefix(ref ast.Ref, path []interface{}) bool { min := len(ref) if len(path) < min { min = len(path) } - cmp := func(a opalog.Value, b interface{}) bool { + cmp := func(a ast.Value, b interface{}) bool { switch a := a.(type) { - case opalog.Null: + case ast.Null: if b == nil { return true } - case opalog.Boolean: + case ast.Boolean: if b, ok := b.(bool); ok { return b == bool(a) } - case opalog.Number: + case ast.Number: if b, ok := b.(float64); ok { return b == float64(a) } - case opalog.String: + case ast.String: if b, ok := b.(string); ok { return b == string(a) } @@ -231,7 +231,7 @@ func commonPrefix(ref opalog.Ref, path []interface{}) bool { return false } - v := opalog.String(ref[0].Value.(opalog.Var)) + v := ast.String(ref[0].Value.(ast.Var)) if !cmp(v, path[0]) { return false diff --git a/eval/storage_test.go b/eval/storage_test.go index 4cdde05e17..2eb05dc824 100644 --- a/eval/storage_test.go +++ b/eval/storage_test.go @@ -12,7 +12,7 @@ import ( "reflect" "testing" - "github.com/open-policy-agent/opa/opalog" + "github.com/open-policy-agent/opa/ast" ) func TestLoadFromJSONFiles(t *testing.T) { @@ -291,7 +291,7 @@ func TestStorageIndexingAddDeepRef(t *testing.T) { } } -func newStorageWithIndices(r ...opalog.Ref) *Storage { +func newStorageWithIndices(r ...ast.Ref) *Storage { data := loadSmallTestData() store := NewStorageFromJSONObject(data) for _, x := range r { @@ -300,7 +300,7 @@ func newStorageWithIndices(r ...opalog.Ref) *Storage { return store } -func mustBuild(store *Storage, ref opalog.Ref) { +func mustBuild(store *Storage, ref ast.Ref) { err := store.Indices.Build(store, ref) if err != nil { panic(err) @@ -320,9 +320,9 @@ func path(input interface{}) []interface{} { return input case string: switch v := parseTerm(input).Value.(type) { - case opalog.Var: + case ast.Var: return []interface{}{string(v)} - case opalog.Ref: + case ast.Ref: path, err := v.Underlying() if err != nil { panic(err) diff --git a/eval/topdown.go b/eval/topdown.go index 916a4be221..2437c0874a 100644 --- a/eval/topdown.go +++ b/eval/topdown.go @@ -7,7 +7,7 @@ package eval import ( "fmt" - "github.com/open-policy-agent/opa/opalog" + "github.com/open-policy-agent/opa/ast" "github.com/pkg/errors" ) @@ -18,7 +18,7 @@ import ( // step and binding. This avoids the need to undo steps and bindings // each time the proof fails but this may be too expensive. type TopDownContext struct { - Query opalog.Body + Query ast.Body Bindings *hashMap Index int Previous *TopDownContext @@ -27,7 +27,7 @@ type TopDownContext struct { } // NewTopDownContext creates a new TopDownContext with no bindings. -func NewTopDownContext(query opalog.Body, store *Storage) *TopDownContext { +func NewTopDownContext(query ast.Body, store *Storage) *TopDownContext { return &TopDownContext{ Query: query, Bindings: newHashMap(), @@ -36,7 +36,7 @@ func NewTopDownContext(query opalog.Body, store *Storage) *TopDownContext { } // BindRef returns a new TopDownContext with bindings that map the reference to the value. -func (ctx *TopDownContext) BindRef(ref opalog.Ref, value opalog.Value) *TopDownContext { +func (ctx *TopDownContext) BindRef(ref ast.Ref, value ast.Value) *TopDownContext { cpy := *ctx cpy.Bindings = ctx.Bindings.Copy() cpy.Bindings.Put(ref, value) @@ -59,11 +59,11 @@ func (ctx *TopDownContext) BindRef(ref opalog.Ref, value opalog.Value) *TopDownC // bindings each time a new binding is added. E.g., if Bind(y, [1,2,x]) and Bind(x, 3) are called // (one after the other), the binding for "y" will be updated. It may be possible to defer this // to a later stage, e.g., when plugging the values. -func (ctx *TopDownContext) BindVar(variable opalog.Var, value opalog.Value) *TopDownContext { +func (ctx *TopDownContext) BindVar(variable ast.Var, value ast.Value) *TopDownContext { if variable.Equal(value) { return ctx } - occurs := walkValue(value, func(other opalog.Value) bool { + occurs := walkValue(value, func(other ast.Value) bool { if variable.Equal(other) { return true } @@ -76,7 +76,7 @@ func (ctx *TopDownContext) BindVar(variable opalog.Var, value opalog.Value) *Top cpy.Bindings = newHashMap() tmp := newHashMap() tmp.Put(variable, value) - ctx.Bindings.Iter(func(k opalog.Value, v opalog.Value) bool { + ctx.Bindings.Iter(func(k ast.Value, v ast.Value) bool { cpy.Bindings.Put(k, plugValue(v, tmp)) return false }) @@ -85,7 +85,7 @@ func (ctx *TopDownContext) BindVar(variable opalog.Var, value opalog.Value) *Top } // Child returns a new context to evaluate a rule that was referenced by this context. -func (ctx *TopDownContext) Child(rule *opalog.Rule, bindings *hashMap) *TopDownContext { +func (ctx *TopDownContext) Child(rule *ast.Rule, bindings *hashMap) *TopDownContext { cpy := *ctx cpy.Query = rule.Body cpy.Bindings = bindings @@ -95,7 +95,7 @@ func (ctx *TopDownContext) Child(rule *opalog.Rule, bindings *hashMap) *TopDownC } // Current returns the current expression to evaluate. -func (ctx *TopDownContext) Current() *opalog.Expr { +func (ctx *TopDownContext) Current() *ast.Expr { return ctx.Query[ctx.Index] } @@ -119,11 +119,11 @@ func (ctx *TopDownContext) traceEval() { ctx.trace("Eval %v", ctx.Current()) } -func (ctx *TopDownContext) traceTry(expr *opalog.Expr) { +func (ctx *TopDownContext) traceTry(expr *ast.Expr) { ctx.trace(" Try %v", expr) } -func (ctx *TopDownContext) traceSuccess(expr *opalog.Expr) { +func (ctx *TopDownContext) traceSuccess(expr *ast.Expr) { ctx.trace(" Success %v", expr) } @@ -154,10 +154,10 @@ type TopDownQueryParams struct { // algorithm is run to generate the virtual document defined by the rules. func TopDownQuery(params *TopDownQueryParams) (interface{}, error) { - var ref opalog.Ref - ref = append(ref, opalog.VarTerm(params.Path[0])) + var ref ast.Ref + ref = append(ref, ast.VarTerm(params.Path[0])) for _, v := range params.Path[1:] { - ref = append(ref, opalog.StringTerm(v)) + ref = append(ref, ast.StringTerm(v)) } node, err := lookup(params.Store, ref) @@ -166,18 +166,18 @@ func TopDownQuery(params *TopDownQueryParams) (interface{}, error) { } switch node := node.(type) { - case []*opalog.Rule: + case []*ast.Rule: if len(node) == 0 { return Undefined{}, nil } // This assumes that all the rules identified by the path are of the same // type. This is checked at compile time. switch node[0].DocKind() { - case opalog.CompleteDoc: + case ast.CompleteDoc: return topDownQueryCompleteDoc(params, node) - case opalog.PartialObjectDoc: + case ast.PartialObjectDoc: return topDownQueryPartialObjectDoc(params, node) - case opalog.PartialSetDoc: + case ast.PartialSetDoc: return topDownQueryPartialSetDoc(params, node) default: return nil, fmt.Errorf("invalid document (kind: %v): %v", node[0].DocKind(), ref) @@ -198,22 +198,22 @@ func (undefined Undefined) String() string { // ValueToInterface returns the underlying Go value associated with an AST value. // If the value is a reference, the reference is fetched from storage. Composite // AST values such as objects and arrays are converted recursively. -func ValueToInterface(v opalog.Value, ctx *TopDownContext) (interface{}, error) { +func ValueToInterface(v ast.Value, ctx *TopDownContext) (interface{}, error) { switch v := v.(type) { // Scalars easily convert to native values. - case opalog.Null: + case ast.Null: return nil, nil - case opalog.Boolean: + case ast.Boolean: return bool(v), nil - case opalog.Number: + case ast.Number: return float64(v), nil - case opalog.String: + case ast.String: return string(v), nil // Recursively convert array into []interface{}... - case opalog.Array: + case ast.Array: buf := []interface{}{} for _, x := range v { x1, err := ValueToInterface(x.Value, ctx) @@ -225,7 +225,7 @@ func ValueToInterface(v opalog.Value, ctx *TopDownContext) (interface{}, error) return buf, nil // Recursively convert object into map[string]interface{}... - case opalog.Object: + case ast.Object: buf := map[string]interface{}{} for _, x := range v { k, err := ValueToInterface(x[0].Value, ctx) @@ -245,7 +245,7 @@ func ValueToInterface(v opalog.Value, ctx *TopDownContext) (interface{}, error) return buf, nil // References convert to native values via lookup. - case opalog.Ref: + case ast.Ref: return lookup(ctx.Store, v) default: @@ -256,19 +256,19 @@ func ValueToInterface(v opalog.Value, ctx *TopDownContext) (interface{}, error) } } -type builtinFunction func(*TopDownContext, *opalog.Expr, TopDownIterator) error +type builtinFunction func(*TopDownContext, *ast.Expr, TopDownIterator) error const ( - equalityBuiltin = opalog.Var("=") + equalityBuiltin = ast.Var("=") ) -var builtinFunctions = map[opalog.Var]builtinFunction{ +var builtinFunctions = map[ast.Var]builtinFunction{ equalityBuiltin: evalEq, } // dereferenceVar is used to lookup the variable binding and convert the value to // a native Go type. -func dereferenceVar(v opalog.Var, ctx *TopDownContext) (interface{}, error) { +func dereferenceVar(v ast.Var, ctx *TopDownContext) (interface{}, error) { binding := ctx.Bindings.Get(v) if binding == nil { return nil, fmt.Errorf("unbound variable: %v", v) @@ -285,7 +285,7 @@ func evalContext(ctx *TopDownContext, iter TopDownIterator) error { // do not appear elsewhere in the query. In this case, "x" and "y" // will be bound to each other; they will not be ground and so // the proof should not be considered successful. - isNonGround := ctx.Bindings.Iter(func(k, v opalog.Value) bool { + isNonGround := ctx.Bindings.Iter(func(k, v ast.Value) bool { if !v.IsGround() { return true } @@ -317,7 +317,7 @@ func evalContext(ctx *TopDownContext, iter TopDownIterator) error { func evalContextNegated(ctx *TopDownContext, iter TopDownIterator) error { negation := *ctx - negation.Query = opalog.Body([]*opalog.Expr{ctx.Current().Complement()}) + negation.Query = ast.Body([]*ast.Expr{ctx.Current().Complement()}) negation.Index = 0 negation.Previous = ctx @@ -339,16 +339,16 @@ func evalContextNegated(ctx *TopDownContext, iter TopDownIterator) error { return nil } -func evalEq(ctx *TopDownContext, expr *opalog.Expr, iter TopDownIterator) error { +func evalEq(ctx *TopDownContext, expr *ast.Expr, iter TopDownIterator) error { - operands := expr.Terms.([]*opalog.Term) + operands := expr.Terms.([]*ast.Term) a := operands[1].Value b := operands[2].Value return evalEqUnify(ctx, a, b, iter) } -func evalEqGround(ctx *TopDownContext, a opalog.Value, b opalog.Value, iter TopDownIterator) error { +func evalEqGround(ctx *TopDownContext, a ast.Value, b ast.Value, iter TopDownIterator) error { av, err := ValueToInterface(a, ctx) if err != nil { return err @@ -379,7 +379,7 @@ func evalEqGround(ctx *TopDownContext, a opalog.Value, b opalog.Value, iter TopD // // In cases involving references, OPA assumes that the references are ground at this stage. // As a result, references are just special cases of the normal scalar/composite unification. -func evalEqUnify(ctx *TopDownContext, a opalog.Value, b opalog.Value, iter TopDownIterator) error { +func evalEqUnify(ctx *TopDownContext, a ast.Value, b ast.Value, iter TopDownIterator) error { // Plug bindings into both terms because this will be called recursively and there may be // new bindings that have been made as part of unification. @@ -387,19 +387,19 @@ func evalEqUnify(ctx *TopDownContext, a opalog.Value, b opalog.Value, iter TopDo b = plugValue(b, ctx.Bindings) switch a := a.(type) { - case opalog.Var: + case ast.Var: return evalEqUnifyVar(ctx, a, b, iter) - case opalog.Object: + case ast.Object: return evalEqUnifyObject(ctx, a, b, iter) - case opalog.Array: + case ast.Array: return evalEqUnifyArray(ctx, a, b, iter) default: switch b := b.(type) { - case opalog.Var: + case ast.Var: return evalEqUnifyVar(ctx, b, a, iter) - case opalog.Array: + case ast.Array: return evalEqUnifyArray(ctx, b, a, iter) - case opalog.Object: + case ast.Object: return evalEqUnifyObject(ctx, b, a, iter) default: return evalEqGround(ctx, a, b, iter) @@ -408,20 +408,20 @@ func evalEqUnify(ctx *TopDownContext, a opalog.Value, b opalog.Value, iter TopDo } -func evalEqUnifyArray(ctx *TopDownContext, a opalog.Array, b opalog.Value, iter TopDownIterator) error { +func evalEqUnifyArray(ctx *TopDownContext, a ast.Array, b ast.Value, iter TopDownIterator) error { switch b := b.(type) { - case opalog.Var: + case ast.Var: return evalEqUnifyVar(ctx, b, a, iter) - case opalog.Ref: + case ast.Ref: return evalEqUnifyArrayRef(ctx, a, b, iter) - case opalog.Array: + case ast.Array: return evalEqUnifyArrays(ctx, a, b, iter) default: return nil } } -func evalEqUnifyArrayRef(ctx *TopDownContext, a opalog.Array, b opalog.Ref, iter TopDownIterator) error { +func evalEqUnifyArrayRef(ctx *TopDownContext, a ast.Array, b ast.Ref, iter TopDownIterator) error { r, err := lookup(ctx.Store, b) if err != nil { @@ -439,9 +439,9 @@ func evalEqUnifyArrayRef(ctx *TopDownContext, a opalog.Array, b opalog.Ref, iter for i := range a { var tmp *TopDownContext - child := make(opalog.Ref, len(b), len(b)+1) + child := make(ast.Ref, len(b), len(b)+1) copy(child, b) - child = append(child, opalog.NumberTerm(float64(i))) + child = append(child, ast.NumberTerm(float64(i))) err := evalEqUnify(ctx, a[i].Value, child, func(ctx *TopDownContext) error { tmp = ctx return nil @@ -457,7 +457,7 @@ func evalEqUnifyArrayRef(ctx *TopDownContext, a opalog.Array, b opalog.Ref, iter return iter(ctx) } -func evalEqUnifyArrays(ctx *TopDownContext, a opalog.Array, b opalog.Array, iter TopDownIterator) error { +func evalEqUnifyArrays(ctx *TopDownContext, a ast.Array, b ast.Array, iter TopDownIterator) error { aLen := len(a) bLen := len(b) if aLen != bLen { @@ -485,20 +485,20 @@ func evalEqUnifyArrays(ctx *TopDownContext, a opalog.Array, b opalog.Array, iter // evalEqUnifyObject attempts to unify the object "a" with some other value "b". // TODO(tsandal): unification of object keys (or unordered sets in general) is not // supported because it would be too expensive. We may revisit this in the future. -func evalEqUnifyObject(ctx *TopDownContext, a opalog.Object, b opalog.Value, iter TopDownIterator) error { +func evalEqUnifyObject(ctx *TopDownContext, a ast.Object, b ast.Value, iter TopDownIterator) error { switch b := b.(type) { - case opalog.Var: + case ast.Var: return evalEqUnifyVar(ctx, b, a, iter) - case opalog.Ref: + case ast.Ref: return evalEqUnifyObjectRef(ctx, a, b, iter) - case opalog.Object: + case ast.Object: return evalEqUnifyObjects(ctx, a, b, iter) default: return nil } } -func evalEqUnifyObjectRef(ctx *TopDownContext, a opalog.Object, b opalog.Ref, iter TopDownIterator) error { +func evalEqUnifyObjectRef(ctx *TopDownContext, a ast.Object, b ast.Ref, iter TopDownIterator) error { r, err := lookup(ctx.Store, b) @@ -523,7 +523,7 @@ func evalEqUnifyObjectRef(ctx *TopDownContext, a opalog.Object, b opalog.Ref, it for i := range a { // TODO(tsandall): support non-string keys in storage. - k, ok := a[i][0].Value.(opalog.String) + k, ok := a[i][0].Value.(ast.String) if !ok { return fmt.Errorf("cannot unify object with non-string key: %v", a[i][0]) } @@ -533,7 +533,7 @@ func evalEqUnifyObjectRef(ctx *TopDownContext, a opalog.Object, b opalog.Ref, it return nil } - child := make(opalog.Ref, len(b), len(b)+1) + child := make(ast.Ref, len(b), len(b)+1) copy(child, b) child = append(child, a[i][0]) var tmp *TopDownContext @@ -552,7 +552,7 @@ func evalEqUnifyObjectRef(ctx *TopDownContext, a opalog.Object, b opalog.Ref, it return iter(ctx) } -func evalEqUnifyObjects(ctx *TopDownContext, a opalog.Object, b opalog.Object, iter TopDownIterator) error { +func evalEqUnifyObjects(ctx *TopDownContext, a ast.Object, b ast.Object, iter TopDownIterator) error { if len(a) != len(b) { return nil @@ -592,7 +592,7 @@ func evalEqUnifyObjects(ctx *TopDownContext, a opalog.Object, b opalog.Object, i return iter(ctx) } -func evalEqUnifyVar(ctx *TopDownContext, a opalog.Var, b opalog.Value, iter TopDownIterator) error { +func evalEqUnifyVar(ctx *TopDownContext, a ast.Var, b ast.Value, iter TopDownIterator) error { ctx = ctx.BindVar(a, b) if ctx == nil { return nil @@ -604,8 +604,8 @@ func evalExpr(ctx *TopDownContext, iter TopDownIterator) error { expr := plugExpr(ctx.Current(), ctx.Bindings) ctx.traceTry(expr) switch tt := expr.Terms.(type) { - case []*opalog.Term: - builtin := builtinFunctions[tt[0].Value.(opalog.Var)] + case []*ast.Term: + builtin := builtinFunctions[tt[0].Value.(ast.Var)] if builtin == nil { // Operator validation is done at compile-time so we panic here because // this should never happen. @@ -615,10 +615,10 @@ func evalExpr(ctx *TopDownContext, iter TopDownIterator) error { ctx.traceSuccess(expr) return iter(ctx) }) - case *opalog.Term: + case *ast.Term: switch tv := tt.Value.(type) { - case opalog.Boolean: - if tv.Equal(opalog.Boolean(true)) { + case ast.Boolean: + if tv.Equal(ast.Boolean(true)) { return iter(ctx) } return nil @@ -630,11 +630,11 @@ func evalExpr(ctx *TopDownContext, iter TopDownIterator) error { } } -func evalRef(ctx *TopDownContext, ref opalog.Ref, iter TopDownIterator) error { - return evalRefRec(ctx, ref, iter, opalog.EmptyRef()) +func evalRef(ctx *TopDownContext, ref ast.Ref, iter TopDownIterator) error { + return evalRefRec(ctx, ref, iter, ast.EmptyRef()) } -func evalRefRec(ctx *TopDownContext, ref opalog.Ref, iter TopDownIterator, path opalog.Ref) error { +func evalRefRec(ctx *TopDownContext, ref ast.Ref, iter TopDownIterator, path ast.Ref) error { if len(ref) == 0 { _, err := lookup(ctx.Store, path) @@ -653,7 +653,7 @@ func evalRefRec(ctx *TopDownContext, ref opalog.Ref, iter TopDownIterator, path head := ref[0] tail := ref[1:] - headVar, isVar := head.Value.(opalog.Var) + headVar, isVar := head.Value.(ast.Var) // Handle head of reference. if isVar && len(path) == 0 { @@ -677,7 +677,7 @@ func evalRefRec(ctx *TopDownContext, ref opalog.Ref, iter TopDownIterator, path } switch node := node.(type) { - case []*opalog.Rule: + case []*ast.Rule: for _, rule := range node { if err := evalRefRule(ctx, ref, path, rule, iter); err != nil { return err @@ -698,7 +698,7 @@ func evalRefRec(ctx *TopDownContext, ref opalog.Ref, iter TopDownIterator, path // Binding already exists for variable. Treat it as a constant. binding := ctx.Bindings.Get(headVar) if binding != nil { - path = append(path, &opalog.Term{Value: binding}) + path = append(path, &ast.Term{Value: binding}) return evalRefRec(ctx, tail, iter, path) } @@ -718,8 +718,8 @@ func evalRefRec(ctx *TopDownContext, ref opalog.Ref, iter TopDownIterator, path switch node := node.(type) { case map[string]interface{}: for key := range node { - cpy := ctx.BindVar(headVar, opalog.String(key)) - path = append(path, opalog.StringTerm(key)) + cpy := ctx.BindVar(headVar, ast.String(key)) + path = append(path, ast.StringTerm(key)) err := evalRefRec(cpy, tail, iter, path) if err != nil { return err @@ -729,8 +729,8 @@ func evalRefRec(ctx *TopDownContext, ref opalog.Ref, iter TopDownIterator, path return nil case []interface{}: for i := range node { - cpy := ctx.BindVar(headVar, opalog.Number(i)) - path = append(path, opalog.NumberTerm(float64(i))) + cpy := ctx.BindVar(headVar, ast.Number(i)) + path = append(path, ast.NumberTerm(float64(i))) err := evalRefRec(cpy, tail, iter, path) if err != nil { return err @@ -743,14 +743,14 @@ func evalRefRec(ctx *TopDownContext, ref opalog.Ref, iter TopDownIterator, path } } -func evalRefRule(ctx *TopDownContext, ref opalog.Ref, path opalog.Ref, rule *opalog.Rule, iter TopDownIterator) error { +func evalRefRule(ctx *TopDownContext, ref ast.Ref, path ast.Ref, rule *ast.Rule, iter TopDownIterator) error { switch rule.DocKind() { - case opalog.PartialSetDoc: + case ast.PartialSetDoc: return evalRefRulePartialSetDoc(ctx, ref, path, rule, iter) - case opalog.PartialObjectDoc: + case ast.PartialObjectDoc: return evalRefRulePartialObjectDoc(ctx, ref, path, rule, iter) - case opalog.CompleteDoc: + case ast.CompleteDoc: return evalRefRuleCompleteDoc(ctx, ref, path, rule, iter) default: panic(fmt.Sprintf("illegal argument: %v", rule)) @@ -758,7 +758,7 @@ func evalRefRule(ctx *TopDownContext, ref opalog.Ref, path opalog.Ref, rule *opa } -func evalRefRuleCompleteDoc(ctx *TopDownContext, ref opalog.Ref, path opalog.Ref, rule *opalog.Rule, iter TopDownIterator) error { +func evalRefRuleCompleteDoc(ctx *TopDownContext, ref ast.Ref, path ast.Ref, rule *ast.Rule, iter TopDownIterator) error { suffix := ref[len(path):] if len(suffix) == 0 { return fmt.Errorf("not implemented: %v %v %v", ref, path, rule) @@ -769,9 +769,9 @@ func evalRefRuleCompleteDoc(ctx *TopDownContext, ref opalog.Ref, path opalog.Ref return TopDown(child, func(child *TopDownContext) error { switch v := rule.Value.Value.(type) { - case opalog.Object: + case ast.Object: return evalRefRuleResult(ctx, ref, suffix, v, iter) - case opalog.Array: + case ast.Array: return evalRefRuleResult(ctx, ref, suffix, v, iter) default: return fmt.Errorf("cannot dereference value (%T) in %v", rule.Value.Value, rule) @@ -779,7 +779,7 @@ func evalRefRuleCompleteDoc(ctx *TopDownContext, ref opalog.Ref, path opalog.Ref }) } -func evalRefRulePartialObjectDoc(ctx *TopDownContext, ref opalog.Ref, path opalog.Ref, rule *opalog.Rule, iter TopDownIterator) error { +func evalRefRulePartialObjectDoc(ctx *TopDownContext, ref ast.Ref, path ast.Ref, rule *ast.Rule, iter TopDownIterator) error { suffix := ref[len(path):] if len(suffix) == 0 { return fmt.Errorf("not implemented: %v %v %v", ref, path, rule) @@ -810,7 +810,7 @@ func evalRefRulePartialObjectDoc(ctx *TopDownContext, ref opalog.Ref, path opalo if value == nil { return fmt.Errorf("unbound variable: %v", rule.Value) } - ctx = ctx.BindVar(suffix[0].Value.(opalog.Var), key) + ctx = ctx.BindVar(suffix[0].Value.(ast.Var), key) return evalRefRuleResult(ctx, ref, ref[len(path)+1:], value, iter) }) } @@ -828,7 +828,7 @@ func evalRefRulePartialObjectDoc(ctx *TopDownContext, ref opalog.Ref, path opalo }) } -func evalRefRulePartialSetDoc(ctx *TopDownContext, ref opalog.Ref, path opalog.Ref, rule *opalog.Rule, iter TopDownIterator) error { +func evalRefRulePartialSetDoc(ctx *TopDownContext, ref ast.Ref, path ast.Ref, rule *ast.Rule, iter TopDownIterator) error { suffix := ref[len(path):] if len(suffix) == 0 { return fmt.Errorf("not implemented: %v %v %v", ref, path, rule) @@ -857,8 +857,8 @@ func evalRefRulePartialSetDoc(ctx *TopDownContext, ref opalog.Ref, path opalog.R // so that expression will be defined. E.g., given a simple rule: // "p = true :- q[x]", we say that "p" should be defined if "q" // is defined for some value "x". - ctx = ctx.BindVar(key.(opalog.Var), value) - ctx = ctx.BindRef(ref[:len(path)+1], opalog.Boolean(true)) + ctx = ctx.BindVar(key.(ast.Var), value) + ctx = ctx.BindRef(ref[:len(path)+1], ast.Boolean(true)) return iter(ctx) }) } @@ -869,16 +869,16 @@ func evalRefRulePartialSetDoc(ctx *TopDownContext, ref opalog.Ref, path opalog.R return TopDown(child, func(child *TopDownContext) error { // See comment above for explanation of why the reference is bound to true. - ctx = ctx.BindRef(ref[:len(path)+1], opalog.Boolean(true)) + ctx = ctx.BindRef(ref[:len(path)+1], ast.Boolean(true)) return iter(ctx) }) } -func evalRefRuleResult(ctx *TopDownContext, ref opalog.Ref, suffix opalog.Ref, result opalog.Value, iter TopDownIterator) error { +func evalRefRuleResult(ctx *TopDownContext, ref ast.Ref, suffix ast.Ref, result ast.Value, iter TopDownIterator) error { switch result := result.(type) { - case opalog.Ref: + case ast.Ref: // Below we concatenate the result of evaluating a rule with the rest of the reference // to be evaluated. // @@ -888,7 +888,7 @@ func evalRefRuleResult(ctx *TopDownContext, ref opalog.Ref, suffix opalog.Ref, r // needing to be processed. This is done by substituting the prefix of the original reference // with the binding. In this case, the prefix is "q[k]" and the binding value would be // "a[]". - var binding opalog.Ref + var binding ast.Ref binding = append(binding, result...) binding = append(binding, suffix...) return evalRefRec(ctx, suffix, func(ctx *TopDownContext) error { @@ -896,13 +896,13 @@ func evalRefRuleResult(ctx *TopDownContext, ref opalog.Ref, suffix opalog.Ref, r return iter(ctx) }, result) - case opalog.Array: + case ast.Array: if len(suffix) > 0 { - var pluggedSuffix opalog.Ref + var pluggedSuffix ast.Ref for _, t := range suffix { pluggedSuffix = append(pluggedSuffix, plugTerm(t, ctx.Bindings)) } - result.Query(pluggedSuffix, func(keys map[opalog.Var]opalog.Value, value opalog.Value) error { + result.Query(pluggedSuffix, func(keys map[ast.Var]ast.Value, value ast.Value) error { ctx = ctx.BindRef(ref, value) for k, v := range keys { ctx = ctx.BindVar(k, v) @@ -916,13 +916,13 @@ func evalRefRuleResult(ctx *TopDownContext, ref opalog.Ref, suffix opalog.Ref, r // This can't be hit because we have checks in the evalRefRule* functions that catch this. panic(fmt.Sprintf("illegal value: %v %v %v", ref, suffix, result)) - case opalog.Object: + case ast.Object: if len(suffix) > 0 { - var pluggedSuffix opalog.Ref + var pluggedSuffix ast.Ref for _, t := range suffix { pluggedSuffix = append(pluggedSuffix, plugTerm(t, ctx.Bindings)) } - result.Query(pluggedSuffix, func(keys map[opalog.Var]opalog.Value, value opalog.Value) error { + result.Query(pluggedSuffix, func(keys map[ast.Var]ast.Value, value ast.Value) error { ctx = ctx.BindRef(ref, value) for k, v := range keys { ctx = ctx.BindVar(k, v) @@ -958,11 +958,11 @@ func evalRefRuleResult(ctx *TopDownContext, ref opalog.Ref, suffix opalog.Ref, r func evalTerms(ctx *TopDownContext, iter TopDownIterator) error { expr := ctx.Current() - var ts []*opalog.Term + var ts []*ast.Term switch t := expr.Terms.(type) { - case []*opalog.Term: + case []*ast.Term: ts = t - case *opalog.Term: + case *ast.Term: ts = append(ts, t) default: panic(fmt.Sprintf("illegal argument: %v", t)) @@ -970,7 +970,7 @@ func evalTerms(ctx *TopDownContext, iter TopDownIterator) error { if indexAvailable(ctx, ts) { - ref, isRef := ts[1].Value.(opalog.Ref) + ref, isRef := ts[1].Value.(ast.Ref) if isRef { ok, err := indexBuildLazy(ctx, ref) @@ -982,7 +982,7 @@ func evalTerms(ctx *TopDownContext, iter TopDownIterator) error { } } - ref, isRef = ts[2].Value.(opalog.Ref) + ref, isRef = ts[2].Value.(ast.Ref) if isRef { ok, err := indexBuildLazy(ctx, ref) @@ -998,7 +998,7 @@ func evalTerms(ctx *TopDownContext, iter TopDownIterator) error { return evalTermsRec(ctx, iter, ts) } -func evalTermsIndexed(ctx *TopDownContext, iter TopDownIterator, indexed opalog.Ref, nonIndexed *opalog.Term) error { +func evalTermsIndexed(ctx *TopDownContext, iter TopDownIterator, indexed ast.Ref, nonIndexed *ast.Term) error { iterateIndex := func(ctx *TopDownContext) error { @@ -1024,10 +1024,10 @@ func evalTermsIndexed(ctx *TopDownContext, iter TopDownIterator, indexed opalog. } - return evalTermsRec(ctx, iterateIndex, []*opalog.Term{nonIndexed}) + return evalTermsRec(ctx, iterateIndex, []*ast.Term{nonIndexed}) } -func evalTermsRec(ctx *TopDownContext, iter TopDownIterator, ts []*opalog.Term) error { +func evalTermsRec(ctx *TopDownContext, iter TopDownIterator, ts []*ast.Term) error { if len(ts) == 0 { return iter(ctx) @@ -1037,15 +1037,15 @@ func evalTermsRec(ctx *TopDownContext, iter TopDownIterator, ts []*opalog.Term) tail := ts[1:] switch head := head.Value.(type) { - case opalog.Ref: + case ast.Ref: return evalRef(ctx, head, func(ctx *TopDownContext) error { return evalTermsRec(ctx, iter, tail) }) - case opalog.Array: + case ast.Array: return evalTermsRecArray(ctx, head, 0, func(ctx *TopDownContext) error { return evalTermsRec(ctx, iter, tail) }) - case opalog.Object: + case ast.Object: return evalTermsRecObject(ctx, head, 0, func(ctx *TopDownContext) error { return evalTermsRec(ctx, iter, tail) }) @@ -1054,20 +1054,20 @@ func evalTermsRec(ctx *TopDownContext, iter TopDownIterator, ts []*opalog.Term) } } -func evalTermsRecArray(ctx *TopDownContext, arr opalog.Array, idx int, iter TopDownIterator) error { +func evalTermsRecArray(ctx *TopDownContext, arr ast.Array, idx int, iter TopDownIterator) error { if idx >= len(arr) { return iter(ctx) } switch v := arr[idx].Value.(type) { - case opalog.Ref: + case ast.Ref: return evalRef(ctx, v, func(ctx *TopDownContext) error { return evalTermsRecArray(ctx, arr, idx+1, iter) }) - case opalog.Array: + case ast.Array: return evalTermsRecArray(ctx, v, 0, func(ctx *TopDownContext) error { return evalTermsRecArray(ctx, arr, idx+1, iter) }) - case opalog.Object: + case ast.Object: return evalTermsRecObject(ctx, v, 0, func(ctx *TopDownContext) error { return evalTermsRecArray(ctx, arr, idx+1, iter) }) @@ -1076,23 +1076,23 @@ func evalTermsRecArray(ctx *TopDownContext, arr opalog.Array, idx int, iter TopD } } -func evalTermsRecObject(ctx *TopDownContext, obj opalog.Object, idx int, iter TopDownIterator) error { +func evalTermsRecObject(ctx *TopDownContext, obj ast.Object, idx int, iter TopDownIterator) error { if idx >= len(obj) { return iter(ctx) } switch k := obj[idx][0].Value.(type) { - case opalog.Ref: + case ast.Ref: return evalRef(ctx, k, func(ctx *TopDownContext) error { switch v := obj[idx][1].Value.(type) { - case opalog.Ref: + case ast.Ref: return evalRef(ctx, v, func(ctx *TopDownContext) error { return evalTermsRecObject(ctx, obj, idx+1, iter) }) - case opalog.Array: + case ast.Array: return evalTermsRecArray(ctx, v, 0, func(ctx *TopDownContext) error { return evalTermsRecObject(ctx, obj, idx+1, iter) }) - case opalog.Object: + case ast.Object: return evalTermsRecObject(ctx, v, 0, func(ctx *TopDownContext) error { return evalTermsRecObject(ctx, obj, idx+1, iter) }) @@ -1102,15 +1102,15 @@ func evalTermsRecObject(ctx *TopDownContext, obj opalog.Object, idx int, iter To }) default: switch v := obj[idx][1].Value.(type) { - case opalog.Ref: + case ast.Ref: return evalRef(ctx, v, func(ctx *TopDownContext) error { return evalTermsRecObject(ctx, obj, idx+1, iter) }) - case opalog.Array: + case ast.Array: return evalTermsRecArray(ctx, v, 0, func(ctx *TopDownContext) error { return evalTermsRecObject(ctx, obj, idx+1, iter) }) - case opalog.Object: + case ast.Object: return evalTermsRecObject(ctx, v, 0, func(ctx *TopDownContext) error { return evalTermsRecObject(ctx, obj, idx+1, iter) }) @@ -1124,7 +1124,7 @@ func evalTermsRecObject(ctx *TopDownContext, obj opalog.Object, idx int, iter To // Indexing is used on equality expressions where both sides are non-ground refs (to base docs) or one // side is a non-ground ref (to a base doc) and the other side is any ground term. In the future, indexing // may be used on references embedded inside array/object values. -func indexAvailable(ctx *TopDownContext, terms []*opalog.Term) bool { +func indexAvailable(ctx *TopDownContext, terms []*ast.Term) bool { // Indexing can only be used when evaluating equality expressions. if !terms[0].Value.Equal(equalityBuiltin) { @@ -1134,8 +1134,8 @@ func indexAvailable(ctx *TopDownContext, terms []*opalog.Term) bool { pluggedA := plugTerm(terms[1], ctx.Bindings) pluggedB := plugTerm(terms[2], ctx.Bindings) - _, isRefA := pluggedA.Value.(opalog.Ref) - _, isRefB := pluggedB.Value.(opalog.Ref) + _, isRefA := pluggedA.Value.(ast.Ref) + _, isRefB := pluggedB.Value.(ast.Ref) if isRefA && !pluggedA.IsGround() { return pluggedB.IsGround() || isRefB @@ -1151,7 +1151,7 @@ func indexAvailable(ctx *TopDownContext, terms []*opalog.Term) bool { // indexBuildLazy returns true if there is an index built for this term. If there is no index // currently built for the term, but the term is a candidate for indexing, ther index will be // built on the fly. -func indexBuildLazy(ctx *TopDownContext, ref opalog.Ref) (bool, error) { +func indexBuildLazy(ctx *TopDownContext, ref ast.Ref) (bool, error) { if ref.IsGround() { return false, nil @@ -1168,7 +1168,7 @@ func indexBuildLazy(ctx *TopDownContext, ref opalog.Ref) (bool, error) { } // Ignore refs against virtual docs. - tmp := opalog.Ref{ref[0]} + tmp := ast.Ref{ref[0]} for _, p := range ref[1:] { path, _ := tmp.Underlying() @@ -1178,7 +1178,7 @@ func indexBuildLazy(ctx *TopDownContext, ref opalog.Ref) (bool, error) { } switch r.(type) { - case ([]*opalog.Rule): + case ([]*ast.Rule): return false, nil } @@ -1196,7 +1196,7 @@ func indexBuildLazy(ctx *TopDownContext, ref opalog.Ref) (bool, error) { return true, nil } -func lookup(store *Storage, ref opalog.Ref) (interface{}, error) { +func lookup(store *Storage, ref ast.Ref) (interface{}, error) { path, err := ref.Underlying() if err != nil { return nil, err @@ -1204,17 +1204,17 @@ func lookup(store *Storage, ref opalog.Ref) (interface{}, error) { return store.Get(path) } -func plugExpr(expr *opalog.Expr, bindings *hashMap) *opalog.Expr { +func plugExpr(expr *ast.Expr, bindings *hashMap) *ast.Expr { plugged := *expr switch ts := plugged.Terms.(type) { - case []*opalog.Term: - var buf []*opalog.Term + case []*ast.Term: + var buf []*ast.Term buf = append(buf, ts[0]) for _, term := range ts[1:] { buf = append(buf, plugTerm(term, bindings)) } plugged.Terms = buf - case *opalog.Term: + case *ast.Term: plugged.Terms = plugTerm(ts, bindings) default: panic(fmt.Sprintf("illegal argument: %v", ts)) @@ -1222,22 +1222,22 @@ func plugExpr(expr *opalog.Expr, bindings *hashMap) *opalog.Expr { return &plugged } -func plugTerm(term *opalog.Term, bindings *hashMap) *opalog.Term { +func plugTerm(term *ast.Term, bindings *hashMap) *ast.Term { switch v := term.Value.(type) { - case opalog.Var: - return &opalog.Term{Value: plugValue(v, bindings)} + case ast.Var: + return &ast.Term{Value: plugValue(v, bindings)} - case opalog.Ref: + case ast.Ref: plugged := *term plugged.Value = plugValue(v, bindings) return &plugged - case opalog.Array: + case ast.Array: plugged := *term plugged.Value = plugValue(v, bindings) return &plugged - case opalog.Object: + case ast.Object: plugged := *term plugged.Value = plugValue(v, bindings) return &plugged @@ -1250,17 +1250,17 @@ func plugTerm(term *opalog.Term, bindings *hashMap) *opalog.Term { } } -func plugValue(v opalog.Value, bindings *hashMap) opalog.Value { +func plugValue(v ast.Value, bindings *hashMap) ast.Value { switch v := v.(type) { - case opalog.Var: + case ast.Var: binding := bindings.Get(v) if binding == nil { return v } return binding - case opalog.Ref: + case ast.Ref: binding := bindings.Get(v) if binding != nil { return binding @@ -1268,26 +1268,26 @@ func plugValue(v opalog.Value, bindings *hashMap) opalog.Value { if v.IsGround() { return v } - var buf opalog.Ref + var buf ast.Ref buf = append(buf, v[0]) for _, p := range v[1:] { buf = append(buf, plugTerm(p, bindings)) } return buf - case opalog.Array: - var buf opalog.Array + case ast.Array: + var buf ast.Array for _, e := range v { buf = append(buf, plugTerm(e, bindings)) } return buf - case opalog.Object: - var buf opalog.Object + case ast.Object: + var buf ast.Object for _, e := range v { k := plugTerm(e[0], bindings) v := plugTerm(e[1], bindings) - buf = append(buf, [...]*opalog.Term{k, v}) + buf = append(buf, [...]*ast.Term{k, v}) } return buf @@ -1299,7 +1299,7 @@ func plugValue(v opalog.Value, bindings *hashMap) opalog.Value { } } -func topDownQueryCompleteDoc(params *TopDownQueryParams, rules []*opalog.Rule) (interface{}, error) { +func topDownQueryCompleteDoc(params *TopDownQueryParams, rules []*ast.Rule) (interface{}, error) { if len(rules) > 1 { return nil, fmt.Errorf("multiple conflicting rules: %v", rules[0].Name) @@ -1329,7 +1329,7 @@ func topDownQueryCompleteDoc(params *TopDownQueryParams, rules []*opalog.Rule) ( return ValueToInterface(rule.Value.Value, ctx) } -func topDownQueryPartialObjectDoc(params *TopDownQueryParams, rules []*opalog.Rule) (interface{}, error) { +func topDownQueryPartialObjectDoc(params *TopDownQueryParams, rules []*ast.Rule) (interface{}, error) { result := map[string]interface{}{} @@ -1340,8 +1340,8 @@ func topDownQueryPartialObjectDoc(params *TopDownQueryParams, rules []*opalog.Ru Store: params.Store, Tracer: params.Tracer, } - key := rule.Key.Value.(opalog.Var) - value := rule.Value.Value.(opalog.Var) + key := rule.Key.Value.(ast.Var) + value := rule.Value.Value.(ast.Var) err := TopDown(ctx, func(ctx *TopDownContext) error { key, err := dereferenceVar(key, ctx) if err != nil { @@ -1366,7 +1366,7 @@ func topDownQueryPartialObjectDoc(params *TopDownQueryParams, rules []*opalog.Ru return result, nil } -func topDownQueryPartialSetDoc(params *TopDownQueryParams, rules []*opalog.Rule) (interface{}, error) { +func topDownQueryPartialSetDoc(params *TopDownQueryParams, rules []*ast.Rule) (interface{}, error) { result := []interface{}{} for _, rule := range rules { ctx := &TopDownContext{ @@ -1375,7 +1375,7 @@ func topDownQueryPartialSetDoc(params *TopDownQueryParams, rules []*opalog.Rule) Store: params.Store, Tracer: params.Tracer, } - key := rule.Key.Value.(opalog.Var) + key := rule.Key.Value.(ast.Var) err := TopDown(ctx, func(ctx *TopDownContext) error { value, err := dereferenceVar(key, ctx) if err != nil { @@ -1395,23 +1395,23 @@ func topDownQueryPartialSetDoc(params *TopDownQueryParams, rules []*opalog.Rule) // walkValue invokes the iterator for each AST value contained inside the supplied AST value. // If walkValue is called with a scalar, the iterator is invoked exactly once. // If walkValue is called with a reference, the iterator is invoked for each element in the reference. -func walkValue(value opalog.Value, iter func(opalog.Value) bool) bool { +func walkValue(value ast.Value, iter func(ast.Value) bool) bool { switch value := value.(type) { - case opalog.Ref: + case ast.Ref: for _, x := range value { if walkValue(x.Value, iter) { return true } } return false - case opalog.Array: + case ast.Array: for _, x := range value { if walkValue(x.Value, iter) { return true } } return false - case opalog.Object: + case ast.Object: for _, i := range value { if walkValue(i[0].Value, iter) { return true diff --git a/eval/topdown_test.go b/eval/topdown_test.go index afcf8f0379..6b0366b201 100644 --- a/eval/topdown_test.go +++ b/eval/topdown_test.go @@ -10,7 +10,7 @@ import "encoding/json" import "reflect" import "sort" -import "github.com/open-policy-agent/opa/opalog" +import "github.com/open-policy-agent/opa/ast" func TestEvalRef(t *testing.T) { @@ -169,16 +169,16 @@ func TestEvalTerms(t *testing.T) { func TestPlugValue(t *testing.T) { - a := opalog.Var("a") - b := opalog.Var("b") - c := opalog.Var("c") - k := opalog.Var("k") - v := opalog.Var("v") + a := ast.Var("a") + b := ast.Var("b") + c := ast.Var("c") + k := ast.Var("k") + v := ast.Var("v") cs := parseTerm("[c]").Value ks := parseTerm(`{k: "world"}`).Value vs := parseTerm(`{"hello": v}`).Value - hello := opalog.String("hello") - world := opalog.String("world") + hello := ast.String("hello") + world := ast.String("world") ctx1 := &TopDownContext{Bindings: newHashMap()} ctx1 = ctx1.BindVar(a, b) @@ -522,9 +522,9 @@ func loadExpectedBindings(input string) []*hashMap { for k, v := range bindings { switch v := v.(type) { case string: - buf.Put(opalog.Var(k), opalog.String(v)) + buf.Put(ast.Var(k), ast.String(v)) case float64: - buf.Put(opalog.Var(k), opalog.Number(v)) + buf.Put(ast.Var(k), ast.Number(v)) default: panic("unreachable") } @@ -607,12 +607,12 @@ func loadSmallTestData() map[string]interface{} { return data } -func newStorage(data map[string]interface{}, rules []*opalog.Rule) *Storage { - byName := map[opalog.Var][]*opalog.Rule{} +func newStorage(data map[string]interface{}, rules []*ast.Rule) *Storage { + byName := map[ast.Var][]*ast.Rule{} for _, rule := range rules { s, ok := byName[rule.Name] if !ok { - s = []*opalog.Rule{} + s = []*ast.Rule{} } s = append(s, rule) byName[rule.Name] = s @@ -627,29 +627,29 @@ func newStorage(data map[string]interface{}, rules []*opalog.Rule) *Storage { return store } -func parseBody(input string) opalog.Body { - return opalog.MustParseStatement(input).(opalog.Body) +func parseBody(input string) ast.Body { + return ast.MustParseStatement(input).(ast.Body) } -func parseRef(input string) opalog.Ref { - body := opalog.MustParseStatement(input).(opalog.Body) - return body[0].Terms.(*opalog.Term).Value.(opalog.Ref) +func parseRef(input string) ast.Ref { + body := ast.MustParseStatement(input).(ast.Body) + return body[0].Terms.(*ast.Term).Value.(ast.Ref) } -func parseRule(input string) *opalog.Rule { - return opalog.MustParseStatement(input).(*opalog.Rule) +func parseRule(input string) *ast.Rule { + return ast.MustParseStatement(input).(*ast.Rule) } -func parseRules(input []string) []*opalog.Rule { - rules := []*opalog.Rule{} +func parseRules(input []string) []*ast.Rule { + rules := []*ast.Rule{} for i := range input { rules = append(rules, parseRule(input[i])) } return rules } -func parseTerm(input string) *opalog.Term { - return opalog.MustParseStatement(input).(opalog.Body)[0].Terms.(*opalog.Term) +func parseTerm(input string) *ast.Term { + return ast.MustParseStatement(input).(ast.Body)[0].Terms.(*ast.Term) } func runTopDownTestCase(t *testing.T, data map[string]interface{}, i int, note string, rules []string, expected interface{}) { @@ -676,8 +676,8 @@ func runTopDownTestCase(t *testing.T, data map[string]interface{}, i int, note s t.Errorf("Test case %d (%v): unexpected error: %v", i+1, note, err) return } - switch store.MustGet([]interface{}{"p"}).([]*opalog.Rule)[0].DocKind() { - case opalog.PartialSetDoc: + switch store.MustGet([]interface{}{"p"}).([]*ast.Rule)[0].DocKind() { + case ast.PartialSetDoc: sort.Sort(ResultSet(result.([]interface{}))) } if !reflect.DeepEqual(result, expected) { diff --git a/main.go b/main.go index 6a36792c1c..ef634c542f 100644 --- a/main.go +++ b/main.go @@ -15,7 +15,7 @@ func main() { } } -// Opalog parser generation: +// Rego parser generation: // -//go:generate pigeon -o opalog/parser.go opalog/opalog.peg -//go:generate goimports -w opalog/parser.go +//go:generate pigeon -o ast/parser.go ast/rego.peg +//go:generate goimports -w ast/parser.go diff --git a/runtime/repl.go b/runtime/repl.go index 0aed0d389f..42c94229f4 100644 --- a/runtime/repl.go +++ b/runtime/repl.go @@ -13,8 +13,8 @@ import ( "strings" "github.com/apcera/termtables" + "github.com/open-policy-agent/opa/ast" "github.com/open-policy-agent/opa/eval" - "github.com/open-policy-agent/opa/opalog" "github.com/peterh/liner" ) @@ -167,7 +167,7 @@ func (r *Repl) evalBufferOne() bool { // The user may enter lines with comments on the end or // multiple lines with comments interspersed. In these cases // the parser will return multiple statements. - stmts, err := opalog.ParseStatements(line) + stmts, err := ast.ParseStatements(line) if err != nil { return false @@ -191,7 +191,7 @@ func (r *Repl) evalBufferMulti() bool { return false } - stmts, err := opalog.ParseStatements(line) + stmts, err := ast.ParseStatements(line) if err != nil { fmt.Fprintln(r.Output, "parse error:", err) @@ -207,15 +207,15 @@ func (r *Repl) evalBufferMulti() bool { func (r *Repl) evalStatement(stmt interface{}) bool { switch stmt := stmt.(type) { - case opalog.Body: + case ast.Body: return r.evalBody(stmt) - case *opalog.Rule: + case *ast.Rule: return r.evalRule(stmt) } return false } -func (r *Repl) evalBody(body opalog.Body) bool { +func (r *Repl) evalBody(body ast.Body) bool { ctx := eval.NewTopDownContext(body, r.Runtime.Store) if r.Trace { @@ -236,8 +236,8 @@ func (r *Repl) evalBody(body opalog.Body) bool { err := eval.TopDown(ctx, func(ctx *eval.TopDownContext) error { var err error row := map[string]interface{}{} - ctx.Bindings.Iter(func(k, v opalog.Value) bool { - if _, isVar := k.(opalog.Var); !isVar { + ctx.Bindings.Iter(func(k, v ast.Value) bool { + if _, isVar := k.(ast.Var); !isVar { return false } r, e := eval.ValueToInterface(v, ctx) @@ -281,7 +281,7 @@ func (r *Repl) evalBody(body opalog.Body) bool { return false } -func (r *Repl) printResults(body opalog.Body, results []map[string]interface{}) { +func (r *Repl) printResults(body ast.Body, results []map[string]interface{}) { table := termtables.CreateTable() r.printHeader(table, body) for _, row := range results { @@ -290,7 +290,7 @@ func (r *Repl) printResults(body opalog.Body, results []map[string]interface{}) fmt.Fprintf(r.Output, table.Render()) } -func (r *Repl) printHeader(table *termtables.Table, body opalog.Body) { +func (r *Repl) printHeader(table *termtables.Table, body ast.Body) { // Build set of fields for the output. The fields are the variables from inside the body. // If the variable appears multiple times, we only want a single field so store them in a @@ -300,11 +300,11 @@ func (r *Repl) printHeader(table *termtables.Table, body opalog.Body) { // TODO(tsandall): perhaps we could refactor this to use a "walk" function on the body. for _, expr := range body { switch ts := expr.Terms.(type) { - case []*opalog.Term: + case []*ast.Term: for _, t := range ts[1:] { buildHeader(fields, t) } - case *opalog.Term: + case *ast.Term: buildHeader(fields, ts) } } @@ -350,11 +350,11 @@ func (r *Repl) printRow(table *termtables.Table, row map[string]interface{}) { table.AddRow(buf...) } -func (r *Repl) evalRule(rule *opalog.Rule) bool { +func (r *Repl) evalRule(rule *ast.Rule) bool { path := []interface{}{string(rule.Name)} - if err := r.Runtime.Store.Patch(eval.StorageAdd, path, []*opalog.Rule{rule}); err != nil { + if err := r.Runtime.Store.Patch(eval.StorageAdd, path, []*ast.Rule{rule}); err != nil { fmt.Fprintln(r.Output, "unexpected error:", err) return true } @@ -384,22 +384,22 @@ func (r *Repl) saveHistory(prompt *liner.State) { } } -func buildHeader(fields map[string]struct{}, term *opalog.Term) { +func buildHeader(fields map[string]struct{}, term *ast.Term) { switch v := term.Value.(type) { - case opalog.Ref: + case ast.Ref: for _, t := range v[1:] { buildHeader(fields, t) } - case opalog.Var: + case ast.Var: fields[string(v)] = struct{}{} - case opalog.Object: + case ast.Object: for _, i := range v { buildHeader(fields, i[0]) buildHeader(fields, i[1]) } - case opalog.Array: + case ast.Array: for _, e := range v { buildHeader(fields, e) } diff --git a/runtime/repl_test.go b/runtime/repl_test.go index ca69a40cb4..02c5734b63 100644 --- a/runtime/repl_test.go +++ b/runtime/repl_test.go @@ -10,8 +10,8 @@ import ( "reflect" "testing" + "github.com/open-policy-agent/opa/ast" "github.com/open-policy-agent/opa/eval" - "github.com/open-policy-agent/opa/opalog" ) func TestDump(t *testing.T) { @@ -76,8 +76,8 @@ func TestOneShotBufferedRule(t *testing.T) { } func TestBuildHeader(t *testing.T) { - expr := opalog.MustParseStatement(`[{"a": x, "b": a.b[y]}] = [{"a": 1, "b": 2}]`).(opalog.Body)[0] - terms := expr.Terms.([]*opalog.Term) + expr := ast.MustParseStatement(`[{"a": x, "b": a.b[y]}] = [{"a": 1, "b": 2}]`).(ast.Body)[0] + terms := expr.Terms.([]*ast.Term) result := map[string]struct{}{} buildHeader(result, terms[1]) expected := map[string]struct{}{