mirror of
https://gitea.com/Lydanne/buildx.git
synced 2025-07-09 21:17:09 +08:00
Extend hcl2 support with more functions
Signed-off-by: CrazyMax <crazy-max@users.noreply.github.com>
This commit is contained in:
152
vendor/github.com/zclconf/go-cty/cty/value_ops.go
generated
vendored
152
vendor/github.com/zclconf/go-cty/cty/value_ops.go
generated
vendored
@ -3,7 +3,6 @@ package cty
|
||||
import (
|
||||
"fmt"
|
||||
"math/big"
|
||||
"reflect"
|
||||
|
||||
"github.com/zclconf/go-cty/cty/set"
|
||||
)
|
||||
@ -133,9 +132,9 @@ func (val Value) Equals(other Value) Value {
|
||||
case val.IsKnown() && !other.IsKnown():
|
||||
switch {
|
||||
case val.IsNull(), other.ty.HasDynamicTypes():
|
||||
// If known is Null, we need to wait for the unkown value since
|
||||
// If known is Null, we need to wait for the unknown value since
|
||||
// nulls of any type are equal.
|
||||
// An unkown with a dynamic type compares as unknown, which we need
|
||||
// An unknown with a dynamic type compares as unknown, which we need
|
||||
// to check before the type comparison below.
|
||||
return UnknownVal(Bool)
|
||||
case !val.ty.Equals(other.ty):
|
||||
@ -148,9 +147,9 @@ func (val Value) Equals(other Value) Value {
|
||||
case other.IsKnown() && !val.IsKnown():
|
||||
switch {
|
||||
case other.IsNull(), val.ty.HasDynamicTypes():
|
||||
// If known is Null, we need to wait for the unkown value since
|
||||
// If known is Null, we need to wait for the unknown value since
|
||||
// nulls of any type are equal.
|
||||
// An unkown with a dynamic type compares as unknown, which we need
|
||||
// An unknown with a dynamic type compares as unknown, which we need
|
||||
// to check before the type comparison below.
|
||||
return UnknownVal(Bool)
|
||||
case !other.ty.Equals(val.ty):
|
||||
@ -171,7 +170,15 @@ func (val Value) Equals(other Value) Value {
|
||||
return BoolVal(false)
|
||||
}
|
||||
|
||||
if val.ty.HasDynamicTypes() || other.ty.HasDynamicTypes() {
|
||||
// Check if there are any nested dynamic values making this comparison
|
||||
// unknown.
|
||||
if !val.HasWhollyKnownType() || !other.HasWhollyKnownType() {
|
||||
// Even if we have dynamic values, we can still determine inequality if
|
||||
// there is no way the types could later conform.
|
||||
if val.ty.TestConformance(other.ty) != nil && other.ty.TestConformance(val.ty) != nil {
|
||||
return BoolVal(false)
|
||||
}
|
||||
|
||||
return UnknownVal(Bool)
|
||||
}
|
||||
|
||||
@ -262,24 +269,26 @@ func (val Value) Equals(other Value) Value {
|
||||
s2 := other.v.(set.Set)
|
||||
equal := true
|
||||
|
||||
// Note that by our definition of sets it's never possible for two
|
||||
// sets that contain unknown values (directly or indicrectly) to
|
||||
// ever be equal, even if they are otherwise identical.
|
||||
|
||||
// FIXME: iterating both lists and checking each item is not the
|
||||
// ideal implementation here, but it works with the primitives we
|
||||
// have in the set implementation. Perhaps the set implementation
|
||||
// can provide its own equality test later.
|
||||
s1.EachValue(func(v interface{}) {
|
||||
if !s2.Has(v) {
|
||||
// Two sets are equal if all of their values are known and all values
|
||||
// in one are also in the other.
|
||||
for it := s1.Iterator(); it.Next(); {
|
||||
rv := it.Value()
|
||||
if rv == unknown { // "unknown" is the internal representation of unknown-ness
|
||||
return UnknownVal(Bool)
|
||||
}
|
||||
if !s2.Has(rv) {
|
||||
equal = false
|
||||
}
|
||||
})
|
||||
s2.EachValue(func(v interface{}) {
|
||||
if !s1.Has(v) {
|
||||
}
|
||||
for it := s2.Iterator(); it.Next(); {
|
||||
rv := it.Value()
|
||||
if rv == unknown { // "unknown" is the internal representation of unknown-ness
|
||||
return UnknownVal(Bool)
|
||||
}
|
||||
if !s1.Has(rv) {
|
||||
equal = false
|
||||
}
|
||||
})
|
||||
}
|
||||
|
||||
result = equal
|
||||
case ty.IsMapType():
|
||||
@ -454,17 +463,32 @@ func (val Value) RawEquals(other Value) bool {
|
||||
return true
|
||||
}
|
||||
return false
|
||||
case ty.IsSetType():
|
||||
s1 := val.v.(set.Set)
|
||||
s2 := other.v.(set.Set)
|
||||
|
||||
// Since we're intentionally ignoring our rule that two unknowns
|
||||
// are never equal, we can cheat here.
|
||||
// (This isn't 100% right since e.g. it will fail if the set contains
|
||||
// numbers that are infinite, which DeepEqual can't compare properly.
|
||||
// We're accepting that limitation for simplicity here, since this
|
||||
// function is here primarily for testing.)
|
||||
return reflect.DeepEqual(s1, s2)
|
||||
case ty.IsSetType():
|
||||
// Convert the set values into a slice so that we can compare each
|
||||
// value. This is safe because the underlying sets are ordered (see
|
||||
// setRules in set_internals.go), and so the results are guaranteed to
|
||||
// be in a consistent order for two equal sets
|
||||
setList1 := val.AsValueSlice()
|
||||
setList2 := other.AsValueSlice()
|
||||
|
||||
// If both physical sets have the same length and they have all of their
|
||||
// _known_ values in common, we know that both sets also have the same
|
||||
// number of unknown values.
|
||||
if len(setList1) != len(setList2) {
|
||||
return false
|
||||
}
|
||||
|
||||
for i := range setList1 {
|
||||
eq := setList1[i].RawEquals(setList2[i])
|
||||
if !eq {
|
||||
return false
|
||||
}
|
||||
}
|
||||
|
||||
// If we got here without returning false already then our sets are
|
||||
// equal enough for RawEquals purposes.
|
||||
return true
|
||||
|
||||
case ty.IsMapType():
|
||||
ety := ty.typeImpl.(typeMap).ElementTypeT
|
||||
@ -572,8 +596,25 @@ func (val Value) Multiply(other Value) Value {
|
||||
return *shortCircuit
|
||||
}
|
||||
|
||||
ret := new(big.Float)
|
||||
// find the larger precision of the arguments
|
||||
resPrec := val.v.(*big.Float).Prec()
|
||||
otherPrec := other.v.(*big.Float).Prec()
|
||||
if otherPrec > resPrec {
|
||||
resPrec = otherPrec
|
||||
}
|
||||
|
||||
// make sure we have enough precision for the product
|
||||
ret := new(big.Float).SetPrec(512)
|
||||
ret.Mul(val.v.(*big.Float), other.v.(*big.Float))
|
||||
|
||||
// now reduce the precision back to the greater argument, or the minimum
|
||||
// required by the product.
|
||||
minPrec := ret.MinPrec()
|
||||
if minPrec > resPrec {
|
||||
resPrec = minPrec
|
||||
}
|
||||
ret.SetPrec(resPrec)
|
||||
|
||||
return NumberVal(ret)
|
||||
}
|
||||
|
||||
@ -645,11 +686,14 @@ func (val Value) Modulo(other Value) Value {
|
||||
// FIXME: This is a bit clumsy. Should come back later and see if there's a
|
||||
// more straightforward way to do this.
|
||||
rat := val.Divide(other)
|
||||
ratFloorInt := &big.Int{}
|
||||
rat.v.(*big.Float).Int(ratFloorInt)
|
||||
work := (&big.Float{}).SetInt(ratFloorInt)
|
||||
ratFloorInt, _ := rat.v.(*big.Float).Int(nil)
|
||||
|
||||
// start with a copy of the original larger value so that we do not lose
|
||||
// precision.
|
||||
v := val.v.(*big.Float)
|
||||
work := new(big.Float).Copy(v).SetInt(ratFloorInt)
|
||||
work.Mul(other.v.(*big.Float), work)
|
||||
work.Sub(val.v.(*big.Float), work)
|
||||
work.Sub(v, work)
|
||||
|
||||
return NumberVal(work)
|
||||
}
|
||||
@ -947,8 +991,7 @@ func (val Value) HasElement(elem Value) Value {
|
||||
// If the receiver is null then this function will panic.
|
||||
//
|
||||
// Note that Length is not supported for strings. To determine the length
|
||||
// of a string, call AsString and take the length of the native Go string
|
||||
// that is returned.
|
||||
// of a string, use the Length function in funcs/stdlib.
|
||||
func (val Value) Length() Value {
|
||||
if val.IsMarked() {
|
||||
val, valMarks := val.Unmark()
|
||||
@ -963,6 +1006,25 @@ func (val Value) Length() Value {
|
||||
if !val.IsKnown() {
|
||||
return UnknownVal(Number)
|
||||
}
|
||||
if val.Type().IsSetType() {
|
||||
// The Length rules are a little different for sets because if any
|
||||
// unknown values are present then the values they are standing in for
|
||||
// may or may not be equal to other elements in the set, and thus they
|
||||
// may or may not coalesce with other elements and produce fewer
|
||||
// items in the resulting set.
|
||||
storeLength := int64(val.v.(set.Set).Length())
|
||||
if storeLength == 1 || val.IsWhollyKnown() {
|
||||
// If our set is wholly known then we know its length.
|
||||
//
|
||||
// We also know the length if the physical store has only one
|
||||
// element, even if that element is unknown, because there's
|
||||
// nothing else in the set for it to coalesce with and a single
|
||||
// unknown value cannot represent more than one known value.
|
||||
return NumberIntVal(storeLength)
|
||||
}
|
||||
// Otherwise, we cannot predict the length.
|
||||
return UnknownVal(Number)
|
||||
}
|
||||
|
||||
return NumberIntVal(int64(val.LengthInt()))
|
||||
}
|
||||
@ -972,6 +1034,13 @@ func (val Value) Length() Value {
|
||||
//
|
||||
// This is an integration method provided for the convenience of code bridging
|
||||
// into Go's type system.
|
||||
//
|
||||
// For backward compatibility with an earlier implementation error, LengthInt's
|
||||
// result can disagree with Length's result for any set containing unknown
|
||||
// values. Length can potentially indicate the set's length is unknown in that
|
||||
// case, whereas LengthInt will return the maximum possible length as if the
|
||||
// unknown values were each a placeholder for a value not equal to any other
|
||||
// value in the set.
|
||||
func (val Value) LengthInt() int {
|
||||
val.assertUnmarked()
|
||||
if val.Type().IsTupleType() {
|
||||
@ -995,6 +1064,15 @@ func (val Value) LengthInt() int {
|
||||
return len(val.v.([]interface{}))
|
||||
|
||||
case val.ty.IsSetType():
|
||||
// NOTE: This is technically not correct in cases where the set
|
||||
// contains unknown values, because in that case we can't know how
|
||||
// many known values those unknown values are standing in for -- they
|
||||
// might coalesce with other values once known.
|
||||
//
|
||||
// However, this incorrect behavior is preserved for backward
|
||||
// compatibility with callers that were relying on LengthInt rather
|
||||
// than calling Length. Instead of panicking when a set contains an
|
||||
// unknown value, LengthInt returns the largest possible length.
|
||||
return val.v.(set.Set).Length()
|
||||
|
||||
case val.ty.IsMapType():
|
||||
|
Reference in New Issue
Block a user