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