Files
releases/topdown/errors.go
T
Torin Sandall 3ebbeede6c Refactor topdown evaluation/unification
These changes modify topdown evaluation to use a binding list that
namespaces variables. This allows topdown to propagate partially ground
ref operands into child query evaluation.

These changes also prepare topdown evaluation to support a partial
evaluation mode.

With these changes, evaluation is no longer performed in two steps
(i.e., first pass of evaluating individual terms, second pass of
evaluating built-in expressions.) Instead, evaluation assumes queries
have been rewritten to eagerly evaluate refs and comprehension. This
way, ref and comprehension bindings do not have to be maintained
separately: they are handled by the normal variable binding list.

This commit contains some breaking changes to the topdown APIs,
namely...

1. Truth explanation has been removed. This feature was not used and the
tracing changes broke it. We can revisit in future if necessary.

2. Data indexing has been removed. Data indexing can be re-added in
future if necessary however it should be handled outside of topdown to
avoid potential memory leaks.

3. Built-in functions produce at-most-one output now. Functions that
used to produce multiple outputs (e.g., io.jwt.decode) can produce a
composite value if they need to.

Fixes #131
2017-11-09 09:07:48 -08:00

96 lines
2.3 KiB
Go

// Copyright 2017 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 topdown
import (
"fmt"
"github.com/open-policy-agent/opa/ast"
)
// Error is the error type returned by the Eval and Query functions when
// an evaluation error occurs.
type Error struct {
Code string `json:"code"`
Message string `json:"message"`
Location *ast.Location `json:"location,omitempty"`
}
const (
// InternalErr represents an unknown evaluation error.
InternalErr string = "eval_internal_error"
// CancelErr indicates the evaluation process was cancelled.
CancelErr string = "eval_cancel_error"
// ConflictErr indicates a conflict was encountered during evaluation. For
// instance, a conflict occurs if a rule produces multiple, differing values
// for the same key in an object. Conflict errors indicate the policy does
// not account for the data loaded into the policy engine.
ConflictErr string = "eval_conflict_error"
// TypeErr indicates evaluation stopped because an expression was applied to
// a value of an inappropriate type.
TypeErr string = "eval_type_error"
)
// IsError returns true if the err is an Error.
func IsError(err error) bool {
_, ok := err.(*Error)
return ok
}
// IsCancel returns true if err was caused by cancellation.
func IsCancel(err error) bool {
if e, ok := err.(*Error); ok {
return e.Code == CancelErr
}
return false
}
func (e *Error) Error() string {
msg := fmt.Sprintf("%v: %v", e.Code, e.Message)
if e.Location != nil {
msg = e.Location.String() + ": " + msg
}
return msg
}
func functionConflictErr(loc *ast.Location) error {
return &Error{
Code: ConflictErr,
Location: loc,
Message: "functions must not produce multiple outputs for same inputs",
}
}
func completeDocConflictErr(loc *ast.Location) error {
return &Error{
Code: ConflictErr,
Location: loc,
Message: "complete rules must not produce multiple outputs",
}
}
func objectDocKeyConflictErr(loc *ast.Location) error {
return &Error{
Code: ConflictErr,
Location: loc,
Message: "object keys must be unique",
}
}
func unsupportedBuiltinErr(loc *ast.Location) error {
return &Error{
Code: InternalErr,
Location: loc,
Message: "unsupported built-in",
}
}