summaryrefslogtreecommitdiff
path: root/src/pkg/go/types/const.go
diff options
context:
space:
mode:
Diffstat (limited to 'src/pkg/go/types/const.go')
-rw-r--r--src/pkg/go/types/const.go718
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
-}