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