// NewFunction creates a new function declaration with a set of function options to configure overloads // and function definitions (implementations). // // Functions are checked for name collisions and singleton redefinition. func NewFunction(name string, opts ...FunctionOpt) (*FunctionDecl, error) { … } type FunctionDecl … type declarationState … const declarationStateUnset … const declarationDisabled … const declarationEnabled … // Name returns the function name in human-readable terms, e.g. 'contains' of 'math.least' func (f *FunctionDecl) Name() string { … } // IsDeclarationDisabled indicates that the function implementation should be added to the dispatcher, but the // declaration should not be exposed for use in expressions. func (f *FunctionDecl) IsDeclarationDisabled() bool { … } // Merge combines an existing function declaration with another. // // If a function is extended, by say adding new overloads to an existing function, then it is merged with the // prior definition of the function at which point its overloads must not collide with pre-existing overloads // and its bindings (singleton, or per-overload) must not conflict with previous definitions either. func (f *FunctionDecl) Merge(other *FunctionDecl) (*FunctionDecl, error) { … } // AddOverload ensures that the new overload does not collide with an existing overload signature; // however, if the function signatures are identical, the implementation may be rewritten as its // difficult to compare functions by object identity. func (f *FunctionDecl) AddOverload(overload *OverloadDecl) error { … } // OverloadDecls returns the overload declarations in the order in which they were declared. func (f *FunctionDecl) OverloadDecls() []*OverloadDecl { … } // Bindings produces a set of function bindings, if any are defined. func (f *FunctionDecl) Bindings() ([]*functions.Overload, error) { … } // MaybeNoSuchOverload determines whether to propagate an error if one is provided as an argument, or // to return an unknown set, or to produce a new error for a missing function signature. func MaybeNoSuchOverload(funcName string, args ...ref.Val) ref.Val { … } type FunctionOpt … // DisableTypeGuards disables automatically generated function invocation guards on direct overload calls. // Type guards remain on during dynamic dispatch for parsed-only expressions. func DisableTypeGuards(value bool) FunctionOpt { … } // DisableDeclaration indicates that the function declaration should be disabled, but the runtime function // binding should be provided. Marking a function as runtime-only is a safe way to manage deprecations // of function declarations while still preserving the runtime behavior for previously compiled expressions. func DisableDeclaration(value bool) FunctionOpt { … } // SingletonUnaryBinding creates a singleton function definition to be used for all function overloads. // // Note, this approach works well if operand is expected to have a specific trait which it implements, // e.g. traits.ContainerType. Otherwise, prefer per-overload function bindings. func SingletonUnaryBinding(fn functions.UnaryOp, traits ...int) FunctionOpt { … } // SingletonBinaryBinding creates a singleton function definition to be used with all function overloads. // // Note, this approach works well if operand is expected to have a specific trait which it implements, // e.g. traits.ContainerType. Otherwise, prefer per-overload function bindings. func SingletonBinaryBinding(fn functions.BinaryOp, traits ...int) FunctionOpt { … } // SingletonFunctionBinding creates a singleton function definition to be used with all function overloads. // // Note, this approach works well if operand is expected to have a specific trait which it implements, // e.g. traits.ContainerType. Otherwise, prefer per-overload function bindings. func SingletonFunctionBinding(fn functions.FunctionOp, traits ...int) FunctionOpt { … } // Overload defines a new global overload with an overload id, argument types, and result type. Through the // use of OverloadOpt options, the overload may also be configured with a binding, an operand trait, and to // be non-strict. // // Note: function bindings should be commonly configured with Overload instances whereas operand traits and // strict-ness should be rare occurrences. func Overload(overloadID string, args []*types.Type, resultType *types.Type, opts ...OverloadOpt) FunctionOpt { … } // MemberOverload defines a new receiver-style overload (or member function) with an overload id, argument types, // and result type. Through the use of OverloadOpt options, the overload may also be configured with a binding, // an operand trait, and to be non-strict. // // Note: function bindings should be commonly configured with Overload instances whereas operand traits and // strict-ness should be rare occurrences. func MemberOverload(overloadID string, args []*types.Type, resultType *types.Type, opts ...OverloadOpt) FunctionOpt { … } func newOverload(overloadID string, memberFunction bool, args []*types.Type, resultType *types.Type, opts ...OverloadOpt) FunctionOpt { … } func newOverloadInternal(overloadID string, memberFunction bool, args []*types.Type, resultType *types.Type, opts ...OverloadOpt) (*OverloadDecl, error) { … } type OverloadDecl … // ID mirrors the overload signature and provides a unique id which may be referenced within the type-checker // and interpreter to optimize performance. // // The ID format is usually one of two styles: // global: <functionName>_<argType>_<argTypeN> // member: <memberType>_<functionName>_<argType>_<argTypeN> func (o *OverloadDecl) ID() string { … } // ArgTypes contains the set of argument types expected by the overload. // // For member functions ArgTypes[0] represents the member operand type. func (o *OverloadDecl) ArgTypes() []*types.Type { … } // IsMemberFunction indicates whether the overload is a member function func (o *OverloadDecl) IsMemberFunction() bool { … } // IsNonStrict returns whether the overload accepts errors and unknown values as arguments. func (o *OverloadDecl) IsNonStrict() bool { … } // OperandTrait returns the trait mask of the first operand to the overload call, e.g. // `traits.Indexer` func (o *OverloadDecl) OperandTrait() int { … } // ResultType indicates the output type from calling the function. func (o *OverloadDecl) ResultType() *types.Type { … } // TypeParams returns the type parameter names associated with the overload. func (o *OverloadDecl) TypeParams() []string { … } // SignatureEquals determines whether the incoming overload declaration signature is equal to the current signature. // // Result type, operand trait, and strict-ness are not considered as part of signature equality. func (o *OverloadDecl) SignatureEquals(other *OverloadDecl) bool { … } // SignatureOverlaps indicates whether two functions have non-equal, but overloapping function signatures. // // For example, list(dyn) collides with list(string) since the 'dyn' type can contain a 'string' type. func (o *OverloadDecl) SignatureOverlaps(other *OverloadDecl) bool { … } // hasBinding indicates whether the overload already has a definition. func (o *OverloadDecl) hasBinding() bool { … } // guardedUnaryOp creates an invocation guard around the provided unary operator, if one is defined. func (o *OverloadDecl) guardedUnaryOp(funcName string, disableTypeGuards bool) functions.UnaryOp { … } // guardedBinaryOp creates an invocation guard around the provided binary operator, if one is defined. func (o *OverloadDecl) guardedBinaryOp(funcName string, disableTypeGuards bool) functions.BinaryOp { … } // guardedFunctionOp creates an invocation guard around the provided variadic function binding, if one is provided. func (o *OverloadDecl) guardedFunctionOp(funcName string, disableTypeGuards bool) functions.FunctionOp { … } // matchesRuntimeUnarySignature indicates whether the argument type is runtime assiganble to the overload's expected argument. func (o *OverloadDecl) matchesRuntimeUnarySignature(disableTypeGuards bool, arg ref.Val) bool { … } // matchesRuntimeBinarySignature indicates whether the argument types are runtime assiganble to the overload's expected arguments. func (o *OverloadDecl) matchesRuntimeBinarySignature(disableTypeGuards bool, arg1, arg2 ref.Val) bool { … } // matchesRuntimeSignature indicates whether the argument types are runtime assiganble to the overload's expected arguments. func (o *OverloadDecl) matchesRuntimeSignature(disableTypeGuards bool, args ...ref.Val) bool { … } func matchRuntimeArgType(nonStrict, disableTypeGuards bool, argType *types.Type, arg ref.Val) bool { … } func matchOperandTrait(trait int, arg ref.Val) bool { … } type OverloadOpt … // UnaryBinding provides the implementation of a unary overload. The provided function is protected by a runtime // type-guard which ensures runtime type agreement between the overload signature and runtime argument types. func UnaryBinding(binding functions.UnaryOp) OverloadOpt { … } // BinaryBinding provides the implementation of a binary overload. The provided function is protected by a runtime // type-guard which ensures runtime type agreement between the overload signature and runtime argument types. func BinaryBinding(binding functions.BinaryOp) OverloadOpt { … } // FunctionBinding provides the implementation of a variadic overload. The provided function is protected by a runtime // type-guard which ensures runtime type agreement between the overload signature and runtime argument types. func FunctionBinding(binding functions.FunctionOp) OverloadOpt { … } // OverloadIsNonStrict enables the function to be called with error and unknown argument values. // // Note: do not use this option unless absoluately necessary as it should be an uncommon feature. func OverloadIsNonStrict() OverloadOpt { … } // OverloadOperandTrait configures a set of traits which the first argument to the overload must implement in order to be // successfully invoked. func OverloadOperandTrait(trait int) OverloadOpt { … } // NewConstant creates a new constant declaration. func NewConstant(name string, t *types.Type, v ref.Val) *VariableDecl { … } // NewVariable creates a new variable declaration. func NewVariable(name string, t *types.Type) *VariableDecl { … } type VariableDecl … // Name returns the fully-qualified variable name func (v *VariableDecl) Name() string { … } // Type returns the types.Type value associated with the variable. func (v *VariableDecl) Type() *types.Type { … } // Value returns the constant value associated with the declaration. func (v *VariableDecl) Value() ref.Val { … } // DeclarationIsEquivalent returns true if one variable declaration has the same name and same type as the input. func (v *VariableDecl) DeclarationIsEquivalent(other *VariableDecl) bool { … } // VariableDeclToExprDecl converts a go-native variable declaration into a protobuf-type variable declaration. func VariableDeclToExprDecl(v *VariableDecl) (*exprpb.Decl, error) { … } // TypeVariable creates a new type identifier for use within a types.Provider func TypeVariable(t *types.Type) *VariableDecl { … } // FunctionDeclToExprDecl converts a go-native function declaration into a protobuf-typed function declaration. func FunctionDeclToExprDecl(f *FunctionDecl) (*exprpb.Decl, error) { … } func collectParamNames(paramNames map[string]struct{ … } var emptyArgs …