Compare commits
10 Commits
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
0f46cd5efb | ||
|
|
35e645c690 | ||
|
|
03596dac45 | ||
|
|
8db7a815e3 | ||
|
|
424e7ac90d | ||
|
|
effd64c980 | ||
|
|
8a88a1ab8a | ||
|
|
030dd3cbc2 | ||
|
|
bee21968c7 | ||
|
|
9abaeeb729 |
@@ -18,7 +18,7 @@ It powers executable Go scripts and plugins, in embedded interpreters or interac
|
||||
* Works everywhere Go works
|
||||
* All Go & runtime resources accessible from script (with control)
|
||||
* Security: `unsafe` and `syscall` packages neither used nor exported by default
|
||||
* Support Go 1.11 and Go 1.12 (the latest 2 major releases)
|
||||
* Support Go 1.12 and Go 1.13 (the latest 2 major releases)
|
||||
|
||||
## Install
|
||||
|
||||
|
||||
16
_test/alias1.go
Normal file
16
_test/alias1.go
Normal file
@@ -0,0 +1,16 @@
|
||||
package main
|
||||
|
||||
import "fmt"
|
||||
|
||||
type MyT T
|
||||
|
||||
type T struct {
|
||||
Name string
|
||||
}
|
||||
|
||||
func main() {
|
||||
fmt.Println(MyT{})
|
||||
}
|
||||
|
||||
// Output:
|
||||
// {}
|
||||
19
_test/for6.go
Normal file
19
_test/for6.go
Normal file
@@ -0,0 +1,19 @@
|
||||
package main
|
||||
|
||||
import "fmt"
|
||||
|
||||
func main() {
|
||||
s := "三"
|
||||
for i := 0; i < len(s); i++ {
|
||||
fmt.Printf("byte %d: %d\n", i, s[i])
|
||||
}
|
||||
for i, r := range s {
|
||||
fmt.Printf("rune %d: %d\n", i, r)
|
||||
}
|
||||
}
|
||||
|
||||
// Output:
|
||||
// byte 0: 228
|
||||
// byte 1: 184
|
||||
// byte 2: 137
|
||||
// rune 0: 19977
|
||||
12
_test/fun9.go
Normal file
12
_test/fun9.go
Normal file
@@ -0,0 +1,12 @@
|
||||
package main
|
||||
|
||||
type T uint
|
||||
|
||||
func main() {
|
||||
type myint int
|
||||
var i = myint(1)
|
||||
println(i)
|
||||
}
|
||||
|
||||
// Output:
|
||||
// 1
|
||||
27
_test/interface11.go
Normal file
27
_test/interface11.go
Normal file
@@ -0,0 +1,27 @@
|
||||
package main
|
||||
|
||||
import "fmt"
|
||||
|
||||
type Error interface {
|
||||
error
|
||||
Code() string
|
||||
}
|
||||
|
||||
type MyError Error
|
||||
|
||||
type T struct {
|
||||
Name string
|
||||
}
|
||||
|
||||
func (t *T) Error() string { return "err: " + t.Name }
|
||||
func (t *T) Code() string { return "code: " + t.Name }
|
||||
|
||||
func newT(s string) MyError { return &T{s} }
|
||||
|
||||
func main() {
|
||||
t := newT("foo")
|
||||
fmt.Println(t.Code())
|
||||
}
|
||||
|
||||
// Output:
|
||||
// code: foo
|
||||
20
_test/method27.go
Normal file
20
_test/method27.go
Normal file
@@ -0,0 +1,20 @@
|
||||
package main
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"net/http"
|
||||
)
|
||||
|
||||
type AuthenticatedRequest struct {
|
||||
http.Request
|
||||
Username string
|
||||
}
|
||||
|
||||
func main() {
|
||||
a := &AuthenticatedRequest{}
|
||||
fmt.Println("ua:", a.UserAgent())
|
||||
|
||||
}
|
||||
|
||||
// Output:
|
||||
// ua:
|
||||
10
_test/shift3.go
Normal file
10
_test/shift3.go
Normal file
@@ -0,0 +1,10 @@
|
||||
package main
|
||||
|
||||
const a = 1.0
|
||||
|
||||
const b = a + 3
|
||||
|
||||
func main() { println(b << (1)) }
|
||||
|
||||
// Output:
|
||||
// 8
|
||||
@@ -6,7 +6,7 @@ import (
|
||||
)
|
||||
|
||||
func main() {
|
||||
t := time.Unix(1e9, 0)
|
||||
t := time.Unix(1e9, 0).In(time.UTC)
|
||||
fmt.Println(t.Minute())
|
||||
}
|
||||
|
||||
|
||||
22
_test/variadic5.go
Normal file
22
_test/variadic5.go
Normal file
@@ -0,0 +1,22 @@
|
||||
package main
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
)
|
||||
|
||||
type A struct {
|
||||
}
|
||||
|
||||
func (a A) f(vals ...bool) {
|
||||
for _, v := range vals {
|
||||
fmt.Println(v)
|
||||
}
|
||||
}
|
||||
|
||||
func main() {
|
||||
a := A{}
|
||||
a.f(true)
|
||||
}
|
||||
|
||||
// Output:
|
||||
// true
|
||||
@@ -109,7 +109,7 @@ func TestPackagesError(t *testing.T) {
|
||||
{
|
||||
desc: "different packages in the same directory",
|
||||
goPath: "./_pkg9/",
|
||||
expected: "found packages pkg and pkgfalse in _pkg9/src/github.com/foo/pkg",
|
||||
expected: "1:21: import \"github.com/foo/pkg\" error: found packages pkg and pkgfalse in _pkg9/src/github.com/foo/pkg",
|
||||
},
|
||||
}
|
||||
|
||||
|
||||
100
interp/cfg.go
100
interp/cfg.go
@@ -3,6 +3,7 @@ package interp
|
||||
import (
|
||||
"fmt"
|
||||
"log"
|
||||
"math"
|
||||
"path"
|
||||
"reflect"
|
||||
"unicode"
|
||||
@@ -77,7 +78,7 @@ func (interp *Interpreter) cfg(root *node) ([]*node, error) {
|
||||
vtyp = &itype{cat: valueT, rtype: typ.Elem()}
|
||||
case reflect.String:
|
||||
ktyp = sc.getType("int")
|
||||
vtyp = sc.getType("byte")
|
||||
vtyp = sc.getType("rune")
|
||||
case reflect.Array, reflect.Slice:
|
||||
ktyp = sc.getType("int")
|
||||
vtyp = &itype{cat: valueT, rtype: typ.Elem()}
|
||||
@@ -96,7 +97,7 @@ func (interp *Interpreter) cfg(root *node) ([]*node, error) {
|
||||
}
|
||||
case stringT:
|
||||
ktyp = sc.getType("int")
|
||||
vtyp = sc.getType("byte")
|
||||
vtyp = sc.getType("rune")
|
||||
case arrayT, variadicT:
|
||||
ktyp = sc.getType("int")
|
||||
vtyp = o.typ.val
|
||||
@@ -203,7 +204,10 @@ func (interp *Interpreter) cfg(root *node) ([]*node, error) {
|
||||
} else if n.anc.typ != nil {
|
||||
n.typ = n.anc.typ.val
|
||||
}
|
||||
// FIXME n.typ can be nil.
|
||||
if n.typ == nil {
|
||||
err = n.cfgErrorf("undefined type")
|
||||
return false
|
||||
}
|
||||
n.typ.untyped = true
|
||||
}
|
||||
// Propagate type to children, to handle implicit types
|
||||
@@ -305,7 +309,25 @@ func (interp *Interpreter) cfg(root *node) ([]*node, error) {
|
||||
return false
|
||||
|
||||
case typeSpec:
|
||||
// processing already done in GTA pass
|
||||
// processing already done in GTA pass for global types, only parses inlined types
|
||||
if sc.def != nil {
|
||||
typeName := n.child[0].ident
|
||||
var typ *itype
|
||||
if typ, err = nodeType(interp, sc, n.child[1]); err != nil {
|
||||
return false
|
||||
}
|
||||
if typ.incomplete {
|
||||
err = n.cfgErrorf("invalid type declaration")
|
||||
return false
|
||||
}
|
||||
if n.child[1].kind == identExpr {
|
||||
n.typ = &itype{cat: aliasT, val: typ, name: typeName}
|
||||
} else {
|
||||
n.typ = typ
|
||||
n.typ.name = typeName
|
||||
}
|
||||
sc.sym[typeName] = &symbol{kind: typeSym, typ: n.typ}
|
||||
}
|
||||
return false
|
||||
|
||||
case arrayType, basicLit, chanType, funcType, mapType, structType:
|
||||
@@ -400,7 +422,7 @@ func (interp *Interpreter) cfg(root *node) ([]*node, error) {
|
||||
err = n.cfgErrorf("illegal operand types for '%v' operator", n.action)
|
||||
}
|
||||
case aShlAssign, aShrAssign:
|
||||
if !(isInt(t0) && isUint(t1)) {
|
||||
if !(dest.isInteger() && src.isNatural()) {
|
||||
err = n.cfgErrorf("illegal operand types for '%v' operator", n.action)
|
||||
}
|
||||
default:
|
||||
@@ -518,7 +540,7 @@ func (interp *Interpreter) cfg(root *node) ([]*node, error) {
|
||||
err = n.cfgErrorf("illegal operand types for '%v' operator", n.action)
|
||||
}
|
||||
case aShl, aShr:
|
||||
if !(isInt(t0) && isUint(t1)) {
|
||||
if !(c0.isInteger() && c1.isNatural()) {
|
||||
err = n.cfgErrorf("illegal operand types for '%v' operator", n.action)
|
||||
}
|
||||
n.typ = c0.typ
|
||||
@@ -1104,19 +1126,23 @@ func (interp *Interpreter) cfg(root *node) ([]*node, error) {
|
||||
n.typ = m.typ
|
||||
n.recv = &receiver{node: n.child[0], index: lind}
|
||||
}
|
||||
} else if m, lind, ok := n.typ.lookupBinMethod(n.child[1].ident); ok {
|
||||
n.gen = getIndexSeqMethod
|
||||
} else if m, lind, isPtr, ok := n.typ.lookupBinMethod(n.child[1].ident); ok {
|
||||
if isPtr {
|
||||
n.gen = getIndexSeqPtrMethod
|
||||
} else {
|
||||
n.gen = getIndexSeqMethod
|
||||
}
|
||||
n.val = append([]int{m.Index}, lind...)
|
||||
n.typ = &itype{cat: valueT, rtype: m.Type}
|
||||
} else if ti := n.typ.lookupField(n.child[1].ident); len(ti) > 0 {
|
||||
// Handle struct field
|
||||
n.val = ti
|
||||
switch n.typ.cat {
|
||||
case interfaceT:
|
||||
switch {
|
||||
case isInterfaceSrc(n.typ):
|
||||
n.typ = n.typ.fieldSeq(ti)
|
||||
n.gen = getMethodByName
|
||||
n.action = aMethod
|
||||
case ptrT:
|
||||
case n.typ.cat == ptrT:
|
||||
n.typ = n.typ.fieldSeq(ti)
|
||||
n.gen = getPtrIndexSeq
|
||||
if n.typ.cat == funcT {
|
||||
@@ -1499,7 +1525,57 @@ func wireChild(n *node) {
|
||||
}
|
||||
}
|
||||
|
||||
// last returns the last child of a node
|
||||
// isInteger returns true if node type is integer, false otherwise
|
||||
func (n *node) isInteger() bool {
|
||||
if isInt(n.typ.TypeOf()) {
|
||||
return true
|
||||
}
|
||||
if n.typ.untyped && n.rval.IsValid() {
|
||||
t := n.rval.Type()
|
||||
if isInt(t) {
|
||||
return true
|
||||
}
|
||||
if isFloat(t) {
|
||||
// untyped float constant with null decimal part is ok
|
||||
f := n.rval.Float()
|
||||
if f == math.Round(f) {
|
||||
n.rval = reflect.ValueOf(int(f))
|
||||
n.typ.rtype = n.rval.Type()
|
||||
return true
|
||||
}
|
||||
}
|
||||
}
|
||||
return false
|
||||
}
|
||||
|
||||
// isNatural returns true if node type is natural, false otherwise
|
||||
func (n *node) isNatural() bool {
|
||||
if isUint(n.typ.TypeOf()) {
|
||||
return true
|
||||
}
|
||||
if n.typ.untyped && n.rval.IsValid() {
|
||||
t := n.rval.Type()
|
||||
if isUint(t) {
|
||||
return true
|
||||
}
|
||||
if isInt(t) && n.rval.Int() >= 0 {
|
||||
// positive untyped integer constant is ok
|
||||
return true
|
||||
}
|
||||
if isFloat(t) {
|
||||
// positive untyped float constant with null decimal part is ok
|
||||
f := n.rval.Float()
|
||||
if f == math.Round(f) && f >= 0 {
|
||||
n.rval = reflect.ValueOf(uint(f))
|
||||
n.typ.rtype = n.rval.Type()
|
||||
return true
|
||||
}
|
||||
}
|
||||
}
|
||||
return false
|
||||
}
|
||||
|
||||
// lastChild returns the last child of a node
|
||||
func (n *node) lastChild() *node { return n.child[len(n.child)-1] }
|
||||
|
||||
func isKey(n *node) bool {
|
||||
|
||||
@@ -156,6 +156,8 @@ func (interp *Interpreter) gta(root *node, rpath string) ([]*node, error) {
|
||||
default: // import symbols in package namespace
|
||||
sc.sym[name] = &symbol{kind: pkgSym, typ: &itype{cat: srcPkgT, path: ipath}}
|
||||
}
|
||||
} else {
|
||||
err = n.cfgErrorf("import %q error: %v", ipath, err)
|
||||
}
|
||||
|
||||
case typeSpec:
|
||||
@@ -165,13 +167,14 @@ func (interp *Interpreter) gta(root *node, rpath string) ([]*node, error) {
|
||||
return false
|
||||
}
|
||||
if n.child[1].kind == identExpr {
|
||||
n.typ = &itype{cat: aliasT, val: typ, name: typeName, path: rpath}
|
||||
n.typ = &itype{cat: aliasT, val: typ, name: typeName, path: rpath, field: typ.field, incomplete: typ.incomplete}
|
||||
copy(n.typ.method, typ.method)
|
||||
} else {
|
||||
n.typ = typ
|
||||
n.typ.name = typeName
|
||||
n.typ.path = rpath
|
||||
}
|
||||
// Type may already be declared for a receiver in a method function
|
||||
// Type may be already declared for a receiver in a method function
|
||||
if sc.sym[typeName] == nil {
|
||||
sc.sym[typeName] = &symbol{kind: typeSym}
|
||||
} else {
|
||||
|
||||
@@ -44,11 +44,13 @@ func TestEvalArithmetic(t *testing.T) {
|
||||
{desc: "rem_FI", src: "8.0 % 4", err: "1:28: illegal operand types for '%' operator"},
|
||||
{desc: "shl_II", src: "1 << 8", res: "256"},
|
||||
{desc: "shl_IN", src: "1 << -1", err: "1:28: illegal operand types for '<<' operator"},
|
||||
{desc: "shl_IF", src: "1 << 1.0", err: "1:28: illegal operand types for '<<' operator"},
|
||||
{desc: "shl_IF", src: "1.0 << 1", err: "1:28: illegal operand types for '<<' operator"},
|
||||
{desc: "shl_IF", src: "1 << 1.0", res: "2"},
|
||||
{desc: "shl_IF1", src: "1 << 1.1", err: "1:28: illegal operand types for '<<' operator"},
|
||||
{desc: "shl_IF", src: "1.0 << 1", res: "2"},
|
||||
{desc: "shr_II", src: "1 >> 8", res: "0"},
|
||||
{desc: "shr_IN", src: "1 >> -1", err: "1:28: illegal operand types for '>>' operator"},
|
||||
{desc: "shr_IF", src: "1 >> 1.0", err: "1:28: illegal operand types for '>>' operator"},
|
||||
{desc: "shr_IF", src: "1 >> 1.0", res: "0"},
|
||||
{desc: "shr_IF1", src: "1 >> 1.1", err: "1:28: illegal operand types for '>>' operator"},
|
||||
})
|
||||
}
|
||||
|
||||
@@ -368,6 +370,32 @@ func TestEvalChan(t *testing.T) {
|
||||
})
|
||||
}
|
||||
|
||||
func TestEvalMissingSymbol(t *testing.T) {
|
||||
defer func() {
|
||||
r := recover()
|
||||
if r != nil {
|
||||
t.Errorf("unexpected panic: %v", r)
|
||||
}
|
||||
}()
|
||||
|
||||
type S2 struct{}
|
||||
type S1 struct {
|
||||
F S2
|
||||
}
|
||||
i := interp.New(interp.Options{})
|
||||
i.Use(interp.Exports{"p": map[string]reflect.Value{
|
||||
"S1": reflect.Zero(reflect.TypeOf(&S1{})),
|
||||
}})
|
||||
_, err := i.Eval(`import "p"`)
|
||||
if err != nil {
|
||||
t.Fatalf("failed to import package: %v", err)
|
||||
}
|
||||
_, err = i.Eval(`p.S1{F: p.S2{}}`)
|
||||
if err == nil {
|
||||
t.Error("unexpected nil error for expression with undefined type")
|
||||
}
|
||||
}
|
||||
|
||||
func runTests(t *testing.T, i *interp.Interpreter, tests []testCase) {
|
||||
for _, test := range tests {
|
||||
t.Run(test.desc, func(t *testing.T) {
|
||||
|
||||
@@ -502,7 +502,7 @@ func genInterfaceWrapper(n *node, typ reflect.Type) func(*frame) reflect.Value {
|
||||
methods[i], indexes[i] = n.typ.lookupMethod(names[i])
|
||||
if methods[i] == nil && n.typ.cat != nilT {
|
||||
// interpreted method not found, look for binary method, possibly embedded
|
||||
_, indexes[i], _ = n.typ.lookupBinMethod(names[i])
|
||||
_, indexes[i], _, _ = n.typ.lookupBinMethod(names[i])
|
||||
}
|
||||
}
|
||||
wrap := n.interp.getWrapper(typ)
|
||||
@@ -671,7 +671,11 @@ func call(n *node) {
|
||||
|
||||
// Init variadic argument vector
|
||||
if variadic >= 0 {
|
||||
vararg = nf.data[numRet+variadic]
|
||||
if method {
|
||||
vararg = nf.data[numRet+variadic+1]
|
||||
} else {
|
||||
vararg = nf.data[numRet+variadic]
|
||||
}
|
||||
}
|
||||
|
||||
// Copy input parameters from caller
|
||||
@@ -1130,6 +1134,27 @@ func getIndexSeqField(n *node) {
|
||||
}
|
||||
}
|
||||
|
||||
func getIndexSeqPtrMethod(n *node) {
|
||||
value := genValue(n.child[0])
|
||||
index := n.val.([]int)
|
||||
fi := index[1:]
|
||||
mi := index[0]
|
||||
i := n.findex
|
||||
next := getExec(n.tnext)
|
||||
|
||||
if n.child[0].typ.TypeOf().Kind() == reflect.Ptr {
|
||||
n.exec = func(f *frame) bltn {
|
||||
f.data[i] = value(f).Elem().FieldByIndex(fi).Addr().Method(mi)
|
||||
return next
|
||||
}
|
||||
} else {
|
||||
n.exec = func(f *frame) bltn {
|
||||
f.data[i] = value(f).FieldByIndex(fi).Addr().Method(mi)
|
||||
return next
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
func getIndexSeqMethod(n *node) {
|
||||
value := genValue(n.child[0])
|
||||
index := n.val.([]int)
|
||||
@@ -1253,6 +1278,12 @@ func _return(n *node) {
|
||||
switch t := def.typ.ret[i]; t.cat {
|
||||
case errorT:
|
||||
values[i] = genInterfaceWrapper(c, t.TypeOf())
|
||||
case aliasT:
|
||||
if isInterfaceSrc(t) {
|
||||
values[i] = genValueInterface(c)
|
||||
} else {
|
||||
values[i] = genValue(c)
|
||||
}
|
||||
case interfaceT:
|
||||
values[i] = genValueInterface(c)
|
||||
default:
|
||||
@@ -1499,14 +1530,22 @@ func compositeSparse(n *node) {
|
||||
|
||||
func empty(n *node) {}
|
||||
|
||||
var rat = reflect.ValueOf((*[]rune)(nil)).Type().Elem() // runes array type
|
||||
|
||||
func _range(n *node) {
|
||||
index0 := n.child[0].findex // array index location in frame
|
||||
fnext := getExec(n.fnext)
|
||||
tnext := getExec(n.tnext)
|
||||
|
||||
var value func(*frame) reflect.Value
|
||||
if len(n.child) == 4 {
|
||||
index1 := n.child[1].findex // array value location in frame
|
||||
value := genValueArray(n.child[2]) // array
|
||||
an := n.child[2]
|
||||
index1 := n.child[1].findex // array value location in frame
|
||||
if isString(an.typ.TypeOf()) {
|
||||
value = genValueAs(an, rat) // range on string iterates over runes
|
||||
} else {
|
||||
value = genValueArray(an)
|
||||
}
|
||||
n.exec = func(f *frame) bltn {
|
||||
a := value(f)
|
||||
v0 := f.data[index0]
|
||||
@@ -1519,7 +1558,12 @@ func _range(n *node) {
|
||||
return tnext
|
||||
}
|
||||
} else {
|
||||
value := genValueArray(n.child[1]) // array
|
||||
an := n.child[1]
|
||||
if isString(an.typ.TypeOf()) {
|
||||
value = genValueAs(an, rat) // range on string iterates over runes
|
||||
} else {
|
||||
value = genValueArray(an)
|
||||
}
|
||||
n.exec = func(f *frame) bltn {
|
||||
a := value(f)
|
||||
v0 := f.data[index0]
|
||||
|
||||
@@ -215,14 +215,8 @@ func nodeType(interp *Interpreter, sc *scope, n *node) (*itype, error) {
|
||||
t.name = "float64"
|
||||
t.untyped = true
|
||||
case int:
|
||||
if isShiftOperand(n) && v >= 0 {
|
||||
t.cat = uintT
|
||||
t.name = "uint"
|
||||
n.rval = reflect.ValueOf(uint(v))
|
||||
} else {
|
||||
t.cat = intT
|
||||
t.name = "int"
|
||||
}
|
||||
t.cat = intT
|
||||
t.name = "int"
|
||||
t.untyped = true
|
||||
case uint:
|
||||
t.cat = uintT
|
||||
@@ -478,7 +472,7 @@ func nodeType(interp *Interpreter, sc *scope, n *node) (*itype, error) {
|
||||
default:
|
||||
if m, _ := lt.lookupMethod(name); m != nil {
|
||||
t, err = nodeType(interp, sc, m.child[2])
|
||||
} else if bm, _, ok := lt.lookupBinMethod(name); ok {
|
||||
} 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)
|
||||
@@ -694,7 +688,7 @@ func (t *itype) lookupField(name string) []int {
|
||||
|
||||
for i, f := range t.field {
|
||||
switch f.typ.cat {
|
||||
case ptrT, structT:
|
||||
case ptrT, structT, interfaceT, aliasT:
|
||||
if index2 := f.typ.lookupField(name); len(index2) > 0 {
|
||||
return append([]int{i}, index2...)
|
||||
}
|
||||
@@ -758,23 +752,28 @@ func (t *itype) lookupMethod(name string) (*node, []int) {
|
||||
}
|
||||
|
||||
// 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) {
|
||||
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, ok2 := f.typ.lookupBinMethod(name); ok2 {
|
||||
if m2, index2, isPtr2, ok2 := f.typ.lookupBinMethod(name); ok2 {
|
||||
index = append([]int{i}, index2...)
|
||||
return m2, index, ok2
|
||||
return m2, index, isPtr2, ok2
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
return m, index, ok
|
||||
return m, index, isPtr, ok
|
||||
}
|
||||
|
||||
func exportName(s string) string {
|
||||
@@ -801,6 +800,8 @@ func (t *itype) refType(defined map[string]bool) reflect.Type {
|
||||
t.val.rtype = interf
|
||||
}
|
||||
switch t.cat {
|
||||
case aliasT:
|
||||
t.rtype = t.val.refType(defined)
|
||||
case arrayT, variadicT:
|
||||
if t.size > 0 {
|
||||
t.rtype = reflect.ArrayOf(t.size, t.val.refType(defined))
|
||||
@@ -862,6 +863,8 @@ func (t *itype) frameType() (r reflect.Type) {
|
||||
panic(err)
|
||||
}
|
||||
switch t.cat {
|
||||
case aliasT:
|
||||
r = t.val.frameType()
|
||||
case arrayT, variadicT:
|
||||
if t.size > 0 {
|
||||
r = reflect.ArrayOf(t.size, t.val.frameType())
|
||||
@@ -904,14 +907,13 @@ func isShiftNode(n *node) bool {
|
||||
return false
|
||||
}
|
||||
|
||||
func isShiftOperand(n *node) bool {
|
||||
if isShiftNode(n.anc) {
|
||||
return n.anc.lastChild() == n
|
||||
}
|
||||
return false
|
||||
func isInterfaceSrc(t *itype) bool {
|
||||
return t.cat == interfaceT || (t.cat == aliasT && isInterfaceSrc(t.val))
|
||||
}
|
||||
|
||||
func isInterface(t *itype) bool { return t.cat == interfaceT || t.TypeOf().Kind() == reflect.Interface }
|
||||
func isInterface(t *itype) bool {
|
||||
return isInterfaceSrc(t) || t.TypeOf().Kind() == reflect.Interface
|
||||
}
|
||||
|
||||
func isStruct(t *itype) bool { return t.TypeOf().Kind() == reflect.Struct }
|
||||
|
||||
|
||||
Reference in New Issue
Block a user