Compare commits
9 Commits
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
3cd37645eb | ||
|
|
e1ac83f7d8 | ||
|
|
4f93be7f19 | ||
|
|
7a0c09f5eb | ||
|
|
275391c1e8 | ||
|
|
273df8af9f | ||
|
|
0d2c39d155 | ||
|
|
1ff1a50753 | ||
|
|
488e491bf8 |
3
_test/foo-bar/foo-bar.go
Normal file
3
_test/foo-bar/foo-bar.go
Normal file
@@ -0,0 +1,3 @@
|
|||||||
|
package bar
|
||||||
|
|
||||||
|
var Name = "foo-bar"
|
||||||
10
_test/import7.go
Normal file
10
_test/import7.go
Normal file
@@ -0,0 +1,10 @@
|
|||||||
|
package main
|
||||||
|
|
||||||
|
import "github.com/containous/yaegi/_test/foo-bar"
|
||||||
|
|
||||||
|
func main() {
|
||||||
|
println(bar.Name)
|
||||||
|
}
|
||||||
|
|
||||||
|
// Output:
|
||||||
|
// foo-bar
|
||||||
17
_test/interface14.go
Normal file
17
_test/interface14.go
Normal file
@@ -0,0 +1,17 @@
|
|||||||
|
package main
|
||||||
|
|
||||||
|
type T struct{}
|
||||||
|
|
||||||
|
func (t *T) Error() string { return "T: error" }
|
||||||
|
|
||||||
|
var invalidT = &T{}
|
||||||
|
|
||||||
|
func main() {
|
||||||
|
var err error
|
||||||
|
if err != invalidT {
|
||||||
|
println("ok")
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// Output:
|
||||||
|
// ok
|
||||||
28
_test/interface15.go
Normal file
28
_test/interface15.go
Normal file
@@ -0,0 +1,28 @@
|
|||||||
|
package main
|
||||||
|
|
||||||
|
type Fooer interface {
|
||||||
|
Foo() string
|
||||||
|
}
|
||||||
|
|
||||||
|
type Barer interface {
|
||||||
|
//fmt.Stringer
|
||||||
|
Fooer
|
||||||
|
Bar()
|
||||||
|
}
|
||||||
|
|
||||||
|
type T struct{}
|
||||||
|
|
||||||
|
func (t *T) Foo() string { return "T: foo" }
|
||||||
|
func (*T) Bar() { println("in bar") }
|
||||||
|
|
||||||
|
var t = &T{}
|
||||||
|
|
||||||
|
func main() {
|
||||||
|
var f Barer
|
||||||
|
if f != t {
|
||||||
|
println("ok")
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// Output:
|
||||||
|
// ok
|
||||||
25
_test/interface16.go
Normal file
25
_test/interface16.go
Normal file
@@ -0,0 +1,25 @@
|
|||||||
|
package main
|
||||||
|
|
||||||
|
import "fmt"
|
||||||
|
|
||||||
|
type Barer interface {
|
||||||
|
fmt.Stringer
|
||||||
|
Bar()
|
||||||
|
}
|
||||||
|
|
||||||
|
type T struct{}
|
||||||
|
|
||||||
|
func (*T) String() string { return "T: nothing" }
|
||||||
|
func (*T) Bar() { println("in bar") }
|
||||||
|
|
||||||
|
var t = &T{}
|
||||||
|
|
||||||
|
func main() {
|
||||||
|
var f Barer
|
||||||
|
if f != t {
|
||||||
|
println("ok")
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// Output:
|
||||||
|
// ok
|
||||||
17
_test/interface17.go
Normal file
17
_test/interface17.go
Normal file
@@ -0,0 +1,17 @@
|
|||||||
|
package main
|
||||||
|
|
||||||
|
type T struct{}
|
||||||
|
|
||||||
|
func (t T) Error() string { return "T: error" }
|
||||||
|
|
||||||
|
var invalidT = T{}
|
||||||
|
|
||||||
|
func main() {
|
||||||
|
var err error
|
||||||
|
if err != invalidT {
|
||||||
|
println("ok")
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// Output:
|
||||||
|
// ok
|
||||||
18
_test/interface18.go
Normal file
18
_test/interface18.go
Normal file
@@ -0,0 +1,18 @@
|
|||||||
|
package main
|
||||||
|
|
||||||
|
type T struct{}
|
||||||
|
|
||||||
|
func (t *T) Error() string { return "T: error" }
|
||||||
|
func (*T) Foo() { println("foo") }
|
||||||
|
|
||||||
|
var invalidT = &T{}
|
||||||
|
|
||||||
|
func main() {
|
||||||
|
var err error
|
||||||
|
if err != invalidT {
|
||||||
|
println("ok")
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// Output:
|
||||||
|
// ok
|
||||||
15
_test/nil0.go
Normal file
15
_test/nil0.go
Normal file
@@ -0,0 +1,15 @@
|
|||||||
|
package main
|
||||||
|
|
||||||
|
import "fmt"
|
||||||
|
|
||||||
|
func f() (host, port string, err error) {
|
||||||
|
return "", "", nil
|
||||||
|
}
|
||||||
|
|
||||||
|
func main() {
|
||||||
|
h, p, err := f()
|
||||||
|
fmt.Println(h, p, err)
|
||||||
|
}
|
||||||
|
|
||||||
|
// Output:
|
||||||
|
// <nil>
|
||||||
11
_test/str4.go
Normal file
11
_test/str4.go
Normal file
@@ -0,0 +1,11 @@
|
|||||||
|
package main
|
||||||
|
|
||||||
|
import "unicode/utf8"
|
||||||
|
|
||||||
|
func main() {
|
||||||
|
r, _ := utf8.DecodeRuneInString("Hello")
|
||||||
|
println(r < utf8.RuneSelf)
|
||||||
|
}
|
||||||
|
|
||||||
|
// Output:
|
||||||
|
// true
|
||||||
19
_test/struct29.go
Normal file
19
_test/struct29.go
Normal file
@@ -0,0 +1,19 @@
|
|||||||
|
package main
|
||||||
|
|
||||||
|
type T1 struct {
|
||||||
|
A []T2
|
||||||
|
B []T2
|
||||||
|
}
|
||||||
|
|
||||||
|
type T2 struct {
|
||||||
|
name string
|
||||||
|
}
|
||||||
|
|
||||||
|
var t = T1{}
|
||||||
|
|
||||||
|
func main() {
|
||||||
|
println("ok")
|
||||||
|
}
|
||||||
|
|
||||||
|
// Output:
|
||||||
|
// ok
|
||||||
19
_test/struct30.go
Normal file
19
_test/struct30.go
Normal file
@@ -0,0 +1,19 @@
|
|||||||
|
package main
|
||||||
|
|
||||||
|
type T1 struct {
|
||||||
|
A []T2
|
||||||
|
M map[uint64]T2
|
||||||
|
}
|
||||||
|
|
||||||
|
type T2 struct {
|
||||||
|
name string
|
||||||
|
}
|
||||||
|
|
||||||
|
var t = T1{}
|
||||||
|
|
||||||
|
func main() {
|
||||||
|
println("ok")
|
||||||
|
}
|
||||||
|
|
||||||
|
// Output:
|
||||||
|
// ok
|
||||||
21
_test/switch22.go
Normal file
21
_test/switch22.go
Normal file
@@ -0,0 +1,21 @@
|
|||||||
|
package main
|
||||||
|
|
||||||
|
type T struct {
|
||||||
|
Name string
|
||||||
|
}
|
||||||
|
|
||||||
|
func f(t interface{}) {
|
||||||
|
switch ext := t.(type) {
|
||||||
|
case *T:
|
||||||
|
println("*T", ext.Name)
|
||||||
|
default:
|
||||||
|
println("unknown")
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
func main() {
|
||||||
|
f(&T{"truc"})
|
||||||
|
}
|
||||||
|
|
||||||
|
// Output:
|
||||||
|
// *T truc
|
||||||
15
_test/time11.go
Normal file
15
_test/time11.go
Normal file
@@ -0,0 +1,15 @@
|
|||||||
|
package main
|
||||||
|
|
||||||
|
import (
|
||||||
|
"fmt"
|
||||||
|
"time"
|
||||||
|
)
|
||||||
|
|
||||||
|
const df = time.Minute * 30
|
||||||
|
|
||||||
|
func main() {
|
||||||
|
fmt.Printf("df: %v %T\n", df, df)
|
||||||
|
}
|
||||||
|
|
||||||
|
// Output:
|
||||||
|
// df: 30m0s time.Duration
|
||||||
@@ -4,8 +4,8 @@ import (
|
|||||||
"fmt"
|
"fmt"
|
||||||
"log"
|
"log"
|
||||||
"math"
|
"math"
|
||||||
"path"
|
|
||||||
"reflect"
|
"reflect"
|
||||||
|
"regexp"
|
||||||
"unicode"
|
"unicode"
|
||||||
)
|
)
|
||||||
|
|
||||||
@@ -32,6 +32,8 @@ var constBltn = map[string]func(*node){
|
|||||||
"real": realConst,
|
"real": realConst,
|
||||||
}
|
}
|
||||||
|
|
||||||
|
var identifier = regexp.MustCompile(`([\pL_][\pL_\d]*)$`)
|
||||||
|
|
||||||
// cfg generates a control flow graph (CFG) from AST (wiring successors in AST)
|
// cfg generates a control flow graph (CFG) from AST (wiring successors in AST)
|
||||||
// and pre-compute frame sizes and indexes for all un-named (temporary) and named
|
// and pre-compute frame sizes and indexes for all un-named (temporary) and named
|
||||||
// variables. A list of nodes of init functions is returned.
|
// variables. A list of nodes of init functions is returned.
|
||||||
@@ -170,23 +172,21 @@ func (interp *Interpreter) cfg(root *node) ([]*node, error) {
|
|||||||
var typ *itype
|
var typ *itype
|
||||||
if len(n.child) == 2 {
|
if len(n.child) == 2 {
|
||||||
// 1 type in clause: define the var with this type in the case clause scope
|
// 1 type in clause: define the var with this type in the case clause scope
|
||||||
switch sym, _, ok := sc.lookup(n.child[0].ident); {
|
switch {
|
||||||
case ok && sym.kind == typeSym:
|
|
||||||
typ = sym.typ
|
|
||||||
case n.child[0].kind == selectorExpr:
|
|
||||||
if typ, err = nodeType(interp, sc, n.child[0]); err != nil {
|
|
||||||
return false
|
|
||||||
}
|
|
||||||
case n.child[0].ident == "nil":
|
case n.child[0].ident == "nil":
|
||||||
typ = sc.getType("interface{}")
|
typ = sc.getType("interface{}")
|
||||||
default:
|
case !n.child[0].isType(sc):
|
||||||
err = n.cfgErrorf("%s is not a type", n.child[0].ident)
|
err = n.cfgErrorf("%s is not a type", n.child[0].ident)
|
||||||
return false
|
default:
|
||||||
|
typ, err = nodeType(interp, sc, n.child[0])
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
// define the var with the type in the switch guard expression
|
// define the var with the type in the switch guard expression
|
||||||
typ = sn.child[1].child[1].child[0].typ
|
typ = sn.child[1].child[1].child[0].typ
|
||||||
}
|
}
|
||||||
|
if err != nil {
|
||||||
|
return false
|
||||||
|
}
|
||||||
nod := n.lastChild().child[0]
|
nod := n.lastChild().child[0]
|
||||||
index := sc.add(typ)
|
index := sc.add(typ)
|
||||||
sc.sym[nod.ident] = &symbol{index: index, kind: varSym, typ: typ}
|
sc.sym[nod.ident] = &symbol{index: index, kind: varSym, typ: typ}
|
||||||
@@ -318,7 +318,7 @@ func (interp *Interpreter) cfg(root *node) ([]*node, error) {
|
|||||||
name = n.child[0].ident
|
name = n.child[0].ident
|
||||||
} else {
|
} else {
|
||||||
ipath = n.child[0].rval.String()
|
ipath = n.child[0].rval.String()
|
||||||
name = path.Base(ipath)
|
name = identifier.FindString(ipath)
|
||||||
}
|
}
|
||||||
if interp.binPkg[ipath] != nil && name != "." {
|
if interp.binPkg[ipath] != nil && name != "." {
|
||||||
sc.sym[name] = &symbol{kind: pkgSym, typ: &itype{cat: binPkgT, path: ipath}}
|
sc.sym[name] = &symbol{kind: pkgSym, typ: &itype{cat: binPkgT, path: ipath}}
|
||||||
@@ -549,7 +549,7 @@ func (interp *Interpreter) cfg(root *node) ([]*node, error) {
|
|||||||
t0, t1 := c0.typ.TypeOf(), c1.typ.TypeOf()
|
t0, t1 := c0.typ.TypeOf(), c1.typ.TypeOf()
|
||||||
// Shift operator type is inherited from first parameter only
|
// Shift operator type is inherited from first parameter only
|
||||||
// All other binary operators require both parameter types to be the same
|
// All other binary operators require both parameter types to be the same
|
||||||
if !isShiftNode(n) && !c0.typ.untyped && !c1.typ.untyped && c0.typ.id() != c1.typ.id() {
|
if !isShiftNode(n) && !c0.typ.untyped && !c1.typ.untyped && !c0.typ.equals(c1.typ) {
|
||||||
err = n.cfgErrorf("mismatched types %s and %s", c0.typ.id(), c1.typ.id())
|
err = n.cfgErrorf("mismatched types %s and %s", c0.typ.id(), c1.typ.id())
|
||||||
break
|
break
|
||||||
}
|
}
|
||||||
@@ -602,8 +602,6 @@ func (interp *Interpreter) cfg(root *node) ([]*node, error) {
|
|||||||
constOp[n.action](n)
|
constOp[n.action](n)
|
||||||
}
|
}
|
||||||
switch {
|
switch {
|
||||||
//case n.typ != nil && n.typ.cat == BoolT && isAncBranch(n):
|
|
||||||
// n.findex = -1
|
|
||||||
case n.rval.IsValid():
|
case n.rval.IsValid():
|
||||||
n.gen = nop
|
n.gen = nop
|
||||||
n.findex = -1
|
n.findex = -1
|
||||||
@@ -1068,7 +1066,7 @@ func (interp *Interpreter) cfg(root *node) ([]*node, error) {
|
|||||||
// nil: Set node value to zero of return type
|
// nil: Set node value to zero of return type
|
||||||
f := sc.def
|
f := sc.def
|
||||||
var typ *itype
|
var typ *itype
|
||||||
if typ, err = nodeType(interp, sc, f.child[2].child[1].child[i].lastChild()); err != nil {
|
if typ, err = nodeType(interp, sc, f.child[2].child[1].fieldType(i)); err != nil {
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
if typ.cat == funcT {
|
if typ.cat == funcT {
|
||||||
@@ -1155,7 +1153,7 @@ func (interp *Interpreter) cfg(root *node) ([]*node, error) {
|
|||||||
n.typ = &itype{cat: valueT, rtype: s.Type().Elem()}
|
n.typ = &itype{cat: valueT, rtype: s.Type().Elem()}
|
||||||
} else {
|
} else {
|
||||||
n.kind = rvalueExpr
|
n.kind = rvalueExpr
|
||||||
n.typ = &itype{cat: valueT, rtype: s.Type()}
|
n.typ = &itype{cat: valueT, rtype: s.Type(), untyped: isValueUntyped(s)}
|
||||||
n.rval = s
|
n.rval = s
|
||||||
}
|
}
|
||||||
n.gen = nop
|
n.gen = nop
|
||||||
@@ -1528,7 +1526,7 @@ func isBinType(v reflect.Value) bool { return v.IsValid() && v.Kind() == reflect
|
|||||||
// isType returns true if node refers to a type definition, false otherwise
|
// isType returns true if node refers to a type definition, false otherwise
|
||||||
func (n *node) isType(sc *scope) bool {
|
func (n *node) isType(sc *scope) bool {
|
||||||
switch n.kind {
|
switch n.kind {
|
||||||
case arrayType, chanType, funcType, mapType, structType, rtypeExpr:
|
case arrayType, chanType, funcType, interfaceType, mapType, structType, rtypeExpr:
|
||||||
return true
|
return true
|
||||||
case parenExpr, starExpr:
|
case parenExpr, starExpr:
|
||||||
if len(n.child) == 1 {
|
if len(n.child) == 1 {
|
||||||
@@ -1536,7 +1534,7 @@ func (n *node) isType(sc *scope) bool {
|
|||||||
}
|
}
|
||||||
case selectorExpr:
|
case selectorExpr:
|
||||||
pkg, name := n.child[0].ident, n.child[1].ident
|
pkg, name := n.child[0].ident, n.child[1].ident
|
||||||
if sym, _, ok := sc.lookup(pkg); ok {
|
if sym, _, ok := sc.lookup(pkg); ok && sym.kind == pkgSym {
|
||||||
path := sym.typ.path
|
path := sym.typ.path
|
||||||
if p, ok := n.interp.binPkg[path]; ok && isBinType(p[name]) {
|
if p, ok := n.interp.binPkg[path]; ok && isBinType(p[name]) {
|
||||||
return true // Imported binary type
|
return true // Imported binary type
|
||||||
@@ -1643,6 +1641,29 @@ func (n *node) isNatural() bool {
|
|||||||
return false
|
return false
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// fieldType returns the nth parameter field node (type) of a fieldList node
|
||||||
|
func (n *node) fieldType(m int) *node {
|
||||||
|
k := 0
|
||||||
|
l := len(n.child)
|
||||||
|
for i := 0; i < l; i++ {
|
||||||
|
cl := len(n.child[i].child)
|
||||||
|
if cl < 2 {
|
||||||
|
if k == m {
|
||||||
|
return n.child[i].lastChild()
|
||||||
|
}
|
||||||
|
k++
|
||||||
|
continue
|
||||||
|
}
|
||||||
|
for j := 0; j < cl-1; j++ {
|
||||||
|
if k == m {
|
||||||
|
return n.child[i].lastChild()
|
||||||
|
}
|
||||||
|
k++
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
|
||||||
// lastChild returns the last child of a node
|
// lastChild returns the last child of a node
|
||||||
func (n *node) lastChild() *node { return n.child[len(n.child)-1] }
|
func (n *node) lastChild() *node { return n.child[len(n.child)-1] }
|
||||||
|
|
||||||
@@ -1825,3 +1846,13 @@ func arrayTypeLen(n *node) int {
|
|||||||
}
|
}
|
||||||
return max + 1
|
return max + 1
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// isValueUntyped returns true if value is untyped
|
||||||
|
func isValueUntyped(v reflect.Value) bool {
|
||||||
|
// Consider only constant values.
|
||||||
|
if v.CanSet() {
|
||||||
|
return false
|
||||||
|
}
|
||||||
|
t := v.Type()
|
||||||
|
return t.String() == t.Kind().String()
|
||||||
|
}
|
||||||
|
|||||||
@@ -1,7 +1,6 @@
|
|||||||
package interp
|
package interp
|
||||||
|
|
||||||
import (
|
import (
|
||||||
"path"
|
|
||||||
"reflect"
|
"reflect"
|
||||||
)
|
)
|
||||||
|
|
||||||
@@ -31,6 +30,7 @@ func (interp *Interpreter) gta(root *node, rpath string) ([]*node, error) {
|
|||||||
case defineStmt:
|
case defineStmt:
|
||||||
var atyp *itype
|
var atyp *itype
|
||||||
if n.nleft+n.nright < len(n.child) {
|
if n.nleft+n.nright < len(n.child) {
|
||||||
|
// Type is declared explicitly in the assign expression.
|
||||||
if atyp, err = nodeType(interp, sc, n.child[n.nleft]); err != nil {
|
if atyp, err = nodeType(interp, sc, n.child[n.nleft]); err != nil {
|
||||||
return false
|
return false
|
||||||
}
|
}
|
||||||
@@ -126,7 +126,7 @@ func (interp *Interpreter) gta(root *node, rpath string) ([]*node, error) {
|
|||||||
name = n.child[0].ident
|
name = n.child[0].ident
|
||||||
} else {
|
} else {
|
||||||
ipath = n.child[0].rval.String()
|
ipath = n.child[0].rval.String()
|
||||||
name = path.Base(ipath)
|
name = identifier.FindString(ipath)
|
||||||
}
|
}
|
||||||
// Try to import a binary package first, or a source package
|
// Try to import a binary package first, or a source package
|
||||||
if interp.binPkg[ipath] != nil {
|
if interp.binPkg[ipath] != nil {
|
||||||
|
|||||||
@@ -239,7 +239,7 @@ func isRecursiveStruct(t *itype, rtype reflect.Type) bool {
|
|||||||
if t.cat == structT && rtype.Kind() == reflect.Interface {
|
if t.cat == structT && rtype.Kind() == reflect.Interface {
|
||||||
return true
|
return true
|
||||||
}
|
}
|
||||||
if t.cat == ptrT {
|
if t.cat == ptrT && t.rtype != nil {
|
||||||
return isRecursiveStruct(t.val, t.rtype.Elem())
|
return isRecursiveStruct(t.val, t.rtype.Elem())
|
||||||
}
|
}
|
||||||
return false
|
return false
|
||||||
@@ -260,7 +260,7 @@ func assign(n *node) {
|
|||||||
switch {
|
switch {
|
||||||
case dest.typ.cat == interfaceT:
|
case dest.typ.cat == interfaceT:
|
||||||
svalue[i] = genValueInterface(src)
|
svalue[i] = genValueInterface(src)
|
||||||
case dest.typ.cat == valueT && dest.typ.rtype.Kind() == reflect.Interface:
|
case (dest.typ.cat == valueT || dest.typ.cat == errorT) && dest.typ.rtype.Kind() == reflect.Interface:
|
||||||
svalue[i] = genInterfaceWrapper(src, dest.typ.rtype)
|
svalue[i] = genInterfaceWrapper(src, dest.typ.rtype)
|
||||||
case dest.typ.cat == valueT && src.typ.cat == funcT:
|
case dest.typ.cat == valueT && src.typ.cat == funcT:
|
||||||
svalue[i] = genFunctionWrapper(src)
|
svalue[i] = genFunctionWrapper(src)
|
||||||
|
|||||||
@@ -401,6 +401,9 @@ func nodeType(interp *Interpreter, sc *scope, n *node) (*itype, error) {
|
|||||||
t.method = m
|
t.method = m
|
||||||
sym.typ = t
|
sym.typ = t
|
||||||
}
|
}
|
||||||
|
if t.node == nil {
|
||||||
|
t.node = n
|
||||||
|
}
|
||||||
} else {
|
} else {
|
||||||
t.incomplete = true
|
t.incomplete = true
|
||||||
sc.sym[n.ident] = &symbol{kind: typeSym, typ: t}
|
sc.sym[n.ident] = &symbol{kind: typeSym, typ: t}
|
||||||
@@ -636,6 +639,74 @@ func (t *itype) finalize() (*itype, error) {
|
|||||||
return t, err
|
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
|
// id returns a unique type identificator string
|
||||||
func (t *itype) id() string {
|
func (t *itype) id() string {
|
||||||
// TODO: if res is nil, build identity from String()
|
// TODO: if res is nil, build identity from String()
|
||||||
@@ -814,7 +885,9 @@ func (t *itype) refType(defined map[string]bool) reflect.Type {
|
|||||||
panic(err)
|
panic(err)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
if t.val != nil && defined[t.val.name] {
|
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
|
t.val.rtype = interf
|
||||||
}
|
}
|
||||||
switch t.cat {
|
switch t.cat {
|
||||||
@@ -834,15 +907,9 @@ func (t *itype) refType(defined map[string]bool) reflect.Type {
|
|||||||
in := make([]reflect.Type, len(t.arg))
|
in := make([]reflect.Type, len(t.arg))
|
||||||
out := make([]reflect.Type, len(t.ret))
|
out := make([]reflect.Type, len(t.ret))
|
||||||
for i, v := range t.arg {
|
for i, v := range t.arg {
|
||||||
if defined[v.name] {
|
|
||||||
v.rtype = interf
|
|
||||||
}
|
|
||||||
in[i] = v.refType(defined)
|
in[i] = v.refType(defined)
|
||||||
}
|
}
|
||||||
for i, v := range t.ret {
|
for i, v := range t.ret {
|
||||||
if defined[v.name] {
|
|
||||||
v.rtype = interf
|
|
||||||
}
|
|
||||||
out[i] = v.refType(defined)
|
out[i] = v.refType(defined)
|
||||||
}
|
}
|
||||||
t.rtype = reflect.FuncOf(in, out, false)
|
t.rtype = reflect.FuncOf(in, out, false)
|
||||||
@@ -933,7 +1000,11 @@ func isInterface(t *itype) bool {
|
|||||||
return isInterfaceSrc(t) || t.TypeOf().Kind() == reflect.Interface
|
return isInterfaceSrc(t) || t.TypeOf().Kind() == reflect.Interface
|
||||||
}
|
}
|
||||||
|
|
||||||
func isStruct(t *itype) bool { return t.TypeOf().Kind() == reflect.Struct }
|
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 isBool(t *itype) bool { return t.TypeOf().Kind() == reflect.Bool }
|
||||||
|
|
||||||
|
|||||||
Reference in New Issue
Block a user