1*4947cdc7SCole Faust// Copyright 2017 The Bazel Authors. All rights reserved. 2*4947cdc7SCole Faust// Use of this source code is governed by a BSD-style 3*4947cdc7SCole Faust// license that can be found in the LICENSE file. 4*4947cdc7SCole Faust 5*4947cdc7SCole Faustpackage starlark 6*4947cdc7SCole Faust 7*4947cdc7SCole Faustimport ( 8*4947cdc7SCole Faust "fmt" 9*4947cdc7SCole Faust "math" 10*4947cdc7SCole Faust "math/big" 11*4947cdc7SCole Faust "reflect" 12*4947cdc7SCole Faust "strconv" 13*4947cdc7SCole Faust 14*4947cdc7SCole Faust "go.starlark.net/syntax" 15*4947cdc7SCole Faust) 16*4947cdc7SCole Faust 17*4947cdc7SCole Faust// Int is the type of a Starlark int. 18*4947cdc7SCole Faust// 19*4947cdc7SCole Faust// The zero value is not a legal value; use MakeInt(0). 20*4947cdc7SCole Fausttype Int struct{ impl intImpl } 21*4947cdc7SCole Faust 22*4947cdc7SCole Faust// --- high-level accessors --- 23*4947cdc7SCole Faust 24*4947cdc7SCole Faust// MakeInt returns a Starlark int for the specified signed integer. 25*4947cdc7SCole Faustfunc MakeInt(x int) Int { return MakeInt64(int64(x)) } 26*4947cdc7SCole Faust 27*4947cdc7SCole Faust// MakeInt64 returns a Starlark int for the specified int64. 28*4947cdc7SCole Faustfunc MakeInt64(x int64) Int { 29*4947cdc7SCole Faust if math.MinInt32 <= x && x <= math.MaxInt32 { 30*4947cdc7SCole Faust return makeSmallInt(x) 31*4947cdc7SCole Faust } 32*4947cdc7SCole Faust return makeBigInt(big.NewInt(x)) 33*4947cdc7SCole Faust} 34*4947cdc7SCole Faust 35*4947cdc7SCole Faust// MakeUint returns a Starlark int for the specified unsigned integer. 36*4947cdc7SCole Faustfunc MakeUint(x uint) Int { return MakeUint64(uint64(x)) } 37*4947cdc7SCole Faust 38*4947cdc7SCole Faust// MakeUint64 returns a Starlark int for the specified uint64. 39*4947cdc7SCole Faustfunc MakeUint64(x uint64) Int { 40*4947cdc7SCole Faust if x <= math.MaxInt32 { 41*4947cdc7SCole Faust return makeSmallInt(int64(x)) 42*4947cdc7SCole Faust } 43*4947cdc7SCole Faust return makeBigInt(new(big.Int).SetUint64(x)) 44*4947cdc7SCole Faust} 45*4947cdc7SCole Faust 46*4947cdc7SCole Faust// MakeBigInt returns a Starlark int for the specified big.Int. 47*4947cdc7SCole Faust// The new Int value will contain a copy of x. The caller is safe to modify x. 48*4947cdc7SCole Faustfunc MakeBigInt(x *big.Int) Int { 49*4947cdc7SCole Faust if n := x.BitLen(); n < 32 || n == 32 && x.Int64() == math.MinInt32 { 50*4947cdc7SCole Faust return makeSmallInt(x.Int64()) 51*4947cdc7SCole Faust } 52*4947cdc7SCole Faust z := new(big.Int).Set(x) 53*4947cdc7SCole Faust return makeBigInt(z) 54*4947cdc7SCole Faust} 55*4947cdc7SCole Faust 56*4947cdc7SCole Faustvar ( 57*4947cdc7SCole Faust zero, one = makeSmallInt(0), makeSmallInt(1) 58*4947cdc7SCole Faust oneBig = big.NewInt(1) 59*4947cdc7SCole Faust 60*4947cdc7SCole Faust _ HasUnary = Int{} 61*4947cdc7SCole Faust) 62*4947cdc7SCole Faust 63*4947cdc7SCole Faust// Unary implements the operations +int, -int, and ~int. 64*4947cdc7SCole Faustfunc (i Int) Unary(op syntax.Token) (Value, error) { 65*4947cdc7SCole Faust switch op { 66*4947cdc7SCole Faust case syntax.MINUS: 67*4947cdc7SCole Faust return zero.Sub(i), nil 68*4947cdc7SCole Faust case syntax.PLUS: 69*4947cdc7SCole Faust return i, nil 70*4947cdc7SCole Faust case syntax.TILDE: 71*4947cdc7SCole Faust return i.Not(), nil 72*4947cdc7SCole Faust } 73*4947cdc7SCole Faust return nil, nil 74*4947cdc7SCole Faust} 75*4947cdc7SCole Faust 76*4947cdc7SCole Faust// Int64 returns the value as an int64. 77*4947cdc7SCole Faust// If it is not exactly representable the result is undefined and ok is false. 78*4947cdc7SCole Faustfunc (i Int) Int64() (_ int64, ok bool) { 79*4947cdc7SCole Faust iSmall, iBig := i.get() 80*4947cdc7SCole Faust if iBig != nil { 81*4947cdc7SCole Faust x, acc := bigintToInt64(iBig) 82*4947cdc7SCole Faust if acc != big.Exact { 83*4947cdc7SCole Faust return // inexact 84*4947cdc7SCole Faust } 85*4947cdc7SCole Faust return x, true 86*4947cdc7SCole Faust } 87*4947cdc7SCole Faust return iSmall, true 88*4947cdc7SCole Faust} 89*4947cdc7SCole Faust 90*4947cdc7SCole Faust// BigInt returns a new big.Int with the same value as the Int. 91*4947cdc7SCole Faustfunc (i Int) BigInt() *big.Int { 92*4947cdc7SCole Faust iSmall, iBig := i.get() 93*4947cdc7SCole Faust if iBig != nil { 94*4947cdc7SCole Faust return new(big.Int).Set(iBig) 95*4947cdc7SCole Faust } 96*4947cdc7SCole Faust return big.NewInt(iSmall) 97*4947cdc7SCole Faust} 98*4947cdc7SCole Faust 99*4947cdc7SCole Faust// bigInt returns the value as a big.Int. 100*4947cdc7SCole Faust// It differs from BigInt in that this method returns the actual 101*4947cdc7SCole Faust// reference and any modification will change the state of i. 102*4947cdc7SCole Faustfunc (i Int) bigInt() *big.Int { 103*4947cdc7SCole Faust iSmall, iBig := i.get() 104*4947cdc7SCole Faust if iBig != nil { 105*4947cdc7SCole Faust return iBig 106*4947cdc7SCole Faust } 107*4947cdc7SCole Faust return big.NewInt(iSmall) 108*4947cdc7SCole Faust} 109*4947cdc7SCole Faust 110*4947cdc7SCole Faust// Uint64 returns the value as a uint64. 111*4947cdc7SCole Faust// If it is not exactly representable the result is undefined and ok is false. 112*4947cdc7SCole Faustfunc (i Int) Uint64() (_ uint64, ok bool) { 113*4947cdc7SCole Faust iSmall, iBig := i.get() 114*4947cdc7SCole Faust if iBig != nil { 115*4947cdc7SCole Faust x, acc := bigintToUint64(iBig) 116*4947cdc7SCole Faust if acc != big.Exact { 117*4947cdc7SCole Faust return // inexact 118*4947cdc7SCole Faust } 119*4947cdc7SCole Faust return x, true 120*4947cdc7SCole Faust } 121*4947cdc7SCole Faust if iSmall < 0 { 122*4947cdc7SCole Faust return // inexact 123*4947cdc7SCole Faust } 124*4947cdc7SCole Faust return uint64(iSmall), true 125*4947cdc7SCole Faust} 126*4947cdc7SCole Faust 127*4947cdc7SCole Faust// The math/big API should provide this function. 128*4947cdc7SCole Faustfunc bigintToInt64(i *big.Int) (int64, big.Accuracy) { 129*4947cdc7SCole Faust sign := i.Sign() 130*4947cdc7SCole Faust if sign > 0 { 131*4947cdc7SCole Faust if i.Cmp(maxint64) > 0 { 132*4947cdc7SCole Faust return math.MaxInt64, big.Below 133*4947cdc7SCole Faust } 134*4947cdc7SCole Faust } else if sign < 0 { 135*4947cdc7SCole Faust if i.Cmp(minint64) < 0 { 136*4947cdc7SCole Faust return math.MinInt64, big.Above 137*4947cdc7SCole Faust } 138*4947cdc7SCole Faust } 139*4947cdc7SCole Faust return i.Int64(), big.Exact 140*4947cdc7SCole Faust} 141*4947cdc7SCole Faust 142*4947cdc7SCole Faust// The math/big API should provide this function. 143*4947cdc7SCole Faustfunc bigintToUint64(i *big.Int) (uint64, big.Accuracy) { 144*4947cdc7SCole Faust sign := i.Sign() 145*4947cdc7SCole Faust if sign > 0 { 146*4947cdc7SCole Faust if i.BitLen() > 64 { 147*4947cdc7SCole Faust return math.MaxUint64, big.Below 148*4947cdc7SCole Faust } 149*4947cdc7SCole Faust } else if sign < 0 { 150*4947cdc7SCole Faust return 0, big.Above 151*4947cdc7SCole Faust } 152*4947cdc7SCole Faust return i.Uint64(), big.Exact 153*4947cdc7SCole Faust} 154*4947cdc7SCole Faust 155*4947cdc7SCole Faustvar ( 156*4947cdc7SCole Faust minint64 = new(big.Int).SetInt64(math.MinInt64) 157*4947cdc7SCole Faust maxint64 = new(big.Int).SetInt64(math.MaxInt64) 158*4947cdc7SCole Faust) 159*4947cdc7SCole Faust 160*4947cdc7SCole Faustfunc (i Int) Format(s fmt.State, ch rune) { 161*4947cdc7SCole Faust iSmall, iBig := i.get() 162*4947cdc7SCole Faust if iBig != nil { 163*4947cdc7SCole Faust iBig.Format(s, ch) 164*4947cdc7SCole Faust return 165*4947cdc7SCole Faust } 166*4947cdc7SCole Faust big.NewInt(iSmall).Format(s, ch) 167*4947cdc7SCole Faust} 168*4947cdc7SCole Faustfunc (i Int) String() string { 169*4947cdc7SCole Faust iSmall, iBig := i.get() 170*4947cdc7SCole Faust if iBig != nil { 171*4947cdc7SCole Faust return iBig.Text(10) 172*4947cdc7SCole Faust } 173*4947cdc7SCole Faust return strconv.FormatInt(iSmall, 10) 174*4947cdc7SCole Faust} 175*4947cdc7SCole Faustfunc (i Int) Type() string { return "int" } 176*4947cdc7SCole Faustfunc (i Int) Freeze() {} // immutable 177*4947cdc7SCole Faustfunc (i Int) Truth() Bool { return i.Sign() != 0 } 178*4947cdc7SCole Faustfunc (i Int) Hash() (uint32, error) { 179*4947cdc7SCole Faust iSmall, iBig := i.get() 180*4947cdc7SCole Faust var lo big.Word 181*4947cdc7SCole Faust if iBig != nil { 182*4947cdc7SCole Faust lo = iBig.Bits()[0] 183*4947cdc7SCole Faust } else { 184*4947cdc7SCole Faust lo = big.Word(iSmall) 185*4947cdc7SCole Faust } 186*4947cdc7SCole Faust return 12582917 * uint32(lo+3), nil 187*4947cdc7SCole Faust} 188*4947cdc7SCole Faustfunc (x Int) CompareSameType(op syntax.Token, v Value, depth int) (bool, error) { 189*4947cdc7SCole Faust y := v.(Int) 190*4947cdc7SCole Faust xSmall, xBig := x.get() 191*4947cdc7SCole Faust ySmall, yBig := y.get() 192*4947cdc7SCole Faust if xBig != nil || yBig != nil { 193*4947cdc7SCole Faust return threeway(op, x.bigInt().Cmp(y.bigInt())), nil 194*4947cdc7SCole Faust } 195*4947cdc7SCole Faust return threeway(op, signum64(xSmall-ySmall)), nil 196*4947cdc7SCole Faust} 197*4947cdc7SCole Faust 198*4947cdc7SCole Faust// Float returns the float value nearest i. 199*4947cdc7SCole Faustfunc (i Int) Float() Float { 200*4947cdc7SCole Faust iSmall, iBig := i.get() 201*4947cdc7SCole Faust if iBig != nil { 202*4947cdc7SCole Faust f, _ := new(big.Float).SetInt(iBig).Float64() 203*4947cdc7SCole Faust return Float(f) 204*4947cdc7SCole Faust } 205*4947cdc7SCole Faust return Float(iSmall) 206*4947cdc7SCole Faust} 207*4947cdc7SCole Faust 208*4947cdc7SCole Faust// finiteFloat returns the finite float value nearest i, 209*4947cdc7SCole Faust// or an error if the magnitude is too large. 210*4947cdc7SCole Faustfunc (i Int) finiteFloat() (Float, error) { 211*4947cdc7SCole Faust f := i.Float() 212*4947cdc7SCole Faust if math.IsInf(float64(f), 0) { 213*4947cdc7SCole Faust return 0, fmt.Errorf("int too large to convert to float") 214*4947cdc7SCole Faust } 215*4947cdc7SCole Faust return f, nil 216*4947cdc7SCole Faust} 217*4947cdc7SCole Faust 218*4947cdc7SCole Faustfunc (x Int) Sign() int { 219*4947cdc7SCole Faust xSmall, xBig := x.get() 220*4947cdc7SCole Faust if xBig != nil { 221*4947cdc7SCole Faust return xBig.Sign() 222*4947cdc7SCole Faust } 223*4947cdc7SCole Faust return signum64(xSmall) 224*4947cdc7SCole Faust} 225*4947cdc7SCole Faust 226*4947cdc7SCole Faustfunc (x Int) Add(y Int) Int { 227*4947cdc7SCole Faust xSmall, xBig := x.get() 228*4947cdc7SCole Faust ySmall, yBig := y.get() 229*4947cdc7SCole Faust if xBig != nil || yBig != nil { 230*4947cdc7SCole Faust return MakeBigInt(new(big.Int).Add(x.bigInt(), y.bigInt())) 231*4947cdc7SCole Faust } 232*4947cdc7SCole Faust return MakeInt64(xSmall + ySmall) 233*4947cdc7SCole Faust} 234*4947cdc7SCole Faustfunc (x Int) Sub(y Int) Int { 235*4947cdc7SCole Faust xSmall, xBig := x.get() 236*4947cdc7SCole Faust ySmall, yBig := y.get() 237*4947cdc7SCole Faust if xBig != nil || yBig != nil { 238*4947cdc7SCole Faust return MakeBigInt(new(big.Int).Sub(x.bigInt(), y.bigInt())) 239*4947cdc7SCole Faust } 240*4947cdc7SCole Faust return MakeInt64(xSmall - ySmall) 241*4947cdc7SCole Faust} 242*4947cdc7SCole Faustfunc (x Int) Mul(y Int) Int { 243*4947cdc7SCole Faust xSmall, xBig := x.get() 244*4947cdc7SCole Faust ySmall, yBig := y.get() 245*4947cdc7SCole Faust if xBig != nil || yBig != nil { 246*4947cdc7SCole Faust return MakeBigInt(new(big.Int).Mul(x.bigInt(), y.bigInt())) 247*4947cdc7SCole Faust } 248*4947cdc7SCole Faust return MakeInt64(xSmall * ySmall) 249*4947cdc7SCole Faust} 250*4947cdc7SCole Faustfunc (x Int) Or(y Int) Int { 251*4947cdc7SCole Faust xSmall, xBig := x.get() 252*4947cdc7SCole Faust ySmall, yBig := y.get() 253*4947cdc7SCole Faust if xBig != nil || yBig != nil { 254*4947cdc7SCole Faust return MakeBigInt(new(big.Int).Or(x.bigInt(), y.bigInt())) 255*4947cdc7SCole Faust } 256*4947cdc7SCole Faust return makeSmallInt(xSmall | ySmall) 257*4947cdc7SCole Faust} 258*4947cdc7SCole Faustfunc (x Int) And(y Int) Int { 259*4947cdc7SCole Faust xSmall, xBig := x.get() 260*4947cdc7SCole Faust ySmall, yBig := y.get() 261*4947cdc7SCole Faust if xBig != nil || yBig != nil { 262*4947cdc7SCole Faust return MakeBigInt(new(big.Int).And(x.bigInt(), y.bigInt())) 263*4947cdc7SCole Faust } 264*4947cdc7SCole Faust return makeSmallInt(xSmall & ySmall) 265*4947cdc7SCole Faust} 266*4947cdc7SCole Faustfunc (x Int) Xor(y Int) Int { 267*4947cdc7SCole Faust xSmall, xBig := x.get() 268*4947cdc7SCole Faust ySmall, yBig := y.get() 269*4947cdc7SCole Faust if xBig != nil || yBig != nil { 270*4947cdc7SCole Faust return MakeBigInt(new(big.Int).Xor(x.bigInt(), y.bigInt())) 271*4947cdc7SCole Faust } 272*4947cdc7SCole Faust return makeSmallInt(xSmall ^ ySmall) 273*4947cdc7SCole Faust} 274*4947cdc7SCole Faustfunc (x Int) Not() Int { 275*4947cdc7SCole Faust xSmall, xBig := x.get() 276*4947cdc7SCole Faust if xBig != nil { 277*4947cdc7SCole Faust return MakeBigInt(new(big.Int).Not(xBig)) 278*4947cdc7SCole Faust } 279*4947cdc7SCole Faust return makeSmallInt(^xSmall) 280*4947cdc7SCole Faust} 281*4947cdc7SCole Faustfunc (x Int) Lsh(y uint) Int { return MakeBigInt(new(big.Int).Lsh(x.bigInt(), y)) } 282*4947cdc7SCole Faustfunc (x Int) Rsh(y uint) Int { return MakeBigInt(new(big.Int).Rsh(x.bigInt(), y)) } 283*4947cdc7SCole Faust 284*4947cdc7SCole Faust// Precondition: y is nonzero. 285*4947cdc7SCole Faustfunc (x Int) Div(y Int) Int { 286*4947cdc7SCole Faust xSmall, xBig := x.get() 287*4947cdc7SCole Faust ySmall, yBig := y.get() 288*4947cdc7SCole Faust // http://python-history.blogspot.com/2010/08/why-pythons-integer-division-floors.html 289*4947cdc7SCole Faust if xBig != nil || yBig != nil { 290*4947cdc7SCole Faust xb, yb := x.bigInt(), y.bigInt() 291*4947cdc7SCole Faust 292*4947cdc7SCole Faust var quo, rem big.Int 293*4947cdc7SCole Faust quo.QuoRem(xb, yb, &rem) 294*4947cdc7SCole Faust if (xb.Sign() < 0) != (yb.Sign() < 0) && rem.Sign() != 0 { 295*4947cdc7SCole Faust quo.Sub(&quo, oneBig) 296*4947cdc7SCole Faust } 297*4947cdc7SCole Faust return MakeBigInt(&quo) 298*4947cdc7SCole Faust } 299*4947cdc7SCole Faust quo := xSmall / ySmall 300*4947cdc7SCole Faust rem := xSmall % ySmall 301*4947cdc7SCole Faust if (xSmall < 0) != (ySmall < 0) && rem != 0 { 302*4947cdc7SCole Faust quo -= 1 303*4947cdc7SCole Faust } 304*4947cdc7SCole Faust return MakeInt64(quo) 305*4947cdc7SCole Faust} 306*4947cdc7SCole Faust 307*4947cdc7SCole Faust// Precondition: y is nonzero. 308*4947cdc7SCole Faustfunc (x Int) Mod(y Int) Int { 309*4947cdc7SCole Faust xSmall, xBig := x.get() 310*4947cdc7SCole Faust ySmall, yBig := y.get() 311*4947cdc7SCole Faust if xBig != nil || yBig != nil { 312*4947cdc7SCole Faust xb, yb := x.bigInt(), y.bigInt() 313*4947cdc7SCole Faust 314*4947cdc7SCole Faust var quo, rem big.Int 315*4947cdc7SCole Faust quo.QuoRem(xb, yb, &rem) 316*4947cdc7SCole Faust if (xb.Sign() < 0) != (yb.Sign() < 0) && rem.Sign() != 0 { 317*4947cdc7SCole Faust rem.Add(&rem, yb) 318*4947cdc7SCole Faust } 319*4947cdc7SCole Faust return MakeBigInt(&rem) 320*4947cdc7SCole Faust } 321*4947cdc7SCole Faust rem := xSmall % ySmall 322*4947cdc7SCole Faust if (xSmall < 0) != (ySmall < 0) && rem != 0 { 323*4947cdc7SCole Faust rem += ySmall 324*4947cdc7SCole Faust } 325*4947cdc7SCole Faust return makeSmallInt(rem) 326*4947cdc7SCole Faust} 327*4947cdc7SCole Faust 328*4947cdc7SCole Faustfunc (i Int) rational() *big.Rat { 329*4947cdc7SCole Faust iSmall, iBig := i.get() 330*4947cdc7SCole Faust if iBig != nil { 331*4947cdc7SCole Faust return new(big.Rat).SetInt(iBig) 332*4947cdc7SCole Faust } 333*4947cdc7SCole Faust return new(big.Rat).SetInt64(iSmall) 334*4947cdc7SCole Faust} 335*4947cdc7SCole Faust 336*4947cdc7SCole Faust// AsInt32 returns the value of x if is representable as an int32. 337*4947cdc7SCole Faustfunc AsInt32(x Value) (int, error) { 338*4947cdc7SCole Faust i, ok := x.(Int) 339*4947cdc7SCole Faust if !ok { 340*4947cdc7SCole Faust return 0, fmt.Errorf("got %s, want int", x.Type()) 341*4947cdc7SCole Faust } 342*4947cdc7SCole Faust iSmall, iBig := i.get() 343*4947cdc7SCole Faust if iBig != nil { 344*4947cdc7SCole Faust return 0, fmt.Errorf("%s out of range", i) 345*4947cdc7SCole Faust } 346*4947cdc7SCole Faust return int(iSmall), nil 347*4947cdc7SCole Faust} 348*4947cdc7SCole Faust 349*4947cdc7SCole Faust// AsInt sets *ptr to the value of Starlark int x, if it is exactly representable, 350*4947cdc7SCole Faust// otherwise it returns an error. 351*4947cdc7SCole Faust// The type of ptr must be one of the pointer types *int, *int8, *int16, *int32, or *int64, 352*4947cdc7SCole Faust// or one of their unsigned counterparts including *uintptr. 353*4947cdc7SCole Faustfunc AsInt(x Value, ptr interface{}) error { 354*4947cdc7SCole Faust xint, ok := x.(Int) 355*4947cdc7SCole Faust if !ok { 356*4947cdc7SCole Faust return fmt.Errorf("got %s, want int", x.Type()) 357*4947cdc7SCole Faust } 358*4947cdc7SCole Faust 359*4947cdc7SCole Faust bits := reflect.TypeOf(ptr).Elem().Size() * 8 360*4947cdc7SCole Faust switch ptr.(type) { 361*4947cdc7SCole Faust case *int, *int8, *int16, *int32, *int64: 362*4947cdc7SCole Faust i, ok := xint.Int64() 363*4947cdc7SCole Faust if !ok || bits < 64 && !(-1<<(bits-1) <= i && i < 1<<(bits-1)) { 364*4947cdc7SCole Faust return fmt.Errorf("%s out of range (want value in signed %d-bit range)", xint, bits) 365*4947cdc7SCole Faust } 366*4947cdc7SCole Faust switch ptr := ptr.(type) { 367*4947cdc7SCole Faust case *int: 368*4947cdc7SCole Faust *ptr = int(i) 369*4947cdc7SCole Faust case *int8: 370*4947cdc7SCole Faust *ptr = int8(i) 371*4947cdc7SCole Faust case *int16: 372*4947cdc7SCole Faust *ptr = int16(i) 373*4947cdc7SCole Faust case *int32: 374*4947cdc7SCole Faust *ptr = int32(i) 375*4947cdc7SCole Faust case *int64: 376*4947cdc7SCole Faust *ptr = int64(i) 377*4947cdc7SCole Faust } 378*4947cdc7SCole Faust 379*4947cdc7SCole Faust case *uint, *uint8, *uint16, *uint32, *uint64, *uintptr: 380*4947cdc7SCole Faust i, ok := xint.Uint64() 381*4947cdc7SCole Faust if !ok || bits < 64 && i >= 1<<bits { 382*4947cdc7SCole Faust return fmt.Errorf("%s out of range (want value in unsigned %d-bit range)", xint, bits) 383*4947cdc7SCole Faust } 384*4947cdc7SCole Faust switch ptr := ptr.(type) { 385*4947cdc7SCole Faust case *uint: 386*4947cdc7SCole Faust *ptr = uint(i) 387*4947cdc7SCole Faust case *uint8: 388*4947cdc7SCole Faust *ptr = uint8(i) 389*4947cdc7SCole Faust case *uint16: 390*4947cdc7SCole Faust *ptr = uint16(i) 391*4947cdc7SCole Faust case *uint32: 392*4947cdc7SCole Faust *ptr = uint32(i) 393*4947cdc7SCole Faust case *uint64: 394*4947cdc7SCole Faust *ptr = uint64(i) 395*4947cdc7SCole Faust case *uintptr: 396*4947cdc7SCole Faust *ptr = uintptr(i) 397*4947cdc7SCole Faust } 398*4947cdc7SCole Faust default: 399*4947cdc7SCole Faust panic(fmt.Sprintf("invalid argument type: %T", ptr)) 400*4947cdc7SCole Faust } 401*4947cdc7SCole Faust return nil 402*4947cdc7SCole Faust} 403*4947cdc7SCole Faust 404*4947cdc7SCole Faust// NumberToInt converts a number x to an integer value. 405*4947cdc7SCole Faust// An int is returned unchanged, a float is truncated towards zero. 406*4947cdc7SCole Faust// NumberToInt reports an error for all other values. 407*4947cdc7SCole Faustfunc NumberToInt(x Value) (Int, error) { 408*4947cdc7SCole Faust switch x := x.(type) { 409*4947cdc7SCole Faust case Int: 410*4947cdc7SCole Faust return x, nil 411*4947cdc7SCole Faust case Float: 412*4947cdc7SCole Faust f := float64(x) 413*4947cdc7SCole Faust if math.IsInf(f, 0) { 414*4947cdc7SCole Faust return zero, fmt.Errorf("cannot convert float infinity to integer") 415*4947cdc7SCole Faust } else if math.IsNaN(f) { 416*4947cdc7SCole Faust return zero, fmt.Errorf("cannot convert float NaN to integer") 417*4947cdc7SCole Faust } 418*4947cdc7SCole Faust return finiteFloatToInt(x), nil 419*4947cdc7SCole Faust 420*4947cdc7SCole Faust } 421*4947cdc7SCole Faust return zero, fmt.Errorf("cannot convert %s to int", x.Type()) 422*4947cdc7SCole Faust} 423*4947cdc7SCole Faust 424*4947cdc7SCole Faust// finiteFloatToInt converts f to an Int, truncating towards zero. 425*4947cdc7SCole Faust// f must be finite. 426*4947cdc7SCole Faustfunc finiteFloatToInt(f Float) Int { 427*4947cdc7SCole Faust if math.MinInt64 <= f && f <= math.MaxInt64 { 428*4947cdc7SCole Faust // small values 429*4947cdc7SCole Faust return MakeInt64(int64(f)) 430*4947cdc7SCole Faust } 431*4947cdc7SCole Faust rat := f.rational() 432*4947cdc7SCole Faust if rat == nil { 433*4947cdc7SCole Faust panic(f) // non-finite 434*4947cdc7SCole Faust } 435*4947cdc7SCole Faust return MakeBigInt(new(big.Int).Div(rat.Num(), rat.Denom())) 436*4947cdc7SCole Faust} 437