Compare commits
24 Commits
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
92d65c22f0 | ||
|
|
2db4579b6f | ||
|
|
101633c380 | ||
|
|
1e0f6ece6e | ||
|
|
662d2a6afe | ||
|
|
b25ee3f809 | ||
|
|
81e1e5f206 | ||
|
|
81d8339132 | ||
|
|
d494f9e420 | ||
|
|
6da1107c39 | ||
|
|
38a7331bf9 | ||
|
|
13783889cb | ||
|
|
ed626f3fb9 | ||
|
|
d0a34d467b | ||
|
|
83676577ac | ||
|
|
f0fc907269 | ||
|
|
61f4704925 | ||
|
|
b1ccfbf47f | ||
|
|
0ed4b362dc | ||
|
|
98807387a4 | ||
|
|
c817823ba1 | ||
|
|
3cb8bca81a | ||
|
|
a38d19288f | ||
|
|
7f8ffa6719 |
29
_test/addr2.go
Normal file
29
_test/addr2.go
Normal file
@@ -0,0 +1,29 @@
|
||||
package main
|
||||
|
||||
import (
|
||||
"encoding/xml"
|
||||
"fmt"
|
||||
)
|
||||
|
||||
type Email struct {
|
||||
Where string `xml:"where,attr"`
|
||||
Addr string
|
||||
}
|
||||
|
||||
func f(s string, r interface{}) error {
|
||||
return xml.Unmarshal([]byte(s), &r)
|
||||
}
|
||||
|
||||
func main() {
|
||||
data := `
|
||||
<Email where='work'>
|
||||
<Addr>bob@work.com</Addr>
|
||||
</Email>
|
||||
`
|
||||
v := Email{}
|
||||
err := f(data, &v)
|
||||
fmt.Println(err, v)
|
||||
}
|
||||
|
||||
// Ouput:
|
||||
// <nil> {work bob@work.com}
|
||||
96
_test/assert0.go
Normal file
96
_test/assert0.go
Normal file
@@ -0,0 +1,96 @@
|
||||
package main
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"reflect"
|
||||
"time"
|
||||
)
|
||||
|
||||
type MyWriter interface {
|
||||
Write(p []byte) (i int, err error)
|
||||
}
|
||||
|
||||
type TestStruct struct{}
|
||||
|
||||
func (t TestStruct) Write(p []byte) (n int, err error) {
|
||||
return len(p), nil
|
||||
}
|
||||
|
||||
func usesWriter(w MyWriter) {
|
||||
n, _ := w.Write([]byte("hello world"))
|
||||
fmt.Println(n)
|
||||
}
|
||||
|
||||
type MyStringer interface {
|
||||
String() string
|
||||
}
|
||||
|
||||
func usesStringer(s MyStringer) {
|
||||
fmt.Println(s.String())
|
||||
}
|
||||
|
||||
func main() {
|
||||
aType := reflect.TypeOf((*MyWriter)(nil)).Elem()
|
||||
|
||||
var t interface{}
|
||||
t = TestStruct{}
|
||||
var tw MyWriter
|
||||
var ok bool
|
||||
tw, ok = t.(MyWriter)
|
||||
if !ok {
|
||||
fmt.Println("TestStruct does not implement MyWriter")
|
||||
} else {
|
||||
fmt.Println("TestStruct implements MyWriter")
|
||||
usesWriter(tw)
|
||||
}
|
||||
n, _ := t.(MyWriter).Write([]byte("hello world"))
|
||||
fmt.Println(n)
|
||||
bType := reflect.TypeOf(TestStruct{})
|
||||
fmt.Println(bType.Implements(aType))
|
||||
|
||||
t = 42
|
||||
foo, ok := t.(MyWriter)
|
||||
if !ok {
|
||||
fmt.Println("42 does not implement MyWriter")
|
||||
} else {
|
||||
fmt.Println("42 implements MyWriter")
|
||||
}
|
||||
_ = foo
|
||||
|
||||
var tt interface{}
|
||||
tt = time.Nanosecond
|
||||
var myD MyStringer
|
||||
myD, ok = tt.(MyStringer)
|
||||
if !ok {
|
||||
fmt.Println("time.Nanosecond does not implement MyStringer")
|
||||
} else {
|
||||
fmt.Println("time.Nanosecond implements MyStringer")
|
||||
usesStringer(myD)
|
||||
}
|
||||
fmt.Println(tt.(MyStringer).String())
|
||||
cType := reflect.TypeOf((*MyStringer)(nil)).Elem()
|
||||
dType := reflect.TypeOf(time.Nanosecond)
|
||||
fmt.Println(dType.Implements(cType))
|
||||
|
||||
tt = 42
|
||||
bar, ok := tt.(MyStringer)
|
||||
if !ok {
|
||||
fmt.Println("42 does not implement MyStringer")
|
||||
} else {
|
||||
fmt.Println("42 implements MyStringer")
|
||||
}
|
||||
_ = bar
|
||||
|
||||
}
|
||||
|
||||
// Output:
|
||||
// TestStruct implements MyWriter
|
||||
// 11
|
||||
// 11
|
||||
// true
|
||||
// 42 does not implement MyWriter
|
||||
// time.Nanosecond implements MyStringer
|
||||
// 1ns
|
||||
// 1ns
|
||||
// true
|
||||
// 42 does not implement MyStringer
|
||||
60
_test/assert1.go
Normal file
60
_test/assert1.go
Normal file
@@ -0,0 +1,60 @@
|
||||
package main
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"reflect"
|
||||
"time"
|
||||
)
|
||||
|
||||
type TestStruct struct{}
|
||||
|
||||
func (t TestStruct) String() string {
|
||||
return "hello world"
|
||||
}
|
||||
|
||||
func main() {
|
||||
aType := reflect.TypeOf((*fmt.Stringer)(nil)).Elem()
|
||||
|
||||
var t interface{}
|
||||
t = time.Nanosecond
|
||||
s, ok := t.(fmt.Stringer)
|
||||
if !ok {
|
||||
fmt.Println("time.Nanosecond does not implement fmt.Stringer")
|
||||
return
|
||||
}
|
||||
fmt.Println(s.String())
|
||||
fmt.Println(t.(fmt.Stringer).String())
|
||||
bType := reflect.TypeOf(time.Nanosecond)
|
||||
fmt.Println(bType.Implements(aType))
|
||||
|
||||
|
||||
t = 42
|
||||
foo, ok := t.(fmt.Stringer)
|
||||
if !ok {
|
||||
fmt.Println("42 does not implement fmt.Stringer")
|
||||
} else {
|
||||
fmt.Println("42 implements fmt.Stringer")
|
||||
}
|
||||
_ = foo
|
||||
|
||||
var tt interface{}
|
||||
tt = TestStruct{}
|
||||
ss, ok := tt.(fmt.Stringer)
|
||||
if !ok {
|
||||
fmt.Println("TestStuct does not implement fmt.Stringer")
|
||||
return
|
||||
}
|
||||
fmt.Println(ss.String())
|
||||
fmt.Println(tt.(fmt.Stringer).String())
|
||||
// TODO(mpl): uncomment when fixed
|
||||
// cType := reflect.TypeOf(TestStruct{})
|
||||
// fmt.Println(cType.Implements(aType))
|
||||
}
|
||||
|
||||
// Output:
|
||||
// 1ns
|
||||
// 1ns
|
||||
// true
|
||||
// 42 does not implement fmt.Stringer
|
||||
// hello world
|
||||
// hello world
|
||||
15
_test/composite14.go
Normal file
15
_test/composite14.go
Normal file
@@ -0,0 +1,15 @@
|
||||
package main
|
||||
|
||||
import "fmt"
|
||||
|
||||
type T struct {
|
||||
b []byte
|
||||
}
|
||||
|
||||
func main() {
|
||||
t := T{nil}
|
||||
fmt.Println(t)
|
||||
}
|
||||
|
||||
// Output:
|
||||
// {[]}
|
||||
21
_test/convert0.go
Normal file
21
_test/convert0.go
Normal file
@@ -0,0 +1,21 @@
|
||||
package main
|
||||
|
||||
type T struct {
|
||||
v int
|
||||
}
|
||||
|
||||
type comparator func(T, T) bool
|
||||
|
||||
func sort(items []T, comp comparator) {
|
||||
println("in sort")
|
||||
}
|
||||
|
||||
func compT(t0, t1 T) bool { return t0.v < t1.v }
|
||||
|
||||
func main() {
|
||||
a := []T{}
|
||||
sort(a, comparator(compT))
|
||||
}
|
||||
|
||||
// Output:
|
||||
// in sort
|
||||
17
_test/convert1.go
Normal file
17
_test/convert1.go
Normal file
@@ -0,0 +1,17 @@
|
||||
package main
|
||||
|
||||
import "strconv"
|
||||
|
||||
type atoidef func(s string) (int, error)
|
||||
|
||||
func main() {
|
||||
stdatoi := atoidef(strconv.Atoi)
|
||||
n, err := stdatoi("7")
|
||||
if err != nil {
|
||||
panic(err)
|
||||
}
|
||||
println(n)
|
||||
}
|
||||
|
||||
// Output:
|
||||
// 7
|
||||
19
_test/convert2.go
Normal file
19
_test/convert2.go
Normal file
@@ -0,0 +1,19 @@
|
||||
package main
|
||||
|
||||
import "bufio"
|
||||
|
||||
func fakeSplitFunc(data []byte, atEOF bool) (advance int, token []byte, err error) {
|
||||
return 7, nil, nil
|
||||
}
|
||||
|
||||
func main() {
|
||||
splitfunc := bufio.SplitFunc(fakeSplitFunc)
|
||||
n, _, err := splitfunc(nil, true)
|
||||
if err != nil {
|
||||
panic(err)
|
||||
}
|
||||
println(n)
|
||||
}
|
||||
|
||||
// Output:
|
||||
// 7
|
||||
16
_test/for15.go
Normal file
16
_test/for15.go
Normal file
@@ -0,0 +1,16 @@
|
||||
package main
|
||||
|
||||
func f() int { println("in f"); return 1 }
|
||||
|
||||
func main() {
|
||||
for i := f(); ; {
|
||||
println("in loop")
|
||||
if i > 0 {
|
||||
break
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// Output:
|
||||
// in f
|
||||
// in loop
|
||||
16
_test/for16.go
Normal file
16
_test/for16.go
Normal file
@@ -0,0 +1,16 @@
|
||||
package main
|
||||
|
||||
func main() {
|
||||
max := 1
|
||||
for ; ; max-- {
|
||||
if max == 0 {
|
||||
break
|
||||
}
|
||||
println("in for")
|
||||
}
|
||||
println("bye")
|
||||
}
|
||||
|
||||
// Output:
|
||||
// in for
|
||||
// bye
|
||||
17
_test/fun26.go
Normal file
17
_test/fun26.go
Normal file
@@ -0,0 +1,17 @@
|
||||
package main
|
||||
|
||||
type F func() (int, error)
|
||||
|
||||
func f1() (int, error) { return 3, nil }
|
||||
|
||||
func f2(a string, f F) {
|
||||
c, _ := f()
|
||||
println(a, c)
|
||||
}
|
||||
|
||||
func main() {
|
||||
f2("hello", F(f1))
|
||||
}
|
||||
|
||||
// Output:
|
||||
// hello 3
|
||||
12
_test/goto1.go
Normal file
12
_test/goto1.go
Normal file
@@ -0,0 +1,12 @@
|
||||
package main
|
||||
|
||||
func main() {
|
||||
if true {
|
||||
goto here
|
||||
}
|
||||
here:
|
||||
println("ok")
|
||||
}
|
||||
|
||||
// Output:
|
||||
// ok
|
||||
28
_test/nil3.go
Normal file
28
_test/nil3.go
Normal file
@@ -0,0 +1,28 @@
|
||||
package main
|
||||
|
||||
type I interface {
|
||||
Hello()
|
||||
}
|
||||
|
||||
type T struct {
|
||||
h I
|
||||
}
|
||||
|
||||
func (t *T) Hello() { println("Hello") }
|
||||
|
||||
func main() {
|
||||
t := &T{}
|
||||
println(t.h != nil)
|
||||
println(t.h == nil)
|
||||
t.h = t
|
||||
println(t.h != nil)
|
||||
println(t.h == nil)
|
||||
t.h.Hello()
|
||||
}
|
||||
|
||||
// Output:
|
||||
// false
|
||||
// true
|
||||
// true
|
||||
// false
|
||||
// Hello
|
||||
20
_test/time14.go
Normal file
20
_test/time14.go
Normal file
@@ -0,0 +1,20 @@
|
||||
package main
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"time"
|
||||
)
|
||||
|
||||
var t time.Time
|
||||
|
||||
func f() time.Time {
|
||||
time := t
|
||||
return time
|
||||
}
|
||||
|
||||
func main() {
|
||||
fmt.Println(f())
|
||||
}
|
||||
|
||||
// Output:
|
||||
// 0001-01-01 00:00:00 +0000 UTC
|
||||
15
_test/time15.go
Normal file
15
_test/time15.go
Normal file
@@ -0,0 +1,15 @@
|
||||
package main
|
||||
|
||||
import "time"
|
||||
|
||||
type TimeValue time.Time
|
||||
|
||||
func (v *TimeValue) decode() { println("in decode") }
|
||||
|
||||
func main() {
|
||||
var tv TimeValue
|
||||
tv.decode()
|
||||
}
|
||||
|
||||
// Output:
|
||||
// in decode
|
||||
@@ -6,6 +6,7 @@ import (
|
||||
"fmt"
|
||||
"go/build"
|
||||
"os"
|
||||
"path/filepath"
|
||||
"regexp"
|
||||
"strconv"
|
||||
"strings"
|
||||
@@ -102,6 +103,18 @@ func test(arg []string) (err error) {
|
||||
testing.Init()
|
||||
os.Args = tf
|
||||
flag.Parse()
|
||||
path += string(filepath.Separator)
|
||||
var dir string
|
||||
|
||||
switch strings.Split(path, string(filepath.Separator))[0] {
|
||||
case ".", "..", string(filepath.Separator):
|
||||
dir = path
|
||||
default:
|
||||
dir = filepath.Join(build.Default.GOPATH, "src", path)
|
||||
}
|
||||
if err = os.Chdir(dir); err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
i := interp.New(interp.Options{GoPath: build.Default.GOPATH, BuildTags: strings.Split(tags, ",")})
|
||||
i.Use(stdlib.Symbols)
|
||||
|
||||
13
example/pkg/_pkg13/src/guthib.com/foo/bar/main.go
Normal file
13
example/pkg/_pkg13/src/guthib.com/foo/bar/main.go
Normal file
@@ -0,0 +1,13 @@
|
||||
package main
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
|
||||
"guthib.com/bat/baz"
|
||||
)
|
||||
|
||||
func main() {
|
||||
t := baz.NewT()
|
||||
|
||||
fmt.Printf("%s", t.A3)
|
||||
}
|
||||
22
example/pkg/_pkg13/src/guthib.com/foo/bar/vendor/guthib.com/bat/baz/baz.go
generated
vendored
Normal file
22
example/pkg/_pkg13/src/guthib.com/foo/bar/vendor/guthib.com/bat/baz/baz.go
generated
vendored
Normal file
@@ -0,0 +1,22 @@
|
||||
package baz
|
||||
|
||||
func NewT() *T {
|
||||
return &T{
|
||||
A1: make([]U, 0),
|
||||
A3: "foobar",
|
||||
}
|
||||
}
|
||||
|
||||
type T struct {
|
||||
A1 []U
|
||||
A3 string
|
||||
}
|
||||
|
||||
type U struct {
|
||||
B1 V
|
||||
B2 V
|
||||
}
|
||||
|
||||
type V struct {
|
||||
C1 string
|
||||
}
|
||||
@@ -93,6 +93,12 @@ func TestPackages(t *testing.T) {
|
||||
expected: "Yo hello",
|
||||
evalFile: "./_pkg12/src/guthib.com/foo/main.go",
|
||||
},
|
||||
{
|
||||
desc: "eval main with vendor",
|
||||
goPath: "./_pkg13/",
|
||||
expected: "foobar",
|
||||
evalFile: "./_pkg13/src/guthib.com/foo/bar/main.go",
|
||||
},
|
||||
}
|
||||
|
||||
for _, test := range testCases {
|
||||
|
||||
@@ -436,10 +436,12 @@ func GetMinor(part string) string {
|
||||
return minor
|
||||
}
|
||||
|
||||
const defaultMinorVersion = 15
|
||||
|
||||
func genBuildTags() (string, error) {
|
||||
version := runtime.Version()
|
||||
if version == "devel" {
|
||||
return "", nil
|
||||
if strings.HasPrefix(version, "devel") {
|
||||
return "", fmt.Errorf("extracting only supported with stable releases of Go, not %v", version)
|
||||
}
|
||||
parts := strings.Split(version, ".")
|
||||
|
||||
@@ -452,6 +454,11 @@ func genBuildTags() (string, error) {
|
||||
return "", fmt.Errorf("failed to parse version: %v", err)
|
||||
}
|
||||
|
||||
// Only append an upper bound if we are not on the latest go
|
||||
if minor >= defaultMinorVersion {
|
||||
return currentGoVersion, nil
|
||||
}
|
||||
|
||||
nextGoVersion := parts[0] + "." + strconv.Itoa(minor+1)
|
||||
|
||||
return currentGoVersion + ",!" + nextGoVersion, nil
|
||||
|
||||
@@ -84,11 +84,12 @@ func main() {
|
||||
oFile = strings.ReplaceAll(importPath, "/", "_") + ".go"
|
||||
}
|
||||
|
||||
prefix := runtime.Version()
|
||||
if runtime.Version() != "devel" {
|
||||
parts := strings.Split(runtime.Version(), ".")
|
||||
prefix = parts[0] + "_" + extract.GetMinor(parts[1])
|
||||
version := runtime.Version()
|
||||
if strings.HasPrefix(version, "devel") {
|
||||
log.Fatalf("extracting only supported with stable releases of Go, not %v", version)
|
||||
}
|
||||
parts := strings.Split(version, ".")
|
||||
prefix := parts[0] + "_" + extract.GetMinor(parts[1])
|
||||
|
||||
f, err := os.Create(prefix + "_" + oFile)
|
||||
if err != nil {
|
||||
|
||||
@@ -51,12 +51,14 @@ const (
|
||||
fieldList
|
||||
fileStmt
|
||||
forStmt0 // for {}
|
||||
forStmt1 // for cond {}
|
||||
forStmt2 // for init; cond; {}
|
||||
forStmt3 // for ; cond; post {}
|
||||
forStmt3a // for init; ; post {}
|
||||
forStmt4 // for init; cond; post {}
|
||||
forRangeStmt // for range
|
||||
forStmt1 // for init; ; {}
|
||||
forStmt2 // for cond {}
|
||||
forStmt3 // for init; cond; {}
|
||||
forStmt4 // for ; ; post {}
|
||||
forStmt5 // for ; cond; post {}
|
||||
forStmt6 // for init; ; post {}
|
||||
forStmt7 // for init; cond; post {}
|
||||
forRangeStmt // for range {}
|
||||
funcDecl
|
||||
funcLit
|
||||
funcType
|
||||
@@ -134,8 +136,10 @@ var kinds = [...]string{
|
||||
forStmt1: "forStmt1",
|
||||
forStmt2: "forStmt2",
|
||||
forStmt3: "forStmt3",
|
||||
forStmt3a: "forStmt3a",
|
||||
forStmt4: "forStmt4",
|
||||
forStmt5: "forStmt5",
|
||||
forStmt6: "forStmt6",
|
||||
forStmt7: "forStmt7",
|
||||
forRangeStmt: "forRangeStmt",
|
||||
funcDecl: "funcDecl",
|
||||
funcType: "funcType",
|
||||
@@ -654,23 +658,23 @@ func (interp *Interpreter) ast(src, name string, inc bool) (string, *node, error
|
||||
case *ast.ForStmt:
|
||||
// Disambiguate variants of FOR statements with a node kind per variant
|
||||
var kind nkind
|
||||
if a.Cond == nil {
|
||||
if a.Init != nil && a.Post != nil {
|
||||
kind = forStmt3a
|
||||
} else {
|
||||
kind = forStmt0
|
||||
}
|
||||
} else {
|
||||
switch {
|
||||
case a.Init == nil && a.Post == nil:
|
||||
kind = forStmt1
|
||||
case a.Init != nil && a.Post == nil:
|
||||
kind = forStmt2
|
||||
case a.Init == nil && a.Post != nil:
|
||||
kind = forStmt3
|
||||
default:
|
||||
kind = forStmt4
|
||||
}
|
||||
switch {
|
||||
case a.Cond == nil && a.Init == nil && a.Post == nil:
|
||||
kind = forStmt0
|
||||
case a.Cond == nil && a.Init != nil && a.Post == nil:
|
||||
kind = forStmt1
|
||||
case a.Cond != nil && a.Init == nil && a.Post == nil:
|
||||
kind = forStmt2
|
||||
case a.Cond != nil && a.Init != nil && a.Post == nil:
|
||||
kind = forStmt3
|
||||
case a.Cond == nil && a.Init == nil && a.Post != nil:
|
||||
kind = forStmt4
|
||||
case a.Cond != nil && a.Init == nil && a.Post != nil:
|
||||
kind = forStmt5
|
||||
case a.Cond == nil && a.Init != nil && a.Post != nil:
|
||||
kind = forStmt6
|
||||
case a.Cond != nil && a.Init != nil && a.Post != nil:
|
||||
kind = forStmt7
|
||||
}
|
||||
st.push(addChild(&root, anc, pos, kind, aNop), nod)
|
||||
|
||||
|
||||
122
interp/cfg.go
122
interp/cfg.go
@@ -66,6 +66,44 @@ func (interp *Interpreter) cfg(root *node, importPath string) ([]*node, error) {
|
||||
return false
|
||||
}
|
||||
switch n.kind {
|
||||
case binaryExpr, unaryExpr, parenExpr:
|
||||
if isBoolAction(n) {
|
||||
break
|
||||
}
|
||||
// Gather assigned type if set, to give context for type propagation at post-order.
|
||||
switch n.anc.kind {
|
||||
case assignStmt, defineStmt:
|
||||
a := n.anc
|
||||
i := childPos(n) - a.nright
|
||||
if i < 0 {
|
||||
break
|
||||
}
|
||||
if len(a.child) > a.nright+a.nleft {
|
||||
i--
|
||||
}
|
||||
dest := a.child[i]
|
||||
if dest.typ != nil && !isInterface(dest.typ) {
|
||||
// Interface type are not propagated, and will be resolved at post-order.
|
||||
n.typ = dest.typ
|
||||
}
|
||||
case binaryExpr, unaryExpr, parenExpr:
|
||||
n.typ = n.anc.typ
|
||||
}
|
||||
|
||||
case defineStmt:
|
||||
// Determine type of variables initialized at declaration, so it can be propagated.
|
||||
if n.nleft+n.nright == len(n.child) {
|
||||
// No type was specified on the left hand side, it will resolved at post-order.
|
||||
break
|
||||
}
|
||||
n.typ, err = nodeType(interp, sc, n.child[n.nleft])
|
||||
if err != nil {
|
||||
break
|
||||
}
|
||||
for i := 0; i < n.nleft; i++ {
|
||||
n.child[i].typ = n.typ
|
||||
}
|
||||
|
||||
case blockStmt:
|
||||
if n.anc != nil && n.anc.kind == rangeStmt {
|
||||
// For range block: ensure that array or map type is propagated to iterators
|
||||
@@ -159,7 +197,7 @@ func (interp *Interpreter) cfg(root *node, importPath string) ([]*node, error) {
|
||||
|
||||
case breakStmt, continueStmt, gotoStmt:
|
||||
if len(n.child) > 0 {
|
||||
// Handle labeled statements
|
||||
// Handle labeled statements.
|
||||
label := n.child[0].ident
|
||||
if sym, _, ok := sc.lookup(label); ok {
|
||||
if sym.kind != labelSym {
|
||||
@@ -176,25 +214,23 @@ func (interp *Interpreter) cfg(root *node, importPath string) ([]*node, error) {
|
||||
|
||||
case labeledStmt:
|
||||
label := n.child[0].ident
|
||||
if sym, _, ok := sc.lookup(label); ok {
|
||||
if sym.kind != labelSym {
|
||||
err = n.child[0].cfgErrorf("label %s not defined", label)
|
||||
break
|
||||
}
|
||||
// TODO(marc): labels must be stored outside of symbols to avoid collisions
|
||||
// Used labels are searched in current and sub scopes, not upper ones.
|
||||
if sym, ok := sc.lookdown(label); ok {
|
||||
sym.node = n
|
||||
n.sym = sym
|
||||
} else {
|
||||
n.sym = &symbol{kind: labelSym, node: n, index: -1}
|
||||
sc.sym[label] = n.sym
|
||||
}
|
||||
sc.sym[label] = n.sym
|
||||
|
||||
case caseClause:
|
||||
sc = sc.pushBloc()
|
||||
if sn := n.anc.anc; sn.kind == typeSwitch && sn.child[1].action == aAssign {
|
||||
// Type switch clause with a var defined in switch guard
|
||||
// Type switch clause with a var defined in switch guard.
|
||||
var typ *itype
|
||||
if len(n.child) == 2 {
|
||||
// 1 type in clause: define the var with this type in the case clause scope
|
||||
// 1 type in clause: define the var with this type in the case clause scope.
|
||||
switch {
|
||||
case n.child[0].ident == nilIdent:
|
||||
typ = sc.getType("interface{}")
|
||||
@@ -204,7 +240,7 @@ func (interp *Interpreter) cfg(root *node, importPath string) ([]*node, error) {
|
||||
typ, err = nodeType(interp, sc, n.child[0])
|
||||
}
|
||||
} else {
|
||||
// define the var with the type in the switch guard expression
|
||||
// Define the var with the type in the switch guard expression.
|
||||
typ = sn.child[1].child[1].child[0].typ
|
||||
}
|
||||
if err != nil {
|
||||
@@ -285,11 +321,7 @@ func (interp *Interpreter) cfg(root *node, importPath string) ([]*node, error) {
|
||||
}
|
||||
}
|
||||
|
||||
case forStmt0, forRangeStmt:
|
||||
sc = sc.pushBloc()
|
||||
sc.loop, sc.loopRestart = n, n.child[0]
|
||||
|
||||
case forStmt1, forStmt2, forStmt3, forStmt3a, forStmt4:
|
||||
case forStmt0, forStmt1, forStmt2, forStmt3, forStmt4, forStmt5, forStmt6, forStmt7, forRangeStmt:
|
||||
sc = sc.pushBloc()
|
||||
sc.loop, sc.loopRestart = n, n.lastChild()
|
||||
|
||||
@@ -386,9 +418,10 @@ func (interp *Interpreter) cfg(root *node, importPath string) ([]*node, error) {
|
||||
return false
|
||||
}
|
||||
|
||||
if n.child[1].kind == identExpr {
|
||||
switch n.child[1].kind {
|
||||
case identExpr, selectorExpr:
|
||||
n.typ = &itype{cat: aliasT, val: typ, name: typeName}
|
||||
} else {
|
||||
default:
|
||||
n.typ = typ
|
||||
n.typ.name = typeName
|
||||
}
|
||||
@@ -447,7 +480,7 @@ func (interp *Interpreter) cfg(root *node, importPath string) ([]*node, error) {
|
||||
var atyp *itype
|
||||
if n.nleft+n.nright < len(n.child) {
|
||||
if atyp, err = nodeType(interp, sc, n.child[n.nleft]); err != nil {
|
||||
return
|
||||
break
|
||||
}
|
||||
}
|
||||
|
||||
@@ -644,7 +677,12 @@ func (interp *Interpreter) cfg(root *node, importPath string) ([]*node, error) {
|
||||
}
|
||||
|
||||
switch n.action {
|
||||
case aRem, aShl, aShr:
|
||||
case aRem:
|
||||
n.typ = c0.typ
|
||||
case aShl, aShr:
|
||||
if c0.typ.untyped {
|
||||
break
|
||||
}
|
||||
n.typ = c0.typ
|
||||
case aEqual, aNotEqual:
|
||||
n.typ = sc.getType("bool")
|
||||
@@ -860,7 +898,12 @@ func (interp *Interpreter) cfg(root *node, importPath string) ([]*node, error) {
|
||||
n.gen = nop
|
||||
n.findex = -1
|
||||
n.typ = c0.typ
|
||||
n.rval = c1.rval.Convert(c0.typ.rtype)
|
||||
if c, ok := c1.rval.Interface().(constant.Value); ok {
|
||||
i, _ := constant.Int64Val(constant.ToInt(c))
|
||||
n.rval = reflect.ValueOf(i).Convert(c0.typ.rtype)
|
||||
} else {
|
||||
n.rval = c1.rval.Convert(c0.typ.rtype)
|
||||
}
|
||||
default:
|
||||
n.gen = convert
|
||||
n.typ = c0.typ
|
||||
@@ -1005,7 +1048,14 @@ func (interp *Interpreter) cfg(root *node, importPath string) ([]*node, error) {
|
||||
body.tnext = n.start
|
||||
sc = sc.pop()
|
||||
|
||||
case forStmt1: // for cond {}
|
||||
case forStmt1: // for init; ; {}
|
||||
init, body := n.child[0], n.child[1]
|
||||
n.start = init.start
|
||||
init.tnext = body.start
|
||||
body.tnext = n.start
|
||||
sc = sc.pop()
|
||||
|
||||
case forStmt2: // for cond {}
|
||||
cond, body := n.child[0], n.child[1]
|
||||
if !isBool(cond.typ) {
|
||||
err = cond.cfgErrorf("non-bool used as for condition")
|
||||
@@ -1024,7 +1074,7 @@ func (interp *Interpreter) cfg(root *node, importPath string) ([]*node, error) {
|
||||
setFNext(cond, n)
|
||||
sc = sc.pop()
|
||||
|
||||
case forStmt2: // for init; cond; {}
|
||||
case forStmt3: // 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")
|
||||
@@ -1046,7 +1096,14 @@ func (interp *Interpreter) cfg(root *node, importPath string) ([]*node, error) {
|
||||
setFNext(cond, n)
|
||||
sc = sc.pop()
|
||||
|
||||
case forStmt3: // for ; cond; post {}
|
||||
case forStmt4: // for ; ; post {}
|
||||
post, body := n.child[0], n.child[1]
|
||||
n.start = body.start
|
||||
post.tnext = body.start
|
||||
body.tnext = post.start
|
||||
sc = sc.pop()
|
||||
|
||||
case forStmt5: // 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")
|
||||
@@ -1066,7 +1123,7 @@ func (interp *Interpreter) cfg(root *node, importPath string) ([]*node, error) {
|
||||
body.tnext = post.start
|
||||
sc = sc.pop()
|
||||
|
||||
case forStmt3a: // for init; ; post {}
|
||||
case forStmt6: // for init; ; post {}
|
||||
init, post, body := n.child[0], n.child[1], n.child[2]
|
||||
n.start = init.start
|
||||
init.tnext = body.start
|
||||
@@ -1074,7 +1131,7 @@ func (interp *Interpreter) cfg(root *node, importPath string) ([]*node, error) {
|
||||
post.tnext = body.start
|
||||
sc = sc.pop()
|
||||
|
||||
case forStmt4: // for init; cond; post {}
|
||||
case forStmt7: // 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")
|
||||
@@ -1326,7 +1383,7 @@ func (interp *Interpreter) cfg(root *node, importPath string) ([]*node, error) {
|
||||
n.val = sc.def
|
||||
for i, c := range n.child {
|
||||
var typ *itype
|
||||
typ, err = nodeType(interp, sc, returnSig.child[1].fieldType(i))
|
||||
typ, err = nodeType(interp, sc.upperLevel(), returnSig.child[1].fieldType(i))
|
||||
if err != nil {
|
||||
return
|
||||
}
|
||||
@@ -2278,7 +2335,7 @@ func isCall(n *node) bool {
|
||||
}
|
||||
|
||||
func isBinCall(n *node) bool {
|
||||
return n.kind == callExpr && n.child[0].typ.cat == valueT && n.child[0].typ.rtype.Kind() == reflect.Func
|
||||
return isCall(n) && n.child[0].typ.cat == valueT && n.child[0].typ.rtype.Kind() == reflect.Func
|
||||
}
|
||||
|
||||
func mustReturnValue(n *node) bool {
|
||||
@@ -2294,7 +2351,7 @@ func mustReturnValue(n *node) bool {
|
||||
}
|
||||
|
||||
func isRegularCall(n *node) bool {
|
||||
return n.kind == callExpr && n.child[0].typ.cat == funcT
|
||||
return isCall(n) && n.child[0].typ.cat == funcT
|
||||
}
|
||||
|
||||
func variadicPos(n *node) int {
|
||||
@@ -2467,3 +2524,12 @@ func isArithmeticAction(n *node) bool {
|
||||
return false
|
||||
}
|
||||
}
|
||||
|
||||
func isBoolAction(n *node) bool {
|
||||
switch n.action {
|
||||
case aEqual, aGreater, aGreaterEqual, aLand, aLor, aLower, aLowerEqual, aNot, aNotEqual:
|
||||
return true
|
||||
default:
|
||||
return false
|
||||
}
|
||||
}
|
||||
|
||||
@@ -145,7 +145,7 @@ func (interp *Interpreter) gta(root *node, rpath, importPath string) ([]*node, e
|
||||
elementType := sc.getType(typeName)
|
||||
if elementType == nil {
|
||||
// Add type if necessary, so method can be registered
|
||||
sc.sym[typeName] = &symbol{kind: typeSym, typ: &itype{name: typeName, path: rpath, incomplete: true, node: rtn.child[0], scope: sc}}
|
||||
sc.sym[typeName] = &symbol{kind: typeSym, typ: &itype{name: typeName, path: importPath, incomplete: true, node: rtn.child[0], scope: sc}}
|
||||
elementType = sc.sym[typeName].typ
|
||||
}
|
||||
rcvrtype = &itype{cat: ptrT, val: elementType, incomplete: elementType.incomplete, node: rtn, scope: sc}
|
||||
@@ -154,7 +154,7 @@ func (interp *Interpreter) gta(root *node, rpath, importPath string) ([]*node, e
|
||||
rcvrtype = sc.getType(typeName)
|
||||
if rcvrtype == nil {
|
||||
// Add type if necessary, so method can be registered
|
||||
sc.sym[typeName] = &symbol{kind: typeSym, typ: &itype{name: typeName, path: rpath, incomplete: true, node: rtn, scope: sc}}
|
||||
sc.sym[typeName] = &symbol{kind: typeSym, typ: &itype{name: typeName, path: importPath, incomplete: true, node: rtn, scope: sc}}
|
||||
rcvrtype = sc.sym[typeName].typ
|
||||
}
|
||||
}
|
||||
@@ -253,13 +253,14 @@ func (interp *Interpreter) gta(root *node, rpath, importPath string) ([]*node, e
|
||||
return false
|
||||
}
|
||||
|
||||
if n.child[1].kind == identExpr {
|
||||
n.typ = &itype{cat: aliasT, val: typ, name: typeName, path: rpath, field: typ.field, incomplete: typ.incomplete, scope: sc, node: n.child[0]}
|
||||
switch n.child[1].kind {
|
||||
case identExpr, selectorExpr:
|
||||
n.typ = &itype{cat: aliasT, val: typ, name: typeName, path: importPath, field: typ.field, incomplete: typ.incomplete, scope: sc, node: n.child[0]}
|
||||
copy(n.typ.method, typ.method)
|
||||
} else {
|
||||
default:
|
||||
n.typ = typ
|
||||
n.typ.name = typeName
|
||||
n.typ.path = rpath
|
||||
n.typ.path = importPath
|
||||
}
|
||||
|
||||
asImportName := filepath.Join(typeName, baseName)
|
||||
|
||||
@@ -71,6 +71,27 @@ func TestEvalArithmetic(t *testing.T) {
|
||||
})
|
||||
}
|
||||
|
||||
func TestEvalShift(t *testing.T) {
|
||||
i := interp.New(interp.Options{})
|
||||
runTests(t, i, []testCase{
|
||||
{src: "a, b, m := uint32(1), uint32(2), uint32(0); m = a + (1 << b)", res: "5"},
|
||||
{src: "c := uint(1); d := uint(+(-(1 << c)))", res: "18446744073709551614"},
|
||||
{src: "e, f := uint32(0), uint32(0); f = 1 << -(e * 2)", res: "1"},
|
||||
{src: "p := uint(0xdead); byte((1 << (p & 7)) - 1)", res: "31"},
|
||||
{pre: func() { eval(t, i, "const k uint = 1 << 17") }, src: "int(k)", res: "131072"},
|
||||
})
|
||||
}
|
||||
|
||||
func TestOpVarConst(t *testing.T) {
|
||||
i := interp.New(interp.Options{})
|
||||
runTests(t, i, []testCase{
|
||||
{pre: func() { eval(t, i, "const a uint = 8 + 2") }, src: "a", res: "10"},
|
||||
{src: "b := uint(5); a+b", res: "15"},
|
||||
{src: "b := uint(5); b+a", res: "15"},
|
||||
{src: "b := uint(5); b>a", res: "false"},
|
||||
})
|
||||
}
|
||||
|
||||
func TestEvalStar(t *testing.T) {
|
||||
i := interp.New(interp.Options{})
|
||||
runTests(t, i, []testCase{
|
||||
@@ -89,6 +110,7 @@ func TestEvalAssign(t *testing.T) {
|
||||
{src: "f := int64(3.2)", err: "1:39: cannot convert expression of type float64 to type int64"},
|
||||
{src: "g := 1; g <<= 8", res: "256"},
|
||||
{src: "h := 1; h >>= 8", res: "0"},
|
||||
{src: "i := 1; j := &i; (*j) = 2", res: "2"},
|
||||
})
|
||||
}
|
||||
|
||||
@@ -423,19 +445,15 @@ func TestEvalSliceExpression(t *testing.T) {
|
||||
{src: `a := []int{0,1,2}[:]`, res: "[0 1 2]"},
|
||||
{src: `a := []int{0,1,2,3}[1:3:4]`, res: "[1 2]"},
|
||||
{src: `a := []int{0,1,2,3}[:3:4]`, res: "[0 1 2]"},
|
||||
{src: `ar := [3]int{0,1,2}
|
||||
a := ar[1:3]`, res: "[1 2]"},
|
||||
{src: `ar := [3]int{0,1,2}; a := ar[1:3]`, res: "[1 2]"},
|
||||
{src: `a := (&[3]int{0,1,2})[1:3]`, res: "[1 2]"},
|
||||
{src: `a := (&[3]int{0,1,2})[1:3]`, res: "[1 2]"},
|
||||
{src: `s := "hello"[1:3]`, res: "el"},
|
||||
{src: `str := "hello"
|
||||
s := str[1:3]`, res: "el"},
|
||||
{src: `str := "hello"; s := str[1:3]`, res: "el"},
|
||||
{src: `a := int(1)[0:1]`, err: "1:33: cannot slice type int"},
|
||||
{src: `a := ([3]int{0,1,2})[1:3]`, err: "1:33: cannot slice type [3]int"},
|
||||
{src: `a := (&[]int{0,1,2,3})[1:3]`, err: "1:33: cannot slice type *[]int"},
|
||||
{src: `a := "hello"[1:3:4]`, err: "1:45: invalid operation: 3-index slice of string"},
|
||||
{src: `ar := [3]int{0,1,2}
|
||||
a := ar[:4]`, err: "2:16: index int is out of bounds"},
|
||||
{src: `ar := [3]int{0,1,2}; a := ar[:4]`, err: "1:58: index int is out of bounds"},
|
||||
{src: `a := []int{0,1,2,3}[1::4]`, err: "1:49: 2nd index required in 3-index slice"},
|
||||
{src: `a := []int{0,1,2,3}[1:3:]`, err: "1:51: 3rd index required in 3-index slice"},
|
||||
{src: `a := []int{0,1,2}[3:1]`, err: "invalid index values, must be low <= high <= max"},
|
||||
|
||||
480
interp/run.go
480
interp/run.go
@@ -3,10 +3,12 @@ package interp
|
||||
//go:generate go run ../internal/cmd/genop/genop.go
|
||||
|
||||
import (
|
||||
"errors"
|
||||
"fmt"
|
||||
"go/constant"
|
||||
"log"
|
||||
"reflect"
|
||||
"regexp"
|
||||
"sync"
|
||||
"unsafe"
|
||||
)
|
||||
@@ -67,11 +69,22 @@ var builtin = [...]bltnGenerator{
|
||||
aStar: deref,
|
||||
aSub: sub,
|
||||
aSubAssign: subAssign,
|
||||
aTypeAssert: typeAssert,
|
||||
aTypeAssert: typeAssert1,
|
||||
aXor: xor,
|
||||
aXorAssign: xorAssign,
|
||||
}
|
||||
|
||||
var receiverStripperRxp *regexp.Regexp
|
||||
|
||||
func init() {
|
||||
re := `func\(((.*?(, |\)))(.*))`
|
||||
var err error
|
||||
receiverStripperRxp, err = regexp.Compile(re)
|
||||
if err != nil {
|
||||
panic(err)
|
||||
}
|
||||
}
|
||||
|
||||
type valueInterface struct {
|
||||
node *node
|
||||
value reflect.Value
|
||||
@@ -108,10 +121,53 @@ func (interp *Interpreter) run(n *node, cf *frame) {
|
||||
runCfg(n.start, f)
|
||||
}
|
||||
|
||||
// originalExecNode looks in the tree of nodes for the node which has exec,
|
||||
// aside from n, in order to know where n "inherited" that exec from.
|
||||
func originalExecNode(n *node, exec bltn) *node {
|
||||
execAddr := reflect.ValueOf(exec).Pointer()
|
||||
var originalNode *node
|
||||
seen := make(map[int64]struct{})
|
||||
root := n
|
||||
for {
|
||||
root = root.anc
|
||||
if root == nil {
|
||||
break
|
||||
}
|
||||
if _, ok := seen[root.index]; ok {
|
||||
continue
|
||||
}
|
||||
|
||||
root.Walk(func(wn *node) bool {
|
||||
if _, ok := seen[wn.index]; ok {
|
||||
return true
|
||||
}
|
||||
seen[wn.index] = struct{}{}
|
||||
if wn.index == n.index {
|
||||
return true
|
||||
}
|
||||
if wn.exec == nil {
|
||||
return true
|
||||
}
|
||||
if reflect.ValueOf(wn.exec).Pointer() == execAddr {
|
||||
originalNode = wn
|
||||
return false
|
||||
}
|
||||
return true
|
||||
}, nil)
|
||||
|
||||
if originalNode != nil {
|
||||
break
|
||||
}
|
||||
}
|
||||
|
||||
return originalNode
|
||||
}
|
||||
|
||||
// Functions set to run during execution of CFG.
|
||||
|
||||
// runCfg executes a node AST by walking its CFG and running node builtin at each step.
|
||||
func runCfg(n *node, f *frame) {
|
||||
var exec bltn
|
||||
defer func() {
|
||||
f.mutex.Lock()
|
||||
f.recovered = recover()
|
||||
@@ -119,14 +175,18 @@ func runCfg(n *node, f *frame) {
|
||||
val[0].Call(val[1:])
|
||||
}
|
||||
if f.recovered != nil {
|
||||
fmt.Println(n.cfgErrorf("panic"))
|
||||
oNode := originalExecNode(n, exec)
|
||||
if oNode == nil {
|
||||
oNode = n
|
||||
}
|
||||
fmt.Println(oNode.cfgErrorf("panic"))
|
||||
f.mutex.Unlock()
|
||||
panic(f.recovered)
|
||||
}
|
||||
f.mutex.Unlock()
|
||||
}()
|
||||
|
||||
for exec := n.exec; exec != nil && f.runid() == n.interp.runid(); {
|
||||
for exec = n.exec; exec != nil && f.runid() == n.interp.runid(); {
|
||||
exec = exec(f)
|
||||
}
|
||||
}
|
||||
@@ -170,79 +230,39 @@ func typeAssertStatus(n *node) {
|
||||
}
|
||||
}
|
||||
|
||||
func typeAssert(n *node) {
|
||||
c0, c1 := n.child[0], n.child[1]
|
||||
value := genValue(c0) // input value
|
||||
value0 := genValue(n) // returned result
|
||||
next := getExec(n.tnext)
|
||||
|
||||
switch {
|
||||
case isInterfaceSrc(c1.typ):
|
||||
typ := n.child[1].typ
|
||||
typID := n.child[1].typ.id()
|
||||
n.exec = func(f *frame) bltn {
|
||||
v := value(f)
|
||||
vi, ok := v.Interface().(valueInterface)
|
||||
if !ok {
|
||||
panic(n.cfgErrorf("interface conversion: nil is not %v", typID))
|
||||
}
|
||||
if !vi.node.typ.implements(typ) {
|
||||
panic(n.cfgErrorf("interface conversion: %v is not %v", vi.node.typ.id(), typID))
|
||||
}
|
||||
value0(f).Set(v)
|
||||
return next
|
||||
}
|
||||
case isInterface(c1.typ):
|
||||
n.exec = func(f *frame) bltn {
|
||||
v := value(f).Elem()
|
||||
typ := value0(f).Type()
|
||||
if !v.IsValid() {
|
||||
panic(fmt.Sprintf("interface conversion: interface {} is nil, not %s", typ.String()))
|
||||
}
|
||||
if !canAssertTypes(v.Type(), typ) {
|
||||
method := firstMissingMethod(v.Type(), typ)
|
||||
panic(fmt.Sprintf("interface conversion: %s is not %s: missing method %s", v.Type().String(), typ.String(), method))
|
||||
}
|
||||
value0(f).Set(v)
|
||||
return next
|
||||
}
|
||||
case c0.typ.cat == valueT || c0.typ.cat == errorT:
|
||||
n.exec = func(f *frame) bltn {
|
||||
v := value(f).Elem()
|
||||
typ := value0(f).Type()
|
||||
if !v.IsValid() {
|
||||
panic(fmt.Sprintf("interface conversion: interface {} is nil, not %s", typ.String()))
|
||||
}
|
||||
if !canAssertTypes(v.Type(), typ) {
|
||||
method := firstMissingMethod(v.Type(), typ)
|
||||
panic(fmt.Sprintf("interface conversion: %s is not %s: missing method %s", v.Type().String(), typ.String(), method))
|
||||
}
|
||||
value0(f).Set(v)
|
||||
return next
|
||||
}
|
||||
default:
|
||||
n.exec = func(f *frame) bltn {
|
||||
v := value(f).Interface().(valueInterface)
|
||||
typ := value0(f).Type()
|
||||
if !v.value.IsValid() {
|
||||
panic(fmt.Sprintf("interface conversion: interface {} is nil, not %s", typ.String()))
|
||||
}
|
||||
if !canAssertTypes(v.value.Type(), typ) {
|
||||
panic(fmt.Sprintf("interface conversion: interface {} is %s, not %s", v.value.Type().String(), typ.String()))
|
||||
}
|
||||
value0(f).Set(v.value)
|
||||
return next
|
||||
}
|
||||
func stripReceiverFromArgs(signature string) (string, error) {
|
||||
fields := receiverStripperRxp.FindStringSubmatch(signature)
|
||||
if len(fields) < 5 {
|
||||
return "", errors.New("error while matching method signature")
|
||||
}
|
||||
if fields[3] == ")" {
|
||||
return fmt.Sprintf("func()%s", fields[4]), nil
|
||||
}
|
||||
return fmt.Sprintf("func(%s", fields[4]), nil
|
||||
}
|
||||
|
||||
func typeAssert1(n *node) {
|
||||
typeAssert(n, false)
|
||||
}
|
||||
|
||||
func typeAssert2(n *node) {
|
||||
typeAssert(n, true)
|
||||
}
|
||||
|
||||
func typeAssert(n *node, withOk bool) {
|
||||
c0, c1 := n.child[0], n.child[1]
|
||||
value := genValue(c0) // input value
|
||||
value0 := genValue(n.anc.child[0]) // returned result
|
||||
value1 := genValue(n.anc.child[1]) // returned status
|
||||
setStatus := n.anc.child[1].ident != "_" // do not assign status to "_"
|
||||
typ := c1.typ // type to assert or convert to
|
||||
value := genValue(c0) // input value
|
||||
var value0, value1 func(*frame) reflect.Value
|
||||
setStatus := false
|
||||
if withOk {
|
||||
value0 = genValue(n.anc.child[0]) // returned result
|
||||
value1 = genValue(n.anc.child[1]) // returned status
|
||||
setStatus = n.anc.child[1].ident != "_" // do not assign status to "_"
|
||||
} else {
|
||||
value0 = genValue(n) // returned result
|
||||
}
|
||||
|
||||
typ := c1.typ // type to assert or convert to
|
||||
typID := typ.id()
|
||||
rtype := typ.rtype // type to assert
|
||||
next := getExec(n.tnext)
|
||||
@@ -251,50 +271,179 @@ func typeAssert2(n *node) {
|
||||
case isInterfaceSrc(typ):
|
||||
n.exec = func(f *frame) bltn {
|
||||
v, ok := value(f).Interface().(valueInterface)
|
||||
if ok && v.node.typ.id() == typID {
|
||||
value0(f).Set(value(f))
|
||||
} else {
|
||||
ok = false
|
||||
}
|
||||
if setStatus {
|
||||
value1(f).SetBool(ok)
|
||||
defer func() {
|
||||
value1(f).SetBool(ok)
|
||||
}()
|
||||
}
|
||||
if !ok {
|
||||
if !withOk {
|
||||
panic(n.cfgErrorf("interface conversion: nil is not %v", typID))
|
||||
}
|
||||
return next
|
||||
}
|
||||
if v.node.typ.id() == typID {
|
||||
value0(f).Set(value(f))
|
||||
return next
|
||||
}
|
||||
m0 := v.node.typ.methods()
|
||||
m1 := typ.methods()
|
||||
if len(m0) < len(m1) {
|
||||
ok = false
|
||||
if !withOk {
|
||||
panic(n.cfgErrorf("interface conversion: %v is not %v", v.node.typ.id(), typID))
|
||||
}
|
||||
return next
|
||||
}
|
||||
|
||||
for k, meth1 := range m1 {
|
||||
var meth0 string
|
||||
meth0, ok = m0[k]
|
||||
if !ok {
|
||||
return next
|
||||
}
|
||||
// As far as we know this equality check can fail because they are two ways to
|
||||
// represent the signature of a method: one where the receiver appears before the
|
||||
// func keyword, and one where it is just a func signature, and the receiver is
|
||||
// seen as the first argument. That's why if that equality fails, we try harder to
|
||||
// compare them afterwards. Hopefully that is the only reason this equality can fail.
|
||||
if meth0 == meth1 {
|
||||
continue
|
||||
}
|
||||
tm := lookupFieldOrMethod(v.node.typ, k)
|
||||
if tm == nil {
|
||||
ok = false
|
||||
return next
|
||||
}
|
||||
|
||||
var err error
|
||||
meth0, err = stripReceiverFromArgs(meth0)
|
||||
if err != nil {
|
||||
ok = false
|
||||
return next
|
||||
}
|
||||
|
||||
if meth0 != meth1 {
|
||||
ok = false
|
||||
return next
|
||||
}
|
||||
}
|
||||
|
||||
value0(f).Set(value(f))
|
||||
return next
|
||||
}
|
||||
case isInterface(typ):
|
||||
n.exec = func(f *frame) bltn {
|
||||
v := value(f).Elem()
|
||||
ok := v.IsValid() && canAssertTypes(v.Type(), rtype)
|
||||
if ok {
|
||||
value0(f).Set(v)
|
||||
}
|
||||
var leftType reflect.Type
|
||||
v := value(f)
|
||||
val, ok := v.Interface().(valueInterface)
|
||||
if setStatus {
|
||||
value1(f).SetBool(ok)
|
||||
defer func() {
|
||||
value1(f).SetBool(ok)
|
||||
}()
|
||||
}
|
||||
if ok && val.node.typ.cat != valueT {
|
||||
m0 := val.node.typ.methods()
|
||||
m1 := typ.methods()
|
||||
if len(m0) < len(m1) {
|
||||
ok = false
|
||||
return next
|
||||
}
|
||||
|
||||
for k, meth1 := range m1 {
|
||||
var meth0 string
|
||||
meth0, ok = m0[k]
|
||||
if !ok {
|
||||
return next
|
||||
}
|
||||
if meth0 != meth1 {
|
||||
ok = false
|
||||
return next
|
||||
}
|
||||
}
|
||||
|
||||
// TODO(mpl): make this case compliant with reflect's Implements.
|
||||
v = genInterfaceWrapper(val.node, rtype)(f)
|
||||
value0(f).Set(v)
|
||||
ok = true
|
||||
return next
|
||||
}
|
||||
|
||||
if ok {
|
||||
v = val.value
|
||||
leftType = val.node.typ.rtype
|
||||
} else {
|
||||
v = v.Elem()
|
||||
leftType = v.Type()
|
||||
ok = true
|
||||
}
|
||||
ok = v.IsValid()
|
||||
if !ok {
|
||||
if !withOk {
|
||||
panic(fmt.Sprintf("interface conversion: interface {} is nil, not %s", rtype.String()))
|
||||
}
|
||||
return next
|
||||
}
|
||||
ok = canAssertTypes(leftType, rtype)
|
||||
if !ok {
|
||||
if !withOk {
|
||||
method := firstMissingMethod(leftType, rtype)
|
||||
panic(fmt.Sprintf("interface conversion: %s is not %s: missing method %s", leftType.String(), rtype.String(), method))
|
||||
}
|
||||
return next
|
||||
}
|
||||
value0(f).Set(v)
|
||||
return next
|
||||
}
|
||||
case n.child[0].typ.cat == valueT || n.child[0].typ.cat == errorT:
|
||||
n.exec = func(f *frame) bltn {
|
||||
v := value(f).Elem()
|
||||
ok := v.IsValid() && canAssertTypes(v.Type(), rtype)
|
||||
if ok {
|
||||
value0(f).Set(v)
|
||||
}
|
||||
ok := v.IsValid()
|
||||
if setStatus {
|
||||
value1(f).SetBool(ok)
|
||||
defer func() {
|
||||
value1(f).SetBool(ok)
|
||||
}()
|
||||
}
|
||||
if !ok {
|
||||
if !withOk {
|
||||
panic(fmt.Sprintf("interface conversion: interface {} is nil, not %s", rtype.String()))
|
||||
}
|
||||
return next
|
||||
}
|
||||
ok = canAssertTypes(v.Type(), rtype)
|
||||
if !ok {
|
||||
if !withOk {
|
||||
method := firstMissingMethod(v.Type(), rtype)
|
||||
panic(fmt.Sprintf("interface conversion: %s is not %s: missing method %s", v.Type().String(), rtype.String(), method))
|
||||
}
|
||||
return next
|
||||
}
|
||||
value0(f).Set(v)
|
||||
return next
|
||||
}
|
||||
default:
|
||||
n.exec = func(f *frame) bltn {
|
||||
v, ok := value(f).Interface().(valueInterface)
|
||||
ok = ok && v.value.IsValid() && canAssertTypes(v.value.Type(), rtype)
|
||||
if ok {
|
||||
value0(f).Set(v.value)
|
||||
}
|
||||
if setStatus {
|
||||
value1(f).SetBool(ok)
|
||||
defer func() {
|
||||
value1(f).SetBool(ok)
|
||||
}()
|
||||
}
|
||||
if !ok || !v.value.IsValid() {
|
||||
ok = false
|
||||
if !withOk {
|
||||
panic(fmt.Sprintf("interface conversion: interface {} is nil, not %s", rtype.String()))
|
||||
}
|
||||
return next
|
||||
}
|
||||
ok = canAssertTypes(v.value.Type(), rtype)
|
||||
if !ok {
|
||||
if !withOk {
|
||||
panic(fmt.Sprintf("interface conversion: interface {} is %s, not %s", v.value.Type().String(), rtype.String()))
|
||||
}
|
||||
return next
|
||||
}
|
||||
value0(f).Set(v.value)
|
||||
return next
|
||||
}
|
||||
}
|
||||
@@ -343,10 +492,30 @@ func convert(n *node) {
|
||||
return
|
||||
}
|
||||
|
||||
if n.child[0].typ.cat == funcT && c.typ.cat == funcT {
|
||||
value := genValue(c)
|
||||
n.exec = func(f *frame) bltn {
|
||||
n, ok := value(f).Interface().(*node)
|
||||
if !ok || !n.typ.convertibleTo(c.typ) {
|
||||
panic("cannot convert")
|
||||
}
|
||||
n1 := *n
|
||||
n1.typ = c.typ
|
||||
dest(f).Set(reflect.ValueOf(&n1))
|
||||
return next
|
||||
}
|
||||
return
|
||||
}
|
||||
|
||||
doConvert := true
|
||||
var value func(*frame) reflect.Value
|
||||
if c.typ.cat == funcT {
|
||||
switch {
|
||||
case c.typ.cat == funcT:
|
||||
value = genFunctionWrapper(c)
|
||||
} else {
|
||||
case n.child[0].typ.cat == funcT && c.typ.cat == valueT:
|
||||
doConvert = false
|
||||
value = genValueNode(c)
|
||||
default:
|
||||
value = genValue(c)
|
||||
}
|
||||
|
||||
@@ -367,7 +536,11 @@ func convert(n *node) {
|
||||
}
|
||||
|
||||
n.exec = func(f *frame) bltn {
|
||||
dest(f).Set(value(f).Convert(typ))
|
||||
if doConvert {
|
||||
dest(f).Set(value(f).Convert(typ))
|
||||
} else {
|
||||
dest(f).Set(value(f))
|
||||
}
|
||||
return next
|
||||
}
|
||||
}
|
||||
@@ -517,12 +690,23 @@ func not(n *node) {
|
||||
|
||||
func addr(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).Addr())
|
||||
return next
|
||||
c0 := n.child[0]
|
||||
value := genValue(c0)
|
||||
switch c0.typ.cat {
|
||||
case interfaceT:
|
||||
i := n.findex
|
||||
l := n.level
|
||||
n.exec = func(f *frame) bltn {
|
||||
v := value(f).Interface().(valueInterface).value
|
||||
getFrame(f, l).data[i] = reflect.ValueOf(v.Interface())
|
||||
return next
|
||||
}
|
||||
default:
|
||||
n.exec = func(f *frame) bltn {
|
||||
dest(f).Set(value(f).Addr())
|
||||
return next
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -692,6 +876,9 @@ func genFunctionWrapper(n *node) func(*frame) reflect.Value {
|
||||
if src.Type().Kind() != dest.Type().Kind() {
|
||||
dest.Set(src.Addr())
|
||||
} else {
|
||||
if wrappedSrc, ok := src.Interface().(valueInterface); ok {
|
||||
src = wrappedSrc.value
|
||||
}
|
||||
dest.Set(src)
|
||||
}
|
||||
d = d[numRet+1:]
|
||||
@@ -797,7 +984,10 @@ func call(n *node) {
|
||||
var method bool
|
||||
value := genValue(n.child[0])
|
||||
var values []func(*frame) reflect.Value
|
||||
if n.child[0].recv != nil {
|
||||
|
||||
recvIndexLater := false
|
||||
switch {
|
||||
case n.child[0].recv != nil:
|
||||
// Compute method receiver value.
|
||||
if isRecursiveType(n.child[0].recv.node.typ, n.child[0].recv.node.typ.rtype) {
|
||||
values = append(values, genValueRecvInterfacePtr(n.child[0]))
|
||||
@@ -805,11 +995,17 @@ func call(n *node) {
|
||||
values = append(values, genValueRecv(n.child[0]))
|
||||
}
|
||||
method = true
|
||||
} else if n.child[0].action == aMethod {
|
||||
case len(n.child[0].child) > 0 && n.child[0].child[0].typ != nil && n.child[0].child[0].typ.cat == interfaceT:
|
||||
recvIndexLater = true
|
||||
values = append(values, genValueBinRecv(n.child[0], &receiver{node: n.child[0].child[0]}))
|
||||
value = genValueBinMethodOnInterface(n, value)
|
||||
method = true
|
||||
case n.child[0].action == aMethod:
|
||||
// Add a place holder for interface method receiver.
|
||||
values = append(values, nil)
|
||||
method = true
|
||||
}
|
||||
|
||||
numRet := len(n.child[0].typ.ret)
|
||||
variadic := variadicPos(n)
|
||||
child := n.child[1:]
|
||||
@@ -919,6 +1115,7 @@ func call(n *node) {
|
||||
n.exec = func(f *frame) bltn {
|
||||
var def *node
|
||||
var ok bool
|
||||
|
||||
bf := value(f)
|
||||
if def, ok = bf.Interface().(*node); ok {
|
||||
bf = def.rval
|
||||
@@ -988,16 +1185,16 @@ func call(n *node) {
|
||||
var src reflect.Value
|
||||
if v == nil {
|
||||
src = def.recv.val
|
||||
if len(def.recv.index) > 0 {
|
||||
if src.Kind() == reflect.Ptr {
|
||||
src = src.Elem().FieldByIndex(def.recv.index)
|
||||
} else {
|
||||
src = src.FieldByIndex(def.recv.index)
|
||||
}
|
||||
}
|
||||
} else {
|
||||
src = v(f)
|
||||
}
|
||||
if recvIndexLater && def.recv != nil && len(def.recv.index) > 0 {
|
||||
if src.Kind() == reflect.Ptr {
|
||||
src = src.Elem().FieldByIndex(def.recv.index)
|
||||
} else {
|
||||
src = src.FieldByIndex(def.recv.index)
|
||||
}
|
||||
}
|
||||
// Accommodate to receiver type
|
||||
d := dest[0]
|
||||
if ks, kd := src.Kind(), d.Kind(); ks != kd {
|
||||
@@ -1116,6 +1313,7 @@ func callBin(n *node) {
|
||||
c.val = reflect.Zero(argType)
|
||||
}
|
||||
}
|
||||
|
||||
switch c.typ.cat {
|
||||
case funcT:
|
||||
values = append(values, genFunctionWrapper(c))
|
||||
@@ -1128,6 +1326,14 @@ func callBin(n *node) {
|
||||
default:
|
||||
values = append(values, genInterfaceWrapper(c, defType))
|
||||
}
|
||||
case ptrT:
|
||||
if c.typ.val.cat == valueT {
|
||||
values = append(values, genValue(c))
|
||||
} else {
|
||||
values = append(values, genInterfaceWrapper(c, defType))
|
||||
}
|
||||
case valueT:
|
||||
values = append(values, genValue(c))
|
||||
default:
|
||||
values = append(values, genInterfaceWrapper(c, defType))
|
||||
}
|
||||
@@ -1528,6 +1734,15 @@ func getMethodByName(n *node) {
|
||||
|
||||
n.exec = func(f *frame) bltn {
|
||||
val := value0(f).Interface().(valueInterface)
|
||||
typ := val.node.typ
|
||||
if typ.node == nil && typ.cat == valueT {
|
||||
// happens with a var of empty interface type, that has value of concrete type
|
||||
// from runtime, being asserted to "user-defined" interface.
|
||||
if _, ok := typ.rtype.MethodByName(name); !ok {
|
||||
panic(fmt.Sprintf("method %s not found", name))
|
||||
}
|
||||
return next
|
||||
}
|
||||
m, li := val.node.typ.lookupMethod(name)
|
||||
fr := f.clone()
|
||||
nod := *m
|
||||
@@ -1719,6 +1934,11 @@ func neg(n *node) {
|
||||
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
|
||||
}
|
||||
case reflect.Float32, reflect.Float64:
|
||||
n.exec = func(f *frame) bltn {
|
||||
dest(f).SetFloat(-value(f).Float())
|
||||
@@ -2104,16 +2324,20 @@ func doComposite(n *node, hasType bool, keyed bool) {
|
||||
val = c
|
||||
fieldIndex = i
|
||||
}
|
||||
convertLiteralValue(val, typ.field[fieldIndex].typ.TypeOf())
|
||||
ft := typ.field[fieldIndex].typ
|
||||
rft := ft.TypeOf()
|
||||
convertLiteralValue(val, rft)
|
||||
switch {
|
||||
case val.typ.cat == nilT:
|
||||
values[fieldIndex] = func(*frame) reflect.Value { return reflect.New(rft).Elem() }
|
||||
case val.typ.cat == funcT:
|
||||
values[fieldIndex] = genFunctionWrapper(val)
|
||||
case isArray(val.typ) && val.typ.val != nil && val.typ.val.cat == interfaceT:
|
||||
values[fieldIndex] = genValueInterfaceArray(val)
|
||||
case isRecursiveType(typ.field[fieldIndex].typ, typ.field[fieldIndex].typ.rtype):
|
||||
values[fieldIndex] = genValueRecursiveInterface(val, typ.field[fieldIndex].typ.rtype)
|
||||
case isInterface(typ.field[fieldIndex].typ):
|
||||
values[fieldIndex] = genInterfaceWrapper(val, typ.field[fieldIndex].typ.rtype)
|
||||
case isRecursiveType(ft, rft):
|
||||
values[fieldIndex] = genValueRecursiveInterface(val, rft)
|
||||
case isInterface(ft):
|
||||
values[fieldIndex] = genInterfaceWrapper(val, rft)
|
||||
default:
|
||||
values[fieldIndex] = genValue(val)
|
||||
}
|
||||
@@ -3087,9 +3311,9 @@ func isNil(n *node) {
|
||||
fnext := getExec(n.fnext)
|
||||
if c0.typ.cat == interfaceT {
|
||||
n.exec = func(f *frame) bltn {
|
||||
vi := value(f).Interface().(valueInterface)
|
||||
if (vi == valueInterface{} ||
|
||||
vi.node.kind == basicLit && vi.node.typ.cat == nilT) {
|
||||
v := value(f)
|
||||
vi, ok := v.Interface().(valueInterface)
|
||||
if ok && (vi == valueInterface{} || vi.node.kind == basicLit && vi.node.typ.cat == nilT) || v.IsNil() {
|
||||
dest(f).SetBool(true)
|
||||
return tnext
|
||||
}
|
||||
@@ -3109,7 +3333,12 @@ func isNil(n *node) {
|
||||
} else {
|
||||
if c0.typ.cat == interfaceT {
|
||||
n.exec = func(f *frame) bltn {
|
||||
dest(f).SetBool(value(f).Interface().(valueInterface) == valueInterface{})
|
||||
v := value(f)
|
||||
if vi, ok := v.Interface().(valueInterface); ok {
|
||||
dest(f).SetBool(vi == valueInterface{} || vi.node.kind == basicLit && vi.node.typ.cat == nilT)
|
||||
} else {
|
||||
dest(f).SetBool(v.IsNil())
|
||||
}
|
||||
return tnext
|
||||
}
|
||||
} else {
|
||||
@@ -3136,9 +3365,9 @@ func isNotNil(n *node) {
|
||||
fnext := getExec(n.fnext)
|
||||
if c0.typ.cat == interfaceT {
|
||||
n.exec = func(f *frame) bltn {
|
||||
vi := value(f).Interface().(valueInterface)
|
||||
if (vi == valueInterface{} ||
|
||||
vi.node.kind == basicLit && vi.node.typ.cat == nilT) {
|
||||
v := value(f)
|
||||
vi, ok := v.Interface().(valueInterface)
|
||||
if ok && (vi == valueInterface{} || vi.node.kind == basicLit && vi.node.typ.cat == nilT) || v.IsNil() {
|
||||
dest(f).SetBool(false)
|
||||
return fnext
|
||||
}
|
||||
@@ -3158,7 +3387,12 @@ func isNotNil(n *node) {
|
||||
} else {
|
||||
if c0.typ.cat == interfaceT {
|
||||
n.exec = func(f *frame) bltn {
|
||||
dest(f).SetBool(!(value(f).Interface().(valueInterface) == valueInterface{}))
|
||||
v := value(f)
|
||||
if vi, ok := v.Interface().(valueInterface); ok {
|
||||
dest(f).SetBool(!(vi == valueInterface{} || vi.node.kind == basicLit && vi.node.typ.cat == nilT))
|
||||
} else {
|
||||
dest(f).SetBool(!v.IsNil())
|
||||
}
|
||||
return tnext
|
||||
}
|
||||
} else {
|
||||
|
||||
@@ -72,26 +72,28 @@ type symbol struct {
|
||||
// execution to the index in frame, created exactly from the types layout.
|
||||
//
|
||||
type scope struct {
|
||||
anc *scope // Ancestor upper scope
|
||||
anc *scope // ancestor upper scope
|
||||
child []*scope // included scopes
|
||||
def *node // function definition node this scope belongs to, or nil
|
||||
loop *node // loop exit node for break statement
|
||||
loopRestart *node // loop restart node for continue statement
|
||||
pkgID string // unique id of package in which scope is defined
|
||||
types []reflect.Type // Frame layout, may be shared by same level scopes
|
||||
level int // Frame level: number of frame indirections to access var during execution
|
||||
sym map[string]*symbol // Map of symbols defined in this current scope
|
||||
types []reflect.Type // frame layout, may be shared by same level scopes
|
||||
level int // frame level: number of frame indirections to access var during execution
|
||||
sym map[string]*symbol // map of symbols defined in this current scope
|
||||
global bool // true if scope refers to global space (single frame for universe and package level scopes)
|
||||
iota int // iota value in this scope
|
||||
}
|
||||
|
||||
// push creates a new scope and chain it to the current one.
|
||||
// push creates a new child scope and chain it to the current one.
|
||||
func (s *scope) push(indirect bool) *scope {
|
||||
sc := scope{anc: s, level: s.level, sym: map[string]*symbol{}}
|
||||
sc := &scope{anc: s, level: s.level, sym: map[string]*symbol{}}
|
||||
s.child = append(s.child, sc)
|
||||
if indirect {
|
||||
sc.types = []reflect.Type{}
|
||||
sc.level = s.level + 1
|
||||
} else {
|
||||
// propagate size, types, def and global as scopes at same level share the same frame
|
||||
// Propagate size, types, def and global as scopes at same level share the same frame.
|
||||
sc.types = s.types
|
||||
sc.def = s.def
|
||||
sc.global = s.global
|
||||
@@ -99,7 +101,7 @@ func (s *scope) push(indirect bool) *scope {
|
||||
}
|
||||
// inherit loop state and pkgID from ancestor
|
||||
sc.loop, sc.loopRestart, sc.pkgID = s.loop, s.loopRestart, s.pkgID
|
||||
return &sc
|
||||
return sc
|
||||
}
|
||||
|
||||
func (s *scope) pushBloc() *scope { return s.push(false) }
|
||||
@@ -107,12 +109,20 @@ func (s *scope) pushFunc() *scope { return s.push(true) }
|
||||
|
||||
func (s *scope) pop() *scope {
|
||||
if s.level == s.anc.level {
|
||||
// propagate size and types, as scopes at same level share the same frame
|
||||
// Propagate size and types, as scopes at same level share the same frame.
|
||||
s.anc.types = s.types
|
||||
}
|
||||
return s.anc
|
||||
}
|
||||
|
||||
func (s *scope) upperLevel() *scope {
|
||||
level := s.level
|
||||
for s != nil && s.level == level {
|
||||
s = s.anc
|
||||
}
|
||||
return s
|
||||
}
|
||||
|
||||
// lookup searches for a symbol in the current scope, and upper ones if not found
|
||||
// it returns the symbol, the number of indirections level from the current scope
|
||||
// and status (false if no result).
|
||||
@@ -130,6 +140,20 @@ func (s *scope) lookup(ident string) (*symbol, int, bool) {
|
||||
return nil, 0, false
|
||||
}
|
||||
|
||||
// lookdown searches for a symbol in the current scope and included ones, recursively.
|
||||
// It returns the first found symbol and true, or nil and false.
|
||||
func (s *scope) lookdown(ident string) (*symbol, bool) {
|
||||
if sym, ok := s.sym[ident]; ok {
|
||||
return sym, true
|
||||
}
|
||||
for _, c := range s.child {
|
||||
if sym, ok := c.lookdown(ident); ok {
|
||||
return sym, true
|
||||
}
|
||||
}
|
||||
return nil, false
|
||||
}
|
||||
|
||||
func (s *scope) rangeChanType(n *node) *itype {
|
||||
if sym, _, found := s.lookup(n.child[1].ident); found {
|
||||
if t := sym.typ; len(n.child) == 3 && t != nil && (t.cat == chanT || t.cat == chanRecvT) {
|
||||
|
||||
@@ -557,7 +557,8 @@ func nodeType(interp *Interpreter, sc *scope, n *node) (*itype, error) {
|
||||
if v, ok := pkg[name]; ok {
|
||||
t.cat = valueT
|
||||
t.rtype = v.Type()
|
||||
if isBinType(v) { // a bin type is encoded as a pointer on nil value
|
||||
if isBinType(v) {
|
||||
// A bin type is encoded as a pointer on a typed nil value.
|
||||
t.rtype = t.rtype.Elem()
|
||||
}
|
||||
} else {
|
||||
@@ -736,7 +737,7 @@ func (t *itype) finalize() (*itype, error) {
|
||||
}
|
||||
|
||||
// ReferTo returns true if the type contains a reference to a
|
||||
// full type name. It allows to asses a type recursive status.
|
||||
// full type name. It allows to assess a type recursive status.
|
||||
func (t *itype) referTo(name string, seen map[*itype]bool) bool {
|
||||
if t.path+"/"+t.name == name {
|
||||
return true
|
||||
|
||||
@@ -217,6 +217,7 @@ var binaryOpPredicates = opPredicates{
|
||||
// binaryExpr type checks a binary expression.
|
||||
func (check typecheck) binaryExpr(n *node) error {
|
||||
c0, c1 := n.child[0], n.child[1]
|
||||
|
||||
a := n.action
|
||||
if isAssignAction(a) {
|
||||
a--
|
||||
@@ -226,6 +227,21 @@ func (check typecheck) binaryExpr(n *node) error {
|
||||
return check.shift(n)
|
||||
}
|
||||
|
||||
switch n.action {
|
||||
case aRem:
|
||||
if zeroConst(c1) {
|
||||
return n.cfgErrorf("invalid operation: division by zero")
|
||||
}
|
||||
case aQuo:
|
||||
if zeroConst(c1) {
|
||||
return n.cfgErrorf("invalid operation: division by zero")
|
||||
}
|
||||
if c0.rval.IsValid() && c1.rval.IsValid() {
|
||||
// Avoid constant conversions below to ensure correct constant integer quotient.
|
||||
return nil
|
||||
}
|
||||
}
|
||||
|
||||
_ = check.convertUntyped(c0, c1.typ)
|
||||
_ = check.convertUntyped(c1, c0.typ)
|
||||
|
||||
@@ -241,16 +257,13 @@ func (check typecheck) binaryExpr(n *node) error {
|
||||
if err := check.op(binaryOpPredicates, a, n, c0, t0); err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
switch n.action {
|
||||
case aQuo, aRem:
|
||||
if (c0.typ.untyped || isInt(t0)) && c1.typ.untyped && constant.Sign(c1.rval.Interface().(constant.Value)) == 0 {
|
||||
return n.cfgErrorf("invalid operation: division by zero")
|
||||
}
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
func zeroConst(n *node) bool {
|
||||
return n.typ.untyped && constant.Sign(n.rval.Interface().(constant.Value)) == 0
|
||||
}
|
||||
|
||||
func (check typecheck) index(n *node, max int) error {
|
||||
if err := check.convertUntyped(n, &itype{cat: intT, name: "int"}); err != nil {
|
||||
return err
|
||||
@@ -486,9 +499,7 @@ func (check typecheck) sliceExpr(n *node) error {
|
||||
case reflect.Array:
|
||||
valid = true
|
||||
l = t.Len()
|
||||
if c.kind != indexExpr && c.kind != selectorExpr && (c.sym == nil || c.sym.kind != varSym) {
|
||||
return c.cfgErrorf("cannot slice type %s", c.typ.id())
|
||||
}
|
||||
// TODO(marc): check addressable status of array object (i.e. composite arrays are not).
|
||||
case reflect.Slice:
|
||||
valid = true
|
||||
case reflect.Ptr:
|
||||
@@ -621,16 +632,13 @@ func (check typecheck) conversion(n *node, typ *itype) error {
|
||||
if !ok {
|
||||
return n.cfgErrorf("cannot convert expression of type %s to type %s", n.typ.id(), typ.id())
|
||||
}
|
||||
|
||||
if n.typ.untyped {
|
||||
if isInterface(typ) || c != nil && !isConstType(typ) {
|
||||
typ = n.typ.defaultType()
|
||||
}
|
||||
if err := check.convertUntyped(n, typ); err != nil {
|
||||
return err
|
||||
}
|
||||
if !n.typ.untyped || c == nil {
|
||||
return nil
|
||||
}
|
||||
return nil
|
||||
if isInterface(typ) || !isConstType(typ) {
|
||||
typ = n.typ.defaultType()
|
||||
}
|
||||
return check.convertUntyped(n, typ)
|
||||
}
|
||||
|
||||
type param struct {
|
||||
|
||||
@@ -33,6 +33,30 @@ func valueOf(data []reflect.Value, i int) reflect.Value {
|
||||
return reflect.Value{}
|
||||
}
|
||||
|
||||
func genValueBinMethodOnInterface(n *node, defaultGen func(*frame) reflect.Value) func(*frame) reflect.Value {
|
||||
if n == nil || n.child == nil || n.child[0] == nil ||
|
||||
n.child[0].child == nil || n.child[0].child[0] == nil {
|
||||
return defaultGen
|
||||
}
|
||||
if n.child[0].child[1] == nil || n.child[0].child[1].ident == "" {
|
||||
return defaultGen
|
||||
}
|
||||
value0 := genValue(n.child[0].child[0])
|
||||
|
||||
return func(f *frame) reflect.Value {
|
||||
val, ok := value0(f).Interface().(valueInterface)
|
||||
if !ok {
|
||||
return defaultGen(f)
|
||||
}
|
||||
typ := val.node.typ
|
||||
if typ.node != nil || typ.cat != valueT {
|
||||
return defaultGen(f)
|
||||
}
|
||||
meth, _ := typ.rtype.MethodByName(n.child[0].child[1].ident)
|
||||
return meth.Func
|
||||
}
|
||||
}
|
||||
|
||||
func genValueRecvIndirect(n *node) func(*frame) reflect.Value {
|
||||
v := genValueRecv(n)
|
||||
return func(f *frame) reflect.Value { return v(f).Elem() }
|
||||
@@ -55,6 +79,35 @@ func genValueRecv(n *node) func(*frame) reflect.Value {
|
||||
}
|
||||
}
|
||||
|
||||
func genValueBinRecv(n *node, recv *receiver) func(*frame) reflect.Value {
|
||||
value := genValue(n)
|
||||
binValue := genValue(recv.node)
|
||||
|
||||
v := func(f *frame) reflect.Value {
|
||||
if def, ok := value(f).Interface().(*node); ok {
|
||||
if def != nil && def.recv != nil && def.recv.val.IsValid() {
|
||||
return def.recv.val
|
||||
}
|
||||
}
|
||||
|
||||
ival, _ := binValue(f).Interface().(valueInterface)
|
||||
return ival.value
|
||||
}
|
||||
|
||||
fi := recv.index
|
||||
if len(fi) == 0 {
|
||||
return v
|
||||
}
|
||||
|
||||
return func(f *frame) reflect.Value {
|
||||
r := v(f)
|
||||
if r.Kind() == reflect.Ptr {
|
||||
r = r.Elem()
|
||||
}
|
||||
return r.FieldByIndex(fi)
|
||||
}
|
||||
}
|
||||
|
||||
func genValueRecvInterfacePtr(n *node) func(*frame) reflect.Value {
|
||||
v := genValue(n.recv.node)
|
||||
fi := n.recv.index
|
||||
@@ -342,6 +395,10 @@ func vInt(v reflect.Value) (i int64) {
|
||||
}
|
||||
|
||||
func vUint(v reflect.Value) (i uint64) {
|
||||
if c := vConstantValue(v); c != nil {
|
||||
i, _ = constant.Uint64Val(constant.ToInt(c))
|
||||
return i
|
||||
}
|
||||
switch v.Type().Kind() {
|
||||
case reflect.Int, reflect.Int8, reflect.Int16, reflect.Int32, reflect.Int64:
|
||||
i = uint64(v.Int())
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
// Code generated by 'yaegi extract archive/tar'. DO NOT EDIT.
|
||||
|
||||
// +build go1.15,!go1.16
|
||||
// +build go1.15
|
||||
|
||||
package stdlib
|
||||
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
// Code generated by 'yaegi extract archive/zip'. DO NOT EDIT.
|
||||
|
||||
// +build go1.15,!go1.16
|
||||
// +build go1.15
|
||||
|
||||
package stdlib
|
||||
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
// Code generated by 'yaegi extract bufio'. DO NOT EDIT.
|
||||
|
||||
// +build go1.15,!go1.16
|
||||
// +build go1.15
|
||||
|
||||
package stdlib
|
||||
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
// Code generated by 'yaegi extract bytes'. DO NOT EDIT.
|
||||
|
||||
// +build go1.15,!go1.16
|
||||
// +build go1.15
|
||||
|
||||
package stdlib
|
||||
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
// Code generated by 'yaegi extract compress/bzip2'. DO NOT EDIT.
|
||||
|
||||
// +build go1.15,!go1.16
|
||||
// +build go1.15
|
||||
|
||||
package stdlib
|
||||
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
// Code generated by 'yaegi extract compress/flate'. DO NOT EDIT.
|
||||
|
||||
// +build go1.15,!go1.16
|
||||
// +build go1.15
|
||||
|
||||
package stdlib
|
||||
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
// Code generated by 'yaegi extract compress/gzip'. DO NOT EDIT.
|
||||
|
||||
// +build go1.15,!go1.16
|
||||
// +build go1.15
|
||||
|
||||
package stdlib
|
||||
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
// Code generated by 'yaegi extract compress/lzw'. DO NOT EDIT.
|
||||
|
||||
// +build go1.15,!go1.16
|
||||
// +build go1.15
|
||||
|
||||
package stdlib
|
||||
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
// Code generated by 'yaegi extract compress/zlib'. DO NOT EDIT.
|
||||
|
||||
// +build go1.15,!go1.16
|
||||
// +build go1.15
|
||||
|
||||
package stdlib
|
||||
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
// Code generated by 'yaegi extract container/heap'. DO NOT EDIT.
|
||||
|
||||
// +build go1.15,!go1.16
|
||||
// +build go1.15
|
||||
|
||||
package stdlib
|
||||
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
// Code generated by 'yaegi extract container/list'. DO NOT EDIT.
|
||||
|
||||
// +build go1.15,!go1.16
|
||||
// +build go1.15
|
||||
|
||||
package stdlib
|
||||
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
// Code generated by 'yaegi extract container/ring'. DO NOT EDIT.
|
||||
|
||||
// +build go1.15,!go1.16
|
||||
// +build go1.15
|
||||
|
||||
package stdlib
|
||||
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
// Code generated by 'yaegi extract context'. DO NOT EDIT.
|
||||
|
||||
// +build go1.15,!go1.16
|
||||
// +build go1.15
|
||||
|
||||
package stdlib
|
||||
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
// Code generated by 'yaegi extract crypto'. DO NOT EDIT.
|
||||
|
||||
// +build go1.15,!go1.16
|
||||
// +build go1.15
|
||||
|
||||
package stdlib
|
||||
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
// Code generated by 'yaegi extract crypto/aes'. DO NOT EDIT.
|
||||
|
||||
// +build go1.15,!go1.16
|
||||
// +build go1.15
|
||||
|
||||
package stdlib
|
||||
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
// Code generated by 'yaegi extract crypto/cipher'. DO NOT EDIT.
|
||||
|
||||
// +build go1.15,!go1.16
|
||||
// +build go1.15
|
||||
|
||||
package stdlib
|
||||
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
// Code generated by 'yaegi extract crypto/des'. DO NOT EDIT.
|
||||
|
||||
// +build go1.15,!go1.16
|
||||
// +build go1.15
|
||||
|
||||
package stdlib
|
||||
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
// Code generated by 'yaegi extract crypto/dsa'. DO NOT EDIT.
|
||||
|
||||
// +build go1.15,!go1.16
|
||||
// +build go1.15
|
||||
|
||||
package stdlib
|
||||
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
// Code generated by 'yaegi extract crypto/ecdsa'. DO NOT EDIT.
|
||||
|
||||
// +build go1.15,!go1.16
|
||||
// +build go1.15
|
||||
|
||||
package stdlib
|
||||
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
// Code generated by 'yaegi extract crypto/ed25519'. DO NOT EDIT.
|
||||
|
||||
// +build go1.15,!go1.16
|
||||
// +build go1.15
|
||||
|
||||
package stdlib
|
||||
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
// Code generated by 'yaegi extract crypto/elliptic'. DO NOT EDIT.
|
||||
|
||||
// +build go1.15,!go1.16
|
||||
// +build go1.15
|
||||
|
||||
package stdlib
|
||||
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
// Code generated by 'yaegi extract crypto/hmac'. DO NOT EDIT.
|
||||
|
||||
// +build go1.15,!go1.16
|
||||
// +build go1.15
|
||||
|
||||
package stdlib
|
||||
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
// Code generated by 'yaegi extract crypto/md5'. DO NOT EDIT.
|
||||
|
||||
// +build go1.15,!go1.16
|
||||
// +build go1.15
|
||||
|
||||
package stdlib
|
||||
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
// Code generated by 'yaegi extract crypto/rand'. DO NOT EDIT.
|
||||
|
||||
// +build go1.15,!go1.16
|
||||
// +build go1.15
|
||||
|
||||
package stdlib
|
||||
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
// Code generated by 'yaegi extract crypto/rc4'. DO NOT EDIT.
|
||||
|
||||
// +build go1.15,!go1.16
|
||||
// +build go1.15
|
||||
|
||||
package stdlib
|
||||
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
// Code generated by 'yaegi extract crypto/rsa'. DO NOT EDIT.
|
||||
|
||||
// +build go1.15,!go1.16
|
||||
// +build go1.15
|
||||
|
||||
package stdlib
|
||||
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
// Code generated by 'yaegi extract crypto/sha1'. DO NOT EDIT.
|
||||
|
||||
// +build go1.15,!go1.16
|
||||
// +build go1.15
|
||||
|
||||
package stdlib
|
||||
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
// Code generated by 'yaegi extract crypto/sha256'. DO NOT EDIT.
|
||||
|
||||
// +build go1.15,!go1.16
|
||||
// +build go1.15
|
||||
|
||||
package stdlib
|
||||
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
// Code generated by 'yaegi extract crypto/sha512'. DO NOT EDIT.
|
||||
|
||||
// +build go1.15,!go1.16
|
||||
// +build go1.15
|
||||
|
||||
package stdlib
|
||||
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
// Code generated by 'yaegi extract crypto/subtle'. DO NOT EDIT.
|
||||
|
||||
// +build go1.15,!go1.16
|
||||
// +build go1.15
|
||||
|
||||
package stdlib
|
||||
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
// Code generated by 'yaegi extract crypto/tls'. DO NOT EDIT.
|
||||
|
||||
// +build go1.15,!go1.16
|
||||
// +build go1.15
|
||||
|
||||
package stdlib
|
||||
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
// Code generated by 'yaegi extract crypto/x509'. DO NOT EDIT.
|
||||
|
||||
// +build go1.15,!go1.16
|
||||
// +build go1.15
|
||||
|
||||
package stdlib
|
||||
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
// Code generated by 'yaegi extract crypto/x509/pkix'. DO NOT EDIT.
|
||||
|
||||
// +build go1.15,!go1.16
|
||||
// +build go1.15
|
||||
|
||||
package stdlib
|
||||
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
// Code generated by 'yaegi extract database/sql'. DO NOT EDIT.
|
||||
|
||||
// +build go1.15,!go1.16
|
||||
// +build go1.15
|
||||
|
||||
package stdlib
|
||||
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
// Code generated by 'yaegi extract database/sql/driver'. DO NOT EDIT.
|
||||
|
||||
// +build go1.15,!go1.16
|
||||
// +build go1.15
|
||||
|
||||
package stdlib
|
||||
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
// Code generated by 'yaegi extract debug/dwarf'. DO NOT EDIT.
|
||||
|
||||
// +build go1.15,!go1.16
|
||||
// +build go1.15
|
||||
|
||||
package stdlib
|
||||
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
// Code generated by 'yaegi extract debug/elf'. DO NOT EDIT.
|
||||
|
||||
// +build go1.15,!go1.16
|
||||
// +build go1.15
|
||||
|
||||
package stdlib
|
||||
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
// Code generated by 'yaegi extract debug/gosym'. DO NOT EDIT.
|
||||
|
||||
// +build go1.15,!go1.16
|
||||
// +build go1.15
|
||||
|
||||
package stdlib
|
||||
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
// Code generated by 'yaegi extract debug/macho'. DO NOT EDIT.
|
||||
|
||||
// +build go1.15,!go1.16
|
||||
// +build go1.15
|
||||
|
||||
package stdlib
|
||||
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
// Code generated by 'yaegi extract debug/pe'. DO NOT EDIT.
|
||||
|
||||
// +build go1.15,!go1.16
|
||||
// +build go1.15
|
||||
|
||||
package stdlib
|
||||
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
// Code generated by 'yaegi extract debug/plan9obj'. DO NOT EDIT.
|
||||
|
||||
// +build go1.15,!go1.16
|
||||
// +build go1.15
|
||||
|
||||
package stdlib
|
||||
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
// Code generated by 'yaegi extract encoding'. DO NOT EDIT.
|
||||
|
||||
// +build go1.15,!go1.16
|
||||
// +build go1.15
|
||||
|
||||
package stdlib
|
||||
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
// Code generated by 'yaegi extract encoding/ascii85'. DO NOT EDIT.
|
||||
|
||||
// +build go1.15,!go1.16
|
||||
// +build go1.15
|
||||
|
||||
package stdlib
|
||||
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
// Code generated by 'yaegi extract encoding/asn1'. DO NOT EDIT.
|
||||
|
||||
// +build go1.15,!go1.16
|
||||
// +build go1.15
|
||||
|
||||
package stdlib
|
||||
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
// Code generated by 'yaegi extract encoding/base32'. DO NOT EDIT.
|
||||
|
||||
// +build go1.15,!go1.16
|
||||
// +build go1.15
|
||||
|
||||
package stdlib
|
||||
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
// Code generated by 'yaegi extract encoding/base64'. DO NOT EDIT.
|
||||
|
||||
// +build go1.15,!go1.16
|
||||
// +build go1.15
|
||||
|
||||
package stdlib
|
||||
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
// Code generated by 'yaegi extract encoding/binary'. DO NOT EDIT.
|
||||
|
||||
// +build go1.15,!go1.16
|
||||
// +build go1.15
|
||||
|
||||
package stdlib
|
||||
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
// Code generated by 'yaegi extract encoding/csv'. DO NOT EDIT.
|
||||
|
||||
// +build go1.15,!go1.16
|
||||
// +build go1.15
|
||||
|
||||
package stdlib
|
||||
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
// Code generated by 'yaegi extract encoding/gob'. DO NOT EDIT.
|
||||
|
||||
// +build go1.15,!go1.16
|
||||
// +build go1.15
|
||||
|
||||
package stdlib
|
||||
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
// Code generated by 'yaegi extract encoding/hex'. DO NOT EDIT.
|
||||
|
||||
// +build go1.15,!go1.16
|
||||
// +build go1.15
|
||||
|
||||
package stdlib
|
||||
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
// Code generated by 'yaegi extract encoding/json'. DO NOT EDIT.
|
||||
|
||||
// +build go1.15,!go1.16
|
||||
// +build go1.15
|
||||
|
||||
package stdlib
|
||||
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
// Code generated by 'yaegi extract encoding/pem'. DO NOT EDIT.
|
||||
|
||||
// +build go1.15,!go1.16
|
||||
// +build go1.15
|
||||
|
||||
package stdlib
|
||||
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
// Code generated by 'yaegi extract encoding/xml'. DO NOT EDIT.
|
||||
|
||||
// +build go1.15,!go1.16
|
||||
// +build go1.15
|
||||
|
||||
package stdlib
|
||||
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
// Code generated by 'yaegi extract errors'. DO NOT EDIT.
|
||||
|
||||
// +build go1.15,!go1.16
|
||||
// +build go1.15
|
||||
|
||||
package stdlib
|
||||
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
// Code generated by 'yaegi extract expvar'. DO NOT EDIT.
|
||||
|
||||
// +build go1.15,!go1.16
|
||||
// +build go1.15
|
||||
|
||||
package stdlib
|
||||
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
// Code generated by 'yaegi extract flag'. DO NOT EDIT.
|
||||
|
||||
// +build go1.15,!go1.16
|
||||
// +build go1.15
|
||||
|
||||
package stdlib
|
||||
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
// Code generated by 'yaegi extract fmt'. DO NOT EDIT.
|
||||
|
||||
// +build go1.15,!go1.16
|
||||
// +build go1.15
|
||||
|
||||
package stdlib
|
||||
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
// Code generated by 'yaegi extract go/ast'. DO NOT EDIT.
|
||||
|
||||
// +build go1.15,!go1.16
|
||||
// +build go1.15
|
||||
|
||||
package stdlib
|
||||
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
// Code generated by 'yaegi extract go/build'. DO NOT EDIT.
|
||||
|
||||
// +build go1.15,!go1.16
|
||||
// +build go1.15
|
||||
|
||||
package stdlib
|
||||
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
// Code generated by 'yaegi extract go/constant'. DO NOT EDIT.
|
||||
|
||||
// +build go1.15,!go1.16
|
||||
// +build go1.15
|
||||
|
||||
package stdlib
|
||||
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
// Code generated by 'yaegi extract go/doc'. DO NOT EDIT.
|
||||
|
||||
// +build go1.15,!go1.16
|
||||
// +build go1.15
|
||||
|
||||
package stdlib
|
||||
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
// Code generated by 'yaegi extract go/format'. DO NOT EDIT.
|
||||
|
||||
// +build go1.15,!go1.16
|
||||
// +build go1.15
|
||||
|
||||
package stdlib
|
||||
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
// Code generated by 'yaegi extract go/importer'. DO NOT EDIT.
|
||||
|
||||
// +build go1.15,!go1.16
|
||||
// +build go1.15
|
||||
|
||||
package stdlib
|
||||
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
// Code generated by 'yaegi extract go/parser'. DO NOT EDIT.
|
||||
|
||||
// +build go1.15,!go1.16
|
||||
// +build go1.15
|
||||
|
||||
package stdlib
|
||||
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
// Code generated by 'yaegi extract go/printer'. DO NOT EDIT.
|
||||
|
||||
// +build go1.15,!go1.16
|
||||
// +build go1.15
|
||||
|
||||
package stdlib
|
||||
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
// Code generated by 'yaegi extract go/scanner'. DO NOT EDIT.
|
||||
|
||||
// +build go1.15,!go1.16
|
||||
// +build go1.15
|
||||
|
||||
package stdlib
|
||||
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
// Code generated by 'yaegi extract go/token'. DO NOT EDIT.
|
||||
|
||||
// +build go1.15,!go1.16
|
||||
// +build go1.15
|
||||
|
||||
package stdlib
|
||||
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
// Code generated by 'yaegi extract go/types'. DO NOT EDIT.
|
||||
|
||||
// +build go1.15,!go1.16
|
||||
// +build go1.15
|
||||
|
||||
package stdlib
|
||||
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
// Code generated by 'yaegi extract hash'. DO NOT EDIT.
|
||||
|
||||
// +build go1.15,!go1.16
|
||||
// +build go1.15
|
||||
|
||||
package stdlib
|
||||
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
// Code generated by 'yaegi extract hash/adler32'. DO NOT EDIT.
|
||||
|
||||
// +build go1.15,!go1.16
|
||||
// +build go1.15
|
||||
|
||||
package stdlib
|
||||
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
// Code generated by 'yaegi extract hash/crc32'. DO NOT EDIT.
|
||||
|
||||
// +build go1.15,!go1.16
|
||||
// +build go1.15
|
||||
|
||||
package stdlib
|
||||
|
||||
|
||||
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user