Compare commits
23 Commits
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
563270ca02 | ||
|
|
5eecbe515b | ||
|
|
0a79069dfc | ||
|
|
0c8f538cd9 | ||
|
|
ca80ada849 | ||
|
|
3c6df504df | ||
|
|
98eacf3610 | ||
|
|
16ff52a949 | ||
|
|
640d1429e5 | ||
|
|
659913eebe | ||
|
|
b3766509cc | ||
|
|
bc2b224bae | ||
|
|
9d4685deea | ||
|
|
2a70a71dc2 | ||
|
|
851444453c | ||
|
|
a8b1c2a017 | ||
|
|
d229c2a2c7 | ||
|
|
2f2df7a0f8 | ||
|
|
4058fd8c44 | ||
|
|
097a745e72 | ||
|
|
1f514e63a8 | ||
|
|
a15ecb7176 | ||
|
|
d4aa84f729 |
16
_test/assign14.go
Normal file
16
_test/assign14.go
Normal file
@@ -0,0 +1,16 @@
|
||||
package main
|
||||
|
||||
var optionsG map[string]string = nil
|
||||
|
||||
var roundG = 30
|
||||
|
||||
func main() {
|
||||
dummy := roundG
|
||||
roundG = dummy + 1
|
||||
println(roundG)
|
||||
println(optionsG == nil)
|
||||
}
|
||||
|
||||
// Output:
|
||||
// 31
|
||||
// true
|
||||
11
_test/assign15.go
Normal file
11
_test/assign15.go
Normal file
@@ -0,0 +1,11 @@
|
||||
package main
|
||||
|
||||
func main() {
|
||||
var c chan<- struct{} = make(chan struct{})
|
||||
var d <-chan struct{} = c
|
||||
|
||||
_ = d
|
||||
}
|
||||
|
||||
// Error:
|
||||
// _test/assign15.go:5:26: cannot use type chan<- struct{} as type <-chan struct{} in assignment
|
||||
14
_test/comp2.go
Normal file
14
_test/comp2.go
Normal file
@@ -0,0 +1,14 @@
|
||||
package main
|
||||
|
||||
type delta int32
|
||||
|
||||
func main() {
|
||||
a := delta(-1)
|
||||
|
||||
println(a != -1)
|
||||
println(a == -1)
|
||||
}
|
||||
|
||||
// Output:
|
||||
// false
|
||||
// true
|
||||
15
_test/composite11.go
Normal file
15
_test/composite11.go
Normal file
@@ -0,0 +1,15 @@
|
||||
package main
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"image/color"
|
||||
)
|
||||
|
||||
func main() {
|
||||
c := color.NRGBA64{1, 1, 1, 1}
|
||||
|
||||
fmt.Println(c)
|
||||
}
|
||||
|
||||
// Output:
|
||||
// {1 1 1 1}
|
||||
17
_test/const15.go
Normal file
17
_test/const15.go
Normal file
@@ -0,0 +1,17 @@
|
||||
package main
|
||||
|
||||
type T1 t1
|
||||
|
||||
type t1 int8
|
||||
|
||||
const (
|
||||
P2 T1 = 2
|
||||
P3 T1 = 3
|
||||
)
|
||||
|
||||
func main() {
|
||||
println(P3)
|
||||
}
|
||||
|
||||
// Output:
|
||||
// 3
|
||||
12
_test/init1.go
Normal file
12
_test/init1.go
Normal file
@@ -0,0 +1,12 @@
|
||||
package main
|
||||
|
||||
func init() {
|
||||
println("here")
|
||||
}
|
||||
|
||||
func main() {
|
||||
init()
|
||||
}
|
||||
|
||||
// Error:
|
||||
// _test/init1.go:8:2: undefined: init
|
||||
19
_test/interface44.go
Normal file
19
_test/interface44.go
Normal file
@@ -0,0 +1,19 @@
|
||||
package main
|
||||
|
||||
type S struct {
|
||||
a int
|
||||
}
|
||||
|
||||
func main() {
|
||||
var i interface{} = S{a: 1}
|
||||
|
||||
s, ok := i.(S)
|
||||
if !ok {
|
||||
println("bad")
|
||||
return
|
||||
}
|
||||
println(s.a)
|
||||
}
|
||||
|
||||
// Output:
|
||||
// 1
|
||||
13
_test/interface45.go
Normal file
13
_test/interface45.go
Normal file
@@ -0,0 +1,13 @@
|
||||
package main
|
||||
|
||||
import "fmt"
|
||||
|
||||
func main() {
|
||||
var i interface{} = 1
|
||||
var s struct{}
|
||||
s, _ = i.(struct{})
|
||||
fmt.Println(s)
|
||||
}
|
||||
|
||||
// Output:
|
||||
// {}
|
||||
29
_test/issue-735.go
Normal file
29
_test/issue-735.go
Normal file
@@ -0,0 +1,29 @@
|
||||
package main
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"strconv"
|
||||
)
|
||||
|
||||
var optionsG map[string]string
|
||||
|
||||
var roundG int = 30
|
||||
|
||||
func strToInt(s string, defaultValue int) int {
|
||||
n, err := strconv.ParseInt(s, 10, 0)
|
||||
if err != nil {
|
||||
return defaultValue
|
||||
}
|
||||
return int(n)
|
||||
}
|
||||
|
||||
func main() {
|
||||
optionsG := map[string]string{"round": "12", "b": "one"}
|
||||
roundG = strToInt(optionsG["round"], 50)
|
||||
fmt.Println(roundG)
|
||||
fmt.Println(optionsG)
|
||||
}
|
||||
|
||||
// Output:
|
||||
// 12
|
||||
// map[b:one round:12]
|
||||
31
_test/issue-772.go
Normal file
31
_test/issue-772.go
Normal file
@@ -0,0 +1,31 @@
|
||||
package main
|
||||
|
||||
import (
|
||||
"log"
|
||||
"os"
|
||||
"text/template"
|
||||
)
|
||||
|
||||
type Message struct {
|
||||
Data string
|
||||
}
|
||||
|
||||
func main() {
|
||||
tmpl := template.New("name")
|
||||
|
||||
_, err := tmpl.Parse("{{.Data}}")
|
||||
if err != nil {
|
||||
log.Fatal(err)
|
||||
}
|
||||
|
||||
err = tmpl.Execute(os.Stdout, Message{
|
||||
Data: "Hello, World!!",
|
||||
})
|
||||
|
||||
if err != nil {
|
||||
log.Fatal(err)
|
||||
}
|
||||
}
|
||||
|
||||
// Output:
|
||||
// Hello, World!!
|
||||
18
_test/issue-775.go
Normal file
18
_test/issue-775.go
Normal file
@@ -0,0 +1,18 @@
|
||||
package main
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"net/http/httptest"
|
||||
)
|
||||
|
||||
func main() {
|
||||
recorder := httptest.NewRecorder()
|
||||
recorder.Header().Add("Foo", "Bar")
|
||||
|
||||
for key, value := range recorder.Header() {
|
||||
fmt.Println(key, value)
|
||||
}
|
||||
}
|
||||
|
||||
// Output:
|
||||
// Foo [Bar]
|
||||
39
_test/issue-776.go
Normal file
39
_test/issue-776.go
Normal file
@@ -0,0 +1,39 @@
|
||||
package main
|
||||
|
||||
import "fmt"
|
||||
|
||||
// Filter is a filter
|
||||
type Filter interface {
|
||||
Foo()
|
||||
}
|
||||
|
||||
// GIFT is a gift
|
||||
type GIFT struct {
|
||||
Filters []Filter
|
||||
}
|
||||
|
||||
// New is a new filter list
|
||||
func New(filters ...Filter) *GIFT {
|
||||
return &GIFT{
|
||||
Filters: filters,
|
||||
}
|
||||
}
|
||||
|
||||
// List lists filters
|
||||
func (g *GIFT) List() {
|
||||
fmt.Printf("Hello from List!\n")
|
||||
}
|
||||
|
||||
// MyFilter is one of the filters
|
||||
type MyFilter struct{}
|
||||
|
||||
// Foo is a foo
|
||||
func (f *MyFilter) Foo() {}
|
||||
|
||||
func main() {
|
||||
g := New(&MyFilter{})
|
||||
g.List()
|
||||
}
|
||||
|
||||
// Output:
|
||||
// Hello from List!
|
||||
12
_test/math2.go
Normal file
12
_test/math2.go
Normal file
@@ -0,0 +1,12 @@
|
||||
package main
|
||||
|
||||
const c uint64 = 2
|
||||
|
||||
func main() {
|
||||
if c&(1<<(uint64(1))) > 0 {
|
||||
println("yes")
|
||||
}
|
||||
}
|
||||
|
||||
// Output:
|
||||
// yes
|
||||
18
_test/restricted0.go
Normal file
18
_test/restricted0.go
Normal file
@@ -0,0 +1,18 @@
|
||||
package main
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"log"
|
||||
)
|
||||
|
||||
func main() {
|
||||
defer func() {
|
||||
r := recover()
|
||||
fmt.Println("recover:", r)
|
||||
}()
|
||||
log.Fatal("log.Fatal does not exit")
|
||||
println("not printed")
|
||||
}
|
||||
|
||||
// Output:
|
||||
// recover: log.Fatal does not exit
|
||||
18
_test/restricted1.go
Normal file
18
_test/restricted1.go
Normal file
@@ -0,0 +1,18 @@
|
||||
package main
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"os"
|
||||
)
|
||||
|
||||
func main() {
|
||||
defer func() {
|
||||
r := recover()
|
||||
fmt.Println("recover:", r)
|
||||
}()
|
||||
os.Exit(1)
|
||||
println("not printed")
|
||||
}
|
||||
|
||||
// Output:
|
||||
// recover: os.Exit(1)
|
||||
14
_test/restricted2.go
Normal file
14
_test/restricted2.go
Normal file
@@ -0,0 +1,14 @@
|
||||
package main
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"os"
|
||||
)
|
||||
|
||||
func main() {
|
||||
p, err := os.FindProcess(os.Getpid())
|
||||
fmt.Println(p, err)
|
||||
}
|
||||
|
||||
// Output:
|
||||
// <nil> restricted
|
||||
23
_test/restricted3.go
Normal file
23
_test/restricted3.go
Normal file
@@ -0,0 +1,23 @@
|
||||
package main
|
||||
|
||||
import (
|
||||
"bytes"
|
||||
"fmt"
|
||||
"log"
|
||||
)
|
||||
|
||||
var (
|
||||
buf bytes.Buffer
|
||||
logger = log.New(&buf, "logger: ", log.Lshortfile)
|
||||
)
|
||||
|
||||
func main() {
|
||||
defer func() {
|
||||
r := recover()
|
||||
fmt.Println("recover:", r, buf.String())
|
||||
}()
|
||||
logger.Fatal("test log")
|
||||
}
|
||||
|
||||
// Output:
|
||||
// recover: test log logger: restricted.go:39: test log
|
||||
@@ -1,15 +1,23 @@
|
||||
package main
|
||||
|
||||
import (
|
||||
"encoding/json"
|
||||
"os"
|
||||
)
|
||||
|
||||
type S struct {
|
||||
Child []*S
|
||||
Name string
|
||||
Child []*S
|
||||
}
|
||||
|
||||
func main() {
|
||||
s := &S{Name: "root"}
|
||||
s.Child = append(s.Child, &S{Name: "child"})
|
||||
println(s.Child[0].Name)
|
||||
a := S{Name: "hello"}
|
||||
a.Child = append(a.Child, &S{Name: "world"})
|
||||
json.NewEncoder(os.Stdout).Encode(a)
|
||||
a.Child[0].Child = append([]*S{}, &S{Name: "sunshine"})
|
||||
json.NewEncoder(os.Stdout).Encode(a)
|
||||
}
|
||||
|
||||
// Output:
|
||||
// child
|
||||
// {"Name":"hello","Child":[{"Name":"world","Child":null}]}
|
||||
// {"Name":"hello","Child":[{"Name":"world","Child":[{"Name":"sunshine","Child":null}]}]}
|
||||
|
||||
33
_test/struct49.go
Normal file
33
_test/struct49.go
Normal file
@@ -0,0 +1,33 @@
|
||||
package main
|
||||
|
||||
type S struct {
|
||||
ts map[string][]*T
|
||||
}
|
||||
|
||||
type T struct {
|
||||
s *S
|
||||
}
|
||||
|
||||
func (c *S) getT(addr string) (t *T, ok bool) {
|
||||
cns, ok := c.ts[addr]
|
||||
if !ok || len(cns) == 0 {
|
||||
return nil, false
|
||||
}
|
||||
|
||||
t = cns[len(cns)-1]
|
||||
c.ts[addr] = cns[:len(cns)-1]
|
||||
return t, true
|
||||
}
|
||||
|
||||
func main() {
|
||||
s := &S{
|
||||
ts: map[string][]*T{},
|
||||
}
|
||||
s.ts["test"] = append(s.ts["test"], &T{s: s})
|
||||
|
||||
t , ok:= s.getT("test")
|
||||
println(t != nil, ok)
|
||||
}
|
||||
|
||||
// Output:
|
||||
// true true
|
||||
20
_test/struct50.go
Normal file
20
_test/struct50.go
Normal file
@@ -0,0 +1,20 @@
|
||||
package main
|
||||
|
||||
import "fmt"
|
||||
|
||||
type Node struct {
|
||||
Name string
|
||||
Child []Node
|
||||
}
|
||||
|
||||
func main() {
|
||||
a := Node{Name: "hello"}
|
||||
a.Child = append([]Node{}, Node{Name: "world"})
|
||||
fmt.Println(a)
|
||||
a.Child[0].Child = append([]Node{}, Node{Name: "sunshine"})
|
||||
fmt.Println(a)
|
||||
}
|
||||
|
||||
// Output:
|
||||
// {hello [{world []}]}
|
||||
// {hello [{world [{sunshine []}]}]}
|
||||
23
_test/struct51.go
Normal file
23
_test/struct51.go
Normal file
@@ -0,0 +1,23 @@
|
||||
package main
|
||||
|
||||
import (
|
||||
"encoding/json"
|
||||
"os"
|
||||
)
|
||||
|
||||
type Node struct {
|
||||
Name string
|
||||
Child [2]*Node
|
||||
}
|
||||
|
||||
func main() {
|
||||
a := Node{Name: "hello"}
|
||||
a.Child[0] = &Node{Name: "world"}
|
||||
json.NewEncoder(os.Stdout).Encode(a)
|
||||
a.Child[0].Child[0] = &Node{Name: "sunshine"}
|
||||
json.NewEncoder(os.Stdout).Encode(a)
|
||||
}
|
||||
|
||||
// Output:
|
||||
// {"Name":"hello","Child":[{"Name":"world","Child":[null,null]},null]}
|
||||
// {"Name":"hello","Child":[{"Name":"world","Child":[{"Name":"sunshine","Child":[null,null]},null]},null]}
|
||||
20
_test/struct52.go
Normal file
20
_test/struct52.go
Normal file
@@ -0,0 +1,20 @@
|
||||
package main
|
||||
|
||||
import "fmt"
|
||||
|
||||
type Node struct {
|
||||
Name string
|
||||
Child map[string]Node
|
||||
}
|
||||
|
||||
func main() {
|
||||
a := Node{Name: "hello", Child: map[string]Node{}}
|
||||
a.Child["1"] = Node{Name: "world", Child: map[string]Node{}}
|
||||
fmt.Println(a)
|
||||
a.Child["1"].Child["1"] = Node{Name: "sunshine", Child: map[string]Node{}}
|
||||
fmt.Println(a)
|
||||
}
|
||||
|
||||
// Output:
|
||||
// {hello map[1:{world map[]}]}
|
||||
// {hello map[1:{world map[1:{sunshine map[]}]}]}
|
||||
23
_test/struct53.go
Normal file
23
_test/struct53.go
Normal file
@@ -0,0 +1,23 @@
|
||||
package main
|
||||
|
||||
import "fmt"
|
||||
|
||||
type T1 struct {
|
||||
P []*T
|
||||
}
|
||||
|
||||
type T2 struct {
|
||||
P2 *T
|
||||
}
|
||||
|
||||
type T struct {
|
||||
*T1
|
||||
S1 *T
|
||||
}
|
||||
|
||||
func main() {
|
||||
fmt.Println(T2{})
|
||||
}
|
||||
|
||||
// Output:
|
||||
// {<nil>}
|
||||
26
_test/struct54.go
Normal file
26
_test/struct54.go
Normal file
@@ -0,0 +1,26 @@
|
||||
package main
|
||||
|
||||
type S struct {
|
||||
t *T
|
||||
}
|
||||
|
||||
func newS() *S {
|
||||
return &S{
|
||||
t: &T{u: map[string]*U{}},
|
||||
}
|
||||
}
|
||||
|
||||
type T struct {
|
||||
u map[string]*U
|
||||
}
|
||||
|
||||
type U struct {
|
||||
a int
|
||||
}
|
||||
|
||||
func main() {
|
||||
s := newS()
|
||||
_ = s
|
||||
|
||||
println("ok")
|
||||
}
|
||||
28
_test/switch38.go
Normal file
28
_test/switch38.go
Normal file
@@ -0,0 +1,28 @@
|
||||
package main
|
||||
|
||||
func isSeparator(c byte) bool {
|
||||
switch c {
|
||||
case '(', ')', '<', '>', '@', ',', ';', ':', '\\', '"', '/', '[', ']', '?', '=', '{', '}', ' ', '\t':
|
||||
return true
|
||||
}
|
||||
return false
|
||||
}
|
||||
|
||||
func main() {
|
||||
s := "max-age=20"
|
||||
for _, c := range []byte(s) {
|
||||
println(string(c), isSeparator(c))
|
||||
}
|
||||
}
|
||||
|
||||
// Output:
|
||||
// m false
|
||||
// a false
|
||||
// x false
|
||||
// - false
|
||||
// a false
|
||||
// g false
|
||||
// e false
|
||||
// = true
|
||||
// 2 false
|
||||
// 0 false
|
||||
18
_test/time13.go
Normal file
18
_test/time13.go
Normal file
@@ -0,0 +1,18 @@
|
||||
package main
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"time"
|
||||
)
|
||||
|
||||
var dummy = 1
|
||||
|
||||
var t time.Time = time.Date(2007, time.November, 10, 23, 4, 5, 0, time.UTC)
|
||||
|
||||
func main() {
|
||||
t = time.Date(2009, time.November, 10, 23, 4, 5, 0, time.UTC)
|
||||
fmt.Println(t.Clock())
|
||||
}
|
||||
|
||||
// Output:
|
||||
// 23 4 5
|
||||
44
_test/type25.go
Normal file
44
_test/type25.go
Normal file
@@ -0,0 +1,44 @@
|
||||
package main
|
||||
|
||||
import (
|
||||
"errors"
|
||||
"sync/atomic"
|
||||
)
|
||||
|
||||
type wrappedError struct {
|
||||
wrapped error
|
||||
}
|
||||
|
||||
func (e wrappedError) Error() string {
|
||||
return "some outer error"
|
||||
}
|
||||
|
||||
func (e wrappedError) Unwrap() error {
|
||||
return e.wrapped
|
||||
}
|
||||
|
||||
var err atomic.Value
|
||||
|
||||
func getWrapped() *wrappedError {
|
||||
if v := err.Load(); v != nil {
|
||||
err := v.(wrappedError)
|
||||
if err.wrapped != nil {
|
||||
return &err
|
||||
}
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
func main() {
|
||||
err.Store(wrappedError{wrapped: errors.New("test")})
|
||||
|
||||
e := getWrapped()
|
||||
if e != nil {
|
||||
println(e.Error())
|
||||
println(e.wrapped.Error())
|
||||
}
|
||||
}
|
||||
|
||||
// Output:
|
||||
// some outer error
|
||||
// test
|
||||
44
_test/type26.go
Normal file
44
_test/type26.go
Normal file
@@ -0,0 +1,44 @@
|
||||
package main
|
||||
|
||||
import (
|
||||
"errors"
|
||||
"sync/atomic"
|
||||
)
|
||||
|
||||
type wrappedError struct {
|
||||
wrapped error
|
||||
}
|
||||
|
||||
func (e *wrappedError) Error() string {
|
||||
return "some outer error"
|
||||
}
|
||||
|
||||
func (e *wrappedError) Unwrap() error {
|
||||
return e.wrapped
|
||||
}
|
||||
|
||||
var err atomic.Value
|
||||
|
||||
func getWrapped() *wrappedError {
|
||||
if v := err.Load(); v != nil {
|
||||
err := v.(*wrappedError)
|
||||
if err.wrapped != nil {
|
||||
return err
|
||||
}
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
func main() {
|
||||
err.Store(&wrappedError{wrapped: errors.New("test")})
|
||||
|
||||
e := getWrapped()
|
||||
if e != nil {
|
||||
println(e.Error())
|
||||
println(e.wrapped.Error())
|
||||
}
|
||||
}
|
||||
|
||||
// Output:
|
||||
// some outer error
|
||||
// test
|
||||
13
_test/var12.go
Normal file
13
_test/var12.go
Normal file
@@ -0,0 +1,13 @@
|
||||
package main
|
||||
|
||||
var (
|
||||
a = b
|
||||
b = "hello"
|
||||
)
|
||||
|
||||
func main() {
|
||||
println(a)
|
||||
}
|
||||
|
||||
// Output:
|
||||
// hello
|
||||
23
_test/var13.go
Normal file
23
_test/var13.go
Normal file
@@ -0,0 +1,23 @@
|
||||
package main
|
||||
|
||||
var (
|
||||
a = concat("hello", b)
|
||||
b = concat(" ", c, "!")
|
||||
c = d
|
||||
d = "world"
|
||||
)
|
||||
|
||||
func concat(a ...string) string {
|
||||
var s string
|
||||
for _, ss := range a {
|
||||
s += ss
|
||||
}
|
||||
return s
|
||||
}
|
||||
|
||||
func main() {
|
||||
println(a)
|
||||
}
|
||||
|
||||
// Output:
|
||||
// hello world!
|
||||
10
_test/var14.go
Normal file
10
_test/var14.go
Normal file
@@ -0,0 +1,10 @@
|
||||
package main
|
||||
|
||||
import "github.com/containous/yaegi/_test/vars"
|
||||
|
||||
func main() {
|
||||
println(vars.A)
|
||||
}
|
||||
|
||||
// Output:
|
||||
// hello world!
|
||||
14
_test/variadic9.go
Normal file
14
_test/variadic9.go
Normal file
@@ -0,0 +1,14 @@
|
||||
package main
|
||||
|
||||
import "fmt"
|
||||
|
||||
func Sprintf(format string, a ...interface{}) string {
|
||||
return fmt.Sprintf(format, a...)
|
||||
}
|
||||
|
||||
func main() {
|
||||
fmt.Println(Sprintf("Hello %s", "World!"))
|
||||
}
|
||||
|
||||
// Output:
|
||||
// Hello World!
|
||||
14
_test/vars/first.go
Normal file
14
_test/vars/first.go
Normal file
@@ -0,0 +1,14 @@
|
||||
package vars
|
||||
|
||||
var (
|
||||
A = concat("hello", B)
|
||||
C = D
|
||||
)
|
||||
|
||||
func concat(a ...string) string {
|
||||
var s string
|
||||
for _, ss := range a {
|
||||
s += ss
|
||||
}
|
||||
return s
|
||||
}
|
||||
6
_test/vars/second.go
Normal file
6
_test/vars/second.go
Normal file
@@ -0,0 +1,6 @@
|
||||
package vars
|
||||
|
||||
var (
|
||||
B = concat(" ", C, "!")
|
||||
D = "world"
|
||||
)
|
||||
@@ -115,6 +115,17 @@ type Wrap struct {
|
||||
Method []Method
|
||||
}
|
||||
|
||||
// restricted map defines symbols for which a special implementation is provided.
|
||||
var restricted = map[string]bool{
|
||||
"osExit": true,
|
||||
"osFindProcess": true,
|
||||
"logFatal": true,
|
||||
"logFatalf": true,
|
||||
"logFatalln": true,
|
||||
"logLogger": true,
|
||||
"logNew": true,
|
||||
}
|
||||
|
||||
func genContent(dest, pkgName, license string, skip map[string]bool) ([]byte, error) {
|
||||
p, err := importer.ForCompiler(token.NewFileSet(), "source", nil).Import(pkgName)
|
||||
if err != nil {
|
||||
@@ -150,6 +161,10 @@ func genContent(dest, pkgName, license string, skip map[string]bool) ([]byte, er
|
||||
if skip[pname] {
|
||||
continue
|
||||
}
|
||||
if rname := path.Base(pkgName) + name; restricted[rname] {
|
||||
// Restricted symbol, locally provided by stdlib wrapper.
|
||||
pname = rname
|
||||
}
|
||||
|
||||
switch o := o.(type) {
|
||||
case *types.Const:
|
||||
|
||||
@@ -96,17 +96,20 @@ import (
|
||||
"github.com/containous/yaegi/interp"
|
||||
"github.com/containous/yaegi/stdlib"
|
||||
"github.com/containous/yaegi/stdlib/syscall"
|
||||
"github.com/containous/yaegi/stdlib/unrestricted"
|
||||
"github.com/containous/yaegi/stdlib/unsafe"
|
||||
)
|
||||
|
||||
func main() {
|
||||
var interactive bool
|
||||
var useUnsafe bool
|
||||
var useSyscall bool
|
||||
var useUnrestricted bool
|
||||
var useUnsafe bool
|
||||
var tags string
|
||||
var cmd string
|
||||
flag.BoolVar(&interactive, "i", false, "start an interactive REPL")
|
||||
flag.BoolVar(&useSyscall, "syscall", false, "include syscall symbols")
|
||||
flag.BoolVar(&useUnrestricted, "unrestricted", false, "include unrestricted symbols")
|
||||
flag.StringVar(&tags, "tags", "", "set a list of build tags")
|
||||
flag.BoolVar(&useUnsafe, "unsafe", false, "include usafe symbols")
|
||||
flag.StringVar(&cmd, "e", "", "set the command to be executed (instead of script or/and shell)")
|
||||
@@ -128,6 +131,10 @@ func main() {
|
||||
if useUnsafe {
|
||||
i.Use(unsafe.Symbols)
|
||||
}
|
||||
if useUnrestricted {
|
||||
// Use of unrestricted symbols should always follow use of stdlib symbols, to update them.
|
||||
i.Use(unrestricted.Symbols)
|
||||
}
|
||||
|
||||
if cmd != `` {
|
||||
i.REPL(strings.NewReader(cmd), os.Stderr)
|
||||
|
||||
11
example/pkg/_pkg12/src/guthib.com/foo/main.go
Normal file
11
example/pkg/_pkg12/src/guthib.com/foo/main.go
Normal file
@@ -0,0 +1,11 @@
|
||||
package main
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
|
||||
"guthib.com/foo/pkg"
|
||||
)
|
||||
|
||||
func main() {
|
||||
fmt.Printf("%s", pkg.NewSample()())
|
||||
}
|
||||
17
example/pkg/_pkg12/src/guthib.com/foo/pkg/pkg.go
Normal file
17
example/pkg/_pkg12/src/guthib.com/foo/pkg/pkg.go
Normal file
@@ -0,0 +1,17 @@
|
||||
package pkg
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
|
||||
"guthib.com/bar"
|
||||
)
|
||||
|
||||
func Here() string {
|
||||
return "hello"
|
||||
}
|
||||
|
||||
func NewSample() func() string {
|
||||
return func() string {
|
||||
return fmt.Sprintf("%s %s", bar.Bar(), Here())
|
||||
}
|
||||
}
|
||||
6
example/pkg/_pkg12/src/guthib.com/foo/vendor/guthib.com/bar/bar.go
generated
vendored
Normal file
6
example/pkg/_pkg12/src/guthib.com/foo/vendor/guthib.com/bar/bar.go
generated
vendored
Normal file
@@ -0,0 +1,6 @@
|
||||
package bar
|
||||
|
||||
// Bar is bar
|
||||
func Bar() string {
|
||||
return "Yo"
|
||||
}
|
||||
@@ -83,6 +83,18 @@ func TestPackages(t *testing.T) {
|
||||
expected: "Fromage",
|
||||
evalFile: "./_pkg11/src/foo/foo.go",
|
||||
},
|
||||
{
|
||||
desc: "vendor dir is a sibling or an uncle",
|
||||
goPath: "./_pkg12/",
|
||||
expected: "Yo hello",
|
||||
topImport: "guthib.com/foo/pkg",
|
||||
},
|
||||
{
|
||||
desc: "eval main with vendor as a sibling",
|
||||
goPath: "./_pkg12/",
|
||||
expected: "Yo hello",
|
||||
evalFile: "./_pkg12/src/guthib.com/foo/main.go",
|
||||
},
|
||||
}
|
||||
|
||||
for _, test := range testCases {
|
||||
@@ -116,7 +128,7 @@ func TestPackages(t *testing.T) {
|
||||
os.Stdout = pw
|
||||
|
||||
if _, err := i.Eval(string(data)); err != nil {
|
||||
t.Fatal(err)
|
||||
fatalStderrf(t, "%v", err)
|
||||
}
|
||||
|
||||
var buf bytes.Buffer
|
||||
@@ -127,10 +139,10 @@ func TestPackages(t *testing.T) {
|
||||
}()
|
||||
|
||||
if err := pw.Close(); err != nil {
|
||||
t.Fatal(err)
|
||||
fatalStderrf(t, "%v", err)
|
||||
}
|
||||
if err := <-errC; err != nil {
|
||||
t.Fatal(err)
|
||||
fatalStderrf(t, "%v", err)
|
||||
}
|
||||
msg = buf.String()
|
||||
} else {
|
||||
@@ -153,12 +165,17 @@ func TestPackages(t *testing.T) {
|
||||
}
|
||||
|
||||
if msg != test.expected {
|
||||
t.Errorf("Got %q, want %q", msg, test.expected)
|
||||
fatalStderrf(t, "Got %q, want %q", msg, test.expected)
|
||||
}
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
func fatalStderrf(t *testing.T, format string, args ...interface{}) {
|
||||
fmt.Fprintf(os.Stderr, format+"\n", args...)
|
||||
t.FailNow()
|
||||
}
|
||||
|
||||
func TestPackagesError(t *testing.T) {
|
||||
testCases := []struct {
|
||||
desc string
|
||||
|
||||
@@ -412,6 +412,8 @@ func {{$name}}(n *node) {
|
||||
dest := genValueOutput(n, reflect.TypeOf(true))
|
||||
c0, c1 := n.child[0], n.child[1]
|
||||
|
||||
{{- if or (eq $op.Name "==") (eq $op.Name "!=") }}
|
||||
|
||||
if c0.typ.cat == aliasT || c1.typ.cat == aliasT {
|
||||
switch {
|
||||
case c0.rval.IsValid():
|
||||
@@ -432,7 +434,7 @@ func {{$name}}(n *node) {
|
||||
dest := genValue(n)
|
||||
n.exec = func(f *frame) bltn {
|
||||
i1 := v1(f).Interface()
|
||||
dest(f).SetBool(i0 != i1)
|
||||
dest(f).SetBool(i0 {{$op.Name}} i1)
|
||||
return tnext
|
||||
}
|
||||
}
|
||||
@@ -454,7 +456,7 @@ func {{$name}}(n *node) {
|
||||
dest := genValue(n)
|
||||
n.exec = func(f *frame) bltn {
|
||||
i0 := v0(f).Interface()
|
||||
dest(f).SetBool(i0 != i1)
|
||||
dest(f).SetBool(i0 {{$op.Name}} i1)
|
||||
return tnext
|
||||
}
|
||||
}
|
||||
@@ -478,13 +480,14 @@ func {{$name}}(n *node) {
|
||||
n.exec = func(f *frame) bltn {
|
||||
i0 := v0(f).Interface()
|
||||
i1 := v1(f).Interface()
|
||||
dest(f).SetBool(i0 != i1)
|
||||
dest(f).SetBool(i0 {{$op.Name}} i1)
|
||||
return tnext
|
||||
}
|
||||
}
|
||||
}
|
||||
return
|
||||
}
|
||||
{{- end}}
|
||||
|
||||
switch t0, t1 := c0.typ.TypeOf(), c1.typ.TypeOf(); {
|
||||
case isString(t0) || isString(t1):
|
||||
|
||||
213
interp/cfg.go
213
interp/cfg.go
@@ -476,6 +476,9 @@ func (interp *Interpreter) cfg(root *node, pkgID string) ([]*node, error) {
|
||||
dest.typ = sc.fixType(src.typ)
|
||||
}
|
||||
}
|
||||
if dest.typ.incomplete {
|
||||
return
|
||||
}
|
||||
if dest.typ.sizedef {
|
||||
dest.typ.size = arrayTypeLen(src)
|
||||
dest.typ.rtype = nil
|
||||
@@ -518,8 +521,25 @@ func (interp *Interpreter) cfg(root *node, pkgID string) ([]*node, error) {
|
||||
err = src.cfgErrorf("invalid float truncate")
|
||||
return
|
||||
}
|
||||
|
||||
// TODO: Rudimentary type check at this point,
|
||||
// improvements need to be made to make it better.
|
||||
switch {
|
||||
case dest.typ.untyped || src.typ.untyped:
|
||||
// Both side of the assignment must be typed.
|
||||
case isRecursiveType(dest.typ, dest.typ.rtype) || isRecursiveType(src.typ, src.typ.rtype):
|
||||
// Recursive types cannot be type checked.
|
||||
case t0.Kind() == reflect.Interface || t0.Kind() == reflect.Func:
|
||||
// We have no way of checking interfaces and functions.
|
||||
case t1.AssignableTo(t0):
|
||||
// All is well when they are assignable.
|
||||
default:
|
||||
err = src.cfgErrorf("cannot use type %s as type %s in assignment", src.typ.id(), dest.typ.id())
|
||||
return
|
||||
}
|
||||
}
|
||||
n.findex = dest.findex
|
||||
n.level = dest.level
|
||||
|
||||
// Propagate type
|
||||
// TODO: Check that existing destination type matches source type
|
||||
@@ -679,6 +699,7 @@ func (interp *Interpreter) cfg(root *node, pkgID string) ([]*node, error) {
|
||||
if !isShiftNode(n) && !isConstVal(c) && !c0.typ.equals(c1.typ) && t0 != nil && t1 != nil {
|
||||
switch {
|
||||
case isConstVal(c0) && isNumber(t1) || isConstVal(c1) && isNumber(t0): // const <-> numberic case
|
||||
case isNumber(t0) && isNumber(t1) && (c0.typ.untyped || c1.typ.untyped):
|
||||
case t0.Kind() == reflect.Uint8 && t1.Kind() == reflect.Int32 || t1.Kind() == reflect.Uint8 && t0.Kind() == reflect.Int32: // byte <-> rune case
|
||||
case isInterface(c0.typ) && isInterface(c1.typ): // interface <-> interface case
|
||||
default:
|
||||
@@ -715,6 +736,18 @@ func (interp *Interpreter) cfg(root *node, pkgID string) ([]*node, error) {
|
||||
n.typ = c0.typ
|
||||
case aEqual, aNotEqual:
|
||||
n.typ = sc.getType("bool")
|
||||
if isConstVal(c0) && !isConstVal(c1) || !isConstVal(c0) && isConstVal(c1) {
|
||||
// if either node is a constant value, but the other is not, the constant
|
||||
// must be converted into the non-constants type.
|
||||
switch {
|
||||
case isConstVal(c0):
|
||||
convertConstantValue(c0)
|
||||
c0.rval = c0.rval.Convert(c1.typ.TypeOf())
|
||||
default:
|
||||
convertConstantValue(c1)
|
||||
c1.rval = c1.rval.Convert(c0.typ.TypeOf())
|
||||
}
|
||||
}
|
||||
if n.child[0].sym == nilSym || n.child[1].sym == nilSym {
|
||||
if n.action == aEqual {
|
||||
n.gen = isNil
|
||||
@@ -749,6 +782,7 @@ func (interp *Interpreter) cfg(root *node, pkgID string) ([]*node, error) {
|
||||
dest := n.anc.child[childPos(n)-n.anc.nright]
|
||||
n.typ = dest.typ
|
||||
n.findex = dest.findex
|
||||
n.level = dest.level
|
||||
case n.anc.kind == returnStmt:
|
||||
// To avoid a copy in frame, if the result is to be returned, store it directly
|
||||
// at the frame location reserved for output arguments.
|
||||
@@ -804,6 +838,7 @@ func (interp *Interpreter) cfg(root *node, pkgID string) ([]*node, error) {
|
||||
if len(n.child) > 0 {
|
||||
l := n.lastChild()
|
||||
n.findex = l.findex
|
||||
n.level = l.level
|
||||
n.val = l.val
|
||||
n.sym = l.sym
|
||||
n.typ = l.typ
|
||||
@@ -811,13 +846,22 @@ func (interp *Interpreter) cfg(root *node, pkgID string) ([]*node, error) {
|
||||
}
|
||||
sc = sc.pop()
|
||||
|
||||
case constDecl, varDecl:
|
||||
case constDecl:
|
||||
wireChild(n)
|
||||
|
||||
case varDecl:
|
||||
// Global varDecl do not need to be wired as this
|
||||
// will be handled after cfg.
|
||||
if n.anc.kind == fileStmt {
|
||||
break
|
||||
}
|
||||
wireChild(n)
|
||||
|
||||
case declStmt, exprStmt, sendStmt:
|
||||
wireChild(n)
|
||||
l := n.lastChild()
|
||||
n.findex = l.findex
|
||||
n.level = l.level
|
||||
n.val = l.val
|
||||
n.sym = l.sym
|
||||
n.typ = l.typ
|
||||
@@ -884,6 +928,7 @@ func (interp *Interpreter) cfg(root *node, pkgID string) ([]*node, error) {
|
||||
n.gen = nop
|
||||
n.typ = n.child[1].typ
|
||||
n.findex = n.child[1].findex
|
||||
n.level = n.child[1].level
|
||||
n.val = n.child[1].val
|
||||
n.rval = n.child[1].rval
|
||||
} else {
|
||||
@@ -997,7 +1042,7 @@ func (interp *Interpreter) cfg(root *node, pkgID string) ([]*node, error) {
|
||||
}
|
||||
|
||||
case fileStmt:
|
||||
wireChild(n)
|
||||
wireChild(n, varDecl)
|
||||
sc = sc.pop()
|
||||
n.findex = -1
|
||||
|
||||
@@ -1109,11 +1154,11 @@ func (interp *Interpreter) cfg(root *node, pkgID string) ([]*node, error) {
|
||||
n.types = sc.types
|
||||
sc = sc.pop()
|
||||
funcName := n.child[1].ident
|
||||
if !isMethod(n) {
|
||||
interp.scopes[pkgID].sym[funcName].index = -1 // to force value to n.val
|
||||
interp.scopes[pkgID].sym[funcName].typ = n.typ
|
||||
interp.scopes[pkgID].sym[funcName].kind = funcSym
|
||||
interp.scopes[pkgID].sym[funcName].node = n
|
||||
if sym := sc.sym[funcName]; !isMethod(n) && sym != nil {
|
||||
sym.index = -1 // to force value to n.val
|
||||
sym.typ = n.typ
|
||||
sym.kind = funcSym
|
||||
sym.node = n
|
||||
}
|
||||
|
||||
case funcLit:
|
||||
@@ -1128,6 +1173,10 @@ func (interp *Interpreter) cfg(root *node, pkgID string) ([]*node, error) {
|
||||
if isKey(n) || isNewDefine(n, sc) {
|
||||
break
|
||||
}
|
||||
if n.anc.kind == funcDecl && n.anc.child[1] == n {
|
||||
// Dont process a function name identExpr.
|
||||
break
|
||||
}
|
||||
|
||||
sym, level, found := sc.lookup(n.ident)
|
||||
if !found {
|
||||
@@ -1152,6 +1201,7 @@ func (interp *Interpreter) cfg(root *node, pkgID string) ([]*node, error) {
|
||||
case n.ident == "iota":
|
||||
n.rval = reflect.ValueOf(sc.iota)
|
||||
n.kind = basicLit
|
||||
n.typ.untyped = true
|
||||
case n.ident == "nil":
|
||||
n.kind = basicLit
|
||||
case sym.kind == binSym:
|
||||
@@ -1278,12 +1328,13 @@ func (interp *Interpreter) cfg(root *node, pkgID string) ([]*node, error) {
|
||||
wireChild(n)
|
||||
c := n.lastChild()
|
||||
n.findex = c.findex
|
||||
n.level = c.level
|
||||
n.typ = c.typ
|
||||
n.rval = c.rval
|
||||
|
||||
case rangeStmt:
|
||||
if sc.rangeChanType(n) != nil {
|
||||
n.start = n.child[1] // Get chan
|
||||
n.start = n.child[1].start // Get chan
|
||||
n.child[1].tnext = n // then go to range function
|
||||
n.tnext = n.child[2].start // then go to range body
|
||||
n.child[2].tnext = n // then body go to range function (loop)
|
||||
@@ -1295,7 +1346,7 @@ func (interp *Interpreter) cfg(root *node, pkgID string) ([]*node, error) {
|
||||
} else {
|
||||
k, o, body = n.child[0], n.child[1], n.child[2]
|
||||
}
|
||||
n.start = o // Get array or map object
|
||||
n.start = o.start // Get array or map object
|
||||
o.tnext = k.start // then go to iterator init
|
||||
k.tnext = n // then go to range function
|
||||
n.tnext = body.start // then go to range body
|
||||
@@ -1680,7 +1731,7 @@ func (interp *Interpreter) cfg(root *node, pkgID string) ([]*node, error) {
|
||||
}
|
||||
}
|
||||
if n.anc.action != aAssignX {
|
||||
if n.child[0].typ.cat == valueT {
|
||||
if n.child[0].typ.cat == valueT && !isStruct(n.child[1].typ) {
|
||||
// Avoid special wrapping of interfaces and func types.
|
||||
n.typ = &itype{cat: valueT, rtype: n.child[1].typ.TypeOf()}
|
||||
} else {
|
||||
@@ -1744,6 +1795,7 @@ func (interp *Interpreter) cfg(root *node, pkgID string) ([]*node, error) {
|
||||
dest := n.anc.child[childPos(n)-n.anc.nright]
|
||||
n.typ = dest.typ
|
||||
n.findex = dest.findex
|
||||
n.level = dest.level
|
||||
case n.anc.kind == returnStmt:
|
||||
pos := childPos(n)
|
||||
n.typ = sc.def.typ.ret[pos]
|
||||
@@ -1902,6 +1954,90 @@ func genRun(nod *node) error {
|
||||
return err
|
||||
}
|
||||
|
||||
func genGlobalVars(roots []*node, sc *scope) (*node, error) {
|
||||
var vars []*node
|
||||
for _, n := range roots {
|
||||
vars = append(vars, getVars(n)...)
|
||||
}
|
||||
|
||||
if len(vars) == 0 {
|
||||
return nil, nil
|
||||
}
|
||||
|
||||
varNode, err := genGlobalVarDecl(vars, sc)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
setExec(varNode.start)
|
||||
return varNode, nil
|
||||
}
|
||||
|
||||
func getVars(n *node) (vars []*node) {
|
||||
for _, child := range n.child {
|
||||
if child.kind == varDecl {
|
||||
vars = append(vars, child.child...)
|
||||
}
|
||||
}
|
||||
return vars
|
||||
}
|
||||
|
||||
func genGlobalVarDecl(nodes []*node, sc *scope) (*node, error) {
|
||||
varNode := &node{kind: varDecl, action: aNop, gen: nop}
|
||||
|
||||
deps := map[*node][]*node{}
|
||||
for _, n := range nodes {
|
||||
deps[n] = getVarDependencies(n, sc)
|
||||
}
|
||||
|
||||
inited := map[*node]bool{}
|
||||
revisit := []*node{}
|
||||
for {
|
||||
for _, n := range nodes {
|
||||
canInit := true
|
||||
for _, d := range deps[n] {
|
||||
if !inited[d] {
|
||||
canInit = false
|
||||
}
|
||||
}
|
||||
if !canInit {
|
||||
revisit = append(revisit, n)
|
||||
continue
|
||||
}
|
||||
|
||||
varNode.child = append(varNode.child, n)
|
||||
inited[n] = true
|
||||
}
|
||||
|
||||
if len(revisit) == 0 || equalNodes(nodes, revisit) {
|
||||
break
|
||||
}
|
||||
|
||||
nodes = revisit
|
||||
revisit = []*node{}
|
||||
}
|
||||
|
||||
if len(revisit) > 0 {
|
||||
return nil, revisit[0].cfgErrorf("variable definition loop")
|
||||
}
|
||||
wireChild(varNode)
|
||||
return varNode, nil
|
||||
}
|
||||
|
||||
func getVarDependencies(nod *node, sc *scope) (deps []*node) {
|
||||
nod.Walk(func(n *node) bool {
|
||||
if n.kind == identExpr {
|
||||
if sym, _, ok := sc.lookup(n.ident); ok {
|
||||
if sym.kind != varSym || !sym.global || sym.node == nod {
|
||||
return false
|
||||
}
|
||||
deps = append(deps, sym.node)
|
||||
}
|
||||
}
|
||||
return true
|
||||
}, nil)
|
||||
return deps
|
||||
}
|
||||
|
||||
// setFnext sets the cond fnext field to next, propagates it for parenthesis blocks
|
||||
// and sets the action to branch.
|
||||
func setFNext(cond, next *node) {
|
||||
@@ -1961,47 +2097,68 @@ func (n *node) isType(sc *scope) bool {
|
||||
}
|
||||
|
||||
// wireChild wires AST nodes for CFG in subtree.
|
||||
func wireChild(n *node) {
|
||||
func wireChild(n *node, exclude ...nkind) {
|
||||
child := excludeNodeKind(n.child, exclude)
|
||||
|
||||
// Set start node, in subtree (propagated to ancestors by post-order processing)
|
||||
for _, child := range n.child {
|
||||
switch child.kind {
|
||||
for _, c := range child {
|
||||
switch c.kind {
|
||||
case arrayType, chanType, chanTypeRecv, chanTypeSend, funcDecl, importDecl, mapType, basicLit, identExpr, typeDecl:
|
||||
continue
|
||||
default:
|
||||
n.start = child.start
|
||||
n.start = c.start
|
||||
}
|
||||
break
|
||||
}
|
||||
|
||||
// Chain sequential operations inside a block (next is right sibling)
|
||||
for i := 1; i < len(n.child); i++ {
|
||||
switch n.child[i].kind {
|
||||
for i := 1; i < len(child); i++ {
|
||||
switch child[i].kind {
|
||||
case funcDecl:
|
||||
n.child[i-1].tnext = n.child[i]
|
||||
child[i-1].tnext = child[i]
|
||||
default:
|
||||
switch n.child[i-1].kind {
|
||||
switch child[i-1].kind {
|
||||
case breakStmt, continueStmt, gotoStmt, returnStmt:
|
||||
// tnext is already computed, no change
|
||||
default:
|
||||
n.child[i-1].tnext = n.child[i].start
|
||||
child[i-1].tnext = child[i].start
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// Chain subtree next to self
|
||||
for i := len(n.child) - 1; i >= 0; i-- {
|
||||
switch n.child[i].kind {
|
||||
for i := len(child) - 1; i >= 0; i-- {
|
||||
switch child[i].kind {
|
||||
case arrayType, chanType, chanTypeRecv, chanTypeSend, importDecl, mapType, funcDecl, basicLit, identExpr, typeDecl:
|
||||
continue
|
||||
case breakStmt, continueStmt, gotoStmt, returnStmt:
|
||||
// tnext is already computed, no change
|
||||
default:
|
||||
n.child[i].tnext = n
|
||||
child[i].tnext = n
|
||||
}
|
||||
break
|
||||
}
|
||||
}
|
||||
|
||||
func excludeNodeKind(child []*node, kinds []nkind) []*node {
|
||||
if len(kinds) == 0 {
|
||||
return child
|
||||
}
|
||||
var res []*node
|
||||
for _, c := range child {
|
||||
exclude := false
|
||||
for _, k := range kinds {
|
||||
if c.kind == k {
|
||||
exclude = true
|
||||
}
|
||||
}
|
||||
if !exclude {
|
||||
res = append(res, c)
|
||||
}
|
||||
}
|
||||
return res
|
||||
}
|
||||
|
||||
func (n *node) name() (s string) {
|
||||
switch {
|
||||
case n.ident != "":
|
||||
@@ -2135,7 +2292,17 @@ func isField(n *node) bool {
|
||||
}
|
||||
|
||||
func isRecursiveField(n *node) bool {
|
||||
return isField(n) && (n.typ.recursive || n.typ.cat == ptrT && n.typ.val.recursive)
|
||||
if !isField(n) {
|
||||
return false
|
||||
}
|
||||
t := n.typ
|
||||
for t != nil {
|
||||
if t.recursive {
|
||||
return true
|
||||
}
|
||||
t = t.val
|
||||
}
|
||||
return false
|
||||
}
|
||||
|
||||
// isNewDefine returns true if node refers to a new definition.
|
||||
|
||||
@@ -78,8 +78,8 @@ func (interp *Interpreter) gta(root *node, rpath, pkgID string) ([]*node, error)
|
||||
if typ.isBinMethod {
|
||||
typ = &itype{cat: valueT, rtype: typ.methodCallType(), isBinMethod: true, scope: sc}
|
||||
}
|
||||
if sc.sym[dest.ident] == nil {
|
||||
sc.sym[dest.ident] = &symbol{kind: varSym, global: true, index: sc.add(typ), typ: typ, rval: val}
|
||||
if sc.sym[dest.ident] == nil || sc.sym[dest.ident].typ.incomplete {
|
||||
sc.sym[dest.ident] = &symbol{kind: varSym, global: true, index: sc.add(typ), typ: typ, rval: val, node: n}
|
||||
}
|
||||
if n.anc.kind == constDecl {
|
||||
sc.sym[dest.ident].kind = constSym
|
||||
@@ -112,7 +112,7 @@ func (interp *Interpreter) gta(root *node, rpath, pkgID string) ([]*node, error)
|
||||
sym1, exists1 := sc.sym[asImportName]
|
||||
sym2, exists2 := sc.sym[c.ident]
|
||||
if !exists1 && !exists2 {
|
||||
sc.sym[c.ident] = &symbol{index: sc.add(n.typ), kind: varSym, global: true, typ: n.typ}
|
||||
sc.sym[c.ident] = &symbol{index: sc.add(n.typ), kind: varSym, global: true, typ: n.typ, node: n}
|
||||
continue
|
||||
}
|
||||
|
||||
@@ -138,11 +138,13 @@ func (interp *Interpreter) gta(root *node, rpath, pkgID string) ([]*node, error)
|
||||
if n.typ, err = nodeType(interp, sc, n.child[2]); err != nil {
|
||||
return false
|
||||
}
|
||||
if isMethod(n) {
|
||||
ident := n.child[1].ident
|
||||
switch {
|
||||
case isMethod(n):
|
||||
// TODO(mpl): redeclaration detection
|
||||
// Add a method symbol in the receiver type name space
|
||||
var rcvrtype *itype
|
||||
n.ident = n.child[1].ident
|
||||
n.ident = ident
|
||||
rcvr := n.child[0].child[0]
|
||||
rtn := rcvr.lastChild()
|
||||
typeName := rtn.ident
|
||||
@@ -167,33 +169,32 @@ func (interp *Interpreter) gta(root *node, rpath, pkgID string) ([]*node, error)
|
||||
}
|
||||
rcvrtype.method = append(rcvrtype.method, n)
|
||||
n.child[0].child[0].lastChild().typ = rcvrtype
|
||||
} else {
|
||||
ident := n.child[1].ident
|
||||
case ident == "init":
|
||||
// TODO(mpl): use constant instead of hardcoded string?
|
||||
if ident != "init" {
|
||||
asImportName := filepath.Join(ident, baseName)
|
||||
if _, exists := sc.sym[asImportName]; exists {
|
||||
// redeclaration error
|
||||
// TODO(mpl): improve error with position of previous declaration.
|
||||
err = n.cfgErrorf("%s redeclared in this block", ident)
|
||||
return false
|
||||
}
|
||||
sym, exists := sc.sym[ident]
|
||||
if exists {
|
||||
// Make sure the symbol we found seems to be about another node, before calling
|
||||
// it a redeclaration.
|
||||
if sym.typ.isComplete() {
|
||||
// TODO(mpl): this check might be too permissive?
|
||||
if sym.kind != funcSym || sym.typ.cat != n.typ.cat || sym.node != n || sym.index != -1 {
|
||||
// redeclaration error
|
||||
// TODO(mpl): improve error with position of previous declaration.
|
||||
err = n.cfgErrorf("%s redeclared in this block", ident)
|
||||
return false
|
||||
}
|
||||
// init functions do not get declared as per the Go spec.
|
||||
default:
|
||||
asImportName := filepath.Join(ident, baseName)
|
||||
if _, exists := sc.sym[asImportName]; exists {
|
||||
// redeclaration error
|
||||
// TODO(mpl): improve error with position of previous declaration.
|
||||
err = n.cfgErrorf("%s redeclared in this block", ident)
|
||||
return false
|
||||
}
|
||||
sym, exists := sc.sym[ident]
|
||||
if exists {
|
||||
// Make sure the symbol we found seems to be about another node, before calling
|
||||
// it a redeclaration.
|
||||
if sym.typ.isComplete() {
|
||||
// TODO(mpl): this check might be too permissive?
|
||||
if sym.kind != funcSym || sym.typ.cat != n.typ.cat || sym.node != n || sym.index != -1 {
|
||||
// redeclaration error
|
||||
// TODO(mpl): improve error with position of previous declaration.
|
||||
err = n.cfgErrorf("%s redeclared in this block", ident)
|
||||
return false
|
||||
}
|
||||
}
|
||||
}
|
||||
// Add a function symbol in the package name space
|
||||
// Add a function symbol in the package name space except for init
|
||||
sc.sym[n.child[1].ident] = &symbol{kind: funcSym, typ: n.typ, node: n, index: -1}
|
||||
}
|
||||
if !n.typ.isComplete() {
|
||||
|
||||
@@ -405,6 +405,13 @@ func (interp *Interpreter) Eval(src string) (res reflect.Value, err error) {
|
||||
// Execute node closures
|
||||
interp.run(root, nil)
|
||||
|
||||
// Wire and execute global vars
|
||||
n, err := genGlobalVars([]*node{root}, interp.scopes[interp.Name])
|
||||
if err != nil {
|
||||
return res, err
|
||||
}
|
||||
interp.run(n, nil)
|
||||
|
||||
for _, n := range initNodes {
|
||||
interp.run(n, interp.frame)
|
||||
}
|
||||
@@ -474,7 +481,14 @@ func (interp *Interpreter) Use(values Exports) {
|
||||
continue
|
||||
}
|
||||
|
||||
interp.binPkg[k] = v
|
||||
if interp.binPkg[k] == nil {
|
||||
interp.binPkg[k] = v
|
||||
continue
|
||||
}
|
||||
|
||||
for s, sym := range v {
|
||||
interp.binPkg[k][s] = sym
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -35,6 +35,7 @@ func TestInterpConsistencyBuild(t *testing.T) {
|
||||
if filepath.Ext(file.Name()) != ".go" ||
|
||||
file.Name() == "assign11.go" || // expect error
|
||||
file.Name() == "assign12.go" || // expect error
|
||||
file.Name() == "assign15.go" || // expect error
|
||||
file.Name() == "bad0.go" || // expect error
|
||||
file.Name() == "const9.go" || // expect error
|
||||
file.Name() == "export1.go" || // non-main package
|
||||
@@ -44,6 +45,7 @@ func TestInterpConsistencyBuild(t *testing.T) {
|
||||
file.Name() == "fun22.go" || // expect error
|
||||
file.Name() == "if2.go" || // expect error
|
||||
file.Name() == "import6.go" || // expect error
|
||||
file.Name() == "init1.go" || // expect error
|
||||
file.Name() == "io0.go" || // use random number
|
||||
file.Name() == "op1.go" || // expect error
|
||||
file.Name() == "op7.go" || // expect error
|
||||
@@ -74,6 +76,10 @@ func TestInterpConsistencyBuild(t *testing.T) {
|
||||
file.Name() == "redeclaration-global4.go" || // expect error
|
||||
file.Name() == "redeclaration-global5.go" || // expect error
|
||||
file.Name() == "redeclaration-global6.go" || // expect error
|
||||
file.Name() == "restricted0.go" || // expect error
|
||||
file.Name() == "restricted1.go" || // expect error
|
||||
file.Name() == "restricted2.go" || // expect error
|
||||
file.Name() == "restricted3.go" || // expect error
|
||||
file.Name() == "server6.go" || // syntax parsing
|
||||
file.Name() == "server5.go" || // syntax parsing
|
||||
file.Name() == "server4.go" || // syntax parsing
|
||||
|
||||
@@ -385,6 +385,25 @@ func TestEvalChan(t *testing.T) {
|
||||
})
|
||||
}
|
||||
|
||||
func TestEvalFunctionCallWithFunctionParam(t *testing.T) {
|
||||
i := interp.New(interp.Options{})
|
||||
eval(t, i, `
|
||||
func Bar(s string, fn func(string)string) string { return fn(s) }
|
||||
`)
|
||||
|
||||
v := eval(t, i, "Bar")
|
||||
bar := v.Interface().(func(string, func(string) string) string)
|
||||
|
||||
got := bar("hello ", func(s string) string {
|
||||
return s + "world!"
|
||||
})
|
||||
|
||||
want := "hello world!"
|
||||
if got != want {
|
||||
t.Errorf("unexpected result of function eval: got %q, want %q", got, want)
|
||||
}
|
||||
}
|
||||
|
||||
func TestEvalMissingSymbol(t *testing.T) {
|
||||
defer func() {
|
||||
r := recover()
|
||||
|
||||
302
interp/op.go
302
interp/op.go
@@ -2053,7 +2053,7 @@ func equal(n *node) {
|
||||
dest := genValue(n)
|
||||
n.exec = func(f *frame) bltn {
|
||||
i1 := v1(f).Interface()
|
||||
dest(f).SetBool(i0 != i1)
|
||||
dest(f).SetBool(i0 == i1)
|
||||
return tnext
|
||||
}
|
||||
}
|
||||
@@ -2075,7 +2075,7 @@ func equal(n *node) {
|
||||
dest := genValue(n)
|
||||
n.exec = func(f *frame) bltn {
|
||||
i0 := v0(f).Interface()
|
||||
dest(f).SetBool(i0 != i1)
|
||||
dest(f).SetBool(i0 == i1)
|
||||
return tnext
|
||||
}
|
||||
}
|
||||
@@ -2099,7 +2099,7 @@ func equal(n *node) {
|
||||
n.exec = func(f *frame) bltn {
|
||||
i0 := v0(f).Interface()
|
||||
i1 := v1(f).Interface()
|
||||
dest(f).SetBool(i0 != i1)
|
||||
dest(f).SetBool(i0 == i1)
|
||||
return tnext
|
||||
}
|
||||
}
|
||||
@@ -2536,80 +2536,6 @@ func greater(n *node) {
|
||||
dest := genValueOutput(n, reflect.TypeOf(true))
|
||||
c0, c1 := n.child[0], n.child[1]
|
||||
|
||||
if c0.typ.cat == aliasT || c1.typ.cat == aliasT {
|
||||
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
|
||||
}
|
||||
}
|
||||
}
|
||||
return
|
||||
}
|
||||
|
||||
switch t0, t1 := c0.typ.TypeOf(), c1.typ.TypeOf(); {
|
||||
case isString(t0) || isString(t1):
|
||||
switch {
|
||||
@@ -2899,80 +2825,6 @@ func greaterEqual(n *node) {
|
||||
dest := genValueOutput(n, reflect.TypeOf(true))
|
||||
c0, c1 := n.child[0], n.child[1]
|
||||
|
||||
if c0.typ.cat == aliasT || c1.typ.cat == aliasT {
|
||||
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
|
||||
}
|
||||
}
|
||||
}
|
||||
return
|
||||
}
|
||||
|
||||
switch t0, t1 := c0.typ.TypeOf(), c1.typ.TypeOf(); {
|
||||
case isString(t0) || isString(t1):
|
||||
switch {
|
||||
@@ -3262,80 +3114,6 @@ func lower(n *node) {
|
||||
dest := genValueOutput(n, reflect.TypeOf(true))
|
||||
c0, c1 := n.child[0], n.child[1]
|
||||
|
||||
if c0.typ.cat == aliasT || c1.typ.cat == aliasT {
|
||||
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
|
||||
}
|
||||
}
|
||||
}
|
||||
return
|
||||
}
|
||||
|
||||
switch t0, t1 := c0.typ.TypeOf(), c1.typ.TypeOf(); {
|
||||
case isString(t0) || isString(t1):
|
||||
switch {
|
||||
@@ -3625,80 +3403,6 @@ func lowerEqual(n *node) {
|
||||
dest := genValueOutput(n, reflect.TypeOf(true))
|
||||
c0, c1 := n.child[0], n.child[1]
|
||||
|
||||
if c0.typ.cat == aliasT || c1.typ.cat == aliasT {
|
||||
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
|
||||
}
|
||||
}
|
||||
}
|
||||
return
|
||||
}
|
||||
|
||||
switch t0, t1 := c0.typ.TypeOf(), c1.typ.TypeOf(); {
|
||||
case isString(t0) || isString(t1):
|
||||
switch {
|
||||
|
||||
274
interp/run.go
274
interp/run.go
@@ -7,6 +7,7 @@ import (
|
||||
"go/constant"
|
||||
"log"
|
||||
"reflect"
|
||||
"unsafe"
|
||||
)
|
||||
|
||||
// bltn type defines functions which run at CFG execution.
|
||||
@@ -83,6 +84,9 @@ func init() {
|
||||
}
|
||||
|
||||
func (interp *Interpreter) run(n *node, cf *frame) {
|
||||
if n == nil {
|
||||
return
|
||||
}
|
||||
var f *frame
|
||||
if cf == nil {
|
||||
f = interp.frame
|
||||
@@ -229,10 +233,11 @@ func typeAssert(n *node) {
|
||||
|
||||
func typeAssert2(n *node) {
|
||||
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
|
||||
typ := c1.typ // type to assert or convert to
|
||||
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
|
||||
typID := typ.id()
|
||||
rtype := typ.rtype // type to assert
|
||||
next := getExec(n.tnext)
|
||||
@@ -246,7 +251,9 @@ func typeAssert2(n *node) {
|
||||
} else {
|
||||
ok = false
|
||||
}
|
||||
value1(f).SetBool(ok)
|
||||
if setStatus {
|
||||
value1(f).SetBool(ok)
|
||||
}
|
||||
return next
|
||||
}
|
||||
case isInterface(typ):
|
||||
@@ -256,7 +263,9 @@ func typeAssert2(n *node) {
|
||||
if ok {
|
||||
value0(f).Set(v)
|
||||
}
|
||||
value1(f).SetBool(ok)
|
||||
if setStatus {
|
||||
value1(f).SetBool(ok)
|
||||
}
|
||||
return next
|
||||
}
|
||||
case n.child[0].typ.cat == valueT:
|
||||
@@ -266,7 +275,9 @@ func typeAssert2(n *node) {
|
||||
if ok {
|
||||
value0(f).Set(v)
|
||||
}
|
||||
value1(f).SetBool(ok)
|
||||
if setStatus {
|
||||
value1(f).SetBool(ok)
|
||||
}
|
||||
return next
|
||||
}
|
||||
default:
|
||||
@@ -276,13 +287,18 @@ func typeAssert2(n *node) {
|
||||
if ok {
|
||||
value0(f).Set(v.value)
|
||||
}
|
||||
value1(f).SetBool(ok)
|
||||
if setStatus {
|
||||
value1(f).SetBool(ok)
|
||||
}
|
||||
return next
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
func canAssertTypes(src, dest reflect.Type) bool {
|
||||
if dest == nil {
|
||||
return false
|
||||
}
|
||||
if src == dest {
|
||||
return true
|
||||
}
|
||||
@@ -351,14 +367,16 @@ func convert(n *node) {
|
||||
}
|
||||
}
|
||||
|
||||
func isRecursiveStruct(t *itype, rtype reflect.Type) bool {
|
||||
func isRecursiveType(t *itype, rtype reflect.Type) bool {
|
||||
if t.cat == structT && rtype.Kind() == reflect.Interface {
|
||||
return true
|
||||
}
|
||||
if t.cat == ptrT && t.rtype != nil {
|
||||
return isRecursiveStruct(t.val, t.rtype.Elem())
|
||||
switch t.cat {
|
||||
case ptrT, arrayT, mapT:
|
||||
return isRecursiveType(t.val, t.val.rtype)
|
||||
default:
|
||||
return false
|
||||
}
|
||||
return false
|
||||
}
|
||||
|
||||
func assign(n *node) {
|
||||
@@ -387,8 +405,10 @@ func assign(n *node) {
|
||||
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 isRecursiveType(dest.typ, dest.typ.rtype):
|
||||
svalue[i] = genValueRecursiveInterface(src, dest.typ.rtype)
|
||||
case isRecursiveType(src.typ, src.typ.rtype):
|
||||
svalue[i] = genValueRecursiveInterfacePtrValue(src)
|
||||
case src.typ.untyped && isComplex(dest.typ.TypeOf()):
|
||||
svalue[i] = genValueComplex(src)
|
||||
case src.typ.untyped && !dest.typ.untyped:
|
||||
@@ -505,19 +525,21 @@ func deref(n *node) {
|
||||
value := genValue(n.child[0])
|
||||
tnext := getExec(n.tnext)
|
||||
i := n.findex
|
||||
l := n.level
|
||||
|
||||
if n.fnext != nil {
|
||||
fnext := getExec(n.fnext)
|
||||
n.exec = func(f *frame) bltn {
|
||||
f.data[i] = value(f).Elem()
|
||||
if f.data[i].Bool() {
|
||||
r := value(f).Elem()
|
||||
if r.Bool() {
|
||||
getFrame(f, l).data[i] = r
|
||||
return tnext
|
||||
}
|
||||
return fnext
|
||||
}
|
||||
} else {
|
||||
n.exec = func(f *frame) bltn {
|
||||
f.data[i] = value(f).Elem()
|
||||
getFrame(f, l).data[i] = value(f).Elem()
|
||||
return tnext
|
||||
}
|
||||
}
|
||||
@@ -672,9 +694,13 @@ func genFunctionWrapper(n *node) func(*frame) reflect.Value {
|
||||
|
||||
// Copy function input arguments in local frame
|
||||
for i, arg := range in {
|
||||
if def.typ.arg[i].cat == interfaceT {
|
||||
typ := def.typ.arg[i]
|
||||
switch {
|
||||
case typ.cat == interfaceT:
|
||||
d[i].Set(reflect.ValueOf(valueInterface{value: arg.Elem()}))
|
||||
} else {
|
||||
case typ.cat == funcT && arg.Kind() == reflect.Func:
|
||||
d[i].Set(reflect.ValueOf(genFunctionNode(arg)))
|
||||
default:
|
||||
d[i].Set(arg)
|
||||
}
|
||||
}
|
||||
@@ -698,6 +724,10 @@ func genFunctionWrapper(n *node) func(*frame) reflect.Value {
|
||||
}
|
||||
}
|
||||
|
||||
func genFunctionNode(v reflect.Value) *node {
|
||||
return &node{kind: funcType, action: aNop, rval: v, typ: &itype{cat: valueT, rtype: v.Type()}}
|
||||
}
|
||||
|
||||
func genInterfaceWrapper(n *node, typ reflect.Type) func(*frame) reflect.Value {
|
||||
value := genValue(n)
|
||||
if typ == nil || typ.Kind() != reflect.Interface || typ.NumMethod() == 0 || n.typ.cat == valueT {
|
||||
@@ -762,7 +792,7 @@ func call(n *node) {
|
||||
var values []func(*frame) reflect.Value
|
||||
if n.child[0].recv != nil {
|
||||
// Compute method receiver value.
|
||||
if isRecursiveStruct(n.child[0].recv.node.typ, n.child[0].recv.node.typ.rtype) {
|
||||
if isRecursiveType(n.child[0].recv.node.typ, n.child[0].recv.node.typ.rtype) {
|
||||
values = append(values, genValueRecvInterfacePtr(n.child[0]))
|
||||
} else {
|
||||
values = append(values, genValueRecv(n.child[0]))
|
||||
@@ -796,20 +826,21 @@ func call(n *node) {
|
||||
values = append(values, func(f *frame) reflect.Value { return f.data[ind] })
|
||||
}
|
||||
default:
|
||||
var arg *itype
|
||||
if variadic >= 0 && i >= variadic {
|
||||
arg = n.child[0].typ.arg[variadic].val
|
||||
} else {
|
||||
arg = n.child[0].typ.arg[i]
|
||||
}
|
||||
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()
|
||||
} else {
|
||||
argType = n.child[0].typ.arg[i].TypeOf()
|
||||
}
|
||||
argType := arg.TypeOf()
|
||||
convertLiteralValue(c, argType)
|
||||
}
|
||||
switch {
|
||||
case len(n.child[0].typ.arg) > i && n.child[0].typ.arg[i].cat == interfaceT:
|
||||
case arg.cat == interfaceT:
|
||||
values = append(values, genValueInterface(c))
|
||||
case isRecursiveStruct(c.typ, c.typ.rtype):
|
||||
values = append(values, genValueDerefInterfacePtr(c))
|
||||
case isRecursiveType(c.typ, c.typ.rtype):
|
||||
values = append(values, genValueRecursiveInterfacePtrValue(c))
|
||||
default:
|
||||
values = append(values, genValue(c))
|
||||
}
|
||||
@@ -852,9 +883,10 @@ func call(n *node) {
|
||||
}
|
||||
default:
|
||||
// Multiple return values frame index are indexed from the node frame index.
|
||||
l := n.level
|
||||
for i := range rtypes {
|
||||
j := n.findex + i
|
||||
rvalues[i] = func(f *frame) reflect.Value { return f.data[j] }
|
||||
rvalues[i] = func(f *frame) reflect.Value { return getFrame(f, l).data[j] }
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1006,6 +1038,21 @@ func pindex(i, variadic int) int {
|
||||
return variadic
|
||||
}
|
||||
|
||||
func getFrame(f *frame, l int) *frame {
|
||||
switch l {
|
||||
case 0:
|
||||
return f
|
||||
case 1:
|
||||
return f.anc
|
||||
case 2:
|
||||
return f.anc.anc
|
||||
}
|
||||
for ; l > 0; l-- {
|
||||
f = f.anc
|
||||
}
|
||||
return f
|
||||
}
|
||||
|
||||
// Callbin calls a function from a bin import, accessible through reflect.
|
||||
func callBin(n *node) {
|
||||
tnext := getExec(n.tnext)
|
||||
@@ -1033,7 +1080,7 @@ func callBin(n *node) {
|
||||
}
|
||||
|
||||
for i, c := range child {
|
||||
defType := funcType.In(pindex(i, variadic))
|
||||
defType := funcType.In(rcvrOffset + pindex(i, variadic))
|
||||
switch {
|
||||
case isBinCall(c):
|
||||
// Handle nested function calls: pass returned values as arguments
|
||||
@@ -1067,7 +1114,7 @@ func callBin(n *node) {
|
||||
values = append(values, genFunctionWrapper(c))
|
||||
case interfaceT:
|
||||
values = append(values, genValueInterfaceValue(c))
|
||||
case arrayT:
|
||||
case arrayT, variadicT:
|
||||
switch c.typ.val.cat {
|
||||
case interfaceT:
|
||||
values = append(values, genValueInterfaceArray(c))
|
||||
@@ -1106,6 +1153,7 @@ func callBin(n *node) {
|
||||
case fnext != nil:
|
||||
// Handle branching according to boolean result.
|
||||
index := n.findex
|
||||
level := n.level
|
||||
n.exec = func(f *frame) bltn {
|
||||
in := make([]reflect.Value, l)
|
||||
for i, v := range values {
|
||||
@@ -1113,7 +1161,7 @@ func callBin(n *node) {
|
||||
}
|
||||
res := callFn(value(f), in)
|
||||
b := res[0].Bool()
|
||||
f.data[index].SetBool(b)
|
||||
getFrame(f, level).data[index].SetBool(b)
|
||||
if b {
|
||||
return tnext
|
||||
}
|
||||
@@ -1169,7 +1217,7 @@ func callBin(n *node) {
|
||||
}
|
||||
out := callFn(value(f), in)
|
||||
for i := 0; i < len(out); i++ {
|
||||
f.data[n.findex+i].Set(out[i])
|
||||
getFrame(f, n.level).data[n.findex+i].Set(out[i])
|
||||
}
|
||||
return tnext
|
||||
}
|
||||
@@ -1180,6 +1228,7 @@ func callBin(n *node) {
|
||||
func getIndexBinMethod(n *node) {
|
||||
// dest := genValue(n)
|
||||
i := n.findex
|
||||
l := n.level
|
||||
m := n.val.(int)
|
||||
value := genValue(n.child[0])
|
||||
next := getExec(n.tnext)
|
||||
@@ -1187,20 +1236,21 @@ func getIndexBinMethod(n *node) {
|
||||
n.exec = func(f *frame) bltn {
|
||||
// Can not use .Set() because dest type contains the receiver and source not
|
||||
// dest(f).Set(value(f).Method(m))
|
||||
f.data[i] = value(f).Method(m)
|
||||
getFrame(f, l).data[i] = value(f).Method(m)
|
||||
return next
|
||||
}
|
||||
}
|
||||
|
||||
func getIndexBinPtrMethod(n *node) {
|
||||
i := n.findex
|
||||
l := n.level
|
||||
m := n.val.(int)
|
||||
value := genValue(n.child[0])
|
||||
next := getExec(n.tnext)
|
||||
|
||||
n.exec = func(f *frame) bltn {
|
||||
// Can not use .Set() because dest type contains the receiver and source not
|
||||
f.data[i] = value(f).Addr().Method(m)
|
||||
getFrame(f, l).data[i] = value(f).Addr().Method(m)
|
||||
return next
|
||||
}
|
||||
}
|
||||
@@ -1210,21 +1260,23 @@ func getIndexArray(n *node) {
|
||||
tnext := getExec(n.tnext)
|
||||
value0 := genValueArray(n.child[0]) // array
|
||||
i := n.findex
|
||||
l := n.level
|
||||
|
||||
if n.child[1].rval.IsValid() { // constant array index
|
||||
ai := int(vInt(n.child[1].rval))
|
||||
if n.fnext != nil {
|
||||
fnext := getExec(n.fnext)
|
||||
n.exec = func(f *frame) bltn {
|
||||
f.data[i] = value0(f).Index(ai)
|
||||
if f.data[i].Bool() {
|
||||
r := value0(f).Index(ai)
|
||||
getFrame(f, l).data[i] = r
|
||||
if r.Bool() {
|
||||
return tnext
|
||||
}
|
||||
return fnext
|
||||
}
|
||||
} else {
|
||||
n.exec = func(f *frame) bltn {
|
||||
f.data[i] = value0(f).Index(ai)
|
||||
getFrame(f, l).data[i] = value0(f).Index(ai)
|
||||
return tnext
|
||||
}
|
||||
}
|
||||
@@ -1235,8 +1287,9 @@ func getIndexArray(n *node) {
|
||||
fnext := getExec(n.fnext)
|
||||
n.exec = func(f *frame) bltn {
|
||||
_, vi := value1(f)
|
||||
f.data[i] = value0(f).Index(int(vi))
|
||||
if f.data[i].Bool() {
|
||||
r := value0(f).Index(int(vi))
|
||||
getFrame(f, l).data[i] = r
|
||||
if r.Bool() {
|
||||
return tnext
|
||||
}
|
||||
return fnext
|
||||
@@ -1244,7 +1297,7 @@ func getIndexArray(n *node) {
|
||||
} else {
|
||||
n.exec = func(f *frame) bltn {
|
||||
_, vi := value1(f)
|
||||
f.data[i] = value0(f).Index(int(vi))
|
||||
getFrame(f, l).data[i] = value0(f).Index(int(vi))
|
||||
return tnext
|
||||
}
|
||||
}
|
||||
@@ -1447,6 +1500,7 @@ func getFunc(n *node) {
|
||||
|
||||
func getMethod(n *node) {
|
||||
i := n.findex
|
||||
l := n.level
|
||||
next := getExec(n.tnext)
|
||||
|
||||
n.exec = func(f *frame) bltn {
|
||||
@@ -1455,7 +1509,7 @@ func getMethod(n *node) {
|
||||
nod.val = &nod
|
||||
nod.recv = n.recv
|
||||
nod.frame = fr
|
||||
f.data[i] = reflect.ValueOf(&nod)
|
||||
getFrame(f, l).data[i] = reflect.ValueOf(&nod)
|
||||
return next
|
||||
}
|
||||
}
|
||||
@@ -1465,6 +1519,7 @@ func getMethodByName(n *node) {
|
||||
value0 := genValue(n.child[0])
|
||||
name := n.child[1].ident
|
||||
i := n.findex
|
||||
l := n.level
|
||||
|
||||
n.exec = func(f *frame) bltn {
|
||||
val := value0(f).Interface().(valueInterface)
|
||||
@@ -1474,7 +1529,7 @@ func getMethodByName(n *node) {
|
||||
nod.val = &nod
|
||||
nod.recv = &receiver{nil, val.value, li}
|
||||
nod.frame = fr
|
||||
f.data[i] = reflect.ValueOf(&nod)
|
||||
getFrame(f, l).data[i] = reflect.ValueOf(&nod)
|
||||
return next
|
||||
}
|
||||
}
|
||||
@@ -1484,6 +1539,7 @@ func getIndexSeq(n *node) {
|
||||
index := n.val.([]int)
|
||||
tnext := getExec(n.tnext)
|
||||
i := n.findex
|
||||
l := n.level
|
||||
|
||||
// Note:
|
||||
// Here we have to store the result using
|
||||
@@ -1498,44 +1554,63 @@ func getIndexSeq(n *node) {
|
||||
if n.fnext != nil {
|
||||
fnext := getExec(n.fnext)
|
||||
n.exec = func(f *frame) bltn {
|
||||
f.data[i] = value(f).FieldByIndex(index)
|
||||
if f.data[i].Bool() {
|
||||
v := value(f)
|
||||
if v.Type().Kind() == reflect.Interface && n.child[0].typ.recursive {
|
||||
v = writableDeref(v)
|
||||
}
|
||||
r := v.FieldByIndex(index)
|
||||
getFrame(f, l).data[i] = r
|
||||
if r.Bool() {
|
||||
return tnext
|
||||
}
|
||||
return fnext
|
||||
}
|
||||
} else {
|
||||
n.exec = func(f *frame) bltn {
|
||||
f.data[i] = value(f).FieldByIndex(index)
|
||||
v := value(f)
|
||||
if v.Type().Kind() == reflect.Interface && n.child[0].typ.recursive {
|
||||
v = writableDeref(v)
|
||||
}
|
||||
getFrame(f, l).data[i] = v.FieldByIndex(index)
|
||||
return tnext
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
//go:nocheckptr
|
||||
func writableDeref(v reflect.Value) reflect.Value {
|
||||
// Here we have an interface to a struct. Any attempt to dereference it will
|
||||
// make a copy of the struct. We need to get a Value to the actual struct.
|
||||
// TODO: using unsafe is a temporary measure. Rethink this.
|
||||
return reflect.NewAt(v.Elem().Type(), unsafe.Pointer(v.InterfaceData()[1])).Elem() //nolint:govet
|
||||
}
|
||||
|
||||
func getPtrIndexSeq(n *node) {
|
||||
index := n.val.([]int)
|
||||
tnext := getExec(n.tnext)
|
||||
var value func(*frame) reflect.Value
|
||||
if isRecursiveStruct(n.child[0].typ, n.child[0].typ.rtype) {
|
||||
if isRecursiveType(n.child[0].typ, n.child[0].typ.rtype) {
|
||||
v := genValue(n.child[0])
|
||||
value = func(f *frame) reflect.Value { return v(f).Elem().Elem() }
|
||||
} else {
|
||||
value = genValue(n.child[0])
|
||||
}
|
||||
i := n.findex
|
||||
l := n.level
|
||||
|
||||
if n.fnext != nil {
|
||||
fnext := getExec(n.fnext)
|
||||
n.exec = func(f *frame) bltn {
|
||||
f.data[i] = value(f).Elem().FieldByIndex(index)
|
||||
if f.data[i].Bool() {
|
||||
r := value(f).Elem().FieldByIndex(index)
|
||||
getFrame(f, l).data[i] = r
|
||||
if r.Bool() {
|
||||
return tnext
|
||||
}
|
||||
return fnext
|
||||
}
|
||||
} else {
|
||||
n.exec = func(f *frame) bltn {
|
||||
f.data[i] = value(f).Elem().FieldByIndex(index)
|
||||
getFrame(f, l).data[i] = value(f).Elem().FieldByIndex(index)
|
||||
return tnext
|
||||
}
|
||||
}
|
||||
@@ -1545,22 +1620,25 @@ func getIndexSeqField(n *node) {
|
||||
value := genValue(n.child[0])
|
||||
index := n.val.([]int)
|
||||
i := n.findex
|
||||
l := n.level
|
||||
tnext := getExec(n.tnext)
|
||||
|
||||
if n.fnext != nil {
|
||||
fnext := getExec(n.fnext)
|
||||
if n.child[0].typ.TypeOf().Kind() == reflect.Ptr {
|
||||
n.exec = func(f *frame) bltn {
|
||||
f.data[i] = value(f).Elem().FieldByIndex(index)
|
||||
if f.data[i].Bool() {
|
||||
r := value(f).Elem().FieldByIndex(index)
|
||||
getFrame(f, l).data[i] = r
|
||||
if r.Bool() {
|
||||
return tnext
|
||||
}
|
||||
return fnext
|
||||
}
|
||||
} else {
|
||||
n.exec = func(f *frame) bltn {
|
||||
f.data[i] = value(f).FieldByIndex(index)
|
||||
if f.data[i].Bool() {
|
||||
r := value(f).FieldByIndex(index)
|
||||
getFrame(f, l).data[i] = r
|
||||
if r.Bool() {
|
||||
return tnext
|
||||
}
|
||||
return fnext
|
||||
@@ -1569,12 +1647,12 @@ func getIndexSeqField(n *node) {
|
||||
} else {
|
||||
if n.child[0].typ.TypeOf().Kind() == reflect.Ptr {
|
||||
n.exec = func(f *frame) bltn {
|
||||
f.data[i] = value(f).Elem().FieldByIndex(index)
|
||||
getFrame(f, l).data[i] = value(f).Elem().FieldByIndex(index)
|
||||
return tnext
|
||||
}
|
||||
} else {
|
||||
n.exec = func(f *frame) bltn {
|
||||
f.data[i] = value(f).FieldByIndex(index)
|
||||
getFrame(f, l).data[i] = value(f).FieldByIndex(index)
|
||||
return tnext
|
||||
}
|
||||
}
|
||||
@@ -1587,16 +1665,17 @@ func getIndexSeqPtrMethod(n *node) {
|
||||
fi := index[1:]
|
||||
mi := index[0]
|
||||
i := n.findex
|
||||
l := n.level
|
||||
next := getExec(n.tnext)
|
||||
|
||||
if n.child[0].typ.TypeOf().Kind() == reflect.Ptr {
|
||||
n.exec = func(f *frame) bltn {
|
||||
f.data[i] = value(f).Elem().FieldByIndex(fi).Addr().Method(mi)
|
||||
getFrame(f, l).data[i] = value(f).Elem().FieldByIndex(fi).Addr().Method(mi)
|
||||
return next
|
||||
}
|
||||
} else {
|
||||
n.exec = func(f *frame) bltn {
|
||||
f.data[i] = value(f).FieldByIndex(fi).Addr().Method(mi)
|
||||
getFrame(f, l).data[i] = value(f).FieldByIndex(fi).Addr().Method(mi)
|
||||
return next
|
||||
}
|
||||
}
|
||||
@@ -1608,16 +1687,17 @@ func getIndexSeqMethod(n *node) {
|
||||
fi := index[1:]
|
||||
mi := index[0]
|
||||
i := n.findex
|
||||
l := n.level
|
||||
next := getExec(n.tnext)
|
||||
|
||||
if n.child[0].typ.TypeOf().Kind() == reflect.Ptr {
|
||||
n.exec = func(f *frame) bltn {
|
||||
f.data[i] = value(f).Elem().FieldByIndex(fi).Method(mi)
|
||||
getFrame(f, l).data[i] = value(f).Elem().FieldByIndex(fi).Method(mi)
|
||||
return next
|
||||
}
|
||||
} else {
|
||||
n.exec = func(f *frame) bltn {
|
||||
f.data[i] = value(f).FieldByIndex(fi).Method(mi)
|
||||
getFrame(f, l).data[i] = value(f).FieldByIndex(fi).Method(mi)
|
||||
return next
|
||||
}
|
||||
}
|
||||
@@ -1946,10 +2026,11 @@ func compositeBinStruct(n *node) {
|
||||
}
|
||||
} else {
|
||||
fieldIndex[i] = []int{i}
|
||||
convertLiteralValue(c.child[1], typ.Field(i).Type)
|
||||
if c.typ.cat == funcT {
|
||||
convertLiteralValue(c.child[1], typ.Field(i).Type)
|
||||
values[i] = genFunctionWrapper(c.child[1])
|
||||
} else {
|
||||
convertLiteralValue(c, typ.Field(i).Type)
|
||||
values[i] = genValue(c)
|
||||
}
|
||||
}
|
||||
@@ -1995,6 +2076,7 @@ func doCompositeLit(n *node, hasType bool) {
|
||||
}
|
||||
|
||||
i := n.findex
|
||||
l := n.level
|
||||
n.exec = func(f *frame) bltn {
|
||||
a := reflect.New(n.typ.TypeOf()).Elem()
|
||||
for i, v := range values {
|
||||
@@ -2006,7 +2088,7 @@ func doCompositeLit(n *node, hasType bool) {
|
||||
case destInterface:
|
||||
d.Set(reflect.ValueOf(valueInterface{n, a}))
|
||||
default:
|
||||
f.data[i] = a
|
||||
getFrame(f, l).data[i] = a
|
||||
}
|
||||
return next
|
||||
}
|
||||
@@ -2023,6 +2105,7 @@ func doCompositeSparse(n *node, hasType bool) {
|
||||
if hasType {
|
||||
child = n.child[1:]
|
||||
}
|
||||
destInterface := destType(n).cat == interfaceT
|
||||
|
||||
values := make(map[int]func(*frame) reflect.Value)
|
||||
a, _ := n.typ.zero()
|
||||
@@ -2033,8 +2116,12 @@ func doCompositeSparse(n *node, hasType bool) {
|
||||
switch {
|
||||
case c1.typ.cat == funcT:
|
||||
values[field] = genFunctionWrapper(c1)
|
||||
case isRecursiveStruct(n.typ.field[field].typ, n.typ.field[field].typ.rtype):
|
||||
values[field] = genValueInterfacePtr(c1)
|
||||
case c1.typ.cat == interfaceT:
|
||||
values[field] = genValueInterfaceValue(c1)
|
||||
case isArray(c1.typ) && c1.typ.val != nil && c1.typ.val.cat == interfaceT:
|
||||
values[field] = genValueInterfaceArray(c1)
|
||||
case isRecursiveType(n.typ.field[field].typ, n.typ.field[field].typ.rtype):
|
||||
values[field] = genValueRecursiveInterface(c1, n.typ.field[field].typ.rtype)
|
||||
default:
|
||||
values[field] = genValue(c1)
|
||||
}
|
||||
@@ -2044,9 +2131,13 @@ func doCompositeSparse(n *node, hasType bool) {
|
||||
for i, v := range values {
|
||||
a.Field(i).Set(v(f))
|
||||
}
|
||||
if d := value(f); d.Type().Kind() == reflect.Ptr {
|
||||
d := value(f)
|
||||
switch {
|
||||
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
|
||||
@@ -2288,8 +2379,13 @@ func _case(n *node) {
|
||||
values[i] = genValue(n.child[i])
|
||||
}
|
||||
n.exec = func(f *frame) bltn {
|
||||
v0 := value(f)
|
||||
for _, v := range values {
|
||||
if value(f).Interface() == v(f).Interface() {
|
||||
v1 := v(f)
|
||||
if !v0.Type().AssignableTo(v1.Type()) {
|
||||
v0 = v0.Convert(v1.Type())
|
||||
}
|
||||
if v0.Interface() == v1.Interface() {
|
||||
return tnext
|
||||
}
|
||||
}
|
||||
@@ -2336,8 +2432,8 @@ func _append(n *node) {
|
||||
switch {
|
||||
case n.typ.val.cat == interfaceT:
|
||||
values[i] = genValueInterface(arg)
|
||||
case isRecursiveStruct(n.typ.val, n.typ.val.rtype):
|
||||
values[i] = genValueInterfacePtr(arg)
|
||||
case isRecursiveType(n.typ.val, n.typ.val.rtype):
|
||||
values[i] = genValueRecursiveInterface(arg, n.typ.val.rtype)
|
||||
case arg.typ.untyped:
|
||||
values[i] = genValueAs(arg, n.child[1].typ.TypeOf().Elem())
|
||||
default:
|
||||
@@ -2358,8 +2454,8 @@ func _append(n *node) {
|
||||
switch {
|
||||
case n.typ.val.cat == interfaceT:
|
||||
value0 = genValueInterface(n.child[2])
|
||||
case isRecursiveStruct(n.typ.val, n.typ.val.rtype):
|
||||
value0 = genValueInterfacePtr(n.child[2])
|
||||
case isRecursiveType(n.typ.val, n.typ.val.rtype):
|
||||
value0 = genValueRecursiveInterface(n.child[2], n.typ.val.rtype)
|
||||
case n.child[2].typ.untyped:
|
||||
value0 = genValueAs(n.child[2], n.child[1].typ.TypeOf().Elem())
|
||||
default:
|
||||
@@ -2582,6 +2678,7 @@ func recv(n *node) {
|
||||
value := genValue(n.child[0])
|
||||
tnext := getExec(n.tnext)
|
||||
i := n.findex
|
||||
l := n.level
|
||||
|
||||
if n.interp.cancelChan {
|
||||
// Cancellable channel read
|
||||
@@ -2589,10 +2686,10 @@ func recv(n *node) {
|
||||
fnext := getExec(n.fnext)
|
||||
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 {
|
||||
if f.data[i].Bool() {
|
||||
if r, ok := ch.TryRecv(); ok {
|
||||
getFrame(f, l).data[i] = r
|
||||
if r.Bool() {
|
||||
return tnext
|
||||
}
|
||||
return fnext
|
||||
@@ -2610,14 +2707,14 @@ func recv(n *node) {
|
||||
} else {
|
||||
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 {
|
||||
if r, ok := ch.TryRecv(); ok {
|
||||
getFrame(f, l).data[i] = r
|
||||
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}})
|
||||
chosen, getFrame(f, l).data[i], _ = reflect.Select([]reflect.SelectCase{f.done, {Dir: reflect.SelectRecv, Chan: ch}})
|
||||
if chosen == 0 {
|
||||
return nil
|
||||
}
|
||||
@@ -2629,7 +2726,8 @@ func recv(n *node) {
|
||||
if n.fnext != nil {
|
||||
fnext := getExec(n.fnext)
|
||||
n.exec = func(f *frame) bltn {
|
||||
if f.data[i], _ = value(f).Recv(); f.data[i].Bool() {
|
||||
if r, _ := value(f).Recv(); r.Bool() {
|
||||
getFrame(f, l).data[i] = r
|
||||
return tnext
|
||||
}
|
||||
return fnext
|
||||
@@ -2637,7 +2735,7 @@ func recv(n *node) {
|
||||
} else {
|
||||
i := n.findex
|
||||
n.exec = func(f *frame) bltn {
|
||||
f.data[i], _ = value(f).Recv()
|
||||
getFrame(f, l).data[i], _ = value(f).Recv()
|
||||
return tnext
|
||||
}
|
||||
}
|
||||
@@ -2685,7 +2783,7 @@ func convertLiteralValue(n *node, t reflect.Type) {
|
||||
case n.typ.cat == nilT:
|
||||
// Create a zero value of target type.
|
||||
n.rval = reflect.New(t).Elem()
|
||||
case !(n.kind == basicLit || n.rval.IsValid()) || t == nil || t.Kind() == reflect.Interface:
|
||||
case !(n.kind == basicLit || n.rval.IsValid()) || t == nil || t.Kind() == reflect.Interface || t.Kind() == reflect.Slice && t.Elem().Kind() == reflect.Interface:
|
||||
// Skip non-constant values, undefined target type or interface target type.
|
||||
case n.rval.IsValid():
|
||||
// Convert constant value to target type.
|
||||
@@ -2918,6 +3016,7 @@ func _select(n *node) {
|
||||
// slice expression: array[low:high:max].
|
||||
func slice(n *node) {
|
||||
i := n.findex
|
||||
l := n.level
|
||||
next := getExec(n.tnext)
|
||||
value0 := genValueArray(n.child[0]) // array
|
||||
value1 := genValue(n.child[1]) // low (if 2 or 3 args) or high (if 1 arg)
|
||||
@@ -2926,7 +3025,7 @@ func slice(n *node) {
|
||||
case 2:
|
||||
n.exec = func(f *frame) bltn {
|
||||
a := value0(f)
|
||||
f.data[i] = a.Slice(int(value1(f).Int()), a.Len())
|
||||
getFrame(f, l).data[i] = a.Slice(int(value1(f).Int()), a.Len())
|
||||
return next
|
||||
}
|
||||
case 3:
|
||||
@@ -2934,7 +3033,7 @@ func slice(n *node) {
|
||||
|
||||
n.exec = func(f *frame) bltn {
|
||||
a := value0(f)
|
||||
f.data[i] = a.Slice(int(value1(f).Int()), int(value2(f).Int()))
|
||||
getFrame(f, l).data[i] = a.Slice(int(value1(f).Int()), int(value2(f).Int()))
|
||||
return next
|
||||
}
|
||||
case 4:
|
||||
@@ -2943,7 +3042,7 @@ func slice(n *node) {
|
||||
|
||||
n.exec = func(f *frame) bltn {
|
||||
a := value0(f)
|
||||
f.data[i] = a.Slice3(int(value1(f).Int()), int(value2(f).Int()), int(value3(f).Int()))
|
||||
getFrame(f, l).data[i] = a.Slice3(int(value1(f).Int()), int(value2(f).Int()), int(value3(f).Int()))
|
||||
return next
|
||||
}
|
||||
}
|
||||
@@ -2952,6 +3051,7 @@ func slice(n *node) {
|
||||
// slice expression, no low value: array[:high:max].
|
||||
func slice0(n *node) {
|
||||
i := n.findex
|
||||
l := n.level
|
||||
next := getExec(n.tnext)
|
||||
value0 := genValueArray(n.child[0])
|
||||
|
||||
@@ -2959,14 +3059,14 @@ func slice0(n *node) {
|
||||
case 1:
|
||||
n.exec = func(f *frame) bltn {
|
||||
a := value0(f)
|
||||
f.data[i] = a.Slice(0, a.Len())
|
||||
getFrame(f, l).data[i] = a.Slice(0, a.Len())
|
||||
return next
|
||||
}
|
||||
case 2:
|
||||
value1 := genValue(n.child[1])
|
||||
n.exec = func(f *frame) bltn {
|
||||
a := value0(f)
|
||||
f.data[i] = a.Slice(0, int(value1(f).Int()))
|
||||
getFrame(f, l).data[i] = a.Slice(0, int(value1(f).Int()))
|
||||
return next
|
||||
}
|
||||
case 3:
|
||||
@@ -2974,7 +3074,7 @@ func slice0(n *node) {
|
||||
value2 := genValue(n.child[2])
|
||||
n.exec = func(f *frame) bltn {
|
||||
a := value0(f)
|
||||
f.data[i] = a.Slice3(0, int(value1(f).Int()), int(value2(f).Int()))
|
||||
getFrame(f, l).data[i] = a.Slice3(0, int(value1(f).Int()), int(value2(f).Int()))
|
||||
return next
|
||||
}
|
||||
}
|
||||
|
||||
@@ -22,7 +22,7 @@ func (interp *Interpreter) importSrc(rPath, path string) (string, error) {
|
||||
// In all other cases, absolute import paths are resolved from the GOPATH
|
||||
// and the nested "vendor" directories.
|
||||
if isPathRelative(path) {
|
||||
if rPath == "main" {
|
||||
if rPath == mainID {
|
||||
rPath = "."
|
||||
}
|
||||
dir = filepath.Join(filepath.Dir(interp.Name), rPath, path)
|
||||
@@ -132,6 +132,13 @@ func (interp *Interpreter) importSrc(rPath, path string) (string, error) {
|
||||
interp.run(n, nil)
|
||||
}
|
||||
|
||||
// Wire and execute global vars
|
||||
n, err := genGlobalVars(rootNodes, interp.scopes[path])
|
||||
if err != nil {
|
||||
return "", err
|
||||
}
|
||||
interp.run(n, nil)
|
||||
|
||||
// Add main to list of functions to run, after all inits
|
||||
if m := interp.main(); m != nil {
|
||||
initNodes = append(initNodes, m)
|
||||
@@ -146,7 +153,7 @@ func (interp *Interpreter) importSrc(rPath, path string) (string, error) {
|
||||
|
||||
func (interp *Interpreter) rootFromSourceLocation(rPath string) (string, error) {
|
||||
sourceFile := interp.Name
|
||||
if rPath != "main" || !strings.HasSuffix(sourceFile, ".go") {
|
||||
if rPath != mainID || !strings.HasSuffix(sourceFile, ".go") {
|
||||
return rPath, nil
|
||||
}
|
||||
wd, err := os.Getwd()
|
||||
@@ -181,13 +188,62 @@ func pkgDir(goPath string, root, path string) (string, string, error) {
|
||||
return "", "", fmt.Errorf("unable to find source related to: %q", path)
|
||||
}
|
||||
|
||||
return pkgDir(goPath, previousRoot(root), path)
|
||||
rootPath := filepath.Join(goPath, "src", root)
|
||||
prevRoot, err := previousRoot(rootPath, root)
|
||||
if err != nil {
|
||||
return "", "", err
|
||||
}
|
||||
|
||||
return pkgDir(goPath, prevRoot, path)
|
||||
}
|
||||
|
||||
// Find the previous source root (vendor > vendor > ... > GOPATH).
|
||||
func previousRoot(root string) string {
|
||||
splitRoot := strings.Split(root, string(filepath.Separator))
|
||||
const vendor = "vendor"
|
||||
|
||||
// Find the previous source root (vendor > vendor > ... > GOPATH).
|
||||
func previousRoot(rootPath, root string) (string, error) {
|
||||
rootPath = filepath.Clean(rootPath)
|
||||
parent, final := filepath.Split(rootPath)
|
||||
parent = filepath.Clean(parent)
|
||||
|
||||
// TODO(mpl): maybe it works for the special case main, but can't be bothered for now.
|
||||
if root != mainID && final != vendor {
|
||||
root = strings.TrimSuffix(root, string(filepath.Separator))
|
||||
prefix := strings.TrimSuffix(rootPath, root)
|
||||
|
||||
// look for the closest vendor in one of our direct ancestors, as it takes priority.
|
||||
var vendored string
|
||||
for {
|
||||
fi, err := os.Lstat(filepath.Join(parent, vendor))
|
||||
if err == nil && fi.IsDir() {
|
||||
vendored = strings.TrimPrefix(strings.TrimPrefix(parent, prefix), string(filepath.Separator))
|
||||
break
|
||||
}
|
||||
if !os.IsNotExist(err) {
|
||||
return "", err
|
||||
}
|
||||
|
||||
// stop when we reach GOPATH/src/blah
|
||||
parent = filepath.Dir(parent)
|
||||
if parent == prefix {
|
||||
break
|
||||
}
|
||||
|
||||
// just an additional failsafe, stop if we reach the filesystem root.
|
||||
// TODO(mpl): It should probably be a critical error actually,
|
||||
// as we shouldn't have gone that high up in the tree.
|
||||
if parent == string(filepath.Separator) {
|
||||
break
|
||||
}
|
||||
}
|
||||
|
||||
if vendored != "" {
|
||||
return vendored, nil
|
||||
}
|
||||
}
|
||||
|
||||
// TODO(mpl): the algorithm below might be redundant with the one above,
|
||||
// but keeping it for now. Investigate/simplify/remove later.
|
||||
splitRoot := strings.Split(root, string(filepath.Separator))
|
||||
var index int
|
||||
for i := len(splitRoot) - 1; i >= 0; i-- {
|
||||
if splitRoot[i] == "vendor" {
|
||||
@@ -197,10 +253,10 @@ func previousRoot(root string) string {
|
||||
}
|
||||
|
||||
if index == 0 {
|
||||
return ""
|
||||
return "", nil
|
||||
}
|
||||
|
||||
return filepath.Join(splitRoot[:index]...)
|
||||
return filepath.Join(splitRoot[:index]...), nil
|
||||
}
|
||||
|
||||
func effectivePkg(root, path string) string {
|
||||
|
||||
@@ -196,9 +196,10 @@ func Test_pkgDir(t *testing.T) {
|
||||
|
||||
func Test_previousRoot(t *testing.T) {
|
||||
testCases := []struct {
|
||||
desc string
|
||||
root string
|
||||
expected string
|
||||
desc string
|
||||
root string
|
||||
rootPathSuffix string
|
||||
expected string
|
||||
}{
|
||||
{
|
||||
desc: "GOPATH",
|
||||
@@ -215,6 +216,18 @@ func Test_previousRoot(t *testing.T) {
|
||||
root: "github.com/foo/pkg/vendor/guthib.com/containous/fromage/vendor/guthib.com/containous/fuu",
|
||||
expected: "github.com/foo/pkg/vendor/guthib.com/containous/fromage",
|
||||
},
|
||||
{
|
||||
desc: "vendor is sibling",
|
||||
root: "github.com/foo/bar",
|
||||
rootPathSuffix: "testdata/src/github.com/foo/bar",
|
||||
expected: "github.com/foo",
|
||||
},
|
||||
{
|
||||
desc: "vendor is uncle",
|
||||
root: "github.com/foo/bar/baz",
|
||||
rootPathSuffix: "testdata/src/github.com/foo/bar/baz",
|
||||
expected: "github.com/foo",
|
||||
},
|
||||
}
|
||||
|
||||
for _, test := range testCases {
|
||||
@@ -222,7 +235,20 @@ func Test_previousRoot(t *testing.T) {
|
||||
t.Run(test.desc, func(t *testing.T) {
|
||||
t.Parallel()
|
||||
|
||||
p := previousRoot(test.root)
|
||||
var rootPath string
|
||||
if test.rootPathSuffix != "" {
|
||||
wd, err := os.Getwd()
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
rootPath = filepath.Join(wd, test.rootPathSuffix)
|
||||
} else {
|
||||
rootPath = vendor
|
||||
}
|
||||
p, err := previousRoot(rootPath, test.root)
|
||||
if err != nil {
|
||||
t.Error(err)
|
||||
}
|
||||
|
||||
if p != test.expected {
|
||||
t.Errorf("got: %s, want: %s", p, test.expected)
|
||||
|
||||
1
interp/testdata/src/github.com/foo/bar/baz/baz.go
vendored
Normal file
1
interp/testdata/src/github.com/foo/bar/baz/baz.go
vendored
Normal file
@@ -0,0 +1 @@
|
||||
package baz
|
||||
1
interp/testdata/src/github.com/foo/vendor/whatever/whatever.go
vendored
Normal file
1
interp/testdata/src/github.com/foo/vendor/whatever/whatever.go
vendored
Normal file
@@ -0,0 +1 @@
|
||||
package whatever
|
||||
@@ -1013,7 +1013,11 @@ func (t *itype) id() (res string) {
|
||||
case arrayT:
|
||||
res = "[" + strconv.Itoa(t.size) + "]" + t.val.id()
|
||||
case chanT:
|
||||
res = "<-" + t.val.id()
|
||||
res = "chan " + t.val.id()
|
||||
case chanSendT:
|
||||
res = "chan<- " + t.val.id()
|
||||
case chanRecvT:
|
||||
res = "<-chan " + t.val.id()
|
||||
case funcT:
|
||||
res = "func("
|
||||
for _, t := range t.arg {
|
||||
@@ -1241,6 +1245,10 @@ func (t *itype) refType(defined map[string]*itype, wrapRecursive bool) reflect.T
|
||||
// a node can still point to a previous copy.
|
||||
st.typ.recursive = st.typ.recursive || st.typ.isRecursive()
|
||||
recursive = st.typ.isRecursive()
|
||||
// It is possible that t.recursive is not inline with st.typ.recursive
|
||||
// which will break recursion detection. Set it here to make sure it
|
||||
// is correct.
|
||||
t.recursive = recursive
|
||||
}
|
||||
}
|
||||
if wrapRecursive && t.recursive {
|
||||
@@ -1252,9 +1260,11 @@ func (t *itype) refType(defined map[string]*itype, wrapRecursive bool) reflect.T
|
||||
if defined[name] != nil && defined[name].rtype != nil {
|
||||
return defined[name].rtype
|
||||
}
|
||||
if t.val != nil && defined[t.val.path+"/"+t.val.name] != nil && t.val.rtype == nil {
|
||||
if t.val != nil && t.val.cat == structT && t.val.rtype == nil && hasRecursiveStruct(t.val, copyDefined(defined)) {
|
||||
// Replace reference to self (direct or indirect) by an interface{} to handle
|
||||
// recursive types with reflect.
|
||||
typ := *t.val
|
||||
t.val = &typ
|
||||
t.val.rtype = interf
|
||||
recursive = true
|
||||
}
|
||||
@@ -1357,6 +1367,44 @@ func (t *itype) implements(it *itype) bool {
|
||||
return t.methods().contains(it.methods())
|
||||
}
|
||||
|
||||
func copyDefined(m map[string]*itype) map[string]*itype {
|
||||
n := make(map[string]*itype, len(m))
|
||||
for k, v := range m {
|
||||
n[k] = v
|
||||
}
|
||||
return n
|
||||
}
|
||||
|
||||
// hasRecursiveStruct determines if a struct is a recursion or a recursion
|
||||
// intermediate. A recursion intermediate is a struct that contains a recursive
|
||||
// struct.
|
||||
func hasRecursiveStruct(t *itype, defined map[string]*itype) bool {
|
||||
if len(defined) == 0 {
|
||||
return false
|
||||
}
|
||||
|
||||
typ := t
|
||||
for typ != nil {
|
||||
if typ.cat != structT {
|
||||
typ = typ.val
|
||||
continue
|
||||
}
|
||||
|
||||
if defined[typ.path+"/"+typ.name] != nil {
|
||||
return true
|
||||
}
|
||||
defined[typ.path+"/"+typ.name] = typ
|
||||
|
||||
for _, f := range typ.field {
|
||||
if hasRecursiveStruct(f.typ, defined) {
|
||||
return true
|
||||
}
|
||||
}
|
||||
return false
|
||||
}
|
||||
return false
|
||||
}
|
||||
|
||||
var errType = reflect.TypeOf((*error)(nil)).Elem()
|
||||
|
||||
func catOf(t reflect.Type) tcat {
|
||||
@@ -1493,6 +1541,10 @@ func isSendChan(t *itype) bool {
|
||||
return rt.Kind() == reflect.Chan && rt.ChanDir() == reflect.SendDir
|
||||
}
|
||||
func isMap(t *itype) bool { return t.TypeOf().Kind() == reflect.Map }
|
||||
func isArray(t *itype) bool {
|
||||
k := t.TypeOf().Kind()
|
||||
return k == reflect.Array || k == reflect.Slice
|
||||
}
|
||||
|
||||
func isInterfaceSrc(t *itype) bool {
|
||||
return t.cat == interfaceT || (t.cat == aliasT && isInterfaceSrc(t.val))
|
||||
|
||||
@@ -182,16 +182,6 @@ func genValueInterfaceArray(n *node) func(*frame) reflect.Value {
|
||||
}
|
||||
}
|
||||
|
||||
func genValueInterfacePtr(n *node) func(*frame) reflect.Value {
|
||||
value := genValue(n)
|
||||
|
||||
return func(f *frame) reflect.Value {
|
||||
v := reflect.New(interf).Elem()
|
||||
v.Set(value(f))
|
||||
return v.Addr()
|
||||
}
|
||||
}
|
||||
|
||||
func genValueInterface(n *node) func(*frame) reflect.Value {
|
||||
value := genValue(n)
|
||||
|
||||
@@ -211,18 +201,6 @@ func genValueInterface(n *node) func(*frame) reflect.Value {
|
||||
}
|
||||
}
|
||||
|
||||
func genValueDerefInterfacePtr(n *node) func(*frame) reflect.Value {
|
||||
value := genValue(n)
|
||||
|
||||
return func(f *frame) reflect.Value {
|
||||
v := value(f)
|
||||
if v.IsZero() {
|
||||
return v
|
||||
}
|
||||
return v.Elem().Elem()
|
||||
}
|
||||
}
|
||||
|
||||
func zeroInterfaceValue() reflect.Value {
|
||||
n := &node{kind: basicLit, typ: &itype{cat: nilT, untyped: true}}
|
||||
v := reflect.New(interf).Elem()
|
||||
@@ -269,6 +247,63 @@ func genValueNode(n *node) func(*frame) reflect.Value {
|
||||
}
|
||||
}
|
||||
|
||||
func genValueRecursiveInterface(n *node, t reflect.Type) func(*frame) reflect.Value {
|
||||
value := genValue(n)
|
||||
|
||||
return func(f *frame) reflect.Value {
|
||||
vv := value(f)
|
||||
v := reflect.New(t).Elem()
|
||||
toRecursive(v, vv)
|
||||
return v
|
||||
}
|
||||
}
|
||||
|
||||
func toRecursive(dest, src reflect.Value) {
|
||||
if !src.IsValid() {
|
||||
return
|
||||
}
|
||||
|
||||
switch dest.Kind() {
|
||||
case reflect.Map:
|
||||
v := reflect.MakeMapWithSize(dest.Type(), src.Len())
|
||||
for _, kv := range src.MapKeys() {
|
||||
vv := reflect.New(dest.Type().Elem()).Elem()
|
||||
toRecursive(vv, src.MapIndex(kv))
|
||||
vv.SetMapIndex(kv, vv)
|
||||
}
|
||||
dest.Set(v)
|
||||
case reflect.Slice:
|
||||
l := src.Len()
|
||||
v := reflect.MakeSlice(dest.Type(), l, l)
|
||||
for i := 0; i < l; i++ {
|
||||
toRecursive(v.Index(i), src.Index(i))
|
||||
}
|
||||
dest.Set(v)
|
||||
case reflect.Ptr:
|
||||
v := reflect.New(dest.Type().Elem()).Elem()
|
||||
s := src
|
||||
if s.Elem().Kind() != reflect.Struct { // In the case of *interface{}, we want *struct{}
|
||||
s = s.Elem()
|
||||
}
|
||||
toRecursive(v, s)
|
||||
dest.Set(v.Addr())
|
||||
default:
|
||||
dest.Set(src)
|
||||
}
|
||||
}
|
||||
|
||||
func genValueRecursiveInterfacePtrValue(n *node) func(*frame) reflect.Value {
|
||||
value := genValue(n)
|
||||
|
||||
return func(f *frame) reflect.Value {
|
||||
v := value(f)
|
||||
if v.IsZero() {
|
||||
return v
|
||||
}
|
||||
return v.Elem().Elem()
|
||||
}
|
||||
}
|
||||
|
||||
func vInt(v reflect.Value) (i int64) {
|
||||
switch v.Type().Kind() {
|
||||
case reflect.Int, reflect.Int8, reflect.Int16, reflect.Int32, reflect.Int64:
|
||||
|
||||
@@ -14,9 +14,9 @@ import (
|
||||
func init() {
|
||||
Symbols["log"] = map[string]reflect.Value{
|
||||
// function, constant and variable definitions
|
||||
"Fatal": reflect.ValueOf(log.Fatal),
|
||||
"Fatalf": reflect.ValueOf(log.Fatalf),
|
||||
"Fatalln": reflect.ValueOf(log.Fatalln),
|
||||
"Fatal": reflect.ValueOf(logFatal),
|
||||
"Fatalf": reflect.ValueOf(logFatalf),
|
||||
"Fatalln": reflect.ValueOf(logFatalln),
|
||||
"Flags": reflect.ValueOf(log.Flags),
|
||||
"LUTC": reflect.ValueOf(constant.MakeFromLiteral("32", token.INT, 0)),
|
||||
"Ldate": reflect.ValueOf(constant.MakeFromLiteral("1", token.INT, 0)),
|
||||
@@ -25,7 +25,7 @@ func init() {
|
||||
"Lshortfile": reflect.ValueOf(constant.MakeFromLiteral("16", token.INT, 0)),
|
||||
"LstdFlags": reflect.ValueOf(constant.MakeFromLiteral("3", token.INT, 0)),
|
||||
"Ltime": reflect.ValueOf(constant.MakeFromLiteral("2", token.INT, 0)),
|
||||
"New": reflect.ValueOf(log.New),
|
||||
"New": reflect.ValueOf(logNew),
|
||||
"Output": reflect.ValueOf(log.Output),
|
||||
"Panic": reflect.ValueOf(log.Panic),
|
||||
"Panicf": reflect.ValueOf(log.Panicf),
|
||||
@@ -40,6 +40,6 @@ func init() {
|
||||
"Writer": reflect.ValueOf(log.Writer),
|
||||
|
||||
// type definitions
|
||||
"Logger": reflect.ValueOf((*log.Logger)(nil)),
|
||||
"Logger": reflect.ValueOf((*logLogger)(nil)),
|
||||
}
|
||||
}
|
||||
|
||||
@@ -31,10 +31,10 @@ func init() {
|
||||
"ErrNotExist": reflect.ValueOf(&os.ErrNotExist).Elem(),
|
||||
"ErrPermission": reflect.ValueOf(&os.ErrPermission).Elem(),
|
||||
"Executable": reflect.ValueOf(os.Executable),
|
||||
"Exit": reflect.ValueOf(os.Exit),
|
||||
"Exit": reflect.ValueOf(osExit),
|
||||
"Expand": reflect.ValueOf(os.Expand),
|
||||
"ExpandEnv": reflect.ValueOf(os.ExpandEnv),
|
||||
"FindProcess": reflect.ValueOf(os.FindProcess),
|
||||
"FindProcess": reflect.ValueOf(osFindProcess),
|
||||
"Getegid": reflect.ValueOf(os.Getegid),
|
||||
"Getenv": reflect.ValueOf(os.Getenv),
|
||||
"Geteuid": reflect.ValueOf(os.Geteuid),
|
||||
|
||||
@@ -1,25 +0,0 @@
|
||||
// Code generated by 'goexports os/exec'. DO NOT EDIT.
|
||||
|
||||
// +build go1.13,!go1.14
|
||||
|
||||
package stdlib
|
||||
|
||||
import (
|
||||
"os/exec"
|
||||
"reflect"
|
||||
)
|
||||
|
||||
func init() {
|
||||
Symbols["os/exec"] = map[string]reflect.Value{
|
||||
// function, constant and variable definitions
|
||||
"Command": reflect.ValueOf(exec.Command),
|
||||
"CommandContext": reflect.ValueOf(exec.CommandContext),
|
||||
"ErrNotFound": reflect.ValueOf(&exec.ErrNotFound).Elem(),
|
||||
"LookPath": reflect.ValueOf(exec.LookPath),
|
||||
|
||||
// type definitions
|
||||
"Cmd": reflect.ValueOf((*exec.Cmd)(nil)),
|
||||
"Error": reflect.ValueOf((*exec.Error)(nil)),
|
||||
"ExitError": reflect.ValueOf((*exec.ExitError)(nil)),
|
||||
}
|
||||
}
|
||||
@@ -14,9 +14,9 @@ import (
|
||||
func init() {
|
||||
Symbols["log"] = map[string]reflect.Value{
|
||||
// function, constant and variable definitions
|
||||
"Fatal": reflect.ValueOf(log.Fatal),
|
||||
"Fatalf": reflect.ValueOf(log.Fatalf),
|
||||
"Fatalln": reflect.ValueOf(log.Fatalln),
|
||||
"Fatal": reflect.ValueOf(logFatal),
|
||||
"Fatalf": reflect.ValueOf(logFatalf),
|
||||
"Fatalln": reflect.ValueOf(logFatalln),
|
||||
"Flags": reflect.ValueOf(log.Flags),
|
||||
"LUTC": reflect.ValueOf(constant.MakeFromLiteral("32", token.INT, 0)),
|
||||
"Ldate": reflect.ValueOf(constant.MakeFromLiteral("1", token.INT, 0)),
|
||||
@@ -26,7 +26,7 @@ func init() {
|
||||
"Lshortfile": reflect.ValueOf(constant.MakeFromLiteral("16", token.INT, 0)),
|
||||
"LstdFlags": reflect.ValueOf(constant.MakeFromLiteral("3", token.INT, 0)),
|
||||
"Ltime": reflect.ValueOf(constant.MakeFromLiteral("2", token.INT, 0)),
|
||||
"New": reflect.ValueOf(log.New),
|
||||
"New": reflect.ValueOf(logNew),
|
||||
"Output": reflect.ValueOf(log.Output),
|
||||
"Panic": reflect.ValueOf(log.Panic),
|
||||
"Panicf": reflect.ValueOf(log.Panicf),
|
||||
@@ -41,6 +41,6 @@ func init() {
|
||||
"Writer": reflect.ValueOf(log.Writer),
|
||||
|
||||
// type definitions
|
||||
"Logger": reflect.ValueOf((*log.Logger)(nil)),
|
||||
"Logger": reflect.ValueOf((*logLogger)(nil)),
|
||||
}
|
||||
}
|
||||
|
||||
@@ -31,10 +31,10 @@ func init() {
|
||||
"ErrNotExist": reflect.ValueOf(&os.ErrNotExist).Elem(),
|
||||
"ErrPermission": reflect.ValueOf(&os.ErrPermission).Elem(),
|
||||
"Executable": reflect.ValueOf(os.Executable),
|
||||
"Exit": reflect.ValueOf(os.Exit),
|
||||
"Exit": reflect.ValueOf(osExit),
|
||||
"Expand": reflect.ValueOf(os.Expand),
|
||||
"ExpandEnv": reflect.ValueOf(os.ExpandEnv),
|
||||
"FindProcess": reflect.ValueOf(os.FindProcess),
|
||||
"FindProcess": reflect.ValueOf(osFindProcess),
|
||||
"Getegid": reflect.ValueOf(os.Getegid),
|
||||
"Getenv": reflect.ValueOf(os.Getenv),
|
||||
"Geteuid": reflect.ValueOf(os.Geteuid),
|
||||
|
||||
@@ -1,25 +0,0 @@
|
||||
// Code generated by 'goexports os/exec'. DO NOT EDIT.
|
||||
|
||||
// +build go1.14,!go1.15
|
||||
|
||||
package stdlib
|
||||
|
||||
import (
|
||||
"os/exec"
|
||||
"reflect"
|
||||
)
|
||||
|
||||
func init() {
|
||||
Symbols["os/exec"] = map[string]reflect.Value{
|
||||
// function, constant and variable definitions
|
||||
"Command": reflect.ValueOf(exec.Command),
|
||||
"CommandContext": reflect.ValueOf(exec.CommandContext),
|
||||
"ErrNotFound": reflect.ValueOf(&exec.ErrNotFound).Elem(),
|
||||
"LookPath": reflect.ValueOf(exec.LookPath),
|
||||
|
||||
// type definitions
|
||||
"Cmd": reflect.ValueOf((*exec.Cmd)(nil)),
|
||||
"Error": reflect.ValueOf((*exec.Error)(nil)),
|
||||
"ExitError": reflect.ValueOf((*exec.ExitError)(nil)),
|
||||
}
|
||||
}
|
||||
55
stdlib/restricted.go
Normal file
55
stdlib/restricted.go
Normal file
@@ -0,0 +1,55 @@
|
||||
package stdlib
|
||||
|
||||
import (
|
||||
"errors"
|
||||
"io"
|
||||
"log"
|
||||
"os"
|
||||
"strconv"
|
||||
)
|
||||
|
||||
var errRestricted = errors.New("restricted")
|
||||
|
||||
// osExit invokes panic instead of exit.
|
||||
func osExit(code int) { panic("os.Exit(" + strconv.Itoa(code) + ")") }
|
||||
|
||||
// osFindProcess returns os.FindProcess, except for self process.
|
||||
func osFindProcess(pid int) (*os.Process, error) {
|
||||
if pid == os.Getpid() {
|
||||
return nil, errRestricted
|
||||
}
|
||||
return os.FindProcess(pid)
|
||||
}
|
||||
|
||||
// The following functions call Panic instead of Fatal to avoid exit.
|
||||
func logFatal(v ...interface{}) { log.Panic(v...) }
|
||||
func logFatalf(f string, v ...interface{}) { log.Panicf(f, v...) }
|
||||
func logFatalln(v ...interface{}) { log.Panicln(v...) }
|
||||
|
||||
type logLogger struct {
|
||||
l *log.Logger
|
||||
}
|
||||
|
||||
// logNew Returns a wrapped logger.
|
||||
func logNew(out io.Writer, prefix string, flag int) *logLogger {
|
||||
return &logLogger{log.New(out, prefix, flag)}
|
||||
}
|
||||
|
||||
// The following methods call Panic instead of Fatal to avoid exit.
|
||||
func (l *logLogger) Fatal(v ...interface{}) { l.l.Panic(v...) }
|
||||
func (l *logLogger) Fatalf(f string, v ...interface{}) { l.l.Panicf(f, v...) }
|
||||
func (l *logLogger) Fatalln(v ...interface{}) { l.l.Panicln(v...) }
|
||||
|
||||
// The following methods just forward to wrapped logger.
|
||||
func (l *logLogger) Flags() int { return l.l.Flags() }
|
||||
func (l *logLogger) Output(d int, s string) error { return l.l.Output(d, s) }
|
||||
func (l *logLogger) Panic(v ...interface{}) { l.l.Panic(v...) }
|
||||
func (l *logLogger) Panicf(f string, v ...interface{}) { l.l.Panicf(f, v...) }
|
||||
func (l *logLogger) Panicln(v ...interface{}) { l.l.Panicln(v...) }
|
||||
func (l *logLogger) Prefix() string { return l.l.Prefix() }
|
||||
func (l *logLogger) Print(v ...interface{}) { l.l.Print(v...) }
|
||||
func (l *logLogger) Printf(f string, v ...interface{}) { l.l.Printf(f, v...) }
|
||||
func (l *logLogger) Println(v ...interface{}) { l.l.Println(v...) }
|
||||
func (l *logLogger) SetFlags(flag int) { l.l.SetFlags(flag) }
|
||||
func (l *logLogger) SetOutput(w io.Writer) { l.l.SetOutput(w) }
|
||||
func (l *logLogger) Writer() io.Writer { return l.l.Writer() }
|
||||
@@ -43,7 +43,7 @@ func init() {
|
||||
//go:generate ../cmd/goexports/goexports net net/http net/http/cgi net/http/cookiejar net/http/fcgi
|
||||
//go:generate ../cmd/goexports/goexports net/http/httptest net/http/httptrace net/http/httputil net/http/pprof
|
||||
//go:generate ../cmd/goexports/goexports net/mail net/rpc net/rpc/jsonrpc net/smtp net/textproto net/url
|
||||
//go:generate ../cmd/goexports/goexports os os/exec os/signal os/user
|
||||
//go:generate ../cmd/goexports/goexports os os/signal os/user
|
||||
//go:generate ../cmd/goexports/goexports path path/filepath reflect regexp regexp/syntax
|
||||
//go:generate ../cmd/goexports/goexports runtime runtime/debug runtime/pprof runtime/trace
|
||||
//go:generate ../cmd/goexports/goexports sort strconv strings sync sync/atomic
|
||||
|
||||
41
stdlib/unrestricted/unrestricted.go
Normal file
41
stdlib/unrestricted/unrestricted.go
Normal file
@@ -0,0 +1,41 @@
|
||||
// Package unrestricted provides the original version of standard library symbols which may cause the interpreter process to exit.
|
||||
package unrestricted
|
||||
|
||||
import (
|
||||
"log"
|
||||
"os"
|
||||
"os/exec"
|
||||
"reflect"
|
||||
)
|
||||
|
||||
// Symbols stores the map of syscall package symbols.
|
||||
var Symbols = map[string]map[string]reflect.Value{}
|
||||
|
||||
func init() {
|
||||
Symbols["os"] = map[string]reflect.Value{
|
||||
"Exit": reflect.ValueOf(os.Exit),
|
||||
"FindProcess": reflect.ValueOf(os.FindProcess),
|
||||
}
|
||||
|
||||
Symbols["os/exec"] = map[string]reflect.Value{
|
||||
"Command": reflect.ValueOf(exec.Command),
|
||||
"CommandContext": reflect.ValueOf(exec.CommandContext),
|
||||
"ErrNotFound": reflect.ValueOf(&exec.ErrNotFound).Elem(),
|
||||
"LookPath": reflect.ValueOf(exec.LookPath),
|
||||
"Cmd": reflect.ValueOf((*exec.Cmd)(nil)),
|
||||
"Error": reflect.ValueOf((*exec.Error)(nil)),
|
||||
"ExitError": reflect.ValueOf((*exec.ExitError)(nil)),
|
||||
}
|
||||
|
||||
Symbols["log"] = map[string]reflect.Value{
|
||||
"Fatal": reflect.ValueOf(log.Fatal),
|
||||
"Fatalf": reflect.ValueOf(log.Fatalf),
|
||||
"Fatalln": reflect.ValueOf(log.Fatalln),
|
||||
"New": reflect.ValueOf(log.New),
|
||||
"Logger": reflect.ValueOf((*log.Logger)(nil)),
|
||||
}
|
||||
|
||||
Symbols["github.com/containous/yaegi/stdlib/unrestricted"] = map[string]reflect.Value{
|
||||
"Symbols": reflect.ValueOf(Symbols),
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user