2015-02-13 14:40:36 -05:00
|
|
|
// Copyright 2009 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.
|
|
|
|
|
|
|
|
package gc
|
|
|
|
|
2015-03-02 16:03:26 -05:00
|
|
|
import (
|
2015-05-21 13:28:10 -04:00
|
|
|
"cmd/compile/internal/big"
|
2015-03-02 16:03:26 -05:00
|
|
|
"cmd/internal/obj"
|
|
|
|
"strings"
|
|
|
|
)
|
2015-02-13 14:40:36 -05:00
|
|
|
|
2015-04-22 20:08:03 -07:00
|
|
|
// Int returns n as an int.
|
|
|
|
// n must be an integer constant.
|
|
|
|
func (n *Node) Int() int64 {
|
|
|
|
if !Isconst(n, CTINT) {
|
2015-08-30 23:10:03 +02:00
|
|
|
Fatalf("Int(%v)", n)
|
2015-04-22 20:08:03 -07:00
|
|
|
}
|
2015-05-27 00:47:05 -04:00
|
|
|
return Mpgetfix(n.Val().U.(*Mpint))
|
2015-04-22 20:08:03 -07:00
|
|
|
}
|
|
|
|
|
|
|
|
// SetInt sets n's value to i.
|
|
|
|
// n must be an integer constant.
|
|
|
|
func (n *Node) SetInt(i int64) {
|
|
|
|
if !Isconst(n, CTINT) {
|
2015-08-30 23:10:03 +02:00
|
|
|
Fatalf("SetInt(%v)", n)
|
2015-04-22 20:08:03 -07:00
|
|
|
}
|
2015-05-27 00:47:05 -04:00
|
|
|
Mpmovecfix(n.Val().U.(*Mpint), i)
|
2015-04-22 20:08:03 -07:00
|
|
|
}
|
|
|
|
|
|
|
|
// SetBigInt sets n's value to x.
|
|
|
|
// n must be an integer constant.
|
|
|
|
func (n *Node) SetBigInt(x *big.Int) {
|
|
|
|
if !Isconst(n, CTINT) {
|
2015-08-30 23:10:03 +02:00
|
|
|
Fatalf("SetBigInt(%v)", n)
|
2015-04-22 20:08:03 -07:00
|
|
|
}
|
2015-05-27 00:47:05 -04:00
|
|
|
n.Val().U.(*Mpint).Val.Set(x)
|
2015-04-22 20:08:03 -07:00
|
|
|
}
|
|
|
|
|
2015-05-07 18:43:03 -07:00
|
|
|
// Bool returns n as an bool.
|
|
|
|
// n must be an boolean constant.
|
|
|
|
func (n *Node) Bool() bool {
|
|
|
|
if !Isconst(n, CTBOOL) {
|
2015-08-30 23:10:03 +02:00
|
|
|
Fatalf("Int(%v)", n)
|
2015-05-07 18:43:03 -07:00
|
|
|
}
|
2015-05-27 00:47:05 -04:00
|
|
|
return n.Val().U.(bool)
|
2015-05-07 18:43:03 -07:00
|
|
|
}
|
|
|
|
|
2015-02-13 14:40:36 -05:00
|
|
|
/*
|
|
|
|
* truncate float literal fv to 32-bit or 64-bit precision
|
|
|
|
* according to type; return truncated value.
|
|
|
|
*/
|
|
|
|
func truncfltlit(oldv *Mpflt, t *Type) *Mpflt {
|
|
|
|
if t == nil {
|
|
|
|
return oldv
|
|
|
|
}
|
|
|
|
|
2015-03-02 14:22:05 -05:00
|
|
|
var v Val
|
2015-05-14 17:57:42 -07:00
|
|
|
v.U = oldv
|
2015-02-13 14:40:36 -05:00
|
|
|
overflow(v, t)
|
|
|
|
|
2015-03-20 16:59:08 -07:00
|
|
|
fv := newMpflt()
|
|
|
|
mpmovefltflt(fv, oldv)
|
2015-02-13 14:40:36 -05:00
|
|
|
|
|
|
|
// convert large precision literal floating
|
|
|
|
// into limited precision (float64 or float32)
|
|
|
|
switch t.Etype {
|
|
|
|
case TFLOAT64:
|
2015-02-23 16:07:24 -05:00
|
|
|
d := mpgetflt(fv)
|
2015-02-13 14:40:36 -05:00
|
|
|
Mpmovecflt(fv, d)
|
|
|
|
|
|
|
|
case TFLOAT32:
|
2015-02-23 16:07:24 -05:00
|
|
|
d := mpgetflt32(fv)
|
2015-02-13 14:40:36 -05:00
|
|
|
Mpmovecflt(fv, d)
|
|
|
|
}
|
|
|
|
|
|
|
|
return fv
|
|
|
|
}
|
|
|
|
|
|
|
|
/*
|
|
|
|
* convert n, if literal, to type t.
|
|
|
|
* implicit conversion.
|
|
|
|
*/
|
|
|
|
func Convlit(np **Node, t *Type) {
|
2015-02-17 22:13:49 -05:00
|
|
|
convlit1(np, t, false)
|
2015-02-13 14:40:36 -05:00
|
|
|
}
|
|
|
|
|
|
|
|
/*
|
|
|
|
* convert n, if literal, to type t.
|
|
|
|
* return a new node if necessary
|
|
|
|
* (if n is a named constant, can't edit n->type directly).
|
|
|
|
*/
|
2015-02-17 22:13:49 -05:00
|
|
|
func convlit1(np **Node, t *Type, explicit bool) {
|
2015-02-23 16:07:24 -05:00
|
|
|
n := *np
|
2015-02-17 22:13:49 -05:00
|
|
|
if n == nil || t == nil || n.Type == nil || isideal(t) || n.Type == t {
|
2015-02-13 14:40:36 -05:00
|
|
|
return
|
|
|
|
}
|
2015-02-17 22:13:49 -05:00
|
|
|
if !explicit && !isideal(n.Type) {
|
2015-02-13 14:40:36 -05:00
|
|
|
return
|
|
|
|
}
|
|
|
|
|
|
|
|
if n.Op == OLITERAL {
|
2015-02-23 16:07:24 -05:00
|
|
|
nn := Nod(OXXX, nil, nil)
|
2015-02-13 14:40:36 -05:00
|
|
|
*nn = *n
|
|
|
|
n = nn
|
|
|
|
*np = n
|
|
|
|
}
|
|
|
|
|
|
|
|
switch n.Op {
|
|
|
|
default:
|
|
|
|
if n.Type == idealbool {
|
|
|
|
if t.Etype == TBOOL {
|
|
|
|
n.Type = t
|
|
|
|
} else {
|
|
|
|
n.Type = Types[TBOOL]
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
if n.Type.Etype == TIDEAL {
|
|
|
|
Convlit(&n.Left, t)
|
|
|
|
Convlit(&n.Right, t)
|
|
|
|
n.Type = t
|
|
|
|
}
|
|
|
|
|
|
|
|
return
|
|
|
|
|
|
|
|
// target is invalid type for a constant? leave alone.
|
|
|
|
case OLITERAL:
|
2015-03-01 07:54:01 +00:00
|
|
|
if !okforconst[t.Etype] && n.Type.Etype != TNIL {
|
2015-02-13 14:40:36 -05:00
|
|
|
defaultlit(&n, nil)
|
|
|
|
*np = n
|
|
|
|
return
|
|
|
|
}
|
|
|
|
|
2015-04-01 09:38:44 -07:00
|
|
|
case OLSH, ORSH:
|
2015-02-17 22:13:49 -05:00
|
|
|
convlit1(&n.Left, t, explicit && isideal(n.Left.Type))
|
2015-02-13 14:40:36 -05:00
|
|
|
t = n.Left.Type
|
2015-05-27 00:47:05 -04:00
|
|
|
if t != nil && t.Etype == TIDEAL && n.Val().Ctype() != CTINT {
|
|
|
|
n.SetVal(toint(n.Val()))
|
2015-02-13 14:40:36 -05:00
|
|
|
}
|
2015-03-01 07:54:01 +00:00
|
|
|
if t != nil && !Isint[t.Etype] {
|
2015-04-17 12:03:22 -04:00
|
|
|
Yyerror("invalid operation: %v (shift of type %v)", n, t)
|
2015-02-13 14:40:36 -05:00
|
|
|
t = nil
|
|
|
|
}
|
|
|
|
|
|
|
|
n.Type = t
|
|
|
|
return
|
|
|
|
|
|
|
|
case OCOMPLEX:
|
|
|
|
if n.Type.Etype == TIDEAL {
|
|
|
|
switch t.Etype {
|
|
|
|
// If trying to convert to non-complex type,
|
|
|
|
// leave as complex128 and let typechecker complain.
|
|
|
|
default:
|
|
|
|
t = Types[TCOMPLEX128]
|
|
|
|
fallthrough
|
|
|
|
|
|
|
|
//fallthrough
|
|
|
|
case TCOMPLEX128:
|
|
|
|
n.Type = t
|
|
|
|
|
|
|
|
Convlit(&n.Left, Types[TFLOAT64])
|
|
|
|
Convlit(&n.Right, Types[TFLOAT64])
|
|
|
|
|
|
|
|
case TCOMPLEX64:
|
|
|
|
n.Type = t
|
|
|
|
Convlit(&n.Left, Types[TFLOAT32])
|
|
|
|
Convlit(&n.Right, Types[TFLOAT32])
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
return
|
|
|
|
}
|
|
|
|
|
|
|
|
// avoided repeated calculations, errors
|
|
|
|
if Eqtype(n.Type, t) {
|
|
|
|
return
|
|
|
|
}
|
|
|
|
|
2015-02-23 16:07:24 -05:00
|
|
|
ct := consttype(n)
|
|
|
|
var et int
|
2015-02-13 14:40:36 -05:00
|
|
|
if ct < 0 {
|
|
|
|
goto bad
|
|
|
|
}
|
|
|
|
|
|
|
|
et = int(t.Etype)
|
|
|
|
if et == TINTER {
|
|
|
|
if ct == CTNIL && n.Type == Types[TNIL] {
|
|
|
|
n.Type = t
|
|
|
|
return
|
|
|
|
}
|
|
|
|
|
|
|
|
defaultlit(np, nil)
|
|
|
|
return
|
|
|
|
}
|
|
|
|
|
|
|
|
switch ct {
|
|
|
|
default:
|
|
|
|
goto bad
|
|
|
|
|
|
|
|
case CTNIL:
|
|
|
|
switch et {
|
|
|
|
default:
|
|
|
|
n.Type = nil
|
|
|
|
goto bad
|
|
|
|
|
|
|
|
// let normal conversion code handle it
|
|
|
|
case TSTRING:
|
|
|
|
return
|
|
|
|
|
|
|
|
case TARRAY:
|
2015-02-17 22:13:49 -05:00
|
|
|
if !Isslice(t) {
|
2015-02-13 14:40:36 -05:00
|
|
|
goto bad
|
|
|
|
}
|
|
|
|
|
|
|
|
case TPTR32,
|
|
|
|
TPTR64,
|
|
|
|
TINTER,
|
|
|
|
TMAP,
|
|
|
|
TCHAN,
|
|
|
|
TFUNC,
|
|
|
|
TUNSAFEPTR:
|
|
|
|
break
|
|
|
|
|
|
|
|
// A nil literal may be converted to uintptr
|
|
|
|
// if it is an unsafe.Pointer
|
|
|
|
case TUINTPTR:
|
|
|
|
if n.Type.Etype == TUNSAFEPTR {
|
2015-05-27 00:47:05 -04:00
|
|
|
n.SetVal(Val{new(Mpint)})
|
|
|
|
Mpmovecfix(n.Val().U.(*Mpint), 0)
|
2015-02-13 14:40:36 -05:00
|
|
|
} else {
|
|
|
|
goto bad
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2015-04-01 09:38:44 -07:00
|
|
|
case CTSTR, CTBOOL:
|
2015-02-13 14:40:36 -05:00
|
|
|
if et != int(n.Type.Etype) {
|
|
|
|
goto bad
|
|
|
|
}
|
|
|
|
|
2015-04-01 09:38:44 -07:00
|
|
|
case CTINT, CTRUNE, CTFLT, CTCPLX:
|
2015-05-01 19:50:27 -07:00
|
|
|
if n.Type.Etype == TUNSAFEPTR && t.Etype != TUINTPTR {
|
|
|
|
goto bad
|
|
|
|
}
|
2015-05-27 00:47:05 -04:00
|
|
|
ct := int(n.Val().Ctype())
|
2015-03-01 07:54:01 +00:00
|
|
|
if Isint[et] {
|
2015-02-13 14:40:36 -05:00
|
|
|
switch ct {
|
|
|
|
default:
|
|
|
|
goto bad
|
|
|
|
|
2015-04-01 09:38:44 -07:00
|
|
|
case CTCPLX, CTFLT, CTRUNE:
|
2015-05-27 00:47:05 -04:00
|
|
|
n.SetVal(toint(n.Val()))
|
2015-02-13 14:40:36 -05:00
|
|
|
fallthrough
|
|
|
|
|
|
|
|
// flowthrough
|
|
|
|
case CTINT:
|
2015-05-27 00:47:05 -04:00
|
|
|
overflow(n.Val(), t)
|
2015-02-13 14:40:36 -05:00
|
|
|
}
|
2015-03-01 07:54:01 +00:00
|
|
|
} else if Isfloat[et] {
|
2015-02-13 14:40:36 -05:00
|
|
|
switch ct {
|
|
|
|
default:
|
|
|
|
goto bad
|
|
|
|
|
2015-04-01 09:38:44 -07:00
|
|
|
case CTCPLX, CTINT, CTRUNE:
|
2015-05-27 00:47:05 -04:00
|
|
|
n.SetVal(toflt(n.Val()))
|
2015-02-13 14:40:36 -05:00
|
|
|
fallthrough
|
|
|
|
|
|
|
|
// flowthrough
|
|
|
|
case CTFLT:
|
2015-05-27 00:47:05 -04:00
|
|
|
n.SetVal(Val{truncfltlit(n.Val().U.(*Mpflt), t)})
|
2015-02-13 14:40:36 -05:00
|
|
|
}
|
2015-03-01 07:54:01 +00:00
|
|
|
} else if Iscomplex[et] {
|
2015-02-13 14:40:36 -05:00
|
|
|
switch ct {
|
|
|
|
default:
|
|
|
|
goto bad
|
|
|
|
|
2015-04-01 09:38:44 -07:00
|
|
|
case CTFLT, CTINT, CTRUNE:
|
2015-05-27 00:47:05 -04:00
|
|
|
n.SetVal(tocplx(n.Val()))
|
2015-02-13 14:40:36 -05:00
|
|
|
|
|
|
|
case CTCPLX:
|
2015-05-27 00:47:05 -04:00
|
|
|
overflow(n.Val(), t)
|
2015-02-13 14:40:36 -05:00
|
|
|
}
|
2015-02-17 22:13:49 -05:00
|
|
|
} else if et == TSTRING && (ct == CTINT || ct == CTRUNE) && explicit {
|
2015-05-27 00:47:05 -04:00
|
|
|
n.SetVal(tostr(n.Val()))
|
2015-02-13 14:40:36 -05:00
|
|
|
} else {
|
|
|
|
goto bad
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
n.Type = t
|
|
|
|
return
|
|
|
|
|
|
|
|
bad:
|
2015-02-17 22:13:49 -05:00
|
|
|
if n.Diag == 0 {
|
2015-09-07 10:37:26 +10:00
|
|
|
if !t.Broke {
|
2015-04-17 12:03:22 -04:00
|
|
|
Yyerror("cannot convert %v to type %v", n, t)
|
2015-02-13 14:40:36 -05:00
|
|
|
}
|
|
|
|
n.Diag = 1
|
|
|
|
}
|
|
|
|
|
2015-02-17 22:13:49 -05:00
|
|
|
if isideal(n.Type) {
|
2015-02-13 14:40:36 -05:00
|
|
|
defaultlit(&n, nil)
|
|
|
|
*np = n
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
func copyval(v Val) Val {
|
2015-05-26 22:50:45 -04:00
|
|
|
switch v.Ctype() {
|
2015-04-01 09:38:44 -07:00
|
|
|
case CTINT, CTRUNE:
|
2015-02-23 16:07:24 -05:00
|
|
|
i := new(Mpint)
|
2015-05-14 17:57:42 -07:00
|
|
|
mpmovefixfix(i, v.U.(*Mpint))
|
2015-05-26 22:50:45 -04:00
|
|
|
i.Rune = v.U.(*Mpint).Rune
|
2015-05-14 17:57:42 -07:00
|
|
|
v.U = i
|
2015-02-13 14:40:36 -05:00
|
|
|
|
|
|
|
case CTFLT:
|
2015-03-20 16:59:08 -07:00
|
|
|
f := newMpflt()
|
2015-05-14 17:57:42 -07:00
|
|
|
mpmovefltflt(f, v.U.(*Mpflt))
|
|
|
|
v.U = f
|
2015-02-13 14:40:36 -05:00
|
|
|
|
|
|
|
case CTCPLX:
|
2015-02-23 16:07:24 -05:00
|
|
|
c := new(Mpcplx)
|
2015-05-14 17:57:42 -07:00
|
|
|
mpmovefltflt(&c.Real, &v.U.(*Mpcplx).Real)
|
|
|
|
mpmovefltflt(&c.Imag, &v.U.(*Mpcplx).Imag)
|
|
|
|
v.U = c
|
2015-02-13 14:40:36 -05:00
|
|
|
}
|
|
|
|
|
|
|
|
return v
|
|
|
|
}
|
|
|
|
|
|
|
|
func tocplx(v Val) Val {
|
2015-05-26 22:50:45 -04:00
|
|
|
switch v.Ctype() {
|
2015-04-01 09:38:44 -07:00
|
|
|
case CTINT, CTRUNE:
|
2015-02-23 16:07:24 -05:00
|
|
|
c := new(Mpcplx)
|
2015-05-14 17:57:42 -07:00
|
|
|
Mpmovefixflt(&c.Real, v.U.(*Mpint))
|
2015-02-13 14:40:36 -05:00
|
|
|
Mpmovecflt(&c.Imag, 0.0)
|
2015-05-14 17:57:42 -07:00
|
|
|
v.U = c
|
2015-02-13 14:40:36 -05:00
|
|
|
|
|
|
|
case CTFLT:
|
2015-02-23 16:07:24 -05:00
|
|
|
c := new(Mpcplx)
|
2015-05-14 17:57:42 -07:00
|
|
|
mpmovefltflt(&c.Real, v.U.(*Mpflt))
|
2015-02-13 14:40:36 -05:00
|
|
|
Mpmovecflt(&c.Imag, 0.0)
|
2015-05-14 17:57:42 -07:00
|
|
|
v.U = c
|
2015-02-13 14:40:36 -05:00
|
|
|
}
|
|
|
|
|
|
|
|
return v
|
|
|
|
}
|
|
|
|
|
|
|
|
func toflt(v Val) Val {
|
2015-05-26 22:50:45 -04:00
|
|
|
switch v.Ctype() {
|
2015-04-01 09:38:44 -07:00
|
|
|
case CTINT, CTRUNE:
|
2015-03-20 16:59:08 -07:00
|
|
|
f := newMpflt()
|
2015-05-14 17:57:42 -07:00
|
|
|
Mpmovefixflt(f, v.U.(*Mpint))
|
|
|
|
v.U = f
|
2015-02-13 14:40:36 -05:00
|
|
|
|
|
|
|
case CTCPLX:
|
2015-03-20 16:59:08 -07:00
|
|
|
f := newMpflt()
|
2015-05-14 17:57:42 -07:00
|
|
|
mpmovefltflt(f, &v.U.(*Mpcplx).Real)
|
|
|
|
if mpcmpfltc(&v.U.(*Mpcplx).Imag, 0) != 0 {
|
|
|
|
Yyerror("constant %v%vi truncated to real", Fconv(&v.U.(*Mpcplx).Real, obj.FmtSharp), Fconv(&v.U.(*Mpcplx).Imag, obj.FmtSharp|obj.FmtSign))
|
2015-02-13 14:40:36 -05:00
|
|
|
}
|
2015-05-14 17:57:42 -07:00
|
|
|
v.U = f
|
2015-02-13 14:40:36 -05:00
|
|
|
}
|
|
|
|
|
|
|
|
return v
|
|
|
|
}
|
|
|
|
|
|
|
|
func toint(v Val) Val {
|
2015-05-26 22:50:45 -04:00
|
|
|
switch v.Ctype() {
|
2015-02-13 14:40:36 -05:00
|
|
|
case CTRUNE:
|
2015-05-26 22:50:45 -04:00
|
|
|
i := new(Mpint)
|
|
|
|
mpmovefixfix(i, v.U.(*Mpint))
|
|
|
|
v.U = i
|
2015-02-13 14:40:36 -05:00
|
|
|
|
|
|
|
case CTFLT:
|
2015-02-23 16:07:24 -05:00
|
|
|
i := new(Mpint)
|
2015-05-14 17:57:42 -07:00
|
|
|
if mpmovefltfix(i, v.U.(*Mpflt)) < 0 {
|
|
|
|
Yyerror("constant %v truncated to integer", Fconv(v.U.(*Mpflt), obj.FmtSharp))
|
2015-02-13 14:40:36 -05:00
|
|
|
}
|
2015-05-14 17:57:42 -07:00
|
|
|
v.U = i
|
2015-02-13 14:40:36 -05:00
|
|
|
|
|
|
|
case CTCPLX:
|
2015-02-23 16:07:24 -05:00
|
|
|
i := new(Mpint)
|
2015-05-14 17:57:42 -07:00
|
|
|
if mpmovefltfix(i, &v.U.(*Mpcplx).Real) < 0 {
|
|
|
|
Yyerror("constant %v%vi truncated to integer", Fconv(&v.U.(*Mpcplx).Real, obj.FmtSharp), Fconv(&v.U.(*Mpcplx).Imag, obj.FmtSharp|obj.FmtSign))
|
2015-02-13 14:40:36 -05:00
|
|
|
}
|
2015-05-14 17:57:42 -07:00
|
|
|
if mpcmpfltc(&v.U.(*Mpcplx).Imag, 0) != 0 {
|
|
|
|
Yyerror("constant %v%vi truncated to real", Fconv(&v.U.(*Mpcplx).Real, obj.FmtSharp), Fconv(&v.U.(*Mpcplx).Imag, obj.FmtSharp|obj.FmtSign))
|
2015-02-13 14:40:36 -05:00
|
|
|
}
|
2015-05-14 17:57:42 -07:00
|
|
|
v.U = i
|
2015-02-13 14:40:36 -05:00
|
|
|
}
|
|
|
|
|
|
|
|
return v
|
|
|
|
}
|
|
|
|
|
2015-02-17 22:13:49 -05:00
|
|
|
func doesoverflow(v Val, t *Type) bool {
|
2015-05-26 22:50:45 -04:00
|
|
|
switch v.Ctype() {
|
2015-04-01 09:38:44 -07:00
|
|
|
case CTINT, CTRUNE:
|
2015-03-01 07:54:01 +00:00
|
|
|
if !Isint[t.Etype] {
|
2015-08-30 23:10:03 +02:00
|
|
|
Fatalf("overflow: %v integer constant", t)
|
2015-02-13 14:40:36 -05:00
|
|
|
}
|
2015-05-14 17:57:42 -07:00
|
|
|
if Mpcmpfixfix(v.U.(*Mpint), Minintval[t.Etype]) < 0 || Mpcmpfixfix(v.U.(*Mpint), Maxintval[t.Etype]) > 0 {
|
2015-02-17 22:13:49 -05:00
|
|
|
return true
|
2015-02-13 14:40:36 -05:00
|
|
|
}
|
|
|
|
|
|
|
|
case CTFLT:
|
2015-03-01 07:54:01 +00:00
|
|
|
if !Isfloat[t.Etype] {
|
2015-08-30 23:10:03 +02:00
|
|
|
Fatalf("overflow: %v floating-point constant", t)
|
2015-02-13 14:40:36 -05:00
|
|
|
}
|
2015-05-14 17:57:42 -07:00
|
|
|
if mpcmpfltflt(v.U.(*Mpflt), minfltval[t.Etype]) <= 0 || mpcmpfltflt(v.U.(*Mpflt), maxfltval[t.Etype]) >= 0 {
|
2015-02-17 22:13:49 -05:00
|
|
|
return true
|
2015-02-13 14:40:36 -05:00
|
|
|
}
|
|
|
|
|
|
|
|
case CTCPLX:
|
2015-03-01 07:54:01 +00:00
|
|
|
if !Iscomplex[t.Etype] {
|
2015-08-30 23:10:03 +02:00
|
|
|
Fatalf("overflow: %v complex constant", t)
|
2015-02-13 14:40:36 -05:00
|
|
|
}
|
2015-05-14 17:57:42 -07:00
|
|
|
if mpcmpfltflt(&v.U.(*Mpcplx).Real, minfltval[t.Etype]) <= 0 || mpcmpfltflt(&v.U.(*Mpcplx).Real, maxfltval[t.Etype]) >= 0 || mpcmpfltflt(&v.U.(*Mpcplx).Imag, minfltval[t.Etype]) <= 0 || mpcmpfltflt(&v.U.(*Mpcplx).Imag, maxfltval[t.Etype]) >= 0 {
|
2015-02-17 22:13:49 -05:00
|
|
|
return true
|
2015-02-13 14:40:36 -05:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2015-02-17 22:13:49 -05:00
|
|
|
return false
|
2015-02-13 14:40:36 -05:00
|
|
|
}
|
|
|
|
|
|
|
|
func overflow(v Val, t *Type) {
|
|
|
|
// v has already been converted
|
|
|
|
// to appropriate form for t.
|
|
|
|
if t == nil || t.Etype == TIDEAL {
|
|
|
|
return
|
|
|
|
}
|
|
|
|
|
2015-05-01 19:50:27 -07:00
|
|
|
// Only uintptrs may be converted to unsafe.Pointer, which cannot overflow.
|
|
|
|
if t.Etype == TUNSAFEPTR {
|
|
|
|
return
|
|
|
|
}
|
|
|
|
|
2015-09-15 11:16:58 -07:00
|
|
|
if doesoverflow(v, t) {
|
|
|
|
Yyerror("constant %s overflows %v", Vconv(v, 0), t)
|
2015-02-13 14:40:36 -05:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
func tostr(v Val) Val {
|
2015-05-26 22:50:45 -04:00
|
|
|
switch v.Ctype() {
|
2015-04-01 09:38:44 -07:00
|
|
|
case CTINT, CTRUNE:
|
2015-05-14 17:57:42 -07:00
|
|
|
if Mpcmpfixfix(v.U.(*Mpint), Minintval[TINT]) < 0 || Mpcmpfixfix(v.U.(*Mpint), Maxintval[TINT]) > 0 {
|
2015-02-13 14:40:36 -05:00
|
|
|
Yyerror("overflow in int -> string")
|
|
|
|
}
|
2015-05-14 17:57:42 -07:00
|
|
|
r := uint(Mpgetfix(v.U.(*Mpint)))
|
2015-02-13 14:40:36 -05:00
|
|
|
v = Val{}
|
2015-05-14 17:57:42 -07:00
|
|
|
v.U = string(r)
|
2015-02-13 14:40:36 -05:00
|
|
|
|
|
|
|
case CTFLT:
|
|
|
|
Yyerror("no float -> string")
|
|
|
|
fallthrough
|
|
|
|
|
|
|
|
case CTNIL:
|
|
|
|
v = Val{}
|
2015-05-14 17:57:42 -07:00
|
|
|
v.U = ""
|
2015-02-13 14:40:36 -05:00
|
|
|
}
|
|
|
|
|
|
|
|
return v
|
|
|
|
}
|
|
|
|
|
|
|
|
func consttype(n *Node) int {
|
|
|
|
if n == nil || n.Op != OLITERAL {
|
|
|
|
return -1
|
|
|
|
}
|
2015-05-27 00:47:05 -04:00
|
|
|
return int(n.Val().Ctype())
|
2015-02-13 14:40:36 -05:00
|
|
|
}
|
|
|
|
|
2015-02-17 22:13:49 -05:00
|
|
|
func Isconst(n *Node, ct int) bool {
|
2015-02-23 16:07:24 -05:00
|
|
|
t := consttype(n)
|
2015-02-13 14:40:36 -05:00
|
|
|
|
|
|
|
// If the caller is asking for CTINT, allow CTRUNE too.
|
|
|
|
// Makes life easier for back ends.
|
2015-02-17 22:13:49 -05:00
|
|
|
return t == ct || (ct == CTINT && t == CTRUNE)
|
2015-02-13 14:40:36 -05:00
|
|
|
}
|
|
|
|
|
|
|
|
func saveorig(n *Node) *Node {
|
|
|
|
if n == n.Orig {
|
|
|
|
// duplicate node for n->orig.
|
2015-02-23 16:07:24 -05:00
|
|
|
n1 := Nod(OLITERAL, nil, nil)
|
2015-02-13 14:40:36 -05:00
|
|
|
|
|
|
|
n.Orig = n1
|
|
|
|
*n1 = *n
|
|
|
|
}
|
|
|
|
|
|
|
|
return n.Orig
|
|
|
|
}
|
|
|
|
|
|
|
|
/*
|
|
|
|
* if n is constant, rewrite as OLITERAL node.
|
|
|
|
*/
|
|
|
|
func evconst(n *Node) {
|
|
|
|
// pick off just the opcodes that can be
|
|
|
|
// constant evaluated.
|
|
|
|
switch n.Op {
|
|
|
|
default:
|
|
|
|
return
|
|
|
|
|
|
|
|
case OADD,
|
|
|
|
OAND,
|
|
|
|
OANDAND,
|
|
|
|
OANDNOT,
|
|
|
|
OARRAYBYTESTR,
|
|
|
|
OCOM,
|
|
|
|
ODIV,
|
|
|
|
OEQ,
|
|
|
|
OGE,
|
|
|
|
OGT,
|
|
|
|
OLE,
|
|
|
|
OLSH,
|
|
|
|
OLT,
|
|
|
|
OMINUS,
|
|
|
|
OMOD,
|
|
|
|
OMUL,
|
|
|
|
ONE,
|
|
|
|
ONOT,
|
|
|
|
OOR,
|
|
|
|
OOROR,
|
|
|
|
OPLUS,
|
|
|
|
ORSH,
|
|
|
|
OSUB,
|
|
|
|
OXOR:
|
|
|
|
break
|
|
|
|
|
|
|
|
case OCONV:
|
|
|
|
if n.Type == nil {
|
|
|
|
return
|
|
|
|
}
|
2015-03-01 07:54:01 +00:00
|
|
|
if !okforconst[n.Type.Etype] && n.Type.Etype != TNIL {
|
2015-02-13 14:40:36 -05:00
|
|
|
return
|
|
|
|
}
|
|
|
|
|
|
|
|
// merge adjacent constants in the argument list.
|
|
|
|
case OADDSTR:
|
2015-02-23 16:07:24 -05:00
|
|
|
var nr *Node
|
|
|
|
var nl *Node
|
|
|
|
var l2 *NodeList
|
|
|
|
for l1 := n.List; l1 != nil; l1 = l1.Next {
|
2015-02-17 22:13:49 -05:00
|
|
|
if Isconst(l1.N, CTSTR) && l1.Next != nil && Isconst(l1.Next.N, CTSTR) {
|
2015-02-13 14:40:36 -05:00
|
|
|
// merge from l1 up to but not including l2
|
2015-03-02 16:03:26 -05:00
|
|
|
var strs []string
|
2015-02-13 14:40:36 -05:00
|
|
|
l2 = l1
|
2015-02-17 22:13:49 -05:00
|
|
|
for l2 != nil && Isconst(l2.N, CTSTR) {
|
2015-02-13 14:40:36 -05:00
|
|
|
nr = l2.N
|
2015-05-27 00:47:05 -04:00
|
|
|
strs = append(strs, nr.Val().U.(string))
|
2015-02-13 14:40:36 -05:00
|
|
|
l2 = l2.Next
|
|
|
|
}
|
|
|
|
|
|
|
|
nl = Nod(OXXX, nil, nil)
|
|
|
|
*nl = *l1.N
|
|
|
|
nl.Orig = nl
|
2015-05-27 00:47:05 -04:00
|
|
|
nl.SetVal(Val{strings.Join(strs, "")})
|
2015-02-13 14:40:36 -05:00
|
|
|
l1.N = nl
|
|
|
|
l1.Next = l2
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
// fix list end pointer.
|
2015-02-23 16:07:24 -05:00
|
|
|
for l2 := n.List; l2 != nil; l2 = l2.Next {
|
2015-02-13 14:40:36 -05:00
|
|
|
n.List.End = l2
|
|
|
|
}
|
|
|
|
|
|
|
|
// collapse single-constant list to single constant.
|
2015-02-17 22:13:49 -05:00
|
|
|
if count(n.List) == 1 && Isconst(n.List.N, CTSTR) {
|
2015-02-13 14:40:36 -05:00
|
|
|
n.Op = OLITERAL
|
2015-05-27 00:47:05 -04:00
|
|
|
n.SetVal(n.List.N.Val())
|
2015-02-13 14:40:36 -05:00
|
|
|
}
|
|
|
|
|
|
|
|
return
|
|
|
|
}
|
|
|
|
|
2015-02-23 16:07:24 -05:00
|
|
|
nl := n.Left
|
2015-02-13 14:40:36 -05:00
|
|
|
if nl == nil || nl.Type == nil {
|
|
|
|
return
|
|
|
|
}
|
|
|
|
if consttype(nl) < 0 {
|
|
|
|
return
|
|
|
|
}
|
2015-02-23 16:07:24 -05:00
|
|
|
wl := int(nl.Type.Etype)
|
2015-03-01 07:54:01 +00:00
|
|
|
if Isint[wl] || Isfloat[wl] || Iscomplex[wl] {
|
2015-02-13 14:40:36 -05:00
|
|
|
wl = TIDEAL
|
|
|
|
}
|
|
|
|
|
2015-02-23 16:07:24 -05:00
|
|
|
nr := n.Right
|
|
|
|
var rv Val
|
|
|
|
var lno int
|
|
|
|
var wr int
|
|
|
|
var v Val
|
|
|
|
var norig *Node
|
2015-02-13 14:40:36 -05:00
|
|
|
if nr == nil {
|
2015-03-02 12:35:15 -05:00
|
|
|
// copy numeric value to avoid modifying
|
|
|
|
// nl, in case someone still refers to it (e.g. iota).
|
2015-05-27 00:47:05 -04:00
|
|
|
v = nl.Val()
|
2015-03-02 12:35:15 -05:00
|
|
|
|
|
|
|
if wl == TIDEAL {
|
|
|
|
v = copyval(v)
|
|
|
|
}
|
|
|
|
|
2015-05-26 22:50:45 -04:00
|
|
|
switch uint32(n.Op)<<16 | uint32(v.Ctype()) {
|
2015-03-02 12:35:15 -05:00
|
|
|
default:
|
|
|
|
if n.Diag == 0 {
|
2015-04-17 12:03:22 -04:00
|
|
|
Yyerror("illegal constant expression %v %v", Oconv(int(n.Op), 0), nl.Type)
|
2015-03-02 12:35:15 -05:00
|
|
|
n.Diag = 1
|
|
|
|
}
|
|
|
|
|
|
|
|
return
|
|
|
|
|
|
|
|
case OCONV<<16 | CTNIL,
|
|
|
|
OARRAYBYTESTR<<16 | CTNIL:
|
|
|
|
if n.Type.Etype == TSTRING {
|
|
|
|
v = tostr(v)
|
|
|
|
nl.Type = n.Type
|
|
|
|
break
|
|
|
|
}
|
|
|
|
fallthrough
|
|
|
|
|
|
|
|
// fall through
|
|
|
|
case OCONV<<16 | CTINT,
|
|
|
|
OCONV<<16 | CTRUNE,
|
|
|
|
OCONV<<16 | CTFLT,
|
|
|
|
OCONV<<16 | CTSTR:
|
|
|
|
convlit1(&nl, n.Type, true)
|
|
|
|
|
2015-05-27 00:47:05 -04:00
|
|
|
v = nl.Val()
|
2015-03-02 12:35:15 -05:00
|
|
|
|
|
|
|
case OPLUS<<16 | CTINT,
|
|
|
|
OPLUS<<16 | CTRUNE:
|
|
|
|
break
|
|
|
|
|
|
|
|
case OMINUS<<16 | CTINT,
|
|
|
|
OMINUS<<16 | CTRUNE:
|
2015-05-14 17:57:42 -07:00
|
|
|
mpnegfix(v.U.(*Mpint))
|
2015-03-02 12:35:15 -05:00
|
|
|
|
|
|
|
case OCOM<<16 | CTINT,
|
|
|
|
OCOM<<16 | CTRUNE:
|
|
|
|
et := Txxx
|
|
|
|
if nl.Type != nil {
|
|
|
|
et = int(nl.Type.Etype)
|
|
|
|
}
|
|
|
|
|
|
|
|
// calculate the mask in b
|
|
|
|
// result will be (a ^ mask)
|
|
|
|
var b Mpint
|
|
|
|
switch et {
|
|
|
|
// signed guys change sign
|
|
|
|
default:
|
|
|
|
Mpmovecfix(&b, -1)
|
|
|
|
|
|
|
|
// unsigned guys invert their bits
|
|
|
|
case TUINT8,
|
|
|
|
TUINT16,
|
|
|
|
TUINT32,
|
|
|
|
TUINT64,
|
|
|
|
TUINT,
|
|
|
|
TUINTPTR:
|
|
|
|
mpmovefixfix(&b, Maxintval[et])
|
|
|
|
}
|
|
|
|
|
2015-05-14 17:57:42 -07:00
|
|
|
mpxorfixfix(v.U.(*Mpint), &b)
|
2015-03-02 12:35:15 -05:00
|
|
|
|
|
|
|
case OPLUS<<16 | CTFLT:
|
|
|
|
break
|
|
|
|
|
|
|
|
case OMINUS<<16 | CTFLT:
|
2015-05-14 17:57:42 -07:00
|
|
|
mpnegflt(v.U.(*Mpflt))
|
2015-03-02 12:35:15 -05:00
|
|
|
|
|
|
|
case OPLUS<<16 | CTCPLX:
|
|
|
|
break
|
|
|
|
|
|
|
|
case OMINUS<<16 | CTCPLX:
|
2015-05-14 17:57:42 -07:00
|
|
|
mpnegflt(&v.U.(*Mpcplx).Real)
|
|
|
|
mpnegflt(&v.U.(*Mpcplx).Imag)
|
2015-03-02 12:35:15 -05:00
|
|
|
|
|
|
|
case ONOT<<16 | CTBOOL:
|
2015-05-14 17:57:42 -07:00
|
|
|
if !v.U.(bool) {
|
2015-03-02 12:35:15 -05:00
|
|
|
goto settrue
|
|
|
|
}
|
|
|
|
goto setfalse
|
|
|
|
}
|
|
|
|
goto ret
|
2015-02-13 14:40:36 -05:00
|
|
|
}
|
|
|
|
if nr.Type == nil {
|
|
|
|
return
|
|
|
|
}
|
|
|
|
if consttype(nr) < 0 {
|
|
|
|
return
|
|
|
|
}
|
|
|
|
wr = int(nr.Type.Etype)
|
2015-03-01 07:54:01 +00:00
|
|
|
if Isint[wr] || Isfloat[wr] || Iscomplex[wr] {
|
2015-02-13 14:40:36 -05:00
|
|
|
wr = TIDEAL
|
|
|
|
}
|
|
|
|
|
|
|
|
// check for compatible general types (numeric, string, etc)
|
|
|
|
if wl != wr {
|
|
|
|
goto illegal
|
|
|
|
}
|
|
|
|
|
|
|
|
// check for compatible types.
|
|
|
|
switch n.Op {
|
|
|
|
// ideal const mixes with anything but otherwise must match.
|
|
|
|
default:
|
|
|
|
if nl.Type.Etype != TIDEAL {
|
|
|
|
defaultlit(&nr, nl.Type)
|
|
|
|
n.Right = nr
|
|
|
|
}
|
|
|
|
|
|
|
|
if nr.Type.Etype != TIDEAL {
|
|
|
|
defaultlit(&nl, nr.Type)
|
|
|
|
n.Left = nl
|
|
|
|
}
|
|
|
|
|
|
|
|
if nl.Type.Etype != nr.Type.Etype {
|
|
|
|
goto illegal
|
|
|
|
}
|
|
|
|
|
|
|
|
// right must be unsigned.
|
|
|
|
// left can be ideal.
|
2015-04-01 09:38:44 -07:00
|
|
|
case OLSH, ORSH:
|
2015-02-13 14:40:36 -05:00
|
|
|
defaultlit(&nr, Types[TUINT])
|
|
|
|
|
|
|
|
n.Right = nr
|
2015-03-01 07:54:01 +00:00
|
|
|
if nr.Type != nil && (Issigned[nr.Type.Etype] || !Isint[nr.Type.Etype]) {
|
2015-02-13 14:40:36 -05:00
|
|
|
goto illegal
|
|
|
|
}
|
2015-05-27 00:47:05 -04:00
|
|
|
if nl.Val().Ctype() != CTRUNE {
|
|
|
|
nl.SetVal(toint(nl.Val()))
|
2015-02-13 14:40:36 -05:00
|
|
|
}
|
2015-05-27 00:47:05 -04:00
|
|
|
nr.SetVal(toint(nr.Val()))
|
2015-02-13 14:40:36 -05:00
|
|
|
}
|
|
|
|
|
|
|
|
// copy numeric value to avoid modifying
|
|
|
|
// n->left, in case someone still refers to it (e.g. iota).
|
2015-05-27 00:47:05 -04:00
|
|
|
v = nl.Val()
|
2015-02-13 14:40:36 -05:00
|
|
|
|
|
|
|
if wl == TIDEAL {
|
|
|
|
v = copyval(v)
|
|
|
|
}
|
|
|
|
|
2015-05-27 00:47:05 -04:00
|
|
|
rv = nr.Val()
|
2015-02-13 14:40:36 -05:00
|
|
|
|
|
|
|
// convert to common ideal
|
2015-05-26 22:50:45 -04:00
|
|
|
if v.Ctype() == CTCPLX || rv.Ctype() == CTCPLX {
|
2015-02-13 14:40:36 -05:00
|
|
|
v = tocplx(v)
|
|
|
|
rv = tocplx(rv)
|
|
|
|
}
|
|
|
|
|
2015-05-26 22:50:45 -04:00
|
|
|
if v.Ctype() == CTFLT || rv.Ctype() == CTFLT {
|
2015-02-13 14:40:36 -05:00
|
|
|
v = toflt(v)
|
|
|
|
rv = toflt(rv)
|
|
|
|
}
|
|
|
|
|
|
|
|
// Rune and int turns into rune.
|
2015-05-26 22:50:45 -04:00
|
|
|
if v.Ctype() == CTRUNE && rv.Ctype() == CTINT {
|
|
|
|
i := new(Mpint)
|
|
|
|
mpmovefixfix(i, rv.U.(*Mpint))
|
|
|
|
i.Rune = true
|
|
|
|
rv.U = i
|
2015-02-13 14:40:36 -05:00
|
|
|
}
|
2015-05-26 22:50:45 -04:00
|
|
|
if v.Ctype() == CTINT && rv.Ctype() == CTRUNE {
|
2015-02-13 14:40:36 -05:00
|
|
|
if n.Op == OLSH || n.Op == ORSH {
|
2015-05-26 22:50:45 -04:00
|
|
|
i := new(Mpint)
|
|
|
|
mpmovefixfix(i, rv.U.(*Mpint))
|
|
|
|
rv.U = i
|
2015-02-13 14:40:36 -05:00
|
|
|
} else {
|
2015-05-26 22:50:45 -04:00
|
|
|
i := new(Mpint)
|
|
|
|
mpmovefixfix(i, v.U.(*Mpint))
|
|
|
|
i.Rune = true
|
|
|
|
v.U = i
|
2015-02-13 14:40:36 -05:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2015-05-26 22:50:45 -04:00
|
|
|
if v.Ctype() != rv.Ctype() {
|
2015-02-13 14:40:36 -05:00
|
|
|
// Use of undefined name as constant?
|
2015-05-26 22:50:45 -04:00
|
|
|
if (v.Ctype() == 0 || rv.Ctype() == 0) && nerrors > 0 {
|
2015-02-13 14:40:36 -05:00
|
|
|
return
|
|
|
|
}
|
2015-08-30 23:10:03 +02:00
|
|
|
Fatalf("constant type mismatch %v(%d) %v(%d)", nl.Type, v.Ctype(), nr.Type, rv.Ctype())
|
2015-02-13 14:40:36 -05:00
|
|
|
}
|
|
|
|
|
|
|
|
// run op
|
2015-05-26 22:50:45 -04:00
|
|
|
switch uint32(n.Op)<<16 | uint32(v.Ctype()) {
|
2015-02-13 14:40:36 -05:00
|
|
|
default:
|
|
|
|
goto illegal
|
|
|
|
|
|
|
|
case OADD<<16 | CTINT,
|
|
|
|
OADD<<16 | CTRUNE:
|
2015-05-14 17:57:42 -07:00
|
|
|
mpaddfixfix(v.U.(*Mpint), rv.U.(*Mpint), 0)
|
2015-02-13 14:40:36 -05:00
|
|
|
|
|
|
|
case OSUB<<16 | CTINT,
|
|
|
|
OSUB<<16 | CTRUNE:
|
2015-05-14 17:57:42 -07:00
|
|
|
mpsubfixfix(v.U.(*Mpint), rv.U.(*Mpint))
|
2015-02-13 14:40:36 -05:00
|
|
|
|
|
|
|
case OMUL<<16 | CTINT,
|
|
|
|
OMUL<<16 | CTRUNE:
|
2015-05-14 17:57:42 -07:00
|
|
|
mpmulfixfix(v.U.(*Mpint), rv.U.(*Mpint))
|
2015-02-13 14:40:36 -05:00
|
|
|
|
|
|
|
case ODIV<<16 | CTINT,
|
|
|
|
ODIV<<16 | CTRUNE:
|
2015-05-14 17:57:42 -07:00
|
|
|
if mpcmpfixc(rv.U.(*Mpint), 0) == 0 {
|
2015-02-13 14:40:36 -05:00
|
|
|
Yyerror("division by zero")
|
2015-05-14 17:57:42 -07:00
|
|
|
mpsetovf(v.U.(*Mpint))
|
2015-02-13 14:40:36 -05:00
|
|
|
break
|
|
|
|
}
|
|
|
|
|
2015-05-14 17:57:42 -07:00
|
|
|
mpdivfixfix(v.U.(*Mpint), rv.U.(*Mpint))
|
2015-02-13 14:40:36 -05:00
|
|
|
|
|
|
|
case OMOD<<16 | CTINT,
|
|
|
|
OMOD<<16 | CTRUNE:
|
2015-05-14 17:57:42 -07:00
|
|
|
if mpcmpfixc(rv.U.(*Mpint), 0) == 0 {
|
2015-02-13 14:40:36 -05:00
|
|
|
Yyerror("division by zero")
|
2015-05-14 17:57:42 -07:00
|
|
|
mpsetovf(v.U.(*Mpint))
|
2015-02-13 14:40:36 -05:00
|
|
|
break
|
|
|
|
}
|
|
|
|
|
2015-05-14 17:57:42 -07:00
|
|
|
mpmodfixfix(v.U.(*Mpint), rv.U.(*Mpint))
|
2015-02-13 14:40:36 -05:00
|
|
|
|
|
|
|
case OLSH<<16 | CTINT,
|
|
|
|
OLSH<<16 | CTRUNE:
|
2015-05-14 17:57:42 -07:00
|
|
|
mplshfixfix(v.U.(*Mpint), rv.U.(*Mpint))
|
2015-02-13 14:40:36 -05:00
|
|
|
|
|
|
|
case ORSH<<16 | CTINT,
|
|
|
|
ORSH<<16 | CTRUNE:
|
2015-05-14 17:57:42 -07:00
|
|
|
mprshfixfix(v.U.(*Mpint), rv.U.(*Mpint))
|
2015-02-13 14:40:36 -05:00
|
|
|
|
|
|
|
case OOR<<16 | CTINT,
|
|
|
|
OOR<<16 | CTRUNE:
|
2015-05-14 17:57:42 -07:00
|
|
|
mporfixfix(v.U.(*Mpint), rv.U.(*Mpint))
|
2015-02-13 14:40:36 -05:00
|
|
|
|
|
|
|
case OAND<<16 | CTINT,
|
|
|
|
OAND<<16 | CTRUNE:
|
2015-05-14 17:57:42 -07:00
|
|
|
mpandfixfix(v.U.(*Mpint), rv.U.(*Mpint))
|
2015-02-13 14:40:36 -05:00
|
|
|
|
|
|
|
case OANDNOT<<16 | CTINT,
|
|
|
|
OANDNOT<<16 | CTRUNE:
|
2015-05-14 17:57:42 -07:00
|
|
|
mpandnotfixfix(v.U.(*Mpint), rv.U.(*Mpint))
|
2015-02-13 14:40:36 -05:00
|
|
|
|
|
|
|
case OXOR<<16 | CTINT,
|
|
|
|
OXOR<<16 | CTRUNE:
|
2015-05-14 17:57:42 -07:00
|
|
|
mpxorfixfix(v.U.(*Mpint), rv.U.(*Mpint))
|
2015-02-13 14:40:36 -05:00
|
|
|
|
|
|
|
case OADD<<16 | CTFLT:
|
2015-05-14 17:57:42 -07:00
|
|
|
mpaddfltflt(v.U.(*Mpflt), rv.U.(*Mpflt))
|
2015-02-13 14:40:36 -05:00
|
|
|
|
|
|
|
case OSUB<<16 | CTFLT:
|
2015-05-14 17:57:42 -07:00
|
|
|
mpsubfltflt(v.U.(*Mpflt), rv.U.(*Mpflt))
|
2015-02-13 14:40:36 -05:00
|
|
|
|
|
|
|
case OMUL<<16 | CTFLT:
|
2015-05-14 17:57:42 -07:00
|
|
|
mpmulfltflt(v.U.(*Mpflt), rv.U.(*Mpflt))
|
2015-02-13 14:40:36 -05:00
|
|
|
|
|
|
|
case ODIV<<16 | CTFLT:
|
2015-05-14 17:57:42 -07:00
|
|
|
if mpcmpfltc(rv.U.(*Mpflt), 0) == 0 {
|
2015-02-13 14:40:36 -05:00
|
|
|
Yyerror("division by zero")
|
2015-05-14 17:57:42 -07:00
|
|
|
Mpmovecflt(v.U.(*Mpflt), 1.0)
|
2015-02-13 14:40:36 -05:00
|
|
|
break
|
|
|
|
}
|
|
|
|
|
2015-05-14 17:57:42 -07:00
|
|
|
mpdivfltflt(v.U.(*Mpflt), rv.U.(*Mpflt))
|
2015-02-13 14:40:36 -05:00
|
|
|
|
|
|
|
// The default case above would print 'ideal % ideal',
|
|
|
|
// which is not quite an ideal error.
|
|
|
|
case OMOD<<16 | CTFLT:
|
2015-02-17 22:13:49 -05:00
|
|
|
if n.Diag == 0 {
|
2015-02-23 14:02:27 -05:00
|
|
|
Yyerror("illegal constant expression: floating-point %% operation")
|
2015-02-13 14:40:36 -05:00
|
|
|
n.Diag = 1
|
|
|
|
}
|
|
|
|
|
|
|
|
return
|
|
|
|
|
|
|
|
case OADD<<16 | CTCPLX:
|
2015-05-14 17:57:42 -07:00
|
|
|
mpaddfltflt(&v.U.(*Mpcplx).Real, &rv.U.(*Mpcplx).Real)
|
|
|
|
mpaddfltflt(&v.U.(*Mpcplx).Imag, &rv.U.(*Mpcplx).Imag)
|
2015-02-13 14:40:36 -05:00
|
|
|
|
|
|
|
case OSUB<<16 | CTCPLX:
|
2015-05-14 17:57:42 -07:00
|
|
|
mpsubfltflt(&v.U.(*Mpcplx).Real, &rv.U.(*Mpcplx).Real)
|
|
|
|
mpsubfltflt(&v.U.(*Mpcplx).Imag, &rv.U.(*Mpcplx).Imag)
|
2015-02-13 14:40:36 -05:00
|
|
|
|
|
|
|
case OMUL<<16 | CTCPLX:
|
2015-05-14 17:57:42 -07:00
|
|
|
cmplxmpy(v.U.(*Mpcplx), rv.U.(*Mpcplx))
|
2015-02-13 14:40:36 -05:00
|
|
|
|
|
|
|
case ODIV<<16 | CTCPLX:
|
2015-05-14 17:57:42 -07:00
|
|
|
if mpcmpfltc(&rv.U.(*Mpcplx).Real, 0) == 0 && mpcmpfltc(&rv.U.(*Mpcplx).Imag, 0) == 0 {
|
2015-02-13 14:40:36 -05:00
|
|
|
Yyerror("complex division by zero")
|
2015-05-14 17:57:42 -07:00
|
|
|
Mpmovecflt(&rv.U.(*Mpcplx).Real, 1.0)
|
|
|
|
Mpmovecflt(&rv.U.(*Mpcplx).Imag, 0.0)
|
2015-02-13 14:40:36 -05:00
|
|
|
break
|
|
|
|
}
|
|
|
|
|
2015-05-14 17:57:42 -07:00
|
|
|
cmplxdiv(v.U.(*Mpcplx), rv.U.(*Mpcplx))
|
2015-02-13 14:40:36 -05:00
|
|
|
|
|
|
|
case OEQ<<16 | CTNIL:
|
|
|
|
goto settrue
|
|
|
|
|
|
|
|
case ONE<<16 | CTNIL:
|
|
|
|
goto setfalse
|
|
|
|
|
|
|
|
case OEQ<<16 | CTINT,
|
|
|
|
OEQ<<16 | CTRUNE:
|
2015-05-14 17:57:42 -07:00
|
|
|
if Mpcmpfixfix(v.U.(*Mpint), rv.U.(*Mpint)) == 0 {
|
2015-02-13 14:40:36 -05:00
|
|
|
goto settrue
|
|
|
|
}
|
|
|
|
goto setfalse
|
|
|
|
|
|
|
|
case ONE<<16 | CTINT,
|
|
|
|
ONE<<16 | CTRUNE:
|
2015-05-14 17:57:42 -07:00
|
|
|
if Mpcmpfixfix(v.U.(*Mpint), rv.U.(*Mpint)) != 0 {
|
2015-02-13 14:40:36 -05:00
|
|
|
goto settrue
|
|
|
|
}
|
|
|
|
goto setfalse
|
|
|
|
|
|
|
|
case OLT<<16 | CTINT,
|
|
|
|
OLT<<16 | CTRUNE:
|
2015-05-14 17:57:42 -07:00
|
|
|
if Mpcmpfixfix(v.U.(*Mpint), rv.U.(*Mpint)) < 0 {
|
2015-02-13 14:40:36 -05:00
|
|
|
goto settrue
|
|
|
|
}
|
|
|
|
goto setfalse
|
|
|
|
|
|
|
|
case OLE<<16 | CTINT,
|
|
|
|
OLE<<16 | CTRUNE:
|
2015-05-14 17:57:42 -07:00
|
|
|
if Mpcmpfixfix(v.U.(*Mpint), rv.U.(*Mpint)) <= 0 {
|
2015-02-13 14:40:36 -05:00
|
|
|
goto settrue
|
|
|
|
}
|
|
|
|
goto setfalse
|
|
|
|
|
|
|
|
case OGE<<16 | CTINT,
|
|
|
|
OGE<<16 | CTRUNE:
|
2015-05-14 17:57:42 -07:00
|
|
|
if Mpcmpfixfix(v.U.(*Mpint), rv.U.(*Mpint)) >= 0 {
|
2015-02-13 14:40:36 -05:00
|
|
|
goto settrue
|
|
|
|
}
|
|
|
|
goto setfalse
|
|
|
|
|
|
|
|
case OGT<<16 | CTINT,
|
|
|
|
OGT<<16 | CTRUNE:
|
2015-05-14 17:57:42 -07:00
|
|
|
if Mpcmpfixfix(v.U.(*Mpint), rv.U.(*Mpint)) > 0 {
|
2015-02-13 14:40:36 -05:00
|
|
|
goto settrue
|
|
|
|
}
|
|
|
|
goto setfalse
|
|
|
|
|
|
|
|
case OEQ<<16 | CTFLT:
|
2015-05-14 17:57:42 -07:00
|
|
|
if mpcmpfltflt(v.U.(*Mpflt), rv.U.(*Mpflt)) == 0 {
|
2015-02-13 14:40:36 -05:00
|
|
|
goto settrue
|
|
|
|
}
|
|
|
|
goto setfalse
|
|
|
|
|
|
|
|
case ONE<<16 | CTFLT:
|
2015-05-14 17:57:42 -07:00
|
|
|
if mpcmpfltflt(v.U.(*Mpflt), rv.U.(*Mpflt)) != 0 {
|
2015-02-13 14:40:36 -05:00
|
|
|
goto settrue
|
|
|
|
}
|
|
|
|
goto setfalse
|
|
|
|
|
|
|
|
case OLT<<16 | CTFLT:
|
2015-05-14 17:57:42 -07:00
|
|
|
if mpcmpfltflt(v.U.(*Mpflt), rv.U.(*Mpflt)) < 0 {
|
2015-02-13 14:40:36 -05:00
|
|
|
goto settrue
|
|
|
|
}
|
|
|
|
goto setfalse
|
|
|
|
|
|
|
|
case OLE<<16 | CTFLT:
|
2015-05-14 17:57:42 -07:00
|
|
|
if mpcmpfltflt(v.U.(*Mpflt), rv.U.(*Mpflt)) <= 0 {
|
2015-02-13 14:40:36 -05:00
|
|
|
goto settrue
|
|
|
|
}
|
|
|
|
goto setfalse
|
|
|
|
|
|
|
|
case OGE<<16 | CTFLT:
|
2015-05-14 17:57:42 -07:00
|
|
|
if mpcmpfltflt(v.U.(*Mpflt), rv.U.(*Mpflt)) >= 0 {
|
2015-02-13 14:40:36 -05:00
|
|
|
goto settrue
|
|
|
|
}
|
|
|
|
goto setfalse
|
|
|
|
|
|
|
|
case OGT<<16 | CTFLT:
|
2015-05-14 17:57:42 -07:00
|
|
|
if mpcmpfltflt(v.U.(*Mpflt), rv.U.(*Mpflt)) > 0 {
|
2015-02-13 14:40:36 -05:00
|
|
|
goto settrue
|
|
|
|
}
|
|
|
|
goto setfalse
|
|
|
|
|
|
|
|
case OEQ<<16 | CTCPLX:
|
2015-05-14 17:57:42 -07:00
|
|
|
if mpcmpfltflt(&v.U.(*Mpcplx).Real, &rv.U.(*Mpcplx).Real) == 0 && mpcmpfltflt(&v.U.(*Mpcplx).Imag, &rv.U.(*Mpcplx).Imag) == 0 {
|
2015-02-13 14:40:36 -05:00
|
|
|
goto settrue
|
|
|
|
}
|
|
|
|
goto setfalse
|
|
|
|
|
|
|
|
case ONE<<16 | CTCPLX:
|
2015-05-14 17:57:42 -07:00
|
|
|
if mpcmpfltflt(&v.U.(*Mpcplx).Real, &rv.U.(*Mpcplx).Real) != 0 || mpcmpfltflt(&v.U.(*Mpcplx).Imag, &rv.U.(*Mpcplx).Imag) != 0 {
|
2015-02-13 14:40:36 -05:00
|
|
|
goto settrue
|
|
|
|
}
|
|
|
|
goto setfalse
|
|
|
|
|
|
|
|
case OEQ<<16 | CTSTR:
|
2015-09-17 21:01:29 +02:00
|
|
|
if strlit(nl) == strlit(nr) {
|
2015-02-13 14:40:36 -05:00
|
|
|
goto settrue
|
|
|
|
}
|
|
|
|
goto setfalse
|
|
|
|
|
|
|
|
case ONE<<16 | CTSTR:
|
2015-09-17 21:01:29 +02:00
|
|
|
if strlit(nl) != strlit(nr) {
|
2015-02-13 14:40:36 -05:00
|
|
|
goto settrue
|
|
|
|
}
|
|
|
|
goto setfalse
|
|
|
|
|
|
|
|
case OLT<<16 | CTSTR:
|
2015-09-17 21:01:29 +02:00
|
|
|
if strlit(nl) < strlit(nr) {
|
2015-02-13 14:40:36 -05:00
|
|
|
goto settrue
|
|
|
|
}
|
|
|
|
goto setfalse
|
|
|
|
|
|
|
|
case OLE<<16 | CTSTR:
|
2015-09-17 21:01:29 +02:00
|
|
|
if strlit(nl) <= strlit(nr) {
|
2015-02-13 14:40:36 -05:00
|
|
|
goto settrue
|
|
|
|
}
|
|
|
|
goto setfalse
|
|
|
|
|
|
|
|
case OGE<<16 | CTSTR:
|
2015-09-17 21:01:29 +02:00
|
|
|
if strlit(nl) >= strlit(nr) {
|
2015-02-13 14:40:36 -05:00
|
|
|
goto settrue
|
|
|
|
}
|
|
|
|
goto setfalse
|
|
|
|
|
|
|
|
case OGT<<16 | CTSTR:
|
2015-09-17 21:01:29 +02:00
|
|
|
if strlit(nl) > strlit(nr) {
|
2015-02-13 14:40:36 -05:00
|
|
|
goto settrue
|
|
|
|
}
|
|
|
|
goto setfalse
|
|
|
|
|
|
|
|
case OOROR<<16 | CTBOOL:
|
2015-05-14 17:57:42 -07:00
|
|
|
if v.U.(bool) || rv.U.(bool) {
|
2015-02-13 14:40:36 -05:00
|
|
|
goto settrue
|
|
|
|
}
|
|
|
|
goto setfalse
|
|
|
|
|
|
|
|
case OANDAND<<16 | CTBOOL:
|
2015-05-14 17:57:42 -07:00
|
|
|
if v.U.(bool) && rv.U.(bool) {
|
2015-02-13 14:40:36 -05:00
|
|
|
goto settrue
|
|
|
|
}
|
|
|
|
goto setfalse
|
|
|
|
|
|
|
|
case OEQ<<16 | CTBOOL:
|
2015-05-14 17:57:42 -07:00
|
|
|
if v.U.(bool) == rv.U.(bool) {
|
2015-02-13 14:40:36 -05:00
|
|
|
goto settrue
|
|
|
|
}
|
|
|
|
goto setfalse
|
|
|
|
|
|
|
|
case ONE<<16 | CTBOOL:
|
2015-05-14 17:57:42 -07:00
|
|
|
if v.U.(bool) != rv.U.(bool) {
|
2015-02-13 14:40:36 -05:00
|
|
|
goto settrue
|
|
|
|
}
|
|
|
|
goto setfalse
|
|
|
|
}
|
|
|
|
|
|
|
|
goto ret
|
|
|
|
|
|
|
|
ret:
|
|
|
|
norig = saveorig(n)
|
|
|
|
*n = *nl
|
|
|
|
|
|
|
|
// restore value of n->orig.
|
|
|
|
n.Orig = norig
|
|
|
|
|
2015-05-27 00:47:05 -04:00
|
|
|
n.SetVal(v)
|
2015-02-13 14:40:36 -05:00
|
|
|
|
|
|
|
// check range.
|
|
|
|
lno = int(setlineno(n))
|
|
|
|
|
|
|
|
overflow(v, n.Type)
|
|
|
|
lineno = int32(lno)
|
|
|
|
|
|
|
|
// truncate precision for non-ideal float.
|
2015-05-26 22:50:45 -04:00
|
|
|
if v.Ctype() == CTFLT && n.Type.Etype != TIDEAL {
|
2015-05-27 00:47:05 -04:00
|
|
|
n.SetVal(Val{truncfltlit(v.U.(*Mpflt), n.Type)})
|
2015-02-13 14:40:36 -05:00
|
|
|
}
|
|
|
|
return
|
|
|
|
|
|
|
|
settrue:
|
|
|
|
norig = saveorig(n)
|
2015-02-17 22:13:49 -05:00
|
|
|
*n = *Nodbool(true)
|
2015-02-13 14:40:36 -05:00
|
|
|
n.Orig = norig
|
|
|
|
return
|
|
|
|
|
|
|
|
setfalse:
|
|
|
|
norig = saveorig(n)
|
2015-02-17 22:13:49 -05:00
|
|
|
*n = *Nodbool(false)
|
2015-02-13 14:40:36 -05:00
|
|
|
n.Orig = norig
|
|
|
|
return
|
|
|
|
|
|
|
|
illegal:
|
2015-02-17 22:13:49 -05:00
|
|
|
if n.Diag == 0 {
|
2015-04-17 12:03:22 -04:00
|
|
|
Yyerror("illegal constant expression: %v %v %v", nl.Type, Oconv(int(n.Op), 0), nr.Type)
|
2015-02-13 14:40:36 -05:00
|
|
|
n.Diag = 1
|
|
|
|
}
|
|
|
|
|
|
|
|
return
|
|
|
|
}
|
|
|
|
|
|
|
|
func nodlit(v Val) *Node {
|
2015-02-23 16:07:24 -05:00
|
|
|
n := Nod(OLITERAL, nil, nil)
|
2015-05-27 00:47:05 -04:00
|
|
|
n.SetVal(v)
|
2015-05-26 22:50:45 -04:00
|
|
|
switch v.Ctype() {
|
2015-02-13 14:40:36 -05:00
|
|
|
default:
|
2015-08-30 23:10:03 +02:00
|
|
|
Fatalf("nodlit ctype %d", v.Ctype())
|
2015-02-13 14:40:36 -05:00
|
|
|
|
|
|
|
case CTSTR:
|
|
|
|
n.Type = idealstring
|
|
|
|
|
|
|
|
case CTBOOL:
|
|
|
|
n.Type = idealbool
|
|
|
|
|
2015-04-01 09:38:44 -07:00
|
|
|
case CTINT, CTRUNE, CTFLT, CTCPLX:
|
2015-02-13 14:40:36 -05:00
|
|
|
n.Type = Types[TIDEAL]
|
|
|
|
|
|
|
|
case CTNIL:
|
|
|
|
n.Type = Types[TNIL]
|
|
|
|
}
|
|
|
|
|
|
|
|
return n
|
|
|
|
}
|
|
|
|
|
|
|
|
func nodcplxlit(r Val, i Val) *Node {
|
|
|
|
r = toflt(r)
|
|
|
|
i = toflt(i)
|
|
|
|
|
2015-02-23 16:07:24 -05:00
|
|
|
c := new(Mpcplx)
|
|
|
|
n := Nod(OLITERAL, nil, nil)
|
2015-02-13 14:40:36 -05:00
|
|
|
n.Type = Types[TIDEAL]
|
2015-05-27 00:47:05 -04:00
|
|
|
n.SetVal(Val{c})
|
2015-02-13 14:40:36 -05:00
|
|
|
|
2015-05-26 22:50:45 -04:00
|
|
|
if r.Ctype() != CTFLT || i.Ctype() != CTFLT {
|
2015-08-30 23:10:03 +02:00
|
|
|
Fatalf("nodcplxlit ctype %d/%d", r.Ctype(), i.Ctype())
|
2015-02-13 14:40:36 -05:00
|
|
|
}
|
|
|
|
|
2015-05-14 17:57:42 -07:00
|
|
|
mpmovefltflt(&c.Real, r.U.(*Mpflt))
|
|
|
|
mpmovefltflt(&c.Imag, i.U.(*Mpflt))
|
2015-02-13 14:40:36 -05:00
|
|
|
return n
|
|
|
|
}
|
|
|
|
|
|
|
|
// idealkind returns a constant kind like consttype
|
|
|
|
// but for an arbitrary "ideal" (untyped constant) expression.
|
|
|
|
func idealkind(n *Node) int {
|
2015-02-17 22:13:49 -05:00
|
|
|
if n == nil || !isideal(n.Type) {
|
2015-02-13 14:40:36 -05:00
|
|
|
return CTxxx
|
|
|
|
}
|
|
|
|
|
|
|
|
switch n.Op {
|
|
|
|
default:
|
|
|
|
return CTxxx
|
|
|
|
|
|
|
|
case OLITERAL:
|
2015-05-27 00:47:05 -04:00
|
|
|
return int(n.Val().Ctype())
|
2015-02-13 14:40:36 -05:00
|
|
|
|
|
|
|
// numeric kinds.
|
|
|
|
case OADD,
|
|
|
|
OAND,
|
|
|
|
OANDNOT,
|
|
|
|
OCOM,
|
|
|
|
ODIV,
|
|
|
|
OMINUS,
|
|
|
|
OMOD,
|
|
|
|
OMUL,
|
|
|
|
OSUB,
|
|
|
|
OXOR,
|
|
|
|
OOR,
|
|
|
|
OPLUS:
|
2015-02-23 16:07:24 -05:00
|
|
|
k1 := idealkind(n.Left)
|
2015-02-13 14:40:36 -05:00
|
|
|
|
2015-02-23 16:07:24 -05:00
|
|
|
k2 := idealkind(n.Right)
|
2015-02-13 14:40:36 -05:00
|
|
|
if k1 > k2 {
|
|
|
|
return k1
|
|
|
|
} else {
|
|
|
|
return k2
|
|
|
|
}
|
|
|
|
|
2015-04-01 09:38:44 -07:00
|
|
|
case OREAL, OIMAG:
|
2015-02-13 14:40:36 -05:00
|
|
|
return CTFLT
|
|
|
|
|
|
|
|
case OCOMPLEX:
|
|
|
|
return CTCPLX
|
|
|
|
|
|
|
|
case OADDSTR:
|
|
|
|
return CTSTR
|
|
|
|
|
|
|
|
case OANDAND,
|
|
|
|
OEQ,
|
|
|
|
OGE,
|
|
|
|
OGT,
|
|
|
|
OLE,
|
|
|
|
OLT,
|
|
|
|
ONE,
|
|
|
|
ONOT,
|
|
|
|
OOROR,
|
|
|
|
OCMPSTR,
|
|
|
|
OCMPIFACE:
|
|
|
|
return CTBOOL
|
|
|
|
|
|
|
|
// shifts (beware!).
|
2015-04-01 09:38:44 -07:00
|
|
|
case OLSH, ORSH:
|
2015-02-13 14:40:36 -05:00
|
|
|
return idealkind(n.Left)
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
func defaultlit(np **Node, t *Type) {
|
2015-02-23 16:07:24 -05:00
|
|
|
n := *np
|
2015-02-17 22:13:49 -05:00
|
|
|
if n == nil || !isideal(n.Type) {
|
2015-02-13 14:40:36 -05:00
|
|
|
return
|
|
|
|
}
|
|
|
|
|
|
|
|
if n.Op == OLITERAL {
|
2015-02-23 16:07:24 -05:00
|
|
|
nn := Nod(OXXX, nil, nil)
|
2015-02-13 14:40:36 -05:00
|
|
|
*nn = *n
|
|
|
|
n = nn
|
|
|
|
*np = n
|
|
|
|
}
|
|
|
|
|
2015-02-23 16:07:24 -05:00
|
|
|
lno := int(setlineno(n))
|
|
|
|
ctype := idealkind(n)
|
|
|
|
var t1 *Type
|
2015-02-13 14:40:36 -05:00
|
|
|
switch ctype {
|
|
|
|
default:
|
|
|
|
if t != nil {
|
|
|
|
Convlit(np, t)
|
|
|
|
return
|
|
|
|
}
|
|
|
|
|
2015-05-27 00:47:05 -04:00
|
|
|
if n.Val().Ctype() == CTNIL {
|
2015-02-13 14:40:36 -05:00
|
|
|
lineno = int32(lno)
|
2015-02-17 22:13:49 -05:00
|
|
|
if n.Diag == 0 {
|
2015-02-13 14:40:36 -05:00
|
|
|
Yyerror("use of untyped nil")
|
|
|
|
n.Diag = 1
|
|
|
|
}
|
|
|
|
|
|
|
|
n.Type = nil
|
|
|
|
break
|
|
|
|
}
|
|
|
|
|
2015-05-27 00:47:05 -04:00
|
|
|
if n.Val().Ctype() == CTSTR {
|
2015-02-23 16:07:24 -05:00
|
|
|
t1 := Types[TSTRING]
|
2015-02-13 14:40:36 -05:00
|
|
|
Convlit(np, t1)
|
|
|
|
break
|
|
|
|
}
|
|
|
|
|
2015-04-17 12:03:22 -04:00
|
|
|
Yyerror("defaultlit: unknown literal: %v", n)
|
2015-02-13 14:40:36 -05:00
|
|
|
|
|
|
|
case CTxxx:
|
2015-08-30 23:10:03 +02:00
|
|
|
Fatalf("defaultlit: idealkind is CTxxx: %v", Nconv(n, obj.FmtSign))
|
2015-02-13 14:40:36 -05:00
|
|
|
|
|
|
|
case CTBOOL:
|
2015-02-23 16:07:24 -05:00
|
|
|
t1 := Types[TBOOL]
|
2015-02-13 14:40:36 -05:00
|
|
|
if t != nil && t.Etype == TBOOL {
|
|
|
|
t1 = t
|
|
|
|
}
|
|
|
|
Convlit(np, t1)
|
|
|
|
|
|
|
|
case CTINT:
|
|
|
|
t1 = Types[TINT]
|
|
|
|
goto num
|
|
|
|
|
|
|
|
case CTRUNE:
|
|
|
|
t1 = runetype
|
|
|
|
goto num
|
|
|
|
|
|
|
|
case CTFLT:
|
|
|
|
t1 = Types[TFLOAT64]
|
|
|
|
goto num
|
|
|
|
|
|
|
|
case CTCPLX:
|
|
|
|
t1 = Types[TCOMPLEX128]
|
|
|
|
goto num
|
|
|
|
}
|
|
|
|
|
|
|
|
lineno = int32(lno)
|
|
|
|
return
|
|
|
|
|
|
|
|
num:
|
|
|
|
if t != nil {
|
2015-03-01 07:54:01 +00:00
|
|
|
if Isint[t.Etype] {
|
2015-02-13 14:40:36 -05:00
|
|
|
t1 = t
|
2015-05-27 00:47:05 -04:00
|
|
|
n.SetVal(toint(n.Val()))
|
2015-03-01 07:54:01 +00:00
|
|
|
} else if Isfloat[t.Etype] {
|
2015-02-13 14:40:36 -05:00
|
|
|
t1 = t
|
2015-05-27 00:47:05 -04:00
|
|
|
n.SetVal(toflt(n.Val()))
|
2015-03-01 07:54:01 +00:00
|
|
|
} else if Iscomplex[t.Etype] {
|
2015-02-13 14:40:36 -05:00
|
|
|
t1 = t
|
2015-05-27 00:47:05 -04:00
|
|
|
n.SetVal(tocplx(n.Val()))
|
2015-02-13 14:40:36 -05:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2015-05-27 00:47:05 -04:00
|
|
|
overflow(n.Val(), t1)
|
2015-02-13 14:40:36 -05:00
|
|
|
Convlit(np, t1)
|
|
|
|
lineno = int32(lno)
|
|
|
|
return
|
|
|
|
}
|
|
|
|
|
|
|
|
/*
|
|
|
|
* defaultlit on both nodes simultaneously;
|
|
|
|
* if they're both ideal going in they better
|
|
|
|
* get the same type going out.
|
|
|
|
* force means must assign concrete (non-ideal) type.
|
|
|
|
*/
|
|
|
|
func defaultlit2(lp **Node, rp **Node, force int) {
|
2015-02-23 16:07:24 -05:00
|
|
|
l := *lp
|
|
|
|
r := *rp
|
2015-02-13 14:40:36 -05:00
|
|
|
if l.Type == nil || r.Type == nil {
|
|
|
|
return
|
|
|
|
}
|
2015-02-17 22:13:49 -05:00
|
|
|
if !isideal(l.Type) {
|
2015-02-13 14:40:36 -05:00
|
|
|
Convlit(rp, l.Type)
|
|
|
|
return
|
|
|
|
}
|
|
|
|
|
2015-02-17 22:13:49 -05:00
|
|
|
if !isideal(r.Type) {
|
2015-02-13 14:40:36 -05:00
|
|
|
Convlit(lp, r.Type)
|
|
|
|
return
|
|
|
|
}
|
|
|
|
|
2015-02-17 22:13:49 -05:00
|
|
|
if force == 0 {
|
2015-02-13 14:40:36 -05:00
|
|
|
return
|
|
|
|
}
|
|
|
|
if l.Type.Etype == TBOOL {
|
|
|
|
Convlit(lp, Types[TBOOL])
|
|
|
|
Convlit(rp, Types[TBOOL])
|
|
|
|
}
|
|
|
|
|
2015-02-23 16:07:24 -05:00
|
|
|
lkind := idealkind(l)
|
|
|
|
rkind := idealkind(r)
|
2015-02-13 14:40:36 -05:00
|
|
|
if lkind == CTCPLX || rkind == CTCPLX {
|
|
|
|
Convlit(lp, Types[TCOMPLEX128])
|
|
|
|
Convlit(rp, Types[TCOMPLEX128])
|
|
|
|
return
|
|
|
|
}
|
|
|
|
|
|
|
|
if lkind == CTFLT || rkind == CTFLT {
|
|
|
|
Convlit(lp, Types[TFLOAT64])
|
|
|
|
Convlit(rp, Types[TFLOAT64])
|
|
|
|
return
|
|
|
|
}
|
|
|
|
|
|
|
|
if lkind == CTRUNE || rkind == CTRUNE {
|
|
|
|
Convlit(lp, runetype)
|
|
|
|
Convlit(rp, runetype)
|
|
|
|
return
|
|
|
|
}
|
|
|
|
|
|
|
|
Convlit(lp, Types[TINT])
|
|
|
|
Convlit(rp, Types[TINT])
|
|
|
|
}
|
|
|
|
|
2015-09-17 21:01:29 +02:00
|
|
|
// strlit returns the value of a literal string Node as a string.
|
|
|
|
func strlit(n *Node) string {
|
|
|
|
return n.Val().U.(string)
|
2015-02-13 14:40:36 -05:00
|
|
|
}
|
|
|
|
|
2015-02-17 22:13:49 -05:00
|
|
|
func Smallintconst(n *Node) bool {
|
|
|
|
if n.Op == OLITERAL && Isconst(n, CTINT) && n.Type != nil {
|
2015-02-13 14:40:36 -05:00
|
|
|
switch Simtype[n.Type.Etype] {
|
|
|
|
case TINT8,
|
|
|
|
TUINT8,
|
|
|
|
TINT16,
|
|
|
|
TUINT16,
|
|
|
|
TINT32,
|
|
|
|
TUINT32,
|
|
|
|
TBOOL,
|
|
|
|
TPTR32:
|
2015-02-17 22:13:49 -05:00
|
|
|
return true
|
2015-02-13 14:40:36 -05:00
|
|
|
|
2015-04-01 09:38:44 -07:00
|
|
|
case TIDEAL, TINT64, TUINT64, TPTR64:
|
2015-05-27 00:47:05 -04:00
|
|
|
if Mpcmpfixfix(n.Val().U.(*Mpint), Minintval[TINT32]) < 0 || Mpcmpfixfix(n.Val().U.(*Mpint), Maxintval[TINT32]) > 0 {
|
2015-02-13 14:40:36 -05:00
|
|
|
break
|
|
|
|
}
|
2015-02-17 22:13:49 -05:00
|
|
|
return true
|
2015-02-13 14:40:36 -05:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2015-02-17 22:13:49 -05:00
|
|
|
return false
|
2015-02-13 14:40:36 -05:00
|
|
|
}
|
|
|
|
|
|
|
|
func nonnegconst(n *Node) int {
|
|
|
|
if n.Op == OLITERAL && n.Type != nil {
|
|
|
|
switch Simtype[n.Type.Etype] {
|
|
|
|
// check negative and 2^31
|
|
|
|
case TINT8,
|
|
|
|
TUINT8,
|
|
|
|
TINT16,
|
|
|
|
TUINT16,
|
|
|
|
TINT32,
|
|
|
|
TUINT32,
|
|
|
|
TINT64,
|
|
|
|
TUINT64,
|
|
|
|
TIDEAL:
|
2015-05-27 00:47:05 -04:00
|
|
|
if Mpcmpfixfix(n.Val().U.(*Mpint), Minintval[TUINT32]) < 0 || Mpcmpfixfix(n.Val().U.(*Mpint), Maxintval[TINT32]) > 0 {
|
2015-02-13 14:40:36 -05:00
|
|
|
break
|
|
|
|
}
|
2015-05-27 00:47:05 -04:00
|
|
|
return int(Mpgetfix(n.Val().U.(*Mpint)))
|
2015-02-13 14:40:36 -05:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
return -1
|
|
|
|
}
|
|
|
|
|
|
|
|
/*
|
|
|
|
* convert x to type et and back to int64
|
|
|
|
* for sign extension and truncation.
|
|
|
|
*/
|
|
|
|
func iconv(x int64, et int) int64 {
|
|
|
|
switch et {
|
|
|
|
case TINT8:
|
|
|
|
x = int64(int8(x))
|
|
|
|
|
|
|
|
case TUINT8:
|
|
|
|
x = int64(uint8(x))
|
|
|
|
|
|
|
|
case TINT16:
|
|
|
|
x = int64(int16(x))
|
|
|
|
|
|
|
|
case TUINT16:
|
|
|
|
x = int64(uint64(x))
|
|
|
|
|
|
|
|
case TINT32:
|
|
|
|
x = int64(int32(x))
|
|
|
|
|
|
|
|
case TUINT32:
|
|
|
|
x = int64(uint32(x))
|
|
|
|
|
2015-04-01 09:38:44 -07:00
|
|
|
case TINT64, TUINT64:
|
2015-02-13 14:40:36 -05:00
|
|
|
break
|
|
|
|
}
|
|
|
|
|
|
|
|
return x
|
|
|
|
}
|
|
|
|
|
2015-05-07 18:43:03 -07:00
|
|
|
// Convconst converts constant node n to type t and
|
|
|
|
// places the result in con.
|
|
|
|
func (n *Node) Convconst(con *Node, t *Type) {
|
2015-02-23 16:07:24 -05:00
|
|
|
tt := Simsimtype(t)
|
2015-02-13 14:40:36 -05:00
|
|
|
|
|
|
|
// copy the constant for conversion
|
|
|
|
Nodconst(con, Types[TINT8], 0)
|
|
|
|
|
|
|
|
con.Type = t
|
2015-05-27 00:47:05 -04:00
|
|
|
con.SetVal(n.Val())
|
2015-02-13 14:40:36 -05:00
|
|
|
|
2015-03-01 07:54:01 +00:00
|
|
|
if Isint[tt] {
|
2015-05-27 00:47:05 -04:00
|
|
|
con.SetVal(Val{new(Mpint)})
|
2015-02-23 16:07:24 -05:00
|
|
|
var i int64
|
2015-05-27 00:47:05 -04:00
|
|
|
switch n.Val().Ctype() {
|
2015-02-13 14:40:36 -05:00
|
|
|
default:
|
2015-08-30 23:10:03 +02:00
|
|
|
Fatalf("convconst ctype=%d %v", n.Val().Ctype(), Tconv(t, obj.FmtLong))
|
2015-02-13 14:40:36 -05:00
|
|
|
|
2015-04-01 09:38:44 -07:00
|
|
|
case CTINT, CTRUNE:
|
2015-05-27 00:47:05 -04:00
|
|
|
i = Mpgetfix(n.Val().U.(*Mpint))
|
2015-02-13 14:40:36 -05:00
|
|
|
|
|
|
|
case CTBOOL:
|
2015-05-27 00:47:05 -04:00
|
|
|
i = int64(obj.Bool2int(n.Val().U.(bool)))
|
2015-02-13 14:40:36 -05:00
|
|
|
|
|
|
|
case CTNIL:
|
|
|
|
i = 0
|
|
|
|
}
|
|
|
|
|
|
|
|
i = iconv(i, tt)
|
2015-05-27 00:47:05 -04:00
|
|
|
Mpmovecfix(con.Val().U.(*Mpint), i)
|
2015-02-13 14:40:36 -05:00
|
|
|
return
|
|
|
|
}
|
|
|
|
|
2015-03-01 07:54:01 +00:00
|
|
|
if Isfloat[tt] {
|
2015-05-27 00:47:05 -04:00
|
|
|
con.SetVal(toflt(con.Val()))
|
|
|
|
if con.Val().Ctype() != CTFLT {
|
2015-08-30 23:10:03 +02:00
|
|
|
Fatalf("convconst ctype=%d %v", con.Val().Ctype(), t)
|
2015-02-13 14:40:36 -05:00
|
|
|
}
|
|
|
|
if tt == TFLOAT32 {
|
2015-05-27 00:47:05 -04:00
|
|
|
con.SetVal(Val{truncfltlit(con.Val().U.(*Mpflt), t)})
|
2015-02-13 14:40:36 -05:00
|
|
|
}
|
|
|
|
return
|
|
|
|
}
|
|
|
|
|
2015-03-01 07:54:01 +00:00
|
|
|
if Iscomplex[tt] {
|
2015-05-27 00:47:05 -04:00
|
|
|
con.SetVal(tocplx(con.Val()))
|
2015-02-13 14:40:36 -05:00
|
|
|
if tt == TCOMPLEX64 {
|
2015-05-27 00:47:05 -04:00
|
|
|
con.Val().U.(*Mpcplx).Real = *truncfltlit(&con.Val().U.(*Mpcplx).Real, Types[TFLOAT32])
|
|
|
|
con.Val().U.(*Mpcplx).Imag = *truncfltlit(&con.Val().U.(*Mpcplx).Imag, Types[TFLOAT32])
|
2015-02-13 14:40:36 -05:00
|
|
|
}
|
|
|
|
return
|
|
|
|
}
|
|
|
|
|
2015-08-30 23:10:03 +02:00
|
|
|
Fatalf("convconst %v constant", Tconv(t, obj.FmtLong))
|
2015-02-13 14:40:36 -05:00
|
|
|
}
|
|
|
|
|
|
|
|
// complex multiply v *= rv
|
|
|
|
// (a, b) * (c, d) = (a*c - b*d, b*c + a*d)
|
|
|
|
func cmplxmpy(v *Mpcplx, rv *Mpcplx) {
|
|
|
|
var ac Mpflt
|
|
|
|
var bd Mpflt
|
|
|
|
var bc Mpflt
|
|
|
|
var ad Mpflt
|
|
|
|
|
|
|
|
mpmovefltflt(&ac, &v.Real)
|
|
|
|
mpmulfltflt(&ac, &rv.Real) // ac
|
|
|
|
|
|
|
|
mpmovefltflt(&bd, &v.Imag)
|
|
|
|
|
|
|
|
mpmulfltflt(&bd, &rv.Imag) // bd
|
|
|
|
|
|
|
|
mpmovefltflt(&bc, &v.Imag)
|
|
|
|
|
|
|
|
mpmulfltflt(&bc, &rv.Real) // bc
|
|
|
|
|
|
|
|
mpmovefltflt(&ad, &v.Real)
|
|
|
|
|
|
|
|
mpmulfltflt(&ad, &rv.Imag) // ad
|
|
|
|
|
|
|
|
mpmovefltflt(&v.Real, &ac)
|
|
|
|
|
|
|
|
mpsubfltflt(&v.Real, &bd) // ac-bd
|
|
|
|
|
|
|
|
mpmovefltflt(&v.Imag, &bc)
|
|
|
|
|
|
|
|
mpaddfltflt(&v.Imag, &ad) // bc+ad
|
|
|
|
}
|
|
|
|
|
|
|
|
// complex divide v /= rv
|
|
|
|
// (a, b) / (c, d) = ((a*c + b*d), (b*c - a*d))/(c*c + d*d)
|
|
|
|
func cmplxdiv(v *Mpcplx, rv *Mpcplx) {
|
|
|
|
var ac Mpflt
|
|
|
|
var bd Mpflt
|
|
|
|
var bc Mpflt
|
|
|
|
var ad Mpflt
|
|
|
|
var cc_plus_dd Mpflt
|
|
|
|
|
|
|
|
mpmovefltflt(&cc_plus_dd, &rv.Real)
|
|
|
|
mpmulfltflt(&cc_plus_dd, &rv.Real) // cc
|
|
|
|
|
|
|
|
mpmovefltflt(&ac, &rv.Imag)
|
|
|
|
|
|
|
|
mpmulfltflt(&ac, &rv.Imag) // dd
|
|
|
|
|
|
|
|
mpaddfltflt(&cc_plus_dd, &ac) // cc+dd
|
|
|
|
|
|
|
|
mpmovefltflt(&ac, &v.Real)
|
|
|
|
|
|
|
|
mpmulfltflt(&ac, &rv.Real) // ac
|
|
|
|
|
|
|
|
mpmovefltflt(&bd, &v.Imag)
|
|
|
|
|
|
|
|
mpmulfltflt(&bd, &rv.Imag) // bd
|
|
|
|
|
|
|
|
mpmovefltflt(&bc, &v.Imag)
|
|
|
|
|
|
|
|
mpmulfltflt(&bc, &rv.Real) // bc
|
|
|
|
|
|
|
|
mpmovefltflt(&ad, &v.Real)
|
|
|
|
|
|
|
|
mpmulfltflt(&ad, &rv.Imag) // ad
|
|
|
|
|
|
|
|
mpmovefltflt(&v.Real, &ac)
|
|
|
|
|
|
|
|
mpaddfltflt(&v.Real, &bd) // ac+bd
|
|
|
|
mpdivfltflt(&v.Real, &cc_plus_dd) // (ac+bd)/(cc+dd)
|
|
|
|
|
|
|
|
mpmovefltflt(&v.Imag, &bc)
|
|
|
|
|
|
|
|
mpsubfltflt(&v.Imag, &ad) // bc-ad
|
|
|
|
mpdivfltflt(&v.Imag, &cc_plus_dd) // (bc+ad)/(cc+dd)
|
|
|
|
}
|
|
|
|
|
|
|
|
// Is n a Go language constant (as opposed to a compile-time constant)?
|
|
|
|
// Expressions derived from nil, like string([]byte(nil)), while they
|
|
|
|
// may be known at compile time, are not Go language constants.
|
|
|
|
// Only called for expressions known to evaluated to compile-time
|
|
|
|
// constants.
|
2015-02-17 22:13:49 -05:00
|
|
|
func isgoconst(n *Node) bool {
|
2015-02-13 14:40:36 -05:00
|
|
|
if n.Orig != nil {
|
|
|
|
n = n.Orig
|
|
|
|
}
|
|
|
|
|
|
|
|
switch n.Op {
|
|
|
|
case OADD,
|
|
|
|
OADDSTR,
|
|
|
|
OAND,
|
|
|
|
OANDAND,
|
|
|
|
OANDNOT,
|
|
|
|
OCOM,
|
|
|
|
ODIV,
|
|
|
|
OEQ,
|
|
|
|
OGE,
|
|
|
|
OGT,
|
|
|
|
OLE,
|
|
|
|
OLSH,
|
|
|
|
OLT,
|
|
|
|
OMINUS,
|
|
|
|
OMOD,
|
|
|
|
OMUL,
|
|
|
|
ONE,
|
|
|
|
ONOT,
|
|
|
|
OOR,
|
|
|
|
OOROR,
|
|
|
|
OPLUS,
|
|
|
|
ORSH,
|
|
|
|
OSUB,
|
|
|
|
OXOR,
|
|
|
|
OIOTA,
|
|
|
|
OCOMPLEX,
|
|
|
|
OREAL,
|
|
|
|
OIMAG:
|
2015-02-17 22:13:49 -05:00
|
|
|
if isgoconst(n.Left) && (n.Right == nil || isgoconst(n.Right)) {
|
|
|
|
return true
|
2015-02-13 14:40:36 -05:00
|
|
|
}
|
|
|
|
|
|
|
|
case OCONV:
|
2015-03-01 07:54:01 +00:00
|
|
|
if okforconst[n.Type.Etype] && isgoconst(n.Left) {
|
2015-02-17 22:13:49 -05:00
|
|
|
return true
|
2015-02-13 14:40:36 -05:00
|
|
|
}
|
|
|
|
|
2015-04-01 09:38:44 -07:00
|
|
|
case OLEN, OCAP:
|
2015-02-23 16:07:24 -05:00
|
|
|
l := n.Left
|
2015-02-17 22:13:49 -05:00
|
|
|
if isgoconst(l) {
|
|
|
|
return true
|
2015-02-13 14:40:36 -05:00
|
|
|
}
|
|
|
|
|
|
|
|
// Special case: len/cap is constant when applied to array or
|
|
|
|
// pointer to array when the expression does not contain
|
|
|
|
// function calls or channel receive operations.
|
2015-02-23 16:07:24 -05:00
|
|
|
t := l.Type
|
2015-02-13 14:40:36 -05:00
|
|
|
|
2015-03-01 07:54:01 +00:00
|
|
|
if t != nil && Isptr[t.Etype] {
|
2015-02-13 14:40:36 -05:00
|
|
|
t = t.Type
|
|
|
|
}
|
2015-02-17 22:13:49 -05:00
|
|
|
if Isfixedarray(t) && !hascallchan(l) {
|
|
|
|
return true
|
2015-02-13 14:40:36 -05:00
|
|
|
}
|
|
|
|
|
|
|
|
case OLITERAL:
|
2015-05-27 00:47:05 -04:00
|
|
|
if n.Val().Ctype() != CTNIL {
|
2015-02-17 22:13:49 -05:00
|
|
|
return true
|
2015-02-13 14:40:36 -05:00
|
|
|
}
|
|
|
|
|
|
|
|
case ONAME:
|
2015-02-23 16:07:24 -05:00
|
|
|
l := n.Sym.Def
|
2015-05-27 00:47:05 -04:00
|
|
|
if l != nil && l.Op == OLITERAL && n.Val().Ctype() != CTNIL {
|
2015-02-17 22:13:49 -05:00
|
|
|
return true
|
2015-02-13 14:40:36 -05:00
|
|
|
}
|
|
|
|
|
|
|
|
case ONONAME:
|
|
|
|
if n.Sym.Def != nil && n.Sym.Def.Op == OIOTA {
|
2015-02-17 22:13:49 -05:00
|
|
|
return true
|
2015-02-13 14:40:36 -05:00
|
|
|
}
|
|
|
|
|
|
|
|
// Only constant calls are unsafe.Alignof, Offsetof, and Sizeof.
|
|
|
|
case OCALL:
|
2015-02-23 16:07:24 -05:00
|
|
|
l := n.Left
|
2015-02-13 14:40:36 -05:00
|
|
|
|
|
|
|
for l.Op == OPAREN {
|
|
|
|
l = l.Left
|
|
|
|
}
|
|
|
|
if l.Op != ONAME || l.Sym.Pkg != unsafepkg {
|
|
|
|
break
|
|
|
|
}
|
|
|
|
if l.Sym.Name == "Alignof" || l.Sym.Name == "Offsetof" || l.Sym.Name == "Sizeof" {
|
2015-02-17 22:13:49 -05:00
|
|
|
return true
|
2015-02-13 14:40:36 -05:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
//dump("nonconst", n);
|
2015-02-17 22:13:49 -05:00
|
|
|
return false
|
2015-02-13 14:40:36 -05:00
|
|
|
}
|
|
|
|
|
2015-02-17 22:13:49 -05:00
|
|
|
func hascallchan(n *Node) bool {
|
2015-02-13 14:40:36 -05:00
|
|
|
if n == nil {
|
2015-02-17 22:13:49 -05:00
|
|
|
return false
|
2015-02-13 14:40:36 -05:00
|
|
|
}
|
|
|
|
switch n.Op {
|
|
|
|
case OAPPEND,
|
|
|
|
OCALL,
|
|
|
|
OCALLFUNC,
|
|
|
|
OCALLINTER,
|
|
|
|
OCALLMETH,
|
|
|
|
OCAP,
|
|
|
|
OCLOSE,
|
|
|
|
OCOMPLEX,
|
|
|
|
OCOPY,
|
|
|
|
ODELETE,
|
|
|
|
OIMAG,
|
|
|
|
OLEN,
|
|
|
|
OMAKE,
|
|
|
|
ONEW,
|
|
|
|
OPANIC,
|
|
|
|
OPRINT,
|
|
|
|
OPRINTN,
|
|
|
|
OREAL,
|
|
|
|
ORECOVER,
|
|
|
|
ORECV:
|
2015-02-17 22:13:49 -05:00
|
|
|
return true
|
2015-02-13 14:40:36 -05:00
|
|
|
}
|
|
|
|
|
2015-02-17 22:13:49 -05:00
|
|
|
if hascallchan(n.Left) || hascallchan(n.Right) {
|
|
|
|
return true
|
2015-02-13 14:40:36 -05:00
|
|
|
}
|
|
|
|
|
2015-02-23 16:07:24 -05:00
|
|
|
for l := n.List; l != nil; l = l.Next {
|
2015-02-17 22:13:49 -05:00
|
|
|
if hascallchan(l.N) {
|
|
|
|
return true
|
2015-02-13 14:40:36 -05:00
|
|
|
}
|
|
|
|
}
|
2015-02-23 16:07:24 -05:00
|
|
|
for l := n.Rlist; l != nil; l = l.Next {
|
2015-02-17 22:13:49 -05:00
|
|
|
if hascallchan(l.N) {
|
|
|
|
return true
|
2015-02-13 14:40:36 -05:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2015-02-17 22:13:49 -05:00
|
|
|
return false
|
2015-02-13 14:40:36 -05:00
|
|
|
}
|