| // Copyright 2018 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 decls provides helpers for creating variable and function declarations. |
| package decls |
| |
| import ( |
| exprpb "google.golang.org/genproto/googleapis/api/expr/v1alpha1" |
| emptypb "google.golang.org/protobuf/types/known/emptypb" |
| structpb "google.golang.org/protobuf/types/known/structpb" |
| ) |
| |
| var ( |
| // Error type used to communicate issues during type-checking. |
| Error = &exprpb.Type{ |
| TypeKind: &exprpb.Type_Error{ |
| Error: &emptypb.Empty{}}} |
| |
| // Dyn is a top-type used to represent any value. |
| Dyn = &exprpb.Type{ |
| TypeKind: &exprpb.Type_Dyn{ |
| Dyn: &emptypb.Empty{}}} |
| ) |
| |
| // Commonly used types. |
| var ( |
| Bool = NewPrimitiveType(exprpb.Type_BOOL) |
| Bytes = NewPrimitiveType(exprpb.Type_BYTES) |
| Double = NewPrimitiveType(exprpb.Type_DOUBLE) |
| Int = NewPrimitiveType(exprpb.Type_INT64) |
| Null = &exprpb.Type{ |
| TypeKind: &exprpb.Type_Null{ |
| Null: structpb.NullValue_NULL_VALUE}} |
| String = NewPrimitiveType(exprpb.Type_STRING) |
| Uint = NewPrimitiveType(exprpb.Type_UINT64) |
| ) |
| |
| // Well-known types. |
| // TODO: Replace with an abstract type registry. |
| var ( |
| Any = NewWellKnownType(exprpb.Type_ANY) |
| Duration = NewWellKnownType(exprpb.Type_DURATION) |
| Timestamp = NewWellKnownType(exprpb.Type_TIMESTAMP) |
| ) |
| |
| // NewAbstractType creates an abstract type declaration which references a proto |
| // message name and may also include type parameters. |
| func NewAbstractType(name string, paramTypes ...*exprpb.Type) *exprpb.Type { |
| return &exprpb.Type{ |
| TypeKind: &exprpb.Type_AbstractType_{ |
| AbstractType: &exprpb.Type_AbstractType{ |
| Name: name, |
| ParameterTypes: paramTypes}}} |
| } |
| |
| // NewOptionalType constructs an abstract type indicating that the parameterized type |
| // may be contained within the object. |
| func NewOptionalType(paramType *exprpb.Type) *exprpb.Type { |
| return NewAbstractType("optional_type", paramType) |
| } |
| |
| // NewFunctionType creates a function invocation contract, typically only used |
| // by type-checking steps after overload resolution. |
| func NewFunctionType(resultType *exprpb.Type, |
| argTypes ...*exprpb.Type) *exprpb.Type { |
| return &exprpb.Type{ |
| TypeKind: &exprpb.Type_Function{ |
| Function: &exprpb.Type_FunctionType{ |
| ResultType: resultType, |
| ArgTypes: argTypes}}} |
| } |
| |
| // NewFunction creates a named function declaration with one or more overloads. |
| func NewFunction(name string, |
| overloads ...*exprpb.Decl_FunctionDecl_Overload) *exprpb.Decl { |
| return &exprpb.Decl{ |
| Name: name, |
| DeclKind: &exprpb.Decl_Function{ |
| Function: &exprpb.Decl_FunctionDecl{ |
| Overloads: overloads}}} |
| } |
| |
| // NewFunctionWithDoc creates a named function declaration with a description and one or more overloads. |
| func NewFunctionWithDoc(name, doc string, |
| overloads ...*exprpb.Decl_FunctionDecl_Overload) *exprpb.Decl { |
| return &exprpb.Decl{ |
| Name: name, |
| DeclKind: &exprpb.Decl_Function{ |
| Function: &exprpb.Decl_FunctionDecl{ |
| // Doc: desc, |
| Overloads: overloads}}} |
| } |
| |
| // NewIdent creates a named identifier declaration with an optional literal |
| // value. |
| // |
| // Literal values are typically only associated with enum identifiers. |
| // |
| // Deprecated: Use NewVar or NewConst instead. |
| func NewIdent(name string, t *exprpb.Type, v *exprpb.Constant) *exprpb.Decl { |
| return newIdent(name, t, v, "") |
| } |
| |
| func newIdent(name string, t *exprpb.Type, v *exprpb.Constant, desc string) *exprpb.Decl { |
| return &exprpb.Decl{ |
| Name: name, |
| DeclKind: &exprpb.Decl_Ident{ |
| Ident: &exprpb.Decl_IdentDecl{ |
| Type: t, |
| Value: v, |
| Doc: desc}}} |
| } |
| |
| // NewConst creates a constant identifier with a CEL constant literal value. |
| func NewConst(name string, t *exprpb.Type, v *exprpb.Constant) *exprpb.Decl { |
| return newIdent(name, t, v, "") |
| } |
| |
| // NewVar creates a variable identifier. |
| func NewVar(name string, t *exprpb.Type) *exprpb.Decl { |
| return newIdent(name, t, nil, "") |
| } |
| |
| // NewVarWithDoc creates a variable identifier with a type and a description string. |
| func NewVarWithDoc(name string, t *exprpb.Type, desc string) *exprpb.Decl { |
| return newIdent(name, t, nil, desc) |
| } |
| |
| // NewInstanceOverload creates a instance function overload contract. |
| // First element of argTypes is instance. |
| func NewInstanceOverload(id string, argTypes []*exprpb.Type, resultType *exprpb.Type) *exprpb.Decl_FunctionDecl_Overload { |
| return &exprpb.Decl_FunctionDecl_Overload{ |
| OverloadId: id, |
| ResultType: resultType, |
| Params: argTypes, |
| IsInstanceFunction: true} |
| } |
| |
| // NewListType generates a new list with elements of a certain type. |
| func NewListType(elem *exprpb.Type) *exprpb.Type { |
| return &exprpb.Type{ |
| TypeKind: &exprpb.Type_ListType_{ |
| ListType: &exprpb.Type_ListType{ |
| ElemType: elem}}} |
| } |
| |
| // NewMapType generates a new map with typed keys and values. |
| func NewMapType(key *exprpb.Type, value *exprpb.Type) *exprpb.Type { |
| return &exprpb.Type{ |
| TypeKind: &exprpb.Type_MapType_{ |
| MapType: &exprpb.Type_MapType{ |
| KeyType: key, |
| ValueType: value}}} |
| } |
| |
| // NewObjectType creates an object type for a qualified type name. |
| func NewObjectType(typeName string) *exprpb.Type { |
| return &exprpb.Type{ |
| TypeKind: &exprpb.Type_MessageType{ |
| MessageType: typeName}} |
| } |
| |
| // NewOverload creates a function overload declaration which contains a unique |
| // overload id as well as the expected argument and result types. Overloads |
| // must be aggregated within a Function declaration. |
| func NewOverload(id string, argTypes []*exprpb.Type, resultType *exprpb.Type) *exprpb.Decl_FunctionDecl_Overload { |
| return &exprpb.Decl_FunctionDecl_Overload{ |
| OverloadId: id, |
| ResultType: resultType, |
| Params: argTypes, |
| IsInstanceFunction: false} |
| } |
| |
| // NewParameterizedInstanceOverload creates a parametric function instance overload type. |
| func NewParameterizedInstanceOverload(id string, |
| argTypes []*exprpb.Type, |
| resultType *exprpb.Type, |
| typeParams []string) *exprpb.Decl_FunctionDecl_Overload { |
| return &exprpb.Decl_FunctionDecl_Overload{ |
| OverloadId: id, |
| ResultType: resultType, |
| Params: argTypes, |
| TypeParams: typeParams, |
| IsInstanceFunction: true} |
| } |
| |
| // NewParameterizedOverload creates a parametric function overload type. |
| func NewParameterizedOverload(id string, |
| argTypes []*exprpb.Type, |
| resultType *exprpb.Type, |
| typeParams []string) *exprpb.Decl_FunctionDecl_Overload { |
| return &exprpb.Decl_FunctionDecl_Overload{ |
| OverloadId: id, |
| ResultType: resultType, |
| Params: argTypes, |
| TypeParams: typeParams, |
| IsInstanceFunction: false} |
| } |
| |
| // NewPrimitiveType creates a type for a primitive value. See the var declarations |
| // for Int, Uint, etc. |
| func NewPrimitiveType(primitive exprpb.Type_PrimitiveType) *exprpb.Type { |
| return &exprpb.Type{ |
| TypeKind: &exprpb.Type_Primitive{ |
| Primitive: primitive}} |
| } |
| |
| // NewTypeType creates a new type designating a type. |
| func NewTypeType(nested *exprpb.Type) *exprpb.Type { |
| if nested == nil { |
| // must set the nested field for a valid oneof option |
| nested = &exprpb.Type{} |
| } |
| return &exprpb.Type{ |
| TypeKind: &exprpb.Type_Type{ |
| Type: nested}} |
| } |
| |
| // NewTypeParamType creates a type corresponding to a named, contextual parameter. |
| func NewTypeParamType(name string) *exprpb.Type { |
| return &exprpb.Type{ |
| TypeKind: &exprpb.Type_TypeParam{ |
| TypeParam: name}} |
| } |
| |
| // NewWellKnownType creates a type corresponding to a protobuf well-known type |
| // value. |
| func NewWellKnownType(wellKnown exprpb.Type_WellKnownType) *exprpb.Type { |
| return &exprpb.Type{ |
| TypeKind: &exprpb.Type_WellKnown{ |
| WellKnown: wellKnown}} |
| } |
| |
| // NewWrapperType creates a wrapped primitive type instance. Wrapped types |
| // are roughly equivalent to a nullable, or optionally valued type. |
| func NewWrapperType(wrapped *exprpb.Type) *exprpb.Type { |
| primitive := wrapped.GetPrimitive() |
| if primitive == exprpb.Type_PRIMITIVE_TYPE_UNSPECIFIED { |
| // TODO: return an error |
| panic("Wrapped type must be a primitive") |
| } |
| return &exprpb.Type{TypeKind: &exprpb.Type_Wrapper{Wrapper: primitive}} |
| } |