Compare commits
15 Commits
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
7037424edf | ||
|
|
1b971b539c | ||
|
|
681f2f9c40 | ||
|
|
05960316f8 | ||
|
|
902af477b8 | ||
|
|
812e55b95e | ||
|
|
6c339ce562 | ||
|
|
23dfef0ac8 | ||
|
|
4fd6a2dc56 | ||
|
|
92a63dbe09 | ||
|
|
e434892b9a | ||
|
|
712891dd77 | ||
|
|
137b16580c | ||
|
|
b057ada531 | ||
|
|
6d90c5a641 |
18
README.md
18
README.md
@@ -129,6 +129,24 @@ $ yaegi cmd/yaegi/yaegi.go
|
||||
>
|
||||
```
|
||||
|
||||
Or for Go scripting in the shebang line:
|
||||
|
||||
```console
|
||||
$ cat /tmp/test
|
||||
#!/usr/bin/env yaegi
|
||||
package main
|
||||
|
||||
import "fmt"
|
||||
|
||||
func main() {
|
||||
fmt.Println("test")
|
||||
}
|
||||
$ ls -la /tmp/test
|
||||
-rwxr-xr-x 1 dow184 dow184 93 Jan 6 13:38 /tmp/test
|
||||
$ /tmp/test
|
||||
test
|
||||
```
|
||||
|
||||
## Documentation
|
||||
|
||||
Documentation about Yaegi commands and libraries can be found at usual [godoc.org][docs].
|
||||
|
||||
23
_test/a40.go
Normal file
23
_test/a40.go
Normal file
@@ -0,0 +1,23 @@
|
||||
package main
|
||||
|
||||
import "fmt"
|
||||
|
||||
type rule uint8
|
||||
|
||||
const (
|
||||
r0 rule = iota
|
||||
r1
|
||||
r2
|
||||
)
|
||||
|
||||
var a = [...]int{
|
||||
r0: 1,
|
||||
r1: 12,
|
||||
}
|
||||
|
||||
func main() {
|
||||
fmt.Println(a)
|
||||
}
|
||||
|
||||
// Output:
|
||||
// [1 12]
|
||||
10
_test/a41.go
Normal file
10
_test/a41.go
Normal file
@@ -0,0 +1,10 @@
|
||||
package main
|
||||
|
||||
var a = [...]bool{true, true}
|
||||
|
||||
func main() {
|
||||
println(a[0] && true)
|
||||
}
|
||||
|
||||
// Output:
|
||||
// true
|
||||
10
_test/and3.go
Normal file
10
_test/and3.go
Normal file
@@ -0,0 +1,10 @@
|
||||
package main
|
||||
|
||||
var a = true && true
|
||||
|
||||
func main() {
|
||||
println(a)
|
||||
}
|
||||
|
||||
// Output:
|
||||
// true
|
||||
7
_test/b1/foo/foo.go
Normal file
7
_test/b1/foo/foo.go
Normal file
@@ -0,0 +1,7 @@
|
||||
package foo
|
||||
|
||||
import bar "github.com/containous/yaegi/_test/b2/foo"
|
||||
|
||||
var Desc = "in b1/foo"
|
||||
|
||||
var Desc2 = Desc + bar.Desc
|
||||
3
_test/b2/foo/foo.go
Normal file
3
_test/b2/foo/foo.go
Normal file
@@ -0,0 +1,3 @@
|
||||
package foo
|
||||
|
||||
var Desc = "in b2/foo"
|
||||
12
_test/chan8.go
Normal file
12
_test/chan8.go
Normal file
@@ -0,0 +1,12 @@
|
||||
package main
|
||||
|
||||
func main() {
|
||||
messages := make(chan bool)
|
||||
|
||||
go func() { messages <- true }()
|
||||
|
||||
println(<-messages && true)
|
||||
}
|
||||
|
||||
// Output:
|
||||
// true
|
||||
16
_test/composite5.go
Normal file
16
_test/composite5.go
Normal file
@@ -0,0 +1,16 @@
|
||||
package main
|
||||
|
||||
import "fmt"
|
||||
|
||||
type T struct {
|
||||
m uint16
|
||||
}
|
||||
|
||||
var t = T{1<<2 | 1<<3}
|
||||
|
||||
func main() {
|
||||
fmt.Println(t)
|
||||
}
|
||||
|
||||
// Output:
|
||||
// {12}
|
||||
20
_test/composite6.go
Normal file
20
_test/composite6.go
Normal file
@@ -0,0 +1,20 @@
|
||||
package main
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
|
||||
"github.com/containous/yaegi/_test/ct1"
|
||||
)
|
||||
|
||||
type T struct {
|
||||
m uint16
|
||||
}
|
||||
|
||||
var t = T{1 << ct1.R}
|
||||
|
||||
func main() {
|
||||
fmt.Println(t)
|
||||
}
|
||||
|
||||
// Output:
|
||||
// {2}
|
||||
22
_test/const6.go
Normal file
22
_test/const6.go
Normal file
@@ -0,0 +1,22 @@
|
||||
package main
|
||||
|
||||
const (
|
||||
maxNonStarters = 30
|
||||
maxBufferSize = maxNonStarters + 2
|
||||
)
|
||||
|
||||
type reorderBuffer struct {
|
||||
rune [maxBufferSize]Properties
|
||||
}
|
||||
|
||||
type Properties struct {
|
||||
pos uint8
|
||||
size uint8
|
||||
}
|
||||
|
||||
func main() {
|
||||
println(len(reorderBuffer{}.rune))
|
||||
}
|
||||
|
||||
// Output:
|
||||
// 32
|
||||
19
_test/const7.go
Normal file
19
_test/const7.go
Normal file
@@ -0,0 +1,19 @@
|
||||
package main
|
||||
|
||||
import "fmt"
|
||||
|
||||
const (
|
||||
a = iota
|
||||
b
|
||||
c
|
||||
d
|
||||
)
|
||||
|
||||
type T [c]int
|
||||
|
||||
func main() {
|
||||
fmt.Println(T{})
|
||||
}
|
||||
|
||||
// Output:
|
||||
// [0 0]
|
||||
9
_test/ct1/ct1.go
Normal file
9
_test/ct1/ct1.go
Normal file
@@ -0,0 +1,9 @@
|
||||
package ct1
|
||||
|
||||
type Class uint
|
||||
|
||||
const (
|
||||
L Class = iota
|
||||
R
|
||||
AL
|
||||
)
|
||||
12
_test/fun11.go
Normal file
12
_test/fun11.go
Normal file
@@ -0,0 +1,12 @@
|
||||
package main
|
||||
|
||||
var f F
|
||||
|
||||
type F func(int)
|
||||
|
||||
func main() {
|
||||
println("ok")
|
||||
}
|
||||
|
||||
// Output:
|
||||
// ok
|
||||
10
_test/import8.go
Normal file
10
_test/import8.go
Normal file
@@ -0,0 +1,10 @@
|
||||
package main
|
||||
|
||||
import "github.com/containous/yaegi/_test/b1/foo"
|
||||
|
||||
func main() {
|
||||
println(foo.Desc)
|
||||
}
|
||||
|
||||
// Output:
|
||||
// in b1/foo
|
||||
12
_test/interface19.go
Normal file
12
_test/interface19.go
Normal file
@@ -0,0 +1,12 @@
|
||||
package main
|
||||
|
||||
import "fmt"
|
||||
|
||||
var I interface{}
|
||||
|
||||
func main() {
|
||||
fmt.Printf("%T %v\n", I, I)
|
||||
}
|
||||
|
||||
// Output:
|
||||
// <nil> <nil>
|
||||
16
_test/map19.go
Normal file
16
_test/map19.go
Normal file
@@ -0,0 +1,16 @@
|
||||
package main
|
||||
|
||||
import "fmt"
|
||||
|
||||
type cmap struct {
|
||||
servers map[int64]*server
|
||||
}
|
||||
|
||||
type server struct {
|
||||
cm *cmap
|
||||
}
|
||||
|
||||
func main() {
|
||||
m := cmap{}
|
||||
fmt.Println(m)
|
||||
}
|
||||
10
_test/map20.go
Normal file
10
_test/map20.go
Normal file
@@ -0,0 +1,10 @@
|
||||
package main
|
||||
|
||||
var a = map[int]bool{1: true, 2: true}
|
||||
|
||||
func main() {
|
||||
println(a[1] && true)
|
||||
}
|
||||
|
||||
// Output:
|
||||
// true
|
||||
16
_test/method29.go
Normal file
16
_test/method29.go
Normal file
@@ -0,0 +1,16 @@
|
||||
package main
|
||||
|
||||
import (
|
||||
"context"
|
||||
"net"
|
||||
)
|
||||
|
||||
var lookupHost = net.DefaultResolver.LookupHost
|
||||
|
||||
func main() {
|
||||
res, err := lookupHost(context.Background(), "localhost")
|
||||
println(len(res) > 0, err == nil)
|
||||
}
|
||||
|
||||
// Output:
|
||||
// true true
|
||||
20
_test/method30.go
Normal file
20
_test/method30.go
Normal file
@@ -0,0 +1,20 @@
|
||||
package main
|
||||
|
||||
type T struct {
|
||||
Name string
|
||||
}
|
||||
|
||||
func (t *T) foo(a string) string {
|
||||
return t.Name + a
|
||||
}
|
||||
|
||||
var g = &T{"global"}
|
||||
|
||||
var f = g.foo
|
||||
|
||||
func main() {
|
||||
println(f("-x"))
|
||||
}
|
||||
|
||||
// Output:
|
||||
// global-x
|
||||
29
_test/method31.go
Normal file
29
_test/method31.go
Normal file
@@ -0,0 +1,29 @@
|
||||
package main
|
||||
|
||||
import "fmt"
|
||||
|
||||
var db dbWrapper
|
||||
|
||||
type dbWrapper struct {
|
||||
DB *cmap
|
||||
}
|
||||
|
||||
func (d *dbWrapper) get() *cmap {
|
||||
return d.DB
|
||||
}
|
||||
|
||||
type cmap struct {
|
||||
name string
|
||||
}
|
||||
|
||||
func (c *cmap) f() {
|
||||
fmt.Println("in f, c", c)
|
||||
}
|
||||
|
||||
func main() {
|
||||
db.DB = &cmap{name: "test"}
|
||||
db.get().f()
|
||||
}
|
||||
|
||||
// Output:
|
||||
// in f, c &{test}
|
||||
10
_test/or2.go
Normal file
10
_test/or2.go
Normal file
@@ -0,0 +1,10 @@
|
||||
package main
|
||||
|
||||
var a = false || true
|
||||
|
||||
func main() {
|
||||
println(a)
|
||||
}
|
||||
|
||||
// Output:
|
||||
// true
|
||||
10
_test/ptr8.go
Normal file
10
_test/ptr8.go
Normal file
@@ -0,0 +1,10 @@
|
||||
package main
|
||||
|
||||
var a = func() *bool { b := true; return &b }()
|
||||
|
||||
func main() {
|
||||
println(*a && true)
|
||||
}
|
||||
|
||||
// Output:
|
||||
// true
|
||||
14
_test/struct31.go
Normal file
14
_test/struct31.go
Normal file
@@ -0,0 +1,14 @@
|
||||
package main
|
||||
|
||||
type T struct {
|
||||
bool
|
||||
}
|
||||
|
||||
var t = T{true}
|
||||
|
||||
func main() {
|
||||
println(t.bool && true)
|
||||
}
|
||||
|
||||
// Output:
|
||||
// true
|
||||
9
_test/type15.go
Normal file
9
_test/type15.go
Normal file
@@ -0,0 +1,9 @@
|
||||
package main
|
||||
|
||||
func main() {
|
||||
err := error(nil)
|
||||
println(err == nil)
|
||||
}
|
||||
|
||||
// Output:
|
||||
// true
|
||||
11
_test/type16.go
Normal file
11
_test/type16.go
Normal file
@@ -0,0 +1,11 @@
|
||||
package main
|
||||
|
||||
import "fmt"
|
||||
|
||||
func main() {
|
||||
a := uint8(15) ^ byte(0)
|
||||
fmt.Printf("%T %v\n", a, a)
|
||||
}
|
||||
|
||||
// Output:
|
||||
// uint8 15
|
||||
11
_test/type17.go
Normal file
11
_test/type17.go
Normal file
@@ -0,0 +1,11 @@
|
||||
package main
|
||||
|
||||
import "fmt"
|
||||
|
||||
func main() {
|
||||
a := int32(15) ^ rune(0)
|
||||
fmt.Printf("%T %v\n", a, a)
|
||||
}
|
||||
|
||||
// Output:
|
||||
// int32 15
|
||||
11
_test/var10.go
Normal file
11
_test/var10.go
Normal file
@@ -0,0 +1,11 @@
|
||||
package main
|
||||
|
||||
var _ = true
|
||||
var _ = "hello"
|
||||
|
||||
func main() {
|
||||
println("hello")
|
||||
}
|
||||
|
||||
// Output:
|
||||
// hello
|
||||
10
_test/var11.go
Normal file
10
_test/var11.go
Normal file
@@ -0,0 +1,10 @@
|
||||
package main
|
||||
|
||||
var a, _, _, b = 1, true, "foo", 2
|
||||
|
||||
func main() {
|
||||
println(a, b)
|
||||
}
|
||||
|
||||
// Output:
|
||||
// 1 2
|
||||
@@ -8,7 +8,7 @@ If invoked with no arguments, it processes the standard input
|
||||
in a Read-Eval-Print-Loop. A prompt is displayed if standard input
|
||||
is a terminal.
|
||||
|
||||
Given a file, it operates on that file. if the first line starts with
|
||||
Given a file, it operates on that file. If the first line starts with
|
||||
"#!/usr/bin/env yaegi", and the file has exec permission, then the file
|
||||
can be invoked directly from the shell.
|
||||
|
||||
|
||||
@@ -75,8 +75,6 @@ const (
|
||||
parenExpr
|
||||
rangeStmt
|
||||
returnStmt
|
||||
rvalueExpr
|
||||
rtypeExpr
|
||||
selectStmt
|
||||
selectorExpr
|
||||
selectorImport
|
||||
@@ -154,8 +152,6 @@ var kinds = [...]string{
|
||||
parenExpr: "parenExpr",
|
||||
rangeStmt: "rangeStmt",
|
||||
returnStmt: "returnStmt",
|
||||
rvalueExpr: "rvalueExpr",
|
||||
rtypeExpr: "rtypeExpr",
|
||||
selectStmt: "selectStmt",
|
||||
selectorExpr: "selectorExpr",
|
||||
selectorImport: "selectorImport",
|
||||
|
||||
@@ -42,8 +42,8 @@ var identifier = regexp.MustCompile(`([\pL_][\pL_\d]*)$`)
|
||||
// and pre-compute frame sizes and indexes for all un-named (temporary) and named
|
||||
// variables. A list of nodes of init functions is returned.
|
||||
// Following this pass, the CFG is ready to run
|
||||
func (interp *Interpreter) cfg(root *node) ([]*node, error) {
|
||||
sc, pkgName := interp.initScopePkg(root)
|
||||
func (interp *Interpreter) cfg(root *node, pkgID string) ([]*node, error) {
|
||||
sc := interp.initScopePkg(pkgID)
|
||||
var initNodes []*node
|
||||
var iotaValue int
|
||||
var err error
|
||||
@@ -231,7 +231,13 @@ func (interp *Interpreter) cfg(root *node) ([]*node, error) {
|
||||
}
|
||||
// Propagate type to children, to handle implicit types
|
||||
for _, c := range n.child {
|
||||
c.typ = n.typ
|
||||
switch c.kind {
|
||||
case binaryExpr, unaryExpr:
|
||||
// Do not attempt to propagate composite type to operator expressions,
|
||||
// it breaks constant folding.
|
||||
default:
|
||||
c.typ = n.typ
|
||||
}
|
||||
}
|
||||
|
||||
case forStmt0, forRangeStmt:
|
||||
@@ -410,7 +416,11 @@ func (interp *Interpreter) cfg(root *node) ([]*node, error) {
|
||||
if src.typ, err = nodeType(interp, sc, src); err != nil {
|
||||
return
|
||||
}
|
||||
dest.typ = src.typ
|
||||
if src.typ.isBinMethod {
|
||||
dest.typ = &itype{cat: valueT, rtype: src.typ.methodCallType()}
|
||||
} else {
|
||||
dest.typ = src.typ
|
||||
}
|
||||
}
|
||||
if dest.typ.sizedef {
|
||||
dest.typ.size = arrayTypeLen(src)
|
||||
@@ -419,7 +429,8 @@ func (interp *Interpreter) cfg(root *node) ([]*node, error) {
|
||||
if sc.global {
|
||||
// Do not overload existing symbols (defined in GTA) in global scope
|
||||
sym, _, _ = sc.lookup(dest.ident)
|
||||
} else {
|
||||
}
|
||||
if sym == nil {
|
||||
sym = &symbol{index: sc.add(dest.typ), kind: varSym, typ: dest.typ}
|
||||
sc.sym[dest.ident] = sym
|
||||
}
|
||||
@@ -499,9 +510,10 @@ func (interp *Interpreter) cfg(root *node) ([]*node, error) {
|
||||
if isMapEntry(dest) {
|
||||
dest.gen = nop // skip getIndexMap
|
||||
}
|
||||
}
|
||||
if n.anc.kind == constDecl {
|
||||
iotaValue++
|
||||
if n.anc.kind == constDecl {
|
||||
sc.sym[dest.ident].kind = constSym
|
||||
iotaValue++
|
||||
}
|
||||
}
|
||||
|
||||
case incDecStmt:
|
||||
@@ -739,7 +751,7 @@ func (interp *Interpreter) cfg(root *node) ([]*node, error) {
|
||||
if isInt(n.child[0].typ.TypeOf()) && n.child[1].kind == basicLit && isFloat(n.child[1].typ.TypeOf()) {
|
||||
err = n.cfgErrorf("truncated to integer")
|
||||
}
|
||||
if isInterface(n.child[0].typ) {
|
||||
if isInterface(n.child[0].typ) && !n.child[1].isNil() {
|
||||
// Convert to interface: just check that all required methods are defined by concrete type.
|
||||
c0, c1 := n.child[0], n.child[1]
|
||||
if !c1.typ.implements(c0.typ) {
|
||||
@@ -897,10 +909,10 @@ func (interp *Interpreter) cfg(root *node) ([]*node, error) {
|
||||
sc = sc.pop()
|
||||
funcName := n.child[1].ident
|
||||
if !isMethod(n) {
|
||||
interp.scopes[pkgName].sym[funcName].index = -1 // to force value to n.val
|
||||
interp.scopes[pkgName].sym[funcName].typ = n.typ
|
||||
interp.scopes[pkgName].sym[funcName].kind = funcSym
|
||||
interp.scopes[pkgName].sym[funcName].node = n
|
||||
interp.scopes[pkgID].sym[funcName].index = -1 // to force value to n.val
|
||||
interp.scopes[pkgID].sym[funcName].typ = n.typ
|
||||
interp.scopes[pkgID].sym[funcName].kind = funcSym
|
||||
interp.scopes[pkgID].sym[funcName].node = n
|
||||
}
|
||||
|
||||
case funcLit:
|
||||
@@ -914,7 +926,8 @@ func (interp *Interpreter) cfg(root *node) ([]*node, error) {
|
||||
case identExpr:
|
||||
if isKey(n) || isNewDefine(n, sc) {
|
||||
break
|
||||
} else if sym, level, ok := sc.lookup(n.ident); ok {
|
||||
}
|
||||
if sym, level, ok := sc.lookup(n.ident); ok {
|
||||
// Found symbol, populate node info
|
||||
n.typ, n.findex, n.level = sym.typ, sym.index, level
|
||||
if n.findex < 0 {
|
||||
@@ -931,11 +944,6 @@ func (interp *Interpreter) cfg(root *node) ([]*node, error) {
|
||||
case n.ident == "nil":
|
||||
n.kind = basicLit
|
||||
case sym.kind == binSym:
|
||||
if sym.rval.IsValid() {
|
||||
n.kind = rvalueExpr
|
||||
} else {
|
||||
n.kind = rtypeExpr
|
||||
}
|
||||
n.typ = sym.typ
|
||||
n.rval = sym.rval
|
||||
case sym.kind == bltnSym:
|
||||
@@ -1097,7 +1105,7 @@ func (interp *Interpreter) cfg(root *node) ([]*node, error) {
|
||||
n.val = method.Index
|
||||
n.gen = getIndexBinMethod
|
||||
n.recv = &receiver{node: n.child[0]}
|
||||
n.typ = &itype{cat: valueT, rtype: method.Type}
|
||||
n.typ = &itype{cat: valueT, rtype: method.Type, isBinMethod: true}
|
||||
case n.typ.rtype.Kind() == reflect.Ptr:
|
||||
if field, ok := n.typ.rtype.Elem().FieldByName(n.child[1].ident); ok {
|
||||
n.typ = &itype{cat: valueT, rtype: field.Type}
|
||||
@@ -1151,10 +1159,8 @@ func (interp *Interpreter) cfg(root *node) ([]*node, error) {
|
||||
pkg := n.child[0].sym.typ.path
|
||||
if s, ok := interp.binPkg[pkg][name]; ok {
|
||||
if isBinType(s) {
|
||||
n.kind = rtypeExpr
|
||||
n.typ = &itype{cat: valueT, rtype: s.Type().Elem()}
|
||||
} else {
|
||||
n.kind = rvalueExpr
|
||||
n.typ = &itype{cat: valueT, rtype: s.Type(), untyped: isValueUntyped(s)}
|
||||
n.rval = s
|
||||
}
|
||||
@@ -1171,6 +1177,7 @@ func (interp *Interpreter) cfg(root *node) ([]*node, error) {
|
||||
n.gen = nop
|
||||
n.typ = sym.typ
|
||||
n.sym = sym
|
||||
n.rval = sym.rval
|
||||
} else {
|
||||
err = n.cfgErrorf("undefined selector: %s.%s", pkg, name)
|
||||
}
|
||||
@@ -1439,8 +1446,14 @@ func (interp *Interpreter) cfg(root *node) ([]*node, error) {
|
||||
}
|
||||
}
|
||||
for _, c := range n.child[:l] {
|
||||
index := sc.add(n.typ)
|
||||
sc.sym[c.ident] = &symbol{index: index, kind: varSym, typ: n.typ}
|
||||
var index int
|
||||
if sc.global {
|
||||
// Global object allocation is already performed in GTA.
|
||||
index = sc.sym[c.ident].index
|
||||
} else {
|
||||
index = sc.add(n.typ)
|
||||
sc.sym[c.ident] = &symbol{index: index, kind: varSym, typ: n.typ}
|
||||
}
|
||||
c.typ = n.typ
|
||||
c.findex = index
|
||||
}
|
||||
@@ -1570,7 +1583,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, interfaceType, mapType, structType, rtypeExpr:
|
||||
case arrayType, chanType, funcType, interfaceType, mapType, structType:
|
||||
return true
|
||||
case parenExpr, starExpr:
|
||||
if len(n.child) == 1 {
|
||||
@@ -1685,6 +1698,9 @@ func (n *node) isNatural() bool {
|
||||
return false
|
||||
}
|
||||
|
||||
// isNil returns true if node is a literal nil value, false otherwise
|
||||
func (n *node) isNil() bool { return n.kind == basicLit && !n.rval.IsValid() }
|
||||
|
||||
// fieldType returns the nth parameter field node (type) of a fieldList node
|
||||
func (n *node) fieldType(m int) *node {
|
||||
k := 0
|
||||
@@ -1783,13 +1799,6 @@ func getExec(n *node) bltn {
|
||||
return n.exec
|
||||
}
|
||||
|
||||
func fileNode(n *node) *node {
|
||||
if n == nil || n.kind == fileStmt {
|
||||
return n
|
||||
}
|
||||
return fileNode(n.anc)
|
||||
}
|
||||
|
||||
// setExec recursively sets the node exec builtin function by walking the CFG
|
||||
// from the entry point (first node to exec).
|
||||
func setExec(n *node) {
|
||||
|
||||
@@ -8,8 +8,8 @@ import (
|
||||
// variables and functions symbols at package level, prior to CFG.
|
||||
// All function bodies are skipped. GTA is necessary to handle out of
|
||||
// order declarations and multiple source files packages.
|
||||
func (interp *Interpreter) gta(root *node, rpath string) ([]*node, error) {
|
||||
sc, _ := interp.initScopePkg(root)
|
||||
func (interp *Interpreter) gta(root *node, rpath, pkgID string) ([]*node, error) {
|
||||
sc := interp.initScopePkg(pkgID)
|
||||
var err error
|
||||
var iotaValue int
|
||||
var revisit []*node
|
||||
@@ -21,6 +21,9 @@ func (interp *Interpreter) gta(root *node, rpath string) ([]*node, error) {
|
||||
switch n.kind {
|
||||
case constDecl:
|
||||
iotaValue = 0
|
||||
// Early parse of constDecl subtree, to compute all constant
|
||||
// values which may be necessary in further declarations.
|
||||
_, err = interp.cfg(n, pkgID)
|
||||
|
||||
case blockStmt:
|
||||
if n != root {
|
||||
@@ -52,7 +55,7 @@ func (interp *Interpreter) gta(root *node, rpath string) ([]*node, error) {
|
||||
val = src.rval
|
||||
}
|
||||
if typ.incomplete {
|
||||
// Come back when type is known
|
||||
// Come back when type is known.
|
||||
revisit = append(revisit, n)
|
||||
return false
|
||||
}
|
||||
@@ -60,7 +63,12 @@ func (interp *Interpreter) gta(root *node, rpath string) ([]*node, error) {
|
||||
err = n.cfgErrorf("use of untyped nil")
|
||||
return false
|
||||
}
|
||||
sc.sym[dest.ident] = &symbol{kind: varSym, global: true, index: sc.add(typ), typ: typ, rval: val}
|
||||
if typ.isBinMethod {
|
||||
typ = &itype{cat: valueT, rtype: typ.methodCallType(), isBinMethod: true}
|
||||
}
|
||||
if sc.sym[dest.ident] == nil {
|
||||
sc.sym[dest.ident] = &symbol{kind: varSym, global: true, index: sc.add(typ), typ: typ, rval: val}
|
||||
}
|
||||
if n.anc.kind == constDecl {
|
||||
sc.sym[dest.ident].kind = constSym
|
||||
iotaValue++
|
||||
@@ -77,6 +85,11 @@ func (interp *Interpreter) gta(root *node, rpath string) ([]*node, error) {
|
||||
if n.typ, err = nodeType(interp, sc, n.child[l]); err != nil {
|
||||
return false
|
||||
}
|
||||
if n.typ.incomplete {
|
||||
// Come back when type is known.
|
||||
revisit = append(revisit, n)
|
||||
return false
|
||||
}
|
||||
}
|
||||
for _, c := range n.child[:l] {
|
||||
sc.sym[c.ident] = &symbol{index: sc.add(n.typ), kind: varSym, global: true, typ: n.typ}
|
||||
@@ -117,6 +130,9 @@ func (interp *Interpreter) gta(root *node, rpath string) ([]*node, error) {
|
||||
// Add a function symbol in the package name space
|
||||
sc.sym[n.child[1].ident] = &symbol{kind: funcSym, typ: n.typ, node: n, index: -1}
|
||||
}
|
||||
if n.typ.incomplete {
|
||||
revisit = append(revisit, n)
|
||||
}
|
||||
return false
|
||||
|
||||
case importSpec:
|
||||
@@ -143,7 +159,7 @@ 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: binPkgT, path: ipath}}
|
||||
}
|
||||
} else if err = interp.importSrc(rpath, ipath, name); err == nil {
|
||||
} else if err = interp.importSrc(rpath, ipath); err == nil {
|
||||
sc.types = interp.universe.types
|
||||
switch name {
|
||||
case "_": // no import of symbols
|
||||
|
||||
@@ -216,7 +216,7 @@ func initUniverse() *scope {
|
||||
sc := &scope{global: true, sym: map[string]*symbol{
|
||||
// predefined Go types
|
||||
"bool": {kind: typeSym, typ: &itype{cat: boolT, name: "bool"}},
|
||||
"byte": {kind: typeSym, typ: &itype{cat: byteT, name: "byte"}},
|
||||
"byte": {kind: typeSym, typ: &itype{cat: uint8T, name: "uint8"}},
|
||||
"complex64": {kind: typeSym, typ: &itype{cat: complex64T, name: "complex64"}},
|
||||
"complex128": {kind: typeSym, typ: &itype{cat: complex128T, name: "complex128"}},
|
||||
"error": {kind: typeSym, typ: &itype{cat: errorT, name: "error"}},
|
||||
@@ -228,7 +228,7 @@ func initUniverse() *scope {
|
||||
"int32": {kind: typeSym, typ: &itype{cat: int32T, name: "int32"}},
|
||||
"int64": {kind: typeSym, typ: &itype{cat: int64T, name: "int64"}},
|
||||
"interface{}": {kind: typeSym, typ: &itype{cat: interfaceT}},
|
||||
"rune": {kind: typeSym, typ: &itype{cat: runeT, name: "rune"}},
|
||||
"rune": {kind: typeSym, typ: &itype{cat: int32T, name: "int32"}},
|
||||
"string": {kind: typeSym, typ: &itype{cat: stringT, name: "string"}},
|
||||
"uint": {kind: typeSym, typ: &itype{cat: uintT, name: "uint"}},
|
||||
"uint8": {kind: typeSym, typ: &itype{cat: uint8T, name: "uint8"}},
|
||||
@@ -283,7 +283,7 @@ func (interp *Interpreter) resizeFrame() {
|
||||
func (interp *Interpreter) main() *node {
|
||||
interp.mutex.RLock()
|
||||
defer interp.mutex.RUnlock()
|
||||
if m, ok := interp.scopes[mainID]; ok && m.sym[mainID] != nil {
|
||||
if m, ok := interp.scopes[interp.Name]; ok && m.sym[mainID] != nil {
|
||||
return m.sym[mainID].node
|
||||
}
|
||||
return nil
|
||||
@@ -308,18 +308,18 @@ func (interp *Interpreter) Eval(src string) (reflect.Value, error) {
|
||||
}
|
||||
|
||||
// Global type analysis
|
||||
revisit, err := interp.gta(root, pkgName)
|
||||
revisit, err := interp.gta(root, pkgName, interp.Name)
|
||||
if err != nil {
|
||||
return res, err
|
||||
}
|
||||
for _, n := range revisit {
|
||||
if _, err = interp.gta(n, pkgName); err != nil {
|
||||
if _, err = interp.gta(n, pkgName, interp.Name); err != nil {
|
||||
return res, err
|
||||
}
|
||||
}
|
||||
|
||||
// Annotate AST with CFG infos
|
||||
initNodes, err := interp.cfg(root)
|
||||
initNodes, err := interp.cfg(root, interp.Name)
|
||||
if err != nil {
|
||||
return res, err
|
||||
}
|
||||
@@ -336,7 +336,7 @@ func (interp *Interpreter) Eval(src string) (reflect.Value, error) {
|
||||
interp.mutex.Lock()
|
||||
if interp.universe.sym[pkgName] == nil {
|
||||
// Make the package visible under a path identical to its name
|
||||
interp.srcPkg[pkgName] = interp.scopes[pkgName].sym
|
||||
interp.srcPkg[pkgName] = interp.scopes[interp.Name].sym
|
||||
interp.universe.sym[pkgName] = &symbol{kind: pkgSym, typ: &itype{cat: srcPkgT, path: pkgName}}
|
||||
}
|
||||
interp.mutex.Unlock()
|
||||
|
||||
@@ -78,11 +78,11 @@ func TestEvalBuiltin(t *testing.T) {
|
||||
i := interp.New(interp.Options{})
|
||||
runTests(t, i, []testCase{
|
||||
{src: `a := []int{}; a = append(a, 1); a`, res: "[1]"},
|
||||
{src: `a := []int{1}; a = append(a, 2, 3); a`, res: "[1 2 3]"},
|
||||
{src: `a := []int{1}; b := []int{2, 3}; a = append(a, b...); a`, res: "[1 2 3]"},
|
||||
{src: `b := []int{1}; b = append(a, 2, 3); b`, res: "[1 2 3]"},
|
||||
{src: `c := []int{1}; d := []int{2, 3}; c = append(c, d...); c`, res: "[1 2 3]"},
|
||||
{src: `string(append([]byte("hello "), "world"...))`, res: "hello world"},
|
||||
{src: `a := "world"; string(append([]byte("hello "), a...))`, res: "hello world"},
|
||||
{src: `a := []byte("Hello"); copy(a, "world"); string(a)`, res: "world"},
|
||||
{src: `e := "world"; string(append([]byte("hello "), e...))`, res: "hello world"},
|
||||
{src: `f := []byte("Hello"); copy(f, "world"); string(f)`, res: "world"},
|
||||
})
|
||||
}
|
||||
|
||||
|
||||
118
interp/run.go
118
interp/run.go
@@ -216,7 +216,7 @@ func convert(n *node) {
|
||||
typ := n.child[0].typ.TypeOf()
|
||||
next := getExec(n.tnext)
|
||||
|
||||
if c.kind == basicLit && !c.rval.IsValid() { // convert nil to type
|
||||
if c.isNil() { // convert nil to type
|
||||
n.exec = func(f *frame) bltn {
|
||||
dest(f).Set(reflect.New(typ).Elem())
|
||||
return next
|
||||
@@ -293,12 +293,17 @@ func assign(n *node) {
|
||||
}
|
||||
|
||||
if n.nleft == 1 {
|
||||
if s, d, i := svalue[0], dvalue[0], ivalue[0]; i != nil {
|
||||
switch s, d, i := svalue[0], dvalue[0], ivalue[0]; {
|
||||
case n.child[0].ident == "_":
|
||||
n.exec = func(f *frame) bltn {
|
||||
return next
|
||||
}
|
||||
case i != nil:
|
||||
n.exec = func(f *frame) bltn {
|
||||
d(f).SetMapIndex(i(f), s(f))
|
||||
return next
|
||||
}
|
||||
} else {
|
||||
default:
|
||||
n.exec = func(f *frame) bltn {
|
||||
d(f).Set(s(f))
|
||||
return next
|
||||
@@ -316,7 +321,6 @@ func assign(n *node) {
|
||||
default:
|
||||
t = typ.TypeOf()
|
||||
}
|
||||
//types[i] = n.child[sbase+i].typ.TypeOf()
|
||||
types[i] = t
|
||||
}
|
||||
|
||||
@@ -326,10 +330,16 @@ func assign(n *node) {
|
||||
n.exec = func(f *frame) bltn {
|
||||
t := make([]reflect.Value, len(svalue))
|
||||
for i, s := range svalue {
|
||||
if n.child[i].ident == "_" {
|
||||
continue
|
||||
}
|
||||
t[i] = reflect.New(types[i]).Elem()
|
||||
t[i].Set(s(f))
|
||||
}
|
||||
for i, d := range dvalue {
|
||||
if n.child[i].ident == "_" {
|
||||
continue
|
||||
}
|
||||
if j := ivalue[i]; j != nil {
|
||||
d(f).SetMapIndex(j(f), t[i]) // Assign a map entry
|
||||
} else {
|
||||
@@ -345,16 +355,15 @@ 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)
|
||||
dest(f).SetBool(true)
|
||||
return tnext
|
||||
}
|
||||
f.data[i].SetBool(false)
|
||||
dest(f).SetBool(false)
|
||||
return fnext
|
||||
}
|
||||
} else {
|
||||
@@ -379,17 +388,18 @@ func addr(n *node) {
|
||||
func deref(n *node) {
|
||||
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).Elem().Bool() {
|
||||
f.data[i] = value(f).Elem()
|
||||
if f.data[i].Bool() {
|
||||
return tnext
|
||||
}
|
||||
return fnext
|
||||
}
|
||||
} else {
|
||||
i := n.findex
|
||||
n.exec = func(f *frame) bltn {
|
||||
f.data[i] = value(f).Elem()
|
||||
return tnext
|
||||
@@ -828,7 +838,9 @@ func callBin(n *node) {
|
||||
// method signature obtained from reflect.Type include receiver as 1st arg, except for interface types
|
||||
rcvrOffset := 0
|
||||
if recv := n.child[0].recv; recv != nil && recv.node.typ.TypeOf().Kind() != reflect.Interface {
|
||||
rcvrOffset = 1
|
||||
if funcType.NumIn() > len(child) {
|
||||
rcvrOffset = 1
|
||||
}
|
||||
}
|
||||
|
||||
for i, c := range child {
|
||||
@@ -867,7 +879,6 @@ func callBin(n *node) {
|
||||
case interfaceT:
|
||||
values = append(values, genValueInterfaceValue(c))
|
||||
default:
|
||||
//values = append(values, genValue(c))
|
||||
values = append(values, genInterfaceWrapper(c, defType))
|
||||
}
|
||||
}
|
||||
@@ -967,21 +978,21 @@ func getIndexBinPtrMethod(n *node) {
|
||||
func getIndexArray(n *node) {
|
||||
tnext := getExec(n.tnext)
|
||||
value0 := genValueArray(n.child[0]) // array
|
||||
i := n.findex
|
||||
|
||||
if n.child[1].rval.IsValid() { // constant array index
|
||||
ai := int(vInt(n.child[1].rval))
|
||||
if n.fnext != nil {
|
||||
fnext := getExec(n.fnext)
|
||||
n.exec = func(f *frame) bltn {
|
||||
if value0(f).Index(ai).Bool() {
|
||||
f.data[i] = value0(f).Index(ai)
|
||||
if f.data[i].Bool() {
|
||||
return tnext
|
||||
}
|
||||
return fnext
|
||||
}
|
||||
} else {
|
||||
i := n.findex
|
||||
n.exec = func(f *frame) bltn {
|
||||
// Can not use .Set due to constraint of being able to assign an array element
|
||||
f.data[i] = value0(f).Index(ai)
|
||||
return tnext
|
||||
}
|
||||
@@ -993,16 +1004,15 @@ func getIndexArray(n *node) {
|
||||
fnext := getExec(n.fnext)
|
||||
n.exec = func(f *frame) bltn {
|
||||
_, vi := value1(f)
|
||||
if value0(f).Index(int(vi)).Bool() {
|
||||
f.data[i] = value0(f).Index(int(vi))
|
||||
if f.data[i].Bool() {
|
||||
return tnext
|
||||
}
|
||||
return fnext
|
||||
}
|
||||
} else {
|
||||
i := n.findex
|
||||
n.exec = func(f *frame) bltn {
|
||||
_, vi := value1(f)
|
||||
// Can not use .Set due to constraint of being able to assign an array element
|
||||
f.data[i] = value0(f).Index(int(vi))
|
||||
return tnext
|
||||
}
|
||||
@@ -1024,8 +1034,10 @@ func getIndexMap(n *node) {
|
||||
fnext := getExec(n.fnext)
|
||||
n.exec = func(f *frame) bltn {
|
||||
if v := value0(f).MapIndex(mi); v.IsValid() && v.Bool() {
|
||||
dest(f).SetBool(true)
|
||||
return tnext
|
||||
}
|
||||
dest(f).Set(z)
|
||||
return fnext
|
||||
}
|
||||
} else {
|
||||
@@ -1045,8 +1057,10 @@ func getIndexMap(n *node) {
|
||||
fnext := getExec(n.fnext)
|
||||
n.exec = func(f *frame) bltn {
|
||||
if v := value0(f).MapIndex(value1(f)); v.IsValid() && v.Bool() {
|
||||
dest(f).SetBool(true)
|
||||
return tnext
|
||||
}
|
||||
dest(f).Set(z)
|
||||
return fnext
|
||||
}
|
||||
} else {
|
||||
@@ -1144,17 +1158,28 @@ func getIndexSeq(n *node) {
|
||||
value := genValue(n.child[0])
|
||||
index := n.val.([]int)
|
||||
tnext := getExec(n.tnext)
|
||||
i := n.findex
|
||||
|
||||
// Note:
|
||||
// Here we have to store the result using
|
||||
// f.data[i] = value(...)
|
||||
// instead of normal
|
||||
// dest(f).Set(value(...)
|
||||
// because the value returned by FieldByIndex() must be preserved
|
||||
// for possible future Set operations on the struct field (avoid a
|
||||
// dereference from Set, resulting in setting a copy of the
|
||||
// original field).
|
||||
|
||||
if n.fnext != nil {
|
||||
fnext := getExec(n.fnext)
|
||||
n.exec = func(f *frame) bltn {
|
||||
if value(f).FieldByIndex(index).Bool() {
|
||||
f.data[i] = value(f).FieldByIndex(index)
|
||||
if f.data[i].Bool() {
|
||||
return tnext
|
||||
}
|
||||
return fnext
|
||||
}
|
||||
} else {
|
||||
i := n.findex
|
||||
n.exec = func(f *frame) bltn {
|
||||
f.data[i] = value(f).FieldByIndex(index)
|
||||
return tnext
|
||||
@@ -1172,17 +1197,18 @@ func getPtrIndexSeq(n *node) {
|
||||
} else {
|
||||
value = genValue(n.child[0])
|
||||
}
|
||||
i := n.findex
|
||||
|
||||
if n.fnext != nil {
|
||||
fnext := getExec(n.fnext)
|
||||
n.exec = func(f *frame) bltn {
|
||||
if value(f).Elem().FieldByIndex(index).Bool() {
|
||||
f.data[i] = value(f).Elem().FieldByIndex(index)
|
||||
if f.data[i].Bool() {
|
||||
return tnext
|
||||
}
|
||||
return fnext
|
||||
}
|
||||
} else {
|
||||
i := n.findex
|
||||
n.exec = func(f *frame) bltn {
|
||||
f.data[i] = value(f).Elem().FieldByIndex(index)
|
||||
return tnext
|
||||
@@ -1194,17 +1220,38 @@ func getIndexSeqField(n *node) {
|
||||
value := genValue(n.child[0])
|
||||
index := n.val.([]int)
|
||||
i := n.findex
|
||||
next := getExec(n.tnext)
|
||||
tnext := 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(index)
|
||||
return next
|
||||
if n.fnext != nil {
|
||||
fnext := getExec(n.fnext)
|
||||
if n.child[0].typ.TypeOf().Kind() == reflect.Ptr {
|
||||
n.exec = func(f *frame) bltn {
|
||||
f.data[i] = value(f).Elem().FieldByIndex(index)
|
||||
if f.data[i].Bool() {
|
||||
return tnext
|
||||
}
|
||||
return fnext
|
||||
}
|
||||
} else {
|
||||
n.exec = func(f *frame) bltn {
|
||||
f.data[i] = value(f).FieldByIndex(index)
|
||||
if f.data[i].Bool() {
|
||||
return tnext
|
||||
}
|
||||
return fnext
|
||||
}
|
||||
}
|
||||
} else {
|
||||
n.exec = func(f *frame) bltn {
|
||||
f.data[i] = value(f).FieldByIndex(index)
|
||||
return next
|
||||
if n.child[0].typ.TypeOf().Kind() == reflect.Ptr {
|
||||
n.exec = func(f *frame) bltn {
|
||||
f.data[i] = value(f).Elem().FieldByIndex(index)
|
||||
return tnext
|
||||
}
|
||||
} else {
|
||||
n.exec = func(f *frame) bltn {
|
||||
f.data[i] = value(f).FieldByIndex(index)
|
||||
return tnext
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -1450,7 +1497,7 @@ func arrayLit(n *node) {
|
||||
if c.kind == keyValueExpr {
|
||||
convertLiteralValue(c.child[1], rtype)
|
||||
values[i] = genValue(c.child[1])
|
||||
index[i] = int(c.child[0].rval.Int())
|
||||
index[i] = int(vInt(c.child[0].rval))
|
||||
} else {
|
||||
convertLiteralValue(c, rtype)
|
||||
values[i] = genValue(c)
|
||||
@@ -2159,16 +2206,18 @@ func reset(n *node) {
|
||||
func recv(n *node) {
|
||||
value := genValue(n.child[0])
|
||||
tnext := getExec(n.tnext)
|
||||
i := n.findex
|
||||
|
||||
if n.interp.cancelChan {
|
||||
// Cancellable channel read
|
||||
if n.fnext != nil {
|
||||
fnext := getExec(n.fnext)
|
||||
n.exec = func(f *frame) bltn {
|
||||
ch := value(f)
|
||||
// Fast: channel read doesn't block
|
||||
if x, ok := ch.TryRecv(); ok {
|
||||
if x.Bool() {
|
||||
var ok bool
|
||||
ch := value(f)
|
||||
if f.data[i], ok = ch.TryRecv(); ok {
|
||||
if f.data[i].Bool() {
|
||||
return tnext
|
||||
}
|
||||
return fnext
|
||||
@@ -2184,7 +2233,6 @@ func recv(n *node) {
|
||||
return fnext
|
||||
}
|
||||
} else {
|
||||
i := n.findex
|
||||
n.exec = func(f *frame) bltn {
|
||||
// Fast: channel read doesn't block
|
||||
var ok bool
|
||||
@@ -2206,7 +2254,7 @@ func recv(n *node) {
|
||||
if n.fnext != nil {
|
||||
fnext := getExec(n.fnext)
|
||||
n.exec = func(f *frame) bltn {
|
||||
if v, _ := value(f).Recv(); v.Bool() {
|
||||
if f.data[i], _ = value(f).Recv(); f.data[i].Bool() {
|
||||
return tnext
|
||||
}
|
||||
return fnext
|
||||
|
||||
@@ -78,6 +78,7 @@ type scope struct {
|
||||
def *node // function definition node this scope belongs to, or nil
|
||||
loop *node // loop exit node for break statement
|
||||
loopRestart *node // loop restart node for continue statement
|
||||
pkgID string // unique id of package in which scope is defined
|
||||
types []reflect.Type // Frame layout, may be shared by same level scopes
|
||||
level int // Frame level: number of frame indirections to access var during execution
|
||||
sym map[string]*symbol // Map of symbols defined in this current scope
|
||||
@@ -97,8 +98,8 @@ func (s *scope) push(indirect bool) *scope {
|
||||
sc.global = s.global
|
||||
sc.level = s.level
|
||||
}
|
||||
// inherit loop state from ancestor
|
||||
sc.loop, sc.loopRestart = s.loop, s.loopRestart
|
||||
// inherit loop state and pkgID from ancestor
|
||||
sc.loop, sc.loopRestart, sc.pkgID = s.loop, s.loopRestart, s.pkgID
|
||||
return &sc
|
||||
}
|
||||
|
||||
@@ -160,19 +161,15 @@ func (s *scope) add(typ *itype) (index int) {
|
||||
return
|
||||
}
|
||||
|
||||
func (interp *Interpreter) initScopePkg(n *node) (*scope, string) {
|
||||
func (interp *Interpreter) initScopePkg(pkgID string) *scope {
|
||||
sc := interp.universe
|
||||
pkgName := mainID
|
||||
|
||||
if p := fileNode(n); p != nil {
|
||||
pkgName = p.child[0].ident
|
||||
}
|
||||
|
||||
interp.mutex.Lock()
|
||||
if _, ok := interp.scopes[pkgName]; !ok {
|
||||
interp.scopes[pkgName] = sc.pushBloc()
|
||||
if _, ok := interp.scopes[pkgID]; !ok {
|
||||
interp.scopes[pkgID] = sc.pushBloc()
|
||||
}
|
||||
sc = interp.scopes[pkgName]
|
||||
sc = interp.scopes[pkgID]
|
||||
sc.pkgID = pkgID
|
||||
interp.mutex.Unlock()
|
||||
return sc, pkgName
|
||||
return sc
|
||||
}
|
||||
|
||||
@@ -8,7 +8,7 @@ import (
|
||||
"strings"
|
||||
)
|
||||
|
||||
func (interp *Interpreter) importSrc(rPath, path, alias string) error {
|
||||
func (interp *Interpreter) importSrc(rPath, path string) error {
|
||||
var dir string
|
||||
var err error
|
||||
|
||||
@@ -29,6 +29,7 @@ func (interp *Interpreter) importSrc(rPath, path, alias string) error {
|
||||
} else if dir, rPath, err = pkgDir(interp.context.GOPATH, rPath, path); err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
if interp.rdir[path] {
|
||||
return fmt.Errorf("import cycle not allowed\n\timports %s", path)
|
||||
}
|
||||
@@ -66,6 +67,9 @@ func (interp *Interpreter) importSrc(rPath, path, alias string) error {
|
||||
if root == nil {
|
||||
continue
|
||||
}
|
||||
if interp.astDot {
|
||||
root.astDot(dotX(), name)
|
||||
}
|
||||
if pkgName == "" {
|
||||
pkgName = pname
|
||||
} else if pkgName != pname {
|
||||
@@ -75,7 +79,7 @@ func (interp *Interpreter) importSrc(rPath, path, alias string) error {
|
||||
|
||||
subRPath := effectivePkg(rPath, path)
|
||||
var list []*node
|
||||
list, err = interp.gta(root, subRPath)
|
||||
list, err = interp.gta(root, subRPath, path)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
@@ -85,7 +89,7 @@ func (interp *Interpreter) importSrc(rPath, path, alias string) error {
|
||||
// revisit incomplete nodes where GTA could not complete
|
||||
for pkg, nodes := range revisit {
|
||||
for _, n := range nodes {
|
||||
if _, err = interp.gta(n, pkg); err != nil {
|
||||
if _, err = interp.gta(n, pkg, path); err != nil {
|
||||
return err
|
||||
}
|
||||
}
|
||||
@@ -94,7 +98,7 @@ func (interp *Interpreter) importSrc(rPath, path, alias string) error {
|
||||
// Generate control flow graphs
|
||||
for _, root := range rootNodes {
|
||||
var nodes []*node
|
||||
if nodes, err = interp.cfg(root); err != nil {
|
||||
if nodes, err = interp.cfg(root, path); err != nil {
|
||||
return err
|
||||
}
|
||||
initNodes = append(initNodes, nodes...)
|
||||
@@ -103,13 +107,7 @@ func (interp *Interpreter) importSrc(rPath, path, alias string) error {
|
||||
// Register source package in the interpreter. The package contains only
|
||||
// the global symbols in the package scope.
|
||||
interp.mutex.Lock()
|
||||
interp.srcPkg[path] = interp.scopes[pkgName].sym
|
||||
|
||||
// Rename imported pkgName to alias if they are different
|
||||
if pkgName != alias {
|
||||
interp.scopes[alias] = interp.scopes[pkgName]
|
||||
delete(interp.scopes, pkgName)
|
||||
}
|
||||
interp.srcPkg[path] = interp.scopes[path].sym
|
||||
|
||||
interp.frame.mutex.Lock()
|
||||
interp.resizeFrame()
|
||||
@@ -189,7 +187,7 @@ func effectivePkg(root, path string) string {
|
||||
for i := 0; i < len(splitPath); i++ {
|
||||
part := splitPath[len(splitPath)-1-i]
|
||||
|
||||
if part == splitRoot[len(splitRoot)-1-rootIndex] {
|
||||
if part == splitRoot[len(splitRoot)-1-rootIndex] && i != 0 {
|
||||
prevRootIndex = rootIndex
|
||||
rootIndex++
|
||||
} else if prevRootIndex == rootIndex {
|
||||
|
||||
@@ -17,7 +17,6 @@ const (
|
||||
binPkgT
|
||||
boolT
|
||||
builtinT
|
||||
byteT
|
||||
chanT
|
||||
complex64T
|
||||
complex128T
|
||||
@@ -33,7 +32,6 @@ const (
|
||||
int64T
|
||||
mapT
|
||||
ptrT
|
||||
runeT
|
||||
srcPkgT
|
||||
stringT
|
||||
structT
|
||||
@@ -54,7 +52,6 @@ var cats = [...]string{
|
||||
arrayT: "arrayT",
|
||||
binT: "binT",
|
||||
binPkgT: "binPkgT",
|
||||
byteT: "byteT",
|
||||
boolT: "boolT",
|
||||
builtinT: "builtinT",
|
||||
chanT: "chanT",
|
||||
@@ -72,7 +69,6 @@ var cats = [...]string{
|
||||
int64T: "int64T",
|
||||
mapT: "mapT",
|
||||
ptrT: "ptrT",
|
||||
runeT: "runeT",
|
||||
srcPkgT: "srcPkgT",
|
||||
stringT: "stringT",
|
||||
structT: "structT",
|
||||
@@ -103,22 +99,23 @@ type structField struct {
|
||||
|
||||
// itype defines the internal representation of types in the interpreter
|
||||
type itype struct {
|
||||
cat tcat // Type category
|
||||
field []structField // Array of struct fields if structT or interfaceT
|
||||
key *itype // Type of key element if MapT or nil
|
||||
val *itype // Type of value element if chanT, mapT, ptrT, aliasT, arrayT or variadicT
|
||||
arg []*itype // Argument types if funcT or nil
|
||||
ret []*itype // Return types if funcT or nil
|
||||
method []*node // Associated methods or nil
|
||||
name string // name of type within its package for a defined type
|
||||
path string // for a defined type, the package import path
|
||||
size int // Size of array if ArrayT
|
||||
rtype reflect.Type // Reflection type if ValueT, or nil
|
||||
incomplete bool // true if type must be parsed again (out of order declarations)
|
||||
untyped bool // true for a literal value (string or number)
|
||||
sizedef bool // true if array size is computed from type definition
|
||||
node *node // root AST node of type definition
|
||||
scope *scope // type declaration scope (in case of re-parse incomplete type)
|
||||
cat tcat // Type category
|
||||
field []structField // Array of struct fields if structT or interfaceT
|
||||
key *itype // Type of key element if MapT or nil
|
||||
val *itype // Type of value element if chanT, mapT, ptrT, aliasT, arrayT or variadicT
|
||||
arg []*itype // Argument types if funcT or nil
|
||||
ret []*itype // Return types if funcT or nil
|
||||
method []*node // Associated methods or nil
|
||||
name string // name of type within its package for a defined type
|
||||
path string // for a defined type, the package import path
|
||||
size int // Size of array if ArrayT
|
||||
rtype reflect.Type // Reflection type if ValueT, or nil
|
||||
incomplete bool // true if type must be parsed again (out of order declarations)
|
||||
untyped bool // true for a literal value (string or number)
|
||||
sizedef bool // true if array size is computed from type definition
|
||||
isBinMethod bool // true if the type refers to a bin method function
|
||||
node *node // root AST node of type definition
|
||||
scope *scope // type declaration scope (in case of re-parse incomplete type)
|
||||
}
|
||||
|
||||
// nodeType returns a type definition for the corresponding AST subtree
|
||||
@@ -175,7 +172,7 @@ func nodeType(interp *Interpreter, sc *scope, n *node) (*itype, error) {
|
||||
}
|
||||
} else {
|
||||
// Evaluate constant array size expression
|
||||
if _, err = interp.cfg(n.child[0]); err != nil {
|
||||
if _, err = interp.cfg(n.child[0], sc.pkgID); err != nil {
|
||||
return nil, err
|
||||
}
|
||||
t.incomplete = true
|
||||
@@ -199,8 +196,8 @@ func nodeType(interp *Interpreter, sc *scope, n *node) (*itype, error) {
|
||||
t.cat = boolT
|
||||
t.name = "bool"
|
||||
case byte:
|
||||
t.cat = byteT
|
||||
t.name = "byte"
|
||||
t.cat = uint8T
|
||||
t.name = "uint8"
|
||||
t.untyped = true
|
||||
case complex64:
|
||||
t.cat = complex64T
|
||||
@@ -226,8 +223,8 @@ func nodeType(interp *Interpreter, sc *scope, n *node) (*itype, error) {
|
||||
t.name = "uint"
|
||||
t.untyped = true
|
||||
case rune:
|
||||
t.cat = runeT
|
||||
t.name = "rune"
|
||||
t.cat = int32T
|
||||
t.name = "int32"
|
||||
t.untyped = true
|
||||
case string:
|
||||
t.cat = stringT
|
||||
@@ -434,6 +431,9 @@ func nodeType(interp *Interpreter, sc *scope, n *node) (*itype, error) {
|
||||
}
|
||||
}
|
||||
|
||||
case landExpr, lorExpr:
|
||||
t.cat = boolT
|
||||
|
||||
case mapType:
|
||||
t.cat = mapT
|
||||
if t.key, err = nodeType(interp, sc, n.child[0]); err != nil {
|
||||
@@ -482,7 +482,7 @@ func nodeType(interp *Interpreter, sc *scope, n *node) (*itype, error) {
|
||||
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}
|
||||
t = &itype{cat: valueT, rtype: bm.Type, isBinMethod: true}
|
||||
} else if ti := lt.lookupField(name); len(ti) > 0 {
|
||||
t = lt.fieldSeq(ti)
|
||||
} else if bs, _, ok := lt.lookupBinField(name); ok {
|
||||
@@ -593,7 +593,6 @@ 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()
|
||||
@@ -604,7 +603,6 @@ func init() {
|
||||
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))
|
||||
@@ -809,6 +807,22 @@ func (t *itype) lookupBinField(name string) (s reflect.StructField, index []int,
|
||||
return s, index, ok
|
||||
}
|
||||
|
||||
// methodCallType returns a method function type without the receiver defined.
|
||||
// The input type must be a method function type with the receiver as the first input argument.
|
||||
func (t *itype) methodCallType() reflect.Type {
|
||||
it := []reflect.Type{}
|
||||
ni := t.rtype.NumIn()
|
||||
for i := 1; i < ni; i++ {
|
||||
it = append(it, t.rtype.In(i))
|
||||
}
|
||||
ot := []reflect.Type{}
|
||||
no := t.rtype.NumOut()
|
||||
for i := 0; i < no; i++ {
|
||||
ot = append(ot, t.rtype.Out(i))
|
||||
}
|
||||
return reflect.FuncOf(it, ot, t.rtype.IsVariadic())
|
||||
}
|
||||
|
||||
// getMethod returns a pointer to the method definition
|
||||
func (t *itype) getMethod(name string) *node {
|
||||
for _, m := range t.method {
|
||||
@@ -916,7 +930,7 @@ func (t *itype) refType(defined map[string]bool) reflect.Type {
|
||||
case interfaceT:
|
||||
t.rtype = interf
|
||||
case mapT:
|
||||
t.rtype = reflect.MapOf(t.key.TypeOf(), t.val.TypeOf())
|
||||
t.rtype = reflect.MapOf(t.key.refType(defined), t.val.refType(defined))
|
||||
case ptrT:
|
||||
t.rtype = reflect.PtrTo(t.val.refType(defined))
|
||||
case structT:
|
||||
|
||||
@@ -90,9 +90,6 @@ func genValue(n *node) func(*frame) reflect.Value {
|
||||
v = reflect.ValueOf(n.val)
|
||||
}
|
||||
return func(f *frame) reflect.Value { return v }
|
||||
case rvalueExpr:
|
||||
v := n.rval
|
||||
return func(f *frame) reflect.Value { return v }
|
||||
default:
|
||||
if n.rval.IsValid() {
|
||||
v := n.rval
|
||||
@@ -180,11 +177,23 @@ func genValueInterface(n *node) func(*frame) reflect.Value {
|
||||
}
|
||||
}
|
||||
|
||||
func zeroInterfaceValue() reflect.Value {
|
||||
n := &node{kind: basicLit, typ: &itype{cat: nilT, untyped: true}}
|
||||
v := reflect.New(reflect.TypeOf((*interface{})(nil)).Elem()).Elem()
|
||||
return reflect.ValueOf(valueInterface{n, v})
|
||||
}
|
||||
|
||||
func genValueInterfaceValue(n *node) func(*frame) reflect.Value {
|
||||
value := genValue(n)
|
||||
|
||||
return func(f *frame) reflect.Value {
|
||||
return value(f).Interface().(valueInterface).value
|
||||
v := value(f)
|
||||
if v.Interface().(valueInterface).node == nil {
|
||||
// Uninitialized interface value, set it to a correct zero value.
|
||||
v.Set(zeroInterfaceValue())
|
||||
v = value(f)
|
||||
}
|
||||
return v.Interface().(valueInterface).value
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
Reference in New Issue
Block a user