diff options
Diffstat (limited to 'src/pkg/go/types/const.go')
-rw-r--r-- | src/pkg/go/types/const.go | 347 |
1 files changed, 347 insertions, 0 deletions
diff --git a/src/pkg/go/types/const.go b/src/pkg/go/types/const.go new file mode 100644 index 000000000..6fdc22f6b --- /dev/null +++ b/src/pkg/go/types/const.go @@ -0,0 +1,347 @@ +// 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 ideal constants. + +package types + +import ( + "big" + "go/token" + "strconv" +) + + +// TODO(gri) Consider changing the API so Const is an interface +// and operations on consts don't have to type switch. + +// A Const implements an ideal constant Value. +// The zero value z for a Const is not a valid constant value. +type Const struct { + // representation of constant values: + // ideal bool -> bool + // ideal int -> *big.Int + // ideal float -> *big.Rat + // ideal complex -> cmplx + // ideal string -> string + val interface{} +} + + +// Representation of complex values. +type cmplx struct { + re, im *big.Rat +} + + +func assert(cond bool) { + if !cond { + panic("go/types internal error: assertion failed") + } +} + + +// MakeConst makes an ideal constant from a literal +// token and the corresponding literal string. +func MakeConst(tok token.Token, lit string) Const { + switch tok { + case token.INT: + var x big.Int + _, ok := x.SetString(lit, 0) + assert(ok) + return Const{&x} + case token.FLOAT: + var y big.Rat + _, ok := y.SetString(lit) + assert(ok) + return Const{&y} + case token.IMAG: + assert(lit[len(lit)-1] == 'i') + var im big.Rat + _, ok := im.SetString(lit[0 : len(lit)-1]) + assert(ok) + return Const{cmplx{big.NewRat(0, 1), &im}} + case token.CHAR: + assert(lit[0] == '\'' && lit[len(lit)-1] == '\'') + code, _, _, err := strconv.UnquoteChar(lit[1:len(lit)-1], '\'') + assert(err == nil) + return Const{big.NewInt(int64(code))} + case token.STRING: + s, err := strconv.Unquote(lit) + assert(err == nil) + return Const{s} + } + panic("unreachable") +} + + +// MakeZero returns the zero constant for the given type. +func MakeZero(typ *Type) Const { + // TODO(gri) fix this + return Const{0} +} + + +// Match attempts to match the internal constant representations of x and y. +// If the attempt is successful, the result is the values of x and y, +// if necessary converted to have the same internal representation; otherwise +// the results are invalid. +func (x Const) Match(y Const) (u, v Const) { + switch a := x.val.(type) { + case bool: + if _, ok := y.val.(bool); ok { + u, v = x, y + } + case *big.Int: + switch y.val.(type) { + case *big.Int: + u, v = x, y + case *big.Rat: + var z big.Rat + z.SetInt(a) + u, v = Const{&z}, y + case cmplx: + var z big.Rat + z.SetInt(a) + u, v = Const{cmplx{&z, big.NewRat(0, 1)}}, y + } + case *big.Rat: + switch y.val.(type) { + case *big.Int: + v, u = y.Match(x) + case *big.Rat: + u, v = x, y + case cmplx: + u, v = Const{cmplx{a, big.NewRat(0, 0)}}, y + } + case cmplx: + switch y.val.(type) { + case *big.Int, *big.Rat: + v, u = y.Match(x) + case cmplx: + u, v = x, y + } + case string: + if _, ok := y.val.(string); ok { + u, v = x, y + } + default: + panic("unreachable") + } + return +} + + +// Convert attempts to convert the constant x to a given type. +// If the attempt is successful, the result is the new constant; +// otherwise the result is invalid. +func (x Const) Convert(typ *Type) Const { + // TODO(gri) implement this + switch x := x.val.(type) { + case bool: + case *big.Int: + case *big.Rat: + case cmplx: + case string: + } + return x +} + + +func (x Const) String() string { + switch x := x.val.(type) { + case bool: + if x { + return "true" + } + return "false" + case *big.Int: + return x.String() + case *big.Rat: + return x.FloatString(10) // 10 digits of precision after decimal point seems fine + case cmplx: + // TODO(gri) don't print 0 components + return x.re.FloatString(10) + " + " + x.im.FloatString(10) + "i" + case string: + return x + } + panic("unreachable") +} + + +func (x Const) UnaryOp(op token.Token) Const { + panic("unimplemented") +} + + +func (x Const) BinaryOp(op token.Token, y Const) Const { + var z interface{} + switch x := x.val.(type) { + case bool: + z = binaryBoolOp(x, op, y.val.(bool)) + case *big.Int: + z = binaryIntOp(x, op, y.val.(*big.Int)) + case *big.Rat: + z = binaryFloatOp(x, op, y.val.(*big.Rat)) + case cmplx: + z = binaryCmplxOp(x, op, y.val.(cmplx)) + case string: + z = binaryStringOp(x, op, y.val.(string)) + default: + panic("unreachable") + } + return Const{z} +} + + +func binaryBoolOp(x bool, op token.Token, y bool) interface{} { + switch op { + case token.EQL: + return x == y + case token.NEQ: + return x != y + } + panic("unreachable") +} + + +func binaryIntOp(x *big.Int, op token.Token, y *big.Int) interface{} { + var z big.Int + switch op { + case token.ADD: + return z.Add(x, y) + case token.SUB: + return z.Sub(x, y) + case token.MUL: + return z.Mul(x, y) + case token.QUO: + return z.Quo(x, y) + case token.REM: + return z.Rem(x, y) + case token.AND: + return z.And(x, y) + case token.OR: + return z.Or(x, y) + case token.XOR: + return z.Xor(x, y) + case token.AND_NOT: + return z.AndNot(x, y) + case token.SHL: + panic("unimplemented") + case token.SHR: + panic("unimplemented") + case token.EQL: + return x.Cmp(y) == 0 + case token.NEQ: + return x.Cmp(y) != 0 + case token.LSS: + return x.Cmp(y) < 0 + case token.LEQ: + return x.Cmp(y) <= 0 + case token.GTR: + return x.Cmp(y) > 0 + case token.GEQ: + return x.Cmp(y) >= 0 + } + panic("unreachable") +} + + +func binaryFloatOp(x *big.Rat, op token.Token, y *big.Rat) interface{} { + var z big.Rat + switch op { + case token.ADD: + return z.Add(x, y) + case token.SUB: + return z.Sub(x, y) + case token.MUL: + return z.Mul(x, y) + case token.QUO: + return z.Quo(x, y) + case token.EQL: + return x.Cmp(y) == 0 + case token.NEQ: + return x.Cmp(y) != 0 + case token.LSS: + return x.Cmp(y) < 0 + case token.LEQ: + return x.Cmp(y) <= 0 + case token.GTR: + return x.Cmp(y) > 0 + case token.GEQ: + return x.Cmp(y) >= 0 + } + panic("unreachable") +} + + +func binaryCmplxOp(x cmplx, op token.Token, y cmplx) interface{} { + a, b := x.re, x.im + c, d := y.re, y.im + switch op { + case token.ADD: + // (a+c) + i(b+d) + var re, im big.Rat + re.Add(a, c) + im.Add(b, d) + return cmplx{&re, &im} + case token.SUB: + // (a-c) + i(b-d) + var re, im big.Rat + re.Sub(a, c) + im.Sub(b, d) + return cmplx{&re, &im} + 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) + var re, im big.Rat + re.Sub(&ac, &bd) + im.Add(&bc, &ad) + return cmplx{&re, &im} + 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)) + var re, im big.Rat + re.Add(&ac, &bd) + re.Quo(&re, &s) + im.Sub(&bc, &ad) + im.Quo(&im, &s) + return cmplx{&re, &im} + case token.EQL: + return a.Cmp(c) == 0 && b.Cmp(d) == 0 + case token.NEQ: + return a.Cmp(c) != 0 || b.Cmp(d) != 0 + } + panic("unreachable") +} + + +func binaryStringOp(x string, op token.Token, y string) interface{} { + switch op { + case token.ADD: + return x + y + case token.EQL: + return x == y + case token.NEQ: + return x != y + case token.LSS: + return x < y + case token.LEQ: + return x <= y + case token.GTR: + return x > y + case token.GEQ: + return x >= y + } + panic("unreachable") +} |