// 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 ir import ( "go/constant" "math" "cmd/compile/internal/base" "cmd/compile/internal/types" ) func ConstType(n Node) constant.Kind { if n == nil || n.Op() != OLITERAL { return constant.Unknown } return n.Val().Kind() } // ConstValue returns the constant value stored in n as an interface{}. // It returns int64s for ints and runes, float64s for floats, // and complex128s for complex values. func ConstValue(n Node) interface{} { switch v := n.Val(); v.Kind() { default: base.Fatalf("unexpected constant: %v", v) panic("unreachable") case constant.Bool: return constant.BoolVal(v) case constant.String: return constant.StringVal(v) case constant.Int: return IntVal(n.Type(), v) case constant.Float: return Float64Val(v) case constant.Complex: return complex(Float64Val(constant.Real(v)), Float64Val(constant.Imag(v))) } } // IntVal returns v converted to int64. // Note: if t is uint64, very large values will be converted to negative int64. func IntVal(t *types.Type, v constant.Value) int64 { if t.IsUnsigned() { if x, ok := constant.Uint64Val(v); ok { return int64(x) } } else { if x, ok := constant.Int64Val(v); ok { return x } } base.Fatalf("%v out of range for %v", v, t) panic("unreachable") } func Float64Val(v constant.Value) float64 { if x, _ := constant.Float64Val(v); !math.IsInf(x, 0) { return x + 0 // avoid -0 (should not be needed, but be conservative) } base.Fatalf("bad float64 value: %v", v) panic("unreachable") } func AssertValidTypeForConst(t *types.Type, v constant.Value) { if !ValidTypeForConst(t, v) { base.Fatalf("%v (%v) does not represent %v (%v)", t, t.Kind(), v, v.Kind()) } } func ValidTypeForConst(t *types.Type, v constant.Value) bool { switch v.Kind() { case constant.Unknown: return OKForConst[t.Kind()] case constant.Bool: return t.IsBoolean() case constant.String: return t.IsString() case constant.Int: return t.IsInteger() case constant.Float: return t.IsFloat() case constant.Complex: return t.IsComplex() } base.Fatalf("unexpected constant kind: %v", v) panic("unreachable") } // NewLiteral returns a new untyped constant with value v. func NewLiteral(v constant.Value) Node { return NewBasicLit(base.Pos, v) } func idealType(ct constant.Kind) *types.Type { switch ct { case constant.String: return types.UntypedString case constant.Bool: return types.UntypedBool case constant.Int: return types.UntypedInt case constant.Float: return types.UntypedFloat case constant.Complex: return types.UntypedComplex } base.Fatalf("unexpected Ctype: %v", ct) return nil } var OKForConst [types.NTYPE]bool // CanInt64 reports whether it is safe to call Int64Val() on n. func CanInt64(n Node) bool { if !IsConst(n, constant.Int) { return false } // if the value inside n cannot be represented as an int64, the // return value of Int64 is undefined _, ok := constant.Int64Val(n.Val()) return ok } // Int64Val returns n as an int64. // n must be an integer or rune constant. func Int64Val(n Node) int64 { if !IsConst(n, constant.Int) { base.Fatalf("Int64Val(%v)", n) } x, ok := constant.Int64Val(n.Val()) if !ok { base.Fatalf("Int64Val(%v)", n) } return x } // Uint64Val returns n as an uint64. // n must be an integer or rune constant. func Uint64Val(n Node) uint64 { if !IsConst(n, constant.Int) { base.Fatalf("Uint64Val(%v)", n) } x, ok := constant.Uint64Val(n.Val()) if !ok { base.Fatalf("Uint64Val(%v)", n) } return x } // BoolVal returns n as a bool. // n must be a boolean constant. func BoolVal(n Node) bool { if !IsConst(n, constant.Bool) { base.Fatalf("BoolVal(%v)", n) } return constant.BoolVal(n.Val()) } // StringVal returns the value of a literal string Node as a string. // n must be a string constant. func StringVal(n Node) string { if !IsConst(n, constant.String) { base.Fatalf("StringVal(%v)", n) } return constant.StringVal(n.Val()) }