| // Copyright 2022 Google LLC |
| // |
| // Licensed under the Apache License, Version 2.0 (the "License"); |
| // you may not use this file except in compliance with the License. |
| // You may obtain a copy of the License at |
| // |
| // http://www.apache.org/licenses/LICENSE-2.0 |
| // |
| // Unless required by applicable law or agreed to in writing, software |
| // distributed under the License is distributed on an "AS IS" BASIS, |
| // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. |
| // See the License for the specific language governing permissions and |
| // limitations under the License. |
| |
| package cel |
| |
| import ( |
| "fmt" |
| |
| "github.com/google/cel-go/common" |
| "github.com/google/cel-go/common/ast" |
| "github.com/google/cel-go/common/types" |
| "github.com/google/cel-go/parser" |
| |
| exprpb "google.golang.org/genproto/googleapis/api/expr/v1alpha1" |
| ) |
| |
| // Macro describes a 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 or as a var arg macro. |
| type Macro = parser.Macro |
| |
| // MacroFactory defines an expansion function which converts a call and its arguments to a cel.Expr value. |
| type MacroFactory = parser.MacroExpander |
| |
| // MacroExprFactory 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 MacroExprFactory = parser.ExprHelper |
| |
| // MacroExpander converts a call and its associated arguments into a protobuf Expr representation. |
| // |
| // 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 MacroExpander func(eh MacroExprHelper, target *exprpb.Expr, args []*exprpb.Expr) (*exprpb.Expr, *Error) |
| |
| // MacroExprHelper exposes helper methods for creating new expressions within a CEL abstract syntax tree. |
| // ExprHelper assists with the manipulation of proto-based Expr values in a manner which is |
| // consistent with the source position and expression id generation code leveraged by both |
| // the parser and type-checker. |
| type MacroExprHelper interface { |
| // Copy the input expression with a brand new set of identifiers. |
| Copy(*exprpb.Expr) *exprpb.Expr |
| |
| // LiteralBool creates an Expr value for a bool literal. |
| LiteralBool(value bool) *exprpb.Expr |
| |
| // LiteralBytes creates an Expr value for a byte literal. |
| LiteralBytes(value []byte) *exprpb.Expr |
| |
| // LiteralDouble creates an Expr value for double literal. |
| LiteralDouble(value float64) *exprpb.Expr |
| |
| // LiteralInt creates an Expr value for an int literal. |
| LiteralInt(value int64) *exprpb.Expr |
| |
| // LiteralString creates am Expr value for a string literal. |
| LiteralString(value string) *exprpb.Expr |
| |
| // LiteralUint creates an Expr value for a uint literal. |
| LiteralUint(value uint64) *exprpb.Expr |
| |
| // NewList creates a CreateList instruction where the list is comprised of the optional set |
| // of elements provided as arguments. |
| NewList(elems ...*exprpb.Expr) *exprpb.Expr |
| |
| // NewMap creates a CreateStruct instruction for a map where the map is comprised of the |
| // optional set of key, value entries. |
| NewMap(entries ...*exprpb.Expr_CreateStruct_Entry) *exprpb.Expr |
| |
| // NewMapEntry creates a Map Entry for the key, value pair. |
| NewMapEntry(key *exprpb.Expr, val *exprpb.Expr, optional bool) *exprpb.Expr_CreateStruct_Entry |
| |
| // NewObject creates a CreateStruct instruction for an object with a given type name and |
| // optional set of field initializers. |
| NewObject(typeName string, fieldInits ...*exprpb.Expr_CreateStruct_Entry) *exprpb.Expr |
| |
| // NewObjectFieldInit creates a new Object field initializer from the field name and value. |
| NewObjectFieldInit(field string, init *exprpb.Expr, optional bool) *exprpb.Expr_CreateStruct_Entry |
| |
| // Fold creates a fold comprehension instruction. |
| // |
| // - iterVar is the iteration variable name. |
| // - iterRange represents the expression that resolves to a list or map where the elements or |
| // keys (respectively) will be iterated over. |
| // - 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. |
| Fold(iterVar string, |
| iterRange *exprpb.Expr, |
| accuVar string, |
| accuInit *exprpb.Expr, |
| condition *exprpb.Expr, |
| step *exprpb.Expr, |
| result *exprpb.Expr) *exprpb.Expr |
| |
| // Ident creates an identifier Expr value. |
| Ident(name string) *exprpb.Expr |
| |
| // AccuIdent returns an accumulator identifier for use with comprehension results. |
| AccuIdent() *exprpb.Expr |
| |
| // GlobalCall creates a function call Expr value for a global (free) function. |
| GlobalCall(function string, args ...*exprpb.Expr) *exprpb.Expr |
| |
| // ReceiverCall creates a function call Expr value for a receiver-style function. |
| ReceiverCall(function string, target *exprpb.Expr, args ...*exprpb.Expr) *exprpb.Expr |
| |
| // PresenceTest creates a Select TestOnly Expr value for modelling has() semantics. |
| PresenceTest(operand *exprpb.Expr, field string) *exprpb.Expr |
| |
| // Select create a field traversal Expr value. |
| Select(operand *exprpb.Expr, field string) *exprpb.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) *Error |
| } |
| |
| // MacroOpt defines a functional option for configuring macro behavior. |
| type MacroOpt = parser.MacroOpt |
| |
| // MacroDocs configures a list of strings into a multiline description for the macro. |
| func MacroDocs(docs ...string) MacroOpt { |
| return parser.MacroDocs(docs...) |
| } |
| |
| // MacroExamples configures a list of examples, either as a string or common.MultilineString, |
| // into an example set to be provided with the macro Documentation() call. |
| func MacroExamples(examples ...string) MacroOpt { |
| return parser.MacroExamples(examples...) |
| } |
| |
| // GlobalMacro creates a Macro for a global function with the specified arg count. |
| func GlobalMacro(function string, argCount int, factory MacroFactory, opts ...MacroOpt) Macro { |
| return parser.NewGlobalMacro(function, argCount, factory, opts...) |
| } |
| |
| // ReceiverMacro creates a Macro for a receiver function matching the specified arg count. |
| func ReceiverMacro(function string, argCount int, factory MacroFactory, opts ...MacroOpt) Macro { |
| return parser.NewReceiverMacro(function, argCount, factory, opts...) |
| } |
| |
| // GlobalVarArgMacro creates a Macro for a global function with a variable arg count. |
| func GlobalVarArgMacro(function string, factory MacroFactory, opts ...MacroOpt) Macro { |
| return parser.NewGlobalVarArgMacro(function, factory, opts...) |
| } |
| |
| // ReceiverVarArgMacro creates a Macro for a receiver function matching a variable arg count. |
| func ReceiverVarArgMacro(function string, factory MacroFactory, opts ...MacroOpt) Macro { |
| return parser.NewReceiverVarArgMacro(function, factory, opts...) |
| } |
| |
| // NewGlobalMacro creates a Macro for a global function with the specified arg count. |
| // |
| // Deprecated: use GlobalMacro |
| func NewGlobalMacro(function string, argCount int, expander MacroExpander) Macro { |
| expand := adaptingExpander{expander} |
| return parser.NewGlobalMacro(function, argCount, expand.Expander) |
| } |
| |
| // NewReceiverMacro creates a Macro for a receiver function matching the specified arg count. |
| // |
| // Deprecated: use ReceiverMacro |
| func NewReceiverMacro(function string, argCount int, expander MacroExpander) Macro { |
| expand := adaptingExpander{expander} |
| return parser.NewReceiverMacro(function, argCount, expand.Expander) |
| } |
| |
| // NewGlobalVarArgMacro creates a Macro for a global function with a variable arg count. |
| // |
| // Deprecated: use GlobalVarArgMacro |
| func NewGlobalVarArgMacro(function string, expander MacroExpander) Macro { |
| expand := adaptingExpander{expander} |
| return parser.NewGlobalVarArgMacro(function, expand.Expander) |
| } |
| |
| // NewReceiverVarArgMacro creates a Macro for a receiver function matching a variable arg count. |
| // |
| // Deprecated: use ReceiverVarArgMacro |
| func NewReceiverVarArgMacro(function string, expander MacroExpander) Macro { |
| expand := adaptingExpander{expander} |
| return parser.NewReceiverVarArgMacro(function, expand.Expander) |
| } |
| |
| // HasMacroExpander expands the input call arguments into a presence test, e.g. has(<operand>.field) |
| func HasMacroExpander(meh MacroExprHelper, target *exprpb.Expr, args []*exprpb.Expr) (*exprpb.Expr, *Error) { |
| ph, err := toParserHelper(meh) |
| if err != nil { |
| return nil, err |
| } |
| arg, err := adaptToExpr(args[0]) |
| if err != nil { |
| return nil, err |
| } |
| if arg.Kind() == ast.SelectKind { |
| s := arg.AsSelect() |
| return adaptToProto(ph.NewPresenceTest(s.Operand(), s.FieldName())) |
| } |
| return nil, ph.NewError(arg.ID(), "invalid argument to has() macro") |
| } |
| |
| // ExistsMacroExpander 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 ExistsMacroExpander(meh MacroExprHelper, target *exprpb.Expr, args []*exprpb.Expr) (*exprpb.Expr, *Error) { |
| ph, err := toParserHelper(meh) |
| if err != nil { |
| return nil, err |
| } |
| out, err := parser.MakeExists(ph, mustAdaptToExpr(target), mustAdaptToExprs(args)) |
| if err != nil { |
| return nil, err |
| } |
| return adaptToProto(out) |
| } |
| |
| // ExistsOneMacroExpander 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 ExistsOneMacroExpander(meh MacroExprHelper, target *exprpb.Expr, args []*exprpb.Expr) (*exprpb.Expr, *Error) { |
| ph, err := toParserHelper(meh) |
| if err != nil { |
| return nil, err |
| } |
| out, err := parser.MakeExistsOne(ph, mustAdaptToExpr(target), mustAdaptToExprs(args)) |
| if err != nil { |
| return nil, err |
| } |
| return adaptToProto(out) |
| } |
| |
| // MapMacroExpander 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 MapMacroExpander(meh MacroExprHelper, target *exprpb.Expr, args []*exprpb.Expr) (*exprpb.Expr, *Error) { |
| ph, err := toParserHelper(meh) |
| if err != nil { |
| return nil, err |
| } |
| out, err := parser.MakeMap(ph, mustAdaptToExpr(target), mustAdaptToExprs(args)) |
| if err != nil { |
| return nil, err |
| } |
| return adaptToProto(out) |
| } |
| |
| // FilterMacroExpander 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 FilterMacroExpander(meh MacroExprHelper, target *exprpb.Expr, args []*exprpb.Expr) (*exprpb.Expr, *Error) { |
| ph, err := toParserHelper(meh) |
| if err != nil { |
| return nil, err |
| } |
| out, err := parser.MakeFilter(ph, mustAdaptToExpr(target), mustAdaptToExprs(args)) |
| if err != nil { |
| return nil, err |
| } |
| return adaptToProto(out) |
| } |
| |
| var ( |
| // Aliases to each macro in the CEL standard environment. |
| // Note: reassigning these macro variables may result in undefined behavior. |
| |
| // HasMacro expands "has(m.f)" which tests the presence of a field, avoiding the need to |
| // specify the field as a string. |
| HasMacro = parser.HasMacro |
| |
| // AllMacro expands "range.all(var, predicate)" into a comprehension which ensures that all |
| // elements in the range satisfy the predicate. |
| AllMacro = parser.AllMacro |
| |
| // ExistsMacro expands "range.exists(var, predicate)" into a comprehension which ensures that |
| // some element in the range satisfies the predicate. |
| ExistsMacro = parser.ExistsMacro |
| |
| // ExistsOneMacro expands "range.exists_one(var, predicate)", which is true if for exactly one |
| // element in range the predicate holds. |
| ExistsOneMacro = parser.ExistsOneMacro |
| |
| // 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 = parser.MapMacro |
| |
| // 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 = parser.MapFilterMacro |
| |
| // 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 = parser.FilterMacro |
| |
| // StandardMacros provides an alias to all the CEL macros defined in the standard environment. |
| StandardMacros = []Macro{ |
| HasMacro, AllMacro, ExistsMacro, ExistsOneMacro, MapMacro, MapFilterMacro, FilterMacro, |
| } |
| |
| // NoMacros provides an alias to an empty list of macros |
| NoMacros = []Macro{} |
| ) |
| |
| type adaptingExpander struct { |
| legacyExpander MacroExpander |
| } |
| |
| func (adapt *adaptingExpander) Expander(eh parser.ExprHelper, target ast.Expr, args []ast.Expr) (ast.Expr, *common.Error) { |
| var legacyTarget *exprpb.Expr = nil |
| var err *Error = nil |
| if target != nil { |
| legacyTarget, err = adaptToProto(target) |
| if err != nil { |
| return nil, err |
| } |
| } |
| legacyArgs := make([]*exprpb.Expr, len(args)) |
| for i, arg := range args { |
| legacyArgs[i], err = adaptToProto(arg) |
| if err != nil { |
| return nil, err |
| } |
| } |
| ah := &adaptingHelper{modernHelper: eh} |
| legacyExpr, err := adapt.legacyExpander(ah, legacyTarget, legacyArgs) |
| if err != nil { |
| return nil, err |
| } |
| ex, err := adaptToExpr(legacyExpr) |
| if err != nil { |
| return nil, err |
| } |
| return ex, nil |
| } |
| |
| func wrapErr(id int64, message string, err error) *common.Error { |
| return &common.Error{ |
| Location: common.NoLocation, |
| Message: fmt.Sprintf("%s: %v", message, err), |
| ExprID: id, |
| } |
| } |
| |
| type adaptingHelper struct { |
| modernHelper parser.ExprHelper |
| } |
| |
| // Copy the input expression with a brand new set of identifiers. |
| func (ah *adaptingHelper) Copy(e *exprpb.Expr) *exprpb.Expr { |
| return mustAdaptToProto(ah.modernHelper.Copy(mustAdaptToExpr(e))) |
| } |
| |
| // LiteralBool creates an Expr value for a bool literal. |
| func (ah *adaptingHelper) LiteralBool(value bool) *exprpb.Expr { |
| return mustAdaptToProto(ah.modernHelper.NewLiteral(types.Bool(value))) |
| } |
| |
| // LiteralBytes creates an Expr value for a byte literal. |
| func (ah *adaptingHelper) LiteralBytes(value []byte) *exprpb.Expr { |
| return mustAdaptToProto(ah.modernHelper.NewLiteral(types.Bytes(value))) |
| } |
| |
| // LiteralDouble creates an Expr value for double literal. |
| func (ah *adaptingHelper) LiteralDouble(value float64) *exprpb.Expr { |
| return mustAdaptToProto(ah.modernHelper.NewLiteral(types.Double(value))) |
| } |
| |
| // LiteralInt creates an Expr value for an int literal. |
| func (ah *adaptingHelper) LiteralInt(value int64) *exprpb.Expr { |
| return mustAdaptToProto(ah.modernHelper.NewLiteral(types.Int(value))) |
| } |
| |
| // LiteralString creates am Expr value for a string literal. |
| func (ah *adaptingHelper) LiteralString(value string) *exprpb.Expr { |
| return mustAdaptToProto(ah.modernHelper.NewLiteral(types.String(value))) |
| } |
| |
| // LiteralUint creates an Expr value for a uint literal. |
| func (ah *adaptingHelper) LiteralUint(value uint64) *exprpb.Expr { |
| return mustAdaptToProto(ah.modernHelper.NewLiteral(types.Uint(value))) |
| } |
| |
| // NewList creates a CreateList instruction where the list is comprised of the optional set |
| // of elements provided as arguments. |
| func (ah *adaptingHelper) NewList(elems ...*exprpb.Expr) *exprpb.Expr { |
| return mustAdaptToProto(ah.modernHelper.NewList(mustAdaptToExprs(elems)...)) |
| } |
| |
| // NewMap creates a CreateStruct instruction for a map where the map is comprised of the |
| // optional set of key, value entries. |
| func (ah *adaptingHelper) NewMap(entries ...*exprpb.Expr_CreateStruct_Entry) *exprpb.Expr { |
| adaptedEntries := make([]ast.EntryExpr, len(entries)) |
| for i, e := range entries { |
| adaptedEntries[i] = mustAdaptToEntryExpr(e) |
| } |
| return mustAdaptToProto(ah.modernHelper.NewMap(adaptedEntries...)) |
| } |
| |
| // NewMapEntry creates a Map Entry for the key, value pair. |
| func (ah *adaptingHelper) NewMapEntry(key *exprpb.Expr, val *exprpb.Expr, optional bool) *exprpb.Expr_CreateStruct_Entry { |
| return mustAdaptToProtoEntry( |
| ah.modernHelper.NewMapEntry(mustAdaptToExpr(key), mustAdaptToExpr(val), optional)) |
| } |
| |
| // NewObject creates a CreateStruct instruction for an object with a given type name and |
| // optional set of field initializers. |
| func (ah *adaptingHelper) NewObject(typeName string, fieldInits ...*exprpb.Expr_CreateStruct_Entry) *exprpb.Expr { |
| adaptedEntries := make([]ast.EntryExpr, len(fieldInits)) |
| for i, e := range fieldInits { |
| adaptedEntries[i] = mustAdaptToEntryExpr(e) |
| } |
| return mustAdaptToProto(ah.modernHelper.NewStruct(typeName, adaptedEntries...)) |
| } |
| |
| // NewObjectFieldInit creates a new Object field initializer from the field name and value. |
| func (ah *adaptingHelper) NewObjectFieldInit(field string, init *exprpb.Expr, optional bool) *exprpb.Expr_CreateStruct_Entry { |
| return mustAdaptToProtoEntry( |
| ah.modernHelper.NewStructField(field, mustAdaptToExpr(init), optional)) |
| } |
| |
| // Fold creates a fold comprehension instruction. |
| // |
| // - iterVar is the iteration variable name. |
| // - iterRange represents the expression that resolves to a list or map where the elements or |
| // keys (respectively) will be iterated over. |
| // - 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. |
| func (ah *adaptingHelper) Fold(iterVar string, |
| iterRange *exprpb.Expr, |
| accuVar string, |
| accuInit *exprpb.Expr, |
| condition *exprpb.Expr, |
| step *exprpb.Expr, |
| result *exprpb.Expr) *exprpb.Expr { |
| return mustAdaptToProto( |
| ah.modernHelper.NewComprehension( |
| mustAdaptToExpr(iterRange), |
| iterVar, |
| accuVar, |
| mustAdaptToExpr(accuInit), |
| mustAdaptToExpr(condition), |
| mustAdaptToExpr(step), |
| mustAdaptToExpr(result), |
| ), |
| ) |
| } |
| |
| // Ident creates an identifier Expr value. |
| func (ah *adaptingHelper) Ident(name string) *exprpb.Expr { |
| return mustAdaptToProto(ah.modernHelper.NewIdent(name)) |
| } |
| |
| // AccuIdent returns an accumulator identifier for use with comprehension results. |
| func (ah *adaptingHelper) AccuIdent() *exprpb.Expr { |
| return mustAdaptToProto(ah.modernHelper.NewAccuIdent()) |
| } |
| |
| // GlobalCall creates a function call Expr value for a global (free) function. |
| func (ah *adaptingHelper) GlobalCall(function string, args ...*exprpb.Expr) *exprpb.Expr { |
| return mustAdaptToProto(ah.modernHelper.NewCall(function, mustAdaptToExprs(args)...)) |
| } |
| |
| // ReceiverCall creates a function call Expr value for a receiver-style function. |
| func (ah *adaptingHelper) ReceiverCall(function string, target *exprpb.Expr, args ...*exprpb.Expr) *exprpb.Expr { |
| return mustAdaptToProto( |
| ah.modernHelper.NewMemberCall(function, mustAdaptToExpr(target), mustAdaptToExprs(args)...)) |
| } |
| |
| // PresenceTest creates a Select TestOnly Expr value for modelling has() semantics. |
| func (ah *adaptingHelper) PresenceTest(operand *exprpb.Expr, field string) *exprpb.Expr { |
| op := mustAdaptToExpr(operand) |
| return mustAdaptToProto(ah.modernHelper.NewPresenceTest(op, field)) |
| } |
| |
| // Select create a field traversal Expr value. |
| func (ah *adaptingHelper) Select(operand *exprpb.Expr, field string) *exprpb.Expr { |
| op := mustAdaptToExpr(operand) |
| return mustAdaptToProto(ah.modernHelper.NewSelect(op, field)) |
| } |
| |
| // OffsetLocation returns the Location of the expression identifier. |
| func (ah *adaptingHelper) OffsetLocation(exprID int64) common.Location { |
| return ah.modernHelper.OffsetLocation(exprID) |
| } |
| |
| // NewError associates an error message with a given expression id. |
| func (ah *adaptingHelper) NewError(exprID int64, message string) *Error { |
| return ah.modernHelper.NewError(exprID, message) |
| } |
| |
| func mustAdaptToExprs(exprs []*exprpb.Expr) []ast.Expr { |
| adapted := make([]ast.Expr, len(exprs)) |
| for i, e := range exprs { |
| adapted[i] = mustAdaptToExpr(e) |
| } |
| return adapted |
| } |
| |
| func mustAdaptToExpr(e *exprpb.Expr) ast.Expr { |
| out, _ := adaptToExpr(e) |
| return out |
| } |
| |
| func adaptToExpr(e *exprpb.Expr) (ast.Expr, *Error) { |
| if e == nil { |
| return nil, nil |
| } |
| out, err := ast.ProtoToExpr(e) |
| if err != nil { |
| return nil, wrapErr(e.GetId(), "proto conversion failure", err) |
| } |
| return out, nil |
| } |
| |
| func mustAdaptToEntryExpr(e *exprpb.Expr_CreateStruct_Entry) ast.EntryExpr { |
| out, _ := ast.ProtoToEntryExpr(e) |
| return out |
| } |
| |
| func mustAdaptToProto(e ast.Expr) *exprpb.Expr { |
| out, _ := adaptToProto(e) |
| return out |
| } |
| |
| func adaptToProto(e ast.Expr) (*exprpb.Expr, *Error) { |
| if e == nil { |
| return nil, nil |
| } |
| out, err := ast.ExprToProto(e) |
| if err != nil { |
| return nil, wrapErr(e.ID(), "expr conversion failure", err) |
| } |
| return out, nil |
| } |
| |
| func mustAdaptToProtoEntry(e ast.EntryExpr) *exprpb.Expr_CreateStruct_Entry { |
| out, _ := ast.EntryExprToProto(e) |
| return out |
| } |
| |
| func toParserHelper(meh MacroExprHelper) (parser.ExprHelper, *Error) { |
| ah, ok := meh.(*adaptingHelper) |
| if !ok { |
| return nil, common.NewError(0, |
| fmt.Sprintf("unsupported macro helper: %v (%T)", meh, meh), |
| common.NoLocation) |
| } |
| return ah.modernHelper, nil |
| } |