OSDN Git Service

libgo: Update to weekly.2012-01-15.
[pf3gnuchains/gcc-fork.git] / libgo / go / exp / types / const.go
1 // Copyright 2011 The Go Authors. All rights reserved.
2 // Use of this source code is governed by a BSD-style
3 // license that can be found in the LICENSE file.
4
5 // This file implements operations on ideal constants.
6
7 package types
8
9 import (
10         "go/token"
11         "math/big"
12         "strconv"
13 )
14
15 // TODO(gri) Consider changing the API so Const is an interface
16 //           and operations on consts don't have to type switch.
17
18 // A Const implements an ideal constant Value.
19 // The zero value z for a Const is not a valid constant value.
20 type Const struct {
21         // representation of constant values:
22         // ideal bool     ->  bool
23         // ideal int      ->  *big.Int
24         // ideal float    ->  *big.Rat
25         // ideal complex  ->  cmplx
26         // ideal string   ->  string
27         val interface{}
28 }
29
30 // Representation of complex values.
31 type cmplx struct {
32         re, im *big.Rat
33 }
34
35 func assert(cond bool) {
36         if !cond {
37                 panic("go/types internal error: assertion failed")
38         }
39 }
40
41 // MakeConst makes an ideal constant from a literal
42 // token and the corresponding literal string.
43 func MakeConst(tok token.Token, lit string) Const {
44         switch tok {
45         case token.INT:
46                 var x big.Int
47                 _, ok := x.SetString(lit, 0)
48                 assert(ok)
49                 return Const{&x}
50         case token.FLOAT:
51                 var y big.Rat
52                 _, ok := y.SetString(lit)
53                 assert(ok)
54                 return Const{&y}
55         case token.IMAG:
56                 assert(lit[len(lit)-1] == 'i')
57                 var im big.Rat
58                 _, ok := im.SetString(lit[0 : len(lit)-1])
59                 assert(ok)
60                 return Const{cmplx{big.NewRat(0, 1), &im}}
61         case token.CHAR:
62                 assert(lit[0] == '\'' && lit[len(lit)-1] == '\'')
63                 code, _, _, err := strconv.UnquoteChar(lit[1:len(lit)-1], '\'')
64                 assert(err == nil)
65                 return Const{big.NewInt(int64(code))}
66         case token.STRING:
67                 s, err := strconv.Unquote(lit)
68                 assert(err == nil)
69                 return Const{s}
70         }
71         panic("unreachable")
72 }
73
74 // MakeZero returns the zero constant for the given type.
75 func MakeZero(typ *Type) Const {
76         // TODO(gri) fix this
77         return Const{0}
78 }
79
80 // Match attempts to match the internal constant representations of x and y.
81 // If the attempt is successful, the result is the values of x and y,
82 // if necessary converted to have the same internal representation; otherwise
83 // the results are invalid.
84 func (x Const) Match(y Const) (u, v Const) {
85         switch a := x.val.(type) {
86         case bool:
87                 if _, ok := y.val.(bool); ok {
88                         u, v = x, y
89                 }
90         case *big.Int:
91                 switch y.val.(type) {
92                 case *big.Int:
93                         u, v = x, y
94                 case *big.Rat:
95                         var z big.Rat
96                         z.SetInt(a)
97                         u, v = Const{&z}, y
98                 case cmplx:
99                         var z big.Rat
100                         z.SetInt(a)
101                         u, v = Const{cmplx{&z, big.NewRat(0, 1)}}, y
102                 }
103         case *big.Rat:
104                 switch y.val.(type) {
105                 case *big.Int:
106                         v, u = y.Match(x)
107                 case *big.Rat:
108                         u, v = x, y
109                 case cmplx:
110                         u, v = Const{cmplx{a, big.NewRat(0, 0)}}, y
111                 }
112         case cmplx:
113                 switch y.val.(type) {
114                 case *big.Int, *big.Rat:
115                         v, u = y.Match(x)
116                 case cmplx:
117                         u, v = x, y
118                 }
119         case string:
120                 if _, ok := y.val.(string); ok {
121                         u, v = x, y
122                 }
123         default:
124                 panic("unreachable")
125         }
126         return
127 }
128
129 // Convert attempts to convert the constant x to a given type.
130 // If the attempt is successful, the result is the new constant;
131 // otherwise the result is invalid.
132 func (x Const) Convert(typ *Type) Const {
133         // TODO(gri) implement this
134         switch x.val.(type) {
135         case bool:
136         case *big.Int:
137         case *big.Rat:
138         case cmplx:
139         case string:
140         }
141         return x
142 }
143
144 func (x Const) String() string {
145         switch x := x.val.(type) {
146         case bool:
147                 if x {
148                         return "true"
149                 }
150                 return "false"
151         case *big.Int:
152                 return x.String()
153         case *big.Rat:
154                 return x.FloatString(10) // 10 digits of precision after decimal point seems fine
155         case cmplx:
156                 // TODO(gri) don't print 0 components
157                 return x.re.FloatString(10) + " + " + x.im.FloatString(10) + "i"
158         case string:
159                 return x
160         }
161         panic("unreachable")
162 }
163
164 func (x Const) UnaryOp(op token.Token) Const {
165         panic("unimplemented")
166 }
167
168 func (x Const) BinaryOp(op token.Token, y Const) Const {
169         var z interface{}
170         switch x := x.val.(type) {
171         case bool:
172                 z = binaryBoolOp(x, op, y.val.(bool))
173         case *big.Int:
174                 z = binaryIntOp(x, op, y.val.(*big.Int))
175         case *big.Rat:
176                 z = binaryFloatOp(x, op, y.val.(*big.Rat))
177         case cmplx:
178                 z = binaryCmplxOp(x, op, y.val.(cmplx))
179         case string:
180                 z = binaryStringOp(x, op, y.val.(string))
181         default:
182                 panic("unreachable")
183         }
184         return Const{z}
185 }
186
187 func binaryBoolOp(x bool, op token.Token, y bool) interface{} {
188         switch op {
189         case token.EQL:
190                 return x == y
191         case token.NEQ:
192                 return x != y
193         }
194         panic("unreachable")
195 }
196
197 func binaryIntOp(x *big.Int, op token.Token, y *big.Int) interface{} {
198         var z big.Int
199         switch op {
200         case token.ADD:
201                 return z.Add(x, y)
202         case token.SUB:
203                 return z.Sub(x, y)
204         case token.MUL:
205                 return z.Mul(x, y)
206         case token.QUO:
207                 return z.Quo(x, y)
208         case token.REM:
209                 return z.Rem(x, y)
210         case token.AND:
211                 return z.And(x, y)
212         case token.OR:
213                 return z.Or(x, y)
214         case token.XOR:
215                 return z.Xor(x, y)
216         case token.AND_NOT:
217                 return z.AndNot(x, y)
218         case token.SHL:
219                 panic("unimplemented")
220         case token.SHR:
221                 panic("unimplemented")
222         case token.EQL:
223                 return x.Cmp(y) == 0
224         case token.NEQ:
225                 return x.Cmp(y) != 0
226         case token.LSS:
227                 return x.Cmp(y) < 0
228         case token.LEQ:
229                 return x.Cmp(y) <= 0
230         case token.GTR:
231                 return x.Cmp(y) > 0
232         case token.GEQ:
233                 return x.Cmp(y) >= 0
234         }
235         panic("unreachable")
236 }
237
238 func binaryFloatOp(x *big.Rat, op token.Token, y *big.Rat) interface{} {
239         var z big.Rat
240         switch op {
241         case token.ADD:
242                 return z.Add(x, y)
243         case token.SUB:
244                 return z.Sub(x, y)
245         case token.MUL:
246                 return z.Mul(x, y)
247         case token.QUO:
248                 return z.Quo(x, y)
249         case token.EQL:
250                 return x.Cmp(y) == 0
251         case token.NEQ:
252                 return x.Cmp(y) != 0
253         case token.LSS:
254                 return x.Cmp(y) < 0
255         case token.LEQ:
256                 return x.Cmp(y) <= 0
257         case token.GTR:
258                 return x.Cmp(y) > 0
259         case token.GEQ:
260                 return x.Cmp(y) >= 0
261         }
262         panic("unreachable")
263 }
264
265 func binaryCmplxOp(x cmplx, op token.Token, y cmplx) interface{} {
266         a, b := x.re, x.im
267         c, d := y.re, y.im
268         switch op {
269         case token.ADD:
270                 // (a+c) + i(b+d)
271                 var re, im big.Rat
272                 re.Add(a, c)
273                 im.Add(b, d)
274                 return cmplx{&re, &im}
275         case token.SUB:
276                 // (a-c) + i(b-d)
277                 var re, im big.Rat
278                 re.Sub(a, c)
279                 im.Sub(b, d)
280                 return cmplx{&re, &im}
281         case token.MUL:
282                 // (ac-bd) + i(bc+ad)
283                 var ac, bd, bc, ad big.Rat
284                 ac.Mul(a, c)
285                 bd.Mul(b, d)
286                 bc.Mul(b, c)
287                 ad.Mul(a, d)
288                 var re, im big.Rat
289                 re.Sub(&ac, &bd)
290                 im.Add(&bc, &ad)
291                 return cmplx{&re, &im}
292         case token.QUO:
293                 // (ac+bd)/s + i(bc-ad)/s, with s = cc + dd
294                 var ac, bd, bc, ad, s big.Rat
295                 ac.Mul(a, c)
296                 bd.Mul(b, d)
297                 bc.Mul(b, c)
298                 ad.Mul(a, d)
299                 s.Add(c.Mul(c, c), d.Mul(d, d))
300                 var re, im big.Rat
301                 re.Add(&ac, &bd)
302                 re.Quo(&re, &s)
303                 im.Sub(&bc, &ad)
304                 im.Quo(&im, &s)
305                 return cmplx{&re, &im}
306         case token.EQL:
307                 return a.Cmp(c) == 0 && b.Cmp(d) == 0
308         case token.NEQ:
309                 return a.Cmp(c) != 0 || b.Cmp(d) != 0
310         }
311         panic("unreachable")
312 }
313
314 func binaryStringOp(x string, op token.Token, y string) interface{} {
315         switch op {
316         case token.ADD:
317                 return x + y
318         case token.EQL:
319                 return x == y
320         case token.NEQ:
321                 return x != y
322         case token.LSS:
323                 return x < y
324         case token.LEQ:
325                 return x <= y
326         case token.GTR:
327                 return x > y
328         case token.GEQ:
329                 return x >= y
330         }
331         panic("unreachable")
332 }