mirror of
https://github.com/golang/go
synced 2024-11-19 03:34:41 -07:00
6c7ce1c2d3
Implement Pos() method for Values: Parameter, Capture, Phi. (Not Literal, Builtin.) Instructions: UnOp, BinOp, Store. 'address' (an lvalue) now needs position of '*' in "*addr". Also: - Un-export fields Pos_ Type_ Name_ Block_ from various values/instructions. Define NewFunction() as a temporary measure. Will try to eliminate calls from clients... - Remove Implements{Value,Member,Interface} marker methods. I've decided I don't like them. - Func.addParamObj helper. - Various comment fixes. R=gri CC=golang-dev https://golang.org/cl/9740046
470 lines
9.8 KiB
Go
470 lines
9.8 KiB
Go
package interp
|
|
|
|
// Values
|
|
//
|
|
// All interpreter values are "boxed" in the empty interface, value.
|
|
// The range of possible dynamic types within value are:
|
|
//
|
|
// - bool
|
|
// - numbers (all built-in int/float/complex types are distinguished)
|
|
// - string
|
|
// - map[value]value --- maps for which usesBuiltinMap(keyType)
|
|
// *hashmap --- maps for which !usesBuiltinMap(keyType)
|
|
// - chan value
|
|
// - []value --- slices
|
|
// - iface --- interfaces.
|
|
// - structure --- structs. Fields are ordered and accessed by numeric indices.
|
|
// - array --- arrays.
|
|
// - *value --- pointers. Careful: *value is a distinct type from *array etc.
|
|
// - *ssa.Function \
|
|
// *ssa.Builtin } --- functions.
|
|
// *closure /
|
|
// - tuple --- as returned by Ret, Next, "value,ok" modes, etc.
|
|
// - iter --- iterators from 'range' over map or string.
|
|
// - bad --- a poison pill for locals that have gone out of scope.
|
|
// - rtype -- the interpreter's concrete implementation of reflect.Type
|
|
//
|
|
// Note that nil is not on this list.
|
|
//
|
|
// Pay close attention to whether or not the dynamic type is a pointer.
|
|
// The compiler cannot help you since value is an empty interface.
|
|
|
|
import (
|
|
"bytes"
|
|
"fmt"
|
|
"io"
|
|
"reflect"
|
|
"strings"
|
|
"unsafe"
|
|
|
|
"code.google.com/p/go.tools/go/types"
|
|
"code.google.com/p/go.tools/ssa"
|
|
)
|
|
|
|
type value interface{}
|
|
|
|
type tuple []value
|
|
|
|
type array []value
|
|
|
|
type iface struct {
|
|
t types.Type // never an "untyped" type
|
|
v value
|
|
}
|
|
|
|
type structure []value
|
|
|
|
// For map, array, *array, slice, string or channel.
|
|
type iter interface {
|
|
// next returns a Tuple (key, value, ok).
|
|
// key and value are unaliased, e.g. copies of the sequence element.
|
|
next() tuple
|
|
}
|
|
|
|
type closure struct {
|
|
Fn *ssa.Function
|
|
Env []value
|
|
}
|
|
|
|
type bad struct{}
|
|
|
|
type rtype struct {
|
|
t types.Type
|
|
}
|
|
|
|
// Hash functions and equivalence relation:
|
|
|
|
// hashString computes the FNV hash of s.
|
|
func hashString(s string) int {
|
|
var h uint32
|
|
for i := 0; i < len(s); i++ {
|
|
h ^= uint32(s[i])
|
|
h *= 16777619
|
|
}
|
|
return int(h)
|
|
}
|
|
|
|
// hashType returns a hash for t such that
|
|
// types.IsIdentical(x, y) => hashType(x) == hashType(y).
|
|
func hashType(t types.Type) int {
|
|
// TODO(adonovan): fix: not sound! "IsIdentical" Signatures
|
|
// may have different parameter names; use typemap.Hasher when
|
|
// available.
|
|
return hashString(t.String()) // TODO(gri): provide a better hash
|
|
}
|
|
|
|
// usesBuiltinMap returns true if the built-in hash function and
|
|
// equivalence relation for type t are consistent with those of the
|
|
// interpreter's representation of type t. Such types are: all basic
|
|
// types (bool, numbers, string), pointers and channels.
|
|
//
|
|
// usesBuiltinMap returns false for types that require a custom map
|
|
// implementation: interfaces, arrays and structs.
|
|
//
|
|
// Panic ensues if t is an invalid map key type: function, map or slice.
|
|
func usesBuiltinMap(t types.Type) bool {
|
|
switch t := t.(type) {
|
|
case *types.Basic, *types.Chan, *types.Pointer:
|
|
return true
|
|
case *types.Named:
|
|
return usesBuiltinMap(t.Underlying())
|
|
case *types.Interface, *types.Array, *types.Struct:
|
|
return false
|
|
}
|
|
panic(fmt.Sprintf("invalid map key type: %T", t))
|
|
}
|
|
|
|
func (x array) eq(_y interface{}) bool {
|
|
y := _y.(array)
|
|
for i, xi := range x {
|
|
if !equals(xi, y[i]) {
|
|
return false
|
|
}
|
|
}
|
|
return true
|
|
}
|
|
|
|
func (x array) hash() int {
|
|
h := 0
|
|
for _, xi := range x {
|
|
h += hash(xi)
|
|
}
|
|
return h
|
|
}
|
|
|
|
func (x structure) eq(_y interface{}) bool {
|
|
y := _y.(structure)
|
|
// TODO(adonovan): fix: only non-blank fields should be
|
|
// compared. This requires that we have type information
|
|
// available from the enclosing == operation or map access;
|
|
// the value is not sufficient.
|
|
for i, xi := range x {
|
|
if !equals(xi, y[i]) {
|
|
return false
|
|
}
|
|
}
|
|
return true
|
|
}
|
|
|
|
func (x structure) hash() int {
|
|
h := 0
|
|
for _, xi := range x {
|
|
h += hash(xi)
|
|
}
|
|
return h
|
|
}
|
|
|
|
func (x iface) eq(_y interface{}) bool {
|
|
y := _y.(iface)
|
|
return types.IsIdentical(x.t, y.t) && (x.t == nil || equals(x.v, y.v))
|
|
}
|
|
|
|
func (x iface) hash() int {
|
|
return hashType(x.t)*8581 + hash(x.v)
|
|
}
|
|
|
|
func (x rtype) hash() int {
|
|
return hashType(x.t)
|
|
}
|
|
|
|
func (x rtype) eq(y interface{}) bool {
|
|
return types.IsIdentical(x.t, y.(rtype).t)
|
|
}
|
|
|
|
// equals returns true iff x and y are equal according to Go's
|
|
// linguistic equivalence relation. In a well-typed program, the
|
|
// types of x and y are guaranteed equal.
|
|
func equals(x, y value) bool {
|
|
switch x := x.(type) {
|
|
case bool:
|
|
return x == y.(bool)
|
|
case int:
|
|
return x == y.(int)
|
|
case int8:
|
|
return x == y.(int8)
|
|
case int16:
|
|
return x == y.(int16)
|
|
case int32:
|
|
return x == y.(int32)
|
|
case int64:
|
|
return x == y.(int64)
|
|
case uint:
|
|
return x == y.(uint)
|
|
case uint8:
|
|
return x == y.(uint8)
|
|
case uint16:
|
|
return x == y.(uint16)
|
|
case uint32:
|
|
return x == y.(uint32)
|
|
case uint64:
|
|
return x == y.(uint64)
|
|
case uintptr:
|
|
return x == y.(uintptr)
|
|
case float32:
|
|
return x == y.(float32)
|
|
case float64:
|
|
return x == y.(float64)
|
|
case complex64:
|
|
return x == y.(complex64)
|
|
case complex128:
|
|
return x == y.(complex128)
|
|
case string:
|
|
return x == y.(string)
|
|
case *value:
|
|
return x == y.(*value)
|
|
case chan value:
|
|
return x == y.(chan value)
|
|
case structure:
|
|
return x.eq(y)
|
|
case array:
|
|
return x.eq(y)
|
|
case iface:
|
|
return x.eq(y)
|
|
case rtype:
|
|
return x.eq(y)
|
|
|
|
// Since the following types don't support comparison,
|
|
// these cases are only reachable if one of x or y is
|
|
// (literally) nil.
|
|
case *hashmap:
|
|
return x == y.(*hashmap)
|
|
case map[value]value:
|
|
return (x != nil) == (y.(map[value]value) != nil)
|
|
case *ssa.Function, *closure:
|
|
return x == y
|
|
case []value:
|
|
return (x != nil) == (y.([]value) != nil)
|
|
}
|
|
panic(fmt.Sprintf("comparing incomparable type %T", x))
|
|
}
|
|
|
|
// Returns an integer hash of x such that equals(x, y) => hash(x) == hash(y).
|
|
func hash(x value) int {
|
|
switch x := x.(type) {
|
|
case bool:
|
|
if x {
|
|
return 1
|
|
}
|
|
return 0
|
|
case int:
|
|
return x
|
|
case int8:
|
|
return int(x)
|
|
case int16:
|
|
return int(x)
|
|
case int32:
|
|
return int(x)
|
|
case int64:
|
|
return int(x)
|
|
case uint:
|
|
return int(x)
|
|
case uint8:
|
|
return int(x)
|
|
case uint16:
|
|
return int(x)
|
|
case uint32:
|
|
return int(x)
|
|
case uint64:
|
|
return int(x)
|
|
case uintptr:
|
|
return int(x)
|
|
case float32:
|
|
return int(x)
|
|
case float64:
|
|
return int(x)
|
|
case complex64:
|
|
return int(real(x))
|
|
case complex128:
|
|
return int(real(x))
|
|
case string:
|
|
return hashString(x)
|
|
case *value:
|
|
return int(uintptr(unsafe.Pointer(x)))
|
|
case chan value:
|
|
return int(uintptr(reflect.ValueOf(x).Pointer()))
|
|
case structure:
|
|
return x.hash()
|
|
case array:
|
|
return x.hash()
|
|
case iface:
|
|
return x.hash()
|
|
case rtype:
|
|
return x.hash()
|
|
}
|
|
panic(fmt.Sprintf("%T is unhashable", x))
|
|
}
|
|
|
|
// copyVal returns a copy of value v.
|
|
// TODO(adonovan): add tests of aliasing and mutation.
|
|
func copyVal(v value) value {
|
|
if v == nil {
|
|
panic("copyVal(nil)")
|
|
}
|
|
switch v := v.(type) {
|
|
case bool, int, int8, int16, int32, int64, uint, uint8, uint16, uint32, uint64, uintptr, float32, float64, complex64, complex128, string, unsafe.Pointer:
|
|
return v
|
|
case map[value]value:
|
|
return v
|
|
case *hashmap:
|
|
return v
|
|
case chan value:
|
|
return v
|
|
case *value:
|
|
return v
|
|
case *ssa.Function, *ssa.Builtin, *closure:
|
|
return v
|
|
case iface:
|
|
return v
|
|
case []value:
|
|
return v
|
|
case structure:
|
|
a := make(structure, len(v))
|
|
copy(a, v)
|
|
return a
|
|
case array:
|
|
a := make(array, len(v))
|
|
copy(a, v)
|
|
return a
|
|
case tuple:
|
|
break
|
|
case rtype:
|
|
return v
|
|
}
|
|
panic(fmt.Sprintf("cannot copy %T", v))
|
|
}
|
|
|
|
// Prints in the style of built-in println.
|
|
// (More or less; in gc println is actually a compiler intrinsic and
|
|
// can distinguish println(1) from println(interface{}(1)).)
|
|
func toWriter(w io.Writer, v value) {
|
|
switch v := v.(type) {
|
|
case nil, bool, int, int8, int16, int32, int64, uint, uint8, uint16, uint32, uint64, uintptr, float32, float64, complex64, complex128, string:
|
|
fmt.Fprintf(w, "%v", v)
|
|
|
|
case map[value]value:
|
|
io.WriteString(w, "map[")
|
|
sep := " "
|
|
for k, e := range v {
|
|
io.WriteString(w, sep)
|
|
sep = " "
|
|
toWriter(w, k)
|
|
io.WriteString(w, ":")
|
|
toWriter(w, e)
|
|
}
|
|
io.WriteString(w, "]")
|
|
|
|
case *hashmap:
|
|
io.WriteString(w, "map[")
|
|
sep := " "
|
|
for _, e := range v.table {
|
|
for e != nil {
|
|
io.WriteString(w, sep)
|
|
sep = " "
|
|
toWriter(w, e.key)
|
|
io.WriteString(w, ":")
|
|
toWriter(w, e.value)
|
|
e = e.next
|
|
}
|
|
}
|
|
io.WriteString(w, "]")
|
|
|
|
case chan value:
|
|
fmt.Fprintf(w, "%v", v) // (an address)
|
|
|
|
case *value:
|
|
if v == nil {
|
|
io.WriteString(w, "<nil>")
|
|
} else {
|
|
fmt.Fprintf(w, "%p", v)
|
|
}
|
|
|
|
case iface:
|
|
toWriter(w, v.v)
|
|
|
|
case structure:
|
|
io.WriteString(w, "{")
|
|
for i, e := range v {
|
|
if i > 0 {
|
|
io.WriteString(w, " ")
|
|
}
|
|
toWriter(w, e)
|
|
}
|
|
io.WriteString(w, "}")
|
|
|
|
case array:
|
|
io.WriteString(w, "[")
|
|
for i, e := range v {
|
|
if i > 0 {
|
|
io.WriteString(w, " ")
|
|
}
|
|
toWriter(w, e)
|
|
}
|
|
io.WriteString(w, "]")
|
|
|
|
case []value:
|
|
io.WriteString(w, "[")
|
|
for i, e := range v {
|
|
if i > 0 {
|
|
io.WriteString(w, " ")
|
|
}
|
|
toWriter(w, e)
|
|
}
|
|
io.WriteString(w, "]")
|
|
|
|
case *ssa.Function, *ssa.Builtin, *closure:
|
|
fmt.Fprintf(w, "%p", v) // (an address)
|
|
|
|
case rtype:
|
|
io.WriteString(w, v.t.String())
|
|
|
|
case tuple:
|
|
// Unreachable in well-formed Go programs
|
|
io.WriteString(w, "(")
|
|
for i, e := range v {
|
|
if i > 0 {
|
|
io.WriteString(w, ", ")
|
|
}
|
|
toWriter(w, e)
|
|
}
|
|
io.WriteString(w, ")")
|
|
|
|
default:
|
|
fmt.Fprintf(w, "<%T>", v)
|
|
}
|
|
}
|
|
|
|
// Implements printing of Go values in the style of built-in println.
|
|
func toString(v value) string {
|
|
var b bytes.Buffer
|
|
toWriter(&b, v)
|
|
return b.String()
|
|
}
|
|
|
|
// ------------------------------------------------------------------------
|
|
// Iterators
|
|
|
|
type stringIter struct {
|
|
*strings.Reader
|
|
i int
|
|
}
|
|
|
|
func (it *stringIter) next() tuple {
|
|
okv := make(tuple, 3)
|
|
ch, n, err := it.ReadRune()
|
|
ok := err != io.EOF
|
|
okv[0] = ok
|
|
if ok {
|
|
okv[1] = it.i
|
|
okv[2] = ch
|
|
}
|
|
it.i += n
|
|
return okv
|
|
}
|
|
|
|
type mapIter chan [2]value
|
|
|
|
func (it mapIter) next() tuple {
|
|
kv, ok := <-it
|
|
return tuple{ok, kv[0], kv[1]}
|
|
}
|