Compare commits

...

44 Commits

Author SHA1 Message Date
Marc Vertes
f1cde2be0f fix: apply automatic type conversion to constant expressions (#484) 2020-01-09 18:01:44 +01:00
Marc Vertes
bb04af2d4d doc: document import of source and binary packages (#477) 2020-01-08 18:51:30 +01:00
Marc Vertes
9a8a88dcb9 fix: use branch operation in || and && operators, fix storage for ! (#476) 2020-01-07 17:27:22 +01:00
Marc Vertes
f3f54a5302 doc: add explanation about CLA in CONTRIBUTING.md (#483) 2020-01-07 16:30:05 +01:00
Marc Vertes
878fcc835c fix: add support for ^ and + as unary operators 2020-01-07 15:34:05 +01:00
Marc Vertes
a1f2d3bf1d fix: isNil was not forwarding result when used in a branch expression 2019-12-19 18:32:04 +01:00
Marc Vertes
3cd37645eb fix: correct isValueUntyped() to handle typed constants 2019-12-19 15:38:05 +01:00
Marc Vertes
e1ac83f7d8 fix: correct type extraction for returned value 2019-12-17 10:18:06 +01:00
Marc Vertes
4f93be7f19 fix: emulate struct by interface{} only for recursive struct types 2019-12-16 19:00:07 +01:00
Marc Vertes
7a0c09f5eb fix: detect untyped values when importing from binary packages 2019-12-13 11:18:04 +01:00
Marc Vertes
275391c1e8 fix: struct type detection, collision between field and type name 2019-12-12 14:40:05 +01:00
Marc Vertes
273df8af9f fix: improve interface type checks using method sets 2019-12-11 14:46:06 +01:00
Marc Vertes
0d2c39d155 fix: implicit import package name was not correctly generated 2019-12-11 11:54:05 +01:00
Marc Vertes
1ff1a50753 fix: add method checks for interface types 2019-12-09 18:24:04 +01:00
Marc Vertes
488e491bf8 fix: improve type switch clause with assign 2019-11-27 23:00:04 +01:00
Marc Vertes
eef59153d8 fix: detect non boolean condition for IF and FOR statements 2019-11-26 00:08:05 +01:00
Marc Vertes
d44e4af527 fix: handle selector expression in type switch 2019-11-25 23:52:03 +01:00
Marc Vertes
786ea366ab fix: handle nil function closure 2019-11-25 23:36:03 +01:00
Marc Vertes
e506969172 fix: correct handling of dynamic type for interface values 2019-11-25 23:20:04 +01:00
Marc Vertes
9f1f31210a fix: automatic type conversion when returning untyped value 2019-11-19 15:22:05 +01:00
Marc Vertes
56bec974e1 fix: handle index expression on binary string type 2019-11-19 15:06:05 +01:00
Marc Vertes
08a37fc4bf fix: handle type assertion from literal interface type 2019-11-19 14:50:06 +01:00
Marc Vertes
c5ec5e492f fix: assign a literal composite to an interface object 2019-11-19 14:34:05 +01:00
Marc Vertes
773147ef71 fix: properly align atomic counters 2019-11-08 00:34:04 +01:00
Marc Vertes
a6ecebab92 fix: automatic conversion of untyped literal float to int 2019-10-31 17:32:05 +01:00
Dan Kortschak
d893a7427e doc: fix spelling 2019-10-30 11:20:05 +01:00
Marc Vertes
3969ab16c4 fix: improve handling of untyped complex numbers 2019-10-29 18:14:05 +01:00
Dan Kortschak
714253c1e6 interp: add eval cancelation by semaphore 2019-10-29 16:18:04 +01:00
Marc Vertes
75a696a5c8 fix: goexports performs correct conversion on float32 constants 2019-10-29 10:20:05 +01:00
Marc Vertes
15686873e0 fix: assign binary func to func type var 2019-10-20 04:52:03 +02:00
Marc Vertes
ac504a2e8a fix: assign untyped value to typed var may require type conversion 2019-10-20 02:30:03 +02:00
Ludovic Fernandez
e193d95dc2 feat: update syscall for go1.12.12 2019-10-19 18:30:04 +02:00
Marc Vertes
7164a23664 fix: do not hide receiver type for method with anonymous receiver 2019-10-19 17:44:03 +02:00
Marc Vertes
0b4dcbf7bb feature: add support for custom build tags 2019-10-11 16:02:05 +02:00
Ludovic Fernandez
2765478137 chore: update linter to support go1.13 2019-10-09 14:14:04 +02:00
Marc Vertes
de5a6e1038 feature: rename exported func Repl into REPL 2019-10-08 23:54:04 +02:00
Dan Kortschak
398b0e0255 interp: use io.Reader and io.Writer for REPL parameters 2019-10-08 17:34:05 +02:00
Marc Vertes
4f95c27634 fix: generate closures for literal functions in CFG 2019-10-05 19:26:04 +02:00
Marc Vertes
7d19108f01 fix: compute type of slice expression globally 2019-10-05 19:14:04 +02:00
Ludovic Fernandez
1cf327bd7d Drop go1.11 2019-10-01 14:40:05 +02:00
Dan Kortschak
4bf4aeecbb interp: fix map range handling 2019-10-01 13:54:03 +02:00
Dan Kortschak
47923866ff interp: fix array size assignment type inference 2019-09-30 22:58:04 +02:00
Dan Kortschak
bb2921b42f interp: fix range expression handling 2019-09-30 22:44:04 +02:00
Marc Vertes
2c2b471cb9 fix: goexports to convert value type only for untyped constants 2019-09-27 15:44:05 +02:00
279 changed files with 2754 additions and 77214 deletions

View File

@@ -17,11 +17,11 @@ func main() {
Expected result:
```console
$ go run ./sample.go
// ouput
// output
```
Got:
```console
$ yaegi ./sample.go
// ouput
// output
```

View File

@@ -5,7 +5,7 @@
[linters-settings]
[linters-settings.govet]
check-shadowing = true
check-shadowing = false
[linters-settings.gocyclo]
min-complexity = 12.0
@@ -32,7 +32,11 @@
"gocyclo",
"gochecknoinits",
"gochecknoglobals",
"typecheck", # v1.17.1 and Go1.13 => bug
"wsl",
"godox",
"funlen",
"gocognit",
"stylecheck",
]
[issues]
@@ -41,10 +45,13 @@
max-same-issues = 0
exclude = []
[[issues.exclude-rules]]
path = "cmd/goexports/goexports.go"
text = "SA1019: importer.For is deprecated: use ForCompiler, which populates a FileSet with the positions of objects created by the importer."
[[issues.exclude-rules]]
path = "interp/.+_test\\.go"
linters = ["goconst"]
[[issues.exclude-rules]]
path = "interp/interp.go"
text = "`in` can be `io.Reader`"
[[issues.exclude-rules]]
path = "interp/interp.go"
text = "`out` can be `io.Writer`"

View File

@@ -19,7 +19,6 @@ cache:
matrix:
fast_finish: true
include:
- go: 1.11.x
- go: 1.12.x
- go: 1.13.x
env: STABLE=true

View File

@@ -13,7 +13,12 @@ discussions.
Once the proposal is approved, a Pull Request can be opened. If you want
to provide early visibility to reviewers, create a [Draft Pull Request].
We will also require you to sign the [Containous Contributor License Agreement]
after you submit your first pull request to this project. The link to sign the
agreement will be presented to you in the web interface of the pull request.
[Issues]: https://github.com/containous/yaegi/issues
[Pull Requests]: https://github.com/containous/yaegi/issues
[Feature Request]: https://github.com/containous/yaegi/issues/new?template=feature_request.md
[Draft Pull Request]: https://github.blog/2019-02-14-introducing-draft-pull-requests/
[Containous Contributor License Agreement]: https://cla-assistant.io/containous/yaegi

View File

@@ -18,5 +18,6 @@ generate: gen_all_syscall
tests:
GO111MODULE=off go test -v ./...
GO111MODULE=off go test -race ./interp
.PHONY: check gen_all_syscall gen_tests

12
_test/a33.go Normal file
View File

@@ -0,0 +1,12 @@
package main
import "fmt"
func main() {
a := [...]int{1, 2, 3}
b := a
fmt.Println(b)
}
// Output:
// [1 2 3]

12
_test/a34.go Normal file
View File

@@ -0,0 +1,12 @@
package main
import "fmt"
func main() {
a := [...]int{1, 2, 3}
var b [3]int = a
fmt.Println(b)
}
// Output:
// [1 2 3]

13
_test/a35.go Normal file
View File

@@ -0,0 +1,13 @@
package main
import "fmt"
func main() {
a := [...]int{1, 2, 3}
b := a
b[0] = -1
fmt.Println(a)
}
// Output:
// [1 2 3]

13
_test/a36.go Normal file
View File

@@ -0,0 +1,13 @@
package main
import "fmt"
func main() {
a := [...]int{1, 2, 3}
var b [3]int = a
b[0] = -1
fmt.Println(a)
}
// Output:
// [1 2 3]

11
_test/a37.go Normal file
View File

@@ -0,0 +1,11 @@
package main
import "fmt"
func main() {
a := [...]int{1, 2, 3}
fmt.Println(a)
}
// Output:
// [1 2 3]

11
_test/a38.go Normal file
View File

@@ -0,0 +1,11 @@
package main
import "fmt"
func main() {
a := [...]byte{}
fmt.Printf("%T\n", a)
}
// Output:
// [0]uint8

12
_test/a39.go Normal file
View File

@@ -0,0 +1,12 @@
package main
import "fmt"
func main() {
a := [...]byte{}
b := a
fmt.Printf("%T %T\n", a, b)
}
// Output:
// [0]uint8 [0]uint8

10
_test/assign10.go Normal file
View File

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

13
_test/bin2.go Normal file
View File

@@ -0,0 +1,13 @@
package main
import (
"fmt"
"math"
)
func main() {
fmt.Println(math.Abs(-5))
}
// Output:
// 5

10
_test/closure8.go Normal file
View File

@@ -0,0 +1,10 @@
package main
var f = func(a int) int { return 2 + a }
func main() {
println(f(3))
}
// Output:
// 5

12
_test/complex1.go Normal file
View File

@@ -0,0 +1,12 @@
package main
import "fmt"
func main() {
var c complex128
c = 1
fmt.Printf("%T %v\n", c, c)
}
// Output:
// complex128 (1+0i)

12
_test/complex2.go Normal file
View File

@@ -0,0 +1,12 @@
package main
import "fmt"
func main() {
c := complex(1, 0)
c += 1
fmt.Printf("%T %v\n", c, c)
}
// Output:
// complex128 (2+0i)

11
_test/complex3.go Normal file
View File

@@ -0,0 +1,11 @@
package main
import "fmt"
func main() {
var s int = 1 + complex(1, 0)
fmt.Printf("%T %v\n", s, s)
}
// Output
// int 2

12
_test/composite3.go Normal file
View File

@@ -0,0 +1,12 @@
package main
func main() {
var err error
var ok bool
_, ok = err.(interface{ IsSet() bool })
println(ok)
}
// Output:
// false

11
_test/composite4.go Normal file
View File

@@ -0,0 +1,11 @@
package main
func main() {
var err error
_, ok := err.(interface{ IsSet() bool })
println(ok)
}
// Output:
// false

3
_test/ct/ct1.go Normal file
View File

@@ -0,0 +1,3 @@
package ct
func init() { println("hello from ct1") }

5
_test/ct/ct2.go Normal file
View File

@@ -0,0 +1,5 @@
// +build !dummy
package ct
func init() { println("hello from ct2") }

5
_test/ct/ct3.go Normal file
View File

@@ -0,0 +1,5 @@
// +build dummy
package ct
func init() { println("hello from ct3") }

3
_test/foo-bar/foo-bar.go Normal file
View File

@@ -0,0 +1,3 @@
package bar
var Name = "foo-bar"

9
_test/for7.go Normal file
View File

@@ -0,0 +1,9 @@
package main
func main() {
for i := 0; i; {
}
}
// Error:
// 4:14: non-bool used as for condition

19
_test/fun10.go Normal file
View File

@@ -0,0 +1,19 @@
package main
import "fmt"
func f() func() {
return nil
}
func main() {
g := f()
fmt.Printf("%T %v\n", g, g)
if g == nil {
fmt.Println("nil func")
}
}
// Output:
// func() <nil>
// nil func

13
_test/if2.go Normal file
View File

@@ -0,0 +1,13 @@
package main
import "fmt"
func main() {
var i int
if i % 1000000 {
fmt.Println("oops")
}
}
// Error:
// 7:5: non-bool used as if condition

10
_test/import7.go Normal file
View File

@@ -0,0 +1,10 @@
package main
import "github.com/containous/yaegi/_test/foo-bar"
func main() {
println(bar.Name)
}
// Output:
// foo-bar

18
_test/interface12.go Normal file
View File

@@ -0,0 +1,18 @@
package main
type I1 interface {
Truc()
}
type T1 struct{}
func (T1) Truc() { println("in T1 truc") }
var x I1 = T1{}
func main() {
x.Truc()
}
// Output:
// in T1 truc

32
_test/interface13.go Normal file
View File

@@ -0,0 +1,32 @@
package main
import (
"fmt"
)
type X struct{}
func (X) Foo() int {
return 1
}
func (X) Bar() int {
return 2
}
type Foo interface {
Foo() int
}
type Bar interface {
Bar() int
}
func main() {
var x X
var i Foo = x
j := i.(Bar)
fmt.Println(j.Bar())
}
// Output:
// 2

17
_test/interface14.go Normal file
View File

@@ -0,0 +1,17 @@
package main
type T struct{}
func (t *T) Error() string { return "T: error" }
var invalidT = &T{}
func main() {
var err error
if err != invalidT {
println("ok")
}
}
// Output:
// ok

28
_test/interface15.go Normal file
View File

@@ -0,0 +1,28 @@
package main
type Fooer interface {
Foo() string
}
type Barer interface {
//fmt.Stringer
Fooer
Bar()
}
type T struct{}
func (t *T) Foo() string { return "T: foo" }
func (*T) Bar() { println("in bar") }
var t = &T{}
func main() {
var f Barer
if f != t {
println("ok")
}
}
// Output:
// ok

25
_test/interface16.go Normal file
View File

@@ -0,0 +1,25 @@
package main
import "fmt"
type Barer interface {
fmt.Stringer
Bar()
}
type T struct{}
func (*T) String() string { return "T: nothing" }
func (*T) Bar() { println("in bar") }
var t = &T{}
func main() {
var f Barer
if f != t {
println("ok")
}
}
// Output:
// ok

17
_test/interface17.go Normal file
View File

@@ -0,0 +1,17 @@
package main
type T struct{}
func (t T) Error() string { return "T: error" }
var invalidT = T{}
func main() {
var err error
if err != invalidT {
println("ok")
}
}
// Output:
// ok

18
_test/interface18.go Normal file
View File

@@ -0,0 +1,18 @@
package main
type T struct{}
func (t *T) Error() string { return "T: error" }
func (*T) Foo() { println("foo") }
var invalidT = &T{}
func main() {
var err error
if err != invalidT {
println("ok")
}
}
// Output:
// ok

13
_test/math1.go Normal file
View File

@@ -0,0 +1,13 @@
package main
import "math"
func main() {
var f float32
if f < math.MaxFloat32 {
println("ok")
}
}
// Output:
// ok

18
_test/method28.go Normal file
View File

@@ -0,0 +1,18 @@
package main
import "fmt"
type T struct {
Name string
}
func (T) create() *T {
return &T{"Hello"}
}
func main() {
fmt.Println(T{}.create())
}
// Output:
// &{Hello}

15
_test/nil0.go Normal file
View File

@@ -0,0 +1,15 @@
package main
import "fmt"
func f() (host, port string, err error) {
return "", "", nil
}
func main() {
h, p, err := f()
fmt.Println(h, p, err)
}
// Output:
// <nil>

12
_test/nil1.go Normal file
View File

@@ -0,0 +1,12 @@
package main
func main() {
var a error = nil
if a == nil || a.Error() == "nil" {
println("a is nil")
}
}
// Output:
// a is nil

9
_test/op4.go Normal file
View File

@@ -0,0 +1,9 @@
package main
func main() {
i := 100
println(i % 1e2)
}
// Output:
// 0

9
_test/or0.go Normal file
View File

@@ -0,0 +1,9 @@
package main
func main() {
c := false
println(c || !c)
}
// Output:
// true

9
_test/or1.go Normal file
View File

@@ -0,0 +1,9 @@
package main
func main() {
c := false
println(!c || c)
}
// Output:
// true

14
_test/range0.go Normal file
View File

@@ -0,0 +1,14 @@
package main
import "fmt"
func main() {
v := []int{1, 2, 3}
for i := range v {
v = append(v, i)
}
fmt.Println(v)
}
// Output:
// [1 2 3 0 1 2]

14
_test/range1.go Normal file
View File

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

14
_test/range2.go Normal file
View File

@@ -0,0 +1,14 @@
package main
import "fmt"
func main() {
a := [...]int{2, 1, 0}
for _, v := range &a {
a[v] = v
}
fmt.Println(a)
}
// Output:
// [2 1 2]

14
_test/range3.go Normal file
View File

@@ -0,0 +1,14 @@
package main
import "fmt"
func main() {
m := map[int]bool{1: true, 3: true, 5: true}
for k := range m {
m[k*2] = true
}
fmt.Println("ok")
}
// Output:
// ok

15
_test/range4.go Normal file
View File

@@ -0,0 +1,15 @@
package main
import "fmt"
func main() {
m := map[int]bool{1: true, 3: true, 5: true}
for _, v := range m {
fmt.Println(v)
}
}
// Output:
// true
// true
// true

15
_test/range5.go Normal file
View File

@@ -0,0 +1,15 @@
package main
import "fmt"
func main() {
m := map[int]bool{1: true, 3: true, 5: true}
var n int
for range m {
n++
}
fmt.Println(n)
}
// Output:
// 3

18
_test/range6.go Normal file
View File

@@ -0,0 +1,18 @@
package main
import (
"fmt"
"math"
)
func main() {
m := map[float64]bool{math.NaN(): true, math.NaN(): true, math.NaN(): true}
for _, v := range m {
fmt.Println(v)
}
}
// Output:
// true
// true
// true

11
_test/ret7.go Normal file
View File

@@ -0,0 +1,11 @@
package main
func one() uint {
return 1
}
func main() {
println(one())
}
// Output:
// 1

11
_test/str3.go Normal file
View File

@@ -0,0 +1,11 @@
package main
import "strconv"
func main() {
str := strconv.Itoa(101)
println(str[0] == '1')
}
// Output:
// true

11
_test/str4.go Normal file
View File

@@ -0,0 +1,11 @@
package main
import "unicode/utf8"
func main() {
r, _ := utf8.DecodeRuneInString("Hello")
println(r < utf8.RuneSelf)
}
// Output:
// true

19
_test/struct29.go Normal file
View File

@@ -0,0 +1,19 @@
package main
type T1 struct {
A []T2
B []T2
}
type T2 struct {
name string
}
var t = T1{}
func main() {
println("ok")
}
// Output:
// ok

19
_test/struct30.go Normal file
View File

@@ -0,0 +1,19 @@
package main
type T1 struct {
A []T2
M map[uint64]T2
}
type T2 struct {
name string
}
var t = T1{}
func main() {
println("ok")
}
// Output:
// ok

17
_test/switch21.go Normal file
View File

@@ -0,0 +1,17 @@
package main
import "fmt"
func main() {
var err error
switch v := err.(type) {
case fmt.Formatter:
println("formatter")
default:
fmt.Println(v)
}
}
// Output:
// <nil>

21
_test/switch22.go Normal file
View File

@@ -0,0 +1,21 @@
package main
type T struct {
Name string
}
func f(t interface{}) {
switch ext := t.(type) {
case *T:
println("*T", ext.Name)
default:
println("unknown")
}
}
func main() {
f(&T{"truc"})
}
// Output:
// *T truc

15
_test/tag0.go Normal file
View File

@@ -0,0 +1,15 @@
// The following comment line has the same effect as 'go run -tags=dummy'
//yaegi:tags dummy
package main
import _ "github.com/containous/yaegi/_test/ct"
func main() {
println("bye")
}
// Output:
// hello from ct1
// hello from ct3
// bye

13
_test/time10.go Normal file
View File

@@ -0,0 +1,13 @@
package main
import "time"
var UnixTime func(int64, int64) time.Time
func main() {
UnixTime = time.Unix
println(UnixTime(1e9, 0).In(time.UTC).Minute())
}
// Output:
// 46

15
_test/time11.go Normal file
View File

@@ -0,0 +1,15 @@
package main
import (
"fmt"
"time"
)
const df = time.Minute * 30
func main() {
fmt.Printf("df: %v %T\n", df, df)
}
// Output:
// df: 30m0s time.Duration

13
_test/time9.go Normal file
View File

@@ -0,0 +1,13 @@
package main
import (
"fmt"
"time"
)
func main() {
fmt.Println((5 * time.Minute).Seconds())
}
// Output:
// 300

11
_test/var9.go Normal file
View File

@@ -0,0 +1,11 @@
package main
var a = "sdofjsdfj"
var z = a[0:2]
func main() {
println(z)
}
// Output:
// sd

View File

@@ -1,7 +1,7 @@
//go:generate go build
/*
Goexports generates wrappers of package exported symbols
Goexports generates wrappers of package exported symbols.
Output files are written in the current directory, and prefixed with the go version.
@@ -26,6 +26,7 @@ import (
"go/constant"
"go/format"
"go/importer"
"go/token"
"go/types"
"io/ioutil"
"log"
@@ -114,7 +115,7 @@ type Wrap struct {
}
func genContent(dest, pkgName, license string) ([]byte, error) {
p, err := importer.For("source", nil).Import(pkgName)
p, err := importer.ForCompiler(token.NewFileSet(), "source", nil).Import(pkgName)
if err != nil {
return nil, err
}
@@ -147,7 +148,12 @@ func genContent(dest, pkgName, license string) ([]byte, error) {
pname := path.Base(pkgName) + "." + name
switch o := o.(type) {
case *types.Const:
val[name] = Val{fixConst(pname, o.Val()), false}
if b, ok := o.Type().(*types.Basic); ok && (b.Info()&types.IsUntyped) != 0 {
// convert untyped constant to right type to avoid overflow
val[name] = Val{fixConst(pname, o.Val()), false}
} else {
val[name] = Val{pname, false}
}
case *types.Func:
val[name] = Val{pname, false}
case *types.Var:
@@ -248,7 +254,14 @@ func genContent(dest, pkgName, license string) ([]byte, error) {
// fixConst checks untyped constant value, converting it if necessary to avoid overflow
func fixConst(name string, val constant.Value) string {
if val.Kind() == constant.Int {
switch val.Kind() {
case constant.Float:
str := val.ExactString()
if _, err := strconv.ParseFloat(str, 32); err == nil {
return "float32(" + name + ")"
}
return name
case constant.Int:
str := val.ExactString()
i, err := strconv.ParseInt(str, 0, 64)
if err == nil {
@@ -265,8 +278,10 @@ func fixConst(name string, val constant.Value) string {
if err == nil {
return "uint64(" + name + ")"
}
return name
default:
return name
}
return name
}
// genLicense generates the correct LICENSE header text from the provided

View File

@@ -18,7 +18,10 @@ at global level in an implicit main package.
Options:
-i
start an interactive REPL after file execution
start an interactive REPL after file execution.
-tags tag,list
a comma-separated list of build tags to consider satisfied during
the interpretation.
Debugging support (may be removed at any time):
YAEGI_AST_DOT=1
@@ -43,7 +46,9 @@ import (
func main() {
var interactive bool
var tags string
flag.BoolVar(&interactive, "i", false, "start an interactive REPL")
flag.StringVar(&tags, "tags", "", "set a list of build tags")
flag.Usage = func() {
fmt.Println("Usage:", os.Args[0], "[options] [script] [args]")
fmt.Println("Options:")
@@ -53,7 +58,7 @@ func main() {
args := flag.Args()
log.SetFlags(log.Lshortfile)
i := interp.New(interp.Options{GoPath: build.Default.GOPATH})
i := interp.New(interp.Options{GoPath: build.Default.GOPATH, BuildTags: strings.Split(tags, ",")})
i.Use(stdlib.Symbols)
i.Use(interp.Symbols)
@@ -79,9 +84,9 @@ func main() {
}
if interactive {
i.Repl(os.Stdin, os.Stdout)
i.REPL(os.Stdin, os.Stdout)
}
} else {
i.Repl(os.Stdin, os.Stdout)
i.REPL(os.Stdin, os.Stdout)
}
}

91
cmd/yaegi/yaegi_test.go Normal file
View File

@@ -0,0 +1,91 @@
package main
import (
"bytes"
"io/ioutil"
"os"
"os/exec"
"path/filepath"
"testing"
"time"
)
func TestYaegiCmdCancel(t *testing.T) {
tmp, err := ioutil.TempDir("", "yaegi-")
if err != nil {
t.Fatalf("failed to create tmp directory: %v", err)
}
defer func() {
err = os.RemoveAll(tmp)
if err != nil {
t.Errorf("failed to clean up %v: %v", tmp, err)
}
}()
yaegi := filepath.Join(tmp, "yaegi")
build := exec.Command("go", "build", "-race", "-o", yaegi, ".")
err = build.Run()
if err != nil {
t.Fatalf("failed to build yaegi command: %v", err)
}
// Test src must be terminated by a single newline.
tests := []string{
"for {}\n",
"select {}\n",
}
for _, src := range tests {
cmd := exec.Command(yaegi)
in, err := cmd.StdinPipe()
if err != nil {
t.Errorf("failed to get stdin pipe to yaegi command: %v", err)
}
var outBuf, errBuf bytes.Buffer
cmd.Stdout = &outBuf
cmd.Stderr = &errBuf
// https://golang.org/doc/articles/race_detector.html#Options
cmd.Env = []string{`GORACE="halt_on_error=1"`}
err = cmd.Start()
if err != nil {
t.Fatalf("failed to start yaegi command: %v", err)
}
_, err = in.Write([]byte(src))
if err != nil {
t.Errorf("failed pipe test source to yaegi command: %v", err)
}
time.Sleep(100 * time.Millisecond)
err = cmd.Process.Signal(os.Interrupt)
if err != nil {
t.Errorf("failed to send os.Interrupt to yaegi command: %v", err)
}
_, err = in.Write([]byte("1+1\n"))
if err != nil {
t.Errorf("failed to probe race: %v", err)
}
err = in.Close()
if err != nil {
t.Errorf("failed to close stdin pipe: %v", err)
}
err = cmd.Wait()
if err != nil {
if cmd.ProcessState.ExitCode() == 66 { // See race_detector.html article.
t.Errorf("race detected running yaegi command canceling %q: %v", src, err)
if testing.Verbose() {
t.Log(&errBuf)
}
} else {
t.Errorf("error running yaegi command for %q: %v", src, err)
}
continue
}
if outBuf.String() != "context canceled\n2\n" {
t.Errorf("unexpected output: %q", &outBuf)
}
}
}

View File

@@ -69,7 +69,6 @@ func TestPackages(t *testing.T) {
for _, test := range testCases {
test := test
t.Run(test.desc, func(t *testing.T) {
goPath, err := filepath.Abs(test.goPath)
if err != nil {
t.Fatal(err)
@@ -116,7 +115,6 @@ func TestPackagesError(t *testing.T) {
for _, test := range testCases {
test := test
t.Run(test.desc, func(t *testing.T) {
// Init go interpreter
i := interp.New(interp.Options{GoPath: test.goPath})
i.Use(stdlib.Symbols) // Use binary standard library

2
go.mod
View File

@@ -1,3 +1,3 @@
module github.com/containous/yaegi
go 1.11
go 1.12

View File

@@ -10,7 +10,7 @@ import (
const model = `package interp
// Code generated by 'go run ../cmd/genop/genop.go'. DO NOT EDIT.
// Code generated by 'go run ../internal/genop/genop.go'. DO NOT EDIT.
import "reflect"
@@ -352,6 +352,30 @@ func {{$name}}(n *node) {
}
}
{{end}}
{{range $name, $op := .Unary}}
func {{$name}}Const(n *node) {
t := n.typ.rtype
v := n.child[0].rval
n.rval = reflect.New(t).Elem()
{{- if $op.Bool}}
n.rval.SetBool({{$op.Name}} v.Bool())
{{- else}}
switch t.Kind() {
case reflect.Int, reflect.Int8, reflect.Int16, reflect.Int32, reflect.Int64:
n.rval.SetInt({{$op.Name}} v.Int())
case reflect.Uint, reflect.Uint8, reflect.Uint16, reflect.Uint32, reflect.Uint64, reflect.Uintptr:
n.rval.SetUint({{$op.Name}} v.Uint())
{{- if $op.Float}}
case reflect.Float32, reflect.Float64:
n.rval.SetFloat({{$op.Name}} v.Float())
case reflect.Complex64, reflect.Complex128:
n.rval.SetComplex({{$op.Name}} v.Complex())
{{- end}}
}
{{- end}}
}
{{end}}
{{range $name, $op := .Comparison}}
func {{$name}}(n *node) {
tnext := getExec(n.tnext)
@@ -427,148 +451,6 @@ func {{$name}}(n *node) {
}
}
}
{{- if $op.Complex}}
case isComplex(t0) || isComplex(t1):
switch {
case c0.rval.IsValid():
s0 := vComplex(c0.rval)
v1 := genValueComplex(c1)
if n.fnext != nil {
fnext := getExec(n.fnext)
n.exec = func(f *frame) bltn {
_, s1 := v1(f)
if s0 {{$op.Name}} s1 {
dest(f).SetBool(true)
return tnext
}
dest(f).SetBool(false)
return fnext
}
} else {
n.exec = func(f *frame) bltn {
_, s1 := v1(f)
dest(f).SetBool(s0 {{$op.Name}} s1)
return tnext
}
}
case c1.rval.IsValid():
s1 := vComplex(c1.rval)
v0 := genValueComplex(c0)
if n.fnext != nil {
fnext := getExec(n.fnext)
n.exec = func(f *frame) bltn {
_, s0 := v0(f)
if s0 {{$op.Name}} s1 {
dest(f).SetBool(true)
return tnext
}
dest(f).SetBool(false)
return fnext
}
} else {
dest := genValue(n)
n.exec = func(f *frame) bltn {
_, s0 := v0(f)
dest(f).SetBool(s0 {{$op.Name}} s1)
return tnext
}
}
default:
v0 := genValueComplex(n.child[0])
v1 := genValueComplex(n.child[1])
if n.fnext != nil {
fnext := getExec(n.fnext)
n.exec = func(f *frame) bltn {
_, s0 := v0(f)
_, s1 := v1(f)
if s0 {{$op.Name}} s1 {
dest(f).SetBool(true)
return tnext
}
dest(f).SetBool(false)
return fnext
}
} else {
n.exec = func(f *frame) bltn {
_, s0 := v0(f)
_, s1 := v1(f)
dest(f).SetBool(s0 {{$op.Name}} s1)
return tnext
}
}
}
default:
switch {
case c0.rval.IsValid():
i0 := c0.rval.Interface()
v1 := genValue(c1)
if n.fnext != nil {
fnext := getExec(n.fnext)
n.exec = func(f *frame) bltn {
i1 := v1(f).Interface()
if i0 {{$op.Name}} i1 {
dest(f).SetBool(true)
return tnext
}
dest(f).SetBool(false)
return fnext
}
} else {
dest := genValue(n)
n.exec = func(f *frame) bltn {
i1 := v1(f).Interface()
dest(f).SetBool(i0 {{$op.Name}} i1)
return tnext
}
}
case c1.rval.IsValid():
i1 := c1.rval.Interface()
v0 := genValue(c0)
if n.fnext != nil {
fnext := getExec(n.fnext)
n.exec = func(f *frame) bltn {
i0 := v0(f).Interface()
if i0 {{$op.Name}} i1 {
dest(f).SetBool(true)
return tnext
}
dest(f).SetBool(false)
return fnext
}
} else {
dest := genValue(n)
n.exec = func(f *frame) bltn {
i0 := v0(f).Interface()
dest(f).SetBool(i0 {{$op.Name}} i1)
return tnext
}
}
default:
v0 := genValue(c0)
v1 := genValue(c1)
if n.fnext != nil {
fnext := getExec(n.fnext)
n.exec = func(f *frame) bltn {
i0 := v0(f).Interface()
i1 := v1(f).Interface()
if i0 {{$op.Name}} i1 {
dest(f).SetBool(true)
return tnext
}
dest(f).SetBool(false)
return fnext
}
} else {
dest := genValue(n)
n.exec = func(f *frame) bltn {
i0 := v0(f).Interface()
i1 := v1(f).Interface()
dest(f).SetBool(i0 {{$op.Name}} i1)
return tnext
}
}
}
{{- end}}
case isFloat(t0) || isFloat(t1):
switch {
case c0.rval.IsValid():
@@ -781,6 +663,148 @@ func {{$name}}(n *node) {
}
}
}
{{- if $op.Complex}}
case isComplex(t0) || isComplex(t1):
switch {
case c0.rval.IsValid():
s0 := vComplex(c0.rval)
v1 := genComplex(c1)
if n.fnext != nil {
fnext := getExec(n.fnext)
n.exec = func(f *frame) bltn {
s1 := v1(f)
if s0 {{$op.Name}} s1 {
dest(f).SetBool(true)
return tnext
}
dest(f).SetBool(false)
return fnext
}
} else {
n.exec = func(f *frame) bltn {
s1 := v1(f)
dest(f).SetBool(s0 {{$op.Name}} s1)
return tnext
}
}
case c1.rval.IsValid():
s1 := vComplex(c1.rval)
v0 := genComplex(c0)
if n.fnext != nil {
fnext := getExec(n.fnext)
n.exec = func(f *frame) bltn {
s0 := v0(f)
if s0 {{$op.Name}} s1 {
dest(f).SetBool(true)
return tnext
}
dest(f).SetBool(false)
return fnext
}
} else {
dest := genValue(n)
n.exec = func(f *frame) bltn {
s0 := v0(f)
dest(f).SetBool(s0 {{$op.Name}} s1)
return tnext
}
}
default:
v0 := genComplex(n.child[0])
v1 := genComplex(n.child[1])
if n.fnext != nil {
fnext := getExec(n.fnext)
n.exec = func(f *frame) bltn {
s0 := v0(f)
s1 := v1(f)
if s0 {{$op.Name}} s1 {
dest(f).SetBool(true)
return tnext
}
dest(f).SetBool(false)
return fnext
}
} else {
n.exec = func(f *frame) bltn {
s0 := v0(f)
s1 := v1(f)
dest(f).SetBool(s0 {{$op.Name}} s1)
return tnext
}
}
}
default:
switch {
case c0.rval.IsValid():
i0 := c0.rval.Interface()
v1 := genValue(c1)
if n.fnext != nil {
fnext := getExec(n.fnext)
n.exec = func(f *frame) bltn {
i1 := v1(f).Interface()
if i0 {{$op.Name}} i1 {
dest(f).SetBool(true)
return tnext
}
dest(f).SetBool(false)
return fnext
}
} else {
dest := genValue(n)
n.exec = func(f *frame) bltn {
i1 := v1(f).Interface()
dest(f).SetBool(i0 {{$op.Name}} i1)
return tnext
}
}
case c1.rval.IsValid():
i1 := c1.rval.Interface()
v0 := genValue(c0)
if n.fnext != nil {
fnext := getExec(n.fnext)
n.exec = func(f *frame) bltn {
i0 := v0(f).Interface()
if i0 {{$op.Name}} i1 {
dest(f).SetBool(true)
return tnext
}
dest(f).SetBool(false)
return fnext
}
} else {
dest := genValue(n)
n.exec = func(f *frame) bltn {
i0 := v0(f).Interface()
dest(f).SetBool(i0 {{$op.Name}} i1)
return tnext
}
}
default:
v0 := genValue(c0)
v1 := genValue(c1)
if n.fnext != nil {
fnext := getExec(n.fnext)
n.exec = func(f *frame) bltn {
i0 := v0(f).Interface()
i1 := v1(f).Interface()
if i0 {{$op.Name}} i1 {
dest(f).SetBool(true)
return tnext
}
dest(f).SetBool(false)
return fnext
}
} else {
dest := genValue(n)
n.exec = func(f *frame) bltn {
i0 := v0(f).Interface()
i1 := v1(f).Interface()
dest(f).SetBool(i0 {{$op.Name}} i1)
return tnext
}
}
}
{{- end}}
}
}
{{end}}
@@ -793,6 +817,7 @@ type Op struct {
Float bool // true if operator applies to float
Complex bool // true if operator applies to complex
Shift bool // true if operator is a shift operation
Bool bool // true if operator applies to bool
}
func main() {
@@ -805,17 +830,17 @@ func main() {
b := &bytes.Buffer{}
data := map[string]interface{}{
"Arithmetic": map[string]Op{
"add": {"+", true, true, true, false},
"sub": {"-", false, true, true, false},
"mul": {"*", false, true, true, false},
"quo": {"/", false, true, true, false},
"rem": {"%", false, false, false, false},
"shl": {"<<", false, false, false, true},
"shr": {">>", false, false, false, true},
"and": {"&", false, false, false, false},
"or": {"|", false, false, false, false},
"xor": {"^", false, false, false, false},
"andNot": {"&^", false, false, false, false},
"add": {"+", true, true, true, false, false},
"sub": {"-", false, true, true, false, false},
"mul": {"*", false, true, true, false, false},
"quo": {"/", false, true, true, false, false},
"rem": {"%", false, false, false, false, false},
"shl": {"<<", false, false, false, true, false},
"shr": {">>", false, false, false, true, false},
"and": {"&", false, false, false, false, false},
"or": {"|", false, false, false, false, false},
"xor": {"^", false, false, false, false, false},
"andNot": {"&^", false, false, false, false, false},
},
"IncDec": map[string]Op{
"inc": {Name: "+"},
@@ -829,6 +854,12 @@ func main() {
"lowerEqual": {Name: "<=", Complex: false},
"notEqual": {Name: "!=", Complex: true},
},
"Unary": map[string]Op{
"not": {Name: "!", Float: false, Bool: true},
"neg": {Name: "-", Float: true, Bool: false},
"pos": {Name: "+", Float: true, Bool: false},
"bitNot": {Name: "^", Float: false, Bool: false},
},
}
if err = parse.Execute(b, data); err != nil {
log.Fatal(err)

View File

@@ -6,8 +6,10 @@ import (
"go/parser"
"go/scanner"
"go/token"
"math"
"reflect"
"strconv"
"sync/atomic"
)
// nkind defines the kind of AST, i.e. the grammar category
@@ -197,6 +199,7 @@ const (
aAndAssign
aAndNot
aAndNotAssign
aBitNot
aCall
aCase
aCompositeLit
@@ -215,11 +218,12 @@ const (
aMethod
aMul
aMulAssign
aNegate
aNeg
aNot
aNotEqual
aOr
aOrAssign
aPos
aQuo
aQuoAssign
aRange
@@ -253,6 +257,7 @@ var actions = [...]string{
aAndAssign: "&=",
aAndNot: "&^",
aAndNotAssign: "&^=",
aBitNot: "^",
aCall: "call",
aCase: "case",
aCompositeLit: "compositeLit",
@@ -269,11 +274,12 @@ var actions = [...]string{
aMethod: "Method",
aMul: "*",
aMulAssign: "*=",
aNegate: "-",
aNeg: "-",
aNot: "!",
aNotEqual: "!=",
aOr: "|",
aOrAssign: "|=",
aPos: "+",
aQuo: "/",
aQuoAssign: "/=",
aRange: "range",
@@ -320,6 +326,7 @@ func (interp *Interpreter) firstToken(src string) token.Token {
func (interp *Interpreter) ast(src, name string) (string, *node, error) {
inRepl := name == ""
var inFunc bool
var mode parser.Mode
// Allow incremental parsing of declarations or statements, by inserting
// them in a pseudo file package or function. Those statements or
@@ -334,26 +341,30 @@ func (interp *Interpreter) ast(src, name string) (string, *node, error) {
inFunc = true
src = "package main; func main() {" + src + "}"
}
// Parse comments in REPL mode, to allow tag setting
mode |= parser.ParseComments
}
if ok, err := interp.buildOk(interp.context, name, src); !ok || err != nil {
if ok, err := interp.buildOk(&interp.context, name, src); !ok || err != nil {
return "", nil, err // skip source not matching build constraints
}
f, err := parser.ParseFile(interp.fset, name, src, 0)
f, err := parser.ParseFile(interp.fset, name, src, mode)
if err != nil {
return "", nil, err
}
setYaegiTags(&interp.context, f.Comments)
var root *node
var anc astNode
var st nodestack
var pkgName string
addChild := func(root **node, anc astNode, pos token.Pos, kind nkind, act action) *node {
interp.nindex++
var i interface{}
n := &node{anc: anc.node, interp: interp, index: interp.nindex, pos: pos, kind: kind, action: act, val: &i, gen: builtin[act]}
nindex := atomic.AddInt64(&interp.nindex, 1)
n := &node{anc: anc.node, interp: interp, index: nindex, pos: pos, kind: kind, action: act, val: &i, gen: builtin[act]}
n.start = n
if anc.node == nil {
*root = n
@@ -364,15 +375,15 @@ func (interp *Interpreter) ast(src, name string) (string, *node, error) {
if len(ancAst.List)+len(ancAst.Body) == len(anc.node.child) {
// All case clause children are collected.
// Split children in condition and body nodes to desambiguify the AST.
interp.nindex++
body := &node{anc: anc.node, interp: interp, index: interp.nindex, pos: pos, kind: caseBody, action: aNop, val: &i, gen: nop}
nindex = atomic.AddInt64(&interp.nindex, 1)
body := &node{anc: anc.node, interp: interp, index: nindex, pos: pos, kind: caseBody, action: aNop, val: &i, gen: nop}
if ts := anc.node.anc.anc; ts.kind == typeSwitch && ts.child[1].action == aAssign {
// In type switch clause, if a switch guard is assigned, duplicate the switch guard symbol
// in each clause body, so a different guard type can be set in each clause
name := ts.child[1].child[0].ident
interp.nindex++
gn := &node{anc: body, interp: interp, ident: name, index: interp.nindex, pos: pos, kind: identExpr, action: aNop, val: &i, gen: nop}
nindex = atomic.AddInt64(&interp.nindex, 1)
gn := &node{anc: body, interp: interp, ident: name, index: nindex, pos: pos, kind: identExpr, action: aNop, val: &i, gen: nop}
body.child = append(body.child, gn)
}
@@ -459,7 +470,11 @@ func (interp *Interpreter) ast(src, name string) (string, *node, error) {
n.rval = reflect.ValueOf(v)
case token.FLOAT:
v, _ := strconv.ParseFloat(a.Value, 64)
n.rval = reflect.ValueOf(v)
if math.Trunc(v) == v {
n.rval = reflect.ValueOf(int(v))
} else {
n.rval = reflect.ValueOf(v)
}
case token.IMAG:
v, _ := strconv.ParseFloat(a.Value[:len(a.Value)-1], 64)
n.rval = reflect.ValueOf(complex(0, v))
@@ -548,6 +563,9 @@ func (interp *Interpreter) ast(src, name string) (string, *node, error) {
case *ast.CommClause:
st.push(addChild(&root, anc, pos, commClause, aNop), nod)
case *ast.CommentGroup:
return false
case *ast.CompositeLit:
st.push(addChild(&root, anc, pos, compositeLitExpr, aCompositeLit), nod)
@@ -757,6 +775,8 @@ func (interp *Interpreter) ast(src, name string) (string, *node, error) {
var kind = unaryExpr
var act action
switch a.Op {
case token.ADD:
act = aPos
case token.AND:
kind = addressExpr
act = aAddr
@@ -765,7 +785,9 @@ func (interp *Interpreter) ast(src, name string) (string, *node, error) {
case token.NOT:
act = aNot
case token.SUB:
act = aNegate
act = aNeg
case token.XOR:
act = aBitNot
}
st.push(addChild(&root, anc, pos, kind, act), nod)
@@ -839,9 +861,9 @@ func (s *nodestack) top() astNode {
// dup returns a duplicated node subtree
func (interp *Interpreter) dup(nod, anc *node) *node {
interp.nindex++
nindex := atomic.AddInt64(&interp.nindex, 1)
n := *nod
n.index = interp.nindex
n.index = nindex
n.anc = anc
n.start = &n
n.pos = anc.pos

View File

@@ -1,6 +1,7 @@
package interp
import (
"go/ast"
"go/build"
"go/parser"
"path"
@@ -11,7 +12,7 @@ import (
// buildOk returns true if a file or script matches build constraints
// as specified in https://golang.org/pkg/go/build/#hdr-Build_Constraints.
// An error from parser is returned as well.
func (interp *Interpreter) buildOk(ctx build.Context, name, src string) (bool, error) {
func (interp *Interpreter) buildOk(ctx *build.Context, name, src string) (bool, error) {
// Extract comments before the first clause
f, err := parser.ParseFile(interp.fset, name, src, parser.PackageClauseOnly|parser.ParseComments)
if err != nil {
@@ -25,12 +26,13 @@ func (interp *Interpreter) buildOk(ctx build.Context, name, src string) (bool, e
}
}
}
setYaegiTags(ctx, f.Comments)
return true, nil
}
// buildLineOk returns true if line is not a build constraint or
// if build constraint is satisfied
func buildLineOk(ctx build.Context, line string) (ok bool) {
func buildLineOk(ctx *build.Context, line string) (ok bool) {
if len(line) < 7 || line[:7] != "+build " {
return true
}
@@ -45,7 +47,7 @@ func buildLineOk(ctx build.Context, line string) (ok bool) {
}
// buildOptionOk return true if all comma separated tags match, false otherwise
func buildOptionOk(ctx build.Context, tag string) bool {
func buildOptionOk(ctx *build.Context, tag string) bool {
// in option, evaluate the AND of individual tags
for _, t := range strings.Split(tag, ",") {
if !buildTagOk(ctx, t) {
@@ -57,7 +59,7 @@ func buildOptionOk(ctx build.Context, tag string) bool {
// buildTagOk returns true if a build tag matches, false otherwise
// if first character is !, result is negated
func buildTagOk(ctx build.Context, s string) (r bool) {
func buildTagOk(ctx *build.Context, s string) (r bool) {
not := s[0] == '!'
if not {
s = s[1:]
@@ -82,6 +84,25 @@ func buildTagOk(ctx build.Context, s string) (r bool) {
return
}
// setYaegiTags scans a comment group for "yaegi:tags tag1 tag2 ..." lines
// and adds the corresponding tags to the interpreter build tags.
func setYaegiTags(ctx *build.Context, comments []*ast.CommentGroup) {
for _, g := range comments {
for _, line := range strings.Split(strings.TrimSpace(g.Text()), "\n") {
if len(line) < 11 || line[:11] != "yaegi:tags " {
continue
}
tags := strings.Split(strings.TrimSpace(line[10:]), " ")
for _, tag := range tags {
if !contains(ctx.BuildTags, tag) {
ctx.BuildTags = append(ctx.BuildTags, tag)
}
}
}
}
}
func contains(tags []string, tag string) bool {
for _, t := range tags {
if t == tag {
@@ -92,7 +113,7 @@ func contains(tags []string, tag string) bool {
}
// goMinorVersion returns the go minor version number
func goMinorVersion(ctx build.Context) int {
func goMinorVersion(ctx *build.Context) int {
current := ctx.ReleaseTags[len(ctx.ReleaseTags)-1]
v := strings.Split(current, ".")
@@ -108,7 +129,7 @@ func goMinorVersion(ctx build.Context) int {
}
// skipFile returns true if file should be skipped
func skipFile(ctx build.Context, p string) bool {
func skipFile(ctx *build.Context, p string) bool {
if !strings.HasSuffix(p, ".go") {
return true
}

View File

@@ -44,7 +44,7 @@ func TestBuildTag(t *testing.T) {
test := test
src := test.src + "\npackage x"
t.Run(test.src, func(t *testing.T) {
if r, _ := i.buildOk(ctx, "", src); r != test.res {
if r, _ := i.buildOk(&ctx, "", src); r != test.res {
t.Errorf("got %v, want %v", r, test.res)
}
})
@@ -74,7 +74,7 @@ func TestBuildFile(t *testing.T) {
for _, test := range tests {
test := test
t.Run(test.src, func(t *testing.T) {
if r := skipFile(ctx, test.src); r != test.res {
if r := skipFile(&ctx, test.src); r != test.res {
t.Errorf("got %v, want %v", r, test.res)
}
})
@@ -106,7 +106,7 @@ func Test_goMinorVersion(t *testing.T) {
for _, test := range tests {
test := test
t.Run(test.desc, func(t *testing.T) {
minor := goMinorVersion(test.context)
minor := goMinorVersion(&test.context)
if minor != test.expected {
t.Errorf("got %v, want %v", minor, test.expected)

View File

@@ -4,8 +4,8 @@ import (
"fmt"
"log"
"math"
"path"
"reflect"
"regexp"
"unicode"
)
@@ -24,8 +24,20 @@ var constOp = map[action]func(*node){
aShr: shrConst,
aAndNot: andNotConst,
aXor: xorConst,
aNot: notConst,
aBitNot: bitNotConst,
aNeg: negConst,
aPos: posConst,
}
var constBltn = map[string]func(*node){
"complex": complexConst,
"imag": imagConst,
"real": realConst,
}
var identifier = regexp.MustCompile(`([\pL_][\pL_\d]*)$`)
// cfg generates a control flow graph (CFG) from AST (wiring successors in AST)
// and pre-compute frame sizes and indexes for all un-named (temporary) and named
// variables. A list of nodes of init functions is returned.
@@ -77,14 +89,18 @@ func (interp *Interpreter) cfg(root *node) ([]*node, error) {
ktyp = &itype{cat: valueT, rtype: typ.Key()}
vtyp = &itype{cat: valueT, rtype: typ.Elem()}
case reflect.String:
sc.add(sc.getType("int")) // Add a dummy type to store array shallow copy for range
ktyp = sc.getType("int")
vtyp = sc.getType("rune")
case reflect.Array, reflect.Slice:
sc.add(sc.getType("int")) // Add a dummy type to store array shallow copy for range
ktyp = sc.getType("int")
vtyp = &itype{cat: valueT, rtype: typ.Elem()}
}
case mapT:
n.anc.gen = rangeMap
ityp := &itype{cat: valueT, rtype: reflect.TypeOf((*reflect.MapIter)(nil))}
sc.add(ityp)
ktyp = o.typ.key
vtyp = o.typ.val
case ptrT:
@@ -96,9 +112,11 @@ func (interp *Interpreter) cfg(root *node) ([]*node, error) {
vtyp = vtyp.val
}
case stringT:
sc.add(sc.getType("int")) // Add a dummy type to store array shallow copy for range
ktyp = sc.getType("int")
vtyp = sc.getType("rune")
case arrayT, variadicT:
sc.add(sc.getType("int")) // Add a dummy type to store array shallow copy for range
ktyp = sc.getType("int")
vtyp = o.typ.val
}
@@ -158,19 +176,21 @@ func (interp *Interpreter) cfg(root *node) ([]*node, error) {
var typ *itype
if len(n.child) == 2 {
// 1 type in clause: define the var with this type in the case clause scope
switch sym, _, ok := sc.lookup(n.child[0].ident); {
case ok && sym.kind == typeSym:
typ = sym.typ
switch {
case n.child[0].ident == "nil":
typ = sc.getType("interface{}")
default:
case !n.child[0].isType(sc):
err = n.cfgErrorf("%s is not a type", n.child[0].ident)
return false
default:
typ, err = nodeType(interp, sc, n.child[0])
}
} else {
// define the var with the type in the switch guard expression
typ = sn.child[1].child[1].child[0].typ
}
if err != nil {
return false
}
nod := n.lastChild().child[0]
index := sc.add(typ)
sc.sym[nod.ident] = &symbol{index: index, kind: varSym, typ: typ}
@@ -258,13 +278,16 @@ func (interp *Interpreter) cfg(root *node) ([]*node, error) {
if len(n.child[0].child) > 0 {
// define receiver symbol
var typ *itype
recvName := n.child[0].child[0].child[0].ident
recvTypeNode := n.child[0].child[0].lastChild()
fr := n.child[0].child[0]
recvTypeNode := fr.lastChild()
if typ, err = nodeType(interp, sc, recvTypeNode); err != nil {
return false
}
recvTypeNode.typ = typ
sc.sym[recvName] = &symbol{index: sc.add(typ), kind: varSym, typ: typ}
index := sc.add(typ)
if len(fr.child) > 1 {
sc.sym[fr.child[0].ident] = &symbol{index: index, kind: varSym, typ: typ}
}
}
for _, c := range n.child[2].child[0].child {
// define input parameter symbols
@@ -299,7 +322,7 @@ func (interp *Interpreter) cfg(root *node) ([]*node, error) {
name = n.child[0].ident
} else {
ipath = n.child[0].rval.String()
name = path.Base(ipath)
name = identifier.FindString(ipath)
}
if interp.binPkg[ipath] != nil && name != "." {
sc.sym[name] = &symbol{kind: pkgSym, typ: &itype{cat: binPkgT, path: ipath}}
@@ -391,11 +414,11 @@ func (interp *Interpreter) cfg(root *node) ([]*node, error) {
dest.typ = src.typ
}
if dest.typ.sizedef {
dest.typ.size = compositeArrayLen(src)
dest.typ.size = arrayTypeLen(src)
dest.typ.rtype = nil
}
if sc.global {
// Do not overload existings symbols (defined in GTA) in global scope
// Do not overload existing symbols (defined in GTA) in global scope
sym, _, _ = sc.lookup(dest.ident)
} else {
sym = &symbol{index: sc.add(dest.typ), kind: varSym, typ: dest.typ}
@@ -441,11 +464,14 @@ func (interp *Interpreter) cfg(root *node) ([]*node, error) {
n.gen = nop
src.level = level
src.findex = dest.findex
if src.typ.untyped && !dest.typ.untyped {
src.typ = dest.typ
}
case n.action == aAssign && src.action == aRecv:
// Assign by reading from a receiving channel
n.gen = nop
src.findex = dest.findex // Set recv address to LHS
dest.typ = src.typ.val
dest.typ = src.typ
case n.action == aAssign && src.action == aCompositeLit:
n.gen = nop
src.findex = dest.findex
@@ -454,6 +480,7 @@ func (interp *Interpreter) cfg(root *node) ([]*node, error) {
// TODO: perform constant folding and propagation here
switch {
case dest.typ.cat == interfaceT:
case isComplex(dest.typ.TypeOf()):
// value set in genValue
case !src.rval.IsValid():
// Assign to nil
@@ -498,7 +525,11 @@ func (interp *Interpreter) cfg(root *node) ([]*node, error) {
n.child[l].gen = getIndexMap2
n.gen = nop
case typeAssertExpr:
n.child[l].gen = typeAssert2
if n.child[0].ident == "_" {
n.child[l].gen = typeAssertStatus
} else {
n.child[l].gen = typeAssert2
}
n.gen = nop
case unaryExpr:
if n.child[l].action == aRecv {
@@ -522,7 +553,7 @@ func (interp *Interpreter) cfg(root *node) ([]*node, error) {
t0, t1 := c0.typ.TypeOf(), c1.typ.TypeOf()
// Shift operator type is inherited from first parameter only
// All other binary operators require both parameter types to be the same
if !isShiftNode(n) && !c0.typ.untyped && !c1.typ.untyped && c0.typ.id() != c1.typ.id() {
if !isShiftNode(n) && !c0.typ.untyped && !c1.typ.untyped && !c0.typ.equals(c1.typ) {
err = n.cfgErrorf("mismatched types %s and %s", c0.typ.id(), c1.typ.id())
break
}
@@ -575,8 +606,6 @@ func (interp *Interpreter) cfg(root *node) ([]*node, error) {
constOp[n.action](n)
}
switch {
//case n.typ != nil && n.typ.cat == BoolT && isAncBranch(n):
// n.findex = -1
case n.rval.IsValid():
n.gen = nop
n.findex = -1
@@ -611,7 +640,11 @@ func (interp *Interpreter) cfg(root *node) ([]*node, error) {
case stringT:
n.typ = sc.getType("byte")
case valueT:
n.typ = &itype{cat: valueT, rtype: t.rtype.Elem()}
if t.rtype.Kind() == reflect.String {
n.typ = sc.getType("byte")
} else {
n.typ = &itype{cat: valueT, rtype: t.rtype.Elem()}
}
default:
n.typ = t.val
}
@@ -698,6 +731,10 @@ func (interp *Interpreter) cfg(root *node) ([]*node, error) {
} else {
n.findex = sc.add(n.typ)
}
if op, ok := constBltn[n.child[0].ident]; ok && n.anc.action != aAssign {
op(n) // pre-compute non-assigned constant builtin calls
}
case n.child[0].isType(sc):
// Type conversion expression
if isInt(n.child[0].typ.TypeOf()) && n.child[1].kind == basicLit && isFloat(n.child[1].typ.TypeOf()) {
@@ -797,6 +834,9 @@ func (interp *Interpreter) cfg(root *node) ([]*node, error) {
case forStmt1: // for cond {}
cond, body := n.child[0], n.child[1]
if !isBool(cond.typ) {
err = cond.cfgErrorf("non-bool used as for condition")
}
n.start = cond.start
cond.tnext = body.start
cond.fnext = n
@@ -806,6 +846,9 @@ func (interp *Interpreter) cfg(root *node) ([]*node, error) {
case forStmt2: // for init; cond; {}
init, cond, body := n.child[0], n.child[1], n.child[2]
if !isBool(cond.typ) {
err = cond.cfgErrorf("non-bool used as for condition")
}
n.start = init.start
init.tnext = cond.start
cond.tnext = body.start
@@ -816,6 +859,9 @@ func (interp *Interpreter) cfg(root *node) ([]*node, error) {
case forStmt3: // for ; cond; post {}
cond, post, body := n.child[0], n.child[1], n.child[2]
if !isBool(cond.typ) {
err = cond.cfgErrorf("non-bool used as for condition")
}
n.start = cond.start
cond.tnext = body.start
cond.fnext = n
@@ -835,6 +881,9 @@ func (interp *Interpreter) cfg(root *node) ([]*node, error) {
case forStmt4: // for init; cond; post {}
init, cond, post, body := n.child[0], n.child[1], n.child[2], n.child[3]
if !isBool(cond.typ) {
err = cond.cfgErrorf("non-bool used as for condition")
}
n.start = init.start
init.tnext = cond.start
cond.tnext = body.start
@@ -865,6 +914,7 @@ func (interp *Interpreter) cfg(root *node) ([]*node, error) {
case funcLit:
n.types = sc.types
sc = sc.pop()
err = genRun(n)
case goStmt:
wireChild(n)
@@ -917,6 +967,9 @@ func (interp *Interpreter) cfg(root *node) ([]*node, error) {
case ifStmt0: // if cond {}
cond, tbody := n.child[0], n.child[1]
if !isBool(cond.typ) {
err = cond.cfgErrorf("non-bool used as if condition")
}
n.start = cond.start
cond.tnext = tbody.start
cond.fnext = n
@@ -925,6 +978,9 @@ func (interp *Interpreter) cfg(root *node) ([]*node, error) {
case ifStmt1: // if cond {} else {}
cond, tbody, fbody := n.child[0], n.child[1], n.child[2]
if !isBool(cond.typ) {
err = cond.cfgErrorf("non-bool used as if condition")
}
n.start = cond.start
cond.tnext = tbody.start
cond.fnext = fbody.start
@@ -934,6 +990,9 @@ func (interp *Interpreter) cfg(root *node) ([]*node, error) {
case ifStmt2: // if init; cond {}
init, cond, tbody := n.child[0], n.child[1], n.child[2]
if !isBool(cond.typ) {
err = cond.cfgErrorf("non-bool used as if condition")
}
n.start = init.start
tbody.tnext = n
init.tnext = cond.start
@@ -943,6 +1002,9 @@ func (interp *Interpreter) cfg(root *node) ([]*node, error) {
case ifStmt3: // if init; cond {} else {}
init, cond, tbody, fbody := n.child[0], n.child[1], n.child[2], n.child[3]
if !isBool(cond.typ) {
err = cond.cfgErrorf("non-bool used as if condition")
}
n.start = init.start
init.tnext = cond.start
cond.tnext = tbody.start
@@ -961,6 +1023,9 @@ func (interp *Interpreter) cfg(root *node) ([]*node, error) {
n.child[1].tnext = n
n.typ = n.child[0].typ
n.findex = sc.add(n.typ)
if n.start.action == aNop {
n.start.gen = branch
}
case lorExpr:
n.start = n.child[0].start
@@ -969,6 +1034,9 @@ func (interp *Interpreter) cfg(root *node) ([]*node, error) {
n.child[1].tnext = n
n.typ = n.child[0].typ
n.findex = sc.add(n.typ)
if n.start.action == aNop {
n.start.gen = branch
}
case parenExpr:
wireChild(n)
@@ -1008,10 +1076,15 @@ func (interp *Interpreter) cfg(root *node) ([]*node, error) {
// nil: Set node value to zero of return type
f := sc.def
var typ *itype
if typ, err = nodeType(interp, sc, f.child[2].child[1].child[i].lastChild()); err != nil {
if typ, err = nodeType(interp, sc, f.child[2].child[1].fieldType(i)); err != nil {
return
}
c.rval = reflect.New(typ.TypeOf()).Elem()
if typ.cat == funcT {
// Wrap the typed nil value in a node, as per other interpreter functions
c.rval = reflect.ValueOf(&node{kind: basicLit, rval: reflect.New(typ.TypeOf()).Elem()})
} else {
c.rval = reflect.New(typ.TypeOf()).Elem()
}
}
}
@@ -1077,7 +1150,6 @@ func (interp *Interpreter) cfg(root *node) ([]*node, error) {
n.typ = &itype{cat: valueT, rtype: field.Type}
n.val = field.Index
n.gen = getPtrIndexSeq
} else {
err = n.cfgErrorf("undefined selector: %s", n.child[1].ident)
}
@@ -1091,7 +1163,7 @@ func (interp *Interpreter) cfg(root *node) ([]*node, error) {
n.typ = &itype{cat: valueT, rtype: s.Type().Elem()}
} else {
n.kind = rvalueExpr
n.typ = &itype{cat: valueT, rtype: s.Type()}
n.typ = &itype{cat: valueT, rtype: s.Type(), untyped: isValueUntyped(s)}
n.rval = s
}
n.gen = nop
@@ -1291,7 +1363,9 @@ func (interp *Interpreter) cfg(root *node) ([]*node, error) {
if len(n.child) > 1 {
wireChild(n)
if n.child[1].typ == nil {
n.child[1].typ = sc.getType(n.child[1].ident)
if n.child[1].typ, err = nodeType(interp, sc, n.child[1]); err != nil {
return
}
}
if n.anc.action != aAssignX {
n.typ = n.child[1].typ
@@ -1303,26 +1377,68 @@ func (interp *Interpreter) cfg(root *node) ([]*node, error) {
case sliceExpr:
wireChild(n)
ctyp := n.child[0].typ
if ctyp.cat == ptrT {
ctyp = ctyp.val
}
if ctyp.size != 0 {
// Create a slice type from an array type
n.typ = &itype{}
*n.typ = *ctyp
n.typ.size = 0
n.typ.rtype = nil
} else {
n.typ = ctyp
if n.typ, err = nodeType(interp, sc, n); err != nil {
return
}
n.findex = sc.add(n.typ)
case unaryExpr:
wireChild(n)
n.typ = n.child[0].typ
switch n.action {
case aRecv:
// Channel receive operation: set type to the channel data type
if n.typ.cat == valueT {
n.typ = &itype{cat: valueT, rtype: n.typ.rtype.Elem()}
} else {
n.typ = n.typ.val
}
case aBitNot:
if !isInt(n.typ.TypeOf()) {
err = n.cfgErrorf("illegal operand type for '^' operator")
return
}
case aNot:
if !isBool(n.typ) {
err = n.cfgErrorf("illegal operand type for '!' operator")
return
}
case aNeg, aPos:
if !isNumber(n.typ.TypeOf()) {
err = n.cfgErrorf("illegal operand type for '%v' operator", n.action)
return
}
}
// TODO: Optimisation: avoid allocation if boolean branch op (i.e. '!' in an 'if' expr)
n.findex = sc.add(n.typ)
if n.child[0].rval.IsValid() && constOp[n.action] != nil {
if n.typ == nil {
if n.typ, err = nodeType(interp, sc, n); err != nil {
return
}
}
n.typ.TypeOf() // init reflect type
constOp[n.action](n)
}
switch {
case n.rval.IsValid():
n.gen = nop
n.findex = -1
case n.anc.kind == assignStmt && n.anc.action == aAssign:
dest := n.anc.child[childPos(n)-n.anc.nright]
n.typ = dest.typ
n.findex = dest.findex
case n.anc.kind == returnStmt:
pos := childPos(n)
n.typ = sc.def.typ.ret[pos]
n.findex = pos
default:
if n.typ == nil {
if n.typ, err = nodeType(interp, sc, n); err != nil {
return
}
}
n.findex = sc.add(n.typ)
}
case valueSpec:
n.gen = reset
@@ -1351,9 +1467,9 @@ func compDefineX(sc *scope, n *node) error {
l := len(n.child) - 1
types := []*itype{}
switch n.child[l].kind {
switch src := n.child[l]; src.kind {
case callExpr:
funtype, err := nodeType(n.interp, sc, n.child[l].child[0])
funtype, err := nodeType(n.interp, sc, src.child[0])
if err != nil {
return err
}
@@ -1368,18 +1484,22 @@ func compDefineX(sc *scope, n *node) error {
n.gen = nop
case indexExpr:
types = append(types, n.child[l].child[0].typ.val, sc.getType("bool"))
types = append(types, src.typ, sc.getType("bool"))
n.child[l].gen = getIndexMap2
n.gen = nop
case typeAssertExpr:
if n.child[0].ident == "_" {
n.child[l].gen = typeAssertStatus
} else {
n.child[l].gen = typeAssert2
}
types = append(types, n.child[l].child[1].typ, sc.getType("bool"))
n.child[l].gen = typeAssert2
n.gen = nop
case unaryExpr:
if n.child[l].action == aRecv {
types = append(types, n.child[l].child[0].typ.val, sc.getType("bool"))
types = append(types, src.typ, sc.getType("bool"))
n.child[l].gen = recv2
n.gen = nop
}
@@ -1460,7 +1580,7 @@ func isBinType(v reflect.Value) bool { return v.IsValid() && v.Kind() == reflect
// isType returns true if node refers to a type definition, false otherwise
func (n *node) isType(sc *scope) bool {
switch n.kind {
case arrayType, chanType, funcType, mapType, structType, rtypeExpr:
case arrayType, chanType, funcType, interfaceType, mapType, structType, rtypeExpr:
return true
case parenExpr, starExpr:
if len(n.child) == 1 {
@@ -1468,7 +1588,7 @@ func (n *node) isType(sc *scope) bool {
}
case selectorExpr:
pkg, name := n.child[0].ident, n.child[1].ident
if sym, _, ok := sc.lookup(pkg); ok {
if sym, _, ok := sc.lookup(pkg); ok && sym.kind == pkgSym {
path := sym.typ.path
if p, ok := n.interp.binPkg[path]; ok && isBinType(p[name]) {
return true // Imported binary type
@@ -1538,7 +1658,7 @@ func (n *node) isInteger() bool {
if isFloat(t) {
// untyped float constant with null decimal part is ok
f := n.rval.Float()
if f == math.Round(f) {
if f == math.Trunc(f) {
n.rval = reflect.ValueOf(int(f))
n.typ.rtype = n.rval.Type()
return true
@@ -1565,7 +1685,7 @@ func (n *node) isNatural() bool {
if isFloat(t) {
// positive untyped float constant with null decimal part is ok
f := n.rval.Float()
if f == math.Round(f) && f >= 0 {
if f == math.Trunc(f) && f >= 0 {
n.rval = reflect.ValueOf(uint(f))
n.typ.rtype = n.rval.Type()
return true
@@ -1575,6 +1695,29 @@ func (n *node) isNatural() bool {
return false
}
// fieldType returns the nth parameter field node (type) of a fieldList node
func (n *node) fieldType(m int) *node {
k := 0
l := len(n.child)
for i := 0; i < l; i++ {
cl := len(n.child[i].child)
if cl < 2 {
if k == m {
return n.child[i].lastChild()
}
k++
continue
}
for j := 0; j < cl-1; j++ {
if k == m {
return n.child[i].lastChild()
}
k++
}
}
return nil
}
// lastChild returns the last child of a node
func (n *node) lastChild() *node { return n.child[len(n.child)-1] }
@@ -1582,7 +1725,8 @@ func isKey(n *node) bool {
return n.anc.kind == fileStmt ||
(n.anc.kind == selectorExpr && n.anc.child[0] != n) ||
(n.anc.kind == funcDecl && isMethod(n.anc)) ||
(n.anc.kind == keyValueExpr && isStruct(n.anc.typ) && n.anc.child[0] == n)
(n.anc.kind == keyValueExpr && isStruct(n.anc.typ) && n.anc.child[0] == n) ||
(n.anc.kind == fieldExpr && len(n.anc.child) > 1 && n.anc.child[0] == n)
}
// isNewDefine returns true if node refers to a new definition
@@ -1735,13 +1879,20 @@ func compositeGenerator(n *node) (gen bltnGenerator) {
return
}
// compositeArrayLen return the litteral array length, computed from definition
func compositeArrayLen(n *node) int {
// arrayTypeLen returns the node's array length. If the expression is an
// array variable it is determined from the value's type, otherwise it is
// computed from the source definition.
func arrayTypeLen(n *node) int {
if n.typ != nil && n.typ.sizedef {
return n.typ.size
}
max := -1
for i, c := range n.child[1:] {
r := i
if c.kind == keyValueExpr {
r = int(c.child[0].rval.Int())
if v := c.child[0].rval; v.IsValid() {
r = int(c.child[0].rval.Int())
}
}
if r > max {
max = r
@@ -1749,3 +1900,13 @@ func compositeArrayLen(n *node) int {
}
return max + 1
}
// isValueUntyped returns true if value is untyped
func isValueUntyped(v reflect.Value) bool {
// Consider only constant values.
if v.CanSet() {
return false
}
t := v.Type()
return t.String() == t.Kind().String()
}

View File

@@ -1,10 +1,47 @@
/*
Package interp provides a complete Go interpreter
Package interp provides a complete Go interpreter.
For the Go language itself, refer to the official Go specification
https://golang.org/ref/spec.
Importing packages
Packages can be imported in source or binary form, using the standard
Go import statement. In source form, packages are searched first in the
vendor directory, the preferred way to store source dependencies. If not
found in vendor, sources modules will be searched in GOPATH. Go modules
are not supported yet by yaegi.
Binary form packages are compiled and linked with the interpreter
executable, and exposed to scripts with the Use method. The goexports
command can be used to generate package wrappers.
Custom build tags
Custom build tags allow to control which files in imported source
packages are interpreted, in the same way as the "-tags" option of the
"go build" command. Setting a custom build tag spans globally for all
future imports of the session.
A build tag is a line comment that begins
// yaegi:tags
that lists the build constraints to be satisfied by the further
imports of source packages.
For example the following custom build tag
// yaegi:tags noasm
Will ensure that an import of a package will exclude files containing
// +build !noasm
And include files containing
// +build noasm
*/
package interp
// BUG(marc): Type checking is not implemented yet
// BUG(marc): Type checking is not implemented yet.

View File

@@ -38,7 +38,7 @@ func (n *node) astDot(out io.Writer, name string) {
func (n *node) cfgDot(out io.Writer) {
fmt.Fprintf(out, "digraph cfg {\n")
n.Walk(nil, func(n *node) {
if n.kind == basicLit || n.kind == identExpr || n.tnext == nil {
if n.kind == basicLit || n.tnext == nil {
return
}
var label string

View File

@@ -1,7 +1,6 @@
package interp
import (
"path"
"reflect"
)
@@ -31,6 +30,7 @@ func (interp *Interpreter) gta(root *node, rpath string) ([]*node, error) {
case defineStmt:
var atyp *itype
if n.nleft+n.nright < len(n.child) {
// Type is declared explicitly in the assign expression.
if atyp, err = nodeType(interp, sc, n.child[n.nleft]); err != nil {
return false
}
@@ -126,7 +126,7 @@ func (interp *Interpreter) gta(root *node, rpath string) ([]*node, error) {
name = n.child[0].ident
} else {
ipath = n.child[0].rval.String()
name = path.Base(ipath)
name = identifier.FindString(ipath)
}
// Try to import a binary package first, or a source package
if interp.binPkg[ipath] != nil {

View File

@@ -2,13 +2,18 @@ package interp
import (
"bufio"
"context"
"fmt"
"go/build"
"go/scanner"
"go/token"
"io"
"os"
"os/signal"
"reflect"
"strconv"
"sync"
"sync/atomic"
)
// Interpreter node structure for AST and CFG
@@ -20,7 +25,7 @@ type node struct {
fnext *node // false branch successor (CFG)
interp *Interpreter // interpreter context
frame *frame // frame pointer used for closures only (TODO: suppress this)
index int // node index (dot display)
index int64 // node index (dot display)
findex int // index of value in frame or frame size (func def, type def)
level int // number of frame indirections to access value
nleft int // number of children in left part (assign)
@@ -48,10 +53,45 @@ type receiver struct {
// frame contains values for the current execution level (a function context)
type frame struct {
anc *frame // ancestor frame (global space)
data []reflect.Value // values
deferred [][]reflect.Value // defer stack
recovered interface{} // to handle panic recover
// id is an atomic counter used for cancellation, only access
// via newFrame/runid/setrunid/clone.
// Located at start of struct to ensure proper aligment.
id uint64
anc *frame // ancestor frame (global space)
data []reflect.Value // values
mutex sync.RWMutex
deferred [][]reflect.Value // defer stack
recovered interface{} // to handle panic recover
done reflect.SelectCase // for cancellation of channel operations
}
func newFrame(anc *frame, len int, id uint64) *frame {
f := &frame{
anc: anc,
data: make([]reflect.Value, len),
id: id,
}
if anc != nil {
f.done = anc.done
}
return f
}
func (f *frame) runid() uint64 { return atomic.LoadUint64(&f.id) }
func (f *frame) setrunid(id uint64) { atomic.StoreUint64(&f.id, id) }
func (f *frame) clone() *frame {
f.mutex.RLock()
defer f.mutex.RUnlock()
return &frame{
anc: f.anc,
data: f.data,
deferred: f.deferred,
recovered: f.recovered,
id: f.runid(),
done: f.done,
}
}
// Exports stores the map of binary packages per package path
@@ -62,24 +102,36 @@ type imports map[string]map[string]*symbol
// opt stores interpreter options
type opt struct {
astDot bool // display AST graph (debug)
cfgDot bool // display CFG graph (debug)
noRun bool // compile, but do not run
context build.Context // build context: GOPATH, build constraints
astDot bool // display AST graph (debug)
cfgDot bool // display CFG graph (debug)
noRun bool // compile, but do not run
fastChan bool // disable cancellable chan operations
context build.Context // build context: GOPATH, build constraints
}
// Interpreter contains global resources and state
type Interpreter struct {
// id is an atomic counter counter used for run cancellation,
// only accessed via runid/stop
// Located at start of struct to ensure proper alignment on 32 bit
// architectures.
id uint64
Name string // program name
opt
opt // user settable options
cancelChan bool // enables cancellable chan operations
nindex int64 // next node index
fset *token.FileSet // fileset to locate node in source code
binPkg Exports // binary packages used in interpreter, indexed by path
rdir map[string]bool // for src import cycle detection
mutex sync.RWMutex
frame *frame // program data storage during execution
nindex int // next node index
fset *token.FileSet // fileset to locate node in source code
universe *scope // interpreter global level scope
scopes map[string]*scope // package level scopes, indexed by package name
binPkg Exports // binary packages used in interpreter, indexed by path
srcPkg imports // source packages used in interpreter, indexed by path
rdir map[string]bool // for src import cycle detection
done chan struct{} // for cancellation of channel operations
}
const (
@@ -146,15 +198,17 @@ func New(options Options) *Interpreter {
i.opt.context.BuildTags = options.BuildTags
}
// AstDot activates AST graph display for the interpreter
// astDot activates AST graph display for the interpreter
i.opt.astDot, _ = strconv.ParseBool(os.Getenv("YAEGI_AST_DOT"))
// CfgDot activates AST graph display for the interpreter
// cfgDot activates AST graph display for the interpreter
i.opt.cfgDot, _ = strconv.ParseBool(os.Getenv("YAEGI_CFG_DOT"))
// NoRun disable the execution (but not the compilation) in the interpreter
// noRun disables the execution (but not the compilation) in the interpreter
i.opt.noRun, _ = strconv.ParseBool(os.Getenv("YAEGI_NO_RUN"))
// fastChan disables the cancellable version of channel operations in evalWithContext
i.opt.fastChan, _ = strconv.ParseBool(os.Getenv("YAEGI_FAST_CHAN"))
return &i
}
@@ -227,6 +281,8 @@ 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 {
return m.sym[mainID].node
}
@@ -277,11 +333,13 @@ func (interp *Interpreter) Eval(src string) (reflect.Value, error) {
// REPL may skip package statement
setExec(root.start)
}
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.universe.sym[pkgName] = &symbol{kind: pkgSym, typ: &itype{cat: srcPkgT, path: pkgName}}
}
interp.mutex.Unlock()
if interp.cfgDot {
root.cfgDot(dotX())
@@ -291,11 +349,18 @@ func (interp *Interpreter) Eval(src string) (reflect.Value, error) {
return res, err
}
// Execute CFG
// Generate node exec closures
if err = genRun(root); err != nil {
return res, err
}
// Init interpreter execution memory frame
interp.frame.setrunid(interp.runid())
interp.frame.mutex.Lock()
interp.resizeFrame()
interp.frame.mutex.Unlock()
// Execute node closures
interp.run(root, nil)
for _, n := range initNodes {
@@ -314,6 +379,42 @@ func (interp *Interpreter) Eval(src string) (reflect.Value, error) {
return res, err
}
// EvalWithContext evaluates Go code represented as a string. It returns
// a map on current interpreted package exported symbols.
func (interp *Interpreter) EvalWithContext(ctx context.Context, src string) (reflect.Value, error) {
var v reflect.Value
var err error
interp.mutex.Lock()
interp.done = make(chan struct{})
interp.cancelChan = !interp.opt.fastChan
interp.mutex.Unlock()
done := make(chan struct{})
go func() {
defer close(done)
v, err = interp.Eval(src)
}()
select {
case <-ctx.Done():
interp.stop()
return reflect.Value{}, ctx.Err()
case <-done:
return v, err
}
}
// stop sends a semaphore to all running frames and closes the chan
// operation short circuit channel. stop may only be called once per
// invocation of EvalWithContext.
func (interp *Interpreter) stop() {
atomic.AddUint64(&interp.id, 1)
close(interp.done)
}
func (interp *Interpreter) runid() uint64 { return atomic.LoadUint64(&interp.id) }
// getWrapper returns the wrapper type of the corresponding interface, or nil if not found
func (interp *Interpreter) getWrapper(t reflect.Type) reflect.Type {
if p, ok := interp.binPkg[t.PkgPath()]; ok {
@@ -330,16 +431,21 @@ func (interp *Interpreter) Use(values Exports) {
}
}
// Repl performs a Read-Eval-Print-Loop on input file descriptor.
// Results are printed on output.
func (interp *Interpreter) Repl(in, out *os.File) {
// REPL performs a Read-Eval-Print-Loop on input reader.
// Results are printed on output writer.
func (interp *Interpreter) REPL(in io.Reader, out io.Writer) {
s := bufio.NewScanner(in)
prompt := getPrompt(in, out)
prompt()
src := ""
for s.Scan() {
src += s.Text() + "\n"
if v, err := interp.Eval(src); err != nil {
ctx, cancel := context.WithCancel(context.Background())
defer cancel()
handleSignal(ctx, cancel)
v, err := interp.EvalWithContext(ctx, src)
signal.Reset()
if err != nil {
switch err.(type) {
case scanner.ErrorList:
// Early failure in the scanner: the source is incomplete
@@ -357,10 +463,35 @@ func (interp *Interpreter) Repl(in, out *os.File) {
}
}
// getPrompt returns a function which prints a prompt only if input is a terminal
func getPrompt(in, out *os.File) func() {
if stat, err := in.Stat(); err == nil && stat.Mode()&os.ModeCharDevice != 0 {
// Repl performs a Read-Eval-Print-Loop on input file descriptor.
// Results are printed on output.
// Deprecated: use REPL instead
func (interp *Interpreter) Repl(in, out *os.File) {
interp.REPL(in, out)
}
// getPrompt returns a function which prints a prompt only if input is a terminal.
func getPrompt(in io.Reader, out io.Writer) func() {
s, ok := in.(interface{ Stat() (os.FileInfo, error) })
if !ok {
return func() {}
}
stat, err := s.Stat()
if err == nil && stat.Mode()&os.ModeCharDevice != 0 {
return func() { fmt.Fprint(out, "> ") }
}
return func() {}
}
// handleSignal wraps signal handling for eval cancellation.
func handleSignal(ctx context.Context, cancel context.CancelFunc) {
c := make(chan os.Signal, 1)
signal.Notify(c, os.Interrupt)
go func() {
select {
case <-c:
cancel()
case <-ctx.Done():
}
}()
}

View File

@@ -35,6 +35,8 @@ func TestInterpConsistencyBuild(t *testing.T) {
file.Name() == "bad0.go" || // expect error
file.Name() == "export1.go" || // non-main package
file.Name() == "export0.go" || // non-main package
file.Name() == "for7.go" || // expect error
file.Name() == "if2.go" || // expect error
file.Name() == "import6.go" || // expect error
file.Name() == "io0.go" || // use random number
file.Name() == "op1.go" || // expect error
@@ -104,7 +106,7 @@ func TestInterpConsistencyBuild(t *testing.T) {
bin := filepath.Join(dir, strings.TrimSuffix(file.Name(), ".go"))
cmdBuild := exec.Command("go", "build", "-o", bin, filePath)
cmdBuild := exec.Command("go", "build", "-tags=dummy", "-o", bin, filePath)
outBuild, err := cmdBuild.CombinedOutput()
if err != nil {
t.Log(string(outBuild))
@@ -136,6 +138,16 @@ func TestInterpErrorConsistency(t *testing.T) {
expectedInterp: "1:1: expected 'package', found println",
expectedExec: "1:1: expected 'package', found println",
},
{
fileName: "if2.go",
expectedInterp: "7:5: non-bool used as if condition",
expectedExec: "7:2: non-bool i % 1000000 (type int) used as if condition",
},
{
fileName: "for7.go",
expectedInterp: "4:14: non-bool used as for condition",
expectedExec: "4:2: non-bool i (type int) used as for condition",
},
{
fileName: "op1.go",
expectedInterp: "5:2: illegal operand types for '+=' operator",

View File

@@ -1,6 +1,7 @@
package interp_test
import (
"context"
"fmt"
"log"
"net/http"
@@ -41,16 +42,22 @@ func TestEvalArithmetic(t *testing.T) {
{desc: "mul_II", src: "2 * 3", res: "6"},
{desc: "mul_FI", src: "2.2 * 3", res: "6.6000000000000005"},
{desc: "mul_IF", src: "3 * 2.2", res: "6.6000000000000005"},
{desc: "rem_FI", src: "8.0 % 4", err: "1:28: illegal operand types for '%' operator"},
{desc: "rem_FI", src: "8.2 % 4", err: "1:28: illegal operand types for '%' operator"},
{desc: "shl_II", src: "1 << 8", res: "256"},
{desc: "shl_IN", src: "1 << -1", err: "1:28: illegal operand types for '<<' operator"},
{desc: "shl_IF", src: "1 << 1.0", res: "2"},
{desc: "shl_IF1", src: "1 << 1.1", err: "1:28: illegal operand types for '<<' operator"},
{desc: "shl_IF", src: "1.0 << 1", res: "2"},
{desc: "shl_IF2", src: "1.0 << 1", res: "2"},
{desc: "shr_II", src: "1 >> 8", res: "0"},
{desc: "shr_IN", src: "1 >> -1", err: "1:28: illegal operand types for '>>' operator"},
{desc: "shr_IF", src: "1 >> 1.0", res: "0"},
{desc: "shr_IF1", src: "1 >> 1.1", err: "1:28: illegal operand types for '>>' operator"},
{desc: "neg_I", src: "-2", res: "-2"},
{desc: "pos_I", src: "+2", res: "2"},
{desc: "bitnot_I", src: "^2", res: "-3"},
{desc: "bitnot_F", src: "^0.2", err: "1:28: illegal operand type for '^' operator"},
{desc: "not_B", src: "!false", res: "true"},
{desc: "not_I", src: "!0", err: "1:28: illegal operand type for '!' operator"},
})
}
@@ -60,7 +67,7 @@ func TestEvalAssign(t *testing.T) {
{src: `a := "Hello"; a += " world"`, res: "Hello world"},
{src: `b := "Hello"; b += 1`, err: "1:42: illegal operand types for '+=' operator"},
{src: `c := "Hello"; c -= " world"`, err: "1:42: illegal operand types for '-=' operator"},
{src: "e := 64.0; e %= 64", err: "1:39: illegal operand types for '%=' operator"},
{src: "e := 64.4; e %= 64", err: "1:39: illegal operand types for '%=' operator"},
{src: "f := int64(3.2)", err: "1:33: truncated to integer"},
{src: "g := 1; g <<= 8", res: "256"},
{src: "h := 1; h >>= 8", res: "0"},
@@ -155,6 +162,14 @@ func TestEvalNil(t *testing.T) {
src: "Hello()",
res: "<nil>",
},
{
desc: "return nil func",
pre: func() {
eval(t, i, `func Bar() func() { return nil }`)
},
src: "Bar()",
res: "<nil>",
},
})
}
@@ -396,6 +411,100 @@ func TestEvalMissingSymbol(t *testing.T) {
}
}
func TestEvalWithContext(t *testing.T) {
tests := []testCase{
{
desc: "for {}",
src: `(func() {
for {}
})()`,
},
{
desc: "select {}",
src: `(func() {
select {}
})()`,
},
{
desc: "blocked chan send",
src: `(func() {
c := make(chan int)
c <- 1
})()`,
},
{
desc: "blocked chan recv",
src: `(func() {
c := make(chan int)
<-c
})()`,
},
{
desc: "blocked chan recv2",
src: `(func() {
c := make(chan int)
_, _ = <-c
})()`,
},
{
desc: "blocked range chan",
src: `(func() {
c := make(chan int)
for range c {}
})()`,
},
{
desc: "double lock",
src: `(func() {
var mu sync.Mutex
mu.Lock()
mu.Lock()
})()`,
},
}
for _, test := range tests {
done := make(chan struct{})
src := test.src
go func() {
defer close(done)
i := interp.New(interp.Options{})
i.Use(stdlib.Symbols)
_, err := i.Eval(`import "sync"`)
if err != nil {
t.Errorf(`failed to import "sync": %v`, err)
return
}
ctx, cancel := context.WithTimeout(context.Background(), 100*time.Millisecond)
defer cancel()
_, err = i.EvalWithContext(ctx, src)
switch err {
case context.DeadlineExceeded:
// Successful cancellation.
// Check we can still execute an expression.
v, err := i.EvalWithContext(context.Background(), "1+1\n") //nolint:govet
if err != nil {
t.Errorf("failed to evaluate expression after cancellation: %v", err)
}
got := v.Interface()
if got != 2 {
t.Errorf("unexpected result of eval(1+1): got %v, want 2", got)
}
case nil:
t.Errorf("unexpected success evaluating expression %q", test.desc)
default:
t.Errorf("failed to evaluate expression %q: %v", test.desc, err)
}
}()
select {
case <-time.After(time.Second):
t.Errorf("timeout failed to terminate execution of %q", test.desc)
case <-done:
}
}
}
func runTests(t *testing.T, i *interp.Interpreter, tests []testCase) {
for _, test := range tests {
t.Run(test.desc, func(t *testing.T) {

View File

@@ -1,6 +1,6 @@
package interp
// Code generated by 'go run ../cmd/genop/genop.go'. DO NOT EDIT.
// Code generated by 'go run ../internal/genop/genop.go'. DO NOT EDIT.
import "reflect"
@@ -1864,6 +1864,57 @@ func inc(n *node) {
}
}
func bitNotConst(n *node) {
t := n.typ.rtype
v := n.child[0].rval
n.rval = reflect.New(t).Elem()
switch t.Kind() {
case reflect.Int, reflect.Int8, reflect.Int16, reflect.Int32, reflect.Int64:
n.rval.SetInt(^v.Int())
case reflect.Uint, reflect.Uint8, reflect.Uint16, reflect.Uint32, reflect.Uint64, reflect.Uintptr:
n.rval.SetUint(^v.Uint())
}
}
func negConst(n *node) {
t := n.typ.rtype
v := n.child[0].rval
n.rval = reflect.New(t).Elem()
switch t.Kind() {
case reflect.Int, reflect.Int8, reflect.Int16, reflect.Int32, reflect.Int64:
n.rval.SetInt(-v.Int())
case reflect.Uint, reflect.Uint8, reflect.Uint16, reflect.Uint32, reflect.Uint64, reflect.Uintptr:
n.rval.SetUint(-v.Uint())
case reflect.Float32, reflect.Float64:
n.rval.SetFloat(-v.Float())
case reflect.Complex64, reflect.Complex128:
n.rval.SetComplex(-v.Complex())
}
}
func notConst(n *node) {
t := n.typ.rtype
v := n.child[0].rval
n.rval = reflect.New(t).Elem()
n.rval.SetBool(!v.Bool())
}
func posConst(n *node) {
t := n.typ.rtype
v := n.child[0].rval
n.rval = reflect.New(t).Elem()
switch t.Kind() {
case reflect.Int, reflect.Int8, reflect.Int16, reflect.Int32, reflect.Int64:
n.rval.SetInt(+v.Int())
case reflect.Uint, reflect.Uint8, reflect.Uint16, reflect.Uint32, reflect.Uint64, reflect.Uintptr:
n.rval.SetUint(+v.Uint())
case reflect.Float32, reflect.Float64:
n.rval.SetFloat(+v.Float())
case reflect.Complex64, reflect.Complex128:
n.rval.SetComplex(+v.Complex())
}
}
func equal(n *node) {
tnext := getExec(n.tnext)
dest := genValue(n)
@@ -1938,146 +1989,6 @@ func equal(n *node) {
}
}
}
case isComplex(t0) || isComplex(t1):
switch {
case c0.rval.IsValid():
s0 := vComplex(c0.rval)
v1 := genValueComplex(c1)
if n.fnext != nil {
fnext := getExec(n.fnext)
n.exec = func(f *frame) bltn {
_, s1 := v1(f)
if s0 == s1 {
dest(f).SetBool(true)
return tnext
}
dest(f).SetBool(false)
return fnext
}
} else {
n.exec = func(f *frame) bltn {
_, s1 := v1(f)
dest(f).SetBool(s0 == s1)
return tnext
}
}
case c1.rval.IsValid():
s1 := vComplex(c1.rval)
v0 := genValueComplex(c0)
if n.fnext != nil {
fnext := getExec(n.fnext)
n.exec = func(f *frame) bltn {
_, s0 := v0(f)
if s0 == s1 {
dest(f).SetBool(true)
return tnext
}
dest(f).SetBool(false)
return fnext
}
} else {
dest := genValue(n)
n.exec = func(f *frame) bltn {
_, s0 := v0(f)
dest(f).SetBool(s0 == s1)
return tnext
}
}
default:
v0 := genValueComplex(n.child[0])
v1 := genValueComplex(n.child[1])
if n.fnext != nil {
fnext := getExec(n.fnext)
n.exec = func(f *frame) bltn {
_, s0 := v0(f)
_, s1 := v1(f)
if s0 == s1 {
dest(f).SetBool(true)
return tnext
}
dest(f).SetBool(false)
return fnext
}
} else {
n.exec = func(f *frame) bltn {
_, s0 := v0(f)
_, s1 := v1(f)
dest(f).SetBool(s0 == s1)
return tnext
}
}
}
default:
switch {
case c0.rval.IsValid():
i0 := c0.rval.Interface()
v1 := genValue(c1)
if n.fnext != nil {
fnext := getExec(n.fnext)
n.exec = func(f *frame) bltn {
i1 := v1(f).Interface()
if i0 == i1 {
dest(f).SetBool(true)
return tnext
}
dest(f).SetBool(false)
return fnext
}
} else {
dest := genValue(n)
n.exec = func(f *frame) bltn {
i1 := v1(f).Interface()
dest(f).SetBool(i0 == i1)
return tnext
}
}
case c1.rval.IsValid():
i1 := c1.rval.Interface()
v0 := genValue(c0)
if n.fnext != nil {
fnext := getExec(n.fnext)
n.exec = func(f *frame) bltn {
i0 := v0(f).Interface()
if i0 == i1 {
dest(f).SetBool(true)
return tnext
}
dest(f).SetBool(false)
return fnext
}
} else {
dest := genValue(n)
n.exec = func(f *frame) bltn {
i0 := v0(f).Interface()
dest(f).SetBool(i0 == i1)
return tnext
}
}
default:
v0 := genValue(c0)
v1 := genValue(c1)
if n.fnext != nil {
fnext := getExec(n.fnext)
n.exec = func(f *frame) bltn {
i0 := v0(f).Interface()
i1 := v1(f).Interface()
if i0 == i1 {
dest(f).SetBool(true)
return tnext
}
dest(f).SetBool(false)
return fnext
}
} else {
dest := genValue(n)
n.exec = func(f *frame) bltn {
i0 := v0(f).Interface()
i1 := v1(f).Interface()
dest(f).SetBool(i0 == i1)
return tnext
}
}
}
case isFloat(t0) || isFloat(t1):
switch {
case c0.rval.IsValid():
@@ -2290,6 +2201,146 @@ func equal(n *node) {
}
}
}
case isComplex(t0) || isComplex(t1):
switch {
case c0.rval.IsValid():
s0 := vComplex(c0.rval)
v1 := genComplex(c1)
if n.fnext != nil {
fnext := getExec(n.fnext)
n.exec = func(f *frame) bltn {
s1 := v1(f)
if s0 == s1 {
dest(f).SetBool(true)
return tnext
}
dest(f).SetBool(false)
return fnext
}
} else {
n.exec = func(f *frame) bltn {
s1 := v1(f)
dest(f).SetBool(s0 == s1)
return tnext
}
}
case c1.rval.IsValid():
s1 := vComplex(c1.rval)
v0 := genComplex(c0)
if n.fnext != nil {
fnext := getExec(n.fnext)
n.exec = func(f *frame) bltn {
s0 := v0(f)
if s0 == s1 {
dest(f).SetBool(true)
return tnext
}
dest(f).SetBool(false)
return fnext
}
} else {
dest := genValue(n)
n.exec = func(f *frame) bltn {
s0 := v0(f)
dest(f).SetBool(s0 == s1)
return tnext
}
}
default:
v0 := genComplex(n.child[0])
v1 := genComplex(n.child[1])
if n.fnext != nil {
fnext := getExec(n.fnext)
n.exec = func(f *frame) bltn {
s0 := v0(f)
s1 := v1(f)
if s0 == s1 {
dest(f).SetBool(true)
return tnext
}
dest(f).SetBool(false)
return fnext
}
} else {
n.exec = func(f *frame) bltn {
s0 := v0(f)
s1 := v1(f)
dest(f).SetBool(s0 == s1)
return tnext
}
}
}
default:
switch {
case c0.rval.IsValid():
i0 := c0.rval.Interface()
v1 := genValue(c1)
if n.fnext != nil {
fnext := getExec(n.fnext)
n.exec = func(f *frame) bltn {
i1 := v1(f).Interface()
if i0 == i1 {
dest(f).SetBool(true)
return tnext
}
dest(f).SetBool(false)
return fnext
}
} else {
dest := genValue(n)
n.exec = func(f *frame) bltn {
i1 := v1(f).Interface()
dest(f).SetBool(i0 == i1)
return tnext
}
}
case c1.rval.IsValid():
i1 := c1.rval.Interface()
v0 := genValue(c0)
if n.fnext != nil {
fnext := getExec(n.fnext)
n.exec = func(f *frame) bltn {
i0 := v0(f).Interface()
if i0 == i1 {
dest(f).SetBool(true)
return tnext
}
dest(f).SetBool(false)
return fnext
}
} else {
dest := genValue(n)
n.exec = func(f *frame) bltn {
i0 := v0(f).Interface()
dest(f).SetBool(i0 == i1)
return tnext
}
}
default:
v0 := genValue(c0)
v1 := genValue(c1)
if n.fnext != nil {
fnext := getExec(n.fnext)
n.exec = func(f *frame) bltn {
i0 := v0(f).Interface()
i1 := v1(f).Interface()
if i0 == i1 {
dest(f).SetBool(true)
return tnext
}
dest(f).SetBool(false)
return fnext
}
} else {
dest := genValue(n)
n.exec = func(f *frame) bltn {
i0 := v0(f).Interface()
i1 := v1(f).Interface()
dest(f).SetBool(i0 == i1)
return tnext
}
}
}
}
}
@@ -3523,146 +3574,6 @@ func notEqual(n *node) {
}
}
}
case isComplex(t0) || isComplex(t1):
switch {
case c0.rval.IsValid():
s0 := vComplex(c0.rval)
v1 := genValueComplex(c1)
if n.fnext != nil {
fnext := getExec(n.fnext)
n.exec = func(f *frame) bltn {
_, s1 := v1(f)
if s0 != s1 {
dest(f).SetBool(true)
return tnext
}
dest(f).SetBool(false)
return fnext
}
} else {
n.exec = func(f *frame) bltn {
_, s1 := v1(f)
dest(f).SetBool(s0 != s1)
return tnext
}
}
case c1.rval.IsValid():
s1 := vComplex(c1.rval)
v0 := genValueComplex(c0)
if n.fnext != nil {
fnext := getExec(n.fnext)
n.exec = func(f *frame) bltn {
_, s0 := v0(f)
if s0 != s1 {
dest(f).SetBool(true)
return tnext
}
dest(f).SetBool(false)
return fnext
}
} else {
dest := genValue(n)
n.exec = func(f *frame) bltn {
_, s0 := v0(f)
dest(f).SetBool(s0 != s1)
return tnext
}
}
default:
v0 := genValueComplex(n.child[0])
v1 := genValueComplex(n.child[1])
if n.fnext != nil {
fnext := getExec(n.fnext)
n.exec = func(f *frame) bltn {
_, s0 := v0(f)
_, s1 := v1(f)
if s0 != s1 {
dest(f).SetBool(true)
return tnext
}
dest(f).SetBool(false)
return fnext
}
} else {
n.exec = func(f *frame) bltn {
_, s0 := v0(f)
_, s1 := v1(f)
dest(f).SetBool(s0 != s1)
return tnext
}
}
}
default:
switch {
case c0.rval.IsValid():
i0 := c0.rval.Interface()
v1 := genValue(c1)
if n.fnext != nil {
fnext := getExec(n.fnext)
n.exec = func(f *frame) bltn {
i1 := v1(f).Interface()
if i0 != i1 {
dest(f).SetBool(true)
return tnext
}
dest(f).SetBool(false)
return fnext
}
} else {
dest := genValue(n)
n.exec = func(f *frame) bltn {
i1 := v1(f).Interface()
dest(f).SetBool(i0 != i1)
return tnext
}
}
case c1.rval.IsValid():
i1 := c1.rval.Interface()
v0 := genValue(c0)
if n.fnext != nil {
fnext := getExec(n.fnext)
n.exec = func(f *frame) bltn {
i0 := v0(f).Interface()
if i0 != i1 {
dest(f).SetBool(true)
return tnext
}
dest(f).SetBool(false)
return fnext
}
} else {
dest := genValue(n)
n.exec = func(f *frame) bltn {
i0 := v0(f).Interface()
dest(f).SetBool(i0 != i1)
return tnext
}
}
default:
v0 := genValue(c0)
v1 := genValue(c1)
if n.fnext != nil {
fnext := getExec(n.fnext)
n.exec = func(f *frame) bltn {
i0 := v0(f).Interface()
i1 := v1(f).Interface()
if i0 != i1 {
dest(f).SetBool(true)
return tnext
}
dest(f).SetBool(false)
return fnext
}
} else {
dest := genValue(n)
n.exec = func(f *frame) bltn {
i0 := v0(f).Interface()
i1 := v1(f).Interface()
dest(f).SetBool(i0 != i1)
return tnext
}
}
}
case isFloat(t0) || isFloat(t1):
switch {
case c0.rval.IsValid():
@@ -3875,5 +3786,145 @@ func notEqual(n *node) {
}
}
}
case isComplex(t0) || isComplex(t1):
switch {
case c0.rval.IsValid():
s0 := vComplex(c0.rval)
v1 := genComplex(c1)
if n.fnext != nil {
fnext := getExec(n.fnext)
n.exec = func(f *frame) bltn {
s1 := v1(f)
if s0 != s1 {
dest(f).SetBool(true)
return tnext
}
dest(f).SetBool(false)
return fnext
}
} else {
n.exec = func(f *frame) bltn {
s1 := v1(f)
dest(f).SetBool(s0 != s1)
return tnext
}
}
case c1.rval.IsValid():
s1 := vComplex(c1.rval)
v0 := genComplex(c0)
if n.fnext != nil {
fnext := getExec(n.fnext)
n.exec = func(f *frame) bltn {
s0 := v0(f)
if s0 != s1 {
dest(f).SetBool(true)
return tnext
}
dest(f).SetBool(false)
return fnext
}
} else {
dest := genValue(n)
n.exec = func(f *frame) bltn {
s0 := v0(f)
dest(f).SetBool(s0 != s1)
return tnext
}
}
default:
v0 := genComplex(n.child[0])
v1 := genComplex(n.child[1])
if n.fnext != nil {
fnext := getExec(n.fnext)
n.exec = func(f *frame) bltn {
s0 := v0(f)
s1 := v1(f)
if s0 != s1 {
dest(f).SetBool(true)
return tnext
}
dest(f).SetBool(false)
return fnext
}
} else {
n.exec = func(f *frame) bltn {
s0 := v0(f)
s1 := v1(f)
dest(f).SetBool(s0 != s1)
return tnext
}
}
}
default:
switch {
case c0.rval.IsValid():
i0 := c0.rval.Interface()
v1 := genValue(c1)
if n.fnext != nil {
fnext := getExec(n.fnext)
n.exec = func(f *frame) bltn {
i1 := v1(f).Interface()
if i0 != i1 {
dest(f).SetBool(true)
return tnext
}
dest(f).SetBool(false)
return fnext
}
} else {
dest := genValue(n)
n.exec = func(f *frame) bltn {
i1 := v1(f).Interface()
dest(f).SetBool(i0 != i1)
return tnext
}
}
case c1.rval.IsValid():
i1 := c1.rval.Interface()
v0 := genValue(c0)
if n.fnext != nil {
fnext := getExec(n.fnext)
n.exec = func(f *frame) bltn {
i0 := v0(f).Interface()
if i0 != i1 {
dest(f).SetBool(true)
return tnext
}
dest(f).SetBool(false)
return fnext
}
} else {
dest := genValue(n)
n.exec = func(f *frame) bltn {
i0 := v0(f).Interface()
dest(f).SetBool(i0 != i1)
return tnext
}
}
default:
v0 := genValue(c0)
v1 := genValue(c1)
if n.fnext != nil {
fnext := getExec(n.fnext)
n.exec = func(f *frame) bltn {
i0 := v0(f).Interface()
i1 := v1(f).Interface()
if i0 != i1 {
dest(f).SetBool(true)
return tnext
}
dest(f).SetBool(false)
return fnext
}
} else {
dest := genValue(n)
n.exec = func(f *frame) bltn {
i0 := v0(f).Interface()
i1 := v1(f).Interface()
dest(f).SetBool(i0 != i1)
return tnext
}
}
}
}
}

View File

@@ -24,6 +24,7 @@ var builtin = [...]bltnGenerator{
aAndAssign: andAssign,
aAndNot: andNot,
aAndNotAssign: andNotAssign,
aBitNot: bitNot,
aCall: call,
aCase: _case,
aCompositeLit: arrayLit,
@@ -40,11 +41,12 @@ var builtin = [...]bltnGenerator{
aLowerEqual: lowerEqual,
aMul: mul,
aMulAssign: mulAssign,
aNegate: negate,
aNeg: neg,
aNot: not,
aNotEqual: notEqual,
aOr: or,
aOrAssign: orAssign,
aPos: pos,
aQuo: quo,
aQuoAssign: quoAssign,
aRange: _range,
@@ -84,8 +86,11 @@ func (interp *Interpreter) run(n *node, cf *frame) {
if cf == nil {
f = interp.frame
} else {
f = &frame{anc: cf, data: make([]reflect.Value, len(n.types))}
f = newFrame(cf, len(n.types), interp.runid())
}
interp.mutex.RLock()
f.done = reflect.SelectCase{Dir: reflect.SelectRecv, Chan: reflect.ValueOf(interp.done)}
interp.mutex.RUnlock()
for i, t := range n.types {
f.data[i] = reflect.New(t).Elem()
@@ -98,42 +103,76 @@ func (interp *Interpreter) run(n *node, cf *frame) {
// runCfg executes a node AST by walking its CFG and running node builtin at each step
func runCfg(n *node, f *frame) {
defer func() {
f.mutex.Lock()
f.recovered = recover()
for _, val := range f.deferred {
val[0].Call(val[1:])
}
if f.recovered != nil {
fmt.Println(n.cfgErrorf("panic"))
f.mutex.Unlock()
panic(f.recovered)
}
f.mutex.Unlock()
}()
for exec := n.exec; exec != nil; {
for exec := n.exec; exec != nil && f.runid() == n.interp.runid(); {
exec = exec(f)
}
}
func typeAssert(n *node) {
value := genValue(n.child[0])
i := n.findex
func typeAssertStatus(n *node) {
value := genValue(n.child[0]) // input value
value1 := genValue(n.anc.child[1]) // returned status
next := getExec(n.tnext)
switch {
case n.child[0].typ.cat == valueT:
n.exec = func(f *frame) bltn {
f.data[i].Set(value(f).Elem())
if !value(f).IsValid() || value(f).IsNil() {
value1(f).SetBool(false)
}
value1(f).SetBool(true)
return next
}
case n.child[1].typ.cat == interfaceT:
n.exec = func(f *frame) bltn {
_, ok := value(f).Interface().(valueInterface)
//value0(f).Set(reflect.ValueOf(valueInterface{v.node, v.value}))
value1(f).SetBool(ok)
return next
}
default:
n.exec = func(f *frame) bltn {
_, ok := value(f).Interface().(valueInterface)
//value0(f).Set(v.value)
value1(f).SetBool(ok)
return next
}
}
}
func typeAssert(n *node) {
value := genValue(n.child[0]) // input value
dest := genValue(n) // returned result
next := getExec(n.tnext)
switch {
case n.child[0].typ.cat == valueT:
n.exec = func(f *frame) bltn {
dest(f).Set(value(f).Elem())
return next
}
case n.child[1].typ.cat == interfaceT:
n.exec = func(f *frame) bltn {
v := value(f).Interface().(valueInterface)
f.data[i] = reflect.ValueOf(valueInterface{v.node, v.value})
dest(f).Set(reflect.ValueOf(valueInterface{v.node, v.value}))
return next
}
default:
n.exec = func(f *frame) bltn {
v := value(f).Interface().(valueInterface)
f.data[i].Set(v.value)
dest(f).Set(v.value)
return next
}
}
@@ -202,7 +241,7 @@ func isRecursiveStruct(t *itype, rtype reflect.Type) bool {
if t.cat == structT && rtype.Kind() == reflect.Interface {
return true
}
if t.cat == ptrT {
if t.cat == ptrT && t.rtype != nil {
return isRecursiveStruct(t.val, t.rtype.Elem())
}
return false
@@ -223,15 +262,21 @@ func assign(n *node) {
switch {
case dest.typ.cat == interfaceT:
svalue[i] = genValueInterface(src)
case dest.typ.cat == valueT && dest.typ.rtype.Kind() == reflect.Interface:
case (dest.typ.cat == valueT || dest.typ.cat == errorT) && dest.typ.rtype.Kind() == reflect.Interface:
svalue[i] = genInterfaceWrapper(src, dest.typ.rtype)
case dest.typ.cat == valueT && src.typ.cat == funcT:
svalue[i] = genFunctionWrapper(src)
case dest.typ.cat == funcT && src.typ.cat == valueT:
svalue[i] = genValueNode(src)
case src.kind == basicLit && src.val == nil:
t := dest.typ.TypeOf()
svalue[i] = func(*frame) reflect.Value { return reflect.New(t).Elem() }
case isRecursiveStruct(dest.typ, dest.typ.rtype):
svalue[i] = genValueInterfacePtr(src)
case src.typ.untyped && isComplex(dest.typ.TypeOf()):
svalue[i] = genValueComplex(src)
case src.typ.untyped && !dest.typ.untyped:
svalue[i] = genValueAs(src, dest.typ.TypeOf())
default:
svalue[i] = genValue(src)
}
@@ -297,21 +342,24 @@ func assign(n *node) {
}
func not(n *node) {
dest := genValue(n)
value := genValue(n.child[0])
tnext := getExec(n.tnext)
i := n.findex
if n.fnext != nil {
fnext := getExec(n.fnext)
n.exec = func(f *frame) bltn {
if !value(f).Bool() {
f.data[i].SetBool(true)
return tnext
}
f.data[i].SetBool(false)
return fnext
}
} else {
i := n.findex
n.exec = func(f *frame) bltn {
f.data[i].SetBool(!value(f).Bool())
dest(f).SetBool(!value(f).Bool())
return tnext
}
}
@@ -416,6 +464,10 @@ func _panic(n *node) {
func genFunctionWrapper(n *node) func(*frame) reflect.Value {
var def *node
var ok bool
if n.kind == basicLit {
return func(f *frame) reflect.Value { return n.rval }
}
if def, ok = n.val.(*node); !ok {
return genValueAsFunctionWrapper(n)
}
@@ -438,7 +490,7 @@ func genFunctionWrapper(n *node) func(*frame) reflect.Value {
}
return reflect.MakeFunc(n.typ.TypeOf(), func(in []reflect.Value) []reflect.Value {
// Allocate and init local frame. All values to be settable and addressable.
fr := frame{anc: f, data: make([]reflect.Value, len(def.types))}
fr := newFrame(f, len(def.types), f.runid())
d := fr.data
for i, t := range def.types {
d[i] = reflect.New(t).Elem()
@@ -467,7 +519,7 @@ func genFunctionWrapper(n *node) func(*frame) reflect.Value {
}
// Interpreter code execution
runCfg(start, &fr)
runCfg(start, fr)
result := fr.data[:numRet]
for i, r := range result {
@@ -611,7 +663,7 @@ func call(n *node) {
values = append(values, func(f *frame) reflect.Value { return f.data[ind] })
}
default:
if c.kind == basicLit {
if c.kind == basicLit || c.rval.IsValid() {
var argType reflect.Type
if variadic >= 0 && i >= variadic {
argType = n.child[0].typ.arg[variadic].val.TypeOf()
@@ -647,12 +699,35 @@ func call(n *node) {
n.exec = func(f *frame) bltn {
def := value(f).Interface().(*node)
// Call bin func if defined
if def.rval.IsValid() {
in := make([]reflect.Value, len(values))
for i, v := range values {
in[i] = v(f)
}
if goroutine {
go def.rval.Call(in)
return tnext
}
out := def.rval.Call(in)
for i, v := range rvalues {
if v != nil {
v(f).Set(out[i])
}
}
if fnext != nil && !out[0].Bool() {
return fnext
}
return tnext
}
anc := f
// Get closure frame context (if any)
if def.frame != nil {
anc = def.frame
}
nf := frame{anc: anc, data: make([]reflect.Value, len(def.types))}
nf := newFrame(anc, len(def.types), anc.runid())
var vararg reflect.Value
// Init return values
@@ -717,10 +792,10 @@ func call(n *node) {
// Execute function body
if goroutine {
go runCfg(def.child[3].start, &nf)
go runCfg(def.child[3].start, nf)
return tnext
}
runCfg(def.child[3].start, &nf)
runCfg(def.child[3].start, nf)
// Handle branching according to boolean result
if fnext != nil && !nf.data[0].Bool() {
@@ -773,7 +848,7 @@ func callBin(n *node) {
values = append(values, func(f *frame) reflect.Value { return f.data[ind] })
}
default:
if c.kind == basicLit {
if c.kind == basicLit || c.rval.IsValid() {
// Convert literal value (untyped) to function argument type (if not an interface{})
var argType reflect.Type
if variadic >= 0 && i >= variadic {
@@ -1022,10 +1097,10 @@ func getFunc(n *node) {
next := getExec(n.tnext)
n.exec = func(f *frame) bltn {
fr := *f
fr := f.clone()
nod := *n
nod.val = &nod
nod.frame = &fr
nod.frame = fr
dest(f).Set(reflect.ValueOf(&nod))
return next
}
@@ -1036,11 +1111,11 @@ func getMethod(n *node) {
next := getExec(n.tnext)
n.exec = func(f *frame) bltn {
fr := *f
fr := f.clone()
nod := *(n.val.(*node))
nod.val = &nod
nod.recv = n.recv
nod.frame = &fr
nod.frame = fr
f.data[i] = reflect.ValueOf(&nod)
return next
}
@@ -1055,11 +1130,11 @@ func getMethodByName(n *node) {
n.exec = func(f *frame) bltn {
val := value0(f).Interface().(valueInterface)
m, li := val.node.typ.lookupMethod(name)
fr := *f
fr := f.clone()
nod := *m
nod.val = &nod
nod.recv = &receiver{nil, val.value, li}
nod.frame = &fr
nod.frame = fr
f.data[i] = reflect.ValueOf(&nod)
return next
}
@@ -1176,7 +1251,7 @@ func getIndexSeqMethod(n *node) {
}
}
func negate(n *node) {
func neg(n *node) {
dest := genValue(n)
value := genValue(n.child[0])
next := getExec(n.tnext)
@@ -1200,6 +1275,37 @@ func negate(n *node) {
}
}
func pos(n *node) {
dest := genValue(n)
value := genValue(n.child[0])
next := getExec(n.tnext)
n.exec = func(f *frame) bltn {
dest(f).Set(value(f))
return next
}
}
func bitNot(n *node) {
dest := genValue(n)
value := genValue(n.child[0])
next := getExec(n.tnext)
typ := n.typ.TypeOf()
switch typ.Kind() {
case reflect.Int, reflect.Int8, reflect.Int16, reflect.Int32, reflect.Int64:
n.exec = func(f *frame) bltn {
dest(f).SetInt(^value(f).Int())
return next
}
case reflect.Uint, reflect.Uint8, reflect.Uint16, reflect.Uint32, reflect.Uint64, reflect.Uintptr:
n.exec = func(f *frame) bltn {
dest(f).SetUint(^value(f).Uint())
return next
}
}
}
func land(n *node) {
value0 := genValue(n.child[0])
value1 := genValue(n.child[1])
@@ -1284,10 +1390,16 @@ func _return(n *node) {
} else {
values[i] = genValue(c)
}
case funcT:
values[i] = genValue(c)
case interfaceT:
values[i] = genValueInterface(c)
default:
values[i] = genValue(c)
if c.typ.untyped {
values[i] = genValueAs(c, def.typ.ret[i].TypeOf())
} else {
values[i] = genValue(c)
}
}
}
@@ -1351,7 +1463,7 @@ func arrayLit(n *node) {
}
var a reflect.Value
if n.typ.size > 0 {
if n.typ.sizedef {
a, _ = n.typ.zero()
} else {
a = reflect.MakeSlice(n.typ.TypeOf(), max, max)
@@ -1460,6 +1572,15 @@ func compositeBinStruct(n *node) {
}
}
func destType(n *node) *itype {
switch n.anc.kind {
case assignStmt, defineStmt:
return n.anc.child[0].typ
default:
return n.typ
}
}
// compositeLit creates and populates a struct object
func compositeLit(n *node) {
value := valueGenerator(n, n.findex)
@@ -1468,6 +1589,7 @@ func compositeLit(n *node) {
if !n.typ.untyped {
child = n.child[1:]
}
destInterface := destType(n).cat == interfaceT
values := make([]func(*frame) reflect.Value, len(child))
for i, c := range child {
@@ -1484,9 +1606,12 @@ func compositeLit(n *node) {
for i, v := range values {
a.Field(i).Set(v(f))
}
if d := value(f); d.Type().Kind() == reflect.Ptr {
switch d := value(f); {
case d.Type().Kind() == reflect.Ptr:
d.Set(a.Addr())
} else {
case destInterface:
d.Set(reflect.ValueOf(valueInterface{n, a}))
default:
d.Set(a)
}
return next
@@ -1534,6 +1659,7 @@ var rat = reflect.ValueOf((*[]rune)(nil)).Type().Elem() // runes array type
func _range(n *node) {
index0 := n.child[0].findex // array index location in frame
index2 := index0 - 1 // shallow array for range, always just behind index0
fnext := getExec(n.fnext)
tnext := getExec(n.tnext)
@@ -1544,10 +1670,10 @@ func _range(n *node) {
if isString(an.typ.TypeOf()) {
value = genValueAs(an, rat) // range on string iterates over runes
} else {
value = genValueArray(an)
value = genValueRangeArray(an)
}
n.exec = func(f *frame) bltn {
a := value(f)
a := f.data[index2]
v0 := f.data[index0]
v0.SetInt(v0.Int() + 1)
i := int(v0.Int())
@@ -1562,13 +1688,12 @@ func _range(n *node) {
if isString(an.typ.TypeOf()) {
value = genValueAs(an, rat) // range on string iterates over runes
} else {
value = genValueArray(an)
value = genValueRangeArray(an)
}
n.exec = func(f *frame) bltn {
a := value(f)
v0 := f.data[index0]
v0.SetInt(v0.Int() + 1)
if int(v0.Int()) >= a.Len() {
if int(v0.Int()) >= f.data[index2].Len() {
return fnext
}
return tnext
@@ -1578,7 +1703,8 @@ func _range(n *node) {
// Init sequence
next := n.exec
n.child[0].exec = func(f *frame) bltn {
f.data[index0].SetInt(-1)
f.data[index2] = value(f) // set array shallow copy for range
f.data[index0].SetInt(-1) // assing index value
return next
}
}
@@ -1590,7 +1716,10 @@ func rangeChan(n *node) {
tnext := getExec(n.tnext)
n.exec = func(f *frame) bltn {
v, ok := value(f).Recv()
chosen, v, ok := reflect.Select([]reflect.SelectCase{f.done, {Dir: reflect.SelectRecv, Chan: value(f)}})
if chosen == 0 {
return nil
}
if !ok {
return fnext
}
@@ -1600,31 +1729,40 @@ func rangeChan(n *node) {
}
func rangeMap(n *node) {
index0 := n.child[0].findex // array index location in frame
index1 := n.child[1].findex // array value location in frame
value := genValue(n.child[2]) // array
index0 := n.child[0].findex // map index location in frame
index2 := index0 - 1 // iterator for range, always just behind index0
fnext := getExec(n.fnext)
tnext := getExec(n.tnext)
// TODO: move i and keys to frame
var i int
var keys []reflect.Value
n.exec = func(f *frame) bltn {
a := value(f)
i++
if i >= a.Len() {
return fnext
var value func(*frame) reflect.Value
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
}
f.data[index0].Set(iter.Key())
f.data[index1].Set(iter.Value())
return tnext
}
} else {
value = genValue(n.child[1]) // map
n.exec = func(f *frame) bltn {
iter := f.data[index2].Interface().(*reflect.MapIter)
if !iter.Next() {
return fnext
}
f.data[index0].Set(iter.Key())
return tnext
}
f.data[index0].Set(keys[i])
f.data[index1].Set(a.MapIndex(keys[i]))
return tnext
}
// Init sequence
next := n.exec
n.child[0].exec = func(f *frame) bltn {
keys = value(f).MapKeys()
i = -1
f.data[index2].Set(reflect.ValueOf(value(f).MapRange()))
return next
}
}
@@ -1757,7 +1895,6 @@ func appendSlice(n *node) {
return next
}
}
}
func _append(n *node) {
@@ -1845,39 +1982,48 @@ func _close(n *node) {
}
func _complex(n *node) {
i := n.findex
convertLiteralValue(n.child[1], floatType)
convertLiteralValue(n.child[2], floatType)
value0 := genValue(n.child[1])
value1 := genValue(n.child[2])
dest := genValue(n)
c1, c2 := n.child[1], n.child[2]
convertLiteralValue(c1, floatType)
convertLiteralValue(c2, floatType)
value0 := genValue(c1)
value1 := genValue(c2)
next := getExec(n.tnext)
n.exec = func(f *frame) bltn {
f.data[i].SetComplex(complex(value0(f).Float(), value1(f).Float()))
return next
if typ := n.typ.TypeOf(); isComplex(typ) {
n.exec = func(f *frame) bltn {
dest(f).SetComplex(complex(value0(f).Float(), value1(f).Float()))
return next
}
} else {
// Not a complex type: ignore imaginary part
n.exec = func(f *frame) bltn {
dest(f).Set(value0(f).Convert(typ))
return next
}
}
}
func _imag(n *node) {
i := n.findex
dest := genValue(n)
convertLiteralValue(n.child[1], complexType)
value := genValue(n.child[1])
next := getExec(n.tnext)
n.exec = func(f *frame) bltn {
f.data[i].SetFloat(imag(value(f).Complex()))
dest(f).SetFloat(imag(value(f).Complex()))
return next
}
}
func _real(n *node) {
i := n.findex
dest := genValue(n)
convertLiteralValue(n.child[1], complexType)
value := genValue(n.child[1])
next := getExec(n.tnext)
n.exec = func(f *frame) bltn {
f.data[i].SetFloat(real(value(f).Complex()))
dest(f).SetFloat(real(value(f).Complex()))
return next
}
}
@@ -1895,12 +2041,12 @@ func _delete(n *node) {
}
func _len(n *node) {
i := n.findex
dest := genValue(n)
value := genValue(n.child[1])
next := getExec(n.tnext)
n.exec = func(f *frame) bltn {
f.data[i].SetInt(int64(value(f).Len()))
dest(f).SetInt(int64(value(f).Len()))
return next
}
}
@@ -2014,19 +2160,63 @@ func recv(n *node) {
value := genValue(n.child[0])
tnext := getExec(n.tnext)
if n.fnext != nil {
fnext := getExec(n.fnext)
n.exec = func(f *frame) bltn {
if v, _ := value(f).Recv(); v.Bool() {
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() {
return tnext
}
return fnext
}
// Slow: channel read blocks, allow cancel
chosen, v, _ := reflect.Select([]reflect.SelectCase{f.done, {Dir: reflect.SelectRecv, Chan: ch}})
if chosen == 0 {
return nil
}
if v.Bool() {
return tnext
}
return fnext
}
} else {
i := n.findex
n.exec = func(f *frame) bltn {
// Fast: channel read doesn't block
var ok bool
ch := value(f)
if f.data[i], ok = ch.TryRecv(); ok {
return tnext
}
// Slow: channel is blocked, allow cancel
var chosen int
chosen, f.data[i], _ = reflect.Select([]reflect.SelectCase{f.done, {Dir: reflect.SelectRecv, Chan: ch}})
if chosen == 0 {
return nil
}
return tnext
}
return fnext
}
} else {
i := n.findex
n.exec = func(f *frame) bltn {
f.data[i], _ = value(f).Recv()
return tnext
// Blocking channel read (less overhead)
if n.fnext != nil {
fnext := getExec(n.fnext)
n.exec = func(f *frame) bltn {
if v, _ := value(f).Recv(); v.Bool() {
return tnext
}
return fnext
}
} else {
i := n.findex
n.exec = func(f *frame) bltn {
f.data[i], _ = value(f).Recv()
return tnext
}
}
}
}
@@ -2037,22 +2227,47 @@ func recv2(n *node) {
vok := genValue(n.anc.child[1]) // status
tnext := getExec(n.tnext)
n.exec = func(f *frame) bltn {
v, ok := vchan(f).Recv()
vres(f).Set(v)
vok(f).SetBool(ok)
return tnext
if n.interp.cancelChan {
// Cancellable channel read
n.exec = func(f *frame) bltn {
ch, result, status := vchan(f), vres(f), vok(f)
// Fast: channel read doesn't block
if v, ok := ch.TryRecv(); ok {
result.Set(v)
status.SetBool(true)
return tnext
}
// Slow: channel is blocked, allow cancel
chosen, v, ok := reflect.Select([]reflect.SelectCase{f.done, {Dir: reflect.SelectRecv, Chan: ch}})
if chosen == 0 {
return nil
}
result.Set(v)
status.SetBool(ok)
return tnext
}
} else {
// Blocking channel read (less overhead)
n.exec = func(f *frame) bltn {
v, ok := vchan(f).Recv()
vres(f).Set(v)
vok(f).SetBool(ok)
return tnext
}
}
}
func convertLiteralValue(n *node, t reflect.Type) {
if n.kind != basicLit || t == nil || t.Kind() == reflect.Interface {
// Skip non-constant values, undefined target type or interface target type.
if !(n.kind == basicLit || n.rval.IsValid()) || t == nil || t.Kind() == reflect.Interface {
return
}
if n.rval.IsValid() {
// Convert constant value to target type.
n.rval = n.rval.Convert(t)
} else {
n.rval = reflect.New(t).Elem() // convert to type nil value
// Create a zero value of target type.
n.rval = reflect.New(t).Elem()
}
}
@@ -2063,9 +2278,27 @@ func send(n *node) {
convertLiteralValue(n.child[1], n.child[0].typ.val.TypeOf())
value1 := genValue(n.child[1]) // value to send
n.exec = func(f *frame) bltn {
value0(f).Send(value1(f))
return next
if n.interp.cancelChan {
// Cancellable send
n.exec = func(f *frame) bltn {
ch, data := value0(f), value1(f)
// Fast: send on channel doesn't block
if ok := ch.TrySend(data); ok {
return next
}
// Slow: send on channel blocks, allow cancel
chosen, _, _ := reflect.Select([]reflect.SelectCase{f.done, {Dir: reflect.SelectSend, Chan: ch, Send: data}})
if chosen == 0 {
return nil
}
return next
}
} else {
// Blocking send (less overhead)
n.exec = func(f *frame) bltn {
value0(f).Send(value1(f))
return next
}
}
}
@@ -2107,7 +2340,7 @@ func _select(n *node) {
chanValues := make([]func(*frame) reflect.Value, nbClause)
assignedValues := make([]func(*frame) reflect.Value, nbClause)
okValues := make([]func(*frame) reflect.Value, nbClause)
cases := make([]reflect.SelectCase, nbClause)
cases := make([]reflect.SelectCase, nbClause+1)
for i := 0; i < nbClause; i++ {
if len(n.child[i].child) > 1 {
@@ -2127,7 +2360,8 @@ func _select(n *node) {
}
n.exec = func(f *frame) bltn {
for i := range cases {
cases[nbClause] = f.done
for i := range cases[:nbClause] {
switch cases[i].Dir {
case reflect.SelectRecv:
cases[i].Chan = chanValues[i](f)
@@ -2139,6 +2373,9 @@ func _select(n *node) {
}
}
j, v, s := reflect.Select(cases)
if j == nbClause {
return nil
}
if cases[j].Dir == reflect.SelectRecv && assignedValues[j] != nil {
assignedValues[j](f).Set(v)
if ok[j] != nil {
@@ -2215,43 +2452,78 @@ func slice0(n *node) {
}
func isNil(n *node) {
value := genValue(n.child[0])
var value func(*frame) reflect.Value
if n.child[0].typ.cat == funcT {
value = genValueAsFunctionWrapper(n.child[0])
} else {
value = genValue(n.child[0])
}
tnext := getExec(n.tnext)
dest := genValue(n)
if n.fnext != nil {
fnext := getExec(n.fnext)
n.exec = func(f *frame) bltn {
if value(f).IsNil() {
dest(f).SetBool(true)
return tnext
}
dest(f).SetBool(false)
return fnext
}
} else {
i := n.findex
n.exec = func(f *frame) bltn {
f.data[i].SetBool(value(f).IsNil())
dest(f).SetBool(value(f).IsNil())
return tnext
}
}
}
func isNotNil(n *node) {
value := genValue(n.child[0])
var value func(*frame) reflect.Value
if n.child[0].typ.cat == funcT {
value = genValueAsFunctionWrapper(n.child[0])
} else {
value = genValue(n.child[0])
}
tnext := getExec(n.tnext)
dest := genValue(n)
if n.fnext != nil {
fnext := getExec(n.fnext)
n.exec = func(f *frame) bltn {
if value(f).IsNil() {
dest(f).SetBool(false)
return fnext
}
dest(f).SetBool(true)
return tnext
}
} else {
i := n.findex
n.exec = func(f *frame) bltn {
f.data[i].SetBool(!value(f).IsNil())
dest(f).SetBool(!value(f).IsNil())
return tnext
}
}
}
func complexConst(n *node) {
if v0, v1 := n.child[1].rval, n.child[2].rval; v0.IsValid() && v1.IsValid() {
n.rval = reflect.ValueOf(complex(vFloat(v0), vFloat(v1)))
n.gen = nop
}
}
func imagConst(n *node) {
if v := n.child[1].rval; v.IsValid() {
n.rval = reflect.ValueOf(imag(v.Complex()))
n.gen = nop
}
}
func realConst(n *node) {
if v := n.child[1].rval; v.IsValid() {
n.rval = reflect.ValueOf(real(v.Complex()))
n.gen = nop
}
}

View File

@@ -164,10 +164,11 @@ func (interp *Interpreter) initScopePkg(n *node) (*scope, string) {
pkgName = p.child[0].ident
}
interp.mutex.Lock()
if _, ok := interp.scopes[pkgName]; !ok {
interp.scopes[pkgName] = sc.pushBloc()
}
sc = interp.scopes[pkgName]
interp.mutex.Unlock()
return sc, pkgName
}

View File

@@ -49,7 +49,7 @@ func (interp *Interpreter) importSrc(rPath, path, alias string) error {
// Parse source files
for _, file := range files {
name := file.Name()
if skipFile(interp.context, name) {
if skipFile(&interp.context, name) {
continue
}
@@ -102,6 +102,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
@@ -110,7 +111,10 @@ func (interp *Interpreter) importSrc(rPath, path, alias string) error {
delete(interp.scopes, pkgName)
}
interp.frame.mutex.Lock()
interp.resizeFrame()
interp.frame.mutex.Unlock()
interp.mutex.Unlock()
// Once all package sources have been parsed, execute entry points then init functions
for _, n := range rootNodes {

View File

@@ -123,10 +123,11 @@ type itype struct {
// nodeType returns a type definition for the corresponding AST subtree
func nodeType(interp *Interpreter, sc *scope, n *node) (*itype, error) {
var err cfgError
if n.typ != nil && !n.typ.incomplete {
return n.typ, err
if n.kind == sliceExpr {
n.typ.sizedef = false
}
return n.typ, nil
}
var t = &itype{node: n, scope: sc}
@@ -141,6 +142,7 @@ func nodeType(interp *Interpreter, sc *scope, n *node) (*itype, error) {
}
}
var err cfgError
switch n.kind {
case addressExpr, starExpr:
t.cat = ptrT
@@ -158,7 +160,7 @@ func nodeType(interp *Interpreter, sc *scope, n *node) (*itype, error) {
t.size = int(n.child[0].rval.Int())
case n.child[0].kind == ellipsisExpr:
// [...]T expression
t.sizedef = true
t.size = arrayTypeLen(n.anc)
default:
if sym, _, ok := sc.lookup(n.child[0].ident); ok {
// Resolve symbol to get size value
@@ -182,6 +184,7 @@ func nodeType(interp *Interpreter, sc *scope, n *node) (*itype, error) {
if t.val, err = nodeType(interp, sc, n.child[1]); err != nil {
return nil, err
}
t.sizedef = true
t.incomplete = t.incomplete || t.val.incomplete
} else {
if t.val, err = nodeType(interp, sc, n.child[0]); err != nil {
@@ -285,6 +288,9 @@ func nodeType(interp *Interpreter, sc *scope, n *node) (*itype, error) {
default:
err = n.cfgErrorf("invalid types %s and %s", t0.Kind(), t1.Kind())
}
if nt0.untyped && nt1.untyped {
t.untyped = true
}
}
case "real", "imag":
if t, err = nodeType(interp, sc, n.child[1]); err != nil {
@@ -297,7 +303,7 @@ func nodeType(interp *Interpreter, sc *scope, n *node) (*itype, error) {
case k == reflect.Complex128:
t = sc.getType("float64")
case t.untyped && isNumber(t.TypeOf()):
t = &itype{cat: valueT, rtype: floatType}
t = &itype{cat: valueT, rtype: floatType, untyped: true}
default:
err = n.cfgErrorf("invalid complex type %s", k)
}
@@ -395,6 +401,9 @@ func nodeType(interp *Interpreter, sc *scope, n *node) (*itype, error) {
t.method = m
sym.typ = t
}
if t.node == nil {
t.node = n
}
} else {
t.incomplete = true
sc.sym[n.ident] = &symbol{kind: typeSym, typ: t}
@@ -483,6 +492,18 @@ func nodeType(interp *Interpreter, sc *scope, n *node) (*itype, error) {
}
}
case sliceExpr:
t, err = nodeType(interp, sc, n.child[0])
if t.cat == ptrT {
t = t.val
}
if err == nil && t.size != 0 {
t1 := *t
t1.size = 0
t1.rtype = nil
t = &t1
}
case structType:
t.cat = structT
var incomplete bool
@@ -618,6 +639,74 @@ func (t *itype) finalize() (*itype, error) {
return t, err
}
// Equals returns true if the given type is identical to the receiver one.
func (t *itype) equals(o *itype) bool {
switch ti, oi := isInterface(t), isInterface(o); {
case ti && oi:
return t.methods().equals(o.methods())
case ti && !oi:
return o.methods().contains(t.methods())
case oi && !ti:
return t.methods().contains(o.methods())
default:
return t.id() == o.id()
}
}
// MethodSet defines the set of methods signatures as strings, indexed per method name.
type methodSet map[string]string
// Contains returns true if the method set m contains the method set n.
func (m methodSet) contains(n methodSet) bool {
for k, v := range n {
if m[k] != v {
return false
}
}
return true
}
// Equal returns true if the method set m is equal to the method set n.
func (m methodSet) equals(n methodSet) bool {
return m.contains(n) && n.contains(m)
}
// Methods returns a map of method type strings, indexed by method names.
func (t *itype) methods() methodSet {
res := make(methodSet)
switch t.cat {
case interfaceT:
// Get methods from recursive analysis of interface fields
for _, f := range t.field {
if f.typ.cat == funcT {
res[f.name] = f.typ.TypeOf().String()
} else {
for k, v := range f.typ.methods() {
res[k] = v
}
}
}
case valueT, errorT:
// Get method from corresponding reflect.Type
for i := t.rtype.NumMethod() - 1; i >= 0; i-- {
m := t.rtype.Method(i)
res[m.Name] = m.Type.String()
}
case ptrT:
// Consider only methods where receiver is a pointer to type t
for _, m := range t.val.method {
if m.child[0].child[0].lastChild().typ.cat == ptrT {
res[m.ident] = m.typ.TypeOf().String()
}
}
default:
for _, m := range t.method {
res[m.ident] = m.typ.TypeOf().String()
}
}
return res
}
// id returns a unique type identificator string
func (t *itype) id() string {
// TODO: if res is nil, build identity from String()
@@ -796,14 +885,16 @@ func (t *itype) refType(defined map[string]bool) reflect.Type {
panic(err)
}
}
if t.val != nil && defined[t.val.name] {
if t.val != nil && defined[t.val.name] && !t.val.incomplete && t.val.rtype == nil {
// Replace reference to self (direct or indirect) by an interface{} to handle
// recursive types with reflect.
t.val.rtype = interf
}
switch t.cat {
case aliasT:
t.rtype = t.val.refType(defined)
case arrayT, variadicT:
if t.size > 0 {
if t.sizedef {
t.rtype = reflect.ArrayOf(t.size, t.val.refType(defined))
} else {
t.rtype = reflect.SliceOf(t.val.refType(defined))
@@ -816,15 +907,9 @@ func (t *itype) refType(defined map[string]bool) reflect.Type {
in := make([]reflect.Type, len(t.arg))
out := make([]reflect.Type, len(t.ret))
for i, v := range t.arg {
if defined[v.name] {
v.rtype = interf
}
in[i] = v.refType(defined)
}
for i, v := range t.ret {
if defined[v.name] {
v.rtype = interf
}
out[i] = v.refType(defined)
}
t.rtype = reflect.FuncOf(in, out, false)
@@ -866,7 +951,7 @@ func (t *itype) frameType() (r reflect.Type) {
case aliasT:
r = t.val.frameType()
case arrayT, variadicT:
if t.size > 0 {
if t.sizedef {
r = reflect.ArrayOf(t.size, t.val.frameType())
} else {
r = reflect.SliceOf(t.val.frameType())
@@ -915,7 +1000,13 @@ func isInterface(t *itype) bool {
return isInterfaceSrc(t) || t.TypeOf().Kind() == reflect.Interface
}
func isStruct(t *itype) bool { return t.TypeOf().Kind() == reflect.Struct }
func isStruct(t *itype) bool {
// Test first for a struct category, because a recursive interpreter struct may be
// represented by an interface{} at reflect level.
return t.cat == structT || t.TypeOf().Kind() == reflect.Struct
}
func isBool(t *itype) bool { return t.TypeOf().Kind() == reflect.Bool }
func isInt(t reflect.Type) bool {
switch t.Kind() {

View File

@@ -7,21 +7,31 @@ import (
func valueGenerator(n *node, i int) func(*frame) reflect.Value {
switch n.level {
case 0:
return func(f *frame) reflect.Value { return f.data[i] }
return func(f *frame) reflect.Value { return valueOf(f.data, i) }
case 1:
return func(f *frame) reflect.Value { return f.anc.data[i] }
return func(f *frame) reflect.Value { return valueOf(f.anc.data, i) }
case 2:
return func(f *frame) reflect.Value { return f.anc.anc.data[i] }
return func(f *frame) reflect.Value { return valueOf(f.anc.anc.data, i) }
default:
return func(f *frame) reflect.Value {
for level := n.level; level > 0; level-- {
f = f.anc
}
return f.data[i]
return valueOf(f.data, i)
}
}
}
// valueOf safely recovers the ith element of data. This is necessary
// because a cancellation prior to any evaluation result may leave
// the frame's data empty.
func valueOf(data []reflect.Value, i int) reflect.Value {
if i < len(data) {
return data[i]
}
return reflect.Value{}
}
func genValueRecvIndirect(n *node) func(*frame) reflect.Value {
v := genValueRecv(n)
return func(f *frame) reflect.Value { return v(f).Elem() }
@@ -45,9 +55,15 @@ func genValueRecv(n *node) func(*frame) reflect.Value {
}
func genValueAsFunctionWrapper(n *node) func(*frame) reflect.Value {
v := genValue(n)
value := genValue(n)
typ := n.typ.TypeOf()
return func(f *frame) reflect.Value {
return genFunctionWrapper(v(f).Interface().(*node))(f)
v := value(f)
if v.IsNil() {
return reflect.New(typ).Elem()
}
return genFunctionWrapper(v.Interface().(*node))(f)
}
}
@@ -118,6 +134,22 @@ func genValueArray(n *node) func(*frame) reflect.Value {
return value
}
func genValueRangeArray(n *node) func(*frame) reflect.Value {
value := genValue(n)
// dereference array pointer, to support array operations on array pointer
if n.typ.TypeOf().Kind() == reflect.Ptr {
return func(f *frame) reflect.Value {
return value(f).Elem()
}
}
return func(f *frame) reflect.Value {
// This is necessary to prevent changes in the returned
// reflect.Value being reflected back to the value used
// for the range expression.
return reflect.ValueOf(value(f).Interface())
}
}
func genValueInterfacePtr(n *node) func(*frame) reflect.Value {
value := genValue(n)
it := reflect.TypeOf((*interface{})(nil)).Elem()
@@ -133,7 +165,18 @@ func genValueInterface(n *node) func(*frame) reflect.Value {
value := genValue(n)
return func(f *frame) reflect.Value {
return reflect.ValueOf(valueInterface{n, value(f)})
v := value(f)
nod := n
for {
// traverse interface indirections to find out concrete type
vi, ok := v.Interface().(valueInterface)
if !ok {
break
}
v = vi.value
nod = vi.node
}
return reflect.ValueOf(valueInterface{nod, v})
}
}
@@ -145,6 +188,14 @@ func genValueInterfaceValue(n *node) func(*frame) reflect.Value {
}
}
func genValueNode(n *node) func(*frame) reflect.Value {
value := genValue(n)
return func(f *frame) reflect.Value {
return reflect.ValueOf(&node{rval: value(f)})
}
}
func vInt(v reflect.Value) (i int64) {
switch v.Type().Kind() {
case reflect.Int, reflect.Int8, reflect.Int16, reflect.Int32, reflect.Int64:
@@ -153,6 +204,8 @@ func vInt(v reflect.Value) (i int64) {
i = int64(v.Uint())
case reflect.Float32, reflect.Float64:
i = int64(v.Float())
case reflect.Complex64, reflect.Complex128:
i = int64(real(v.Complex()))
}
return
}
@@ -165,6 +218,8 @@ func vUint(v reflect.Value) (i uint64) {
i = v.Uint()
case reflect.Float32, reflect.Float64:
i = uint64(v.Float())
case reflect.Complex64, reflect.Complex128:
i = uint64(real(v.Complex()))
}
return
}
@@ -191,6 +246,8 @@ func vFloat(v reflect.Value) (i float64) {
i = float64(v.Uint())
case reflect.Float32, reflect.Float64:
i = v.Float()
case reflect.Complex64, reflect.Complex128:
i = real(v.Complex())
}
return
}
@@ -205,6 +262,10 @@ func genValueInt(n *node) func(*frame) (reflect.Value, int64) {
return func(f *frame) (reflect.Value, int64) { v := value(f); return v, int64(v.Uint()) }
case reflect.Float32, reflect.Float64:
return func(f *frame) (reflect.Value, int64) { v := value(f); return v, int64(v.Float()) }
case reflect.Complex64, reflect.Complex128:
if n.typ.untyped && n.rval.IsValid() && imag(n.rval.Complex()) == 0 {
return func(f *frame) (reflect.Value, int64) { v := value(f); return v, int64(real(v.Complex())) }
}
}
return nil
}
@@ -219,6 +280,10 @@ func genValueUint(n *node) func(*frame) (reflect.Value, uint64) {
return func(f *frame) (reflect.Value, uint64) { v := value(f); return v, v.Uint() }
case reflect.Float32, reflect.Float64:
return func(f *frame) (reflect.Value, uint64) { v := value(f); return v, uint64(v.Float()) }
case reflect.Complex64, reflect.Complex128:
if n.typ.untyped && n.rval.IsValid() && imag(n.rval.Complex()) == 0 {
return func(f *frame) (reflect.Value, uint64) { v := value(f); return v, uint64(real(v.Complex())) }
}
}
return nil
}
@@ -233,22 +298,31 @@ func genValueFloat(n *node) func(*frame) (reflect.Value, float64) {
return func(f *frame) (reflect.Value, float64) { v := value(f); return v, float64(v.Uint()) }
case reflect.Float32, reflect.Float64:
return func(f *frame) (reflect.Value, float64) { v := value(f); return v, v.Float() }
case reflect.Complex64, reflect.Complex128:
if n.typ.untyped && n.rval.IsValid() && imag(n.rval.Complex()) == 0 {
return func(f *frame) (reflect.Value, float64) { v := value(f); return v, real(v.Complex()) }
}
}
return nil
}
func genValueComplex(n *node) func(*frame) (reflect.Value, complex128) {
func genValueComplex(n *node) func(*frame) reflect.Value {
vc := genComplex(n)
return func(f *frame) reflect.Value { return reflect.ValueOf(vc(f)) }
}
func genComplex(n *node) func(*frame) complex128 {
value := genValue(n)
switch n.typ.TypeOf().Kind() {
case reflect.Int, reflect.Int8, reflect.Int16, reflect.Int32, reflect.Int64:
return func(f *frame) (reflect.Value, complex128) { v := value(f); return v, complex(float64(v.Int()), 0) }
return func(f *frame) complex128 { return complex(float64(value(f).Int()), 0) }
case reflect.Uint, reflect.Uint8, reflect.Uint16, reflect.Uint32, reflect.Uint64, reflect.Uintptr:
return func(f *frame) (reflect.Value, complex128) { v := value(f); return v, complex(float64(v.Uint()), 0) }
return func(f *frame) complex128 { return complex(float64(value(f).Uint()), 0) }
case reflect.Float32, reflect.Float64:
return func(f *frame) (reflect.Value, complex128) { v := value(f); return v, complex(v.Float(), 0) }
return func(f *frame) complex128 { return complex(value(f).Float(), 0) }
case reflect.Complex64, reflect.Complex128:
return func(f *frame) (reflect.Value, complex128) { v := value(f); return v, v.Complex() }
return func(f *frame) complex128 { return value(f).Complex() }
}
return nil
}

View File

@@ -1,47 +0,0 @@
// Code generated by 'goexports archive/tar'. DO NOT EDIT.
// +build go1.11,!go1.12
package stdlib
import (
"archive/tar"
"reflect"
)
func init() {
Symbols["archive/tar"] = map[string]reflect.Value{
// function, constant and variable definitions
"ErrFieldTooLong": reflect.ValueOf(&tar.ErrFieldTooLong).Elem(),
"ErrHeader": reflect.ValueOf(&tar.ErrHeader).Elem(),
"ErrWriteAfterClose": reflect.ValueOf(&tar.ErrWriteAfterClose).Elem(),
"ErrWriteTooLong": reflect.ValueOf(&tar.ErrWriteTooLong).Elem(),
"FileInfoHeader": reflect.ValueOf(tar.FileInfoHeader),
"FormatGNU": reflect.ValueOf(tar.FormatGNU),
"FormatPAX": reflect.ValueOf(tar.FormatPAX),
"FormatUSTAR": reflect.ValueOf(tar.FormatUSTAR),
"FormatUnknown": reflect.ValueOf(tar.FormatUnknown),
"NewReader": reflect.ValueOf(tar.NewReader),
"NewWriter": reflect.ValueOf(tar.NewWriter),
"TypeBlock": reflect.ValueOf(tar.TypeBlock),
"TypeChar": reflect.ValueOf(tar.TypeChar),
"TypeCont": reflect.ValueOf(tar.TypeCont),
"TypeDir": reflect.ValueOf(tar.TypeDir),
"TypeFifo": reflect.ValueOf(tar.TypeFifo),
"TypeGNULongLink": reflect.ValueOf(tar.TypeGNULongLink),
"TypeGNULongName": reflect.ValueOf(tar.TypeGNULongName),
"TypeGNUSparse": reflect.ValueOf(tar.TypeGNUSparse),
"TypeLink": reflect.ValueOf(tar.TypeLink),
"TypeReg": reflect.ValueOf(tar.TypeReg),
"TypeRegA": reflect.ValueOf(tar.TypeRegA),
"TypeSymlink": reflect.ValueOf(tar.TypeSymlink),
"TypeXGlobalHeader": reflect.ValueOf(tar.TypeXGlobalHeader),
"TypeXHeader": reflect.ValueOf(tar.TypeXHeader),
// type definitions
"Format": reflect.ValueOf((*tar.Format)(nil)),
"Header": reflect.ValueOf((*tar.Header)(nil)),
"Reader": reflect.ValueOf((*tar.Reader)(nil)),
"Writer": reflect.ValueOf((*tar.Writer)(nil)),
}
}

View File

@@ -1,36 +0,0 @@
// Code generated by 'goexports archive/zip'. DO NOT EDIT.
// +build go1.11,!go1.12
package stdlib
import (
"archive/zip"
"reflect"
)
func init() {
Symbols["archive/zip"] = map[string]reflect.Value{
// function, constant and variable definitions
"Deflate": reflect.ValueOf(zip.Deflate),
"ErrAlgorithm": reflect.ValueOf(&zip.ErrAlgorithm).Elem(),
"ErrChecksum": reflect.ValueOf(&zip.ErrChecksum).Elem(),
"ErrFormat": reflect.ValueOf(&zip.ErrFormat).Elem(),
"FileInfoHeader": reflect.ValueOf(zip.FileInfoHeader),
"NewReader": reflect.ValueOf(zip.NewReader),
"NewWriter": reflect.ValueOf(zip.NewWriter),
"OpenReader": reflect.ValueOf(zip.OpenReader),
"RegisterCompressor": reflect.ValueOf(zip.RegisterCompressor),
"RegisterDecompressor": reflect.ValueOf(zip.RegisterDecompressor),
"Store": reflect.ValueOf(zip.Store),
// type definitions
"Compressor": reflect.ValueOf((*zip.Compressor)(nil)),
"Decompressor": reflect.ValueOf((*zip.Decompressor)(nil)),
"File": reflect.ValueOf((*zip.File)(nil)),
"FileHeader": reflect.ValueOf((*zip.FileHeader)(nil)),
"ReadCloser": reflect.ValueOf((*zip.ReadCloser)(nil)),
"Reader": reflect.ValueOf((*zip.Reader)(nil)),
"Writer": reflect.ValueOf((*zip.Writer)(nil)),
}
}

View File

@@ -1,42 +0,0 @@
// Code generated by 'goexports bufio'. DO NOT EDIT.
// +build go1.11,!go1.12
package stdlib
import (
"bufio"
"reflect"
)
func init() {
Symbols["bufio"] = map[string]reflect.Value{
// function, constant and variable definitions
"ErrAdvanceTooFar": reflect.ValueOf(&bufio.ErrAdvanceTooFar).Elem(),
"ErrBufferFull": reflect.ValueOf(&bufio.ErrBufferFull).Elem(),
"ErrFinalToken": reflect.ValueOf(&bufio.ErrFinalToken).Elem(),
"ErrInvalidUnreadByte": reflect.ValueOf(&bufio.ErrInvalidUnreadByte).Elem(),
"ErrInvalidUnreadRune": reflect.ValueOf(&bufio.ErrInvalidUnreadRune).Elem(),
"ErrNegativeAdvance": reflect.ValueOf(&bufio.ErrNegativeAdvance).Elem(),
"ErrNegativeCount": reflect.ValueOf(&bufio.ErrNegativeCount).Elem(),
"ErrTooLong": reflect.ValueOf(&bufio.ErrTooLong).Elem(),
"MaxScanTokenSize": reflect.ValueOf(bufio.MaxScanTokenSize),
"NewReadWriter": reflect.ValueOf(bufio.NewReadWriter),
"NewReader": reflect.ValueOf(bufio.NewReader),
"NewReaderSize": reflect.ValueOf(bufio.NewReaderSize),
"NewScanner": reflect.ValueOf(bufio.NewScanner),
"NewWriter": reflect.ValueOf(bufio.NewWriter),
"NewWriterSize": reflect.ValueOf(bufio.NewWriterSize),
"ScanBytes": reflect.ValueOf(bufio.ScanBytes),
"ScanLines": reflect.ValueOf(bufio.ScanLines),
"ScanRunes": reflect.ValueOf(bufio.ScanRunes),
"ScanWords": reflect.ValueOf(bufio.ScanWords),
// type definitions
"ReadWriter": reflect.ValueOf((*bufio.ReadWriter)(nil)),
"Reader": reflect.ValueOf((*bufio.Reader)(nil)),
"Scanner": reflect.ValueOf((*bufio.Scanner)(nil)),
"SplitFunc": reflect.ValueOf((*bufio.SplitFunc)(nil)),
"Writer": reflect.ValueOf((*bufio.Writer)(nil)),
}
}

View File

@@ -1,70 +0,0 @@
// Code generated by 'goexports bytes'. DO NOT EDIT.
// +build go1.11,!go1.12
package stdlib
import (
"bytes"
"reflect"
)
func init() {
Symbols["bytes"] = map[string]reflect.Value{
// function, constant and variable definitions
"Compare": reflect.ValueOf(bytes.Compare),
"Contains": reflect.ValueOf(bytes.Contains),
"ContainsAny": reflect.ValueOf(bytes.ContainsAny),
"ContainsRune": reflect.ValueOf(bytes.ContainsRune),
"Count": reflect.ValueOf(bytes.Count),
"Equal": reflect.ValueOf(bytes.Equal),
"EqualFold": reflect.ValueOf(bytes.EqualFold),
"ErrTooLarge": reflect.ValueOf(&bytes.ErrTooLarge).Elem(),
"Fields": reflect.ValueOf(bytes.Fields),
"FieldsFunc": reflect.ValueOf(bytes.FieldsFunc),
"HasPrefix": reflect.ValueOf(bytes.HasPrefix),
"HasSuffix": reflect.ValueOf(bytes.HasSuffix),
"Index": reflect.ValueOf(bytes.Index),
"IndexAny": reflect.ValueOf(bytes.IndexAny),
"IndexByte": reflect.ValueOf(bytes.IndexByte),
"IndexFunc": reflect.ValueOf(bytes.IndexFunc),
"IndexRune": reflect.ValueOf(bytes.IndexRune),
"Join": reflect.ValueOf(bytes.Join),
"LastIndex": reflect.ValueOf(bytes.LastIndex),
"LastIndexAny": reflect.ValueOf(bytes.LastIndexAny),
"LastIndexByte": reflect.ValueOf(bytes.LastIndexByte),
"LastIndexFunc": reflect.ValueOf(bytes.LastIndexFunc),
"Map": reflect.ValueOf(bytes.Map),
"MinRead": reflect.ValueOf(bytes.MinRead),
"NewBuffer": reflect.ValueOf(bytes.NewBuffer),
"NewBufferString": reflect.ValueOf(bytes.NewBufferString),
"NewReader": reflect.ValueOf(bytes.NewReader),
"Repeat": reflect.ValueOf(bytes.Repeat),
"Replace": reflect.ValueOf(bytes.Replace),
"Runes": reflect.ValueOf(bytes.Runes),
"Split": reflect.ValueOf(bytes.Split),
"SplitAfter": reflect.ValueOf(bytes.SplitAfter),
"SplitAfterN": reflect.ValueOf(bytes.SplitAfterN),
"SplitN": reflect.ValueOf(bytes.SplitN),
"Title": reflect.ValueOf(bytes.Title),
"ToLower": reflect.ValueOf(bytes.ToLower),
"ToLowerSpecial": reflect.ValueOf(bytes.ToLowerSpecial),
"ToTitle": reflect.ValueOf(bytes.ToTitle),
"ToTitleSpecial": reflect.ValueOf(bytes.ToTitleSpecial),
"ToUpper": reflect.ValueOf(bytes.ToUpper),
"ToUpperSpecial": reflect.ValueOf(bytes.ToUpperSpecial),
"Trim": reflect.ValueOf(bytes.Trim),
"TrimFunc": reflect.ValueOf(bytes.TrimFunc),
"TrimLeft": reflect.ValueOf(bytes.TrimLeft),
"TrimLeftFunc": reflect.ValueOf(bytes.TrimLeftFunc),
"TrimPrefix": reflect.ValueOf(bytes.TrimPrefix),
"TrimRight": reflect.ValueOf(bytes.TrimRight),
"TrimRightFunc": reflect.ValueOf(bytes.TrimRightFunc),
"TrimSpace": reflect.ValueOf(bytes.TrimSpace),
"TrimSuffix": reflect.ValueOf(bytes.TrimSuffix),
// type definitions
"Buffer": reflect.ValueOf((*bytes.Buffer)(nil)),
"Reader": reflect.ValueOf((*bytes.Reader)(nil)),
}
}

View File

@@ -1,20 +0,0 @@
// Code generated by 'goexports compress/bzip2'. DO NOT EDIT.
// +build go1.11,!go1.12
package stdlib
import (
"compress/bzip2"
"reflect"
)
func init() {
Symbols["compress/bzip2"] = map[string]reflect.Value{
// function, constant and variable definitions
"NewReader": reflect.ValueOf(bzip2.NewReader),
// type definitions
"StructuralError": reflect.ValueOf((*bzip2.StructuralError)(nil)),
}
}

View File

@@ -1,55 +0,0 @@
// Code generated by 'goexports compress/flate'. DO NOT EDIT.
// +build go1.11,!go1.12
package stdlib
import (
"compress/flate"
"io"
"reflect"
)
func init() {
Symbols["compress/flate"] = map[string]reflect.Value{
// function, constant and variable definitions
"BestCompression": reflect.ValueOf(flate.BestCompression),
"BestSpeed": reflect.ValueOf(flate.BestSpeed),
"DefaultCompression": reflect.ValueOf(flate.DefaultCompression),
"HuffmanOnly": reflect.ValueOf(flate.HuffmanOnly),
"NewReader": reflect.ValueOf(flate.NewReader),
"NewReaderDict": reflect.ValueOf(flate.NewReaderDict),
"NewWriter": reflect.ValueOf(flate.NewWriter),
"NewWriterDict": reflect.ValueOf(flate.NewWriterDict),
"NoCompression": reflect.ValueOf(flate.NoCompression),
// type definitions
"CorruptInputError": reflect.ValueOf((*flate.CorruptInputError)(nil)),
"InternalError": reflect.ValueOf((*flate.InternalError)(nil)),
"ReadError": reflect.ValueOf((*flate.ReadError)(nil)),
"Reader": reflect.ValueOf((*flate.Reader)(nil)),
"Resetter": reflect.ValueOf((*flate.Resetter)(nil)),
"WriteError": reflect.ValueOf((*flate.WriteError)(nil)),
"Writer": reflect.ValueOf((*flate.Writer)(nil)),
// interface wrapper definitions
"_Reader": reflect.ValueOf((*_compress_flate_Reader)(nil)),
"_Resetter": reflect.ValueOf((*_compress_flate_Resetter)(nil)),
}
}
// _compress_flate_Reader is an interface wrapper for Reader type
type _compress_flate_Reader struct {
WRead func(p []byte) (n int, err error)
WReadByte func() (byte, error)
}
func (W _compress_flate_Reader) Read(p []byte) (n int, err error) { return W.WRead(p) }
func (W _compress_flate_Reader) ReadByte() (byte, error) { return W.WReadByte() }
// _compress_flate_Resetter is an interface wrapper for Resetter type
type _compress_flate_Resetter struct {
WReset func(r io.Reader, dict []byte) error
}
func (W _compress_flate_Resetter) Reset(r io.Reader, dict []byte) error { return W.WReset(r, dict) }

View File

@@ -1,31 +0,0 @@
// Code generated by 'goexports compress/gzip'. DO NOT EDIT.
// +build go1.11,!go1.12
package stdlib
import (
"compress/gzip"
"reflect"
)
func init() {
Symbols["compress/gzip"] = map[string]reflect.Value{
// function, constant and variable definitions
"BestCompression": reflect.ValueOf(gzip.BestCompression),
"BestSpeed": reflect.ValueOf(gzip.BestSpeed),
"DefaultCompression": reflect.ValueOf(gzip.DefaultCompression),
"ErrChecksum": reflect.ValueOf(&gzip.ErrChecksum).Elem(),
"ErrHeader": reflect.ValueOf(&gzip.ErrHeader).Elem(),
"HuffmanOnly": reflect.ValueOf(gzip.HuffmanOnly),
"NewReader": reflect.ValueOf(gzip.NewReader),
"NewWriter": reflect.ValueOf(gzip.NewWriter),
"NewWriterLevel": reflect.ValueOf(gzip.NewWriterLevel),
"NoCompression": reflect.ValueOf(gzip.NoCompression),
// type definitions
"Header": reflect.ValueOf((*gzip.Header)(nil)),
"Reader": reflect.ValueOf((*gzip.Reader)(nil)),
"Writer": reflect.ValueOf((*gzip.Writer)(nil)),
}
}

View File

@@ -1,23 +0,0 @@
// Code generated by 'goexports compress/lzw'. DO NOT EDIT.
// +build go1.11,!go1.12
package stdlib
import (
"compress/lzw"
"reflect"
)
func init() {
Symbols["compress/lzw"] = map[string]reflect.Value{
// function, constant and variable definitions
"LSB": reflect.ValueOf(lzw.LSB),
"MSB": reflect.ValueOf(lzw.MSB),
"NewReader": reflect.ValueOf(lzw.NewReader),
"NewWriter": reflect.ValueOf(lzw.NewWriter),
// type definitions
"Order": reflect.ValueOf((*lzw.Order)(nil)),
}
}

View File

@@ -1,44 +0,0 @@
// Code generated by 'goexports compress/zlib'. DO NOT EDIT.
// +build go1.11,!go1.12
package stdlib
import (
"compress/zlib"
"io"
"reflect"
)
func init() {
Symbols["compress/zlib"] = map[string]reflect.Value{
// function, constant and variable definitions
"BestCompression": reflect.ValueOf(zlib.BestCompression),
"BestSpeed": reflect.ValueOf(zlib.BestSpeed),
"DefaultCompression": reflect.ValueOf(zlib.DefaultCompression),
"ErrChecksum": reflect.ValueOf(&zlib.ErrChecksum).Elem(),
"ErrDictionary": reflect.ValueOf(&zlib.ErrDictionary).Elem(),
"ErrHeader": reflect.ValueOf(&zlib.ErrHeader).Elem(),
"HuffmanOnly": reflect.ValueOf(zlib.HuffmanOnly),
"NewReader": reflect.ValueOf(zlib.NewReader),
"NewReaderDict": reflect.ValueOf(zlib.NewReaderDict),
"NewWriter": reflect.ValueOf(zlib.NewWriter),
"NewWriterLevel": reflect.ValueOf(zlib.NewWriterLevel),
"NewWriterLevelDict": reflect.ValueOf(zlib.NewWriterLevelDict),
"NoCompression": reflect.ValueOf(zlib.NoCompression),
// type definitions
"Resetter": reflect.ValueOf((*zlib.Resetter)(nil)),
"Writer": reflect.ValueOf((*zlib.Writer)(nil)),
// interface wrapper definitions
"_Resetter": reflect.ValueOf((*_compress_zlib_Resetter)(nil)),
}
}
// _compress_zlib_Resetter is an interface wrapper for Resetter type
type _compress_zlib_Resetter struct {
WReset func(r io.Reader, dict []byte) error
}
func (W _compress_zlib_Resetter) Reset(r io.Reader, dict []byte) error { return W.WReset(r, dict) }

View File

@@ -1,42 +0,0 @@
// Code generated by 'goexports container/heap'. DO NOT EDIT.
// +build go1.11,!go1.12
package stdlib
import (
"container/heap"
"reflect"
)
func init() {
Symbols["container/heap"] = map[string]reflect.Value{
// function, constant and variable definitions
"Fix": reflect.ValueOf(heap.Fix),
"Init": reflect.ValueOf(heap.Init),
"Pop": reflect.ValueOf(heap.Pop),
"Push": reflect.ValueOf(heap.Push),
"Remove": reflect.ValueOf(heap.Remove),
// type definitions
"Interface": reflect.ValueOf((*heap.Interface)(nil)),
// interface wrapper definitions
"_Interface": reflect.ValueOf((*_container_heap_Interface)(nil)),
}
}
// _container_heap_Interface is an interface wrapper for Interface type
type _container_heap_Interface struct {
WLen func() int
WLess func(i int, j int) bool
WPop func() interface{}
WPush func(x interface{})
WSwap func(i int, j int)
}
func (W _container_heap_Interface) Len() int { return W.WLen() }
func (W _container_heap_Interface) Less(i int, j int) bool { return W.WLess(i, j) }
func (W _container_heap_Interface) Pop() interface{} { return W.WPop() }
func (W _container_heap_Interface) Push(x interface{}) { W.WPush(x) }
func (W _container_heap_Interface) Swap(i int, j int) { W.WSwap(i, j) }

View File

@@ -1,21 +0,0 @@
// Code generated by 'goexports container/list'. DO NOT EDIT.
// +build go1.11,!go1.12
package stdlib
import (
"container/list"
"reflect"
)
func init() {
Symbols["container/list"] = map[string]reflect.Value{
// function, constant and variable definitions
"New": reflect.ValueOf(list.New),
// type definitions
"Element": reflect.ValueOf((*list.Element)(nil)),
"List": reflect.ValueOf((*list.List)(nil)),
}
}

View File

@@ -1,20 +0,0 @@
// Code generated by 'goexports container/ring'. DO NOT EDIT.
// +build go1.11,!go1.12
package stdlib
import (
"container/ring"
"reflect"
)
func init() {
Symbols["container/ring"] = map[string]reflect.Value{
// function, constant and variable definitions
"New": reflect.ValueOf(ring.New),
// type definitions
"Ring": reflect.ValueOf((*ring.Ring)(nil)),
}
}

View File

@@ -1,45 +0,0 @@
// Code generated by 'goexports context'. DO NOT EDIT.
// +build go1.11,!go1.12
package stdlib
import (
"context"
"reflect"
"time"
)
func init() {
Symbols["context"] = map[string]reflect.Value{
// function, constant and variable definitions
"Background": reflect.ValueOf(context.Background),
"Canceled": reflect.ValueOf(&context.Canceled).Elem(),
"DeadlineExceeded": reflect.ValueOf(&context.DeadlineExceeded).Elem(),
"TODO": reflect.ValueOf(context.TODO),
"WithCancel": reflect.ValueOf(context.WithCancel),
"WithDeadline": reflect.ValueOf(context.WithDeadline),
"WithTimeout": reflect.ValueOf(context.WithTimeout),
"WithValue": reflect.ValueOf(context.WithValue),
// type definitions
"CancelFunc": reflect.ValueOf((*context.CancelFunc)(nil)),
"Context": reflect.ValueOf((*context.Context)(nil)),
// interface wrapper definitions
"_Context": reflect.ValueOf((*_context_Context)(nil)),
}
}
// _context_Context is an interface wrapper for Context type
type _context_Context struct {
WDeadline func() (deadline time.Time, ok bool)
WDone func() <-chan struct{}
WErr func() error
WValue func(key interface{}) interface{}
}
func (W _context_Context) Deadline() (deadline time.Time, ok bool) { return W.WDeadline() }
func (W _context_Context) Done() <-chan struct{} { return W.WDone() }
func (W _context_Context) Err() error { return W.WErr() }
func (W _context_Context) Value(key interface{}) interface{} { return W.WValue(key) }

View File

@@ -1,95 +0,0 @@
// Code generated by 'goexports crypto'. DO NOT EDIT.
// +build go1.11,!go1.12
package stdlib
import (
"crypto"
"io"
"reflect"
)
func init() {
Symbols["crypto"] = map[string]reflect.Value{
// function, constant and variable definitions
"BLAKE2b_256": reflect.ValueOf(crypto.BLAKE2b_256),
"BLAKE2b_384": reflect.ValueOf(crypto.BLAKE2b_384),
"BLAKE2b_512": reflect.ValueOf(crypto.BLAKE2b_512),
"BLAKE2s_256": reflect.ValueOf(crypto.BLAKE2s_256),
"MD4": reflect.ValueOf(crypto.MD4),
"MD5": reflect.ValueOf(crypto.MD5),
"MD5SHA1": reflect.ValueOf(crypto.MD5SHA1),
"RIPEMD160": reflect.ValueOf(crypto.RIPEMD160),
"RegisterHash": reflect.ValueOf(crypto.RegisterHash),
"SHA1": reflect.ValueOf(crypto.SHA1),
"SHA224": reflect.ValueOf(crypto.SHA224),
"SHA256": reflect.ValueOf(crypto.SHA256),
"SHA384": reflect.ValueOf(crypto.SHA384),
"SHA3_224": reflect.ValueOf(crypto.SHA3_224),
"SHA3_256": reflect.ValueOf(crypto.SHA3_256),
"SHA3_384": reflect.ValueOf(crypto.SHA3_384),
"SHA3_512": reflect.ValueOf(crypto.SHA3_512),
"SHA512": reflect.ValueOf(crypto.SHA512),
"SHA512_224": reflect.ValueOf(crypto.SHA512_224),
"SHA512_256": reflect.ValueOf(crypto.SHA512_256),
// type definitions
"Decrypter": reflect.ValueOf((*crypto.Decrypter)(nil)),
"DecrypterOpts": reflect.ValueOf((*crypto.DecrypterOpts)(nil)),
"Hash": reflect.ValueOf((*crypto.Hash)(nil)),
"PrivateKey": reflect.ValueOf((*crypto.PrivateKey)(nil)),
"PublicKey": reflect.ValueOf((*crypto.PublicKey)(nil)),
"Signer": reflect.ValueOf((*crypto.Signer)(nil)),
"SignerOpts": reflect.ValueOf((*crypto.SignerOpts)(nil)),
// interface wrapper definitions
"_Decrypter": reflect.ValueOf((*_crypto_Decrypter)(nil)),
"_DecrypterOpts": reflect.ValueOf((*_crypto_DecrypterOpts)(nil)),
"_PrivateKey": reflect.ValueOf((*_crypto_PrivateKey)(nil)),
"_PublicKey": reflect.ValueOf((*_crypto_PublicKey)(nil)),
"_Signer": reflect.ValueOf((*_crypto_Signer)(nil)),
"_SignerOpts": reflect.ValueOf((*_crypto_SignerOpts)(nil)),
}
}
// _crypto_Decrypter is an interface wrapper for Decrypter type
type _crypto_Decrypter struct {
WDecrypt func(rand io.Reader, msg []byte, opts crypto.DecrypterOpts) (plaintext []byte, err error)
WPublic func() crypto.PublicKey
}
func (W _crypto_Decrypter) Decrypt(rand io.Reader, msg []byte, opts crypto.DecrypterOpts) (plaintext []byte, err error) {
return W.WDecrypt(rand, msg, opts)
}
func (W _crypto_Decrypter) Public() crypto.PublicKey { return W.WPublic() }
// _crypto_DecrypterOpts is an interface wrapper for DecrypterOpts type
type _crypto_DecrypterOpts struct {
}
// _crypto_PrivateKey is an interface wrapper for PrivateKey type
type _crypto_PrivateKey struct {
}
// _crypto_PublicKey is an interface wrapper for PublicKey type
type _crypto_PublicKey struct {
}
// _crypto_Signer is an interface wrapper for Signer type
type _crypto_Signer struct {
WPublic func() crypto.PublicKey
WSign func(rand io.Reader, digest []byte, opts crypto.SignerOpts) (signature []byte, err error)
}
func (W _crypto_Signer) Public() crypto.PublicKey { return W.WPublic() }
func (W _crypto_Signer) Sign(rand io.Reader, digest []byte, opts crypto.SignerOpts) (signature []byte, err error) {
return W.WSign(rand, digest, opts)
}
// _crypto_SignerOpts is an interface wrapper for SignerOpts type
type _crypto_SignerOpts struct {
WHashFunc func() crypto.Hash
}
func (W _crypto_SignerOpts) HashFunc() crypto.Hash { return W.WHashFunc() }

View File

@@ -1,21 +0,0 @@
// Code generated by 'goexports crypto/aes'. DO NOT EDIT.
// +build go1.11,!go1.12
package stdlib
import (
"crypto/aes"
"reflect"
)
func init() {
Symbols["crypto/aes"] = map[string]reflect.Value{
// function, constant and variable definitions
"BlockSize": reflect.ValueOf(aes.BlockSize),
"NewCipher": reflect.ValueOf(aes.NewCipher),
// type definitions
"KeySizeError": reflect.ValueOf((*aes.KeySizeError)(nil)),
}
}

View File

@@ -1,83 +0,0 @@
// Code generated by 'goexports crypto/cipher'. DO NOT EDIT.
// +build go1.11,!go1.12
package stdlib
import (
"crypto/cipher"
"reflect"
)
func init() {
Symbols["crypto/cipher"] = map[string]reflect.Value{
// function, constant and variable definitions
"NewCBCDecrypter": reflect.ValueOf(cipher.NewCBCDecrypter),
"NewCBCEncrypter": reflect.ValueOf(cipher.NewCBCEncrypter),
"NewCFBDecrypter": reflect.ValueOf(cipher.NewCFBDecrypter),
"NewCFBEncrypter": reflect.ValueOf(cipher.NewCFBEncrypter),
"NewCTR": reflect.ValueOf(cipher.NewCTR),
"NewGCM": reflect.ValueOf(cipher.NewGCM),
"NewGCMWithNonceSize": reflect.ValueOf(cipher.NewGCMWithNonceSize),
"NewGCMWithTagSize": reflect.ValueOf(cipher.NewGCMWithTagSize),
"NewOFB": reflect.ValueOf(cipher.NewOFB),
// type definitions
"AEAD": reflect.ValueOf((*cipher.AEAD)(nil)),
"Block": reflect.ValueOf((*cipher.Block)(nil)),
"BlockMode": reflect.ValueOf((*cipher.BlockMode)(nil)),
"Stream": reflect.ValueOf((*cipher.Stream)(nil)),
"StreamReader": reflect.ValueOf((*cipher.StreamReader)(nil)),
"StreamWriter": reflect.ValueOf((*cipher.StreamWriter)(nil)),
// interface wrapper definitions
"_AEAD": reflect.ValueOf((*_crypto_cipher_AEAD)(nil)),
"_Block": reflect.ValueOf((*_crypto_cipher_Block)(nil)),
"_BlockMode": reflect.ValueOf((*_crypto_cipher_BlockMode)(nil)),
"_Stream": reflect.ValueOf((*_crypto_cipher_Stream)(nil)),
}
}
// _crypto_cipher_AEAD is an interface wrapper for AEAD type
type _crypto_cipher_AEAD struct {
WNonceSize func() int
WOpen func(dst []byte, nonce []byte, ciphertext []byte, additionalData []byte) ([]byte, error)
WOverhead func() int
WSeal func(dst []byte, nonce []byte, plaintext []byte, additionalData []byte) []byte
}
func (W _crypto_cipher_AEAD) NonceSize() int { return W.WNonceSize() }
func (W _crypto_cipher_AEAD) Open(dst []byte, nonce []byte, ciphertext []byte, additionalData []byte) ([]byte, error) {
return W.WOpen(dst, nonce, ciphertext, additionalData)
}
func (W _crypto_cipher_AEAD) Overhead() int { return W.WOverhead() }
func (W _crypto_cipher_AEAD) Seal(dst []byte, nonce []byte, plaintext []byte, additionalData []byte) []byte {
return W.WSeal(dst, nonce, plaintext, additionalData)
}
// _crypto_cipher_Block is an interface wrapper for Block type
type _crypto_cipher_Block struct {
WBlockSize func() int
WDecrypt func(dst []byte, src []byte)
WEncrypt func(dst []byte, src []byte)
}
func (W _crypto_cipher_Block) BlockSize() int { return W.WBlockSize() }
func (W _crypto_cipher_Block) Decrypt(dst []byte, src []byte) { W.WDecrypt(dst, src) }
func (W _crypto_cipher_Block) Encrypt(dst []byte, src []byte) { W.WEncrypt(dst, src) }
// _crypto_cipher_BlockMode is an interface wrapper for BlockMode type
type _crypto_cipher_BlockMode struct {
WBlockSize func() int
WCryptBlocks func(dst []byte, src []byte)
}
func (W _crypto_cipher_BlockMode) BlockSize() int { return W.WBlockSize() }
func (W _crypto_cipher_BlockMode) CryptBlocks(dst []byte, src []byte) { W.WCryptBlocks(dst, src) }
// _crypto_cipher_Stream is an interface wrapper for Stream type
type _crypto_cipher_Stream struct {
WXORKeyStream func(dst []byte, src []byte)
}
func (W _crypto_cipher_Stream) XORKeyStream(dst []byte, src []byte) { W.WXORKeyStream(dst, src) }

View File

@@ -1,22 +0,0 @@
// Code generated by 'goexports crypto/des'. DO NOT EDIT.
// +build go1.11,!go1.12
package stdlib
import (
"crypto/des"
"reflect"
)
func init() {
Symbols["crypto/des"] = map[string]reflect.Value{
// function, constant and variable definitions
"BlockSize": reflect.ValueOf(des.BlockSize),
"NewCipher": reflect.ValueOf(des.NewCipher),
"NewTripleDESCipher": reflect.ValueOf(des.NewTripleDESCipher),
// type definitions
"KeySizeError": reflect.ValueOf((*des.KeySizeError)(nil)),
}
}

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