396 lines
9.6 KiB
Go
396 lines
9.6 KiB
Go
// Copyright 2018 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 ir defines an intermediate representation (IR) for Rego.
|
|
//
|
|
// The IR specifies an imperative execution model for Rego policies similar to a
|
|
// query plan in traditional databases.
|
|
package ir
|
|
|
|
import (
|
|
"fmt"
|
|
)
|
|
|
|
type (
|
|
// Policy represents a planned policy query.
|
|
Policy struct {
|
|
Static *Static
|
|
Plan *Plan
|
|
Funcs *Funcs
|
|
}
|
|
|
|
// Static represents a static data segment that is indexed into by the policy.
|
|
Static struct {
|
|
Strings []*StringConst
|
|
BuiltinFuncs []*BuiltinFunc
|
|
}
|
|
|
|
// BuiltinFunc represents a built-in function that may be required by the
|
|
// policy.
|
|
BuiltinFunc struct {
|
|
Name string
|
|
}
|
|
|
|
// Funcs represents a collection of planned functions to include in the
|
|
// policy.
|
|
Funcs struct {
|
|
Funcs []*Func
|
|
}
|
|
|
|
// Func represents a named plan (function) that can be invoked. Functions
|
|
// accept one or more parameters and return a value. By convention, the
|
|
// input document and data documents are always passed as the first and
|
|
// second arguments (respectively).
|
|
Func struct {
|
|
Name string
|
|
Params []Local
|
|
Return Local
|
|
Blocks []*Block // TODO(tsandall): should this be a plan?
|
|
}
|
|
|
|
// Plan represents an ordered series of blocks to execute. Plan execution
|
|
// stops when a return statement is reached. Blocks are executed in-order.
|
|
Plan struct {
|
|
Blocks []*Block
|
|
}
|
|
|
|
// Block represents an ordered sequence of statements to execute. Blocks are
|
|
// executed until a return statement is encountered, a statement is undefined,
|
|
// or there are no more statements. If all statements are defined but no return
|
|
// statement is encountered, the block is undefined.
|
|
Block struct {
|
|
Stmts []Stmt
|
|
}
|
|
|
|
// Stmt represents an operation (e.g., comparison, loop, dot, etc.) to execute.
|
|
Stmt interface {
|
|
}
|
|
|
|
// Local represents a plan-scoped variable.
|
|
//
|
|
// TODO(tsandall): should this be int32 for safety?
|
|
Local int
|
|
|
|
// Const represents a constant value from the policy.
|
|
Const interface {
|
|
typeMarker()
|
|
}
|
|
|
|
// NullConst represents a null value.
|
|
NullConst struct{}
|
|
|
|
// BooleanConst represents a boolean value.
|
|
BooleanConst struct {
|
|
Value bool
|
|
}
|
|
|
|
// StringConst represents a string value.
|
|
StringConst struct {
|
|
Value string
|
|
}
|
|
|
|
// IntConst represents an integer constant.
|
|
IntConst struct {
|
|
Value int64
|
|
}
|
|
|
|
// FloatConst represents a floating-point constant.
|
|
FloatConst struct {
|
|
Value float64
|
|
}
|
|
)
|
|
|
|
const (
|
|
// Input is the local variable that refers to the global input document.
|
|
Input Local = iota
|
|
|
|
// Data is the local variable that refers to the global data document.
|
|
Data
|
|
|
|
// Unused is the free local variable that can be allocated in a plan.
|
|
Unused
|
|
)
|
|
|
|
func (a *Policy) String() string {
|
|
return "Policy"
|
|
}
|
|
|
|
func (a *Static) String() string {
|
|
return fmt.Sprintf("Static (%d strings)", len(a.Strings))
|
|
}
|
|
|
|
func (a *Funcs) String() string {
|
|
return fmt.Sprintf("Funcs (%d funcs)", len(a.Funcs))
|
|
}
|
|
|
|
func (a *Func) String() string {
|
|
return fmt.Sprintf("%v (%d params: %v, %d blocks)", a.Name, len(a.Params), a.Params, len(a.Blocks))
|
|
}
|
|
|
|
func (a *Plan) String() string {
|
|
return fmt.Sprintf("Plan (%d blocks)", len(a.Blocks))
|
|
}
|
|
|
|
func (a *Block) String() string {
|
|
return fmt.Sprintf("Block (%d statements)", len(a.Stmts))
|
|
}
|
|
|
|
func (a *BooleanConst) typeMarker() {}
|
|
func (a *NullConst) typeMarker() {}
|
|
func (a *IntConst) typeMarker() {}
|
|
func (a *FloatConst) typeMarker() {}
|
|
func (a *StringConst) typeMarker() {}
|
|
|
|
// ReturnLocalStmt represents a return statement that yields a local value.
|
|
type ReturnLocalStmt struct {
|
|
Source Local
|
|
}
|
|
|
|
// CallStmt represents a named function call. The result should be stored in the
|
|
// result local.
|
|
type CallStmt struct {
|
|
Func string
|
|
Args []Local
|
|
Result Local
|
|
}
|
|
|
|
// BlockStmt represents a nested block. Nested blocks and break statements can
|
|
// be used to short-circuit execution.
|
|
type BlockStmt struct {
|
|
Blocks []*Block
|
|
}
|
|
|
|
func (a *BlockStmt) String() string {
|
|
return fmt.Sprintf("BlockStmt (%d blocks)", len(a.Blocks))
|
|
}
|
|
|
|
// BreakStmt represents a jump out of the current block. The index specifies how
|
|
// many blocks to jump starting from zero (the current block). Execution will
|
|
// continue from the end of the block that is jumped to.
|
|
type BreakStmt struct {
|
|
Index uint32
|
|
}
|
|
|
|
// DotStmt represents a lookup operation on a value (e.g., array, object, etc.)
|
|
// The source of a DotStmt may be a scalar value in which case the statement
|
|
// will be undefined.
|
|
type DotStmt struct {
|
|
Source Local
|
|
Key Local
|
|
Target Local
|
|
}
|
|
|
|
// LenStmt represents a length() operation on a local variable. The
|
|
// result is stored in the target local variable.
|
|
type LenStmt struct {
|
|
Source Local
|
|
Target Local
|
|
}
|
|
|
|
// ScanStmt represents a linear scan over a composite value. The
|
|
// source may be a scalar in which case the block will never execute.
|
|
type ScanStmt struct {
|
|
Source Local
|
|
Key Local
|
|
Value Local
|
|
Block *Block
|
|
}
|
|
|
|
// NotStmt represents a negated statement.
|
|
type NotStmt struct {
|
|
Block *Block
|
|
}
|
|
|
|
// AssignBooleanStmt represents an assignment of a boolean value to a local variable.
|
|
type AssignBooleanStmt struct {
|
|
Value bool
|
|
Target Local
|
|
}
|
|
|
|
// AssignIntStmt represents an assignment of an integer value to a
|
|
// local variable.
|
|
type AssignIntStmt struct {
|
|
Value int64
|
|
Target Local
|
|
}
|
|
|
|
// AssignVarStmt represents an assignment of one local variable to another.
|
|
type AssignVarStmt struct {
|
|
Source Local
|
|
Target Local
|
|
}
|
|
|
|
// AssignVarOnceStmt represents an assignment of one local variable to another.
|
|
// If the target is defined, execution aborts with a conflict error.
|
|
//
|
|
// TODO(tsandall): is there a better name for this?
|
|
type AssignVarOnceStmt struct {
|
|
Target Local
|
|
Source Local
|
|
}
|
|
|
|
// MakeStringStmt constructs a local variable that refers to a string constant.
|
|
type MakeStringStmt struct {
|
|
Index int
|
|
Target Local
|
|
}
|
|
|
|
// MakeNullStmt constructs a local variable that refers to a null value.
|
|
type MakeNullStmt struct {
|
|
Target Local
|
|
}
|
|
|
|
// MakeBooleanStmt constructs a local variable that refers to a boolean value.
|
|
type MakeBooleanStmt struct {
|
|
Value bool
|
|
Target Local
|
|
}
|
|
|
|
// MakeNumberFloatStmt constructs a local variable that refers to a
|
|
// floating-point number value.
|
|
type MakeNumberFloatStmt struct {
|
|
Value float64
|
|
Target Local
|
|
}
|
|
|
|
// MakeNumberIntStmt constructs a local variable that refers to an integer value.
|
|
type MakeNumberIntStmt struct {
|
|
Value int64
|
|
Target Local
|
|
}
|
|
|
|
// MakeNumberRefStmt constructs a local variable that refers to a number stored as a string.
|
|
type MakeNumberRefStmt struct {
|
|
Index int
|
|
Target Local
|
|
}
|
|
|
|
// MakeArrayStmt constructs a local variable that refers to an array value.
|
|
type MakeArrayStmt struct {
|
|
Capacity int32
|
|
Target Local
|
|
}
|
|
|
|
// MakeObjectStmt constructs a local variable that refers to an object value.
|
|
type MakeObjectStmt struct {
|
|
Target Local
|
|
}
|
|
|
|
// MakeSetStmt constructs a local variable that refers to a set value.
|
|
type MakeSetStmt struct {
|
|
Target Local
|
|
}
|
|
|
|
// EqualStmt represents an value-equality check of two local variables.
|
|
type EqualStmt struct {
|
|
A Local
|
|
B Local
|
|
}
|
|
|
|
// LessThanStmt represents a < check of two local variables.
|
|
type LessThanStmt struct {
|
|
A Local
|
|
B Local
|
|
}
|
|
|
|
// LessThanEqualStmt represents a <= check of two local variables.
|
|
type LessThanEqualStmt struct {
|
|
A Local
|
|
B Local
|
|
}
|
|
|
|
// GreaterThanStmt represents a > check of two local variables.
|
|
type GreaterThanStmt struct {
|
|
A Local
|
|
B Local
|
|
}
|
|
|
|
// GreaterThanEqualStmt represents a >= check of two local variables.
|
|
type GreaterThanEqualStmt struct {
|
|
A Local
|
|
B Local
|
|
}
|
|
|
|
// NotEqualStmt represents a != check of two local variables.
|
|
type NotEqualStmt struct {
|
|
A Local
|
|
B Local
|
|
}
|
|
|
|
// IsArrayStmt represents a dynamic type check on a local variable.
|
|
type IsArrayStmt struct {
|
|
Source Local
|
|
}
|
|
|
|
// IsObjectStmt represents a dynamic type check on a local variable.
|
|
type IsObjectStmt struct {
|
|
Source Local
|
|
}
|
|
|
|
// IsDefinedStmt represents a check of whether a local variable is defined.
|
|
type IsDefinedStmt struct {
|
|
Source Local
|
|
}
|
|
|
|
// IsUndefinedStmt represents a check of whether local variable is undefined.
|
|
type IsUndefinedStmt struct {
|
|
Source Local
|
|
}
|
|
|
|
// ArrayAppendStmt represents a dynamic append operation of a value
|
|
// onto an array.
|
|
type ArrayAppendStmt struct {
|
|
Value Local
|
|
Array Local
|
|
}
|
|
|
|
// ObjectInsertStmt represents a dynamic insert operation of a
|
|
// key/value pair into an object.
|
|
type ObjectInsertStmt struct {
|
|
Key Local
|
|
Value Local
|
|
Object Local
|
|
}
|
|
|
|
// ObjectInsertOnceStmt represents a dynamic insert operation of a key/value
|
|
// pair into an object. If the key already exists and the value differs,
|
|
// execution aborts with a conflict error.
|
|
type ObjectInsertOnceStmt struct {
|
|
Key Local
|
|
Value Local
|
|
Object Local
|
|
}
|
|
|
|
// ObjectMergeStmt performs a recursive merge of two object values. If either of
|
|
// the locals refer to non-object values this operation will abort with a
|
|
// conflict error. Overlapping object keys are merged recursively.
|
|
type ObjectMergeStmt struct {
|
|
A Local
|
|
B Local
|
|
Target Local
|
|
}
|
|
|
|
// SetAddStmt represents a dynamic add operation of an element into a set.
|
|
type SetAddStmt struct {
|
|
Value Local
|
|
Set Local
|
|
}
|
|
|
|
// WithStmt replaces the Local or a portion of the document referred to by the
|
|
// Local with the Value and executes the contained block. If the Path is
|
|
// non-empty, the Value is upserted into the Local. If the intermediate nodes in
|
|
// the Local referred to by the Path do not exist, they will be created. When
|
|
// the WithStmt finishes the Local is reset to it's original value.
|
|
type WithStmt struct {
|
|
Local Local
|
|
Path []int
|
|
Value Local
|
|
Block *Block
|
|
}
|
|
|
|
// ResultSetAdd adds a value into the result set returned by the query plan.
|
|
type ResultSetAdd struct {
|
|
Value Local
|
|
}
|