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.go347
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")
+}