Files
moxa/interp/type.go

1052 lines
26 KiB
Go

package interp
import (
"reflect"
"strconv"
)
// tcat defines interpreter type categories
type tcat uint
// Types for go language
const (
nilT tcat = iota
aliasT
arrayT
binT
binPkgT
boolT
builtinT
byteT
chanT
complex64T
complex128T
errorT
float32T
float64T
funcT
interfaceT
intT
int8T
int16T
int32T
int64T
mapT
ptrT
runeT
srcPkgT
stringT
structT
uintT
uint8T
uint16T
uint32T
uint64T
uintptrT
valueT
variadicT
maxT
)
var cats = [...]string{
nilT: "nilT",
aliasT: "aliasT",
arrayT: "arrayT",
binT: "binT",
binPkgT: "binPkgT",
byteT: "byteT",
boolT: "boolT",
builtinT: "builtinT",
chanT: "chanT",
complex64T: "complex64T",
complex128T: "complex128T",
errorT: "errorT",
float32T: "float32",
float64T: "float64T",
funcT: "funcT",
interfaceT: "interfaceT",
intT: "intT",
int8T: "int8T",
int16T: "int16T",
int32T: "int32T",
int64T: "int64T",
mapT: "mapT",
ptrT: "ptrT",
runeT: "runeT",
srcPkgT: "srcPkgT",
stringT: "stringT",
structT: "structT",
uintT: "uintT",
uint8T: "uint8T",
uint16T: "uint16T",
uint32T: "uint32T",
uint64T: "uint64T",
uintptrT: "uintptrT",
valueT: "valueT",
variadicT: "variadicT",
}
func (c tcat) String() string {
if c < tcat(len(cats)) {
return cats[c]
}
return "Cat(" + strconv.Itoa(int(c)) + ")"
}
// structField type defines a field in a struct
type structField struct {
name string
tag string
embed bool
typ *itype
}
// itype defines the internal representation of types in the interpreter
type itype struct {
cat tcat // Type category
field []structField // Array of struct fields if structT or interfaceT
key *itype // Type of key element if MapT or nil
val *itype // Type of value element if chanT, mapT, ptrT, aliasT, arrayT or variadicT
arg []*itype // Argument types if funcT or nil
ret []*itype // Return types if funcT or nil
method []*node // Associated methods or nil
name string // name of type within its package for a defined type
path string // for a defined type, the package import path
size int // Size of array if ArrayT
rtype reflect.Type // Reflection type if ValueT, or nil
incomplete bool // true if type must be parsed again (out of order declarations)
untyped bool // true for a literal value (string or number)
sizedef bool // true if array size is computed from type definition
node *node // root AST node of type definition
scope *scope // type declaration scope (in case of re-parse incomplete type)
}
// nodeType returns a type definition for the corresponding AST subtree
func nodeType(interp *Interpreter, sc *scope, n *node) (*itype, error) {
if n.typ != nil && !n.typ.incomplete {
if n.kind == sliceExpr {
n.typ.sizedef = false
}
return n.typ, nil
}
var t = &itype{node: n, scope: sc}
if n.anc.kind == typeSpec {
name := n.anc.child[0].ident
if sym := sc.sym[name]; sym != nil {
// recover previously declared methods
t.method = sym.typ.method
t.path = sym.typ.path
t.name = name
}
}
var err cfgError
switch n.kind {
case addressExpr, starExpr:
t.cat = ptrT
if t.val, err = nodeType(interp, sc, n.child[0]); err != nil {
return nil, err
}
t.incomplete = t.val.incomplete
case arrayType:
t.cat = arrayT
if len(n.child) > 1 {
switch {
case n.child[0].rval.IsValid():
// constant size
t.size = int(n.child[0].rval.Int())
case n.child[0].kind == ellipsisExpr:
// [...]T expression
t.size = arrayTypeLen(n.anc)
default:
if sym, _, ok := sc.lookup(n.child[0].ident); ok {
// Resolve symbol to get size value
if sym.typ != nil && sym.typ.cat == intT {
if v, ok := sym.rval.Interface().(int); ok {
t.size = v
} else {
t.incomplete = true
}
} else {
t.incomplete = true
}
} else {
// Evaluate constant array size expression
if _, err = interp.cfg(n.child[0]); err != nil {
return nil, err
}
t.incomplete = true
}
}
if t.val, err = nodeType(interp, sc, n.child[1]); err != nil {
return nil, err
}
t.sizedef = true
t.incomplete = t.incomplete || t.val.incomplete
} else {
if t.val, err = nodeType(interp, sc, n.child[0]); err != nil {
return nil, err
}
t.incomplete = t.val.incomplete
}
case basicLit:
switch v := n.rval.Interface().(type) {
case bool:
t.cat = boolT
t.name = "bool"
case byte:
t.cat = byteT
t.name = "byte"
t.untyped = true
case complex64:
t.cat = complex64T
t.name = "complex64"
case complex128:
t.cat = complex128T
t.name = "complex128"
t.untyped = true
case float32:
t.cat = float32T
t.name = "float32"
t.untyped = true
case float64:
t.cat = float64T
t.name = "float64"
t.untyped = true
case int:
t.cat = intT
t.name = "int"
t.untyped = true
case uint:
t.cat = uintT
t.name = "uint"
t.untyped = true
case rune:
t.cat = runeT
t.name = "rune"
t.untyped = true
case string:
t.cat = stringT
t.name = "string"
t.untyped = true
default:
err = n.cfgErrorf("missing support for type %T: %v", v, n.rval)
}
case unaryExpr:
t, err = nodeType(interp, sc, n.child[0])
case binaryExpr:
if a := n.anc; a.kind == defineStmt && len(a.child) > a.nleft+a.nright {
t, err = nodeType(interp, sc, a.child[a.nleft])
} else {
if t, err = nodeType(interp, sc, n.child[0]); err != nil {
return nil, err
}
// Shift operator type is inherited from first parameter only
// For other operators, infer type in from 2nd parameter in case of untyped first
if t.untyped && !isShiftNode(n) {
var t1 *itype
t1, err = nodeType(interp, sc, n.child[1])
if !(t1.untyped && isInt(t1.TypeOf()) && isFloat(t.TypeOf())) {
t = t1
}
}
}
case callExpr:
if interp.isBuiltinCall(n) {
// builtin types are special and may depend from their call arguments
t.cat = builtinT
switch n.child[0].ident {
case "complex":
var nt0, nt1 *itype
if nt0, err = nodeType(interp, sc, n.child[1]); err != nil {
return nil, err
}
if nt1, err = nodeType(interp, sc, n.child[2]); err != nil {
return nil, err
}
if nt0.incomplete || nt1.incomplete {
t.incomplete = true
} else {
switch t0, t1 := nt0.TypeOf(), nt1.TypeOf(); {
case isFloat32(t0) && isFloat32(t1):
t = sc.getType("complex64")
case isFloat64(t0) && isFloat64(t1):
t = sc.getType("complex128")
case nt0.untyped && isNumber(t0) && nt1.untyped && isNumber(t1):
t = &itype{cat: valueT, rtype: complexType}
case nt0.untyped && isFloat32(t1) || nt1.untyped && isFloat32(t0):
t = sc.getType("complex64")
case nt0.untyped && isFloat64(t1) || nt1.untyped && isFloat64(t0):
t = sc.getType("complex128")
default:
err = n.cfgErrorf("invalid types %s and %s", t0.Kind(), t1.Kind())
}
if nt0.untyped && nt1.untyped {
t.untyped = true
}
}
case "real", "imag":
if t, err = nodeType(interp, sc, n.child[1]); err != nil {
return nil, err
}
if !t.incomplete {
switch k := t.TypeOf().Kind(); {
case k == reflect.Complex64:
t = sc.getType("float32")
case k == reflect.Complex128:
t = sc.getType("float64")
case t.untyped && isNumber(t.TypeOf()):
t = &itype{cat: valueT, rtype: floatType, untyped: true}
default:
err = n.cfgErrorf("invalid complex type %s", k)
}
}
case "cap", "copy", "len":
t = sc.getType("int")
case "append", "make":
t, err = nodeType(interp, sc, n.child[1])
case "new":
t, err = nodeType(interp, sc, n.child[1])
t = &itype{cat: ptrT, val: t, incomplete: t.incomplete}
case "recover":
t = sc.getType("interface{}")
}
if err != nil {
return nil, err
}
} else {
if t, err = nodeType(interp, sc, n.child[0]); err != nil {
return nil, err
}
switch t.cat {
case valueT:
if t.rtype.NumOut() == 1 {
t = &itype{cat: valueT, rtype: t.rtype.Out(0)}
}
default:
if len(t.ret) == 1 {
t = t.ret[0]
}
}
}
case compositeLitExpr:
t, err = nodeType(interp, sc, n.child[0])
case chanType:
t.cat = chanT
if t.val, err = nodeType(interp, sc, n.child[0]); err != nil {
return nil, err
}
t.incomplete = t.val.incomplete
case ellipsisExpr:
t.cat = variadicT
if t.val, err = nodeType(interp, sc, n.child[0]); err != nil {
return nil, err
}
t.incomplete = t.val.incomplete
case funcLit:
t, err = nodeType(interp, sc, n.child[2])
case funcType:
t.cat = funcT
// Handle input parameters
for _, arg := range n.child[0].child {
cl := len(arg.child) - 1
typ, err := nodeType(interp, sc, arg.child[cl])
if err != nil {
return nil, err
}
t.arg = append(t.arg, typ)
for i := 1; i < cl; i++ {
// Several arguments may be factorized on the same field type
t.arg = append(t.arg, typ)
}
t.incomplete = t.incomplete || typ.incomplete
}
if len(n.child) == 2 {
// Handle returned values
for _, ret := range n.child[1].child {
cl := len(ret.child) - 1
typ, err := nodeType(interp, sc, ret.child[cl])
if err != nil {
return nil, err
}
t.ret = append(t.ret, typ)
for i := 1; i < cl; i++ {
// Several arguments may be factorized on the same field type
t.ret = append(t.ret, typ)
}
t.incomplete = t.incomplete || typ.incomplete
}
}
case identExpr:
if sym, _, found := sc.lookup(n.ident); found {
t = sym.typ
if t.incomplete && t.node != n {
m := t.method
if t, err = nodeType(interp, sc, t.node); err != nil {
return nil, err
}
t.method = m
sym.typ = t
}
if t.node == nil {
t.node = n
}
} else {
t.incomplete = true
sc.sym[n.ident] = &symbol{kind: typeSym, typ: t}
}
case interfaceType:
t.cat = interfaceT
if sname := typeName(n); sname != "" {
if sym, _, found := sc.lookup(sname); found && sym.kind == typeSym {
sym.typ = t
}
}
for _, field := range n.child[0].child {
if len(field.child) == 1 {
typ, err := nodeType(interp, sc, field.child[0])
if err != nil {
return nil, err
}
t.field = append(t.field, structField{name: fieldName(field.child[0]), embed: true, typ: typ})
t.incomplete = t.incomplete || typ.incomplete
} else {
typ, err := nodeType(interp, sc, field.child[1])
if err != nil {
return nil, err
}
t.field = append(t.field, structField{name: field.child[0].ident, typ: typ})
t.incomplete = t.incomplete || typ.incomplete
}
}
case mapType:
t.cat = mapT
if t.key, err = nodeType(interp, sc, n.child[0]); err != nil {
return nil, err
}
if t.val, err = nodeType(interp, sc, n.child[1]); err != nil {
return nil, err
}
t.incomplete = t.key.incomplete || t.val.incomplete
case parenExpr:
t, err = nodeType(interp, sc, n.child[0])
case selectorExpr:
// Resolve the left part of selector, then lookup the right part on it
var lt *itype
if lt, err = nodeType(interp, sc, n.child[0]); err != nil {
return nil, err
}
if lt.incomplete {
t.incomplete = true
break
}
name := n.child[1].ident
switch lt.cat {
case binPkgT:
pkg := interp.binPkg[lt.path]
if v, ok := pkg[name]; ok {
t.cat = valueT
t.rtype = v.Type()
if isBinType(v) { // a bin type is encoded as a pointer on nil value
t.rtype = t.rtype.Elem()
}
} else {
err = n.cfgErrorf("undefined selector %s.%s", lt.path, name)
panic(err)
}
case srcPkgT:
pkg := interp.srcPkg[lt.path]
if s, ok := pkg[name]; ok {
t = s.typ
} else {
err = n.cfgErrorf("undefined selector %s.%s", lt.path, name)
}
default:
if m, _ := lt.lookupMethod(name); m != nil {
t, err = nodeType(interp, sc, m.child[2])
} else if bm, _, _, ok := lt.lookupBinMethod(name); ok {
t = &itype{cat: valueT, rtype: bm.Type}
} else if ti := lt.lookupField(name); len(ti) > 0 {
t = lt.fieldSeq(ti)
} else if bs, _, ok := lt.lookupBinField(name); ok {
t = &itype{cat: valueT, rtype: bs.Type}
} else {
err = lt.node.cfgErrorf("undefined selector %s", name)
}
}
case sliceExpr:
t, err = nodeType(interp, sc, n.child[0])
if t.cat == ptrT {
t = t.val
}
if err == nil && t.size != 0 {
t1 := *t
t1.size = 0
t1.rtype = nil
t = &t1
}
case structType:
t.cat = structT
var incomplete bool
if sname := typeName(n); sname != "" {
if sym, _, found := sc.lookup(sname); found && sym.kind == typeSym {
sym.typ = t
}
}
for _, c := range n.child[0].child {
switch {
case len(c.child) == 1:
typ, err := nodeType(interp, sc, c.child[0])
if err != nil {
return nil, err
}
t.field = append(t.field, structField{name: fieldName(c.child[0]), embed: true, typ: typ})
incomplete = incomplete || typ.incomplete
case len(c.child) == 2 && c.child[1].kind == basicLit:
tag := c.child[1].rval.String()
typ, err := nodeType(interp, sc, c.child[0])
if err != nil {
return nil, err
}
t.field = append(t.field, structField{name: fieldName(c.child[0]), embed: true, typ: typ, tag: tag})
incomplete = incomplete || typ.incomplete
default:
var tag string
l := len(c.child)
if c.lastChild().kind == basicLit {
tag = c.lastChild().rval.String()
l--
}
typ, err := nodeType(interp, sc, c.child[l-1])
if err != nil {
return nil, err
}
incomplete = incomplete || typ.incomplete
for _, d := range c.child[:l-1] {
t.field = append(t.field, structField{name: d.ident, typ: typ, tag: tag})
}
}
}
t.incomplete = incomplete
default:
err = n.cfgErrorf("type definition not implemented: %s", n.kind)
}
if err == nil && t.cat == nilT && !t.incomplete {
err = n.cfgErrorf("use of untyped nil %s", t.name)
}
return t, err
}
func (interp *Interpreter) isBuiltinCall(n *node) bool {
if n.kind != callExpr {
return false
}
s := interp.universe.sym[n.child[0].ident]
return s != nil && s.kind == bltnSym
}
// struct name returns the name of a struct type
func typeName(n *node) string {
if n.anc.kind == typeSpec {
return n.anc.child[0].ident
}
return ""
}
// fieldName returns an implicit struct field name according to node kind
func fieldName(n *node) string {
switch n.kind {
case selectorExpr:
return fieldName(n.child[1])
case starExpr:
return fieldName(n.child[0])
case identExpr:
return n.ident
default:
return ""
}
}
var zeroValues [maxT]reflect.Value
func init() {
zeroValues[boolT] = reflect.ValueOf(false)
zeroValues[byteT] = reflect.ValueOf(byte(0))
zeroValues[complex64T] = reflect.ValueOf(complex64(0))
zeroValues[complex128T] = reflect.ValueOf(complex128(0))
zeroValues[errorT] = reflect.ValueOf(new(error)).Elem()
zeroValues[float32T] = reflect.ValueOf(float32(0))
zeroValues[float64T] = reflect.ValueOf(float64(0))
zeroValues[intT] = reflect.ValueOf(int(0))
zeroValues[int8T] = reflect.ValueOf(int8(0))
zeroValues[int16T] = reflect.ValueOf(int16(0))
zeroValues[int32T] = reflect.ValueOf(int32(0))
zeroValues[int64T] = reflect.ValueOf(int64(0))
zeroValues[runeT] = reflect.ValueOf(rune(0))
zeroValues[stringT] = reflect.ValueOf("")
zeroValues[uintT] = reflect.ValueOf(uint(0))
zeroValues[uint8T] = reflect.ValueOf(uint8(0))
zeroValues[uint16T] = reflect.ValueOf(uint16(0))
zeroValues[uint32T] = reflect.ValueOf(uint32(0))
zeroValues[uint64T] = reflect.ValueOf(uint64(0))
zeroValues[uintptrT] = reflect.ValueOf(uintptr(0))
}
// if type is incomplete, re-parse it.
func (t *itype) finalize() (*itype, error) {
var err cfgError
if t.incomplete {
sym, _, found := t.scope.lookup(t.name)
if found && !sym.typ.incomplete {
sym.typ.method = append(sym.typ.method, t.method...)
return sym.typ, nil
}
m := t.method
if t, err = nodeType(t.node.interp, t.scope, t.node); err != nil {
return nil, err
}
if t.incomplete {
return nil, t.node.cfgErrorf("incomplete type %s", t.name)
}
t.method = m
t.node.typ = t
if sym != nil {
sym.typ = t
}
}
return t, err
}
// Equals returns true if the given type is identical to the receiver one.
func (t *itype) equals(o *itype) bool {
switch ti, oi := isInterface(t), isInterface(o); {
case ti && oi:
return t.methods().equals(o.methods())
case ti && !oi:
return o.methods().contains(t.methods())
case oi && !ti:
return t.methods().contains(o.methods())
default:
return t.id() == o.id()
}
}
// MethodSet defines the set of methods signatures as strings, indexed per method name.
type methodSet map[string]string
// Contains returns true if the method set m contains the method set n.
func (m methodSet) contains(n methodSet) bool {
for k, v := range n {
if m[k] != v {
return false
}
}
return true
}
// Equal returns true if the method set m is equal to the method set n.
func (m methodSet) equals(n methodSet) bool {
return m.contains(n) && n.contains(m)
}
// Methods returns a map of method type strings, indexed by method names.
func (t *itype) methods() methodSet {
res := make(methodSet)
switch t.cat {
case interfaceT:
// Get methods from recursive analysis of interface fields
for _, f := range t.field {
if f.typ.cat == funcT {
res[f.name] = f.typ.TypeOf().String()
} else {
for k, v := range f.typ.methods() {
res[k] = v
}
}
}
case valueT, errorT:
// Get method from corresponding reflect.Type
for i := t.rtype.NumMethod() - 1; i >= 0; i-- {
m := t.rtype.Method(i)
res[m.Name] = m.Type.String()
}
case ptrT:
// Consider only methods where receiver is a pointer to type t
for _, m := range t.val.method {
if m.child[0].child[0].lastChild().typ.cat == ptrT {
res[m.ident] = m.typ.TypeOf().String()
}
}
default:
for _, m := range t.method {
res[m.ident] = m.typ.TypeOf().String()
}
}
return res
}
// id returns a unique type identificator string
func (t *itype) id() string {
// TODO: if res is nil, build identity from String()
res := ""
switch t.cat {
case valueT:
res = t.rtype.PkgPath() + "." + t.rtype.Name()
case ptrT:
res = "*" + t.val.id()
default:
res = t.path + "." + t.name
}
return res
}
// zero instantiates and return a zero value object for the given type during execution
func (t *itype) zero() (v reflect.Value, err error) {
if t, err = t.finalize(); err != nil {
return v, err
}
switch t.cat {
case aliasT:
v, err = t.val.zero()
case arrayT, ptrT, structT:
v = reflect.New(t.TypeOf()).Elem()
case valueT:
v = reflect.New(t.rtype).Elem()
default:
v = zeroValues[t.cat]
}
return v, err
}
// fieldIndex returns the field index from name in a struct, or -1 if not found
func (t *itype) fieldIndex(name string) int {
if t.cat == ptrT {
return t.val.fieldIndex(name)
}
for i, field := range t.field {
if name == field.name {
return i
}
}
return -1
}
// fieldSeq returns the field type from the list of field indexes
func (t *itype) fieldSeq(seq []int) *itype {
ft := t
for _, i := range seq {
if ft.cat == ptrT {
ft = ft.val
}
ft = ft.field[i].typ
}
return ft
}
// lookupField returns a list of indices, i.e. a path to access a field in a struct object
func (t *itype) lookupField(name string) []int {
if fi := t.fieldIndex(name); fi >= 0 {
return []int{fi}
}
for i, f := range t.field {
switch f.typ.cat {
case ptrT, structT, interfaceT, aliasT:
if index2 := f.typ.lookupField(name); len(index2) > 0 {
return append([]int{i}, index2...)
}
}
}
return nil
}
// lookupBinField returns a structfield and a path to access an embedded binary field in a struct object
func (t *itype) lookupBinField(name string) (s reflect.StructField, index []int, ok bool) {
if t.cat == ptrT {
return t.val.lookupBinField(name)
}
if !isStruct(t) {
return
}
s, ok = t.TypeOf().FieldByName(name)
if !ok {
for i, f := range t.field {
if f.embed {
if s2, index2, ok2 := f.typ.lookupBinField(name); ok2 {
index = append([]int{i}, index2...)
return s2, index, ok2
}
}
}
}
return s, index, ok
}
// getMethod returns a pointer to the method definition
func (t *itype) getMethod(name string) *node {
for _, m := range t.method {
if name == m.ident {
return m
}
}
return nil
}
// lookupMethod returns a pointer to method definition associated to type t
// and the list of indices to access the right struct field, in case of an embedded method
func (t *itype) lookupMethod(name string) (*node, []int) {
if t.cat == ptrT {
return t.val.lookupMethod(name)
}
var index []int
m := t.getMethod(name)
if m == nil {
for i, f := range t.field {
if f.embed {
if n, index2 := f.typ.lookupMethod(name); n != nil {
index = append([]int{i}, index2...)
return n, index
}
}
}
}
return m, index
}
// lookupBinMethod returns a method and a path to access a field in a struct object (the receiver)
func (t *itype) lookupBinMethod(name string) (reflect.Method, []int, bool, bool) {
var isPtr bool
if t.cat == ptrT {
return t.val.lookupBinMethod(name)
}
var index []int
m, ok := t.TypeOf().MethodByName(name)
if !ok {
m, ok = reflect.PtrTo(t.TypeOf()).MethodByName(name)
isPtr = ok
}
if !ok {
for i, f := range t.field {
if f.embed {
if m2, index2, isPtr2, ok2 := f.typ.lookupBinMethod(name); ok2 {
index = append([]int{i}, index2...)
return m2, index, isPtr2, ok2
}
}
}
}
return m, index, isPtr, ok
}
func exportName(s string) string {
if canExport(s) {
return s
}
return "X" + s
}
var interf = reflect.TypeOf(new(interface{})).Elem()
func (t *itype) refType(defined map[string]bool) reflect.Type {
if t.rtype != nil {
return t.rtype
}
if t.incomplete || t.cat == nilT {
var err error
if t, err = t.finalize(); err != nil {
panic(err)
}
}
if t.val != nil && defined[t.val.name] && !t.val.incomplete && t.val.rtype == nil {
// Replace reference to self (direct or indirect) by an interface{} to handle
// recursive types with reflect.
t.val.rtype = interf
}
switch t.cat {
case aliasT:
t.rtype = t.val.refType(defined)
case arrayT, variadicT:
if t.sizedef {
t.rtype = reflect.ArrayOf(t.size, t.val.refType(defined))
} else {
t.rtype = reflect.SliceOf(t.val.refType(defined))
}
case chanT:
t.rtype = reflect.ChanOf(reflect.BothDir, t.val.refType(defined))
case errorT:
t.rtype = reflect.TypeOf(new(error)).Elem()
case funcT:
in := make([]reflect.Type, len(t.arg))
out := make([]reflect.Type, len(t.ret))
for i, v := range t.arg {
in[i] = v.refType(defined)
}
for i, v := range t.ret {
out[i] = v.refType(defined)
}
t.rtype = reflect.FuncOf(in, out, false)
case interfaceT:
t.rtype = interf
case mapT:
t.rtype = reflect.MapOf(t.key.TypeOf(), t.val.TypeOf())
case ptrT:
t.rtype = reflect.PtrTo(t.val.refType(defined))
case structT:
if t.name != "" {
defined[t.name] = true
}
var fields []reflect.StructField
for _, f := range t.field {
field := reflect.StructField{Name: exportName(f.name), Type: f.typ.refType(defined), Tag: reflect.StructTag(f.tag)}
fields = append(fields, field)
}
t.rtype = reflect.StructOf(fields)
default:
if z, _ := t.zero(); z.IsValid() {
t.rtype = z.Type()
}
}
return t.rtype
}
// TypeOf returns the reflection type of dynamic interpreter type t.
func (t *itype) TypeOf() reflect.Type {
return t.refType(map[string]bool{})
}
func (t *itype) frameType() (r reflect.Type) {
var err error
if t, err = t.finalize(); err != nil {
panic(err)
}
switch t.cat {
case aliasT:
r = t.val.frameType()
case arrayT, variadicT:
if t.sizedef {
r = reflect.ArrayOf(t.size, t.val.frameType())
} else {
r = reflect.SliceOf(t.val.frameType())
}
case funcT:
r = reflect.TypeOf((*node)(nil))
case interfaceT:
r = reflect.TypeOf((*valueInterface)(nil)).Elem()
default:
r = t.TypeOf()
}
return r
}
func (t *itype) implements(it *itype) bool {
if t.cat == valueT {
return t.TypeOf().Implements(it.TypeOf())
}
// TODO: implement method check for interpreted types
return true
}
func defRecvType(n *node) *itype {
if n.kind != funcDecl || len(n.child[0].child) == 0 {
return nil
}
if r := n.child[0].child[0].lastChild(); r != nil {
return r.typ
}
return nil
}
func isShiftNode(n *node) bool {
switch n.action {
case aShl, aShr, aShlAssign, aShrAssign:
return true
}
return false
}
func isInterfaceSrc(t *itype) bool {
return t.cat == interfaceT || (t.cat == aliasT && isInterfaceSrc(t.val))
}
func isInterface(t *itype) bool {
return isInterfaceSrc(t) || t.TypeOf().Kind() == reflect.Interface
}
func isStruct(t *itype) bool {
// Test first for a struct category, because a recursive interpreter struct may be
// represented by an interface{} at reflect level.
return t.cat == structT || t.TypeOf().Kind() == reflect.Struct
}
func isBool(t *itype) bool { return t.TypeOf().Kind() == reflect.Bool }
func isInt(t reflect.Type) bool {
switch t.Kind() {
case reflect.Int, reflect.Int8, reflect.Int16, reflect.Int32, reflect.Int64, reflect.Uint, reflect.Uint8, reflect.Uint16, reflect.Uint32, reflect.Uint64, reflect.Uintptr:
return true
}
return false
}
func isUint(t reflect.Type) bool {
switch t.Kind() {
case reflect.Uint, reflect.Uint8, reflect.Uint16, reflect.Uint32, reflect.Uint64, reflect.Uintptr:
return true
}
return false
}
func isComplex(t reflect.Type) bool {
switch t.Kind() {
case reflect.Complex64, reflect.Complex128:
return true
}
return false
}
func isFloat(t reflect.Type) bool {
switch t.Kind() {
case reflect.Float32, reflect.Float64:
return true
}
return false
}
func isByteArray(t reflect.Type) bool {
k := t.Kind()
return (k == reflect.Array || k == reflect.Slice) && t.Elem().Kind() == reflect.Uint8
}
func isFloat32(t reflect.Type) bool { return t.Kind() == reflect.Float32 }
func isFloat64(t reflect.Type) bool { return t.Kind() == reflect.Float64 }
func isNumber(t reflect.Type) bool { return isInt(t) || isFloat(t) || isComplex(t) }
func isString(t reflect.Type) bool { return t.Kind() == reflect.String }