switch x := v.U.(type) {
default:
Fatalf("unexpected Ctype for %T", v.U)
- panic("not reached")
+ panic("unreachable")
case nil:
return 0
case *NilVal:
switch x := a.U.(type) {
default:
Fatalf("unexpected Ctype for %T", a.U)
- panic("not reached")
+ panic("unreachable")
case *NilVal:
return true
case bool:
switch x := v.U.(type) {
default:
Fatalf("unexpected Interface for %T", v.U)
- panic("not reached")
+ panic("unreachable")
case *NilVal:
return nil
case bool, string:
return n
}
-func copyval(v Val) Val {
- switch u := v.U.(type) {
- case *Mpint:
- i := new(Mpint)
- i.Set(u)
- i.Rune = u.Rune
- v.U = i
-
- case *Mpflt:
- f := newMpflt()
- f.Set(u)
- v.U = f
-
- case *Mpcplx:
- c := new(Mpcplx)
- c.Real.Set(&u.Real)
- c.Imag.Set(&u.Imag)
- v.U = c
- }
-
- return v
-}
-
func tocplx(v Val) Val {
switch u := v.U.(type) {
case *Mpint:
i = u.Int64()
}
v.U = string(i)
-
- case *NilVal:
- // Can happen because of string([]byte(nil)).
- v.U = ""
}
return v
return t == ct || (ct == CTINT && t == CTRUNE)
}
-// if n is constant, rewrite as OLITERAL node.
+// evconst rewrites constant expressions into OLITERAL nodes.
func evconst(n *Node) {
- // pick off just the opcodes that can be
- // constant evaluated.
- switch n.Op {
- default:
- return
+ nl, nr := n.Left, n.Right
- 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
+ // Pick off just the opcodes that can be constant evaluated.
+ switch op := n.Op; op {
+ case OPLUS, OMINUS, OCOM, ONOT:
+ if nl.Op == OLITERAL {
+ setconst(n, unaryOp(op, nl.Val(), n.Type))
+ }
+
+ case OADD, OSUB, OMUL, ODIV, OMOD, OOR, OXOR, OAND, OANDNOT, OOROR, OANDAND:
+ if nl.Op == OLITERAL && nr.Op == OLITERAL {
+ setconst(n, binaryOp(nl.Val(), op, nr.Val()))
+ }
+
+ case OEQ, ONE, OLT, OLE, OGT, OGE:
+ if nl.Op == OLITERAL && nr.Op == OLITERAL {
+ if nl.Type.IsInterface() != nr.Type.IsInterface() {
+ // Mixed interface/non-interface
+ // constant comparison means comparing
+ // nil interface with some typed
+ // constant, which is always unequal.
+ // E.g., interface{}(nil) == (*int)(nil).
+ setboolconst(n, op == ONE)
+ } else {
+ setboolconst(n, compareOp(nl.Val(), op, nr.Val()))
+ }
+ }
+
+ case OLSH, ORSH:
+ if nl.Op == OLITERAL && nr.Op == OLITERAL {
+ setconst(n, shiftOp(nl.Val(), op, nr.Val()))
+ }
case OCONV:
- if n.Type == nil {
- return
+ if n.Type != nil && okforconst[n.Type.Etype] && nl.Op == OLITERAL {
+ // TODO(mdempsky): There should be a convval function.
+ setconst(n, convlit1(nl, n.Type, true, false).Val())
}
- if !okforconst[n.Type.Etype] && n.Type.Etype != TNIL {
- return
+
+ case OARRAYBYTESTR:
+ // string([]byte(nil)) or string([]rune(nil))
+ if nl.Op == OLITERAL && nl.Val().Ctype() == CTNIL {
+ setconst(n, Val{U: ""})
}
- // merge adjacent constants in the argument list.
case OADDSTR:
+ // Merge adjacent constants in the argument list.
s := n.List.Slice()
for i1 := 0; i1 < len(s); i1++ {
if Isconst(s[i1], CTSTR) && i1+1 < len(s) && Isconst(s[i1+1], CTSTR) {
} else {
n.List.Set(s)
}
-
- return
- }
-
- nl := n.Left
- if nl == nil || nl.Type == nil {
- return
- }
- if consttype(nl) == 0 {
- return
- }
- wl := nl.Type.Etype
- if isInt[wl] || isFloat[wl] || isComplex[wl] {
- wl = TIDEAL
- }
-
- // avoid constant conversions in switches below
- const (
- CTINT_ = uint32(CTINT)
- CTRUNE_ = uint32(CTRUNE)
- CTFLT_ = uint32(CTFLT)
- CTCPLX_ = uint32(CTCPLX)
- CTSTR_ = uint32(CTSTR)
- CTBOOL_ = uint32(CTBOOL)
- CTNIL_ = uint32(CTNIL)
- OCONV_ = uint32(OCONV) << 16
- OARRAYBYTESTR_ = uint32(OARRAYBYTESTR) << 16
- OPLUS_ = uint32(OPLUS) << 16
- OMINUS_ = uint32(OMINUS) << 16
- OCOM_ = uint32(OCOM) << 16
- ONOT_ = uint32(ONOT) << 16
- OLSH_ = uint32(OLSH) << 16
- ORSH_ = uint32(ORSH) << 16
- OADD_ = uint32(OADD) << 16
- OSUB_ = uint32(OSUB) << 16
- OMUL_ = uint32(OMUL) << 16
- ODIV_ = uint32(ODIV) << 16
- OMOD_ = uint32(OMOD) << 16
- OOR_ = uint32(OOR) << 16
- OAND_ = uint32(OAND) << 16
- OANDNOT_ = uint32(OANDNOT) << 16
- OXOR_ = uint32(OXOR) << 16
- OEQ_ = uint32(OEQ) << 16
- ONE_ = uint32(ONE) << 16
- OLT_ = uint32(OLT) << 16
- OLE_ = uint32(OLE) << 16
- OGE_ = uint32(OGE) << 16
- OGT_ = uint32(OGT) << 16
- OOROR_ = uint32(OOROR) << 16
- OANDAND_ = uint32(OANDAND) << 16
- )
-
- nr := n.Right
- var rv Val
- var wr types.EType
- var ctype uint32
- var v Val
- if nr == nil {
- // copy numeric value to avoid modifying
- // nl, in case someone still refers to it (e.g. iota).
- v = copyval(nl.Val())
-
- // rune values are int values for the purpose of constant folding.
- ctype = uint32(v.Ctype())
- if ctype == CTRUNE_ {
- ctype = CTINT_
- }
-
- switch uint32(n.Op)<<16 | ctype {
- default:
- if !n.Diag() {
- yyerror("illegal constant expression %v %v", n.Op, nl.Type)
- n.SetDiag(true)
- }
- return
-
- case OCONV_ | CTNIL_,
- OARRAYBYTESTR_ | CTNIL_:
- if n.Type.IsString() {
- v = tostr(v)
- nl.Type = n.Type
- break
- }
- fallthrough
- case OCONV_ | CTINT_,
- OCONV_ | CTFLT_,
- OCONV_ | CTCPLX_,
- OCONV_ | CTSTR_,
- OCONV_ | CTBOOL_:
- nl = convlit1(nl, n.Type, true, false)
- v = nl.Val()
-
- case OPLUS_ | CTINT_:
- break
-
- case OMINUS_ | CTINT_:
- v.U.(*Mpint).Neg()
-
- case OCOM_ | CTINT_:
- et := Txxx
- if nl.Type != nil {
- et = nl.Type.Etype
- }
-
- // calculate the mask in b
- // result will be (a ^ mask)
- var b Mpint
- switch et {
- // signed guys change sign
- default:
- b.SetInt64(-1)
-
- // unsigned guys invert their bits
- case TUINT8,
- TUINT16,
- TUINT32,
- TUINT64,
- TUINT,
- TUINTPTR:
- b.Set(maxintval[et])
- }
-
- v.U.(*Mpint).Xor(&b)
-
- case OPLUS_ | CTFLT_:
- break
-
- case OMINUS_ | CTFLT_:
- v.U.(*Mpflt).Neg()
-
- case OPLUS_ | CTCPLX_:
- break
-
- case OMINUS_ | CTCPLX_:
- v.U.(*Mpcplx).Real.Neg()
- v.U.(*Mpcplx).Imag.Neg()
-
- case ONOT_ | CTBOOL_:
- if !v.U.(bool) {
- goto settrue
- }
- goto setfalse
- }
- goto ret
}
- if nr.Type == nil {
- return
- }
- if consttype(nr) == 0 {
- return
- }
- wr = nr.Type.Etype
- if isInt[wr] || isFloat[wr] || isComplex[wr] {
- wr = TIDEAL
- }
-
- // check for compatible general types (numeric, string, etc)
- if wl != wr {
- if wl == TINTER || wr == TINTER {
- if n.Op == ONE {
- goto settrue
- }
- goto setfalse
- }
- goto illegal
- }
-
- // check for compatible types.
- switch n.Op {
- // ideal const mixes with anything but otherwise must match.
- default:
- if nl.Type.Etype != TIDEAL {
- nr = defaultlit(nr, nl.Type)
- n.Right = nr
- }
-
- if nr.Type.Etype != TIDEAL {
- nl = defaultlit(nl, nr.Type)
- n.Left = nl
- }
-
- if nl.Type.Etype != nr.Type.Etype {
- goto illegal
- }
-
- // right must be unsigned.
- // left can be ideal.
- case OLSH, ORSH:
- nr = defaultlit(nr, types.Types[TUINT])
+}
- n.Right = nr
- if nr.Type != nil && (nr.Type.IsSigned() || !nr.Type.IsInteger()) {
- goto illegal
- }
- if nl.Val().Ctype() != CTRUNE {
- nl.SetVal(toint(nl.Val()))
- }
- nr.SetVal(toint(nr.Val()))
+func match(x, y Val) (Val, Val) {
+ switch {
+ case x.Ctype() == CTCPLX || y.Ctype() == CTCPLX:
+ return tocplx(x), tocplx(y)
+ case x.Ctype() == CTFLT || y.Ctype() == CTFLT:
+ return toflt(x), toflt(y)
}
- // copy numeric value to avoid modifying
- // n->left, in case someone still refers to it (e.g. iota).
- v = copyval(nl.Val())
- rv = nr.Val()
-
- // convert to common ideal
- if v.Ctype() == CTCPLX || rv.Ctype() == CTCPLX {
- v = tocplx(v)
- rv = tocplx(rv)
- }
+ // Mixed int/rune are fine.
+ return x, y
+}
- if v.Ctype() == CTFLT || rv.Ctype() == CTFLT {
- v = toflt(v)
- rv = toflt(rv)
- }
+func compareOp(x Val, op Op, y Val) bool {
+ x, y = match(x, y)
- // Rune and int turns into rune.
- if v.Ctype() == CTRUNE && rv.Ctype() == CTINT {
- i := new(Mpint)
- i.Set(rv.U.(*Mpint))
- i.Rune = true
- rv.U = i
- }
- if v.Ctype() == CTINT && rv.Ctype() == CTRUNE {
- if n.Op == OLSH || n.Op == ORSH {
- i := new(Mpint)
- i.Set(rv.U.(*Mpint))
- rv.U = i
- } else {
- i := new(Mpint)
- i.Set(v.U.(*Mpint))
- i.Rune = true
- v.U = i
+ switch x.Ctype() {
+ case CTNIL:
+ _, _ = x.U.(*NilVal), y.U.(*NilVal) // assert dynamic types match
+ switch op {
+ case OEQ:
+ return true
+ case ONE:
+ return false
}
- }
- if v.Ctype() != rv.Ctype() {
- // Use of undefined name as constant?
- if (v.Ctype() == 0 || rv.Ctype() == 0) && nerrors > 0 {
- return
+ case CTBOOL:
+ x, y := x.U.(bool), y.U.(bool)
+ switch op {
+ case OEQ:
+ return x == y
+ case ONE:
+ return x != y
}
- Fatalf("constant type mismatch %v(%d) %v(%d)", nl.Type, v.Ctype(), nr.Type, rv.Ctype())
- }
-
- // rune values are int values for the purpose of constant folding.
- ctype = uint32(v.Ctype())
- if ctype == CTRUNE_ {
- ctype = CTINT_
- }
-
- // run op
- switch uint32(n.Op)<<16 | ctype {
- default:
- goto illegal
-
- case OADD_ | CTINT_:
- v.U.(*Mpint).Add(rv.U.(*Mpint))
-
- case OSUB_ | CTINT_:
- v.U.(*Mpint).Sub(rv.U.(*Mpint))
- case OMUL_ | CTINT_:
- v.U.(*Mpint).Mul(rv.U.(*Mpint))
+ case CTINT, CTRUNE:
+ x, y := x.U.(*Mpint), y.U.(*Mpint)
+ return cmpZero(x.Cmp(y), op)
- case ODIV_ | CTINT_:
- if rv.U.(*Mpint).CmpInt64(0) == 0 {
- yyerror("division by zero")
- v.U.(*Mpint).SetOverflow()
- break
- }
-
- v.U.(*Mpint).Quo(rv.U.(*Mpint))
+ case CTFLT:
+ x, y := x.U.(*Mpflt), y.U.(*Mpflt)
+ return cmpZero(x.Cmp(y), op)
- case OMOD_ | CTINT_:
- if rv.U.(*Mpint).CmpInt64(0) == 0 {
- yyerror("division by zero")
- v.U.(*Mpint).SetOverflow()
- break
+ case CTCPLX:
+ x, y := x.U.(*Mpcplx), y.U.(*Mpcplx)
+ eq := x.Real.Cmp(&y.Real) == 0 && x.Imag.Cmp(&y.Imag) == 0
+ switch op {
+ case OEQ:
+ return eq
+ case ONE:
+ return !eq
}
- v.U.(*Mpint).Rem(rv.U.(*Mpint))
-
- case OLSH_ | CTINT_:
- v.U.(*Mpint).Lsh(rv.U.(*Mpint))
-
- case ORSH_ | CTINT_:
- v.U.(*Mpint).Rsh(rv.U.(*Mpint))
-
- case OOR_ | CTINT_:
- v.U.(*Mpint).Or(rv.U.(*Mpint))
-
- case OAND_ | CTINT_:
- v.U.(*Mpint).And(rv.U.(*Mpint))
-
- case OANDNOT_ | CTINT_:
- v.U.(*Mpint).AndNot(rv.U.(*Mpint))
-
- case OXOR_ | CTINT_:
- v.U.(*Mpint).Xor(rv.U.(*Mpint))
-
- case OADD_ | CTFLT_:
- v.U.(*Mpflt).Add(rv.U.(*Mpflt))
+ case CTSTR:
+ x, y := x.U.(string), y.U.(string)
+ switch op {
+ case OEQ:
+ return x == y
+ case ONE:
+ return x != y
+ case OLT:
+ return x < y
+ case OLE:
+ return x <= y
+ case OGT:
+ return x > y
+ case OGE:
+ return x >= y
+ }
+ }
+
+ Fatalf("compareOp: bad comparison: %v %v %v", x, op, y)
+ panic("unreachable")
+}
- case OSUB_ | CTFLT_:
- v.U.(*Mpflt).Sub(rv.U.(*Mpflt))
+func cmpZero(x int, op Op) bool {
+ switch op {
+ case OEQ:
+ return x == 0
+ case ONE:
+ return x != 0
+ case OLT:
+ return x < 0
+ case OLE:
+ return x <= 0
+ case OGT:
+ return x > 0
+ case OGE:
+ return x >= 0
+ }
+
+ Fatalf("cmpZero: want comparison operator, got %v", op)
+ panic("unreachable")
+}
- case OMUL_ | CTFLT_:
- v.U.(*Mpflt).Mul(rv.U.(*Mpflt))
+func binaryOp(x Val, op Op, y Val) Val {
+ x, y = match(x, y)
- case ODIV_ | CTFLT_:
- if rv.U.(*Mpflt).CmpFloat64(0) == 0 {
- yyerror("division by zero")
- v.U.(*Mpflt).SetFloat64(1.0)
- break
+Outer:
+ switch x.Ctype() {
+ case CTBOOL:
+ x, y := x.U.(bool), y.U.(bool)
+ switch op {
+ case OANDAND:
+ return Val{U: x && y}
+ case OOROR:
+ return Val{U: x || y}
+ }
+
+ case CTINT, CTRUNE:
+ x, y := x.U.(*Mpint), y.U.(*Mpint)
+
+ u := new(Mpint)
+ u.Rune = x.Rune || y.Rune
+ u.Set(x)
+ switch op {
+ case OADD:
+ u.Add(y)
+ case OSUB:
+ u.Sub(y)
+ case OMUL:
+ u.Mul(y)
+ case ODIV:
+ if y.CmpInt64(0) == 0 {
+ yyerror("division by zero")
+ u.SetOverflow()
+ break
+ }
+ u.Quo(y)
+ case OMOD:
+ if y.CmpInt64(0) == 0 {
+ yyerror("division by zero")
+ u.SetOverflow()
+ break
+ }
+ u.Rem(y)
+ case OOR:
+ u.Or(y)
+ case OAND:
+ u.And(y)
+ case OANDNOT:
+ u.AndNot(y)
+ case OXOR:
+ u.Xor(y)
+ default:
+ break Outer
}
+ return Val{U: u}
- v.U.(*Mpflt).Quo(rv.U.(*Mpflt))
-
- // The default case above would print 'ideal % ideal',
- // which is not quite an ideal error.
- case OMOD_ | CTFLT_:
- if !n.Diag() {
+ case CTFLT:
+ x, y := x.U.(*Mpflt), y.U.(*Mpflt)
+
+ u := newMpflt()
+ u.Set(x)
+ switch op {
+ case OADD:
+ u.Add(y)
+ case OSUB:
+ u.Sub(y)
+ case OMUL:
+ u.Mul(y)
+ case ODIV:
+ if y.CmpFloat64(0) == 0 {
+ yyerror("division by zero")
+ u.SetFloat64(1)
+ break
+ }
+ u.Quo(y)
+ case OMOD:
+ // TODO(mdempsky): Move to typecheck.
yyerror("illegal constant expression: floating-point %% operation")
- n.SetDiag(true)
- }
-
- return
-
- case OADD_ | CTCPLX_:
- v.U.(*Mpcplx).Real.Add(&rv.U.(*Mpcplx).Real)
- v.U.(*Mpcplx).Imag.Add(&rv.U.(*Mpcplx).Imag)
-
- case OSUB_ | CTCPLX_:
- v.U.(*Mpcplx).Real.Sub(&rv.U.(*Mpcplx).Real)
- v.U.(*Mpcplx).Imag.Sub(&rv.U.(*Mpcplx).Imag)
-
- case OMUL_ | CTCPLX_:
- v.U.(*Mpcplx).Mul(rv.U.(*Mpcplx))
-
- case ODIV_ | CTCPLX_:
- if !v.U.(*Mpcplx).Div(rv.U.(*Mpcplx)) {
- yyerror("complex division by zero")
- rv.U.(*Mpcplx).Real.SetFloat64(1.0)
- rv.U.(*Mpcplx).Imag.SetFloat64(0.0)
- break
- }
-
- case OEQ_ | CTNIL_:
- goto settrue
-
- case ONE_ | CTNIL_:
- goto setfalse
-
- case OEQ_ | CTINT_:
- if v.U.(*Mpint).Cmp(rv.U.(*Mpint)) == 0 {
- goto settrue
- }
- goto setfalse
-
- case ONE_ | CTINT_:
- if v.U.(*Mpint).Cmp(rv.U.(*Mpint)) != 0 {
- goto settrue
- }
- goto setfalse
-
- case OLT_ | CTINT_:
- if v.U.(*Mpint).Cmp(rv.U.(*Mpint)) < 0 {
- goto settrue
- }
- goto setfalse
-
- case OLE_ | CTINT_:
- if v.U.(*Mpint).Cmp(rv.U.(*Mpint)) <= 0 {
- goto settrue
- }
- goto setfalse
-
- case OGE_ | CTINT_:
- if v.U.(*Mpint).Cmp(rv.U.(*Mpint)) >= 0 {
- goto settrue
- }
- goto setfalse
-
- case OGT_ | CTINT_:
- if v.U.(*Mpint).Cmp(rv.U.(*Mpint)) > 0 {
- goto settrue
- }
- goto setfalse
-
- case OEQ_ | CTFLT_:
- if v.U.(*Mpflt).Cmp(rv.U.(*Mpflt)) == 0 {
- goto settrue
- }
- goto setfalse
-
- case ONE_ | CTFLT_:
- if v.U.(*Mpflt).Cmp(rv.U.(*Mpflt)) != 0 {
- goto settrue
- }
- goto setfalse
-
- case OLT_ | CTFLT_:
- if v.U.(*Mpflt).Cmp(rv.U.(*Mpflt)) < 0 {
- goto settrue
- }
- goto setfalse
-
- case OLE_ | CTFLT_:
- if v.U.(*Mpflt).Cmp(rv.U.(*Mpflt)) <= 0 {
- goto settrue
- }
- goto setfalse
-
- case OGE_ | CTFLT_:
- if v.U.(*Mpflt).Cmp(rv.U.(*Mpflt)) >= 0 {
- goto settrue
- }
- goto setfalse
-
- case OGT_ | CTFLT_:
- if v.U.(*Mpflt).Cmp(rv.U.(*Mpflt)) > 0 {
- goto settrue
- }
- goto setfalse
-
- case OEQ_ | CTCPLX_:
- if v.U.(*Mpcplx).Real.Cmp(&rv.U.(*Mpcplx).Real) == 0 && v.U.(*Mpcplx).Imag.Cmp(&rv.U.(*Mpcplx).Imag) == 0 {
- goto settrue
- }
- goto setfalse
-
- case ONE_ | CTCPLX_:
- if v.U.(*Mpcplx).Real.Cmp(&rv.U.(*Mpcplx).Real) != 0 || v.U.(*Mpcplx).Imag.Cmp(&rv.U.(*Mpcplx).Imag) != 0 {
- goto settrue
- }
- goto setfalse
-
- case OEQ_ | CTSTR_:
- if strlit(nl) == strlit(nr) {
- goto settrue
- }
- goto setfalse
-
- case ONE_ | CTSTR_:
- if strlit(nl) != strlit(nr) {
- goto settrue
- }
- goto setfalse
-
- case OLT_ | CTSTR_:
- if strlit(nl) < strlit(nr) {
- goto settrue
- }
- goto setfalse
-
- case OLE_ | CTSTR_:
- if strlit(nl) <= strlit(nr) {
- goto settrue
- }
- goto setfalse
-
- case OGE_ | CTSTR_:
- if strlit(nl) >= strlit(nr) {
- goto settrue
- }
- goto setfalse
-
- case OGT_ | CTSTR_:
- if strlit(nl) > strlit(nr) {
- goto settrue
+ default:
+ break Outer
}
- goto setfalse
+ return Val{U: u}
- case OOROR_ | CTBOOL_:
- if v.U.(bool) || rv.U.(bool) {
- goto settrue
+ case CTCPLX:
+ x, y := x.U.(*Mpcplx), y.U.(*Mpcplx)
+
+ u := new(Mpcplx)
+ u.Real.Set(&x.Real)
+ u.Imag.Set(&x.Imag)
+ switch op {
+ case OADD:
+ u.Real.Add(&y.Real)
+ u.Imag.Add(&y.Imag)
+ case OSUB:
+ u.Real.Sub(&y.Real)
+ u.Imag.Sub(&y.Imag)
+ case OMUL:
+ u.Mul(y)
+ case ODIV:
+ if !u.Div(y) {
+ yyerror("complex division by zero")
+ u.Real.SetFloat64(1)
+ u.Imag.SetFloat64(0)
+ }
+ default:
+ break Outer
}
- goto setfalse
+ return Val{U: u}
+ }
- case OANDAND_ | CTBOOL_:
- if v.U.(bool) && rv.U.(bool) {
- goto settrue
- }
- goto setfalse
+ Fatalf("binaryOp: bad operation: %v %v %v", x, op, y)
+ panic("unreachable")
+}
- case OEQ_ | CTBOOL_:
- if v.U.(bool) == rv.U.(bool) {
- goto settrue
+func unaryOp(op Op, x Val, t *types.Type) Val {
+ switch op {
+ case OPLUS:
+ switch x.Ctype() {
+ case CTINT, CTRUNE, CTFLT, CTCPLX:
+ return x
+ }
+
+ case OMINUS:
+ switch x.Ctype() {
+ case CTINT, CTRUNE:
+ x := x.U.(*Mpint)
+ u := new(Mpint)
+ u.Rune = x.Rune
+ u.Set(x)
+ u.Neg()
+ return Val{U: u}
+
+ case CTFLT:
+ x := x.U.(*Mpflt)
+ u := newMpflt()
+ u.Set(x)
+ u.Neg()
+ return Val{U: u}
+
+ case CTCPLX:
+ x := x.U.(*Mpcplx)
+ u := new(Mpcplx)
+ u.Real.Set(&x.Real)
+ u.Imag.Set(&x.Imag)
+ u.Real.Neg()
+ u.Imag.Neg()
+ return Val{U: u}
+ }
+
+ case OCOM:
+ x := x.U.(*Mpint)
+
+ u := new(Mpint)
+ u.Rune = x.Rune
+ if t.IsSigned() || t.IsUntyped() {
+ // Signed values change sign.
+ u.SetInt64(-1)
+ } else {
+ // Unsigned values invert their bits.
+ u.Set(maxintval[t.Etype])
}
- goto setfalse
+ u.Xor(x)
+ return Val{U: u}
- case ONE_ | CTBOOL_:
- if v.U.(bool) != rv.U.(bool) {
- goto settrue
- }
- goto setfalse
+ case ONOT:
+ return Val{U: !x.U.(bool)}
}
-ret:
- setconst(n, v)
- return
-
-settrue:
- setconst(n, Val{true})
- return
+ Fatalf("unaryOp: bad operation: %v %v", op, x)
+ panic("unreachable")
+}
-setfalse:
- setconst(n, Val{false})
- return
+func shiftOp(x Val, op Op, y Val) Val {
+ if x.Ctype() != CTRUNE {
+ x = toint(x)
+ }
+ y = toint(y)
-illegal:
- if !n.Diag() {
- yyerror("illegal constant expression: %v %v %v", nl.Type, n.Op, nr.Type)
- n.SetDiag(true)
+ u := new(Mpint)
+ u.Set(x.U.(*Mpint))
+ u.Rune = x.U.(*Mpint).Rune
+ switch op {
+ case OLSH:
+ u.Lsh(y.U.(*Mpint))
+ case ORSH:
+ u.Rsh(y.U.(*Mpint))
+ default:
+ Fatalf("shiftOp: bad operator: %v", op)
+ panic("unreachable")
}
+ return Val{U: u}
}
// setconst rewrites n as an OLITERAL with value v.
}
}
+func setboolconst(n *Node, v bool) {
+ setconst(n, Val{U: v})
+}
+
func setintconst(n *Node, v int64) {
u := new(Mpint)
u.SetInt64(v)