Compare commits
15 Commits
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
f1cde2be0f | ||
|
|
bb04af2d4d | ||
|
|
9a8a88dcb9 | ||
|
|
f3f54a5302 | ||
|
|
878fcc835c | ||
|
|
a1f2d3bf1d | ||
|
|
3cd37645eb | ||
|
|
e1ac83f7d8 | ||
|
|
4f93be7f19 | ||
|
|
7a0c09f5eb | ||
|
|
275391c1e8 | ||
|
|
273df8af9f | ||
|
|
0d2c39d155 | ||
|
|
1ff1a50753 | ||
|
|
488e491bf8 |
@@ -13,7 +13,12 @@ discussions.
|
||||
Once the proposal is approved, a Pull Request can be opened. If you want
|
||||
to provide early visibility to reviewers, create a [Draft Pull Request].
|
||||
|
||||
We will also require you to sign the [Containous Contributor License Agreement]
|
||||
after you submit your first pull request to this project. The link to sign the
|
||||
agreement will be presented to you in the web interface of the pull request.
|
||||
|
||||
[Issues]: https://github.com/containous/yaegi/issues
|
||||
[Pull Requests]: https://github.com/containous/yaegi/issues
|
||||
[Feature Request]: https://github.com/containous/yaegi/issues/new?template=feature_request.md
|
||||
[Draft Pull Request]: https://github.blog/2019-02-14-introducing-draft-pull-requests/
|
||||
[Containous Contributor License Agreement]: https://cla-assistant.io/containous/yaegi
|
||||
|
||||
13
_test/bin2.go
Normal file
13
_test/bin2.go
Normal file
@@ -0,0 +1,13 @@
|
||||
package main
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"math"
|
||||
)
|
||||
|
||||
func main() {
|
||||
fmt.Println(math.Abs(-5))
|
||||
}
|
||||
|
||||
// Output:
|
||||
// 5
|
||||
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>
|
||||
12
_test/nil1.go
Normal file
12
_test/nil1.go
Normal file
@@ -0,0 +1,12 @@
|
||||
package main
|
||||
|
||||
func main() {
|
||||
var a error = nil
|
||||
|
||||
if a == nil || a.Error() == "nil" {
|
||||
println("a is nil")
|
||||
}
|
||||
}
|
||||
|
||||
// Output:
|
||||
// a is nil
|
||||
9
_test/or0.go
Normal file
9
_test/or0.go
Normal file
@@ -0,0 +1,9 @@
|
||||
package main
|
||||
|
||||
func main() {
|
||||
c := false
|
||||
println(c || !c)
|
||||
}
|
||||
|
||||
// Output:
|
||||
// true
|
||||
9
_test/or1.go
Normal file
9
_test/or1.go
Normal file
@@ -0,0 +1,9 @@
|
||||
package main
|
||||
|
||||
func main() {
|
||||
c := false
|
||||
println(!c || c)
|
||||
}
|
||||
|
||||
// Output:
|
||||
// true
|
||||
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
|
||||
@@ -352,6 +352,30 @@ func {{$name}}(n *node) {
|
||||
}
|
||||
}
|
||||
{{end}}
|
||||
{{range $name, $op := .Unary}}
|
||||
func {{$name}}Const(n *node) {
|
||||
t := n.typ.rtype
|
||||
v := n.child[0].rval
|
||||
n.rval = reflect.New(t).Elem()
|
||||
|
||||
{{- if $op.Bool}}
|
||||
n.rval.SetBool({{$op.Name}} v.Bool())
|
||||
{{- else}}
|
||||
switch t.Kind() {
|
||||
case reflect.Int, reflect.Int8, reflect.Int16, reflect.Int32, reflect.Int64:
|
||||
n.rval.SetInt({{$op.Name}} v.Int())
|
||||
case reflect.Uint, reflect.Uint8, reflect.Uint16, reflect.Uint32, reflect.Uint64, reflect.Uintptr:
|
||||
n.rval.SetUint({{$op.Name}} v.Uint())
|
||||
{{- if $op.Float}}
|
||||
case reflect.Float32, reflect.Float64:
|
||||
n.rval.SetFloat({{$op.Name}} v.Float())
|
||||
case reflect.Complex64, reflect.Complex128:
|
||||
n.rval.SetComplex({{$op.Name}} v.Complex())
|
||||
{{- end}}
|
||||
}
|
||||
{{- end}}
|
||||
}
|
||||
{{end}}
|
||||
{{range $name, $op := .Comparison}}
|
||||
func {{$name}}(n *node) {
|
||||
tnext := getExec(n.tnext)
|
||||
@@ -793,6 +817,7 @@ type Op struct {
|
||||
Float bool // true if operator applies to float
|
||||
Complex bool // true if operator applies to complex
|
||||
Shift bool // true if operator is a shift operation
|
||||
Bool bool // true if operator applies to bool
|
||||
}
|
||||
|
||||
func main() {
|
||||
@@ -805,17 +830,17 @@ func main() {
|
||||
b := &bytes.Buffer{}
|
||||
data := map[string]interface{}{
|
||||
"Arithmetic": map[string]Op{
|
||||
"add": {"+", true, true, true, false},
|
||||
"sub": {"-", false, true, true, false},
|
||||
"mul": {"*", false, true, true, false},
|
||||
"quo": {"/", false, true, true, false},
|
||||
"rem": {"%", false, false, false, false},
|
||||
"shl": {"<<", false, false, false, true},
|
||||
"shr": {">>", false, false, false, true},
|
||||
"and": {"&", false, false, false, false},
|
||||
"or": {"|", false, false, false, false},
|
||||
"xor": {"^", false, false, false, false},
|
||||
"andNot": {"&^", false, false, false, false},
|
||||
"add": {"+", true, true, true, false, false},
|
||||
"sub": {"-", false, true, true, false, false},
|
||||
"mul": {"*", false, true, true, false, false},
|
||||
"quo": {"/", false, true, true, false, false},
|
||||
"rem": {"%", false, false, false, false, false},
|
||||
"shl": {"<<", false, false, false, true, false},
|
||||
"shr": {">>", false, false, false, true, false},
|
||||
"and": {"&", false, false, false, false, false},
|
||||
"or": {"|", false, false, false, false, false},
|
||||
"xor": {"^", false, false, false, false, false},
|
||||
"andNot": {"&^", false, false, false, false, false},
|
||||
},
|
||||
"IncDec": map[string]Op{
|
||||
"inc": {Name: "+"},
|
||||
@@ -829,6 +854,12 @@ func main() {
|
||||
"lowerEqual": {Name: "<=", Complex: false},
|
||||
"notEqual": {Name: "!=", Complex: true},
|
||||
},
|
||||
"Unary": map[string]Op{
|
||||
"not": {Name: "!", Float: false, Bool: true},
|
||||
"neg": {Name: "-", Float: true, Bool: false},
|
||||
"pos": {Name: "+", Float: true, Bool: false},
|
||||
"bitNot": {Name: "^", Float: false, Bool: false},
|
||||
},
|
||||
}
|
||||
if err = parse.Execute(b, data); err != nil {
|
||||
log.Fatal(err)
|
||||
|
||||
@@ -199,6 +199,7 @@ const (
|
||||
aAndAssign
|
||||
aAndNot
|
||||
aAndNotAssign
|
||||
aBitNot
|
||||
aCall
|
||||
aCase
|
||||
aCompositeLit
|
||||
@@ -217,11 +218,12 @@ const (
|
||||
aMethod
|
||||
aMul
|
||||
aMulAssign
|
||||
aNegate
|
||||
aNeg
|
||||
aNot
|
||||
aNotEqual
|
||||
aOr
|
||||
aOrAssign
|
||||
aPos
|
||||
aQuo
|
||||
aQuoAssign
|
||||
aRange
|
||||
@@ -255,6 +257,7 @@ var actions = [...]string{
|
||||
aAndAssign: "&=",
|
||||
aAndNot: "&^",
|
||||
aAndNotAssign: "&^=",
|
||||
aBitNot: "^",
|
||||
aCall: "call",
|
||||
aCase: "case",
|
||||
aCompositeLit: "compositeLit",
|
||||
@@ -271,11 +274,12 @@ var actions = [...]string{
|
||||
aMethod: "Method",
|
||||
aMul: "*",
|
||||
aMulAssign: "*=",
|
||||
aNegate: "-",
|
||||
aNeg: "-",
|
||||
aNot: "!",
|
||||
aNotEqual: "!=",
|
||||
aOr: "|",
|
||||
aOrAssign: "|=",
|
||||
aPos: "+",
|
||||
aQuo: "/",
|
||||
aQuoAssign: "/=",
|
||||
aRange: "range",
|
||||
@@ -771,6 +775,8 @@ func (interp *Interpreter) ast(src, name string) (string, *node, error) {
|
||||
var kind = unaryExpr
|
||||
var act action
|
||||
switch a.Op {
|
||||
case token.ADD:
|
||||
act = aPos
|
||||
case token.AND:
|
||||
kind = addressExpr
|
||||
act = aAddr
|
||||
@@ -779,7 +785,9 @@ func (interp *Interpreter) ast(src, name string) (string, *node, error) {
|
||||
case token.NOT:
|
||||
act = aNot
|
||||
case token.SUB:
|
||||
act = aNegate
|
||||
act = aNeg
|
||||
case token.XOR:
|
||||
act = aBitNot
|
||||
}
|
||||
st.push(addChild(&root, anc, pos, kind, act), nod)
|
||||
|
||||
|
||||
125
interp/cfg.go
125
interp/cfg.go
@@ -4,8 +4,8 @@ import (
|
||||
"fmt"
|
||||
"log"
|
||||
"math"
|
||||
"path"
|
||||
"reflect"
|
||||
"regexp"
|
||||
"unicode"
|
||||
)
|
||||
|
||||
@@ -24,6 +24,10 @@ var constOp = map[action]func(*node){
|
||||
aShr: shrConst,
|
||||
aAndNot: andNotConst,
|
||||
aXor: xorConst,
|
||||
aNot: notConst,
|
||||
aBitNot: bitNotConst,
|
||||
aNeg: negConst,
|
||||
aPos: posConst,
|
||||
}
|
||||
|
||||
var constBltn = map[string]func(*node){
|
||||
@@ -32,6 +36,8 @@ var constBltn = map[string]func(*node){
|
||||
"real": realConst,
|
||||
}
|
||||
|
||||
var identifier = regexp.MustCompile(`([\pL_][\pL_\d]*)$`)
|
||||
|
||||
// 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
|
||||
// variables. A list of nodes of init functions is returned.
|
||||
@@ -170,23 +176,21 @@ func (interp *Interpreter) cfg(root *node) ([]*node, error) {
|
||||
var typ *itype
|
||||
if len(n.child) == 2 {
|
||||
// 1 type in clause: define the var with this type in the case clause scope
|
||||
switch sym, _, ok := sc.lookup(n.child[0].ident); {
|
||||
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
|
||||
}
|
||||
switch {
|
||||
case n.child[0].ident == "nil":
|
||||
typ = sc.getType("interface{}")
|
||||
default:
|
||||
case !n.child[0].isType(sc):
|
||||
err = n.cfgErrorf("%s is not a type", n.child[0].ident)
|
||||
return false
|
||||
default:
|
||||
typ, err = nodeType(interp, sc, n.child[0])
|
||||
}
|
||||
} else {
|
||||
// define the var with the type in the switch guard expression
|
||||
typ = sn.child[1].child[1].child[0].typ
|
||||
}
|
||||
if err != nil {
|
||||
return false
|
||||
}
|
||||
nod := n.lastChild().child[0]
|
||||
index := sc.add(typ)
|
||||
sc.sym[nod.ident] = &symbol{index: index, kind: varSym, typ: typ}
|
||||
@@ -318,7 +322,7 @@ func (interp *Interpreter) cfg(root *node) ([]*node, error) {
|
||||
name = n.child[0].ident
|
||||
} else {
|
||||
ipath = n.child[0].rval.String()
|
||||
name = path.Base(ipath)
|
||||
name = identifier.FindString(ipath)
|
||||
}
|
||||
if interp.binPkg[ipath] != nil && name != "." {
|
||||
sc.sym[name] = &symbol{kind: pkgSym, typ: &itype{cat: binPkgT, path: ipath}}
|
||||
@@ -549,7 +553,7 @@ func (interp *Interpreter) cfg(root *node) ([]*node, error) {
|
||||
t0, t1 := c0.typ.TypeOf(), c1.typ.TypeOf()
|
||||
// Shift operator type is inherited from first parameter only
|
||||
// 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())
|
||||
break
|
||||
}
|
||||
@@ -602,8 +606,6 @@ func (interp *Interpreter) cfg(root *node) ([]*node, error) {
|
||||
constOp[n.action](n)
|
||||
}
|
||||
switch {
|
||||
//case n.typ != nil && n.typ.cat == BoolT && isAncBranch(n):
|
||||
// n.findex = -1
|
||||
case n.rval.IsValid():
|
||||
n.gen = nop
|
||||
n.findex = -1
|
||||
@@ -1021,6 +1023,9 @@ func (interp *Interpreter) cfg(root *node) ([]*node, error) {
|
||||
n.child[1].tnext = n
|
||||
n.typ = n.child[0].typ
|
||||
n.findex = sc.add(n.typ)
|
||||
if n.start.action == aNop {
|
||||
n.start.gen = branch
|
||||
}
|
||||
|
||||
case lorExpr:
|
||||
n.start = n.child[0].start
|
||||
@@ -1029,6 +1034,9 @@ func (interp *Interpreter) cfg(root *node) ([]*node, error) {
|
||||
n.child[1].tnext = n
|
||||
n.typ = n.child[0].typ
|
||||
n.findex = sc.add(n.typ)
|
||||
if n.start.action == aNop {
|
||||
n.start.gen = branch
|
||||
}
|
||||
|
||||
case parenExpr:
|
||||
wireChild(n)
|
||||
@@ -1068,7 +1076,7 @@ func (interp *Interpreter) cfg(root *node) ([]*node, error) {
|
||||
// nil: Set node value to zero of return type
|
||||
f := sc.def
|
||||
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
|
||||
}
|
||||
if typ.cat == funcT {
|
||||
@@ -1155,7 +1163,7 @@ func (interp *Interpreter) cfg(root *node) ([]*node, error) {
|
||||
n.typ = &itype{cat: valueT, rtype: s.Type().Elem()}
|
||||
} else {
|
||||
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.gen = nop
|
||||
@@ -1377,16 +1385,60 @@ func (interp *Interpreter) cfg(root *node) ([]*node, error) {
|
||||
case unaryExpr:
|
||||
wireChild(n)
|
||||
n.typ = n.child[0].typ
|
||||
if n.action == aRecv {
|
||||
switch n.action {
|
||||
case aRecv:
|
||||
// Channel receive operation: set type to the channel data type
|
||||
if n.typ.cat == valueT {
|
||||
n.typ = &itype{cat: valueT, rtype: n.typ.rtype.Elem()}
|
||||
} else {
|
||||
n.typ = n.typ.val
|
||||
}
|
||||
case aBitNot:
|
||||
if !isInt(n.typ.TypeOf()) {
|
||||
err = n.cfgErrorf("illegal operand type for '^' operator")
|
||||
return
|
||||
}
|
||||
case aNot:
|
||||
if !isBool(n.typ) {
|
||||
err = n.cfgErrorf("illegal operand type for '!' operator")
|
||||
return
|
||||
}
|
||||
case aNeg, aPos:
|
||||
if !isNumber(n.typ.TypeOf()) {
|
||||
err = n.cfgErrorf("illegal operand type for '%v' operator", n.action)
|
||||
return
|
||||
}
|
||||
}
|
||||
// TODO: Optimisation: avoid allocation if boolean branch op (i.e. '!' in an 'if' expr)
|
||||
n.findex = sc.add(n.typ)
|
||||
if n.child[0].rval.IsValid() && constOp[n.action] != nil {
|
||||
if n.typ == nil {
|
||||
if n.typ, err = nodeType(interp, sc, n); err != nil {
|
||||
return
|
||||
}
|
||||
}
|
||||
n.typ.TypeOf() // init reflect type
|
||||
constOp[n.action](n)
|
||||
}
|
||||
switch {
|
||||
case n.rval.IsValid():
|
||||
n.gen = nop
|
||||
n.findex = -1
|
||||
case n.anc.kind == assignStmt && n.anc.action == aAssign:
|
||||
dest := n.anc.child[childPos(n)-n.anc.nright]
|
||||
n.typ = dest.typ
|
||||
n.findex = dest.findex
|
||||
case n.anc.kind == returnStmt:
|
||||
pos := childPos(n)
|
||||
n.typ = sc.def.typ.ret[pos]
|
||||
n.findex = pos
|
||||
default:
|
||||
if n.typ == nil {
|
||||
if n.typ, err = nodeType(interp, sc, n); err != nil {
|
||||
return
|
||||
}
|
||||
}
|
||||
n.findex = sc.add(n.typ)
|
||||
}
|
||||
|
||||
case valueSpec:
|
||||
n.gen = reset
|
||||
@@ -1528,7 +1580,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
|
||||
func (n *node) isType(sc *scope) bool {
|
||||
switch n.kind {
|
||||
case arrayType, chanType, funcType, mapType, structType, rtypeExpr:
|
||||
case arrayType, chanType, funcType, interfaceType, mapType, structType, rtypeExpr:
|
||||
return true
|
||||
case parenExpr, starExpr:
|
||||
if len(n.child) == 1 {
|
||||
@@ -1536,7 +1588,7 @@ func (n *node) isType(sc *scope) bool {
|
||||
}
|
||||
case selectorExpr:
|
||||
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
|
||||
if p, ok := n.interp.binPkg[path]; ok && isBinType(p[name]) {
|
||||
return true // Imported binary type
|
||||
@@ -1643,6 +1695,29 @@ func (n *node) isNatural() bool {
|
||||
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
|
||||
func (n *node) lastChild() *node { return n.child[len(n.child)-1] }
|
||||
|
||||
@@ -1825,3 +1900,13 @@ func arrayTypeLen(n *node) int {
|
||||
}
|
||||
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()
|
||||
}
|
||||
|
||||
@@ -4,6 +4,18 @@ Package interp provides a complete Go interpreter.
|
||||
For the Go language itself, refer to the official Go specification
|
||||
https://golang.org/ref/spec.
|
||||
|
||||
Importing packages
|
||||
|
||||
Packages can be imported in source or binary form, using the standard
|
||||
Go import statement. In source form, packages are searched first in the
|
||||
vendor directory, the preferred way to store source dependencies. If not
|
||||
found in vendor, sources modules will be searched in GOPATH. Go modules
|
||||
are not supported yet by yaegi.
|
||||
|
||||
Binary form packages are compiled and linked with the interpreter
|
||||
executable, and exposed to scripts with the Use method. The goexports
|
||||
command can be used to generate package wrappers.
|
||||
|
||||
Custom build tags
|
||||
|
||||
Custom build tags allow to control which files in imported source
|
||||
|
||||
@@ -38,7 +38,7 @@ func (n *node) astDot(out io.Writer, name string) {
|
||||
func (n *node) cfgDot(out io.Writer) {
|
||||
fmt.Fprintf(out, "digraph cfg {\n")
|
||||
n.Walk(nil, func(n *node) {
|
||||
if n.kind == basicLit || n.kind == identExpr || n.tnext == nil {
|
||||
if n.kind == basicLit || n.tnext == nil {
|
||||
return
|
||||
}
|
||||
var label string
|
||||
|
||||
@@ -1,7 +1,6 @@
|
||||
package interp
|
||||
|
||||
import (
|
||||
"path"
|
||||
"reflect"
|
||||
)
|
||||
|
||||
@@ -31,6 +30,7 @@ func (interp *Interpreter) gta(root *node, rpath string) ([]*node, error) {
|
||||
case defineStmt:
|
||||
var atyp *itype
|
||||
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 {
|
||||
return false
|
||||
}
|
||||
@@ -126,7 +126,7 @@ func (interp *Interpreter) gta(root *node, rpath string) ([]*node, error) {
|
||||
name = n.child[0].ident
|
||||
} else {
|
||||
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
|
||||
if interp.binPkg[ipath] != nil {
|
||||
|
||||
@@ -47,11 +47,17 @@ func TestEvalArithmetic(t *testing.T) {
|
||||
{desc: "shl_IN", src: "1 << -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: "shl_IF2", 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", res: "0"},
|
||||
{desc: "shr_IF1", src: "1 >> 1.1", err: "1:28: illegal operand types for '>>' operator"},
|
||||
{desc: "neg_I", src: "-2", res: "-2"},
|
||||
{desc: "pos_I", src: "+2", res: "2"},
|
||||
{desc: "bitnot_I", src: "^2", res: "-3"},
|
||||
{desc: "bitnot_F", src: "^0.2", err: "1:28: illegal operand type for '^' operator"},
|
||||
{desc: "not_B", src: "!false", res: "true"},
|
||||
{desc: "not_I", src: "!0", err: "1:28: illegal operand type for '!' operator"},
|
||||
})
|
||||
}
|
||||
|
||||
|
||||
51
interp/op.go
51
interp/op.go
@@ -1864,6 +1864,57 @@ func inc(n *node) {
|
||||
}
|
||||
}
|
||||
|
||||
func bitNotConst(n *node) {
|
||||
t := n.typ.rtype
|
||||
v := n.child[0].rval
|
||||
n.rval = reflect.New(t).Elem()
|
||||
switch t.Kind() {
|
||||
case reflect.Int, reflect.Int8, reflect.Int16, reflect.Int32, reflect.Int64:
|
||||
n.rval.SetInt(^v.Int())
|
||||
case reflect.Uint, reflect.Uint8, reflect.Uint16, reflect.Uint32, reflect.Uint64, reflect.Uintptr:
|
||||
n.rval.SetUint(^v.Uint())
|
||||
}
|
||||
}
|
||||
|
||||
func negConst(n *node) {
|
||||
t := n.typ.rtype
|
||||
v := n.child[0].rval
|
||||
n.rval = reflect.New(t).Elem()
|
||||
switch t.Kind() {
|
||||
case reflect.Int, reflect.Int8, reflect.Int16, reflect.Int32, reflect.Int64:
|
||||
n.rval.SetInt(-v.Int())
|
||||
case reflect.Uint, reflect.Uint8, reflect.Uint16, reflect.Uint32, reflect.Uint64, reflect.Uintptr:
|
||||
n.rval.SetUint(-v.Uint())
|
||||
case reflect.Float32, reflect.Float64:
|
||||
n.rval.SetFloat(-v.Float())
|
||||
case reflect.Complex64, reflect.Complex128:
|
||||
n.rval.SetComplex(-v.Complex())
|
||||
}
|
||||
}
|
||||
|
||||
func notConst(n *node) {
|
||||
t := n.typ.rtype
|
||||
v := n.child[0].rval
|
||||
n.rval = reflect.New(t).Elem()
|
||||
n.rval.SetBool(!v.Bool())
|
||||
}
|
||||
|
||||
func posConst(n *node) {
|
||||
t := n.typ.rtype
|
||||
v := n.child[0].rval
|
||||
n.rval = reflect.New(t).Elem()
|
||||
switch t.Kind() {
|
||||
case reflect.Int, reflect.Int8, reflect.Int16, reflect.Int32, reflect.Int64:
|
||||
n.rval.SetInt(+v.Int())
|
||||
case reflect.Uint, reflect.Uint8, reflect.Uint16, reflect.Uint32, reflect.Uint64, reflect.Uintptr:
|
||||
n.rval.SetUint(+v.Uint())
|
||||
case reflect.Float32, reflect.Float64:
|
||||
n.rval.SetFloat(+v.Float())
|
||||
case reflect.Complex64, reflect.Complex128:
|
||||
n.rval.SetComplex(+v.Complex())
|
||||
}
|
||||
}
|
||||
|
||||
func equal(n *node) {
|
||||
tnext := getExec(n.tnext)
|
||||
dest := genValue(n)
|
||||
|
||||
@@ -24,6 +24,7 @@ var builtin = [...]bltnGenerator{
|
||||
aAndAssign: andAssign,
|
||||
aAndNot: andNot,
|
||||
aAndNotAssign: andNotAssign,
|
||||
aBitNot: bitNot,
|
||||
aCall: call,
|
||||
aCase: _case,
|
||||
aCompositeLit: arrayLit,
|
||||
@@ -40,11 +41,12 @@ var builtin = [...]bltnGenerator{
|
||||
aLowerEqual: lowerEqual,
|
||||
aMul: mul,
|
||||
aMulAssign: mulAssign,
|
||||
aNegate: negate,
|
||||
aNeg: neg,
|
||||
aNot: not,
|
||||
aNotEqual: notEqual,
|
||||
aOr: or,
|
||||
aOrAssign: orAssign,
|
||||
aPos: pos,
|
||||
aQuo: quo,
|
||||
aQuoAssign: quoAssign,
|
||||
aRange: _range,
|
||||
@@ -239,7 +241,7 @@ func isRecursiveStruct(t *itype, rtype reflect.Type) bool {
|
||||
if t.cat == structT && rtype.Kind() == reflect.Interface {
|
||||
return true
|
||||
}
|
||||
if t.cat == ptrT {
|
||||
if t.cat == ptrT && t.rtype != nil {
|
||||
return isRecursiveStruct(t.val, t.rtype.Elem())
|
||||
}
|
||||
return false
|
||||
@@ -260,7 +262,7 @@ func assign(n *node) {
|
||||
switch {
|
||||
case dest.typ.cat == interfaceT:
|
||||
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)
|
||||
case dest.typ.cat == valueT && src.typ.cat == funcT:
|
||||
svalue[i] = genFunctionWrapper(src)
|
||||
@@ -340,21 +342,24 @@ func assign(n *node) {
|
||||
}
|
||||
|
||||
func not(n *node) {
|
||||
dest := genValue(n)
|
||||
value := genValue(n.child[0])
|
||||
tnext := getExec(n.tnext)
|
||||
i := n.findex
|
||||
|
||||
if n.fnext != nil {
|
||||
fnext := getExec(n.fnext)
|
||||
n.exec = func(f *frame) bltn {
|
||||
if !value(f).Bool() {
|
||||
f.data[i].SetBool(true)
|
||||
return tnext
|
||||
}
|
||||
f.data[i].SetBool(false)
|
||||
return fnext
|
||||
}
|
||||
} else {
|
||||
i := n.findex
|
||||
n.exec = func(f *frame) bltn {
|
||||
f.data[i].SetBool(!value(f).Bool())
|
||||
dest(f).SetBool(!value(f).Bool())
|
||||
return tnext
|
||||
}
|
||||
}
|
||||
@@ -658,7 +663,7 @@ func call(n *node) {
|
||||
values = append(values, func(f *frame) reflect.Value { return f.data[ind] })
|
||||
}
|
||||
default:
|
||||
if c.kind == basicLit {
|
||||
if c.kind == basicLit || c.rval.IsValid() {
|
||||
var argType reflect.Type
|
||||
if variadic >= 0 && i >= variadic {
|
||||
argType = n.child[0].typ.arg[variadic].val.TypeOf()
|
||||
@@ -843,7 +848,7 @@ func callBin(n *node) {
|
||||
values = append(values, func(f *frame) reflect.Value { return f.data[ind] })
|
||||
}
|
||||
default:
|
||||
if c.kind == basicLit {
|
||||
if c.kind == basicLit || c.rval.IsValid() {
|
||||
// Convert literal value (untyped) to function argument type (if not an interface{})
|
||||
var argType reflect.Type
|
||||
if variadic >= 0 && i >= variadic {
|
||||
@@ -1246,7 +1251,7 @@ func getIndexSeqMethod(n *node) {
|
||||
}
|
||||
}
|
||||
|
||||
func negate(n *node) {
|
||||
func neg(n *node) {
|
||||
dest := genValue(n)
|
||||
value := genValue(n.child[0])
|
||||
next := getExec(n.tnext)
|
||||
@@ -1270,6 +1275,37 @@ func negate(n *node) {
|
||||
}
|
||||
}
|
||||
|
||||
func pos(n *node) {
|
||||
dest := genValue(n)
|
||||
value := genValue(n.child[0])
|
||||
next := getExec(n.tnext)
|
||||
|
||||
n.exec = func(f *frame) bltn {
|
||||
dest(f).Set(value(f))
|
||||
return next
|
||||
}
|
||||
}
|
||||
|
||||
func bitNot(n *node) {
|
||||
dest := genValue(n)
|
||||
value := genValue(n.child[0])
|
||||
next := getExec(n.tnext)
|
||||
typ := n.typ.TypeOf()
|
||||
|
||||
switch typ.Kind() {
|
||||
case reflect.Int, reflect.Int8, reflect.Int16, reflect.Int32, reflect.Int64:
|
||||
n.exec = func(f *frame) bltn {
|
||||
dest(f).SetInt(^value(f).Int())
|
||||
return next
|
||||
}
|
||||
case reflect.Uint, reflect.Uint8, reflect.Uint16, reflect.Uint32, reflect.Uint64, reflect.Uintptr:
|
||||
n.exec = func(f *frame) bltn {
|
||||
dest(f).SetUint(^value(f).Uint())
|
||||
return next
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
func land(n *node) {
|
||||
value0 := genValue(n.child[0])
|
||||
value1 := genValue(n.child[1])
|
||||
@@ -1946,7 +1982,7 @@ func _close(n *node) {
|
||||
}
|
||||
|
||||
func _complex(n *node) {
|
||||
i := n.findex
|
||||
dest := genValue(n)
|
||||
c1, c2 := n.child[1], n.child[2]
|
||||
convertLiteralValue(c1, floatType)
|
||||
convertLiteralValue(c2, floatType)
|
||||
@@ -1956,38 +1992,38 @@ func _complex(n *node) {
|
||||
|
||||
if typ := n.typ.TypeOf(); isComplex(typ) {
|
||||
n.exec = func(f *frame) bltn {
|
||||
f.data[i].SetComplex(complex(value0(f).Float(), value1(f).Float()))
|
||||
dest(f).SetComplex(complex(value0(f).Float(), value1(f).Float()))
|
||||
return next
|
||||
}
|
||||
} else {
|
||||
// Not a complex type: ignore imaginary part
|
||||
n.exec = func(f *frame) bltn {
|
||||
f.data[i].Set(value0(f).Convert(typ))
|
||||
dest(f).Set(value0(f).Convert(typ))
|
||||
return next
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
func _imag(n *node) {
|
||||
i := n.findex
|
||||
dest := genValue(n)
|
||||
convertLiteralValue(n.child[1], complexType)
|
||||
value := genValue(n.child[1])
|
||||
next := getExec(n.tnext)
|
||||
|
||||
n.exec = func(f *frame) bltn {
|
||||
f.data[i].SetFloat(imag(value(f).Complex()))
|
||||
dest(f).SetFloat(imag(value(f).Complex()))
|
||||
return next
|
||||
}
|
||||
}
|
||||
|
||||
func _real(n *node) {
|
||||
i := n.findex
|
||||
dest := genValue(n)
|
||||
convertLiteralValue(n.child[1], complexType)
|
||||
value := genValue(n.child[1])
|
||||
next := getExec(n.tnext)
|
||||
|
||||
n.exec = func(f *frame) bltn {
|
||||
f.data[i].SetFloat(real(value(f).Complex()))
|
||||
dest(f).SetFloat(real(value(f).Complex()))
|
||||
return next
|
||||
}
|
||||
}
|
||||
@@ -2005,12 +2041,12 @@ func _delete(n *node) {
|
||||
}
|
||||
|
||||
func _len(n *node) {
|
||||
i := n.findex
|
||||
dest := genValue(n)
|
||||
value := genValue(n.child[1])
|
||||
next := getExec(n.tnext)
|
||||
|
||||
n.exec = func(f *frame) bltn {
|
||||
f.data[i].SetInt(int64(value(f).Len()))
|
||||
dest(f).SetInt(int64(value(f).Len()))
|
||||
return next
|
||||
}
|
||||
}
|
||||
@@ -2222,13 +2258,16 @@ func recv2(n *node) {
|
||||
}
|
||||
|
||||
func convertLiteralValue(n *node, t reflect.Type) {
|
||||
if n.kind != basicLit || t == nil || t.Kind() == reflect.Interface {
|
||||
// Skip non-constant values, undefined target type or interface target type.
|
||||
if !(n.kind == basicLit || n.rval.IsValid()) || t == nil || t.Kind() == reflect.Interface {
|
||||
return
|
||||
}
|
||||
if n.rval.IsValid() {
|
||||
// Convert constant value to target type.
|
||||
n.rval = n.rval.Convert(t)
|
||||
} else {
|
||||
n.rval = reflect.New(t).Elem() // convert to type nil value
|
||||
// Create a zero value of target type.
|
||||
n.rval = reflect.New(t).Elem()
|
||||
}
|
||||
}
|
||||
|
||||
@@ -2420,19 +2459,21 @@ func isNil(n *node) {
|
||||
value = genValue(n.child[0])
|
||||
}
|
||||
tnext := getExec(n.tnext)
|
||||
dest := genValue(n)
|
||||
|
||||
if n.fnext != nil {
|
||||
fnext := getExec(n.fnext)
|
||||
n.exec = func(f *frame) bltn {
|
||||
if value(f).IsNil() {
|
||||
dest(f).SetBool(true)
|
||||
return tnext
|
||||
}
|
||||
dest(f).SetBool(false)
|
||||
return fnext
|
||||
}
|
||||
} else {
|
||||
i := n.findex
|
||||
n.exec = func(f *frame) bltn {
|
||||
f.data[i].SetBool(value(f).IsNil())
|
||||
dest(f).SetBool(value(f).IsNil())
|
||||
return tnext
|
||||
}
|
||||
}
|
||||
@@ -2446,19 +2487,21 @@ func isNotNil(n *node) {
|
||||
value = genValue(n.child[0])
|
||||
}
|
||||
tnext := getExec(n.tnext)
|
||||
dest := genValue(n)
|
||||
|
||||
if n.fnext != nil {
|
||||
fnext := getExec(n.fnext)
|
||||
n.exec = func(f *frame) bltn {
|
||||
if value(f).IsNil() {
|
||||
dest(f).SetBool(false)
|
||||
return fnext
|
||||
}
|
||||
dest(f).SetBool(true)
|
||||
return tnext
|
||||
}
|
||||
} else {
|
||||
i := n.findex
|
||||
n.exec = func(f *frame) bltn {
|
||||
f.data[i].SetBool(!value(f).IsNil())
|
||||
dest(f).SetBool(!value(f).IsNil())
|
||||
return tnext
|
||||
}
|
||||
}
|
||||
|
||||
@@ -401,6 +401,9 @@ func nodeType(interp *Interpreter, sc *scope, n *node) (*itype, error) {
|
||||
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}
|
||||
@@ -636,6 +639,74 @@ func (t *itype) finalize() (*itype, error) {
|
||||
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()
|
||||
@@ -814,7 +885,9 @@ func (t *itype) refType(defined map[string]bool) reflect.Type {
|
||||
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
|
||||
}
|
||||
switch t.cat {
|
||||
@@ -834,15 +907,9 @@ func (t *itype) refType(defined map[string]bool) reflect.Type {
|
||||
in := make([]reflect.Type, len(t.arg))
|
||||
out := make([]reflect.Type, len(t.ret))
|
||||
for i, v := range t.arg {
|
||||
if defined[v.name] {
|
||||
v.rtype = interf
|
||||
}
|
||||
in[i] = v.refType(defined)
|
||||
}
|
||||
for i, v := range t.ret {
|
||||
if defined[v.name] {
|
||||
v.rtype = interf
|
||||
}
|
||||
out[i] = v.refType(defined)
|
||||
}
|
||||
t.rtype = reflect.FuncOf(in, out, false)
|
||||
@@ -933,7 +1000,11 @@ func isInterface(t *itype) bool {
|
||||
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 }
|
||||
|
||||
|
||||
@@ -1,5 +1,6 @@
|
||||
// +build go1.12,!go1.14
|
||||
|
||||
// Package stdlib provides wrappers of standard library packages to be imported natively in Yaegi.
|
||||
package stdlib
|
||||
|
||||
import "reflect"
|
||||
|
||||
@@ -1,5 +1,6 @@
|
||||
// +build go1.12,!go1.14
|
||||
|
||||
// Package syscall provide wrapper of standard library syscall package for native import in Yaegi.
|
||||
package syscall
|
||||
|
||||
import "reflect"
|
||||
|
||||
@@ -1,5 +1,6 @@
|
||||
// +build go1.12,!go1.14
|
||||
|
||||
// Package unsafe provides wrapper of standard library unsafe package to be imported natively in Yaegi.
|
||||
package unsafe
|
||||
|
||||
import "reflect"
|
||||
|
||||
Reference in New Issue
Block a user