func (t *itype) getMethod(name string) *node {
	for _, m := range t.method {
		if name == m.ident {
			return m
		}
	}
	return nil
}
getMethod returns a pointer to the method definition
package interp
import (
	"reflect"
	"strconv"
)
type tcat uint
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)) + ")"
}
type structField struct {
	name  string
	tag   string
	embed bool
	typ   *itype
}
type itype struct {
	cat        tcat           
	field      []structField  
	key        *itype         
	val        *itype         
	arg        []*itype       
	ret        []*itype       
	method     []*node        
	name       string         
	path       string         
	size       int            
	rtype      reflect.Type   
	incomplete bool           
	untyped    bool           
	sizedef    bool           
	node       *node          
	scope      *scope         
}
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 {
			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():
				t.size = int(n.child[0].rval.Int())
			case n.child[0].kind == ellipsisExpr:
				t.size = arrayTypeLen(n.anc)
			default:
				if sym, _, ok := sc.lookup(n.child[0].ident); ok {
					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 {
					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
			}
			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) {
			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())
					}
				}
			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}
					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
		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++ {
				t.arg = append(t.arg, typ)
			}
			t.incomplete = t.incomplete || typ.incomplete
		}
		if len(n.child) == 2 {
			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++ {
					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
			}
		} 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:
		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) {  
					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 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
}
func typeName(n *node) string {
	if n.anc.kind == typeSpec {
		return n.anc.child[0].ident
	}
	return ""
}
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))
}
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
}
func (t *itype) id() 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
}
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
}
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
}
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
}
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
}
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
}