Compare commits

...

30 Commits

Author SHA1 Message Date
Marc Vertes
ca68c6cd95 fix: resolve embedded method on pointer types 2020-03-17 18:14:04 +01:00
Marc Vertes
953b122e67 fix: avoid infinite recursion in genFunctionWrapper() 2020-03-17 18:02:05 +01:00
Marc Vertes
9b07e73b5e fix: resolve receiver for binary methods on non interface types 2020-03-12 14:42:04 +01:00
Marc Vertes
78bbcda1f8 fix: do not overwrite input for assign operators 2020-03-12 12:24:04 +01:00
Marc Vertes
6e33f89146 fix: correct control flow graph for some switch statements 2020-03-09 18:20:04 +01:00
Dmitrii Okunev
d29b0a48ff Add option "-e"
Option "-e" allows to set the command to be executed:

```
echo '6001d5ff0000000003000000000107000000dcff' | \
	yaegi -e 'import "fmt"; import "os"; import "encoding/hex"; import "io/ioutil"; func main() { in, _ := ioutil.ReadAll(os.Stdin); decoded, _ := hex.DecodeString(string(in));fmt.Println(string(decoded)) }' 2>/dev/null | \
	hexdump -C
00000000  60 01 d5 ff 00 00 00 00  03 00 00 00 00 01 07 00  |`...............|
00000010  00 00 dc ff 0a                                    |.....|
00000015
```
2020-03-09 18:07:04 +01:00
Marc Vertes
c7c1bea7ef fix: do not attempt to store data in _ var 2020-03-09 13:22:04 +01:00
Marc Vertes
1ae2649655 fix: correct control flow graph for defer statements 2020-03-09 10:52:05 +01:00
Traefiker Bot
0ace9244c4 fix: correctly init variables from index expressions 2020-03-05 14:28:06 +01:00
Traefiker Bot
2edd18a0c0 fix: handle use of functions in struct fields 2020-03-05 13:40:05 +01:00
Marc Vertes
cfb73445a2 fix: handle interface values in map and arrays 2020-03-03 18:32:04 +01:00
Ludovic Fernandez
94e0b582ea Update stdlib for go1.14 2020-02-26 15:06:06 +01:00
Dan Kortschak
3548c8744e interp: weaken panics to errors and return panicked values 2020-02-25 13:12:05 +01:00
Marc Vertes
d8bdc6670b fix: detect field names in struct pointer 2020-02-22 15:24:06 +01:00
Marc Vertes
27520f6dae fix: re-apply GTA until all global types/constants are defined 2020-02-20 12:44:04 +01:00
Marc Vertes
7037424edf fix: correctly store boolean result for branching operations 2020-02-14 16:26:04 +01:00
Marc Vertes
1b971b539c fix: correctly handle arbitrary type of literal array index 2020-02-12 15:06:04 +01:00
Marc Vertes
681f2f9c40 fix: correctly handle constant init for further type declarations 2020-02-12 12:32:03 +01:00
Marc Vertes
05960316f8 fix: correct type inference in composite literal init 2020-02-11 10:10:04 +01:00
Marc Vertes
902af477b8 fix: correct behavior for rune and byte types 2020-02-09 05:18:04 +01:00
Marc Vertes
812e55b95e fix: handle conversion of nil to an interface type 2020-02-09 05:04:04 +01:00
Marc Vertes
6c339ce562 fix: handle method declaration with forward declared type 2020-02-07 15:44:04 +01:00
Marc Vertes
23dfef0ac8 fix: define a correct zero value for an not initialized interface{} 2020-02-04 18:04:05 +01:00
Marc Vertes
4fd6a2dc56 fix: handle recursive type definition involving a map object 2020-02-04 16:36:05 +01:00
Marc Vertes
92a63dbe09 fix: handle out of order type declaration for global var declaration 2020-02-03 17:36:04 +01:00
Marc Vertes
e434892b9a fix: import different source packages with same base name 2020-02-03 17:22:04 +01:00
Marc Vertes
712891dd77 fix: allow reuse of _ symbol in the same scope 2020-02-03 17:08:05 +01:00
Marc Vertes
137b16580c fix: handle binary methods where receiver is implicit 2020-02-03 16:54:04 +01:00
Sven Dowideit
b057ada531 Add an example of yaegi in a shebang line 2020-01-15 16:54:06 +01:00
Camal Cakar
6d90c5a641 Case sensitivity fix 2020-01-15 16:40:06 +01:00
260 changed files with 8245 additions and 1909 deletions

View File

@@ -37,6 +37,7 @@
"funlen",
"gocognit",
"stylecheck",
"gomnd",
]
[issues]

View File

@@ -19,8 +19,8 @@ cache:
matrix:
fast_finish: true
include:
- go: 1.12.x
- go: 1.13.x
- go: 1.14.x
env: STABLE=true
env:

View File

@@ -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
View 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
View 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
View File

@@ -0,0 +1,10 @@
package main
var a = true && true
func main() {
println(a)
}
// Output:
// true

View File

@@ -9,5 +9,5 @@ func main() {
fmt.Println(buf)
}
// Output
// Output:
// []

7
_test/b1/foo/foo.go Normal file
View 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
View File

@@ -0,0 +1,3 @@
package foo
var Desc = "in b2/foo"

View File

@@ -1,4 +1,4 @@
println("Hello")
// Error:
// _test/bad0.go:1:1: expected 'package', found println
// 1:1: expected 'package', found println

12
_test/bin3.go Normal file
View File

@@ -0,0 +1,12 @@
package main
import "fmt"
func main() {
str := "part1"
str += fmt.Sprintf("%s", "part2")
fmt.Println(str)
}
// Output:
// part1part2

12
_test/chan8.go Normal file
View File

@@ -0,0 +1,12 @@
package main
func main() {
messages := make(chan bool)
go func() { messages <- true }()
println(<-messages && true)
}
// Output:
// true

View File

@@ -7,5 +7,5 @@ func main() {
fmt.Printf("%T %v\n", s, s)
}
// Output
// Output:
// int 2

16
_test/composite5.go Normal file
View 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
View 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}

20
_test/composite7.go Normal file
View File

@@ -0,0 +1,20 @@
package main
type T struct {
name string
}
var tab = []*T{{
name: "foo",
}, {
name: "bar",
}}
func main() {
println(len(tab))
println(tab[0].name)
}
// Output:
// 2
// foo

17
_test/const10.go Normal file
View File

@@ -0,0 +1,17 @@
package main
const (
a = 2
b = c + d
c = a + d
d = e + f
e = 3
f = 4
)
func main() {
println(b)
}
// Output:
// 16

22
_test/const6.go Normal file
View 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
View 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]

15
_test/const8.go Normal file
View File

@@ -0,0 +1,15 @@
package main
const (
a = 2
b = c + d
c = 4
d = 5
)
func main() {
println(a, b, c, d)
}
// Output:
// 2 9 4 5

17
_test/const9.go Normal file
View File

@@ -0,0 +1,17 @@
package main
const (
a = 2
b = c + d
c = a + d
d = e + f
e = b + 2
f = 4
)
func main() {
println(b)
}
// Error:
// 5:2: constant definition loop

9
_test/ct1/ct1.go Normal file
View File

@@ -0,0 +1,9 @@
package ct1
type Class uint
const (
L Class = iota
R
AL
)

23
_test/defer4.go Normal file
View File

@@ -0,0 +1,23 @@
package main
import "sync"
type T struct {
mu sync.RWMutex
name string
}
func (t *T) get() string {
t.mu.RLock()
defer t.mu.RUnlock()
return t.name
}
var d = T{name: "test"}
func main() {
println(d.get())
}
// Output:
// test

12
_test/fun11.go Normal file
View 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
View 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
View File

@@ -0,0 +1,12 @@
package main
import "fmt"
var I interface{}
func main() {
fmt.Printf("%T %v\n", I, I)
}
// Output:
// <nil> <nil>

12
_test/interface20.go Normal file
View File

@@ -0,0 +1,12 @@
package main
import "fmt"
func main() {
var a interface{}
a = string("A")
fmt.Println(a)
}
// Output:
// A

12
_test/interface21.go Normal file
View File

@@ -0,0 +1,12 @@
package main
import "fmt"
func main() {
s := make([]interface{}, 1)
s[0] = 1
fmt.Println(s[0])
}
// Output:
// 1

12
_test/interface22.go Normal file
View File

@@ -0,0 +1,12 @@
package main
import "fmt"
func main() {
s := make([]interface{}, 0)
s = append(s, 1)
fmt.Println(s[0])
}
// Output:
// 1

12
_test/interface23.go Normal file
View File

@@ -0,0 +1,12 @@
package main
import "fmt"
func main() {
m := make(map[string]interface{})
m["A"] = string("A")
fmt.Println(m["A"])
}
// Output:
// A

11
_test/interface24.go Normal file
View File

@@ -0,0 +1,11 @@
package main
import "fmt"
func main() {
m := make(map[string]interface{})
fmt.Println(m["B"])
}
// Output:
// <nil>

14
_test/interface25.go Normal file
View File

@@ -0,0 +1,14 @@
package main
import "fmt"
func main() {
m := make(map[string]interface{})
m["A"] = 1
for _, v := range m {
fmt.Println(v)
}
}
// Output:
// 1

14
_test/interface26.go Normal file
View File

@@ -0,0 +1,14 @@
package main
import "fmt"
func main() {
s := make([]interface{}, 0)
s = append(s, 1)
for _, v := range s {
fmt.Println(v)
}
}
// Output:
// 1

19
_test/map19.go Normal file
View File

@@ -0,0 +1,19 @@
package main
import "fmt"
type cmap struct {
servers map[int64]*server
}
type server struct {
cm *cmap
}
func main() {
m := cmap{}
fmt.Println(m)
}
// Output:
// {map[]}

10
_test/map20.go Normal file
View File

@@ -0,0 +1,10 @@
package main
var a = map[int]bool{1: true, 2: true}
func main() {
println(a[1] && true)
}
// Output:
// true

15
_test/map21.go Normal file
View File

@@ -0,0 +1,15 @@
package main
var m = map[int]string{
1: "foo",
}
func main() {
var ok bool
if _, ok = m[1]; ok {
println("ok")
}
}
// Output:
// ok

14
_test/map22.go Normal file
View File

@@ -0,0 +1,14 @@
package main
var m = map[int]string{
1: "foo",
}
func main() {
var s string
s, _ = m[1]
println(s)
}
// Output:
// foo

13
_test/map23.go Normal file
View File

@@ -0,0 +1,13 @@
package main
var m = map[int]string{
1: "foo",
}
func main() {
_, _ = m[1]
println("ok")
}
// Output:
// ok

16
_test/method29.go Normal file
View 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
View 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
View 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
View File

@@ -0,0 +1,10 @@
package main
var a = false || true
func main() {
println(a)
}
// Output:
// true

10
_test/ptr8.go Normal file
View 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
View File

@@ -0,0 +1,14 @@
package main
type T struct {
bool
}
var t = T{true}
func main() {
println(t.bool && true)
}
// Output:
// true

39
_test/struct32.go Normal file
View File

@@ -0,0 +1,39 @@
package main
type T0 struct {
name string
}
type lookupFunc func(s string) T0
type T1 struct {
name string
info lookupFunc
}
func (t T0) F1() bool { println("in F1"); return true }
type T2 struct {
t1 T1
}
func (t2 *T2) f() {
info := t2.t1.info("foo")
println(info.F1())
}
var t0 = T0{"t0"}
func main() {
t := &T2{T1{
"bar", func(s string) T0 { return t0 },
}}
println("hello")
println(t.t1.info("foo").F1())
}
// Output:
// hello
// in F1
// true

34
_test/struct33.go Normal file
View File

@@ -0,0 +1,34 @@
package main
type T0 struct {
name string
}
type lookupFunc func(s string) T0
type T1 struct {
name string
info lookupFunc
}
func (t T0) F1() bool { println("in F1"); return true }
var t0 = T0{"t0"}
func look(s string) T0 { println("in look"); return t0 }
var table = []*T1{{
name: "bar",
info: look,
},
}
func main() {
info := table[0].info
println(info("foo").F1())
}
// Output:
// in look
// in F1
// true

16
_test/struct34.go Normal file
View File

@@ -0,0 +1,16 @@
package main
type T struct {
f func(*T)
}
func f1(t *T) { t.f = f2 }
func f2(t *T) { t.f = f1 }
func main() {
println("ok")
}
// Output:
// ok

16
_test/struct35.go Normal file
View File

@@ -0,0 +1,16 @@
package main
type T struct {
f func(*T)
}
func f1(t *T) { t.f = f1 }
func main() {
t := &T{}
f1(t)
println(t.f != nil)
}
// Output:
// true

21
_test/struct36.go Normal file
View File

@@ -0,0 +1,21 @@
package main
import (
"net/http"
"strings"
)
type S struct {
http.Client
}
func main() {
var s S
if _, err := s.Get("url"); err != nil {
println(strings.Contains(err.Error(), "unsupported protocol scheme"))
}
return
}
// Output:
// true

17
_test/struct37.go Normal file
View File

@@ -0,0 +1,17 @@
package main
import (
"net/http"
"strings"
)
type MyHttpClient struct {
*http.Client
}
func main() {
c := new(MyHttpClient)
c.Client = new(http.Client)
_, err := c.Get("url")
println(strings.Contains(err.Error(), "unsupported protocol scheme"))
}

15
_test/switch23.go Normal file
View File

@@ -0,0 +1,15 @@
package main
func getType() string { return "T1" }
func main() {
switch getType() {
case "T1":
println("T1")
default:
println("default")
}
}
// Output:
// T1

16
_test/switch24.go Normal file
View File

@@ -0,0 +1,16 @@
package main
func main() {
a := 3
switch a + 2 {
case 5:
println(5)
default:
println("default")
}
println("bye")
}
// Output:
// 5
// bye

18
_test/switch25.go Normal file
View File

@@ -0,0 +1,18 @@
package main
func main() {
a := 2
switch {
case a == 1:
println(1)
case a == 2:
println(2)
default:
println("default")
}
println("bye")
}
// Output:
// 2
// bye

18
_test/switch26.go Normal file
View File

@@ -0,0 +1,18 @@
package main
func main() {
a := 1
switch a := 2; {
case a == 1:
println(1)
case a == 2:
println(2)
default:
println("default")
}
println(a)
}
// Output:
// 2
// 1

9
_test/type15.go Normal file
View File

@@ -0,0 +1,9 @@
package main
func main() {
err := error(nil)
println(err == nil)
}
// Output:
// true

11
_test/type16.go Normal file
View 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
View 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

20
_test/type18.go Normal file
View File

@@ -0,0 +1,20 @@
package main
type T struct {
name string
size int
}
var table = []*T{{
name: "foo",
size: 2,
}}
var s = table[0].size
func main() {
println(s)
}
// Output:
// 2

21
_test/type19.go Normal file
View File

@@ -0,0 +1,21 @@
package main
type T struct {
name string
size int
}
var table = map[int]*T{
0: {
name: "foo",
size: 2,
}}
var s = table[0].size
func main() {
println(s)
}
// Output:
// 2

11
_test/var10.go Normal file
View File

@@ -0,0 +1,11 @@
package main
var _ = true
var _ = "hello"
func main() {
println("hello")
}
// Output:
// hello

10
_test/var11.go Normal file
View File

@@ -0,0 +1,10 @@
package main
var a, _, _, b = 1, true, "foo", 2
func main() {
println(a, b)
}
// Output:
// 1 2

View File

@@ -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.
@@ -47,8 +47,10 @@ import (
func main() {
var interactive bool
var tags string
var cmd string
flag.BoolVar(&interactive, "i", false, "start an interactive REPL")
flag.StringVar(&tags, "tags", "", "set a list of build tags")
flag.StringVar(&cmd, "e", "", "set the command to be executed (instead of script or/and shell)")
flag.Usage = func() {
fmt.Println("Usage:", os.Args[0], "[options] [script] [args]")
fmt.Println("Options:")
@@ -62,31 +64,41 @@ func main() {
i.Use(stdlib.Symbols)
i.Use(interp.Symbols)
if len(args) > 0 {
// Skip first os arg to set command line as expected by interpreted main
os.Args = os.Args[1:]
flag.CommandLine = flag.NewFlagSet(os.Args[0], flag.ExitOnError)
if cmd != `` {
i.REPL(strings.NewReader(cmd), os.Stderr)
}
b, err := ioutil.ReadFile(args[0])
if err != nil {
log.Fatal("Could not read file: ", args[0])
}
s := string(b)
if s[:2] == "#!" {
// Allow executable go scripts, but fix them prior to parse
s = strings.Replace(s, "#!", "//", 1)
}
i.Name = args[0]
if _, err := i.Eval(s); err != nil {
fmt.Println(err)
}
if interactive {
if len(args) == 0 {
if interactive || cmd == `` {
i.REPL(os.Stdin, os.Stdout)
}
} else {
return
}
// Skip first os arg to set command line as expected by interpreted main
os.Args = os.Args[1:]
flag.CommandLine = flag.NewFlagSet(os.Args[0], flag.ExitOnError)
b, err := ioutil.ReadFile(args[0])
if err != nil {
log.Fatal("Could not read file: ", args[0])
}
s := string(b)
if s[:2] == "#!" {
// Allow executable go scripts, but fix them prior to parse
s = strings.Replace(s, "#!", "//", 1)
}
i.Name = args[0]
if _, err := i.Eval(s); err != nil {
fmt.Println(err)
if p, ok := err.(interp.Panic); ok {
fmt.Println(string(p.Stack))
}
}
if interactive {
i.REPL(os.Stdin, os.Stdout)
}
}

View File

@@ -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",
@@ -204,7 +200,6 @@ const (
aCase
aCompositeLit
aDec
aDefer
aEqual
aGreater
aGreaterEqual
@@ -262,7 +257,6 @@ var actions = [...]string{
aCase: "case",
aCompositeLit: "compositeLit",
aDec: "--",
aDefer: "defer",
aEqual: "==",
aGreater: ">",
aGetFunc: "getFunc",
@@ -573,7 +567,7 @@ func (interp *Interpreter) ast(src, name string) (string, *node, error) {
st.push(addChild(&root, anc, pos, declStmt, aNop), nod)
case *ast.DeferStmt:
st.push(addChild(&root, anc, pos, deferStmt, aDefer), nod)
st.push(addChild(&root, anc, pos, deferStmt, aNop), nod)
case *ast.Ellipsis:
st.push(addChild(&root, anc, pos, ellipsisExpr, aNop), nod)

View File

@@ -10,7 +10,12 @@ import (
)
// A cfgError represents an error during CFG build stage
type cfgError error
type cfgError struct {
*node
error
}
func (c *cfgError) Error() string { return c.error.Error() }
var constOp = map[action]func(*node){
aAdd: addConst,
@@ -42,8 +47,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 +236,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 +421,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 +434,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
}
@@ -448,7 +464,7 @@ func (interp *Interpreter) cfg(root *node) ([]*node, error) {
err = n.cfgErrorf("illegal operand types for '%v' operator", n.action)
}
default:
// Detect invalid float truncate
// Detect invalid float truncate.
if isInt(t0) && isFloat(t1) {
err = src.cfgErrorf("invalid float truncate")
return
@@ -459,7 +475,8 @@ func (interp *Interpreter) cfg(root *node) ([]*node, error) {
// Propagate type
// TODO: Check that existing destination type matches source type
switch {
case n.action == aAssign && src.action == aCall:
case n.action == aAssign && src.action == aCall && dest.typ.cat != interfaceT:
// Call action may perform the assignment directly.
n.gen = nop
src.level = level
src.findex = dest.findex
@@ -467,7 +484,7 @@ func (interp *Interpreter) cfg(root *node) ([]*node, error) {
src.typ = dest.typ
}
case n.action == aAssign && src.action == aRecv:
// Assign by reading from a receiving channel
// Assign by reading from a receiving channel.
n.gen = nop
src.findex = dest.findex // Set recv address to LHS
dest.typ = src.typ
@@ -476,16 +493,16 @@ func (interp *Interpreter) cfg(root *node) ([]*node, error) {
src.findex = dest.findex
src.level = level
case src.kind == basicLit:
// TODO: perform constant folding and propagation here
// TODO: perform constant folding and propagation here.
switch {
case dest.typ.cat == interfaceT:
case isComplex(dest.typ.TypeOf()):
// value set in genValue
// Value set in genValue.
case !src.rval.IsValid():
// Assign to nil
// Assign to nil.
src.rval = reflect.New(dest.typ.TypeOf()).Elem()
default:
// Convert literal value to destination type
// Convert literal value to destination type.
src.rval = src.rval.Convert(dest.typ.TypeOf())
src.typ = dest.typ
}
@@ -499,9 +516,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 +757,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) {
@@ -759,10 +777,20 @@ func (interp *Interpreter) cfg(root *node) ([]*node, error) {
case isBinCall(n):
n.gen = callBin
if typ := n.child[0].typ.rtype; typ.NumOut() > 0 {
n.typ = &itype{cat: valueT, rtype: typ.Out(0)}
n.findex = sc.add(n.typ)
for i := 1; i < typ.NumOut(); i++ {
sc.add(&itype{cat: valueT, rtype: typ.Out(i)})
if funcType := n.child[0].typ.val; funcType != nil {
// Use the original unwrapped function type, to allow future field and
// methods resolutions, otherwise impossible on the opaque bin type.
n.typ = funcType.ret[0]
n.findex = sc.add(n.typ)
for i := 1; i < len(funcType.ret); i++ {
sc.add(funcType.ret[i])
}
} else {
n.typ = &itype{cat: valueT, rtype: typ.Out(0)}
n.findex = sc.add(n.typ)
for i := 1; i < typ.NumOut(); i++ {
sc.add(&itype{cat: valueT, rtype: typ.Out(i)})
}
}
}
default:
@@ -812,7 +840,7 @@ func (interp *Interpreter) cfg(root *node) ([]*node, error) {
n.findex = sc.add(n.typ)
}
// TODO: Check that composite literal expr matches corresponding type
n.gen = compositeGenerator(n)
n.gen = compositeGenerator(n, sc)
case fallthroughtStmt:
if n.anc.kind != caseBody {
@@ -897,10 +925,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:
@@ -908,13 +936,14 @@ func (interp *Interpreter) cfg(root *node) ([]*node, error) {
sc = sc.pop()
err = genRun(n)
case goStmt:
case deferStmt, goStmt:
wireChild(n)
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 +960,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 +1121,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 +1175,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 +1193,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)
}
@@ -1191,11 +1214,12 @@ func (interp *Interpreter) cfg(root *node) ([]*node, error) {
n.recv = &receiver{node: n.child[0], index: lind}
}
} else if m, lind, isPtr, ok := n.typ.lookupBinMethod(n.child[1].ident); ok {
if isPtr {
if isPtr && n.typ.fieldSeq(lind).cat != ptrT {
n.gen = getIndexSeqPtrMethod
} else {
n.gen = getIndexSeqMethod
}
n.recv = &receiver{node: n.child[0], index: lind}
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 {
@@ -1212,7 +1236,7 @@ func (interp *Interpreter) cfg(root *node) ([]*node, error) {
if n.typ.cat == funcT {
// function in a struct field is always wrapped in reflect.Value
rtype := n.typ.TypeOf()
n.typ = &itype{cat: valueT, rtype: rtype}
n.typ = &itype{cat: valueT, rtype: rtype, val: n.typ}
}
default:
n.gen = getIndexSeq
@@ -1220,7 +1244,7 @@ func (interp *Interpreter) cfg(root *node) ([]*node, error) {
if n.typ.cat == funcT {
// function in a struct field is always wrapped in reflect.Value
rtype := n.typ.TypeOf()
n.typ = &itype{cat: valueT, rtype: rtype}
n.typ = &itype{cat: valueT, rtype: rtype, val: n.typ}
}
}
} else if s, lind, ok := n.typ.lookupBinField(n.child[1].ident); ok {
@@ -1303,14 +1327,8 @@ func (interp *Interpreter) cfg(root *node) ([]*node, error) {
}
c := clauses[l-1]
c.tnext = c.lastChild().start
if n.child[0].action == aAssign &&
(n.child[0].child[0].kind != typeAssertExpr || len(n.child[0].child[0].child) > 1) {
// switch init statement is defined
n.start = n.child[0].start
n.child[0].tnext = sbn.start
} else {
n.start = sbn.start
}
n.start = n.child[0].start
n.child[0].tnext = sbn.start
sc = sc.pop()
case switchIfStmt: // like an if-else chain
@@ -1337,16 +1355,13 @@ func (interp *Interpreter) cfg(root *node) ([]*node, error) {
// If last case body statement is a fallthrough, then jump to next case body
if i < l-1 && len(body.child) > 0 && body.lastChild().kind == fallthroughtStmt {
body.tnext = clauses[i+1].lastChild().start
} else {
body.tnext = n
}
}
sbn.start = clauses[0].start
if n.child[0].action == aAssign {
// switch init statement is defined
n.start = n.child[0].start
n.child[0].tnext = sbn.start
} else {
n.start = sbn.start
}
n.start = n.child[0].start
n.child[0].tnext = sbn.start
sc = sc.pop()
case typeAssertExpr:
@@ -1439,8 +1454,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
}
@@ -1526,13 +1547,13 @@ func childPos(n *node) int {
return -1
}
func (n *node) cfgErrorf(format string, a ...interface{}) cfgError {
func (n *node) cfgErrorf(format string, a ...interface{}) *cfgError {
a = append([]interface{}{n.interp.fset.Position(n.pos)}, a...)
return cfgError(fmt.Errorf("%s: "+format, a...))
return &cfgError{n, fmt.Errorf("%s: "+format, a...)}
}
func genRun(nod *node) error {
var err cfgError
var err error
nod.Walk(func(n *node) bool {
if err != nil {
@@ -1570,7 +1591,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 +1706,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
@@ -1719,6 +1743,10 @@ func isKey(n *node) bool {
(n.anc.kind == fieldExpr && len(n.anc.child) > 1 && n.anc.child[0] == n)
}
func isField(n *node) bool {
return n.kind == selectorExpr && len(n.child) > 0 && n.child[0].typ != nil && isStruct(n.child[0].typ)
}
// isNewDefine returns true if node refers to a new definition
func isNewDefine(n *node, sc *scope) bool {
if n.ident == "_" {
@@ -1783,13 +1811,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) {
@@ -1840,21 +1861,32 @@ func gotoLabel(s *symbol) {
}
}
func compositeGenerator(n *node) (gen bltnGenerator) {
func compositeGenerator(n *node, sc *scope) (gen bltnGenerator) {
switch n.typ.cat {
case aliasT, ptrT:
n.typ.val.untyped = n.typ.untyped
n.typ = n.typ.val
gen = compositeGenerator(n)
gen = compositeGenerator(n, sc)
case arrayT:
gen = arrayLit
case mapT:
gen = mapLit
case structT:
if len(n.child) > 0 && n.lastChild().kind == keyValueExpr {
gen = compositeSparse
} else {
gen = compositeLit
switch {
case len(n.child) == 0:
gen = compositeLitNotype
case n.lastChild().kind == keyValueExpr:
if n.child[0].isType(sc) {
gen = compositeSparse
} else {
gen = compositeSparseNotype
}
default:
if n.child[0].isType(sc) {
gen = compositeLit
} else {
gen = compositeLitNotype
}
}
case valueT:
switch k := n.typ.rtype.Kind(); k {
@@ -1866,7 +1898,7 @@ func compositeGenerator(n *node) (gen bltnGenerator) {
log.Panic(n.cfgErrorf("compositeGenerator not implemented for type kind: %s", k))
}
}
return
return gen
}
// arrayTypeLen returns the node's array length. If the expression is an

View File

@@ -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,12 @@ 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.
if _, err = interp.cfg(n, pkgID); err != nil {
// No error processing here, to allow recovery in subtree nodes.
err = nil
}
case blockStmt:
if n != root {
@@ -44,6 +50,14 @@ func (interp *Interpreter) gta(root *node, rpath string) ([]*node, error) {
for i := 0; i < n.nleft; i++ {
dest, src := n.child[i], n.child[sbase+i]
val := reflect.ValueOf(iotaValue)
if n.anc.kind == constDecl {
if _, err2 := interp.cfg(n, pkgID); err2 != nil {
// Constant value can not be computed yet.
// Come back when child dependencies are known.
revisit = append(revisit, n)
return false
}
}
typ := atyp
if typ == nil {
if typ, err = nodeType(interp, sc, src); err != nil {
@@ -52,7 +66,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 +74,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 +96,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 +141,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 +170,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
@@ -194,3 +221,42 @@ func (interp *Interpreter) gta(root *node, rpath string) ([]*node, error) {
}
return revisit, err
}
// gtaRetry (re)applies gta until all global constants and types are defined.
func (interp *Interpreter) gtaRetry(nodes []*node, rpath, pkgID string) error {
revisit := []*node{}
for {
for _, n := range nodes {
list, err := interp.gta(n, rpath, pkgID)
if err != nil {
return err
}
revisit = append(revisit, list...)
}
if len(revisit) == 0 || equalNodes(nodes, revisit) {
break
}
nodes = revisit
revisit = []*node{}
}
if len(revisit) > 0 {
return revisit[0].cfgErrorf("constant definition loop")
}
return nil
}
// equalNodes returns true if two slices of nodes are identical.
func equalNodes(a, b []*node) bool {
if len(a) != len(b) {
return false
}
for i, n := range a {
if n != b[i] {
return false
}
}
return true
}

View File

@@ -11,6 +11,8 @@ import (
"os"
"os/signal"
"reflect"
"runtime"
"runtime/debug"
"strconv"
"sync"
"sync/atomic"
@@ -158,6 +160,24 @@ type _error struct {
func (w _error) Error() string { return w.WError() }
// Panic is an error recovered from a panic call in interpreted code.
type Panic struct {
// Value is the recovered value of a call to panic.
Value interface{}
// Callers is the call stack obtained from the recover call.
// It may be used as the parameter to runtime.CallersFrames.
Callers []uintptr
// Stack is the call stack buffer for debug.
Stack []byte
}
// TODO: Capture interpreter stack frames also and remove
// fmt.Println(n.cfgErrorf("panic")) in runCfg.
func (e Panic) Error() string { return fmt.Sprint(e.Value) }
// Walk traverses AST n in depth first order, call cbin function
// at node entry and cbout function at node exit.
func (n *node) Walk(in func(n *node) bool, out func(n *node)) {
@@ -216,7 +236,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 +248,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 +303,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
@@ -291,10 +311,17 @@ func (interp *Interpreter) main() *node {
// Eval evaluates Go code represented as a string. It returns a map on
// current interpreted package exported symbols
func (interp *Interpreter) Eval(src string) (reflect.Value, error) {
var res reflect.Value
func (interp *Interpreter) Eval(src string) (res reflect.Value, err error) {
defer func() {
r := recover()
if r != nil {
var pc [64]uintptr // 64 frames should be enough.
n := runtime.Callers(1, pc[:])
err = Panic{Value: r, Callers: pc[:n], Stack: debug.Stack()}
}
}()
// Parse source to AST
// Parse source to AST.
pkgName, root, err := interp.ast(src, interp.Name)
if err != nil || root == nil {
return res, err
@@ -307,19 +334,13 @@ func (interp *Interpreter) Eval(src string) (reflect.Value, error) {
}
}
// Global type analysis
revisit, err := interp.gta(root, pkgName)
if err != nil {
// Perform global types analysis.
if err = interp.gtaRetry([]*node{root}, pkgName, interp.Name); err != nil {
return res, err
}
for _, n := range revisit {
if _, err = interp.gta(n, pkgName); 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 +357,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()
@@ -446,12 +467,15 @@ func (interp *Interpreter) REPL(in io.Reader, out io.Writer) {
v, err := interp.EvalWithContext(ctx, src)
signal.Reset()
if err != nil {
switch err.(type) {
switch e := err.(type) {
case scanner.ErrorList:
// Early failure in the scanner: the source is incomplete
// and no AST could be produced, neither compiled / run.
// Get one more line, and retry
continue
case Panic:
fmt.Fprintln(out, e.Value)
fmt.Fprintln(out, string(e.Stack))
default:
fmt.Fprintln(out, err)
}

View File

@@ -33,6 +33,7 @@ func TestInterpConsistencyBuild(t *testing.T) {
for _, file := range files {
if filepath.Ext(file.Name()) != ".go" ||
file.Name() == "bad0.go" || // expect error
file.Name() == "const9.go" || // expect error
file.Name() == "export1.go" || // non-main package
file.Name() == "export0.go" || // non-main package
file.Name() == "for7.go" || // expect error
@@ -138,6 +139,11 @@ func TestInterpErrorConsistency(t *testing.T) {
expectedInterp: "1:1: expected 'package', found println",
expectedExec: "1:1: expected 'package', found println",
},
{
fileName: "const9.go",
expectedInterp: "5:2: constant definition loop",
expectedExec: "5:2: constant definition loop",
},
{
fileName: "if2.go",
expectedInterp: "7:5: non-bool used as if condition",

View File

@@ -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"},
})
}
@@ -525,7 +525,11 @@ func eval(t *testing.T, i *interp.Interpreter, src string) reflect.Value {
t.Helper()
res, err := i.Eval(src)
if err != nil {
t.Fatal(err)
t.Logf("Error: %v", err)
if e, ok := err.(interp.Panic); ok {
t.Logf(string(e.Stack))
}
t.FailNow()
}
return res
}
@@ -541,7 +545,11 @@ func assertEval(t *testing.T, i *interp.Interpreter, src, expectedError, expecte
}
if err != nil {
t.Fatalf("got an error %v", err)
t.Logf("got an error: %v", err)
if e, ok := err.(interp.Panic); ok {
t.Logf(string(e.Stack))
}
t.FailNow()
}
if fmt.Sprintf("%v", res) != expectedRes {

View File

@@ -29,7 +29,6 @@ var builtin = [...]bltnGenerator{
aCase: _case,
aCompositeLit: arrayLit,
aDec: dec,
aDefer: _defer,
aEqual: equal,
aGetFunc: getFunc,
aGreater: greater,
@@ -216,7 +215,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
@@ -264,7 +263,9 @@ func assign(n *node) {
svalue[i] = genValueInterface(src)
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:
case src.typ.cat == funcT && dest.typ.cat == valueT:
svalue[i] = genFunctionWrapper(src)
case src.typ.cat == funcT && isField(dest):
svalue[i] = genFunctionWrapper(src)
case dest.typ.cat == funcT && src.typ.cat == valueT:
svalue[i] = genValueNode(src)
@@ -293,12 +294,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 +322,6 @@ func assign(n *node) {
default:
t = typ.TypeOf()
}
//types[i] = n.child[sbase+i].typ.TypeOf()
types[i] = t
}
@@ -326,10 +331,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 +356,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 +389,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
@@ -471,7 +482,6 @@ func genFunctionWrapper(n *node) func(*frame) reflect.Value {
if def, ok = n.val.(*node); !ok {
return genValueAsFunctionWrapper(n)
}
setExec(def.child[3].start)
start := def.child[3].start
numRet := len(def.typ.ret)
var rcvr func(*frame) reflect.Value
@@ -585,47 +595,6 @@ func genInterfaceWrapper(n *node, typ reflect.Type) func(*frame) reflect.Value {
}
}
func _defer(n *node) {
tnext := getExec(n.tnext)
values := make([]func(*frame) reflect.Value, len(n.child[0].child))
var method func(*frame) reflect.Value
for i, c := range n.child[0].child {
if c.typ.cat == funcT {
values[i] = genFunctionWrapper(c)
} else {
if c.recv != nil {
// defer a method on a binary obj
mi := c.val.(int)
m := genValue(c.child[0])
method = func(f *frame) reflect.Value { return m(f).Method(mi) }
}
values[i] = genValue(c)
}
}
if method != nil {
n.exec = func(f *frame) bltn {
val := make([]reflect.Value, len(values))
val[0] = method(f)
for i, v := range values[1:] {
val[i+1] = v(f)
}
f.deferred = append([][]reflect.Value{val}, f.deferred...)
return tnext
}
} else {
n.exec = func(f *frame) bltn {
val := make([]reflect.Value, len(values))
for i, v := range values {
val[i] = v(f)
}
f.deferred = append([][]reflect.Value{val}, f.deferred...)
return tnext
}
}
}
func call(n *node) {
goroutine := n.anc.kind == goStmt
var method bool
@@ -697,20 +666,40 @@ func call(n *node) {
}
}
if n.anc.kind == deferStmt {
// Store function call in frame for deferred execution.
value = genFunctionWrapper(n.child[0])
n.exec = func(f *frame) bltn {
val := make([]reflect.Value, len(values)+1)
val[0] = value(f)
for i, v := range values {
val[i+1] = v(f)
}
f.deferred = append([][]reflect.Value{val}, f.deferred...)
return tnext
}
return
}
n.exec = func(f *frame) bltn {
def := value(f).Interface().(*node)
var def *node
var ok bool
bf := value(f)
if def, ok = bf.Interface().(*node); ok {
bf = def.rval
}
// Call bin func if defined
if def.rval.IsValid() {
if bf.IsValid() {
in := make([]reflect.Value, len(values))
for i, v := range values {
in[i] = v(f)
}
if goroutine {
go def.rval.Call(in)
go bf.Call(in)
return tnext
}
out := def.rval.Call(in)
out := bf.Call(in)
for i, v := range rvalues {
if v != nil {
v(f).Set(out[i])
@@ -813,7 +802,7 @@ func pindex(i, variadic int) int {
return variadic
}
// Call a function from a bin import, accessible through reflect
// Callbin calls a function from a bin import, accessible through reflect.
func callBin(n *node) {
tnext := getExec(n.tnext)
fnext := getExec(n.fnext)
@@ -825,10 +814,12 @@ func callBin(n *node) {
if funcType.IsVariadic() {
variadic = funcType.NumIn() - 1
}
// method signature obtained from reflect.Type include receiver as 1st arg, except for interface types
// A method signature obtained from reflect.Type includes 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 recv := n.child[0].recv; recv != nil && !isInterface(recv.node.typ) {
if funcType.NumIn() > len(child) {
rcvrOffset = 1
}
}
for i, c := range child {
@@ -867,7 +858,6 @@ func callBin(n *node) {
case interfaceT:
values = append(values, genValueInterfaceValue(c))
default:
//values = append(values, genValue(c))
values = append(values, genInterfaceWrapper(c, defType))
}
}
@@ -875,8 +865,19 @@ func callBin(n *node) {
l := len(values)
switch {
case n.anc.kind == deferStmt:
// Store function call in frame for deferred execution.
n.exec = func(f *frame) bltn {
val := make([]reflect.Value, l+1)
val[0] = value(f)
for i, v := range values {
val[i+1] = v(f)
}
f.deferred = append([][]reflect.Value{val}, f.deferred...)
return tnext
}
case n.anc.kind == goStmt:
// Execute function in a goroutine, discard results
// Execute function in a goroutine, discard results.
n.exec = func(f *frame) bltn {
in := make([]reflect.Value, l)
for i, v := range values {
@@ -886,7 +887,7 @@ func callBin(n *node) {
return tnext
}
case fnext != nil:
// Handle branching according to boolean result
// Handle branching according to boolean result.
n.exec = func(f *frame) bltn {
in := make([]reflect.Value, l)
for i, v := range values {
@@ -899,8 +900,10 @@ func callBin(n *node) {
return fnext
}
default:
switch n.anc.kind {
case defineStmt, assignStmt, defineXStmt, assignXStmt:
switch n.anc.action {
case aAssign, aAssignX:
// The function call is part of an assign expression, we write results direcly
// to assigned location, to avoid an additional assign operation.
rvalues := make([]func(*frame) reflect.Value, funcType.NumOut())
for i := range rvalues {
c := n.anc.child[i]
@@ -967,21 +970,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 +996,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
}
@@ -1015,20 +1017,33 @@ func getIndexMap(n *node) {
dest := genValue(n)
value0 := genValue(n.child[0]) // map
tnext := getExec(n.tnext)
z := reflect.New(n.child[0].typ.TypeOf().Elem()).Elem()
z := reflect.New(n.child[0].typ.frameType().Elem()).Elem()
if n.child[1].rval.IsValid() { // constant map index
mi := n.child[1].rval
if n.fnext != nil {
switch {
case n.fnext != nil:
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 {
case n.typ.cat == interfaceT:
z = reflect.New(n.child[0].typ.val.frameType()).Elem()
n.exec = func(f *frame) bltn {
if v := value0(f).MapIndex(mi); v.IsValid() {
dest(f).Set(v.Elem())
} else {
dest(f).Set(z)
}
return tnext
}
default:
n.exec = func(f *frame) bltn {
if v := value0(f).MapIndex(mi); v.IsValid() {
dest(f).Set(v)
@@ -1041,15 +1056,28 @@ func getIndexMap(n *node) {
} else {
value1 := genValue(n.child[1]) // map index
if n.fnext != nil {
switch {
case n.fnext != nil:
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 {
case n.typ.cat == interfaceT:
z = reflect.New(n.child[0].typ.val.frameType()).Elem()
n.exec = func(f *frame) bltn {
if v := value0(f).MapIndex(value1(f)); v.IsValid() {
dest(f).Set(v.Elem())
} else {
dest(f).Set(z)
}
return tnext
}
default:
n.exec = func(f *frame) bltn {
if v := value0(f).MapIndex(value1(f)); v.IsValid() {
dest(f).Set(v)
@@ -1068,26 +1096,77 @@ func getIndexMap2(n *node) {
value0 := genValue(n.child[0]) // map
value2 := genValue(n.anc.child[1]) // status
next := getExec(n.tnext)
typ := n.anc.child[0].typ
doValue := n.anc.child[0].ident != "_"
doStatus := n.anc.child[1].ident != "_"
if !doValue && !doStatus {
nop(n)
return
}
if n.child[1].rval.IsValid() { // constant map index
mi := n.child[1].rval
n.exec = func(f *frame) bltn {
v := value0(f).MapIndex(mi)
if v.IsValid() {
dest(f).Set(v)
switch {
case !doValue:
n.exec = func(f *frame) bltn {
v := value0(f).MapIndex(mi)
value2(f).SetBool(v.IsValid())
return next
}
case typ.cat == interfaceT:
n.exec = func(f *frame) bltn {
v := value0(f).MapIndex(mi)
if v.IsValid() {
dest(f).Set(v.Elem())
}
if doStatus {
value2(f).SetBool(v.IsValid())
}
return next
}
default:
n.exec = func(f *frame) bltn {
v := value0(f).MapIndex(mi)
if v.IsValid() {
dest(f).Set(v)
}
if doStatus {
value2(f).SetBool(v.IsValid())
}
return next
}
value2(f).SetBool(v.IsValid())
return next
}
} else {
value1 := genValue(n.child[1]) // map index
n.exec = func(f *frame) bltn {
v := value0(f).MapIndex(value1(f))
if v.IsValid() {
dest(f).Set(v)
switch {
case !doValue:
n.exec = func(f *frame) bltn {
v := value0(f).MapIndex(value1(f))
value2(f).SetBool(v.IsValid())
return next
}
case typ.cat == interfaceT:
n.exec = func(f *frame) bltn {
v := value0(f).MapIndex(value1(f))
if v.IsValid() {
dest(f).Set(v.Elem())
}
if doStatus {
value2(f).SetBool(v.IsValid())
}
return next
}
default:
n.exec = func(f *frame) bltn {
v := value0(f).MapIndex(value1(f))
if v.IsValid() {
dest(f).Set(v)
}
if doStatus {
value2(f).SetBool(v.IsValid())
}
return next
}
value2(f).SetBool(v.IsValid())
return next
}
}
}
@@ -1144,17 +1223,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 +1262,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 +1285,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 +1562,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)
@@ -1581,12 +1693,12 @@ func destType(n *node) *itype {
}
}
// compositeLit creates and populates a struct object
func compositeLit(n *node) {
// doCompositeLit creates and populates a struct object
func doCompositeLit(n *node, hasType bool) {
value := valueGenerator(n, n.findex)
next := getExec(n.tnext)
child := n.child
if !n.typ.untyped {
if hasType {
child = n.child[1:]
}
destInterface := destType(n).cat == interfaceT
@@ -1618,12 +1730,15 @@ func compositeLit(n *node) {
}
}
// compositeSparse creates a struct Object, filling fields from sparse key-values
func compositeSparse(n *node) {
func compositeLit(n *node) { doCompositeLit(n, true) }
func compositeLitNotype(n *node) { doCompositeLit(n, false) }
// doCompositeSparse creates a struct Object, filling fields from sparse key-values
func doCompositeSparse(n *node, hasType bool) {
value := valueGenerator(n, n.findex)
next := getExec(n.tnext)
child := n.child
if !n.typ.untyped {
if hasType {
child = n.child[1:]
}
@@ -1653,6 +1768,9 @@ func compositeSparse(n *node) {
}
}
func compositeSparse(n *node) { doCompositeSparse(n, true) }
func compositeSparseNotype(n *node) { doCompositeSparse(n, false) }
func empty(n *node) {}
var rat = reflect.ValueOf((*[]rune)(nil)).Type().Elem() // runes array type
@@ -1738,14 +1856,26 @@ func rangeMap(n *node) {
if len(n.child) == 4 {
index1 := n.child[1].findex // map value location in frame
value = genValue(n.child[2]) // map
n.exec = func(f *frame) bltn {
iter := f.data[index2].Interface().(*reflect.MapIter)
if !iter.Next() {
return fnext
if n.child[1].typ.cat == interfaceT {
n.exec = func(f *frame) bltn {
iter := f.data[index2].Interface().(*reflect.MapIter)
if !iter.Next() {
return fnext
}
f.data[index0].Set(iter.Key())
f.data[index1].Set(iter.Value().Elem())
return tnext
}
} else {
n.exec = func(f *frame) bltn {
iter := f.data[index2].Interface().(*reflect.MapIter)
if !iter.Next() {
return fnext
}
f.data[index0].Set(iter.Key())
f.data[index1].Set(iter.Value())
return tnext
}
f.data[index0].Set(iter.Key())
f.data[index1].Set(iter.Value())
return tnext
}
} else {
value = genValue(n.child[1]) // map
@@ -1913,6 +2043,8 @@ func _append(n *node) {
values := make([]func(*frame) reflect.Value, l)
for i, arg := range args {
switch {
case n.typ.val.cat == interfaceT:
values[i] = genValueInterface(arg)
case isRecursiveStruct(n.typ.val, n.typ.val.rtype):
values[i] = genValueInterfacePtr(arg)
case arg.typ.untyped:
@@ -1933,6 +2065,8 @@ func _append(n *node) {
} else {
var value0 func(*frame) reflect.Value
switch {
case n.typ.val.cat == interfaceT:
value0 = genValueInterface(n.child[2])
case isRecursiveStruct(n.typ.val, n.typ.val.rtype):
value0 = genValueInterfacePtr(n.child[2])
case n.child[2].typ.untyped:
@@ -2066,7 +2200,7 @@ func _new(n *node) {
func _make(n *node) {
dest := genValue(n)
next := getExec(n.tnext)
typ := n.child[1].typ.TypeOf()
typ := n.child[1].typ.frameType()
switch typ.Kind() {
case reflect.Array, reflect.Slice:
@@ -2159,16 +2293,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 +2320,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 +2341,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

View File

@@ -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
}

View File

@@ -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)
}
@@ -46,7 +47,7 @@ func (interp *Interpreter) importSrc(rPath, path, alias string) error {
var root *node
var pkgName string
// Parse source files
// Parse source files.
for _, file := range files {
name := file.Name()
if skipFile(&interp.context, name) {
@@ -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,26 +79,24 @@ 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
}
revisit[subRPath] = append(revisit[subRPath], list...)
}
// revisit incomplete nodes where GTA could not complete
// 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 {
return err
}
if err = interp.gtaRetry(nodes, pkg, path); err != nil {
return err
}
}
// 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 +105,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 +185,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 {

View File

@@ -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,24 @@ 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)
recursive bool // true if the type has an element which refer to itself
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
@@ -142,7 +140,7 @@ func nodeType(interp *Interpreter, sc *scope, n *node) (*itype, error) {
}
}
var err cfgError
var err error
switch n.kind {
case addressExpr, starExpr:
t.cat = ptrT
@@ -175,7 +173,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 +197,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 +224,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
@@ -409,6 +407,20 @@ func nodeType(interp *Interpreter, sc *scope, n *node) (*itype, error) {
sc.sym[n.ident] = &symbol{kind: typeSym, typ: t}
}
case indexExpr:
var lt *itype
if lt, err = nodeType(interp, sc, n.child[0]); err != nil {
return nil, err
}
if lt.incomplete {
t.incomplete = true
break
}
switch lt.cat {
case arrayT, mapT:
t = lt.val
}
case interfaceType:
t.cat = interfaceT
if sname := typeName(n); sname != "" {
@@ -434,6 +446,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 +497,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 +608,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 +618,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))
@@ -616,11 +629,13 @@ func init() {
// if type is incomplete, re-parse it.
func (t *itype) finalize() (*itype, error) {
var err cfgError
var err error
if t.incomplete {
sym, _, found := t.scope.lookup(t.name)
if found && !sym.typ.incomplete {
sym.typ.method = append(sym.typ.method, t.method...)
t.method = sym.typ.method
t.incomplete = false
return sym.typ, nil
}
m := t.method
@@ -809,6 +824,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 {
@@ -841,13 +872,11 @@ 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, bool) {
var isPtr bool
func (t *itype) lookupBinMethod(name string) (m reflect.Method, index []int, isPtr bool, ok bool) {
if t.cat == ptrT {
return t.val.lookupBinMethod(name)
}
var index []int
m, ok := t.TypeOf().MethodByName(name)
m, ok = t.TypeOf().MethodByName(name)
if !ok {
m, ok = reflect.PtrTo(t.TypeOf()).MethodByName(name)
isPtr = ok
@@ -874,7 +903,7 @@ func exportName(s string) string {
var interf = reflect.TypeOf(new(interface{})).Elem()
func (t *itype) refType(defined map[string]bool) reflect.Type {
func (t *itype) refType(defined map[string]*itype, wrapRecursive bool) reflect.Type {
if t.rtype != nil {
return t.rtype
}
@@ -885,50 +914,56 @@ func (t *itype) refType(defined map[string]bool) reflect.Type {
panic(err)
}
}
if t.val != nil && defined[t.val.name] && !t.val.incomplete && t.val.rtype == nil {
if t.val != nil && defined[t.val.name] != nil && !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
defined[t.val.name].recursive = true
}
switch t.cat {
case aliasT:
t.rtype = t.val.refType(defined)
t.rtype = t.val.refType(defined, wrapRecursive)
case arrayT, variadicT:
if t.sizedef {
t.rtype = reflect.ArrayOf(t.size, t.val.refType(defined))
t.rtype = reflect.ArrayOf(t.size, t.val.refType(defined, wrapRecursive))
} else {
t.rtype = reflect.SliceOf(t.val.refType(defined))
t.rtype = reflect.SliceOf(t.val.refType(defined, wrapRecursive))
}
case chanT:
t.rtype = reflect.ChanOf(reflect.BothDir, t.val.refType(defined))
t.rtype = reflect.ChanOf(reflect.BothDir, t.val.refType(defined, wrapRecursive))
case errorT:
t.rtype = reflect.TypeOf(new(error)).Elem()
case funcT:
in := make([]reflect.Type, len(t.arg))
out := make([]reflect.Type, len(t.ret))
//wrap := false
for i, v := range t.arg {
in[i] = v.refType(defined)
in[i] = v.refType(defined, true)
}
for i, v := range t.ret {
out[i] = v.refType(defined)
out[i] = v.refType(defined, true)
}
t.rtype = reflect.FuncOf(in, out, false)
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, wrapRecursive), t.val.refType(defined, wrapRecursive))
case ptrT:
t.rtype = reflect.PtrTo(t.val.refType(defined))
t.rtype = reflect.PtrTo(t.val.refType(defined, wrapRecursive))
case structT:
if t.name != "" {
defined[t.name] = true
defined[t.name] = t
}
var fields []reflect.StructField
for _, f := range t.field {
field := reflect.StructField{Name: exportName(f.name), Type: f.typ.refType(defined), Tag: reflect.StructTag(f.tag)}
field := reflect.StructField{Name: exportName(f.name), Type: f.typ.refType(defined, wrapRecursive), Tag: reflect.StructTag(f.tag)}
fields = append(fields, field)
}
t.rtype = reflect.StructOf(fields)
if t.recursive && wrapRecursive {
t.rtype = interf
} else {
t.rtype = reflect.StructOf(fields)
}
default:
if z, _ := t.zero(); z.IsValid() {
t.rtype = z.Type()
@@ -939,7 +974,7 @@ func (t *itype) refType(defined map[string]bool) reflect.Type {
// TypeOf returns the reflection type of dynamic interpreter type t.
func (t *itype) TypeOf() reflect.Type {
return t.refType(map[string]bool{})
return t.refType(map[string]*itype{}, false)
}
func (t *itype) frameType() (r reflect.Type) {
@@ -1003,7 +1038,17 @@ func isInterface(t *itype) bool {
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
switch t.cat {
case structT:
return true
case aliasT, ptrT:
return isStruct(t.val)
case valueT:
k := t.rtype.Kind()
return k == reflect.Struct || (k == reflect.Ptr && t.rtype.Elem().Kind() == reflect.Struct)
default:
return false
}
}
func isBool(t *itype) bool { return t.TypeOf().Kind() == reflect.Bool }

View File

@@ -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
@@ -167,7 +164,7 @@ func genValueInterface(n *node) func(*frame) reflect.Value {
return func(f *frame) reflect.Value {
v := value(f)
nod := n
for {
for v.IsValid() {
// traverse interface indirections to find out concrete type
vi, ok := v.Interface().(valueInterface)
if !ok {
@@ -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
}
}

View File

@@ -1,6 +1,6 @@
// Code generated by 'goexports archive/tar'. DO NOT EDIT.
// +build go1.12,!go1.13
// +build go1.14,!go1.15
package stdlib

View File

@@ -1,6 +1,6 @@
// Code generated by 'goexports archive/zip'. DO NOT EDIT.
// +build go1.12,!go1.13
// +build go1.14,!go1.15
package stdlib

View File

@@ -1,6 +1,6 @@
// Code generated by 'goexports bufio'. DO NOT EDIT.
// +build go1.12,!go1.13
// +build go1.14,!go1.15
package stdlib

View File

@@ -1,6 +1,6 @@
// Code generated by 'goexports bytes'. DO NOT EDIT.
// +build go1.12,!go1.13
// +build go1.14,!go1.15
package stdlib
@@ -54,6 +54,7 @@ func init() {
"ToTitleSpecial": reflect.ValueOf(bytes.ToTitleSpecial),
"ToUpper": reflect.ValueOf(bytes.ToUpper),
"ToUpperSpecial": reflect.ValueOf(bytes.ToUpperSpecial),
"ToValidUTF8": reflect.ValueOf(bytes.ToValidUTF8),
"Trim": reflect.ValueOf(bytes.Trim),
"TrimFunc": reflect.ValueOf(bytes.TrimFunc),
"TrimLeft": reflect.ValueOf(bytes.TrimLeft),

View File

@@ -1,6 +1,6 @@
// Code generated by 'goexports compress/bzip2'. DO NOT EDIT.
// +build go1.12,!go1.13
// +build go1.14,!go1.15
package stdlib

View File

@@ -1,6 +1,6 @@
// Code generated by 'goexports compress/flate'. DO NOT EDIT.
// +build go1.12,!go1.13
// +build go1.14,!go1.15
package stdlib

View File

@@ -1,6 +1,6 @@
// Code generated by 'goexports compress/gzip'. DO NOT EDIT.
// +build go1.12,!go1.13
// +build go1.14,!go1.15
package stdlib

View File

@@ -1,6 +1,6 @@
// Code generated by 'goexports compress/lzw'. DO NOT EDIT.
// +build go1.12,!go1.13
// +build go1.14,!go1.15
package stdlib

View File

@@ -1,6 +1,6 @@
// Code generated by 'goexports compress/zlib'. DO NOT EDIT.
// +build go1.12,!go1.13
// +build go1.14,!go1.15
package stdlib

View File

@@ -1,6 +1,6 @@
// Code generated by 'goexports container/heap'. DO NOT EDIT.
// +build go1.12,!go1.13
// +build go1.14,!go1.15
package stdlib

View File

@@ -1,6 +1,6 @@
// Code generated by 'goexports container/list'. DO NOT EDIT.
// +build go1.12,!go1.13
// +build go1.14,!go1.15
package stdlib

View File

@@ -1,6 +1,6 @@
// Code generated by 'goexports container/ring'. DO NOT EDIT.
// +build go1.12,!go1.13
// +build go1.14,!go1.15
package stdlib

View File

@@ -1,6 +1,6 @@
// Code generated by 'goexports context'. DO NOT EDIT.
// +build go1.12,!go1.13
// +build go1.14,!go1.15
package stdlib

View File

@@ -1,6 +1,6 @@
// Code generated by 'goexports crypto'. DO NOT EDIT.
// +build go1.12,!go1.13
// +build go1.14,!go1.15
package stdlib

View File

@@ -1,6 +1,6 @@
// Code generated by 'goexports crypto/aes'. DO NOT EDIT.
// +build go1.12,!go1.13
// +build go1.14,!go1.15
package stdlib

View File

@@ -1,6 +1,6 @@
// Code generated by 'goexports crypto/cipher'. DO NOT EDIT.
// +build go1.12,!go1.13
// +build go1.14,!go1.15
package stdlib

View File

@@ -1,6 +1,6 @@
// Code generated by 'goexports crypto/des'. DO NOT EDIT.
// +build go1.12,!go1.13
// +build go1.14,!go1.15
package stdlib

View File

@@ -1,6 +1,6 @@
// Code generated by 'goexports crypto/dsa'. DO NOT EDIT.
// +build go1.12,!go1.13
// +build go1.14,!go1.15
package stdlib

View File

@@ -1,6 +1,6 @@
// Code generated by 'goexports crypto/ecdsa'. DO NOT EDIT.
// +build go1.12,!go1.13
// +build go1.14,!go1.15
package stdlib

View File

@@ -0,0 +1,28 @@
// Code generated by 'goexports crypto/ed25519'. DO NOT EDIT.
// +build go1.14,!go1.15
package stdlib
import (
"crypto/ed25519"
"reflect"
)
func init() {
Symbols["crypto/ed25519"] = map[string]reflect.Value{
// function, constant and variable definitions
"GenerateKey": reflect.ValueOf(ed25519.GenerateKey),
"NewKeyFromSeed": reflect.ValueOf(ed25519.NewKeyFromSeed),
"PrivateKeySize": reflect.ValueOf(ed25519.PrivateKeySize),
"PublicKeySize": reflect.ValueOf(ed25519.PublicKeySize),
"SeedSize": reflect.ValueOf(ed25519.SeedSize),
"Sign": reflect.ValueOf(ed25519.Sign),
"SignatureSize": reflect.ValueOf(ed25519.SignatureSize),
"Verify": reflect.ValueOf(ed25519.Verify),
// type definitions
"PrivateKey": reflect.ValueOf((*ed25519.PrivateKey)(nil)),
"PublicKey": reflect.ValueOf((*ed25519.PublicKey)(nil)),
}
}

View File

@@ -1,6 +1,6 @@
// Code generated by 'goexports crypto/elliptic'. DO NOT EDIT.
// +build go1.12,!go1.13
// +build go1.14,!go1.15
package stdlib

View File

@@ -1,6 +1,6 @@
// Code generated by 'goexports crypto/hmac'. DO NOT EDIT.
// +build go1.12,!go1.13
// +build go1.14,!go1.15
package stdlib

View File

@@ -1,6 +1,6 @@
// Code generated by 'goexports crypto/md5'. DO NOT EDIT.
// +build go1.12,!go1.13
// +build go1.14,!go1.15
package stdlib

View File

@@ -1,6 +1,6 @@
// Code generated by 'goexports crypto/rand'. DO NOT EDIT.
// +build go1.12,!go1.13
// +build go1.14,!go1.15
package stdlib

View File

@@ -1,6 +1,6 @@
// Code generated by 'goexports crypto/rc4'. DO NOT EDIT.
// +build go1.12,!go1.13
// +build go1.14,!go1.15
package stdlib

View File

@@ -1,6 +1,6 @@
// Code generated by 'goexports crypto/rsa'. DO NOT EDIT.
// +build go1.12,!go1.13
// +build go1.14,!go1.15
package stdlib

View File

@@ -1,6 +1,6 @@
// Code generated by 'goexports crypto/sha1'. DO NOT EDIT.
// +build go1.12,!go1.13
// +build go1.14,!go1.15
package stdlib

Some files were not shown because too many files have changed in this diff Show More