mirror of
https://github.com/open-policy-agent/opa.git
synced 2026-08-13 03:42:35 -06:00
2f99f291ce
- Basic compiler framework with a few steps to resolve references
- Extend runtime to support loading policies
- Update evaluation to deal with resolved references
* Store calls (e.g., Patch, Get) expect paths. It's assumed that the path
has had the "data" prefix removed.
* The top level query interface expects paths so the "data" prefix is
added before calling into the actual TopDown implementation.
* The head of a reference can be used to determine whether it refers to a
local variable or a document in the db.
* Updates to misc. test helpers to preserve existing structure. Implicitly
import top-level documents, rename local variables to avoid conflicts,
etc.
- Refactor reference evaluation
* Remove special casing around first reference term.
This was what prevented embedded virtual doc references from working
immediately. Previously, the code assumed that the first term in the
reference identified the virtual doc/rule. This was an over simplification
that worked while the initial implementation was in progress. Now that
modules are supported, virtual docs/rules may be embedded at arbitrary
depths, e.g., "data.a.b.c[i].d[j]" where "c" is the rule name and
"a.b" is the package containing the rule.
* Break up the reference valuation into smaller functions.
* Reorder ref/path arguments
* Rename path/ref to path/tail respectively
- Separate test case for embedded virtual docs.
Also, a few misc. changes:
- Fix Ref.String() in empty case.
- Refactor hashMap into separate package.
- Get rid of ad-hoc FNV implementation. Use the one from the stdlib!
- Refactored parsing helpers from eval into ast
138 lines
3.1 KiB
Go
138 lines
3.1 KiB
Go
// Copyright 2016 The OPA Authors. All rights reserved.
|
|
// Use of this source code is governed by an Apache2
|
|
// license that can be found in the LICENSE file.
|
|
|
|
package util
|
|
|
|
import "fmt"
|
|
import "strings"
|
|
|
|
// T is a concise way to refer to T.
|
|
type T interface{}
|
|
|
|
type hashEntry struct {
|
|
k T
|
|
v T
|
|
next *hashEntry
|
|
}
|
|
|
|
// HashMap represents a key/value map.
|
|
type HashMap struct {
|
|
eq func(T, T) bool
|
|
hash func(T) int
|
|
table map[int]*hashEntry
|
|
size int
|
|
}
|
|
|
|
// NewHashMap returns a new empty HashMap.
|
|
func NewHashMap(eq func(T, T) bool, hash func(T) int) *HashMap {
|
|
return &HashMap{
|
|
eq: eq,
|
|
hash: hash,
|
|
table: make(map[int]*hashEntry),
|
|
size: 0,
|
|
}
|
|
}
|
|
|
|
// Copy returns a shallow copy of this HashMap.
|
|
func (h *HashMap) Copy() *HashMap {
|
|
cpy := NewHashMap(h.eq, h.hash)
|
|
h.Iter(func(k, v T) bool {
|
|
cpy.Put(k, v)
|
|
return false
|
|
})
|
|
return cpy
|
|
}
|
|
|
|
// Equal returns true if this HashMap equals the other HashMap.
|
|
// Two hash maps are equal if they contain the same key/value pairs.
|
|
func (h *HashMap) Equal(other *HashMap) bool {
|
|
if h.Len() != other.Len() {
|
|
return false
|
|
}
|
|
return !h.Iter(func(k, v T) bool {
|
|
ov, ok := other.Get(k)
|
|
if !ok {
|
|
return true
|
|
}
|
|
return !h.eq(v, ov)
|
|
})
|
|
}
|
|
|
|
// Get returns the value for k.
|
|
func (h *HashMap) Get(k T) (T, bool) {
|
|
hash := h.hash(k)
|
|
for entry := h.table[hash]; entry != nil; entry = entry.next {
|
|
if h.eq(entry.k, k) {
|
|
return entry.v, true
|
|
}
|
|
}
|
|
return nil, false
|
|
}
|
|
|
|
// Hash returns the hash code for this hash map.
|
|
func (h *HashMap) Hash() int {
|
|
var hash int
|
|
h.Iter(func(k, v T) bool {
|
|
hash += h.hash(k) + h.hash(v)
|
|
return false
|
|
})
|
|
return hash
|
|
}
|
|
|
|
// Iter invokes the iter function for each element in the HashMap.
|
|
// 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 (h *HashMap) Iter(iter func(T, T) bool) bool {
|
|
for _, entry := range h.table {
|
|
for ; entry != nil; entry = entry.next {
|
|
if iter(entry.k, entry.v) {
|
|
return true
|
|
}
|
|
}
|
|
}
|
|
return false
|
|
}
|
|
|
|
// Len returns the current size of this HashMap.
|
|
func (h *HashMap) Len() int {
|
|
return h.size
|
|
}
|
|
|
|
// Put inserts a key/value pair into this HashMap. If the key is already present, the existing
|
|
// value is overwritten.
|
|
func (h *HashMap) Put(k T, v T) {
|
|
hash := h.hash(k)
|
|
head := h.table[hash]
|
|
for entry := head; entry != nil; entry = entry.next {
|
|
if h.eq(entry.k, k) {
|
|
entry.v = v
|
|
return
|
|
}
|
|
}
|
|
h.table[hash] = &hashEntry{k: k, v: v, next: head}
|
|
h.size++
|
|
}
|
|
|
|
func (h *HashMap) String() string {
|
|
var buf []string
|
|
h.Iter(func(k T, v T) bool {
|
|
buf = append(buf, fmt.Sprintf("%v: %v", k, v))
|
|
return false
|
|
})
|
|
return "{" + strings.Join(buf, ", ") + "}"
|
|
}
|
|
|
|
// Update returns a new HashMap with elements from the other HashMap put into this HashMap.
|
|
// If the other HashMap contains elements with the same key as this HashMap, the value
|
|
// from the other HashMap overwrites the value from this HashMap.
|
|
func (h *HashMap) Update(other *HashMap) *HashMap {
|
|
updated := h.Copy()
|
|
other.Iter(func(k, v T) bool {
|
|
updated.Put(k, v)
|
|
return false
|
|
})
|
|
return updated
|
|
}
|