diff options
Diffstat (limited to 'src/pkg/go/types/const.go')
-rw-r--r-- | src/pkg/go/types/const.go | 718 |
1 files changed, 0 insertions, 718 deletions
diff --git a/src/pkg/go/types/const.go b/src/pkg/go/types/const.go deleted file mode 100644 index 503652e75..000000000 --- a/src/pkg/go/types/const.go +++ /dev/null @@ -1,718 +0,0 @@ -// Copyright 2011 The Go Authors. All rights reserved. -// Use of this source code is governed by a BSD-style -// license that can be found in the LICENSE file. - -// This file implements operations on constant values. - -package types - -import ( - "fmt" - "go/token" - "math/big" - "strconv" -) - -// TODO(gri) At the moment, constants are different types -// passed around as interface{} values. Introduce a Const -// interface and use methods instead of xConst functions. - -// Representation of constant values. -// -// bool -> bool (true, false) -// numeric -> int64, *big.Int, *big.Rat, Complex (ordered by increasing data structure "size") -// string -> string -// nil -> NilType (nilConst) -// -// Numeric constants are normalized after each operation such -// that they are represented by the "smallest" data structure -// required to represent the constant, independent of actual -// type. Non-numeric constants are always normalized. - -// Representation of complex numbers. -type Complex struct { - Re, Im *big.Rat -} - -func (c Complex) String() string { - if c.Re.Sign() == 0 { - return fmt.Sprintf("%si", c.Im) - } - // normalized complex values always have an imaginary part - return fmt.Sprintf("(%s + %si)", c.Re, c.Im) -} - -// Representation of nil. -type NilType struct{} - -func (NilType) String() string { - return "nil" -} - -// Frequently used values. -var ( - nilConst = NilType{} - zeroConst = int64(0) -) - -// int64 bounds -var ( - minInt64 = big.NewInt(-1 << 63) - maxInt64 = big.NewInt(1<<63 - 1) -) - -// normalizeIntConst returns the smallest constant representation -// for the specific value of x; either an int64 or a *big.Int value. -// -func normalizeIntConst(x *big.Int) interface{} { - if minInt64.Cmp(x) <= 0 && x.Cmp(maxInt64) <= 0 { - return x.Int64() - } - return x -} - -// normalizeRatConst returns the smallest constant representation -// for the specific value of x; either an int64, *big.Int, -// or *big.Rat value. -// -func normalizeRatConst(x *big.Rat) interface{} { - if x.IsInt() { - return normalizeIntConst(x.Num()) - } - return x -} - -// newComplex returns the smallest constant representation -// for the specific value re + im*i; either an int64, *big.Int, -// *big.Rat, or complex value. -// -func newComplex(re, im *big.Rat) interface{} { - if im.Sign() == 0 { - return normalizeRatConst(re) - } - return Complex{re, im} -} - -// makeRuneConst returns the int64 code point for the rune literal -// lit. The result is nil if lit is not a correct rune literal. -// -func makeRuneConst(lit string) interface{} { - if n := len(lit); n >= 2 { - if code, _, _, err := strconv.UnquoteChar(lit[1:n-1], '\''); err == nil { - return int64(code) - } - } - return nil -} - -// makeRuneConst returns the smallest integer constant representation -// (int64, *big.Int) for the integer literal lit. The result is nil if -// lit is not a correct integer literal. -// -func makeIntConst(lit string) interface{} { - if x, err := strconv.ParseInt(lit, 0, 64); err == nil { - return x - } - if x, ok := new(big.Int).SetString(lit, 0); ok { - return x - } - return nil -} - -// makeFloatConst returns the smallest floating-point constant representation -// (int64, *big.Int, *big.Rat) for the floating-point literal lit. The result -// is nil if lit is not a correct floating-point literal. -// -func makeFloatConst(lit string) interface{} { - if x, ok := new(big.Rat).SetString(lit); ok { - return normalizeRatConst(x) - } - return nil -} - -// makeComplexConst returns the complex constant representation (Complex) for -// the imaginary literal lit. The result is nil if lit is not a correct imaginary -// literal. -// -func makeComplexConst(lit string) interface{} { - n := len(lit) - if n > 0 && lit[n-1] == 'i' { - if im, ok := new(big.Rat).SetString(lit[0 : n-1]); ok { - return newComplex(big.NewRat(0, 1), im) - } - } - return nil -} - -// makeStringConst returns the string constant representation (string) for -// the string literal lit. The result is nil if lit is not a correct string -// literal. -// -func makeStringConst(lit string) interface{} { - if s, err := strconv.Unquote(lit); err == nil { - return s - } - return nil -} - -// toImagConst returns the constant Complex(0, x) for a non-complex x. -func toImagConst(x interface{}) interface{} { - var im *big.Rat - switch x := x.(type) { - case int64: - im = big.NewRat(x, 1) - case *big.Int: - im = new(big.Rat).SetFrac(x, int1) - case *big.Rat: - im = x - default: - unreachable() - } - return Complex{rat0, im} -} - -// isZeroConst reports whether the value of constant x is 0. -// x must be normalized. -// -func isZeroConst(x interface{}) bool { - i, ok := x.(int64) // good enough since constants are normalized - return ok && i == 0 -} - -// isNegConst reports whether the value of constant x is < 0. -// x must be a non-complex numeric value. -// -func isNegConst(x interface{}) bool { - switch x := x.(type) { - case int64: - return x < 0 - case *big.Int: - return x.Sign() < 0 - case *big.Rat: - return x.Sign() < 0 - } - unreachable() - return false -} - -// isRepresentableConst reports whether the value of constant x can -// be represented as a value of the basic type Typ[as] without loss -// of precision. -// -func isRepresentableConst(x interface{}, ctxt *Context, as BasicKind) bool { - switch x := x.(type) { - case bool: - return as == Bool || as == UntypedBool - - case int64: - switch as { - case Int: - var s = uint(ctxt.sizeof(Typ[as])) * 8 - return int64(-1)<<(s-1) <= x && x <= int64(1)<<(s-1)-1 - case Int8: - const s = 8 - return -1<<(s-1) <= x && x <= 1<<(s-1)-1 - case Int16: - const s = 16 - return -1<<(s-1) <= x && x <= 1<<(s-1)-1 - case Int32: - const s = 32 - return -1<<(s-1) <= x && x <= 1<<(s-1)-1 - case Int64: - return true - case Uint, Uintptr: - var s = uint(ctxt.sizeof(Typ[as])) * 8 - return 0 <= x && x <= int64(1)<<(s-1)-1 - case Uint8: - const s = 8 - return 0 <= x && x <= 1<<s-1 - case Uint16: - const s = 16 - return 0 <= x && x <= 1<<s-1 - case Uint32: - const s = 32 - return 0 <= x && x <= 1<<s-1 - case Uint64: - return 0 <= x - case Float32: - return true // TODO(gri) fix this - case Float64: - return true // TODO(gri) fix this - case Complex64: - return true // TODO(gri) fix this - case Complex128: - return true // TODO(gri) fix this - case UntypedInt, UntypedFloat, UntypedComplex: - return true - } - - case *big.Int: - switch as { - case Uint, Uintptr: - var s = uint(ctxt.sizeof(Typ[as])) * 8 - return x.Sign() >= 0 && x.BitLen() <= int(s) - case Uint64: - return x.Sign() >= 0 && x.BitLen() <= 64 - case Float32: - return true // TODO(gri) fix this - case Float64: - return true // TODO(gri) fix this - case Complex64: - return true // TODO(gri) fix this - case Complex128: - return true // TODO(gri) fix this - case UntypedInt, UntypedFloat, UntypedComplex: - return true - } - - case *big.Rat: - switch as { - case Float32: - return true // TODO(gri) fix this - case Float64: - return true // TODO(gri) fix this - case Complex64: - return true // TODO(gri) fix this - case Complex128: - return true // TODO(gri) fix this - case UntypedFloat, UntypedComplex: - return true - } - - case Complex: - switch as { - case Complex64: - return true // TODO(gri) fix this - case Complex128: - return true // TODO(gri) fix this - case UntypedComplex: - return true - } - - case string: - return as == String || as == UntypedString - - case NilType: - return as == UntypedNil || as == UnsafePointer - - default: - unreachable() - } - - return false -} - -var ( - int1 = big.NewInt(1) - rat0 = big.NewRat(0, 1) -) - -// complexity returns a measure of representation complexity for constant x. -func complexity(x interface{}) int { - switch x.(type) { - case bool, string, NilType: - return 1 - case int64: - return 2 - case *big.Int: - return 3 - case *big.Rat: - return 4 - case Complex: - return 5 - } - unreachable() - return 0 -} - -// matchConst returns the matching representation (same type) with the -// smallest complexity for two constant values x and y. They must be -// of the same "kind" (boolean, numeric, string, or NilType). -// -func matchConst(x, y interface{}) (_, _ interface{}) { - if complexity(x) > complexity(y) { - y, x = matchConst(y, x) - return x, y - } - // complexity(x) <= complexity(y) - - switch x := x.(type) { - case bool, Complex, string, NilType: - return x, y - - case int64: - switch y := y.(type) { - case int64: - return x, y - case *big.Int: - return big.NewInt(x), y - case *big.Rat: - return big.NewRat(x, 1), y - case Complex: - return Complex{big.NewRat(x, 1), rat0}, y - } - - case *big.Int: - switch y := y.(type) { - case *big.Int: - return x, y - case *big.Rat: - return new(big.Rat).SetFrac(x, int1), y - case Complex: - return Complex{new(big.Rat).SetFrac(x, int1), rat0}, y - } - - case *big.Rat: - switch y := y.(type) { - case *big.Rat: - return x, y - case Complex: - return Complex{x, rat0}, y - } - } - - unreachable() - return nil, nil -} - -// is32bit reports whether x can be represented using 32 bits. -func is32bit(x int64) bool { - return -1<<31 <= x && x <= 1<<31-1 -} - -// is63bit reports whether x can be represented using 63 bits. -func is63bit(x int64) bool { - return -1<<62 <= x && x <= 1<<62-1 -} - -// unaryOpConst returns the result of the constant evaluation op x where x is of the given type. -func unaryOpConst(x interface{}, ctxt *Context, op token.Token, typ *Basic) interface{} { - switch op { - case token.ADD: - return x // nothing to do - case token.SUB: - switch x := x.(type) { - case int64: - if z := -x; z != x { - return z // no overflow - } - // overflow - need to convert to big.Int - return normalizeIntConst(new(big.Int).Neg(big.NewInt(x))) - case *big.Int: - return normalizeIntConst(new(big.Int).Neg(x)) - case *big.Rat: - return normalizeRatConst(new(big.Rat).Neg(x)) - case Complex: - return newComplex(new(big.Rat).Neg(x.Re), new(big.Rat).Neg(x.Im)) - } - case token.XOR: - var z big.Int - switch x := x.(type) { - case int64: - z.Not(big.NewInt(x)) - case *big.Int: - z.Not(x) - default: - unreachable() - } - // For unsigned types, the result will be negative and - // thus "too large": We must limit the result size to - // the type's size. - if typ.Info&IsUnsigned != 0 { - s := uint(ctxt.sizeof(typ)) * 8 - z.AndNot(&z, new(big.Int).Lsh(big.NewInt(-1), s)) // z &^= (-1)<<s - } - return normalizeIntConst(&z) - case token.NOT: - return !x.(bool) - } - unreachable() - return nil -} - -// binaryOpConst returns the result of the constant evaluation x op y; -// both operands must be of the same constant "kind" (boolean, numeric, or string). -// If typ is an integer type, division (op == token.QUO) is using integer division -// (and the result is guaranteed to be integer) rather than floating-point -// division. Division by zero leads to a run-time panic. -// -func binaryOpConst(x, y interface{}, op token.Token, typ *Basic) interface{} { - x, y = matchConst(x, y) - - switch x := x.(type) { - case bool: - y := y.(bool) - switch op { - case token.LAND: - return x && y - case token.LOR: - return x || y - } - - case int64: - y := y.(int64) - switch op { - case token.ADD: - // TODO(gri) can do better than this - if is63bit(x) && is63bit(y) { - return x + y - } - return normalizeIntConst(new(big.Int).Add(big.NewInt(x), big.NewInt(y))) - case token.SUB: - // TODO(gri) can do better than this - if is63bit(x) && is63bit(y) { - return x - y - } - return normalizeIntConst(new(big.Int).Sub(big.NewInt(x), big.NewInt(y))) - case token.MUL: - // TODO(gri) can do better than this - if is32bit(x) && is32bit(y) { - return x * y - } - return normalizeIntConst(new(big.Int).Mul(big.NewInt(x), big.NewInt(y))) - case token.REM: - return x % y - case token.QUO: - if typ.Info&IsInteger != 0 { - return x / y - } - return normalizeRatConst(new(big.Rat).SetFrac(big.NewInt(x), big.NewInt(y))) - case token.AND: - return x & y - case token.OR: - return x | y - case token.XOR: - return x ^ y - case token.AND_NOT: - return x &^ y - } - - case *big.Int: - y := y.(*big.Int) - var z big.Int - switch op { - case token.ADD: - z.Add(x, y) - case token.SUB: - z.Sub(x, y) - case token.MUL: - z.Mul(x, y) - case token.REM: - z.Rem(x, y) - case token.QUO: - if typ.Info&IsInteger != 0 { - z.Quo(x, y) - } else { - return normalizeRatConst(new(big.Rat).SetFrac(x, y)) - } - case token.AND: - z.And(x, y) - case token.OR: - z.Or(x, y) - case token.XOR: - z.Xor(x, y) - case token.AND_NOT: - z.AndNot(x, y) - default: - unreachable() - } - return normalizeIntConst(&z) - - case *big.Rat: - y := y.(*big.Rat) - var z big.Rat - switch op { - case token.ADD: - z.Add(x, y) - case token.SUB: - z.Sub(x, y) - case token.MUL: - z.Mul(x, y) - case token.QUO: - z.Quo(x, y) - default: - unreachable() - } - return normalizeRatConst(&z) - - case Complex: - y := y.(Complex) - a, b := x.Re, x.Im - c, d := y.Re, y.Im - var re, im big.Rat - switch op { - case token.ADD: - // (a+c) + i(b+d) - re.Add(a, c) - im.Add(b, d) - case token.SUB: - // (a-c) + i(b-d) - re.Sub(a, c) - im.Sub(b, d) - case token.MUL: - // (ac-bd) + i(bc+ad) - var ac, bd, bc, ad big.Rat - ac.Mul(a, c) - bd.Mul(b, d) - bc.Mul(b, c) - ad.Mul(a, d) - re.Sub(&ac, &bd) - im.Add(&bc, &ad) - case token.QUO: - // (ac+bd)/s + i(bc-ad)/s, with s = cc + dd - var ac, bd, bc, ad, s big.Rat - ac.Mul(a, c) - bd.Mul(b, d) - bc.Mul(b, c) - ad.Mul(a, d) - s.Add(c.Mul(c, c), d.Mul(d, d)) - re.Add(&ac, &bd) - re.Quo(&re, &s) - im.Sub(&bc, &ad) - im.Quo(&im, &s) - default: - unreachable() - } - return newComplex(&re, &im) - - case string: - if op == token.ADD { - return x + y.(string) - } - } - - unreachable() - return nil -} - -// shiftConst returns the result of the constant evaluation x op s -// where op is token.SHL or token.SHR (<< or >>). x must be an -// integer constant. -// -func shiftConst(x interface{}, s uint, op token.Token) interface{} { - switch x := x.(type) { - case int64: - switch op { - case token.SHL: - z := big.NewInt(x) - return normalizeIntConst(z.Lsh(z, s)) - case token.SHR: - return x >> s - } - - case *big.Int: - var z big.Int - switch op { - case token.SHL: - return normalizeIntConst(z.Lsh(x, s)) - case token.SHR: - return normalizeIntConst(z.Rsh(x, s)) - } - } - - unreachable() - return nil -} - -// compareConst returns the result of the constant comparison x op y; -// both operands must be of the same "kind" (boolean, numeric, string, -// or NilType). -// -func compareConst(x, y interface{}, op token.Token) (z bool) { - x, y = matchConst(x, y) - - // x == y => x == y - // x != y => x != y - // x > y => y < x - // x >= y => u <= x - swap := false - switch op { - case token.GTR: - swap = true - op = token.LSS - case token.GEQ: - swap = true - op = token.LEQ - } - - // x == y => x == y - // x != y => !(x == y) - // x < y => x < y - // x <= y => !(y < x) - negate := false - switch op { - case token.NEQ: - negate = true - op = token.EQL - case token.LEQ: - swap = !swap - negate = true - op = token.LSS - } - - if negate { - defer func() { z = !z }() - } - - if swap { - x, y = y, x - } - - switch x := x.(type) { - case bool: - if op == token.EQL { - return x == y.(bool) - } - - case int64: - y := y.(int64) - switch op { - case token.EQL: - return x == y - case token.LSS: - return x < y - } - - case *big.Int: - s := x.Cmp(y.(*big.Int)) - switch op { - case token.EQL: - return s == 0 - case token.LSS: - return s < 0 - } - - case *big.Rat: - s := x.Cmp(y.(*big.Rat)) - switch op { - case token.EQL: - return s == 0 - case token.LSS: - return s < 0 - } - - case Complex: - y := y.(Complex) - if op == token.EQL { - return x.Re.Cmp(y.Re) == 0 && x.Im.Cmp(y.Im) == 0 - } - - case string: - y := y.(string) - switch op { - case token.EQL: - return x == y - case token.LSS: - return x < y - } - - case NilType: - if op == token.EQL { - return x == y.(NilType) - } - } - - fmt.Printf("x = %s (%T), y = %s (%T)\n", x, x, y, y) - unreachable() - return -} |