1// Copyright 2013 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
5package ir
6
7// This file defines the Const SSA value type.
8
9import (
10	"fmt"
11	"go/constant"
12	"go/types"
13	"strconv"
14)
15
16// NewConst returns a new constant of the specified value and type.
17// val must be valid according to the specification of Const.Value.
18//
19func NewConst(val constant.Value, typ types.Type) *Const {
20	return &Const{
21		register: register{
22			typ: typ,
23		},
24		Value: val,
25	}
26}
27
28// intConst returns an 'int' constant that evaluates to i.
29// (i is an int64 in case the host is narrower than the target.)
30func intConst(i int64) *Const {
31	return NewConst(constant.MakeInt64(i), tInt)
32}
33
34// nilConst returns a nil constant of the specified type, which may
35// be any reference type, including interfaces.
36//
37func nilConst(typ types.Type) *Const {
38	return NewConst(nil, typ)
39}
40
41// stringConst returns a 'string' constant that evaluates to s.
42func stringConst(s string) *Const {
43	return NewConst(constant.MakeString(s), tString)
44}
45
46// zeroConst returns a new "zero" constant of the specified type,
47// which must not be an array or struct type: the zero values of
48// aggregates are well-defined but cannot be represented by Const.
49//
50func zeroConst(t types.Type) *Const {
51	switch t := t.(type) {
52	case *types.Basic:
53		switch {
54		case t.Info()&types.IsBoolean != 0:
55			return NewConst(constant.MakeBool(false), t)
56		case t.Info()&types.IsNumeric != 0:
57			return NewConst(constant.MakeInt64(0), t)
58		case t.Info()&types.IsString != 0:
59			return NewConst(constant.MakeString(""), t)
60		case t.Kind() == types.UnsafePointer:
61			fallthrough
62		case t.Kind() == types.UntypedNil:
63			return nilConst(t)
64		default:
65			panic(fmt.Sprint("zeroConst for unexpected type:", t))
66		}
67	case *types.Pointer, *types.Slice, *types.Interface, *types.Chan, *types.Map, *types.Signature:
68		return nilConst(t)
69	case *types.Named:
70		return NewConst(zeroConst(t.Underlying()).Value, t)
71	case *types.Array, *types.Struct, *types.Tuple:
72		panic(fmt.Sprint("zeroConst applied to aggregate:", t))
73	}
74	panic(fmt.Sprint("zeroConst: unexpected ", t))
75}
76
77func (c *Const) RelString(from *types.Package) string {
78	var p string
79	if c.Value == nil {
80		p = "nil"
81	} else if c.Value.Kind() == constant.String {
82		v := constant.StringVal(c.Value)
83		const max = 20
84		// TODO(adonovan): don't cut a rune in half.
85		if len(v) > max {
86			v = v[:max-3] + "..." // abbreviate
87		}
88		p = strconv.Quote(v)
89	} else {
90		p = c.Value.String()
91	}
92	return fmt.Sprintf("Const <%s> {%s}", relType(c.Type(), from), p)
93}
94
95func (c *Const) String() string {
96	return c.RelString(c.Parent().pkg())
97}
98
99// IsNil returns true if this constant represents a typed or untyped nil value.
100func (c *Const) IsNil() bool {
101	return c.Value == nil
102}
103
104// Int64 returns the numeric value of this constant truncated to fit
105// a signed 64-bit integer.
106//
107func (c *Const) Int64() int64 {
108	switch x := constant.ToInt(c.Value); x.Kind() {
109	case constant.Int:
110		if i, ok := constant.Int64Val(x); ok {
111			return i
112		}
113		return 0
114	case constant.Float:
115		f, _ := constant.Float64Val(x)
116		return int64(f)
117	}
118	panic(fmt.Sprintf("unexpected constant value: %T", c.Value))
119}
120
121// Uint64 returns the numeric value of this constant truncated to fit
122// an unsigned 64-bit integer.
123//
124func (c *Const) Uint64() uint64 {
125	switch x := constant.ToInt(c.Value); x.Kind() {
126	case constant.Int:
127		if u, ok := constant.Uint64Val(x); ok {
128			return u
129		}
130		return 0
131	case constant.Float:
132		f, _ := constant.Float64Val(x)
133		return uint64(f)
134	}
135	panic(fmt.Sprintf("unexpected constant value: %T", c.Value))
136}
137
138// Float64 returns the numeric value of this constant truncated to fit
139// a float64.
140//
141func (c *Const) Float64() float64 {
142	f, _ := constant.Float64Val(c.Value)
143	return f
144}
145
146// Complex128 returns the complex value of this constant truncated to
147// fit a complex128.
148//
149func (c *Const) Complex128() complex128 {
150	re, _ := constant.Float64Val(constant.Real(c.Value))
151	im, _ := constant.Float64Val(constant.Imag(c.Value))
152	return complex(re, im)
153}
154