mirror of
https://gitea.com/Lydanne/buildx.git
synced 2025-07-09 21:17:09 +08:00
70
vendor/github.com/zclconf/go-cty/cty/function/argument.go
generated
vendored
Normal file
70
vendor/github.com/zclconf/go-cty/cty/function/argument.go
generated
vendored
Normal file
@ -0,0 +1,70 @@
|
||||
package function
|
||||
|
||||
import (
|
||||
"github.com/zclconf/go-cty/cty"
|
||||
)
|
||||
|
||||
// Parameter represents a parameter to a function.
|
||||
type Parameter struct {
|
||||
// Name is an optional name for the argument. This package ignores this
|
||||
// value, but callers may use it for documentation, etc.
|
||||
Name string
|
||||
|
||||
// A type that any argument for this parameter must conform to.
|
||||
// cty.DynamicPseudoType can be used, either at top-level or nested
|
||||
// in a parameterized type, to indicate that any type should be
|
||||
// permitted, to allow the definition of type-generic functions.
|
||||
Type cty.Type
|
||||
|
||||
// If AllowNull is set then null values may be passed into this
|
||||
// argument's slot in both the type-check function and the implementation
|
||||
// function. If not set, such values are rejected by the built-in
|
||||
// checking rules.
|
||||
AllowNull bool
|
||||
|
||||
// If AllowUnknown is set then unknown values may be passed into this
|
||||
// argument's slot in the implementation function. If not set, any
|
||||
// unknown values will cause the function to immediately return
|
||||
// an unkonwn value without calling the implementation function, thus
|
||||
// freeing the function implementer from dealing with this case.
|
||||
AllowUnknown bool
|
||||
|
||||
// If AllowDynamicType is set then DynamicVal may be passed into this
|
||||
// argument's slot in the implementation function. If not set, any
|
||||
// dynamic values will cause the function to immediately return
|
||||
// DynamicVal value without calling the implementation function, thus
|
||||
// freeing the function implementer from dealing with this case.
|
||||
//
|
||||
// Note that DynamicVal is also unknown, so in order to receive dynamic
|
||||
// *values* it is also necessary to set AllowUnknown.
|
||||
//
|
||||
// However, it is valid to set AllowDynamicType without AllowUnknown, in
|
||||
// which case a dynamic value may be passed to the type checking function
|
||||
// but will not make it to the *implementation* function. Instead, an
|
||||
// unknown value of the type returned by the type-check function will be
|
||||
// returned. This is suggested for functions that have a static return
|
||||
// type since it allows the return value to be typed even if the input
|
||||
// values are not, thus improving the type-check accuracy of derived
|
||||
// values.
|
||||
AllowDynamicType bool
|
||||
|
||||
// If AllowMarked is set then marked values may be passed into this
|
||||
// argument's slot in the implementation function. If not set, any
|
||||
// marked value will be unmarked before calling and then the markings
|
||||
// from that value will be applied automatically to the function result,
|
||||
// ensuring that the marks get propagated in a simplistic way even if
|
||||
// a function is unable to handle them.
|
||||
//
|
||||
// For any argument whose parameter has AllowMarked set, it's the
|
||||
// function implementation's responsibility to Unmark the given value
|
||||
// and propagate the marks appropriatedly to the result in order to
|
||||
// avoid losing the marks. Application-specific functions might use
|
||||
// special rules to selectively propagate particular marks.
|
||||
//
|
||||
// The automatic unmarking of values applies only to the main
|
||||
// implementation function. In an application that uses marked values,
|
||||
// the Type implementation for a function must always be prepared to accept
|
||||
// marked values, which is easy to achieve by consulting only the type
|
||||
// and ignoring the value itself.
|
||||
AllowMarked bool
|
||||
}
|
6
vendor/github.com/zclconf/go-cty/cty/function/doc.go
generated
vendored
Normal file
6
vendor/github.com/zclconf/go-cty/cty/function/doc.go
generated
vendored
Normal file
@ -0,0 +1,6 @@
|
||||
// Package function builds on the functionality of cty by modeling functions
|
||||
// that operate on cty Values.
|
||||
//
|
||||
// Functions are, at their core, Go anonymous functions. However, this package
|
||||
// wraps around them utility functions for parameter type checking, etc.
|
||||
package function
|
50
vendor/github.com/zclconf/go-cty/cty/function/error.go
generated
vendored
Normal file
50
vendor/github.com/zclconf/go-cty/cty/function/error.go
generated
vendored
Normal file
@ -0,0 +1,50 @@
|
||||
package function
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"runtime/debug"
|
||||
)
|
||||
|
||||
// ArgError represents an error with one of the arguments in a call. The
|
||||
// attribute Index represents the zero-based index of the argument in question.
|
||||
//
|
||||
// Its error *may* be a cty.PathError, in which case the error actually
|
||||
// pertains to a nested value within the data structure passed as the argument.
|
||||
type ArgError struct {
|
||||
error
|
||||
Index int
|
||||
}
|
||||
|
||||
func NewArgErrorf(i int, f string, args ...interface{}) error {
|
||||
return ArgError{
|
||||
error: fmt.Errorf(f, args...),
|
||||
Index: i,
|
||||
}
|
||||
}
|
||||
|
||||
func NewArgError(i int, err error) error {
|
||||
return ArgError{
|
||||
error: err,
|
||||
Index: i,
|
||||
}
|
||||
}
|
||||
|
||||
// PanicError indicates that a panic occurred while executing either a
|
||||
// function's type or implementation function. This is captured and wrapped
|
||||
// into a normal error so that callers (expected to be language runtimes)
|
||||
// are freed from having to deal with panics in buggy functions.
|
||||
type PanicError struct {
|
||||
Value interface{}
|
||||
Stack []byte
|
||||
}
|
||||
|
||||
func errorForPanic(val interface{}) error {
|
||||
return PanicError{
|
||||
Value: val,
|
||||
Stack: debug.Stack(),
|
||||
}
|
||||
}
|
||||
|
||||
func (e PanicError) Error() string {
|
||||
return fmt.Sprintf("panic in function implementation: %s\n%s", e.Value, e.Stack)
|
||||
}
|
342
vendor/github.com/zclconf/go-cty/cty/function/function.go
generated
vendored
Normal file
342
vendor/github.com/zclconf/go-cty/cty/function/function.go
generated
vendored
Normal file
@ -0,0 +1,342 @@
|
||||
package function
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
|
||||
"github.com/zclconf/go-cty/cty"
|
||||
)
|
||||
|
||||
// Function represents a function. This is the main type in this package.
|
||||
type Function struct {
|
||||
spec *Spec
|
||||
}
|
||||
|
||||
// Spec is the specification of a function, used to instantiate
|
||||
// a new Function.
|
||||
type Spec struct {
|
||||
// Params is a description of the positional parameters for the function.
|
||||
// The standard checking logic rejects any calls that do not provide
|
||||
// arguments conforming to this definition, freeing the function
|
||||
// implementer from dealing with such inconsistencies.
|
||||
Params []Parameter
|
||||
|
||||
// VarParam is an optional specification of additional "varargs" the
|
||||
// function accepts. If this is non-nil then callers may provide an
|
||||
// arbitrary number of additional arguments (after those matching with
|
||||
// the fixed parameters in Params) that conform to the given specification,
|
||||
// which will appear as additional values in the slices of values
|
||||
// provided to the type and implementation functions.
|
||||
VarParam *Parameter
|
||||
|
||||
// Type is the TypeFunc that decides the return type of the function
|
||||
// given its arguments, which may be Unknown. See the documentation
|
||||
// of TypeFunc for more information.
|
||||
//
|
||||
// Use StaticReturnType if the function's return type does not vary
|
||||
// depending on its arguments.
|
||||
Type TypeFunc
|
||||
|
||||
// Impl is the ImplFunc that implements the function's behavior.
|
||||
//
|
||||
// Functions are expected to behave as pure functions, and not create
|
||||
// any visible side-effects.
|
||||
//
|
||||
// If a TypeFunc is also provided, the value returned from Impl *must*
|
||||
// conform to the type it returns, or a call to the function will panic.
|
||||
Impl ImplFunc
|
||||
}
|
||||
|
||||
// New creates a new function with the given specification.
|
||||
//
|
||||
// After passing a Spec to this function, the caller must no longer read from
|
||||
// or mutate it.
|
||||
func New(spec *Spec) Function {
|
||||
f := Function{
|
||||
spec: spec,
|
||||
}
|
||||
return f
|
||||
}
|
||||
|
||||
// TypeFunc is a callback type for determining the return type of a function
|
||||
// given its arguments.
|
||||
//
|
||||
// Any of the values passed to this function may be unknown, even if the
|
||||
// parameters are not configured to accept unknowns.
|
||||
//
|
||||
// If any of the given values are *not* unknown, the TypeFunc may use the
|
||||
// values for pre-validation and for choosing the return type. For example,
|
||||
// a hypothetical JSON-unmarshalling function could return
|
||||
// cty.DynamicPseudoType if the given JSON string is unknown, but return
|
||||
// a concrete type based on the JSON structure if the JSON string is already
|
||||
// known.
|
||||
type TypeFunc func(args []cty.Value) (cty.Type, error)
|
||||
|
||||
// ImplFunc is a callback type for the main implementation of a function.
|
||||
//
|
||||
// "args" are the values for the arguments, and this slice will always be at
|
||||
// least as long as the argument definition slice for the function.
|
||||
//
|
||||
// "retType" is the type returned from the Type callback, included as a
|
||||
// convenience to avoid the need to re-compute the return type for generic
|
||||
// functions whose return type is a function of the arguments.
|
||||
type ImplFunc func(args []cty.Value, retType cty.Type) (cty.Value, error)
|
||||
|
||||
// StaticReturnType returns a TypeFunc that always returns the given type.
|
||||
//
|
||||
// This is provided as a convenience for defining a function whose return
|
||||
// type does not depend on the argument types.
|
||||
func StaticReturnType(ty cty.Type) TypeFunc {
|
||||
return func([]cty.Value) (cty.Type, error) {
|
||||
return ty, nil
|
||||
}
|
||||
}
|
||||
|
||||
// ReturnType returns the return type of a function given a set of candidate
|
||||
// argument types, or returns an error if the given types are unacceptable.
|
||||
//
|
||||
// If the caller already knows values for at least some of the arguments
|
||||
// it can be better to call ReturnTypeForValues, since certain functions may
|
||||
// determine their return types from their values and return DynamicVal if
|
||||
// the values are unknown.
|
||||
func (f Function) ReturnType(argTypes []cty.Type) (cty.Type, error) {
|
||||
vals := make([]cty.Value, len(argTypes))
|
||||
for i, ty := range argTypes {
|
||||
vals[i] = cty.UnknownVal(ty)
|
||||
}
|
||||
return f.ReturnTypeForValues(vals)
|
||||
}
|
||||
|
||||
// ReturnTypeForValues is similar to ReturnType but can be used if the caller
|
||||
// already knows the values of some or all of the arguments, in which case
|
||||
// the function may be able to determine a more definite result if its
|
||||
// return type depends on the argument *values*.
|
||||
//
|
||||
// For any arguments whose values are not known, pass an Unknown value of
|
||||
// the appropriate type.
|
||||
func (f Function) ReturnTypeForValues(args []cty.Value) (ty cty.Type, err error) {
|
||||
var posArgs []cty.Value
|
||||
var varArgs []cty.Value
|
||||
|
||||
if f.spec.VarParam == nil {
|
||||
if len(args) != len(f.spec.Params) {
|
||||
return cty.Type{}, fmt.Errorf(
|
||||
"wrong number of arguments (%d required; %d given)",
|
||||
len(f.spec.Params), len(args),
|
||||
)
|
||||
}
|
||||
|
||||
posArgs = args
|
||||
varArgs = nil
|
||||
} else {
|
||||
if len(args) < len(f.spec.Params) {
|
||||
return cty.Type{}, fmt.Errorf(
|
||||
"wrong number of arguments (at least %d required; %d given)",
|
||||
len(f.spec.Params), len(args),
|
||||
)
|
||||
}
|
||||
|
||||
posArgs = args[0:len(f.spec.Params)]
|
||||
varArgs = args[len(f.spec.Params):]
|
||||
}
|
||||
|
||||
for i, spec := range f.spec.Params {
|
||||
val := posArgs[i]
|
||||
|
||||
if val.IsMarked() && !spec.AllowMarked {
|
||||
// During type checking we just unmark values and discard their
|
||||
// marks, under the assumption that during actual execution of
|
||||
// the function we'll do similarly and then re-apply the marks
|
||||
// afterwards. Note that this does mean that a function that
|
||||
// inspects values (rather than just types) in its Type
|
||||
// implementation can potentially fail to take into account marks,
|
||||
// unless it specifically opts in to seeing them.
|
||||
unmarked, _ := val.Unmark()
|
||||
newArgs := make([]cty.Value, len(args))
|
||||
copy(newArgs, args)
|
||||
newArgs[i] = unmarked
|
||||
args = newArgs
|
||||
}
|
||||
|
||||
if val.IsNull() && !spec.AllowNull {
|
||||
return cty.Type{}, NewArgErrorf(i, "argument must not be null")
|
||||
}
|
||||
|
||||
// AllowUnknown is ignored for type-checking, since we expect to be
|
||||
// able to type check with unknown values. We *do* still need to deal
|
||||
// with DynamicPseudoType here though, since the Type function might
|
||||
// not be ready to deal with that.
|
||||
|
||||
if val.Type() == cty.DynamicPseudoType {
|
||||
if !spec.AllowDynamicType {
|
||||
return cty.DynamicPseudoType, nil
|
||||
}
|
||||
} else if errs := val.Type().TestConformance(spec.Type); errs != nil {
|
||||
// For now we'll just return the first error in the set, since
|
||||
// we don't have a good way to return the whole list here.
|
||||
// Would be good to do something better at some point...
|
||||
return cty.Type{}, NewArgError(i, errs[0])
|
||||
}
|
||||
}
|
||||
|
||||
if varArgs != nil {
|
||||
spec := f.spec.VarParam
|
||||
for i, val := range varArgs {
|
||||
realI := i + len(posArgs)
|
||||
|
||||
if val.IsMarked() && !spec.AllowMarked {
|
||||
// See the similar block in the loop above for what's going on here.
|
||||
unmarked, _ := val.Unmark()
|
||||
newArgs := make([]cty.Value, len(args))
|
||||
copy(newArgs, args)
|
||||
newArgs[realI] = unmarked
|
||||
args = newArgs
|
||||
}
|
||||
|
||||
if val.IsNull() && !spec.AllowNull {
|
||||
return cty.Type{}, NewArgErrorf(realI, "argument must not be null")
|
||||
}
|
||||
|
||||
if val.Type() == cty.DynamicPseudoType {
|
||||
if !spec.AllowDynamicType {
|
||||
return cty.DynamicPseudoType, nil
|
||||
}
|
||||
} else if errs := val.Type().TestConformance(spec.Type); errs != nil {
|
||||
// For now we'll just return the first error in the set, since
|
||||
// we don't have a good way to return the whole list here.
|
||||
// Would be good to do something better at some point...
|
||||
return cty.Type{}, NewArgError(i, errs[0])
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// Intercept any panics from the function and return them as normal errors,
|
||||
// so a calling language runtime doesn't need to deal with panics.
|
||||
defer func() {
|
||||
if r := recover(); r != nil {
|
||||
ty = cty.NilType
|
||||
err = errorForPanic(r)
|
||||
}
|
||||
}()
|
||||
|
||||
return f.spec.Type(args)
|
||||
}
|
||||
|
||||
// Call actually calls the function with the given arguments, which must
|
||||
// conform to the function's parameter specification or an error will be
|
||||
// returned.
|
||||
func (f Function) Call(args []cty.Value) (val cty.Value, err error) {
|
||||
expectedType, err := f.ReturnTypeForValues(args)
|
||||
if err != nil {
|
||||
return cty.NilVal, err
|
||||
}
|
||||
|
||||
// Type checking already dealt with most situations relating to our
|
||||
// parameter specification, but we still need to deal with unknown
|
||||
// values and marked values.
|
||||
posArgs := args[:len(f.spec.Params)]
|
||||
varArgs := args[len(f.spec.Params):]
|
||||
var resultMarks []cty.ValueMarks
|
||||
|
||||
for i, spec := range f.spec.Params {
|
||||
val := posArgs[i]
|
||||
|
||||
if !val.IsKnown() && !spec.AllowUnknown {
|
||||
return cty.UnknownVal(expectedType), nil
|
||||
}
|
||||
|
||||
if val.IsMarked() && !spec.AllowMarked {
|
||||
unwrappedVal, marks := val.Unmark()
|
||||
// In order to avoid additional overhead on applications that
|
||||
// are not using marked values, we copy the given args only
|
||||
// if we encounter a marked value we need to unmark. However,
|
||||
// as a consequence we end up doing redundant copying if multiple
|
||||
// marked values need to be unwrapped. That seems okay because
|
||||
// argument lists are generally small.
|
||||
newArgs := make([]cty.Value, len(args))
|
||||
copy(newArgs, args)
|
||||
newArgs[i] = unwrappedVal
|
||||
resultMarks = append(resultMarks, marks)
|
||||
args = newArgs
|
||||
}
|
||||
}
|
||||
|
||||
if f.spec.VarParam != nil {
|
||||
spec := f.spec.VarParam
|
||||
for i, val := range varArgs {
|
||||
if !val.IsKnown() && !spec.AllowUnknown {
|
||||
return cty.UnknownVal(expectedType), nil
|
||||
}
|
||||
if val.IsMarked() && !spec.AllowMarked {
|
||||
unwrappedVal, marks := val.Unmark()
|
||||
newArgs := make([]cty.Value, len(args))
|
||||
copy(newArgs, args)
|
||||
newArgs[len(posArgs)+i] = unwrappedVal
|
||||
resultMarks = append(resultMarks, marks)
|
||||
args = newArgs
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
var retVal cty.Value
|
||||
{
|
||||
// Intercept any panics from the function and return them as normal errors,
|
||||
// so a calling language runtime doesn't need to deal with panics.
|
||||
defer func() {
|
||||
if r := recover(); r != nil {
|
||||
val = cty.NilVal
|
||||
err = errorForPanic(r)
|
||||
}
|
||||
}()
|
||||
|
||||
retVal, err = f.spec.Impl(args, expectedType)
|
||||
if err != nil {
|
||||
return cty.NilVal, err
|
||||
}
|
||||
if len(resultMarks) > 0 {
|
||||
retVal = retVal.WithMarks(resultMarks...)
|
||||
}
|
||||
}
|
||||
|
||||
// Returned value must conform to what the Type function expected, to
|
||||
// protect callers from having to deal with inconsistencies.
|
||||
if errs := retVal.Type().TestConformance(expectedType); errs != nil {
|
||||
panic(fmt.Errorf(
|
||||
"returned value %#v does not conform to expected return type %#v: %s",
|
||||
retVal, expectedType, errs[0],
|
||||
))
|
||||
}
|
||||
|
||||
return retVal, nil
|
||||
}
|
||||
|
||||
// ProxyFunc the type returned by the method Function.Proxy.
|
||||
type ProxyFunc func(args ...cty.Value) (cty.Value, error)
|
||||
|
||||
// Proxy returns a function that can be called with cty.Value arguments
|
||||
// to run the function. This is provided as a convenience for when using
|
||||
// a function directly within Go code.
|
||||
func (f Function) Proxy() ProxyFunc {
|
||||
return func(args ...cty.Value) (cty.Value, error) {
|
||||
return f.Call(args)
|
||||
}
|
||||
}
|
||||
|
||||
// Params returns information about the function's fixed positional parameters.
|
||||
// This does not include information about any variadic arguments accepted;
|
||||
// for that, call VarParam.
|
||||
func (f Function) Params() []Parameter {
|
||||
new := make([]Parameter, len(f.spec.Params))
|
||||
copy(new, f.spec.Params)
|
||||
return new
|
||||
}
|
||||
|
||||
// VarParam returns information about the variadic arguments the function
|
||||
// expects, or nil if the function is not variadic.
|
||||
func (f Function) VarParam() *Parameter {
|
||||
if f.spec.VarParam == nil {
|
||||
return nil
|
||||
}
|
||||
|
||||
ret := *f.spec.VarParam
|
||||
return &ret
|
||||
}
|
31
vendor/github.com/zclconf/go-cty/cty/function/unpredictable.go
generated
vendored
Normal file
31
vendor/github.com/zclconf/go-cty/cty/function/unpredictable.go
generated
vendored
Normal file
@ -0,0 +1,31 @@
|
||||
package function
|
||||
|
||||
import (
|
||||
"github.com/zclconf/go-cty/cty"
|
||||
)
|
||||
|
||||
// Unpredictable wraps a given function such that it retains the same arguments
|
||||
// and type checking behavior but will return an unknown value when called.
|
||||
//
|
||||
// It is recommended that most functions be "pure", which is to say that they
|
||||
// will always produce the same value given particular input. However,
|
||||
// sometimes it is necessary to offer functions whose behavior depends on
|
||||
// some external state, such as reading a file or determining the current time.
|
||||
// In such cases, an unpredictable wrapper might be used to stand in for
|
||||
// the function during some sort of prior "checking" phase in order to delay
|
||||
// the actual effect until later.
|
||||
//
|
||||
// While Unpredictable can support a function that isn't pure in its
|
||||
// implementation, it still expects a function to be pure in its type checking
|
||||
// behavior, except for the special case of returning cty.DynamicPseudoType
|
||||
// if it is not yet able to predict its return value based on current argument
|
||||
// information.
|
||||
func Unpredictable(f Function) Function {
|
||||
newSpec := *f.spec // shallow copy
|
||||
newSpec.Impl = unpredictableImpl
|
||||
return New(&newSpec)
|
||||
}
|
||||
|
||||
func unpredictableImpl(args []cty.Value, retType cty.Type) (cty.Value, error) {
|
||||
return cty.UnknownVal(retType), nil
|
||||
}
|
Reference in New Issue
Block a user