github.com/jd-ly/tools@v0.5.7/go/ssa/const.go (about)

     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  
     5  package ssa
     6  
     7  // This file defines the Const SSA value type.
     8  
     9  import (
    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  //
    20  func 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.)
    26  func 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  //
    33  func nilConst(typ types.Type) *Const {
    34  	return NewConst(nil, typ)
    35  }
    36  
    37  // stringConst returns a 'string' constant that evaluates to s.
    38  func 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  //
    46  func 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  
    73  func (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  
    91  func (c *Const) Name() string {
    92  	return c.RelString(nil)
    93  }
    94  
    95  func (c *Const) String() string {
    96  	return c.Name()
    97  }
    98  
    99  func (c *Const) Type() types.Type {
   100  	return c.typ
   101  }
   102  
   103  func (c *Const) Referrers() *[]Instruction {
   104  	return nil
   105  }
   106  
   107  func (c *Const) Parent() *Function { return nil }
   108  
   109  func (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.
   114  func (c *Const) IsNil() bool {
   115  	return c.Value == nil
   116  }
   117  
   118  // TODO(adonovan): move everything below into github.com/jd-ly/tools/go/ssa/interp.
   119  
   120  // Int64 returns the numeric value of this constant truncated to fit
   121  // a signed 64-bit integer.
   122  //
   123  func (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  //
   140  func (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  //
   157  func (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  //
   165  func (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  }