Documentation ¶
Overview ¶
Package parser declares an expression parser with support for macro expansion.
Index ¶
- Constants
- Variables
- func MakeAll(eh ExprHelper, target ast.Expr, args []ast.Expr) (ast.Expr, *common.Error)
- func MakeExists(eh ExprHelper, target ast.Expr, args []ast.Expr) (ast.Expr, *common.Error)
- func MakeExistsOne(eh ExprHelper, target ast.Expr, args []ast.Expr) (ast.Expr, *common.Error)
- func MakeFilter(eh ExprHelper, target ast.Expr, args []ast.Expr) (ast.Expr, *common.Error)
- func MakeHas(eh ExprHelper, target ast.Expr, args []ast.Expr) (ast.Expr, *common.Error)
- func MakeMap(eh ExprHelper, target ast.Expr, args []ast.Expr) (ast.Expr, *common.Error)
- func Parse(source common.Source) (*ast.AST, *common.Errors)deprecated
- func Unparse(expr ast.Expr, info *ast.SourceInfo, opts ...UnparserOption) (string, error)
- type ExprHelper
- type Macro
- func NewGlobalMacro(function string, argCount int, expander MacroExpander) Macro
- func NewGlobalVarArgMacro(function string, expander MacroExpander) Macro
- func NewReceiverMacro(function string, argCount int, expander MacroExpander) Macro
- func NewReceiverVarArgMacro(function string, expander MacroExpander) Macro
- type MacroExpander
- type Option
- func EnableOptionalSyntax(optionalSyntax bool) Option
- func EnableVariadicOperatorASTs(varArgASTs bool) Option
- func ErrorRecoveryLimit(limit int) Option
- func ErrorRecoveryLookaheadTokenLimit(limit int) Option
- func ErrorReportingLimit(limit int) Option
- func ExpressionSizeCodePointLimit(expressionSizeCodePointLimit int) Option
- func Macros(macros ...Macro) Option
- func MaxRecursionDepth(limit int) Option
- func PopulateMacroCalls(populateMacroCalls bool) Option
- type Parser
- type UnparserOption
Constants ¶
const AccumulatorName = "__result__"
AccumulatorName is the traditional variable name assigned to the fold accumulator variable.
Variables ¶
var ( // HasMacro expands "has(m.f)" which tests the presence of a field, avoiding the need to // specify the field as a string. HasMacro = NewGlobalMacro(operators.Has, 1, MakeHas) // AllMacro expands "range.all(var, predicate)" into a comprehension which ensures that all // elements in the range satisfy the predicate. AllMacro = NewReceiverMacro(operators.All, 2, MakeAll) // ExistsMacro expands "range.exists(var, predicate)" into a comprehension which ensures that // some element in the range satisfies the predicate. ExistsMacro = NewReceiverMacro(operators.Exists, 2, MakeExists) // ExistsOneMacro expands "range.exists_one(var, predicate)", which is true if for exactly one // element in range the predicate holds. ExistsOneMacro = NewReceiverMacro(operators.ExistsOne, 2, MakeExistsOne) // MapMacro expands "range.map(var, function)" into a comprehension which applies the function // to each element in the range to produce a new list. MapMacro = NewReceiverMacro(operators.Map, 2, MakeMap) // MapFilterMacro expands "range.map(var, predicate, function)" into a comprehension which // first filters the elements in the range by the predicate, then applies the transform function // to produce a new list. MapFilterMacro = NewReceiverMacro(operators.Map, 3, MakeMap) // FilterMacro expands "range.filter(var, predicate)" into a comprehension which filters // elements in the range, producing a new list from the elements that satisfy the predicate. FilterMacro = NewReceiverMacro(operators.Filter, 2, MakeFilter) // AllMacros includes the list of all spec-supported macros. AllMacros = []Macro{ HasMacro, AllMacro, ExistsMacro, ExistsOneMacro, MapMacro, MapFilterMacro, FilterMacro, } // NoMacros list. NoMacros = []Macro{} )
Functions ¶
func MakeAll ¶ added in v0.12.0
MakeAll expands the input call arguments into a comprehension that returns true if all of the elements in the range match the predicate expressions: <iterRange>.all(<iterVar>, <predicate>)
func MakeExists ¶ added in v0.12.0
MakeExists expands the input call arguments into a comprehension that returns true if any of the elements in the range match the predicate expressions: <iterRange>.exists(<iterVar>, <predicate>)
func MakeExistsOne ¶ added in v0.12.0
MakeExistsOne expands the input call arguments into a comprehension that returns true if exactly one of the elements in the range match the predicate expressions: <iterRange>.exists_one(<iterVar>, <predicate>)
func MakeFilter ¶ added in v0.12.0
MakeFilter expands the input call arguments into a comprehension which produces a list which contains only elements which match the provided predicate expression: <iterRange>.filter(<iterVar>, <predicate>)
func MakeHas ¶ added in v0.12.0
MakeHas expands the input call arguments into a presence test, e.g. has(<operand>.field)
func MakeMap ¶ added in v0.12.0
MakeMap expands the input call arguments into a comprehension that transforms each element in the input to produce an output list.
There are two call patterns supported by map:
<iterRange>.map(<iterVar>, <transform>) <iterRange>.map(<iterVar>, <predicate>, <transform>)
In the second form only iterVar values which return true when provided to the predicate expression are transformed.
func Unparse ¶ added in v0.3.0
func Unparse(expr ast.Expr, info *ast.SourceInfo, opts ...UnparserOption) (string, error)
Unparse takes an input expression and source position information and generates a human-readable expression.
Note, unparsing an AST will often generate the same expression as was originally parsed, but some formatting may be lost in translation, notably:
- All quoted literals are doubled quoted. - Byte literals are represented as octal escapes (same as Google SQL). - Floating point values are converted to the small number of digits needed to represent the value. - Spacing around punctuation marks may be lost. - Parentheses will only be applied when they affect operator precedence.
This function optionally takes in one or more UnparserOption to alter the unparsing behavior, such as performing word wrapping on expressions.
Types ¶
type ExprHelper ¶
type ExprHelper interface { // Copy the input expression with a brand new set of identifiers. Copy(ast.Expr) ast.Expr // Literal creates an Expr value for a scalar literal value. NewLiteral(value ref.Val) ast.Expr // NewList creates a list literal instruction with an optional set of elements. NewList(elems ...ast.Expr) ast.Expr // NewMap creates a CreateStruct instruction for a map where the map is comprised of the // optional set of key, value entries. NewMap(entries ...ast.EntryExpr) ast.Expr // NewMapEntry creates a Map Entry for the key, value pair. NewMapEntry(key ast.Expr, val ast.Expr, optional bool) ast.EntryExpr // NewStruct creates a struct literal expression with an optional set of field initializers. NewStruct(typeName string, fieldInits ...ast.EntryExpr) ast.Expr // NewStructField creates a new struct field initializer from the field name and value. NewStructField(field string, init ast.Expr, optional bool) ast.EntryExpr // NewComprehension creates a new comprehension instruction. // // - iterRange represents the expression that resolves to a list or map where the elements or // keys (respectively) will be iterated over. // - iterVar is the iteration variable name. // - accuVar is the accumulation variable name, typically parser.AccumulatorName. // - accuInit is the initial expression whose value will be set for the accuVar prior to // folding. // - condition is the expression to test to determine whether to continue folding. // - step is the expression to evaluation at the conclusion of a single fold iteration. // - result is the computation to evaluate at the conclusion of the fold. // // The accuVar should not shadow variable names that you would like to reference within the // environment in the step and condition expressions. Presently, the name __result__ is commonly // used by built-in macros but this may change in the future. NewComprehension(iterRange ast.Expr, iterVar string, accuVar string, accuInit ast.Expr, condition ast.Expr, step ast.Expr, result ast.Expr) ast.Expr // NewIdent creates an identifier Expr value. NewIdent(name string) ast.Expr // NewAccuIdent returns an accumulator identifier for use with comprehension results. NewAccuIdent() ast.Expr // NewCall creates a function call Expr value for a global (free) function. NewCall(function string, args ...ast.Expr) ast.Expr // NewMemberCall creates a function call Expr value for a receiver-style function. NewMemberCall(function string, target ast.Expr, args ...ast.Expr) ast.Expr // NewPresenceTest creates a Select TestOnly Expr value for modelling has() semantics. NewPresenceTest(operand ast.Expr, field string) ast.Expr // NewSelect create a field traversal Expr value. NewSelect(operand ast.Expr, field string) ast.Expr // OffsetLocation returns the Location of the expression identifier. OffsetLocation(exprID int64) common.Location // NewError associates an error message with a given expression id. NewError(exprID int64, message string) *common.Error }
ExprHelper assists with the creation of Expr values in a manner which is consistent the internal semantics and id generation behaviors of the parser and checker libraries.
type Macro ¶
type Macro interface { // Function name to match. Function() string // ArgCount for the function call. // // When the macro is a var-arg style macro, the return value will be zero, but the MacroKey // will contain a `*` where the arg count would have been. ArgCount() int // IsReceiverStyle returns true if the macro matches a receiver style call. IsReceiverStyle() bool // MacroKey returns the macro signatures accepted by this macro. // // Format: `<function>:<arg-count>:<is-receiver>`. // // When the macros is a var-arg style macro, the `arg-count` value is represented as a `*`. MacroKey() string // Expander returns the MacroExpander to apply when the macro key matches the parsed call // signature. Expander() MacroExpander }
Macro interface for describing the function signature to match and the MacroExpander to apply.
Note: when a Macro should apply to multiple overloads (based on arg count) of a given function, a Macro should be created per arg-count.
func NewGlobalMacro ¶
func NewGlobalMacro(function string, argCount int, expander MacroExpander) Macro
NewGlobalMacro creates a Macro for a global function with the specified arg count.
func NewGlobalVarArgMacro ¶
func NewGlobalVarArgMacro(function string, expander MacroExpander) Macro
NewGlobalVarArgMacro creates a Macro for a global function with a variable arg count.
func NewReceiverMacro ¶
func NewReceiverMacro(function string, argCount int, expander MacroExpander) Macro
NewReceiverMacro creates a Macro for a receiver function matching the specified arg count.
func NewReceiverVarArgMacro ¶
func NewReceiverVarArgMacro(function string, expander MacroExpander) Macro
NewReceiverVarArgMacro creates a Macro for a receiver function matching a variable arg count.
type MacroExpander ¶
MacroExpander converts a call and its associated arguments into a new CEL abstract syntax tree.
If the MacroExpander determines within the implementation that an expansion is not needed it may return a nil Expr value to indicate a non-match. However, if an expansion is to be performed, but the arguments are not well-formed, the result of the expansion will be an error.
The MacroExpander accepts as arguments a MacroExprHelper as well as the arguments used in the function call and produces as output an Expr ast node.
Note: when the Macro.IsReceiverStyle() method returns true, the target argument will be nil.
type Option ¶ added in v0.8.0
type Option func(*options) error
Option configures the behavior of the parser.
func EnableOptionalSyntax ¶ added in v0.13.0
EnableOptionalSyntax enables syntax for optional field and index selection.
func EnableVariadicOperatorASTs ¶ added in v0.17.0
EnableVariadicOperatorASTs enables a compact representation of chained like-kind commutative operators. e.g. `a || b || c || d` -> `call(op='||', args=[a, b, c, d])`
The benefit of enabling variadic operators ASTs is a more compact representation deeply nested logic graphs.
func ErrorRecoveryLimit ¶ added in v0.8.0
ErrorRecoveryLimit limits the number of attempts the parser will perform to recover from an error.
func ErrorRecoveryLookaheadTokenLimit ¶ added in v0.8.0
ErrorRecoveryLookaheadTokenLimit limits the number of lexer tokens that may be considered during error recovery.
Error recovery often involves looking ahead in the input to determine if there's a point at which parsing may successfully resume. In some pathological cases, the parser can look through quite a large set of input which in turn generates a lot of back-tracking and performance degredation.
The limit must be >= 1, and is recommended to be less than the default of 256.
func ErrorReportingLimit ¶ added in v0.15.0
ErrorReportingLimit limits the number of syntax error reports before terminating parsing.
The limit must be at least 1. If unset, the limit will be 100.
func ExpressionSizeCodePointLimit ¶ added in v0.8.0
ExpressionSizeCodePointLimit is an option which limits the maximum code point count of an expression.
func MaxRecursionDepth ¶ added in v0.8.0
MaxRecursionDepth limits the maximum depth the parser will attempt to parse the expression before giving up.
func PopulateMacroCalls ¶ added in v0.9.0
PopulateMacroCalls ensures that the original call signatures replaced by expanded macros are preserved in the `SourceInfo` of parse result.
type Parser ¶ added in v0.8.0
type Parser struct {
// contains filtered or unexported fields
}
Parser encapsulates the context necessary to perform parsing for different expressions.
type UnparserOption ¶ added in v0.12.2
type UnparserOption func(*unparserOption) (*unparserOption, error)
UnparserOption is a functional option for configuring the output formatting of the Unparse function.
func WrapAfterColumnLimit ¶ added in v0.12.2
func WrapAfterColumnLimit(wrapAfter bool) UnparserOption
WrapAfterColumnLimit dictates whether to insert a newline before or after the specified operator when word wrapping is performed.
Example usage:
Unparse(expr, sourceInfo, WrapOnColumn(40), WrapOnOperators(Operators.LogicalAnd), WrapAfterColumnLimit(false))
This will insert a newline immediately before the logical AND operator for the below example input, ensuring that the length of a line never exceeds the specified column limit:
Input: 'my-principal-group' in request.auth.claims && request.auth.claims.iat > now - duration('5m')
Output: 'my-principal-group' in request.auth.claims && request.auth.claims.iat > now - duration('5m')
func WrapOnColumn ¶ added in v0.12.2
func WrapOnColumn(col int) UnparserOption
WrapOnColumn wraps the output expression when its string length exceeds a specified limit for operators set by WrapOnOperators function or by default, "&&" and "||" will be wrapped.
Example usage:
Unparse(expr, sourceInfo, WrapOnColumn(40), WrapOnOperators(Operators.LogicalAnd))
This will insert a newline immediately after the logical AND operator for the below example input:
Input: 'my-principal-group' in request.auth.claims && request.auth.claims.iat > now - duration('5m')
Output: 'my-principal-group' in request.auth.claims && request.auth.claims.iat > now - duration('5m')
func WrapOnOperators ¶ added in v0.12.2
func WrapOnOperators(symbols ...string) UnparserOption
WrapOnOperators specifies which operators to perform word wrapping on an output expression when its string length exceeds the column limit set by WrapOnColumn function.
Word wrapping is supported on non-unary symbolic operators. Refer to operators.go for the full list
This will replace any previously supplied operators instead of merging them.