Compare commits
33 Commits
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
cdf4622421 | ||
|
|
b9720d15e1 | ||
|
|
7fab75fbe4 | ||
|
|
7eac6955b3 | ||
|
|
7070367d21 | ||
|
|
22dfc8b10a | ||
|
|
7fba3fe580 | ||
|
|
ff36ec58b1 | ||
|
|
f6c8b8b14f | ||
|
|
e12c8b72c4 | ||
|
|
e4acba031d | ||
|
|
7d56fb067e | ||
|
|
1feece61ce | ||
|
|
01e2e4600e | ||
|
|
92eebbade2 | ||
|
|
a6389aca5e | ||
|
|
de8cb7dc3b | ||
|
|
18b843646c | ||
|
|
71f730b3d7 | ||
|
|
7b2d91bcb5 | ||
|
|
3ed4ec3f6f | ||
|
|
5e142fdedd | ||
|
|
94d44e7265 | ||
|
|
56925e6fea | ||
|
|
c580dfdbc8 | ||
|
|
29e1777d82 | ||
|
|
50a34fd2a7 | ||
|
|
465cb578e7 | ||
|
|
12942b59a0 | ||
|
|
3e76267f8e | ||
|
|
988f0c9672 | ||
|
|
b0053c874f | ||
|
|
b20ad3a01d |
9
_test/add0.go
Normal file
9
_test/add0.go
Normal file
@@ -0,0 +1,9 @@
|
||||
package main
|
||||
|
||||
func main() {
|
||||
var a interface{} = 2 + 5
|
||||
println(a.(int))
|
||||
}
|
||||
|
||||
// Output:
|
||||
// 7
|
||||
10
_test/add1.go
Normal file
10
_test/add1.go
Normal file
@@ -0,0 +1,10 @@
|
||||
package main
|
||||
|
||||
func main() {
|
||||
b := 2
|
||||
var a interface{} = 5 + b
|
||||
println(a.(int))
|
||||
}
|
||||
|
||||
// Output:
|
||||
// 7
|
||||
12
_test/add2.go
Normal file
12
_test/add2.go
Normal file
@@ -0,0 +1,12 @@
|
||||
package main
|
||||
|
||||
type iface interface{}
|
||||
|
||||
func main() {
|
||||
b := 2
|
||||
var a iface = 5 + b
|
||||
println(a.(int))
|
||||
}
|
||||
|
||||
// Output:
|
||||
// 7
|
||||
14
_test/append0.go
Normal file
14
_test/append0.go
Normal file
@@ -0,0 +1,14 @@
|
||||
package main
|
||||
|
||||
import "fmt"
|
||||
|
||||
func f(a []int, b int) interface{} { return append(a, b) }
|
||||
|
||||
func main() {
|
||||
a := []int{1, 2}
|
||||
r := f(a, 3)
|
||||
fmt.Println(r.([]int))
|
||||
}
|
||||
|
||||
// Output:
|
||||
// [1 2 3]
|
||||
10
_test/assign11.go
Normal file
10
_test/assign11.go
Normal file
@@ -0,0 +1,10 @@
|
||||
package main
|
||||
|
||||
import "fmt"
|
||||
|
||||
func main() {
|
||||
_, _, _ = fmt.Println("test")
|
||||
}
|
||||
|
||||
// Error:
|
||||
// 6:2: assignment mismatch: 3 variables but fmt.Println returns 2 values
|
||||
11
_test/assign12.go
Normal file
11
_test/assign12.go
Normal file
@@ -0,0 +1,11 @@
|
||||
package main
|
||||
|
||||
import "fmt"
|
||||
|
||||
func main() {
|
||||
a, b, c := fmt.Println("test")
|
||||
println(a, b, c)
|
||||
}
|
||||
|
||||
// Error:
|
||||
// 6:2: assignment mismatch: 3 variables but fmt.Println returns 2 values
|
||||
18
_test/bin4.go
Normal file
18
_test/bin4.go
Normal file
@@ -0,0 +1,18 @@
|
||||
package main
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"strings"
|
||||
)
|
||||
|
||||
func Bar(s string) bool {
|
||||
a := strings.HasPrefix("fas", "f")
|
||||
b := strings.HasPrefix("aaaaa", "a")
|
||||
a_and_b := strings.HasPrefix("fas", "f") && strings.HasPrefix("aaaaa", "a")
|
||||
fmt.Println(a, b, a && b, a_and_b)
|
||||
return a && b
|
||||
}
|
||||
|
||||
func main() {
|
||||
println(Bar("kung"))
|
||||
}
|
||||
15
_test/bin5.go
Normal file
15
_test/bin5.go
Normal file
@@ -0,0 +1,15 @@
|
||||
package main
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"net"
|
||||
)
|
||||
|
||||
func main() {
|
||||
addr := net.TCPAddr{IP: net.IPv4(1, 1, 1, 1), Port: 80}
|
||||
var s fmt.Stringer = &addr
|
||||
fmt.Println(s.String())
|
||||
}
|
||||
|
||||
// Output:
|
||||
// 1.1.1.1:80
|
||||
13
_test/cap0.go
Normal file
13
_test/cap0.go
Normal file
@@ -0,0 +1,13 @@
|
||||
package main
|
||||
|
||||
func f(a []int) interface{} {
|
||||
return cap(a)
|
||||
}
|
||||
|
||||
func main() {
|
||||
a := []int{1, 2}
|
||||
println(f(a).(int))
|
||||
}
|
||||
|
||||
// Output:
|
||||
// 2
|
||||
20
_test/chan9.go
Normal file
20
_test/chan9.go
Normal file
@@ -0,0 +1,20 @@
|
||||
package main
|
||||
|
||||
type Channel chan string
|
||||
|
||||
type T struct {
|
||||
Channel
|
||||
}
|
||||
|
||||
func send(c Channel) { c <- "ping" }
|
||||
|
||||
func main() {
|
||||
t := &T{}
|
||||
t.Channel = make(Channel)
|
||||
go send(t.Channel)
|
||||
msg := <-t.Channel
|
||||
println(msg)
|
||||
}
|
||||
|
||||
// Output:
|
||||
// ping
|
||||
9
_test/comp1.go
Normal file
9
_test/comp1.go
Normal file
@@ -0,0 +1,9 @@
|
||||
package main
|
||||
|
||||
func main() {
|
||||
var a interface{} = 1 < 2
|
||||
println(a.(bool))
|
||||
}
|
||||
|
||||
// Output:
|
||||
// true
|
||||
13
_test/complex4.go
Normal file
13
_test/complex4.go
Normal file
@@ -0,0 +1,13 @@
|
||||
package main
|
||||
|
||||
import "fmt"
|
||||
|
||||
func f(a, b float64) interface{} { return complex(a, b) }
|
||||
|
||||
func main() {
|
||||
a := f(3, 2)
|
||||
fmt.Println(a.(complex128))
|
||||
}
|
||||
|
||||
// Output:
|
||||
// (3+2i)
|
||||
16
_test/composite8.go
Normal file
16
_test/composite8.go
Normal file
@@ -0,0 +1,16 @@
|
||||
package main
|
||||
|
||||
type T struct{ I int }
|
||||
|
||||
func main() {
|
||||
t := []*T{}
|
||||
s := []int{1, 2}
|
||||
for _, e := range s {
|
||||
x := &T{e}
|
||||
t = append(t, x)
|
||||
}
|
||||
println(t[0].I, t[1].I)
|
||||
}
|
||||
|
||||
// Output:
|
||||
// 1 2
|
||||
13
_test/const11.go
Normal file
13
_test/const11.go
Normal file
@@ -0,0 +1,13 @@
|
||||
package main
|
||||
|
||||
func main() {
|
||||
const (
|
||||
x = 2 * iota
|
||||
dim
|
||||
)
|
||||
var t [dim * 2]int
|
||||
println(t[0], len(t))
|
||||
}
|
||||
|
||||
// Output:
|
||||
// 0 4
|
||||
16
_test/copy2.go
Normal file
16
_test/copy2.go
Normal file
@@ -0,0 +1,16 @@
|
||||
package main
|
||||
|
||||
import "fmt"
|
||||
|
||||
func f(a, b []int) interface{} { return copy(a, b) }
|
||||
|
||||
func main() {
|
||||
a := []int{10, 20, 30}
|
||||
b := [4]int{}
|
||||
c := b[:]
|
||||
r := f(c, a)
|
||||
fmt.Println(r.(int))
|
||||
}
|
||||
|
||||
// Output:
|
||||
// 3
|
||||
12
_test/fun12.go
Normal file
12
_test/fun12.go
Normal file
@@ -0,0 +1,12 @@
|
||||
package main
|
||||
|
||||
func use(interface{}) {}
|
||||
|
||||
func main() {
|
||||
z := map[string]interface{}{"a": 5}
|
||||
use(z)
|
||||
println("bye")
|
||||
}
|
||||
|
||||
// Output:
|
||||
// bye
|
||||
19
_test/fun13.go
Normal file
19
_test/fun13.go
Normal file
@@ -0,0 +1,19 @@
|
||||
package main
|
||||
|
||||
import "fmt"
|
||||
|
||||
type T struct{}
|
||||
|
||||
func newT() (T, error) { return T{}, nil }
|
||||
|
||||
func main() {
|
||||
var (
|
||||
i interface{}
|
||||
err error
|
||||
)
|
||||
i, err = newT()
|
||||
fmt.Println(i, err)
|
||||
}
|
||||
|
||||
// Output:
|
||||
// {} <nil>
|
||||
13
_test/fun14.go
Normal file
13
_test/fun14.go
Normal file
@@ -0,0 +1,13 @@
|
||||
package main
|
||||
|
||||
func f() (bool, int) { return true, 2 }
|
||||
|
||||
func g() (bool, int) { return f() }
|
||||
|
||||
func main() {
|
||||
b, i := g()
|
||||
println(b, i)
|
||||
}
|
||||
|
||||
// Output:
|
||||
// true 2
|
||||
11
_test/fun15.go
Normal file
11
_test/fun15.go
Normal file
@@ -0,0 +1,11 @@
|
||||
package main
|
||||
|
||||
func f1(a int) interface{} { return a + 1 }
|
||||
|
||||
func main() {
|
||||
c := f1(3)
|
||||
println(c.(int))
|
||||
}
|
||||
|
||||
// Output:
|
||||
// 4
|
||||
13
_test/fun16.go
Normal file
13
_test/fun16.go
Normal file
@@ -0,0 +1,13 @@
|
||||
package main
|
||||
|
||||
func f1(a int) int { return a + 1 }
|
||||
|
||||
func f2(a int) interface{} { return f1(a) }
|
||||
|
||||
func main() {
|
||||
c := f2(3)
|
||||
println(c.(int))
|
||||
}
|
||||
|
||||
// Output:
|
||||
// 4
|
||||
13
_test/fun17.go
Normal file
13
_test/fun17.go
Normal file
@@ -0,0 +1,13 @@
|
||||
package main
|
||||
|
||||
func f1(a int) interface{} { return a + 1 }
|
||||
|
||||
func f2(a int) interface{} { return f1(a) }
|
||||
|
||||
func main() {
|
||||
c := f2(3)
|
||||
println(c.(int))
|
||||
}
|
||||
|
||||
// Output:
|
||||
// 4
|
||||
12
_test/fun18.go
Normal file
12
_test/fun18.go
Normal file
@@ -0,0 +1,12 @@
|
||||
package main
|
||||
|
||||
var m = map[string]int{"foo": 1, "bar": 2}
|
||||
|
||||
func f(s string) interface{} { return m[s] }
|
||||
|
||||
func main() {
|
||||
println(f("foo").(int))
|
||||
}
|
||||
|
||||
// Output:
|
||||
// 1
|
||||
17
_test/fun19.go
Normal file
17
_test/fun19.go
Normal file
@@ -0,0 +1,17 @@
|
||||
package main
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
)
|
||||
|
||||
func foo() ([]string, error) {
|
||||
return nil, fmt.Errorf("bar")
|
||||
}
|
||||
|
||||
func main() {
|
||||
a, b := foo()
|
||||
fmt.Println(a, b)
|
||||
}
|
||||
|
||||
// Output:
|
||||
// [] bar
|
||||
19
_test/fun20.go
Normal file
19
_test/fun20.go
Normal file
@@ -0,0 +1,19 @@
|
||||
package main
|
||||
|
||||
import "fmt"
|
||||
|
||||
var myerr error = fmt.Errorf("bar")
|
||||
|
||||
func ferr() error { return myerr }
|
||||
|
||||
func foo() ([]string, error) {
|
||||
return nil, ferr()
|
||||
}
|
||||
|
||||
func main() {
|
||||
a, b := foo()
|
||||
fmt.Println(a, b)
|
||||
}
|
||||
|
||||
// Output:
|
||||
// [] bar
|
||||
14
_test/imag0.go
Normal file
14
_test/imag0.go
Normal file
@@ -0,0 +1,14 @@
|
||||
package main
|
||||
|
||||
import "fmt"
|
||||
|
||||
func f(c complex128) interface{} { return imag(c) }
|
||||
|
||||
func main() {
|
||||
c := complex(3, 2)
|
||||
a := f(c)
|
||||
fmt.Println(a.(float64))
|
||||
}
|
||||
|
||||
// Output:
|
||||
// 2
|
||||
11
_test/interface31.go
Normal file
11
_test/interface31.go
Normal file
@@ -0,0 +1,11 @@
|
||||
package main
|
||||
|
||||
import "fmt"
|
||||
|
||||
func main() {
|
||||
s := []interface{}{"test", 2}
|
||||
fmt.Println(s[0], s[1])
|
||||
}
|
||||
|
||||
// Output:
|
||||
// test 2
|
||||
11
_test/interface32.go
Normal file
11
_test/interface32.go
Normal file
@@ -0,0 +1,11 @@
|
||||
package main
|
||||
|
||||
import "fmt"
|
||||
|
||||
func main() {
|
||||
s := [2]interface{}{"test", 2}
|
||||
fmt.Println(s[0], s[1])
|
||||
}
|
||||
|
||||
// Output:
|
||||
// test 2
|
||||
11
_test/interface33.go
Normal file
11
_test/interface33.go
Normal file
@@ -0,0 +1,11 @@
|
||||
package main
|
||||
|
||||
import "fmt"
|
||||
|
||||
func main() {
|
||||
var a = map[string]interface{}{"test": "test"}
|
||||
fmt.Println(a["test"])
|
||||
}
|
||||
|
||||
// Output:
|
||||
// test
|
||||
11
_test/interface34.go
Normal file
11
_test/interface34.go
Normal file
@@ -0,0 +1,11 @@
|
||||
package main
|
||||
|
||||
import "fmt"
|
||||
|
||||
func main() {
|
||||
s := [2]interface{}{1: "test", 0: 2}
|
||||
fmt.Println(s[0], s[1])
|
||||
}
|
||||
|
||||
// Output:
|
||||
// 2 test
|
||||
15
_test/interface35.go
Normal file
15
_test/interface35.go
Normal file
@@ -0,0 +1,15 @@
|
||||
package main
|
||||
|
||||
import "fmt"
|
||||
|
||||
type T struct {
|
||||
I interface{}
|
||||
}
|
||||
|
||||
func main() {
|
||||
t := T{"test"}
|
||||
fmt.Println(t)
|
||||
}
|
||||
|
||||
// Output:
|
||||
// {test}
|
||||
37
_test/interface36.go
Normal file
37
_test/interface36.go
Normal file
@@ -0,0 +1,37 @@
|
||||
package main
|
||||
|
||||
import "fmt"
|
||||
|
||||
var (
|
||||
t *S
|
||||
_ I = t
|
||||
_ J = t
|
||||
)
|
||||
|
||||
type S struct {
|
||||
Name string
|
||||
}
|
||||
|
||||
func (s *S) F() int { return len(s.Name) }
|
||||
func (s *S) G() int { return s.F() }
|
||||
func (s *S) Ri() I { return s }
|
||||
func (s *S) Rj() J { return s }
|
||||
|
||||
type J interface {
|
||||
I
|
||||
G() int
|
||||
Rj() J
|
||||
}
|
||||
|
||||
type I interface {
|
||||
F() int
|
||||
Ri() I
|
||||
}
|
||||
|
||||
func main() {
|
||||
var j J
|
||||
fmt.Println(j)
|
||||
}
|
||||
|
||||
// Output:
|
||||
// <nil>
|
||||
23
_test/interface37.go
Normal file
23
_test/interface37.go
Normal file
@@ -0,0 +1,23 @@
|
||||
package main
|
||||
|
||||
type I interface {
|
||||
A() string
|
||||
B() string
|
||||
}
|
||||
|
||||
type s struct{}
|
||||
|
||||
func NewS() (I, error) {
|
||||
return &s{}, nil
|
||||
}
|
||||
|
||||
func (c *s) A() string { return "a" }
|
||||
func (c *s) B() string { return "b" }
|
||||
|
||||
func main() {
|
||||
s, _ := NewS()
|
||||
println(s.A())
|
||||
}
|
||||
|
||||
// Output:
|
||||
// a
|
||||
55
_test/issue-558.go
Normal file
55
_test/issue-558.go
Normal file
@@ -0,0 +1,55 @@
|
||||
package main
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"io"
|
||||
"io/ioutil"
|
||||
"log"
|
||||
"strings"
|
||||
)
|
||||
|
||||
type readAutoCloser struct {
|
||||
r io.ReadCloser
|
||||
}
|
||||
|
||||
func (a readAutoCloser) Read(b []byte) (n int, err error) {
|
||||
if a.r == nil {
|
||||
return 0, io.EOF
|
||||
}
|
||||
n, err = a.r.Read(b)
|
||||
if err == io.EOF {
|
||||
a.Close()
|
||||
}
|
||||
return n, err
|
||||
}
|
||||
|
||||
func (a readAutoCloser) Close() error {
|
||||
if a.r == nil {
|
||||
return nil
|
||||
}
|
||||
return a.r.(io.Closer).Close()
|
||||
}
|
||||
|
||||
type pipe struct {
|
||||
Reader readAutoCloser
|
||||
}
|
||||
|
||||
func newReadAutoCloser(r io.Reader) readAutoCloser {
|
||||
if _, ok := r.(io.Closer); !ok {
|
||||
return readAutoCloser{ioutil.NopCloser(r)}
|
||||
}
|
||||
return readAutoCloser{r.(io.ReadCloser)}
|
||||
}
|
||||
|
||||
func main() {
|
||||
p := &pipe{}
|
||||
p.Reader = newReadAutoCloser(strings.NewReader("test"))
|
||||
b, err := ioutil.ReadAll(p.Reader)
|
||||
if err != nil {
|
||||
log.Fatal(err)
|
||||
}
|
||||
fmt.Println(string(b))
|
||||
}
|
||||
|
||||
// Output:
|
||||
// test
|
||||
13
_test/len0.go
Normal file
13
_test/len0.go
Normal file
@@ -0,0 +1,13 @@
|
||||
package main
|
||||
|
||||
func f(a []int) interface{} {
|
||||
return len(a)
|
||||
}
|
||||
|
||||
func main() {
|
||||
a := []int{1, 2}
|
||||
println(f(a).(int))
|
||||
}
|
||||
|
||||
// Output:
|
||||
// 2
|
||||
13
_test/make0.go
Normal file
13
_test/make0.go
Normal file
@@ -0,0 +1,13 @@
|
||||
package main
|
||||
|
||||
func f() interface{} {
|
||||
return make([]int, 2)
|
||||
}
|
||||
|
||||
func main() {
|
||||
a := f()
|
||||
println(len(a.([]int)))
|
||||
}
|
||||
|
||||
// Output:
|
||||
// 2
|
||||
15
_test/make1.go
Normal file
15
_test/make1.go
Normal file
@@ -0,0 +1,15 @@
|
||||
package main
|
||||
|
||||
import "fmt"
|
||||
|
||||
func f() interface{} {
|
||||
return make(map[int]int)
|
||||
}
|
||||
|
||||
func main() {
|
||||
a, ok := f().(map[int]int)
|
||||
fmt.Println(a, ok)
|
||||
}
|
||||
|
||||
// Output:
|
||||
// map[] true
|
||||
18
_test/map24.go
Normal file
18
_test/map24.go
Normal file
@@ -0,0 +1,18 @@
|
||||
package main
|
||||
|
||||
import (
|
||||
"encoding/json"
|
||||
"fmt"
|
||||
)
|
||||
|
||||
func main() {
|
||||
jb := []byte(`{"property": "test"}`)
|
||||
params := map[string]interface{}{"foo": 1}
|
||||
if err := json.Unmarshal(jb, ¶ms); err != nil {
|
||||
panic("marshal failed.")
|
||||
}
|
||||
fmt.Println(params["foo"], params["property"])
|
||||
}
|
||||
|
||||
// Output:
|
||||
// 1 test
|
||||
26
_test/map25.go
Normal file
26
_test/map25.go
Normal file
@@ -0,0 +1,26 @@
|
||||
package main
|
||||
|
||||
import (
|
||||
"encoding/json"
|
||||
"strconv"
|
||||
)
|
||||
|
||||
func main() {
|
||||
jb := []byte(`{"num": "2"}`)
|
||||
params := map[string]interface{}{"foo": "1"}
|
||||
if err := json.Unmarshal(jb, ¶ms); err != nil {
|
||||
panic(err)
|
||||
}
|
||||
sum := 0
|
||||
for _, v := range params {
|
||||
i, err := strconv.Atoi(v.(string))
|
||||
if err != nil {
|
||||
panic(err)
|
||||
}
|
||||
sum += i
|
||||
}
|
||||
println(sum)
|
||||
}
|
||||
|
||||
// Output:
|
||||
// 3
|
||||
11
_test/map26.go
Normal file
11
_test/map26.go
Normal file
@@ -0,0 +1,11 @@
|
||||
package main
|
||||
|
||||
var m = map[string]int{"foo": 1, "bar": 2}
|
||||
|
||||
func main() {
|
||||
var a interface{} = m["foo"]
|
||||
println(a.(int))
|
||||
}
|
||||
|
||||
// Output:
|
||||
// 1
|
||||
24
_test/map27.go
Normal file
24
_test/map27.go
Normal file
@@ -0,0 +1,24 @@
|
||||
package main
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"text/template"
|
||||
)
|
||||
|
||||
type fm map[string]interface{}
|
||||
|
||||
type foo struct{}
|
||||
|
||||
func main() {
|
||||
a := make(fm)
|
||||
a["foo"] = &foo{}
|
||||
fmt.Println(a["foo"])
|
||||
|
||||
b := make(template.FuncMap) // type FuncMap map[string]interface{}
|
||||
b["foo"] = &foo{}
|
||||
fmt.Println(b["foo"])
|
||||
}
|
||||
|
||||
// Output:
|
||||
// &{}
|
||||
// &{}
|
||||
13
_test/new2.go
Normal file
13
_test/new2.go
Normal file
@@ -0,0 +1,13 @@
|
||||
package main
|
||||
|
||||
func f() interface{} {
|
||||
return new(int)
|
||||
}
|
||||
|
||||
func main() {
|
||||
a := f()
|
||||
println(*(a.(*int)))
|
||||
}
|
||||
|
||||
// Output:
|
||||
// 0
|
||||
12
_test/nil2.go
Normal file
12
_test/nil2.go
Normal file
@@ -0,0 +1,12 @@
|
||||
package main
|
||||
|
||||
func test() error { return nil }
|
||||
|
||||
func main() {
|
||||
if err := test(); nil == err {
|
||||
println("err is nil")
|
||||
}
|
||||
}
|
||||
|
||||
// Output:
|
||||
// err is nil
|
||||
16
_test/not0.go
Normal file
16
_test/not0.go
Normal file
@@ -0,0 +1,16 @@
|
||||
package main
|
||||
|
||||
func main() {
|
||||
a := 0
|
||||
b := true
|
||||
c := false
|
||||
if b && c {
|
||||
a = 1
|
||||
} else {
|
||||
a = -1
|
||||
}
|
||||
println(a)
|
||||
}
|
||||
|
||||
// Output:
|
||||
// -1
|
||||
15
_test/not1.go
Normal file
15
_test/not1.go
Normal file
@@ -0,0 +1,15 @@
|
||||
package main
|
||||
|
||||
func main() {
|
||||
a := 0
|
||||
b := true
|
||||
if (!b) {
|
||||
a = 1
|
||||
} else {
|
||||
a = -1
|
||||
}
|
||||
println(a)
|
||||
}
|
||||
|
||||
// Output:
|
||||
// -1
|
||||
9
_test/not2.go
Normal file
9
_test/not2.go
Normal file
@@ -0,0 +1,9 @@
|
||||
package main
|
||||
|
||||
func main() {
|
||||
var b interface{} = !(1 == 2)
|
||||
println(b.(bool))
|
||||
}
|
||||
|
||||
// Output:
|
||||
// true
|
||||
10
_test/num0.go
Normal file
10
_test/num0.go
Normal file
@@ -0,0 +1,10 @@
|
||||
package main
|
||||
|
||||
import "fmt"
|
||||
|
||||
func main() {
|
||||
fmt.Printf("%g\n", 1.0)
|
||||
}
|
||||
|
||||
// Output:
|
||||
// 1
|
||||
@@ -1,9 +1,9 @@
|
||||
package main
|
||||
|
||||
func main() {
|
||||
i := 100
|
||||
println(i % 1e2)
|
||||
i := 102
|
||||
println(i % -1e2)
|
||||
}
|
||||
|
||||
// Output:
|
||||
// 0
|
||||
// 2
|
||||
|
||||
12
_test/op5.go
Normal file
12
_test/op5.go
Normal file
@@ -0,0 +1,12 @@
|
||||
package main
|
||||
|
||||
import "fmt"
|
||||
|
||||
func main() {
|
||||
i := 100
|
||||
j := i % 1e2
|
||||
fmt.Printf("%T %v\n", j, j)
|
||||
}
|
||||
|
||||
// Output:
|
||||
// int 0
|
||||
14
_test/real0.go
Normal file
14
_test/real0.go
Normal file
@@ -0,0 +1,14 @@
|
||||
package main
|
||||
|
||||
import "fmt"
|
||||
|
||||
func f(c complex128) interface{} { return real(c) }
|
||||
|
||||
func main() {
|
||||
c := complex(3, 2)
|
||||
a := f(c)
|
||||
fmt.Println(a.(float64))
|
||||
}
|
||||
|
||||
// Output:
|
||||
// 3
|
||||
14
_test/select10.go
Normal file
14
_test/select10.go
Normal file
@@ -0,0 +1,14 @@
|
||||
package main
|
||||
|
||||
func main() {
|
||||
c := make(chan string)
|
||||
select {
|
||||
case <-c:
|
||||
println("unexpected")
|
||||
default:
|
||||
}
|
||||
println("bye")
|
||||
}
|
||||
|
||||
// Output:
|
||||
// bye
|
||||
16
_test/select11.go
Normal file
16
_test/select11.go
Normal file
@@ -0,0 +1,16 @@
|
||||
package main
|
||||
|
||||
func main() {
|
||||
c := make(chan string)
|
||||
select {
|
||||
case <-c:
|
||||
println("unexpected")
|
||||
default:
|
||||
println("nothing received")
|
||||
}
|
||||
println("bye")
|
||||
}
|
||||
|
||||
// Output:
|
||||
// nothing received
|
||||
// bye
|
||||
17
_test/select4.go
Normal file
17
_test/select4.go
Normal file
@@ -0,0 +1,17 @@
|
||||
package main
|
||||
|
||||
func main() {
|
||||
c1 := make(chan string)
|
||||
|
||||
go func() { c1 <- "done" }()
|
||||
|
||||
select {
|
||||
case msg1 := <-c1:
|
||||
println("received from c1:", msg1)
|
||||
}
|
||||
println("Bye")
|
||||
}
|
||||
|
||||
// Output:
|
||||
// received from c1: done
|
||||
// Bye
|
||||
22
_test/select5.go
Normal file
22
_test/select5.go
Normal file
@@ -0,0 +1,22 @@
|
||||
package main
|
||||
|
||||
type T struct {
|
||||
c1 chan string
|
||||
}
|
||||
|
||||
func main() {
|
||||
t := &T{}
|
||||
t.c1 = make(chan string)
|
||||
|
||||
go func(c chan string) { c <- "done" }(t.c1)
|
||||
|
||||
select {
|
||||
case msg1 := <-t.c1:
|
||||
println("received from c1:", msg1)
|
||||
}
|
||||
println("Bye")
|
||||
}
|
||||
|
||||
// Output:
|
||||
// received from c1: done
|
||||
// Bye
|
||||
22
_test/select6.go
Normal file
22
_test/select6.go
Normal file
@@ -0,0 +1,22 @@
|
||||
package main
|
||||
|
||||
type T struct {
|
||||
c1 chan string
|
||||
}
|
||||
|
||||
func main() {
|
||||
t := &T{}
|
||||
t.c1 = make(chan string)
|
||||
|
||||
go func(c chan string) { c <- "done" }(t.c1)
|
||||
|
||||
select {
|
||||
case <-t.c1:
|
||||
println("received from c1")
|
||||
}
|
||||
println("Bye")
|
||||
}
|
||||
|
||||
// Output:
|
||||
// received from c1
|
||||
// Bye
|
||||
24
_test/select7.go
Normal file
24
_test/select7.go
Normal file
@@ -0,0 +1,24 @@
|
||||
package main
|
||||
|
||||
type T struct {
|
||||
c1 chan string
|
||||
}
|
||||
|
||||
func main() {
|
||||
t := &T{}
|
||||
t.c1 = make(chan string)
|
||||
a := 0
|
||||
|
||||
go func() {
|
||||
select {
|
||||
case t.c1 <- "done":
|
||||
a++
|
||||
}
|
||||
}()
|
||||
|
||||
msg1 := <-t.c1
|
||||
println("received from c1:", msg1)
|
||||
}
|
||||
|
||||
// Output:
|
||||
// received from c1: done
|
||||
24
_test/select8.go
Normal file
24
_test/select8.go
Normal file
@@ -0,0 +1,24 @@
|
||||
package main
|
||||
|
||||
type T struct {
|
||||
c1 chan string
|
||||
c2 chan string
|
||||
}
|
||||
|
||||
func main() {
|
||||
t := &T{}
|
||||
t.c1 = make(chan string)
|
||||
|
||||
go func(c chan string) { c <- "done" }(t.c1)
|
||||
|
||||
select {
|
||||
case msg := <-t.c1:
|
||||
println("received from c1:", msg)
|
||||
case <-t.c2:
|
||||
}
|
||||
println("Bye")
|
||||
}
|
||||
|
||||
// Output:
|
||||
// received from c1: done
|
||||
// Bye
|
||||
22
_test/select9.go
Normal file
22
_test/select9.go
Normal file
@@ -0,0 +1,22 @@
|
||||
package main
|
||||
|
||||
type T struct {
|
||||
c1 chan string
|
||||
}
|
||||
|
||||
func main() {
|
||||
t := &T{}
|
||||
t.c1 = make(chan string)
|
||||
|
||||
go func() {
|
||||
select {
|
||||
case t.c1 <- "done":
|
||||
}
|
||||
}()
|
||||
|
||||
msg1 := <-t.c1
|
||||
println("received from c1:", msg1)
|
||||
}
|
||||
|
||||
// Output:
|
||||
// received from c1: done
|
||||
@@ -15,3 +15,6 @@ func main() {
|
||||
_, err := c.Get("url")
|
||||
println(strings.Contains(err.Error(), "unsupported protocol scheme"))
|
||||
}
|
||||
|
||||
// Output:
|
||||
// true
|
||||
|
||||
22
_test/struct39.go
Normal file
22
_test/struct39.go
Normal file
@@ -0,0 +1,22 @@
|
||||
package main
|
||||
|
||||
type T struct {
|
||||
t *T1
|
||||
y *xxx
|
||||
}
|
||||
|
||||
type T1 struct {
|
||||
T
|
||||
}
|
||||
|
||||
var x = &T1{}
|
||||
var t = &T{}
|
||||
|
||||
type xxx struct{}
|
||||
|
||||
func main() {
|
||||
println("ok")
|
||||
}
|
||||
|
||||
// Output:
|
||||
// ok
|
||||
23
_test/struct40.go
Normal file
23
_test/struct40.go
Normal file
@@ -0,0 +1,23 @@
|
||||
package main
|
||||
|
||||
type T struct {
|
||||
t *T1
|
||||
y *xxx
|
||||
}
|
||||
|
||||
type T1 struct {
|
||||
T
|
||||
}
|
||||
|
||||
func f(t *T) { println("in f") }
|
||||
|
||||
var x = &T1{}
|
||||
|
||||
type xxx struct{}
|
||||
|
||||
func main() {
|
||||
println("ok")
|
||||
}
|
||||
|
||||
// Output:
|
||||
// ok
|
||||
26
_test/struct41.go
Normal file
26
_test/struct41.go
Normal file
@@ -0,0 +1,26 @@
|
||||
package main
|
||||
|
||||
type Ti func(*T)
|
||||
|
||||
type T1 struct {
|
||||
t Ti
|
||||
}
|
||||
|
||||
type T struct {
|
||||
t Ti
|
||||
y *xxx
|
||||
}
|
||||
|
||||
func f(t *T) { println("in f") }
|
||||
|
||||
type xxx struct{}
|
||||
|
||||
var x = &T1{t: f}
|
||||
|
||||
func main() {
|
||||
x.t = f
|
||||
println("ok")
|
||||
}
|
||||
|
||||
// Output:
|
||||
// ok
|
||||
19
_test/struct42.go
Normal file
19
_test/struct42.go
Normal file
@@ -0,0 +1,19 @@
|
||||
package main
|
||||
|
||||
type T struct {
|
||||
t func(*T)
|
||||
y *xxx
|
||||
}
|
||||
|
||||
func f(t *T) { println("in f") }
|
||||
|
||||
var x = &T{t: f}
|
||||
|
||||
type xxx struct{}
|
||||
|
||||
func main() {
|
||||
println("ok")
|
||||
}
|
||||
|
||||
// Output:
|
||||
// ok
|
||||
19
_test/struct43.go
Normal file
19
_test/struct43.go
Normal file
@@ -0,0 +1,19 @@
|
||||
package main
|
||||
|
||||
type T struct {
|
||||
t func(*T)
|
||||
y *xxx
|
||||
}
|
||||
|
||||
func f(t *T) { println("in f") }
|
||||
|
||||
type xxx struct{}
|
||||
|
||||
func main() {
|
||||
x := &T{}
|
||||
x.t = f
|
||||
println("ok")
|
||||
}
|
||||
|
||||
// Output:
|
||||
// ok
|
||||
27
_test/struct44.go
Normal file
27
_test/struct44.go
Normal file
@@ -0,0 +1,27 @@
|
||||
package main
|
||||
|
||||
type Ti func(*T) X
|
||||
|
||||
type T1 struct {
|
||||
t Ti
|
||||
}
|
||||
|
||||
type T struct {
|
||||
t Ti
|
||||
y *xxx
|
||||
}
|
||||
|
||||
func f(t *T) X { println("in f"); return X{} }
|
||||
|
||||
type X struct{ Name string }
|
||||
|
||||
type xxx struct{}
|
||||
|
||||
var x = &T1{t: f}
|
||||
|
||||
func main() {
|
||||
println("ok")
|
||||
}
|
||||
|
||||
// Output:
|
||||
// ok
|
||||
18
_test/struct45.go
Normal file
18
_test/struct45.go
Normal file
@@ -0,0 +1,18 @@
|
||||
package main
|
||||
|
||||
type T struct {
|
||||
b bool
|
||||
}
|
||||
|
||||
type T1 struct {
|
||||
T
|
||||
}
|
||||
|
||||
func main() {
|
||||
t := &T1{}
|
||||
t.b = true
|
||||
println(t.b)
|
||||
}
|
||||
|
||||
// Output:
|
||||
// true
|
||||
13
_test/switch34.go
Normal file
13
_test/switch34.go
Normal file
@@ -0,0 +1,13 @@
|
||||
package main
|
||||
|
||||
func main() {
|
||||
var a interface{}
|
||||
switch a.(type) {
|
||||
case []int:
|
||||
case []string:
|
||||
}
|
||||
println("bye")
|
||||
}
|
||||
|
||||
// Output:
|
||||
// bye
|
||||
15
_test/time12.go
Normal file
15
_test/time12.go
Normal file
@@ -0,0 +1,15 @@
|
||||
package main
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"time"
|
||||
)
|
||||
|
||||
var twentyFourHours = time.Duration(24 * time.Hour)
|
||||
|
||||
func main() {
|
||||
fmt.Println(twentyFourHours.Hours())
|
||||
}
|
||||
|
||||
// Output:
|
||||
// 24
|
||||
18
_test/type20.go
Normal file
18
_test/type20.go
Normal file
@@ -0,0 +1,18 @@
|
||||
package main
|
||||
|
||||
import (
|
||||
"io"
|
||||
"strings"
|
||||
)
|
||||
|
||||
func isCloser(r io.Reader) bool {
|
||||
_, ok := r.(io.Closer)
|
||||
return ok
|
||||
}
|
||||
|
||||
func main() {
|
||||
println(isCloser(strings.NewReader("test")))
|
||||
}
|
||||
|
||||
// Output:
|
||||
// false
|
||||
16
_test/type21.go
Normal file
16
_test/type21.go
Normal file
@@ -0,0 +1,16 @@
|
||||
package main
|
||||
|
||||
import (
|
||||
"reflect"
|
||||
"time"
|
||||
)
|
||||
|
||||
func main() {
|
||||
t := time.Date(2009, time.November, 10, 23, 4, 5, 0, time.UTC)
|
||||
v := reflect.ValueOf(t.String)
|
||||
f := v.Interface().(func() string)
|
||||
println(f())
|
||||
}
|
||||
|
||||
// Output:
|
||||
// 2009-11-10 23:04:05 +0000 UTC
|
||||
18
_test/type22.go
Normal file
18
_test/type22.go
Normal file
@@ -0,0 +1,18 @@
|
||||
package main
|
||||
|
||||
type T1 T
|
||||
|
||||
func foo() T1 {
|
||||
return T1(T{"foo"})
|
||||
}
|
||||
|
||||
type T struct {
|
||||
Name string
|
||||
}
|
||||
|
||||
func main() {
|
||||
println(foo().Name)
|
||||
}
|
||||
|
||||
// Output:
|
||||
// foo
|
||||
20
_test/variadic6.go
Normal file
20
_test/variadic6.go
Normal file
@@ -0,0 +1,20 @@
|
||||
package main
|
||||
|
||||
import "fmt"
|
||||
|
||||
type A struct {
|
||||
}
|
||||
|
||||
func (a A) f(vals ...bool) {
|
||||
for _, v := range vals {
|
||||
fmt.Println(v)
|
||||
}
|
||||
}
|
||||
func main() {
|
||||
bools := []bool{true}
|
||||
a := A{}
|
||||
a.f(bools...)
|
||||
}
|
||||
|
||||
// Output:
|
||||
// true
|
||||
@@ -1,22 +1,66 @@
|
||||
/*
|
||||
Yaegi interprets Go programs.
|
||||
|
||||
Yaegi reads Go language programs from its standard input or from a file
|
||||
and evaluates them.
|
||||
Yaegi reads Go language programs from standard input, string
|
||||
parameters or files and run them.
|
||||
|
||||
If invoked with no arguments, it processes the standard input
|
||||
in a Read-Eval-Print-Loop. A prompt is displayed if standard input
|
||||
is a terminal.
|
||||
If invoked with no arguments, it processes the standard input in
|
||||
a Read-Eval-Print-Loop. A prompt is displayed if standard input is
|
||||
a terminal.
|
||||
|
||||
Given a file, it operates on that file. If the first line starts with
|
||||
"#!/usr/bin/env yaegi", and the file has exec permission, then the file
|
||||
can be invoked directly from the shell.
|
||||
File Mode
|
||||
|
||||
In file mode, as in standard Go, files are read entirely, then parsed,
|
||||
then evaluated. In REPL mode, each line is parsed and evaluated separately,
|
||||
at global level in an implicit main package.
|
||||
In file mode, as in a standard Go compiler, source files are read entirely
|
||||
before being parsed, then evaluated. It allows to handle forward
|
||||
declarations and to have package code split in multiple source files.
|
||||
|
||||
Go specifications fully apply in this mode.
|
||||
|
||||
All files are interpreted in file mode except the initial file if it
|
||||
starts with "#!" characters (the shebang pattern to allow executable
|
||||
scripts), for example "#!/usr/bin/env yaegi". In that case, the initial
|
||||
file is interpreted in REPL mode.
|
||||
|
||||
REPL mode
|
||||
|
||||
In REPL mode, the interpreter parses the code incrementally. As soon
|
||||
as a statement is complete, it evaluates it. This makes the interpreter
|
||||
suitable for interactive command line and scripts.
|
||||
|
||||
Go specifications apply with the following differences:
|
||||
|
||||
All local and global declarations (const, var, type, func) are allowed,
|
||||
including in short form, except that all identifiers must be defined
|
||||
before use (as declarations inside a standard Go function).
|
||||
|
||||
The statements are evaluated in the global space, within an implicit
|
||||
"main" package.
|
||||
|
||||
It is not necessary to have a package statement, or a main function in
|
||||
REPL mode. Import statements for preloaded binary packages can also
|
||||
be avoided (i.e. all the standard library except the few packages
|
||||
where default names collide, as "math/rand" and "crypto/rand", for which
|
||||
an explicit import is still necessary).
|
||||
|
||||
Note that the source packages are always interpreted in file mode,
|
||||
even if imported from REPL.
|
||||
|
||||
The following extract is a valid executable script:
|
||||
|
||||
#!/usr/bin/env yaegi
|
||||
helloHandler := func(w http.ResponseWriter, req *http.Request) {
|
||||
io.WriteString(w, "Hello, world!\n")
|
||||
}
|
||||
http.HandleFunc("/hello", helloHandler)
|
||||
log.Fatal(http.ListenAndServe(":8080", nil))
|
||||
|
||||
Example of a one liner:
|
||||
|
||||
$ yaegi -e 'println(reflect.TypeOf(fmt.Print))'
|
||||
|
||||
Options:
|
||||
-e string
|
||||
evaluate the string and return.
|
||||
-i
|
||||
start an interactive REPL after file execution.
|
||||
-tags tag,list
|
||||
@@ -86,15 +130,18 @@ func main() {
|
||||
|
||||
s := string(b)
|
||||
if s[:2] == "#!" {
|
||||
// Allow executable go scripts, but fix them prior to parse
|
||||
// Allow executable go scripts, Have the same behavior as in interactive mode.
|
||||
s = strings.Replace(s, "#!", "//", 1)
|
||||
}
|
||||
|
||||
i.Name = args[0]
|
||||
if _, err := i.Eval(s); err != nil {
|
||||
fmt.Println(err)
|
||||
if p, ok := err.(interp.Panic); ok {
|
||||
fmt.Println(string(p.Stack))
|
||||
i.REPL(strings.NewReader(s), os.Stdout)
|
||||
} else {
|
||||
// Files not starting with "#!" are supposed to be pure Go, directly Evaled.
|
||||
i.Name = args[0]
|
||||
_, err := i.Eval(s)
|
||||
if err != nil {
|
||||
fmt.Println(err)
|
||||
if p, ok := err.(interp.Panic); ok {
|
||||
fmt.Println(string(p.Stack))
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -84,7 +84,7 @@ func TestYaegiCmdCancel(t *testing.T) {
|
||||
continue
|
||||
}
|
||||
|
||||
if outBuf.String() != "context canceled\n2\n" {
|
||||
if outBuf.String() != "context canceled\n" {
|
||||
t.Errorf("unexpected output: %q", &outBuf)
|
||||
}
|
||||
}
|
||||
|
||||
@@ -17,9 +17,9 @@ import "reflect"
|
||||
// Arithmetic operators
|
||||
{{range $name, $op := .Arithmetic}}
|
||||
func {{$name}}(n *node) {
|
||||
dest := genValue(n)
|
||||
next := getExec(n.tnext)
|
||||
typ := n.typ.TypeOf()
|
||||
typ := n.typ.concrete().TypeOf()
|
||||
dest := genValueOutput(n, typ)
|
||||
c0, c1 := n.child[0], n.child[1]
|
||||
|
||||
switch typ.Kind() {
|
||||
@@ -379,7 +379,7 @@ func {{$name}}Const(n *node) {
|
||||
{{range $name, $op := .Comparison}}
|
||||
func {{$name}}(n *node) {
|
||||
tnext := getExec(n.tnext)
|
||||
dest := genValue(n)
|
||||
dest := genValueOutput(n, reflect.TypeOf(true))
|
||||
c0, c1 := n.child[0], n.child[1]
|
||||
|
||||
switch t0, t1 := c0.typ.TypeOf(), c1.typ.TypeOf(); {
|
||||
|
||||
@@ -6,7 +6,6 @@ import (
|
||||
"go/parser"
|
||||
"go/scanner"
|
||||
"go/token"
|
||||
"math"
|
||||
"reflect"
|
||||
"strconv"
|
||||
"sync/atomic"
|
||||
@@ -196,15 +195,18 @@ const (
|
||||
aAndNot
|
||||
aAndNotAssign
|
||||
aBitNot
|
||||
aBranch
|
||||
aCall
|
||||
aCase
|
||||
aCompositeLit
|
||||
aConvert
|
||||
aDec
|
||||
aEqual
|
||||
aGreater
|
||||
aGreaterEqual
|
||||
aGetFunc
|
||||
aGetIndex
|
||||
aGetSym
|
||||
aInc
|
||||
aLand
|
||||
aLor
|
||||
@@ -253,14 +255,17 @@ var actions = [...]string{
|
||||
aAndNot: "&^",
|
||||
aAndNotAssign: "&^=",
|
||||
aBitNot: "^",
|
||||
aBranch: "branch",
|
||||
aCall: "call",
|
||||
aCase: "case",
|
||||
aCompositeLit: "compositeLit",
|
||||
aConvert: "convert",
|
||||
aDec: "--",
|
||||
aEqual: "==",
|
||||
aGreater: ">",
|
||||
aGetFunc: "getFunc",
|
||||
aGetIndex: "getIndex",
|
||||
aGetSym: ".",
|
||||
aInc: "++",
|
||||
aLand: "&&",
|
||||
aLor: "||",
|
||||
@@ -464,11 +469,7 @@ func (interp *Interpreter) ast(src, name string) (string, *node, error) {
|
||||
n.rval = reflect.ValueOf(v)
|
||||
case token.FLOAT:
|
||||
v, _ := strconv.ParseFloat(a.Value, 64)
|
||||
if math.Trunc(v) == v {
|
||||
n.rval = reflect.ValueOf(int(v))
|
||||
} else {
|
||||
n.rval = reflect.ValueOf(v)
|
||||
}
|
||||
n.rval = reflect.ValueOf(v)
|
||||
case token.IMAG:
|
||||
v, _ := strconv.ParseFloat(a.Value[:len(a.Value)-1], 64)
|
||||
n.rval = reflect.ValueOf(complex(0, v))
|
||||
|
||||
287
interp/cfg.go
287
interp/cfg.go
@@ -50,7 +50,6 @@ var identifier = regexp.MustCompile(`([\pL_][\pL_\d]*)$`)
|
||||
func (interp *Interpreter) cfg(root *node, pkgID string) ([]*node, error) {
|
||||
sc := interp.initScopePkg(pkgID)
|
||||
var initNodes []*node
|
||||
var iotaValue int
|
||||
var err error
|
||||
|
||||
root.Walk(func(n *node) bool {
|
||||
@@ -204,15 +203,22 @@ func (interp *Interpreter) cfg(root *node, pkgID string) ([]*node, error) {
|
||||
|
||||
case commClause:
|
||||
sc = sc.pushBloc()
|
||||
if n.child[0].action == aAssign {
|
||||
if len(n.child) > 0 && n.child[0].action == aAssign {
|
||||
ch := n.child[0].child[1].child[0]
|
||||
if sym, _, ok := sc.lookup(ch.ident); ok {
|
||||
assigned := n.child[0].child[0]
|
||||
index := sc.add(sym.typ.val)
|
||||
sc.sym[assigned.ident] = &symbol{index: index, kind: varSym, typ: sym.typ.val}
|
||||
assigned.findex = index
|
||||
assigned.typ = sym.typ.val
|
||||
var typ *itype
|
||||
if typ, err = nodeType(interp, sc, ch); err != nil {
|
||||
return false
|
||||
}
|
||||
if !isChan(typ) {
|
||||
err = n.cfgErrorf("invalid operation: receive from non-chan type")
|
||||
return false
|
||||
}
|
||||
elem := chanElement(typ)
|
||||
assigned := n.child[0].child[0]
|
||||
index := sc.add(elem)
|
||||
sc.sym[assigned.ident] = &symbol{index: index, kind: varSym, typ: elem}
|
||||
assigned.findex = index
|
||||
assigned.typ = elem
|
||||
}
|
||||
|
||||
case compositeLitExpr:
|
||||
@@ -363,6 +369,18 @@ func (interp *Interpreter) cfg(root *node, pkgID string) ([]*node, error) {
|
||||
}
|
||||
return false
|
||||
|
||||
case constDecl:
|
||||
// Early parse of constDecl subtrees, to compute all constant
|
||||
// values which may be used in further declarations.
|
||||
if !sc.global {
|
||||
for _, c := range n.child {
|
||||
if _, err = interp.cfg(c, pkgID); err != nil {
|
||||
// No error processing here, to allow recovery in subtree nodes.
|
||||
err = nil
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
case arrayType, basicLit, chanType, funcType, mapType, structType:
|
||||
n.typ, err = nodeType(interp, sc, n)
|
||||
return false
|
||||
@@ -518,7 +536,11 @@ func (interp *Interpreter) cfg(root *node, pkgID string) ([]*node, error) {
|
||||
}
|
||||
if n.anc.kind == constDecl {
|
||||
sc.sym[dest.ident].kind = constSym
|
||||
iotaValue++
|
||||
if childPos(n) == len(n.anc.child)-1 {
|
||||
sc.iota = 0
|
||||
} else {
|
||||
sc.iota++
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -535,22 +557,28 @@ func (interp *Interpreter) cfg(root *node, pkgID string) ([]*node, error) {
|
||||
case assignXStmt:
|
||||
wireChild(n)
|
||||
l := len(n.child) - 1
|
||||
switch n.child[l].kind {
|
||||
switch lc := n.child[l]; lc.kind {
|
||||
case callExpr:
|
||||
if n.child[l-1].isType(sc) {
|
||||
l--
|
||||
}
|
||||
if r := lc.child[0].typ.numOut(); r != l {
|
||||
err = n.cfgErrorf("assignment mismatch: %d variables but %s returns %d values", l, lc.child[0].name(), r)
|
||||
}
|
||||
n.gen = nop
|
||||
case indexExpr:
|
||||
n.child[l].gen = getIndexMap2
|
||||
lc.gen = getIndexMap2
|
||||
n.gen = nop
|
||||
case typeAssertExpr:
|
||||
if n.child[0].ident == "_" {
|
||||
n.child[l].gen = typeAssertStatus
|
||||
lc.gen = typeAssertStatus
|
||||
} else {
|
||||
n.child[l].gen = typeAssert2
|
||||
lc.gen = typeAssert2
|
||||
}
|
||||
n.gen = nop
|
||||
case unaryExpr:
|
||||
if n.child[l].action == aRecv {
|
||||
n.child[l].gen = recv2
|
||||
if lc.action == aRecv {
|
||||
lc.gen = recv2
|
||||
n.gen = nop
|
||||
}
|
||||
}
|
||||
@@ -558,7 +586,7 @@ func (interp *Interpreter) cfg(root *node, pkgID string) ([]*node, error) {
|
||||
case defineXStmt:
|
||||
wireChild(n)
|
||||
if sc.def == nil {
|
||||
// in global scope, type definition already handled by GTA
|
||||
// In global scope, type definition already handled by GTA.
|
||||
break
|
||||
}
|
||||
err = compDefineX(sc, n)
|
||||
@@ -568,8 +596,8 @@ func (interp *Interpreter) cfg(root *node, pkgID string) ([]*node, error) {
|
||||
nilSym := interp.universe.sym["nil"]
|
||||
c0, c1 := n.child[0], n.child[1]
|
||||
t0, t1 := c0.typ.TypeOf(), c1.typ.TypeOf()
|
||||
// Shift operator type is inherited from first parameter only
|
||||
// All other binary operators require both parameter types to be the same
|
||||
// Shift operator type is inherited from first parameter only.
|
||||
// All other binary operators require both parameter types to be the same.
|
||||
if !isShiftNode(n) && !c0.typ.untyped && !c1.typ.untyped && !c0.typ.equals(c1.typ) {
|
||||
err = n.cfgErrorf("mismatched types %s and %s", c0.typ.id(), c1.typ.id())
|
||||
break
|
||||
@@ -583,10 +611,15 @@ func (interp *Interpreter) cfg(root *node, pkgID string) ([]*node, error) {
|
||||
if !(isNumber(t0) && isNumber(t1)) {
|
||||
err = n.cfgErrorf("illegal operand types for '%v' operator", n.action)
|
||||
}
|
||||
case aRem, aAnd, aOr, aXor, aAndNot:
|
||||
case aAnd, aOr, aXor, aAndNot:
|
||||
if !(isInt(t0) && isInt(t1)) {
|
||||
err = n.cfgErrorf("illegal operand types for '%v' operator", n.action)
|
||||
}
|
||||
case aRem:
|
||||
if !(c0.isInteger() && c1.isInteger()) {
|
||||
err = n.cfgErrorf("illegal operand types for '%v' operator", n.action)
|
||||
}
|
||||
n.typ = c0.typ
|
||||
case aShl, aShr:
|
||||
if !(c0.isInteger() && c1.isNatural()) {
|
||||
err = n.cfgErrorf("illegal operand types for '%v' operator", n.action)
|
||||
@@ -613,33 +646,35 @@ func (interp *Interpreter) cfg(root *node, pkgID string) ([]*node, error) {
|
||||
if err != nil {
|
||||
break
|
||||
}
|
||||
if c0.rval.IsValid() && c1.rval.IsValid() && constOp[n.action] != nil {
|
||||
if n.typ == nil {
|
||||
if n.typ, err = nodeType(interp, sc, n); err != nil {
|
||||
return
|
||||
}
|
||||
if n.typ == nil {
|
||||
if n.typ, err = nodeType(interp, sc, n); err != nil {
|
||||
break
|
||||
}
|
||||
n.typ.TypeOf() // init reflect type
|
||||
constOp[n.action](n)
|
||||
}
|
||||
if c0.rval.IsValid() && c1.rval.IsValid() && !isInterface(n.typ) && constOp[n.action] != nil {
|
||||
n.typ.TypeOf() // Force compute of reflection type.
|
||||
constOp[n.action](n) // Compute a constant result now rather than during exec.
|
||||
}
|
||||
switch {
|
||||
case n.rval.IsValid():
|
||||
// This operation involved constants, and the result is already computed
|
||||
// by constOp and available in n.rval. Nothing else to do at execution.
|
||||
n.gen = nop
|
||||
n.findex = -1
|
||||
case n.anc.kind == assignStmt && n.anc.action == aAssign:
|
||||
// To avoid a copy in frame, if the result is to be assigned, store it directly
|
||||
// at the frame location of destination.
|
||||
dest := n.anc.child[childPos(n)-n.anc.nright]
|
||||
n.typ = dest.typ
|
||||
n.findex = dest.findex
|
||||
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.
|
||||
pos := childPos(n)
|
||||
n.typ = sc.def.typ.ret[pos]
|
||||
n.findex = pos
|
||||
default:
|
||||
if n.typ == nil {
|
||||
if n.typ, err = nodeType(interp, sc, n); err != nil {
|
||||
return
|
||||
}
|
||||
}
|
||||
// Allocate a new location in frame, and store the result here.
|
||||
n.findex = sc.add(n.typ)
|
||||
}
|
||||
|
||||
@@ -647,7 +682,7 @@ func (interp *Interpreter) cfg(root *node, pkgID string) ([]*node, error) {
|
||||
wireChild(n)
|
||||
t := n.child[0].typ
|
||||
switch t.cat {
|
||||
case ptrT:
|
||||
case aliasT, ptrT:
|
||||
n.typ = t.val
|
||||
if t.val.cat == valueT {
|
||||
n.typ = &itype{cat: valueT, rtype: t.val.rtype.Elem()}
|
||||
@@ -695,11 +730,7 @@ func (interp *Interpreter) cfg(root *node, pkgID string) ([]*node, error) {
|
||||
}
|
||||
sc = sc.pop()
|
||||
|
||||
case constDecl:
|
||||
iotaValue = 0
|
||||
wireChild(n)
|
||||
|
||||
case varDecl:
|
||||
case constDecl, varDecl:
|
||||
wireChild(n)
|
||||
|
||||
case declStmt, exprStmt, sendStmt:
|
||||
@@ -742,14 +773,18 @@ func (interp *Interpreter) cfg(root *node, pkgID string) ([]*node, error) {
|
||||
if n.typ, err = nodeType(interp, sc, n); err != nil {
|
||||
return
|
||||
}
|
||||
if n.typ.cat == builtinT {
|
||||
switch {
|
||||
case n.typ.cat == builtinT:
|
||||
n.findex = -1
|
||||
n.val = nil
|
||||
} else {
|
||||
case n.anc.kind == returnStmt:
|
||||
// Store result directly to frame output location, to avoid a frame copy.
|
||||
n.findex = 0
|
||||
default:
|
||||
n.findex = sc.add(n.typ)
|
||||
}
|
||||
if op, ok := constBltn[n.child[0].ident]; ok && n.anc.action != aAssign {
|
||||
op(n) // pre-compute non-assigned constant builtin calls
|
||||
op(n) // pre-compute non-assigned constant :
|
||||
}
|
||||
|
||||
case n.child[0].isType(sc):
|
||||
@@ -757,6 +792,7 @@ func (interp *Interpreter) cfg(root *node, pkgID string) ([]*node, error) {
|
||||
if isInt(n.child[0].typ.TypeOf()) && n.child[1].kind == basicLit && isFloat(n.child[1].typ.TypeOf()) {
|
||||
err = n.cfgErrorf("truncated to integer")
|
||||
}
|
||||
n.action = aConvert
|
||||
if isInterface(n.child[0].typ) && !n.child[1].isNil() {
|
||||
// Convert to interface: just check that all required methods are defined by concrete type.
|
||||
c0, c1 := n.child[0], n.child[1]
|
||||
@@ -787,22 +823,30 @@ func (interp *Interpreter) cfg(root *node, pkgID string) ([]*node, error) {
|
||||
}
|
||||
} else {
|
||||
n.typ = &itype{cat: valueT, rtype: typ.Out(0)}
|
||||
n.findex = sc.add(n.typ)
|
||||
for i := 1; i < typ.NumOut(); i++ {
|
||||
sc.add(&itype{cat: valueT, rtype: typ.Out(i)})
|
||||
if n.anc.kind == returnStmt {
|
||||
n.findex = childPos(n)
|
||||
} else {
|
||||
n.findex = sc.add(n.typ)
|
||||
for i := 1; i < typ.NumOut(); i++ {
|
||||
sc.add(&itype{cat: valueT, rtype: typ.Out(i)})
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
default:
|
||||
if n.child[0].action == aGetFunc {
|
||||
// allocate frame entry for anonymous function
|
||||
// Allocate a frame entry to store the anonymous function definition.
|
||||
sc.add(n.child[0].typ)
|
||||
}
|
||||
if typ := n.child[0].typ; len(typ.ret) > 0 {
|
||||
n.typ = typ.ret[0]
|
||||
n.findex = sc.add(n.typ)
|
||||
for _, t := range typ.ret[1:] {
|
||||
sc.add(t)
|
||||
if n.anc.kind == returnStmt {
|
||||
n.findex = childPos(n)
|
||||
} else {
|
||||
n.findex = sc.add(n.typ)
|
||||
for _, t := range typ.ret[1:] {
|
||||
sc.add(t)
|
||||
}
|
||||
}
|
||||
} else {
|
||||
n.findex = -1
|
||||
@@ -815,7 +859,7 @@ func (interp *Interpreter) cfg(root *node, pkgID string) ([]*node, error) {
|
||||
case typeSwichAssign(n) && len(n.child) > 1:
|
||||
n.start = n.child[1].start
|
||||
case len(n.child) == 0:
|
||||
// empty case body: jump to switch node (exit node)
|
||||
// Empty case body: jump to switch node (exit node).
|
||||
n.start = n.anc.anc.anc
|
||||
default:
|
||||
n.start = n.child[0].start
|
||||
@@ -826,12 +870,16 @@ func (interp *Interpreter) cfg(root *node, pkgID string) ([]*node, error) {
|
||||
|
||||
case commClause:
|
||||
wireChild(n)
|
||||
if len(n.child) > 1 {
|
||||
n.start = n.child[1].start // Skip chan operation, performed by select
|
||||
} else {
|
||||
switch len(n.child) {
|
||||
case 0:
|
||||
sc.pop()
|
||||
return
|
||||
case 1:
|
||||
n.start = n.child[0].start // default clause
|
||||
default:
|
||||
n.start = n.child[1].start // Skip chan operation, performed by select
|
||||
}
|
||||
n.lastChild().tnext = n.anc.anc // exit node is SelectStmt
|
||||
n.lastChild().tnext = n.anc.anc // exit node is selectStmt
|
||||
sc = sc.pop()
|
||||
|
||||
case compositeLitExpr:
|
||||
@@ -874,7 +922,7 @@ func (interp *Interpreter) cfg(root *node, pkgID string) ([]*node, error) {
|
||||
cond.tnext = body.start
|
||||
body.tnext = cond.start
|
||||
}
|
||||
cond.fnext = n
|
||||
setFNext(cond, n)
|
||||
sc = sc.pop()
|
||||
|
||||
case forStmt2: // for init; cond; {}
|
||||
@@ -896,7 +944,7 @@ func (interp *Interpreter) cfg(root *node, pkgID string) ([]*node, error) {
|
||||
body.tnext = cond.start
|
||||
}
|
||||
cond.tnext = body.start
|
||||
cond.fnext = n
|
||||
setFNext(cond, n)
|
||||
sc = sc.pop()
|
||||
|
||||
case forStmt3: // for ; cond; post {}
|
||||
@@ -915,7 +963,7 @@ func (interp *Interpreter) cfg(root *node, pkgID string) ([]*node, error) {
|
||||
post.tnext = cond.start
|
||||
}
|
||||
cond.tnext = body.start
|
||||
cond.fnext = n
|
||||
setFNext(cond, n)
|
||||
body.tnext = post.start
|
||||
sc = sc.pop()
|
||||
|
||||
@@ -946,13 +994,13 @@ func (interp *Interpreter) cfg(root *node, pkgID string) ([]*node, error) {
|
||||
post.tnext = cond.start
|
||||
}
|
||||
cond.tnext = body.start
|
||||
cond.fnext = n
|
||||
setFNext(cond, n)
|
||||
body.tnext = post.start
|
||||
sc = sc.pop()
|
||||
|
||||
case forRangeStmt:
|
||||
n.start = n.child[0].start
|
||||
n.child[0].fnext = n
|
||||
setFNext(n.child[0], n)
|
||||
sc = sc.pop()
|
||||
|
||||
case funcDecl:
|
||||
@@ -991,7 +1039,7 @@ func (interp *Interpreter) cfg(root *node, pkgID string) ([]*node, error) {
|
||||
n.rval = sym.rval
|
||||
n.kind = basicLit
|
||||
case n.ident == "iota":
|
||||
n.rval = reflect.ValueOf(iotaValue)
|
||||
n.rval = reflect.ValueOf(sc.iota)
|
||||
n.kind = basicLit
|
||||
case n.ident == "nil":
|
||||
n.kind = basicLit
|
||||
@@ -1003,9 +1051,6 @@ func (interp *Interpreter) cfg(root *node, pkgID string) ([]*node, error) {
|
||||
err = n.cfgErrorf("use of builtin %s not in function call", n.ident)
|
||||
}
|
||||
}
|
||||
if sym.kind == varSym && sym.typ != nil && sym.typ.TypeOf().Kind() == reflect.Bool {
|
||||
fixBranch(n)
|
||||
}
|
||||
}
|
||||
if n.sym != nil {
|
||||
n.recv = n.sym.recv
|
||||
@@ -1028,7 +1073,7 @@ func (interp *Interpreter) cfg(root *node, pkgID string) ([]*node, error) {
|
||||
n.start = cond.start
|
||||
cond.tnext = tbody.start
|
||||
}
|
||||
cond.fnext = n
|
||||
setFNext(cond, n)
|
||||
tbody.tnext = n
|
||||
sc = sc.pop()
|
||||
|
||||
@@ -1047,7 +1092,7 @@ func (interp *Interpreter) cfg(root *node, pkgID string) ([]*node, error) {
|
||||
} else {
|
||||
n.start = cond.start
|
||||
cond.tnext = tbody.start
|
||||
cond.fnext = fbody.start
|
||||
setFNext(cond, fbody.start)
|
||||
}
|
||||
tbody.tnext = n
|
||||
fbody.tnext = n
|
||||
@@ -1071,7 +1116,7 @@ func (interp *Interpreter) cfg(root *node, pkgID string) ([]*node, error) {
|
||||
cond.tnext = tbody.start
|
||||
}
|
||||
tbody.tnext = n
|
||||
cond.fnext = n
|
||||
setFNext(cond, n)
|
||||
sc = sc.pop()
|
||||
|
||||
case ifStmt3: // if init; cond {} else {}
|
||||
@@ -1090,7 +1135,7 @@ func (interp *Interpreter) cfg(root *node, pkgID string) ([]*node, error) {
|
||||
} else {
|
||||
init.tnext = cond.start
|
||||
cond.tnext = tbody.start
|
||||
cond.fnext = fbody.start
|
||||
setFNext(cond, fbody.start)
|
||||
}
|
||||
tbody.tnext = n
|
||||
fbody.tnext = n
|
||||
@@ -1102,7 +1147,7 @@ func (interp *Interpreter) cfg(root *node, pkgID string) ([]*node, error) {
|
||||
case landExpr:
|
||||
n.start = n.child[0].start
|
||||
n.child[0].tnext = n.child[1].start
|
||||
n.child[0].fnext = n
|
||||
setFNext(n.child[0], n)
|
||||
n.child[1].tnext = n
|
||||
n.typ = n.child[0].typ
|
||||
n.findex = sc.add(n.typ)
|
||||
@@ -1113,7 +1158,7 @@ func (interp *Interpreter) cfg(root *node, pkgID string) ([]*node, error) {
|
||||
case lorExpr:
|
||||
n.start = n.child[0].start
|
||||
n.child[0].tnext = n
|
||||
n.child[0].fnext = n.child[1].start
|
||||
setFNext(n.child[0], n.child[1].start)
|
||||
n.child[1].tnext = n
|
||||
n.typ = n.child[0].typ
|
||||
n.findex = sc.add(n.typ)
|
||||
@@ -1247,6 +1292,7 @@ func (interp *Interpreter) cfg(root *node, pkgID string) ([]*node, error) {
|
||||
n.typ = &itype{cat: valueT, rtype: s.Type(), untyped: isValueUntyped(s)}
|
||||
n.rval = s
|
||||
}
|
||||
n.action = aGetSym
|
||||
n.gen = nop
|
||||
} else {
|
||||
err = n.cfgErrorf("package %s \"%s\" has no symbol %s", n.child[0].ident, pkg, name)
|
||||
@@ -1258,6 +1304,7 @@ func (interp *Interpreter) cfg(root *node, pkgID string) ([]*node, error) {
|
||||
n.findex = sym.index
|
||||
n.val = sym.node
|
||||
n.gen = nop
|
||||
n.action = aGetSym
|
||||
n.typ = sym.typ
|
||||
n.sym = sym
|
||||
n.rval = sym.rval
|
||||
@@ -1329,9 +1376,41 @@ func (interp *Interpreter) cfg(root *node, pkgID string) ([]*node, error) {
|
||||
|
||||
case selectStmt:
|
||||
wireChild(n)
|
||||
// Move action to block statement, so select node can be an exit point
|
||||
// Move action to block statement, so select node can be an exit point.
|
||||
n.child[0].gen = _select
|
||||
n.start = n.child[0]
|
||||
// Chain channel init actions in commClauses prior to invoke select.
|
||||
var cur *node
|
||||
for _, c := range n.child[0].child {
|
||||
var an *node // channel init action node
|
||||
if len(c.child) > 0 {
|
||||
switch c0 := c.child[0]; {
|
||||
case c0.kind == exprStmt && len(c0.child) == 1 && c0.child[0].action == aRecv:
|
||||
an = c0.child[0].child[0]
|
||||
case c0.action == aAssign:
|
||||
an = c0.lastChild().child[0]
|
||||
case c0.kind == sendStmt:
|
||||
an = c0.child[0]
|
||||
}
|
||||
}
|
||||
if an != nil {
|
||||
if cur == nil {
|
||||
// First channel init action, the entry point for the select block.
|
||||
n.start = an.start
|
||||
} else {
|
||||
// Chain channel init action to the previous one.
|
||||
cur.tnext = an.start
|
||||
}
|
||||
}
|
||||
cur = an
|
||||
}
|
||||
// Invoke select action
|
||||
if cur == nil {
|
||||
// There is no channel init action, call select directly.
|
||||
n.start = n.child[0]
|
||||
} else {
|
||||
// Select is called after the last channel init action.
|
||||
cur.tnext = n.child[0]
|
||||
}
|
||||
|
||||
case starExpr:
|
||||
switch {
|
||||
@@ -1385,7 +1464,8 @@ func (interp *Interpreter) cfg(root *node, pkgID string) ([]*node, error) {
|
||||
}
|
||||
// Chain case clauses.
|
||||
for i, c := range clauses[:l-1] {
|
||||
c.fnext = clauses[i+1] // Chain to next clause.
|
||||
// Chain to next clause.
|
||||
setFNext(c, clauses[i+1])
|
||||
if len(c.child) == 0 {
|
||||
c.tnext = n // Clause body is empty, exit.
|
||||
} else {
|
||||
@@ -1406,6 +1486,7 @@ func (interp *Interpreter) cfg(root *node, pkgID string) ([]*node, error) {
|
||||
}
|
||||
}
|
||||
c := clauses[l-1] // Last clause.
|
||||
c.fnext = n
|
||||
if len(c.child) == 0 {
|
||||
c.tnext = n // Clause body is empty, exit.
|
||||
} else {
|
||||
@@ -1434,9 +1515,9 @@ func (interp *Interpreter) cfg(root *node, pkgID string) ([]*node, error) {
|
||||
cond := c.child[0]
|
||||
cond.tnext = body.start
|
||||
if i == l-1 {
|
||||
cond.fnext = n
|
||||
setFNext(cond, n)
|
||||
} else {
|
||||
cond.fnext = clauses[i+1].start
|
||||
setFNext(cond, clauses[i+1].start)
|
||||
}
|
||||
c.start = cond.start
|
||||
} else {
|
||||
@@ -1462,7 +1543,12 @@ func (interp *Interpreter) cfg(root *node, pkgID string) ([]*node, error) {
|
||||
}
|
||||
}
|
||||
if n.anc.action != aAssignX {
|
||||
n.typ = n.child[1].typ
|
||||
if n.child[0].typ.cat == valueT {
|
||||
// Avoid special wrapping of interfaces and func types.
|
||||
n.typ = &itype{cat: valueT, rtype: n.child[1].typ.TypeOf()}
|
||||
} else {
|
||||
n.typ = n.child[1].typ
|
||||
}
|
||||
n.findex = sc.add(n.typ)
|
||||
}
|
||||
} else {
|
||||
@@ -1503,13 +1589,13 @@ func (interp *Interpreter) cfg(root *node, pkgID string) ([]*node, error) {
|
||||
return
|
||||
}
|
||||
}
|
||||
// TODO: Optimisation: avoid allocation if boolean branch op (i.e. '!' in an 'if' expr)
|
||||
if n.child[0].rval.IsValid() && constOp[n.action] != nil {
|
||||
if n.typ == nil {
|
||||
if n.typ, err = nodeType(interp, sc, n); err != nil {
|
||||
return
|
||||
}
|
||||
if n.typ == nil {
|
||||
if n.typ, err = nodeType(interp, sc, n); err != nil {
|
||||
return
|
||||
}
|
||||
}
|
||||
// TODO: Optimisation: avoid allocation if boolean branch op (i.e. '!' in an 'if' expr)
|
||||
if n.child[0].rval.IsValid() && !isInterface(n.typ) && constOp[n.action] != nil {
|
||||
n.typ.TypeOf() // init reflect type
|
||||
constOp[n.action](n)
|
||||
}
|
||||
@@ -1526,11 +1612,6 @@ func (interp *Interpreter) cfg(root *node, pkgID string) ([]*node, error) {
|
||||
n.typ = sc.def.typ.ret[pos]
|
||||
n.findex = pos
|
||||
default:
|
||||
if n.typ == nil {
|
||||
if n.typ, err = nodeType(interp, sc, n); err != nil {
|
||||
return
|
||||
}
|
||||
}
|
||||
n.findex = sc.add(n.typ)
|
||||
}
|
||||
|
||||
@@ -1581,6 +1662,12 @@ func compDefineX(sc *scope, n *node) error {
|
||||
} else {
|
||||
types = funtype.ret
|
||||
}
|
||||
if n.child[l-1].isType(sc) {
|
||||
l--
|
||||
}
|
||||
if len(types) != l {
|
||||
return n.cfgErrorf("assignment mismatch: %d variables but %s returns %d values", l, src.child[0].name(), len(types))
|
||||
}
|
||||
n.gen = nop
|
||||
|
||||
case indexExpr:
|
||||
@@ -1665,15 +1752,19 @@ func genRun(nod *node) error {
|
||||
return err
|
||||
}
|
||||
|
||||
// FixBranch sets the branch action to the identExpr node if it is a bool
|
||||
// used in a conditional expression.
|
||||
func fixBranch(n *node) {
|
||||
switch n.anc.kind {
|
||||
case ifStmt0, ifStmt1, ifStmt2, ifStmt3, forStmt1, forStmt2, forStmt3, forStmt4:
|
||||
n.gen = branch
|
||||
case parenExpr:
|
||||
fixBranch(n.anc)
|
||||
// setFnext sets the cond fnext field to next, propagates it for parenthesis blocks
|
||||
// and sets the action to branch.
|
||||
func setFNext(cond, next *node) {
|
||||
if cond.action == aNop {
|
||||
cond.action = aBranch
|
||||
cond.gen = branch
|
||||
cond.fnext = next
|
||||
}
|
||||
if cond.kind == parenExpr {
|
||||
setFNext(cond.lastChild(), next)
|
||||
return
|
||||
}
|
||||
cond.fnext = next
|
||||
}
|
||||
|
||||
// GetDefault return the index of default case clause in a switch statement, or -1.
|
||||
@@ -1761,6 +1852,16 @@ func wireChild(n *node) {
|
||||
}
|
||||
}
|
||||
|
||||
func (n *node) name() (s string) {
|
||||
switch {
|
||||
case n.ident != "":
|
||||
s = n.ident
|
||||
case n.action == aGetSym:
|
||||
s = n.child[0].ident + "." + n.child[1].ident
|
||||
}
|
||||
return s
|
||||
}
|
||||
|
||||
// isInteger returns true if node type is integer, false otherwise
|
||||
func (n *node) isInteger() bool {
|
||||
if isInt(n.typ.TypeOf()) {
|
||||
@@ -1877,7 +1978,7 @@ func isMethod(n *node) bool {
|
||||
}
|
||||
|
||||
func isMapEntry(n *node) bool {
|
||||
return n.action == aGetIndex && n.child[0].typ.cat == mapT
|
||||
return n.action == aGetIndex && isMap(n.child[0].typ)
|
||||
}
|
||||
|
||||
func isBinCall(n *node) bool {
|
||||
|
||||
@@ -9,7 +9,6 @@ import "reflect"
|
||||
func (interp *Interpreter) gta(root *node, rpath, pkgID string) ([]*node, error) {
|
||||
sc := interp.initScopePkg(pkgID)
|
||||
var err error
|
||||
var iotaValue int
|
||||
var revisit []*node
|
||||
|
||||
root.Walk(func(n *node) bool {
|
||||
@@ -18,9 +17,8 @@ func (interp *Interpreter) gta(root *node, rpath, pkgID string) ([]*node, error)
|
||||
}
|
||||
switch n.kind {
|
||||
case constDecl:
|
||||
iotaValue = 0
|
||||
// Early parse of constDecl subtree, to compute all constant
|
||||
// values which may be necessary in further declarations.
|
||||
// values which may be used in further declarations.
|
||||
if _, err = interp.cfg(n, pkgID); err != nil {
|
||||
// No error processing here, to allow recovery in subtree nodes.
|
||||
err = nil
|
||||
@@ -47,7 +45,7 @@ func (interp *Interpreter) gta(root *node, rpath, pkgID string) ([]*node, error)
|
||||
|
||||
for i := 0; i < n.nleft; i++ {
|
||||
dest, src := n.child[i], n.child[sbase+i]
|
||||
val := reflect.ValueOf(iotaValue)
|
||||
val := reflect.ValueOf(sc.iota)
|
||||
if n.anc.kind == constDecl {
|
||||
if _, err2 := interp.cfg(n, pkgID); err2 != nil {
|
||||
// Constant value can not be computed yet.
|
||||
@@ -63,7 +61,7 @@ func (interp *Interpreter) gta(root *node, rpath, pkgID string) ([]*node, error)
|
||||
}
|
||||
val = src.rval
|
||||
}
|
||||
if typ.incomplete {
|
||||
if !typ.isComplete() {
|
||||
// Come back when type is known.
|
||||
revisit = append(revisit, n)
|
||||
return false
|
||||
@@ -73,14 +71,18 @@ func (interp *Interpreter) gta(root *node, rpath, pkgID string) ([]*node, error)
|
||||
return false
|
||||
}
|
||||
if typ.isBinMethod {
|
||||
typ = &itype{cat: valueT, rtype: typ.methodCallType(), isBinMethod: true}
|
||||
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 n.anc.kind == constDecl {
|
||||
sc.sym[dest.ident].kind = constSym
|
||||
iotaValue++
|
||||
if childPos(n) == len(n.anc.child)-1 {
|
||||
sc.iota = 0
|
||||
} else {
|
||||
sc.iota++
|
||||
}
|
||||
}
|
||||
}
|
||||
return false
|
||||
@@ -94,7 +96,7 @@ func (interp *Interpreter) gta(root *node, rpath, pkgID string) ([]*node, error)
|
||||
if n.typ, err = nodeType(interp, sc, n.child[l]); err != nil {
|
||||
return false
|
||||
}
|
||||
if n.typ.incomplete {
|
||||
if !n.typ.isComplete() {
|
||||
// Come back when type is known.
|
||||
revisit = append(revisit, n)
|
||||
return false
|
||||
@@ -139,7 +141,7 @@ func (interp *Interpreter) gta(root *node, rpath, pkgID string) ([]*node, error)
|
||||
// Add a function symbol in the package name space
|
||||
sc.sym[n.child[1].ident] = &symbol{kind: funcSym, typ: n.typ, node: n, index: -1}
|
||||
}
|
||||
if n.typ.incomplete {
|
||||
if !n.typ.isComplete() {
|
||||
revisit = append(revisit, n)
|
||||
}
|
||||
return false
|
||||
@@ -163,10 +165,10 @@ func (interp *Interpreter) gta(root *node, rpath, pkgID string) ([]*node, error)
|
||||
if isBinType(v) {
|
||||
typ = typ.Elem()
|
||||
}
|
||||
sc.sym[n] = &symbol{kind: binSym, typ: &itype{cat: valueT, rtype: typ}, rval: v}
|
||||
sc.sym[n] = &symbol{kind: binSym, typ: &itype{cat: valueT, rtype: typ, scope: sc}, rval: v}
|
||||
}
|
||||
default: // import symbols in package namespace
|
||||
sc.sym[name] = &symbol{kind: pkgSym, typ: &itype{cat: binPkgT, path: ipath}}
|
||||
sc.sym[name] = &symbol{kind: pkgSym, typ: &itype{cat: binPkgT, path: ipath, scope: sc}}
|
||||
}
|
||||
} else if err = interp.importSrc(rpath, ipath); err == nil {
|
||||
sc.types = interp.universe.types
|
||||
@@ -179,7 +181,7 @@ func (interp *Interpreter) gta(root *node, rpath, pkgID string) ([]*node, error)
|
||||
}
|
||||
}
|
||||
default: // import symbols in package namespace
|
||||
sc.sym[name] = &symbol{kind: pkgSym, typ: &itype{cat: srcPkgT, path: ipath}}
|
||||
sc.sym[name] = &symbol{kind: pkgSym, typ: &itype{cat: srcPkgT, path: ipath, scope: sc}}
|
||||
}
|
||||
} else {
|
||||
err = n.cfgErrorf("import %q error: %v", ipath, err)
|
||||
@@ -192,7 +194,7 @@ func (interp *Interpreter) gta(root *node, rpath, pkgID string) ([]*node, error)
|
||||
return false
|
||||
}
|
||||
if n.child[1].kind == identExpr {
|
||||
n.typ = &itype{cat: aliasT, val: typ, name: typeName, path: rpath, field: typ.field, incomplete: typ.incomplete}
|
||||
n.typ = &itype{cat: aliasT, val: typ, name: typeName, path: rpath, field: typ.field, incomplete: typ.incomplete, scope: sc, node: n.child[0]}
|
||||
copy(n.typ.method, typ.method)
|
||||
} else {
|
||||
n.typ = typ
|
||||
@@ -206,7 +208,7 @@ func (interp *Interpreter) gta(root *node, rpath, pkgID string) ([]*node, error)
|
||||
n.typ.method = append(n.typ.method, sc.sym[typeName].typ.method...)
|
||||
}
|
||||
sc.sym[typeName].typ = n.typ
|
||||
if n.typ.incomplete {
|
||||
if !n.typ.isComplete() {
|
||||
revisit = append(revisit, n)
|
||||
}
|
||||
return false
|
||||
|
||||
@@ -455,16 +455,34 @@ func (interp *Interpreter) Use(values Exports) {
|
||||
// REPL performs a Read-Eval-Print-Loop on input reader.
|
||||
// Results are printed on output writer.
|
||||
func (interp *Interpreter) REPL(in io.Reader, out io.Writer) {
|
||||
s := bufio.NewScanner(in)
|
||||
// Preimport used bin packages, to avoid having to import these packages manually
|
||||
// in REPL mode. These packages are already loaded anyway.
|
||||
sc := interp.universe
|
||||
for k := range interp.binPkg {
|
||||
name := identifier.FindString(k)
|
||||
if name == "" || name == "rand" || name == "scanner" || name == "template" || name == "pprof" {
|
||||
// Skip any package with an ambiguous name (i.e crypto/rand vs math/rand).
|
||||
// Those will have to be imported explicitly.
|
||||
continue
|
||||
}
|
||||
sc.sym[name] = &symbol{kind: pkgSym, typ: &itype{cat: binPkgT, path: k, scope: sc}}
|
||||
}
|
||||
|
||||
// Set prompt.
|
||||
var v reflect.Value
|
||||
var err error
|
||||
prompt := getPrompt(in, out)
|
||||
prompt()
|
||||
prompt(v)
|
||||
|
||||
// Read, Eval, Print in a Loop.
|
||||
src := ""
|
||||
s := bufio.NewScanner(in)
|
||||
for s.Scan() {
|
||||
src += s.Text() + "\n"
|
||||
ctx, cancel := context.WithCancel(context.Background())
|
||||
defer cancel()
|
||||
handleSignal(ctx, cancel)
|
||||
v, err := interp.EvalWithContext(ctx, src)
|
||||
v, err = interp.EvalWithContext(ctx, src)
|
||||
signal.Reset()
|
||||
if err != nil {
|
||||
switch e := err.(type) {
|
||||
@@ -479,11 +497,9 @@ func (interp *Interpreter) REPL(in io.Reader, out io.Writer) {
|
||||
default:
|
||||
fmt.Fprintln(out, err)
|
||||
}
|
||||
} else if v.IsValid() {
|
||||
fmt.Fprintln(out, v)
|
||||
}
|
||||
src = ""
|
||||
prompt()
|
||||
prompt(v)
|
||||
}
|
||||
}
|
||||
|
||||
@@ -495,16 +511,21 @@ func (interp *Interpreter) Repl(in, out *os.File) {
|
||||
}
|
||||
|
||||
// getPrompt returns a function which prints a prompt only if input is a terminal.
|
||||
func getPrompt(in io.Reader, out io.Writer) func() {
|
||||
func getPrompt(in io.Reader, out io.Writer) func(reflect.Value) {
|
||||
s, ok := in.(interface{ Stat() (os.FileInfo, error) })
|
||||
if !ok {
|
||||
return func() {}
|
||||
return func(reflect.Value) {}
|
||||
}
|
||||
stat, err := s.Stat()
|
||||
if err == nil && stat.Mode()&os.ModeCharDevice != 0 {
|
||||
return func() { fmt.Fprint(out, "> ") }
|
||||
return func(v reflect.Value) {
|
||||
if v.IsValid() {
|
||||
fmt.Fprintln(out, ":", v)
|
||||
}
|
||||
fmt.Fprint(out, "> ")
|
||||
}
|
||||
}
|
||||
return func() {}
|
||||
return func(reflect.Value) {}
|
||||
}
|
||||
|
||||
// handleSignal wraps signal handling for eval cancellation.
|
||||
|
||||
@@ -32,6 +32,8 @@ func TestInterpConsistencyBuild(t *testing.T) {
|
||||
|
||||
for _, file := range files {
|
||||
if filepath.Ext(file.Name()) != ".go" ||
|
||||
file.Name() == "assign11.go" || // expect error
|
||||
file.Name() == "assign12.go" || // expect error
|
||||
file.Name() == "bad0.go" || // expect error
|
||||
file.Name() == "const9.go" || // expect error
|
||||
file.Name() == "export1.go" || // non-main package
|
||||
@@ -134,6 +136,16 @@ func TestInterpErrorConsistency(t *testing.T) {
|
||||
expectedInterp string
|
||||
expectedExec string
|
||||
}{
|
||||
{
|
||||
fileName: "assign11.go",
|
||||
expectedInterp: "6:2: assignment mismatch: 3 variables but fmt.Println returns 2 values",
|
||||
expectedExec: "6:10: assignment mismatch: 3 variables but fmt.Println returns 2 values",
|
||||
},
|
||||
{
|
||||
fileName: "assign12.go",
|
||||
expectedInterp: "6:2: assignment mismatch: 3 variables but fmt.Println returns 2 values",
|
||||
expectedExec: "6:10: assignment mismatch: 3 variables but fmt.Println returns 2 values",
|
||||
},
|
||||
{
|
||||
fileName: "bad0.go",
|
||||
expectedInterp: "1:1: expected 'package', found println",
|
||||
|
||||
56
interp/op.go
56
interp/op.go
@@ -7,9 +7,9 @@ import "reflect"
|
||||
// Arithmetic operators
|
||||
|
||||
func add(n *node) {
|
||||
dest := genValue(n)
|
||||
next := getExec(n.tnext)
|
||||
typ := n.typ.TypeOf()
|
||||
typ := n.typ.concrete().TypeOf()
|
||||
dest := genValueOutput(n, typ)
|
||||
c0, c1 := n.child[0], n.child[1]
|
||||
|
||||
switch typ.Kind() {
|
||||
@@ -167,9 +167,9 @@ func addConst(n *node) {
|
||||
}
|
||||
|
||||
func and(n *node) {
|
||||
dest := genValue(n)
|
||||
next := getExec(n.tnext)
|
||||
typ := n.typ.TypeOf()
|
||||
typ := n.typ.concrete().TypeOf()
|
||||
dest := genValueOutput(n, typ)
|
||||
c0, c1 := n.child[0], n.child[1]
|
||||
|
||||
switch typ.Kind() {
|
||||
@@ -245,9 +245,9 @@ func andConst(n *node) {
|
||||
}
|
||||
|
||||
func andNot(n *node) {
|
||||
dest := genValue(n)
|
||||
next := getExec(n.tnext)
|
||||
typ := n.typ.TypeOf()
|
||||
typ := n.typ.concrete().TypeOf()
|
||||
dest := genValueOutput(n, typ)
|
||||
c0, c1 := n.child[0], n.child[1]
|
||||
|
||||
switch typ.Kind() {
|
||||
@@ -323,9 +323,9 @@ func andNotConst(n *node) {
|
||||
}
|
||||
|
||||
func mul(n *node) {
|
||||
dest := genValue(n)
|
||||
next := getExec(n.tnext)
|
||||
typ := n.typ.TypeOf()
|
||||
typ := n.typ.concrete().TypeOf()
|
||||
dest := genValueOutput(n, typ)
|
||||
c0, c1 := n.child[0], n.child[1]
|
||||
|
||||
switch typ.Kind() {
|
||||
@@ -457,9 +457,9 @@ func mulConst(n *node) {
|
||||
}
|
||||
|
||||
func or(n *node) {
|
||||
dest := genValue(n)
|
||||
next := getExec(n.tnext)
|
||||
typ := n.typ.TypeOf()
|
||||
typ := n.typ.concrete().TypeOf()
|
||||
dest := genValueOutput(n, typ)
|
||||
c0, c1 := n.child[0], n.child[1]
|
||||
|
||||
switch typ.Kind() {
|
||||
@@ -535,9 +535,9 @@ func orConst(n *node) {
|
||||
}
|
||||
|
||||
func quo(n *node) {
|
||||
dest := genValue(n)
|
||||
next := getExec(n.tnext)
|
||||
typ := n.typ.TypeOf()
|
||||
typ := n.typ.concrete().TypeOf()
|
||||
dest := genValueOutput(n, typ)
|
||||
c0, c1 := n.child[0], n.child[1]
|
||||
|
||||
switch typ.Kind() {
|
||||
@@ -669,9 +669,9 @@ func quoConst(n *node) {
|
||||
}
|
||||
|
||||
func rem(n *node) {
|
||||
dest := genValue(n)
|
||||
next := getExec(n.tnext)
|
||||
typ := n.typ.TypeOf()
|
||||
typ := n.typ.concrete().TypeOf()
|
||||
dest := genValueOutput(n, typ)
|
||||
c0, c1 := n.child[0], n.child[1]
|
||||
|
||||
switch typ.Kind() {
|
||||
@@ -747,9 +747,9 @@ func remConst(n *node) {
|
||||
}
|
||||
|
||||
func shl(n *node) {
|
||||
dest := genValue(n)
|
||||
next := getExec(n.tnext)
|
||||
typ := n.typ.TypeOf()
|
||||
typ := n.typ.concrete().TypeOf()
|
||||
dest := genValueOutput(n, typ)
|
||||
c0, c1 := n.child[0], n.child[1]
|
||||
|
||||
switch typ.Kind() {
|
||||
@@ -825,9 +825,9 @@ func shlConst(n *node) {
|
||||
}
|
||||
|
||||
func shr(n *node) {
|
||||
dest := genValue(n)
|
||||
next := getExec(n.tnext)
|
||||
typ := n.typ.TypeOf()
|
||||
typ := n.typ.concrete().TypeOf()
|
||||
dest := genValueOutput(n, typ)
|
||||
c0, c1 := n.child[0], n.child[1]
|
||||
|
||||
switch typ.Kind() {
|
||||
@@ -903,9 +903,9 @@ func shrConst(n *node) {
|
||||
}
|
||||
|
||||
func sub(n *node) {
|
||||
dest := genValue(n)
|
||||
next := getExec(n.tnext)
|
||||
typ := n.typ.TypeOf()
|
||||
typ := n.typ.concrete().TypeOf()
|
||||
dest := genValueOutput(n, typ)
|
||||
c0, c1 := n.child[0], n.child[1]
|
||||
|
||||
switch typ.Kind() {
|
||||
@@ -1037,9 +1037,9 @@ func subConst(n *node) {
|
||||
}
|
||||
|
||||
func xor(n *node) {
|
||||
dest := genValue(n)
|
||||
next := getExec(n.tnext)
|
||||
typ := n.typ.TypeOf()
|
||||
typ := n.typ.concrete().TypeOf()
|
||||
dest := genValueOutput(n, typ)
|
||||
c0, c1 := n.child[0], n.child[1]
|
||||
|
||||
switch typ.Kind() {
|
||||
@@ -1917,7 +1917,7 @@ func posConst(n *node) {
|
||||
|
||||
func equal(n *node) {
|
||||
tnext := getExec(n.tnext)
|
||||
dest := genValue(n)
|
||||
dest := genValueOutput(n, reflect.TypeOf(true))
|
||||
c0, c1 := n.child[0], n.child[1]
|
||||
|
||||
switch t0, t1 := c0.typ.TypeOf(), c1.typ.TypeOf(); {
|
||||
@@ -2346,7 +2346,7 @@ func equal(n *node) {
|
||||
|
||||
func greater(n *node) {
|
||||
tnext := getExec(n.tnext)
|
||||
dest := genValue(n)
|
||||
dest := genValueOutput(n, reflect.TypeOf(true))
|
||||
c0, c1 := n.child[0], n.child[1]
|
||||
|
||||
switch t0, t1 := c0.typ.TypeOf(), c1.typ.TypeOf(); {
|
||||
@@ -2635,7 +2635,7 @@ func greater(n *node) {
|
||||
|
||||
func greaterEqual(n *node) {
|
||||
tnext := getExec(n.tnext)
|
||||
dest := genValue(n)
|
||||
dest := genValueOutput(n, reflect.TypeOf(true))
|
||||
c0, c1 := n.child[0], n.child[1]
|
||||
|
||||
switch t0, t1 := c0.typ.TypeOf(), c1.typ.TypeOf(); {
|
||||
@@ -2924,7 +2924,7 @@ func greaterEqual(n *node) {
|
||||
|
||||
func lower(n *node) {
|
||||
tnext := getExec(n.tnext)
|
||||
dest := genValue(n)
|
||||
dest := genValueOutput(n, reflect.TypeOf(true))
|
||||
c0, c1 := n.child[0], n.child[1]
|
||||
|
||||
switch t0, t1 := c0.typ.TypeOf(), c1.typ.TypeOf(); {
|
||||
@@ -3213,7 +3213,7 @@ func lower(n *node) {
|
||||
|
||||
func lowerEqual(n *node) {
|
||||
tnext := getExec(n.tnext)
|
||||
dest := genValue(n)
|
||||
dest := genValueOutput(n, reflect.TypeOf(true))
|
||||
c0, c1 := n.child[0], n.child[1]
|
||||
|
||||
switch t0, t1 := c0.typ.TypeOf(), c1.typ.TypeOf(); {
|
||||
@@ -3502,7 +3502,7 @@ func lowerEqual(n *node) {
|
||||
|
||||
func notEqual(n *node) {
|
||||
tnext := getExec(n.tnext)
|
||||
dest := genValue(n)
|
||||
dest := genValueOutput(n, reflect.TypeOf(true))
|
||||
c0, c1 := n.child[0], n.child[1]
|
||||
|
||||
switch t0, t1 := c0.typ.TypeOf(), c1.typ.TypeOf(); {
|
||||
|
||||
343
interp/run.go
343
interp/run.go
@@ -121,30 +121,33 @@ func runCfg(n *node, f *frame) {
|
||||
}
|
||||
|
||||
func typeAssertStatus(n *node) {
|
||||
value := genValue(n.child[0]) // input value
|
||||
c0, c1 := n.child[0], n.child[1]
|
||||
value := genValue(c0) // input value
|
||||
value1 := genValue(n.anc.child[1]) // returned status
|
||||
typ := c1.typ.rtype // type to assert
|
||||
next := getExec(n.tnext)
|
||||
|
||||
switch {
|
||||
case n.child[0].typ.cat == valueT:
|
||||
case c0.typ.cat == valueT:
|
||||
n.exec = func(f *frame) bltn {
|
||||
if !value(f).IsValid() || value(f).IsNil() {
|
||||
v := value(f)
|
||||
if !v.IsValid() || v.IsNil() {
|
||||
value1(f).SetBool(false)
|
||||
}
|
||||
value1(f).SetBool(true)
|
||||
value1(f).SetBool(v.Type().Implements(typ))
|
||||
return next
|
||||
}
|
||||
case n.child[1].typ.cat == interfaceT:
|
||||
case c1.typ.cat == interfaceT:
|
||||
n.exec = func(f *frame) bltn {
|
||||
_, ok := value(f).Interface().(valueInterface)
|
||||
//value0(f).Set(reflect.ValueOf(valueInterface{v.node, v.value}))
|
||||
// TODO: verify that value(f) implements asserted type.
|
||||
value1(f).SetBool(ok)
|
||||
return next
|
||||
}
|
||||
default:
|
||||
n.exec = func(f *frame) bltn {
|
||||
_, ok := value(f).Interface().(valueInterface)
|
||||
//value0(f).Set(v.value)
|
||||
// TODO: verify that value(f) implements asserted type.
|
||||
value1(f).SetBool(ok)
|
||||
return next
|
||||
}
|
||||
@@ -152,25 +155,29 @@ func typeAssertStatus(n *node) {
|
||||
}
|
||||
|
||||
func typeAssert(n *node) {
|
||||
value := genValue(n.child[0]) // input value
|
||||
dest := genValue(n) // returned result
|
||||
c0, c1 := n.child[0], n.child[1]
|
||||
value := genValue(c0) // input value
|
||||
dest := genValue(n) // returned result
|
||||
next := getExec(n.tnext)
|
||||
|
||||
switch {
|
||||
case n.child[0].typ.cat == valueT:
|
||||
case c0.typ.cat == valueT:
|
||||
n.exec = func(f *frame) bltn {
|
||||
dest(f).Set(value(f).Elem())
|
||||
v := value(f)
|
||||
dest(f).Set(v.Elem())
|
||||
return next
|
||||
}
|
||||
case n.child[1].typ.cat == interfaceT:
|
||||
case c1.typ.cat == interfaceT:
|
||||
n.exec = func(f *frame) bltn {
|
||||
v := value(f).Interface().(valueInterface)
|
||||
// TODO: verify that value(f) implements asserted type.
|
||||
dest(f).Set(reflect.ValueOf(valueInterface{v.node, v.value}))
|
||||
return next
|
||||
}
|
||||
default:
|
||||
n.exec = func(f *frame) bltn {
|
||||
v := value(f).Interface().(valueInterface)
|
||||
// TODO: verify that value(f) implements asserted type.
|
||||
dest(f).Set(v.value)
|
||||
return next
|
||||
}
|
||||
@@ -195,6 +202,7 @@ func typeAssert2(n *node) {
|
||||
case n.child[1].typ.cat == interfaceT:
|
||||
n.exec = func(f *frame) bltn {
|
||||
v, ok := value(f).Interface().(valueInterface)
|
||||
// TODO: verify that value(f) implements asserted type.
|
||||
value0(f).Set(reflect.ValueOf(valueInterface{v.node, v.value}))
|
||||
value1(f).SetBool(ok)
|
||||
return next
|
||||
@@ -202,6 +210,7 @@ func typeAssert2(n *node) {
|
||||
default:
|
||||
n.exec = func(f *frame) bltn {
|
||||
v, ok := value(f).Interface().(valueInterface)
|
||||
// TODO: verify that value(f) implements asserted type.
|
||||
value0(f).Set(v.value)
|
||||
value1(f).SetBool(ok)
|
||||
return next
|
||||
@@ -493,12 +502,13 @@ func genFunctionWrapper(n *node) func(*frame) reflect.Value {
|
||||
rcvr = genValueRecv(n)
|
||||
}
|
||||
}
|
||||
funcType := n.typ.TypeOf()
|
||||
|
||||
return func(f *frame) reflect.Value {
|
||||
if n.frame != nil { // Use closure context if defined
|
||||
f = n.frame
|
||||
}
|
||||
return reflect.MakeFunc(n.typ.TypeOf(), func(in []reflect.Value) []reflect.Value {
|
||||
return reflect.MakeFunc(funcType, func(in []reflect.Value) []reflect.Value {
|
||||
// Allocate and init local frame. All values to be settable and addressable.
|
||||
fr := newFrame(f, len(def.types), f.runid())
|
||||
d := fr.data
|
||||
@@ -571,17 +581,26 @@ func genInterfaceWrapper(n *node, typ reflect.Type) func(*frame) reflect.Value {
|
||||
|
||||
return func(f *frame) reflect.Value {
|
||||
v := value(f)
|
||||
vv := v
|
||||
switch v.Kind() {
|
||||
case reflect.Chan, reflect.Func, reflect.Interface, reflect.Map, reflect.Ptr, reflect.Slice:
|
||||
if v.IsNil() {
|
||||
return reflect.New(typ).Elem()
|
||||
}
|
||||
if v.Kind() == reflect.Ptr {
|
||||
vv = v.Elem()
|
||||
}
|
||||
}
|
||||
w := reflect.New(wrap).Elem()
|
||||
for i, m := range methods {
|
||||
if m == nil {
|
||||
if r := v.FieldByIndex(indexes[i]).MethodByName(names[i]); r.IsValid() {
|
||||
w.Field(i).Set(v.FieldByIndex(indexes[i]).MethodByName(names[i]))
|
||||
if r := v.MethodByName(names[i]); r.IsValid() {
|
||||
w.Field(i).Set(r)
|
||||
continue
|
||||
}
|
||||
o := vv.FieldByIndex(indexes[i])
|
||||
if r := o.MethodByName(names[i]); r.IsValid() {
|
||||
w.Field(i).Set(r)
|
||||
} else {
|
||||
log.Println(n.cfgErrorf("genInterfaceWrapper error, no method %s", names[i]))
|
||||
}
|
||||
@@ -601,11 +620,11 @@ func call(n *node) {
|
||||
value := genValue(n.child[0])
|
||||
var values []func(*frame) reflect.Value
|
||||
if n.child[0].recv != nil {
|
||||
// Compute method receiver value
|
||||
// Compute method receiver value.
|
||||
values = append(values, genValueRecv(n.child[0]))
|
||||
method = true
|
||||
} else if n.child[0].action == aMethod {
|
||||
// add a place holder for interface method receiver
|
||||
// Add a place holder for interface method receiver.
|
||||
values = append(values, nil)
|
||||
method = true
|
||||
}
|
||||
@@ -615,18 +634,18 @@ func call(n *node) {
|
||||
tnext := getExec(n.tnext)
|
||||
fnext := getExec(n.fnext)
|
||||
|
||||
// compute input argument value functions
|
||||
// Compute input argument value functions.
|
||||
for i, c := range child {
|
||||
switch {
|
||||
case isBinCall(c):
|
||||
// Handle nested function calls: pass returned values as arguments
|
||||
// Handle nested function calls: pass returned values as arguments.
|
||||
numOut := c.child[0].typ.rtype.NumOut()
|
||||
for j := 0; j < numOut; j++ {
|
||||
ind := c.findex + j
|
||||
values = append(values, func(f *frame) reflect.Value { return f.data[ind] })
|
||||
}
|
||||
case isRegularCall(c):
|
||||
// Arguments are return values of a nested function call
|
||||
// Arguments are return values of a nested function call.
|
||||
for j := range c.child[0].typ.ret {
|
||||
ind := c.findex + j
|
||||
values = append(values, func(f *frame) reflect.Value { return f.data[ind] })
|
||||
@@ -649,17 +668,42 @@ func call(n *node) {
|
||||
}
|
||||
}
|
||||
|
||||
// Compute output argument value functions.
|
||||
rtypes := n.child[0].typ.ret
|
||||
rvalues := make([]func(*frame) reflect.Value, len(rtypes))
|
||||
switch n.anc.kind {
|
||||
case defineXStmt, assignXStmt:
|
||||
for i := range rvalues {
|
||||
c := n.anc.child[i]
|
||||
if c.ident != "_" {
|
||||
switch {
|
||||
case c.ident == "_":
|
||||
// Skip assigning return value to blank var.
|
||||
case c.typ.cat == interfaceT && rtypes[i].cat != interfaceT:
|
||||
rvalues[i] = genValueInterfaceValue(c)
|
||||
default:
|
||||
rvalues[i] = genValue(c)
|
||||
}
|
||||
}
|
||||
case returnStmt:
|
||||
// Function call from a return statement: forward return values (always at frame start).
|
||||
for i := range rtypes {
|
||||
j := n.findex + i
|
||||
ret := n.child[0].typ.ret[i]
|
||||
callret := n.anc.val.(*node).typ.ret[i]
|
||||
if callret.cat == interfaceT && ret.cat != interfaceT {
|
||||
// Wrap the returned value in a valueInterface in caller frame.
|
||||
rvalues[i] = func(f *frame) reflect.Value {
|
||||
v := reflect.New(ret.rtype).Elem()
|
||||
f.data[j].Set(reflect.ValueOf(valueInterface{n, v}))
|
||||
return v
|
||||
}
|
||||
} else {
|
||||
// Set the return value location in return value of caller frame.
|
||||
rvalues[i] = func(f *frame) reflect.Value { return f.data[j] }
|
||||
}
|
||||
}
|
||||
default:
|
||||
// Multiple return values frame index are indexed from the node frame index.
|
||||
for i := range rtypes {
|
||||
j := n.findex + i
|
||||
rvalues[i] = func(f *frame) reflect.Value { return f.data[j] }
|
||||
@@ -747,39 +791,44 @@ func call(n *node) {
|
||||
}
|
||||
|
||||
// Copy input parameters from caller
|
||||
dest := nf.data[numRet:]
|
||||
for i, v := range values {
|
||||
switch {
|
||||
case method && i == 0:
|
||||
// compute receiver
|
||||
var src reflect.Value
|
||||
if v == nil {
|
||||
src = def.recv.val
|
||||
if len(def.recv.index) > 0 {
|
||||
if src.Kind() == reflect.Ptr {
|
||||
src = src.Elem().FieldByIndex(def.recv.index)
|
||||
} else {
|
||||
src = src.FieldByIndex(def.recv.index)
|
||||
if dest := nf.data[numRet:]; len(dest) > 0 {
|
||||
for i, v := range values {
|
||||
switch {
|
||||
case method && i == 0:
|
||||
// compute receiver
|
||||
var src reflect.Value
|
||||
if v == nil {
|
||||
src = def.recv.val
|
||||
if len(def.recv.index) > 0 {
|
||||
if src.Kind() == reflect.Ptr {
|
||||
src = src.Elem().FieldByIndex(def.recv.index)
|
||||
} else {
|
||||
src = src.FieldByIndex(def.recv.index)
|
||||
}
|
||||
}
|
||||
}
|
||||
} else {
|
||||
src = v(f)
|
||||
}
|
||||
// Accommodate to receiver type
|
||||
d := dest[0]
|
||||
if ks, kd := src.Kind(), d.Kind(); ks != kd {
|
||||
if kd == reflect.Ptr {
|
||||
d.Set(src.Addr())
|
||||
} else {
|
||||
d.Set(src.Elem())
|
||||
src = v(f)
|
||||
}
|
||||
} else {
|
||||
d.Set(src)
|
||||
// Accommodate to receiver type
|
||||
d := dest[0]
|
||||
if ks, kd := src.Kind(), d.Kind(); ks != kd {
|
||||
if kd == reflect.Ptr {
|
||||
d.Set(src.Addr())
|
||||
} else {
|
||||
d.Set(src.Elem())
|
||||
}
|
||||
} else {
|
||||
d.Set(src)
|
||||
}
|
||||
case variadic >= 0 && i >= variadic:
|
||||
if v(f).Type() == vararg.Type() {
|
||||
vararg.Set(v(f))
|
||||
} else {
|
||||
vararg.Set(reflect.Append(vararg, v(f)))
|
||||
}
|
||||
default:
|
||||
dest[i].Set(v(f))
|
||||
}
|
||||
case variadic >= 0 && i >= variadic:
|
||||
vararg.Set(reflect.Append(vararg, v(f)))
|
||||
default:
|
||||
dest[i].Set(v(f))
|
||||
}
|
||||
}
|
||||
|
||||
@@ -892,13 +941,16 @@ func callBin(n *node) {
|
||||
}
|
||||
case fnext != nil:
|
||||
// Handle branching according to boolean result.
|
||||
index := n.findex
|
||||
n.exec = func(f *frame) bltn {
|
||||
in := make([]reflect.Value, l)
|
||||
for i, v := range values {
|
||||
in[i] = v(f)
|
||||
}
|
||||
res := value(f).Call(in)
|
||||
if res[0].Bool() {
|
||||
b := res[0].Bool()
|
||||
f.data[index].SetBool(b)
|
||||
if b {
|
||||
return tnext
|
||||
}
|
||||
return fnext
|
||||
@@ -906,8 +958,8 @@ func callBin(n *node) {
|
||||
default:
|
||||
switch n.anc.action {
|
||||
case aAssign, aAssignX:
|
||||
// The function call is part of an assign expression, we write results direcly
|
||||
// to assigned location, to avoid an additional assign operation.
|
||||
// The function call is part of an assign expression, store results direcly
|
||||
// to assigned location, to avoid an additional frame copy.
|
||||
rvalues := make([]func(*frame) reflect.Value, funcType.NumOut())
|
||||
for i := range rvalues {
|
||||
c := n.anc.child[i]
|
||||
@@ -928,6 +980,21 @@ func callBin(n *node) {
|
||||
}
|
||||
return tnext
|
||||
}
|
||||
case aReturn:
|
||||
// The function call is part of a return statement, store output results
|
||||
// directly in the frame location of outputs of the current function.
|
||||
b := childPos(n)
|
||||
n.exec = func(f *frame) bltn {
|
||||
in := make([]reflect.Value, l)
|
||||
for i, v := range values {
|
||||
in[i] = v(f)
|
||||
}
|
||||
out := value(f).Call(in)
|
||||
for i, v := range out {
|
||||
f.data[b+i].Set(v)
|
||||
}
|
||||
return tnext
|
||||
}
|
||||
default:
|
||||
n.exec = func(f *frame) bltn {
|
||||
in := make([]reflect.Value, l)
|
||||
@@ -1016,6 +1083,9 @@ func getIndexArray(n *node) {
|
||||
}
|
||||
}
|
||||
|
||||
// valueInterfaceType is the reflection type of valueInterface
|
||||
var valueInterfaceType = reflect.TypeOf((*valueInterface)(nil)).Elem()
|
||||
|
||||
// getIndexMap retrieves map value from index
|
||||
func getIndexMap(n *node) {
|
||||
dest := genValue(n)
|
||||
@@ -1041,7 +1111,11 @@ func getIndexMap(n *node) {
|
||||
z = reflect.New(n.child[0].typ.val.frameType()).Elem()
|
||||
n.exec = func(f *frame) bltn {
|
||||
if v := value0(f).MapIndex(mi); v.IsValid() {
|
||||
dest(f).Set(v.Elem())
|
||||
if e := v.Elem(); e.Type().AssignableTo(valueInterfaceType) {
|
||||
dest(f).Set(e)
|
||||
} else {
|
||||
dest(f).Set(reflect.ValueOf(valueInterface{n, e}))
|
||||
}
|
||||
} else {
|
||||
dest(f).Set(z)
|
||||
}
|
||||
@@ -1075,7 +1149,11 @@ func getIndexMap(n *node) {
|
||||
z = reflect.New(n.child[0].typ.val.frameType()).Elem()
|
||||
n.exec = func(f *frame) bltn {
|
||||
if v := value0(f).MapIndex(value1(f)); v.IsValid() {
|
||||
dest(f).Set(v.Elem())
|
||||
if e := v.Elem(); e.Type().AssignableTo(valueInterfaceType) {
|
||||
dest(f).Set(e)
|
||||
} else {
|
||||
dest(f).Set(reflect.ValueOf(valueInterface{n, e}))
|
||||
}
|
||||
} else {
|
||||
dest(f).Set(z)
|
||||
}
|
||||
@@ -1121,7 +1199,11 @@ func getIndexMap2(n *node) {
|
||||
n.exec = func(f *frame) bltn {
|
||||
v := value0(f).MapIndex(mi)
|
||||
if v.IsValid() {
|
||||
dest(f).Set(v.Elem())
|
||||
if e := v.Elem(); e.Type().AssignableTo(valueInterfaceType) {
|
||||
dest(f).Set(e)
|
||||
} else {
|
||||
dest(f).Set(reflect.ValueOf(valueInterface{n, e}))
|
||||
}
|
||||
}
|
||||
if doStatus {
|
||||
value2(f).SetBool(v.IsValid())
|
||||
@@ -1153,7 +1235,11 @@ func getIndexMap2(n *node) {
|
||||
n.exec = func(f *frame) bltn {
|
||||
v := value0(f).MapIndex(value1(f))
|
||||
if v.IsValid() {
|
||||
dest(f).Set(v.Elem())
|
||||
if e := v.Elem(); e.Type().AssignableTo(valueInterfaceType) {
|
||||
dest(f).Set(e)
|
||||
} else {
|
||||
dest(f).Set(reflect.ValueOf(valueInterface{n, e}))
|
||||
}
|
||||
}
|
||||
if doStatus {
|
||||
value2(f).SetBool(v.IsValid())
|
||||
@@ -1493,7 +1579,6 @@ func branch(n *node) {
|
||||
|
||||
func _return(n *node) {
|
||||
child := n.child
|
||||
next := getExec(n.tnext)
|
||||
def := n.val.(*node)
|
||||
values := make([]func(*frame) reflect.Value, len(child))
|
||||
for i, c := range child {
|
||||
@@ -1521,15 +1606,15 @@ func _return(n *node) {
|
||||
|
||||
switch len(child) {
|
||||
case 0:
|
||||
n.exec = func(f *frame) bltn { return next }
|
||||
n.exec = nil
|
||||
case 1:
|
||||
if child[0].kind == binaryExpr {
|
||||
n.exec = func(f *frame) bltn { return next }
|
||||
if child[0].kind == binaryExpr || child[0].action == aCall {
|
||||
n.exec = nil
|
||||
} else {
|
||||
v := values[0]
|
||||
n.exec = func(f *frame) bltn {
|
||||
f.data[0].Set(v(f))
|
||||
return next
|
||||
return nil
|
||||
}
|
||||
}
|
||||
case 2:
|
||||
@@ -1537,14 +1622,14 @@ func _return(n *node) {
|
||||
n.exec = func(f *frame) bltn {
|
||||
f.data[0].Set(v0(f))
|
||||
f.data[1].Set(v1(f))
|
||||
return next
|
||||
return nil
|
||||
}
|
||||
default:
|
||||
n.exec = func(f *frame) bltn {
|
||||
for i, value := range values {
|
||||
f.data[i].Set(value(f))
|
||||
}
|
||||
return next
|
||||
return nil
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -1565,11 +1650,19 @@ func arrayLit(n *node) {
|
||||
for i, c := range child {
|
||||
if c.kind == keyValueExpr {
|
||||
convertLiteralValue(c.child[1], rtype)
|
||||
values[i] = genValue(c.child[1])
|
||||
if n.typ.val.cat == interfaceT {
|
||||
values[i] = genValueInterface(c.child[1])
|
||||
} else {
|
||||
values[i] = genValue(c.child[1])
|
||||
}
|
||||
index[i] = int(vInt(c.child[0].rval))
|
||||
} else {
|
||||
convertLiteralValue(c, rtype)
|
||||
values[i] = genValue(c)
|
||||
if n.typ.val.cat == interfaceT {
|
||||
values[i] = genValueInterface(c)
|
||||
} else {
|
||||
values[i] = genValue(c)
|
||||
}
|
||||
index[i] = prev
|
||||
}
|
||||
prev = index[i] + 1
|
||||
@@ -1578,14 +1671,14 @@ func arrayLit(n *node) {
|
||||
}
|
||||
}
|
||||
|
||||
var a reflect.Value
|
||||
if n.typ.sizedef {
|
||||
a, _ = n.typ.zero()
|
||||
} else {
|
||||
a = reflect.MakeSlice(n.typ.TypeOf(), max, max)
|
||||
}
|
||||
|
||||
typ := n.typ.frameType()
|
||||
n.exec = func(f *frame) bltn {
|
||||
var a reflect.Value
|
||||
if n.typ.sizedef {
|
||||
a, _ = n.typ.zero()
|
||||
} else {
|
||||
a = reflect.MakeSlice(typ, max, max)
|
||||
}
|
||||
for i, v := range values {
|
||||
a.Index(index[i]).Set(v(f))
|
||||
}
|
||||
@@ -1607,8 +1700,16 @@ func mapLit(n *node) {
|
||||
for i, c := range child {
|
||||
convertLiteralValue(c.child[0], n.typ.key.TypeOf())
|
||||
convertLiteralValue(c.child[1], n.typ.val.TypeOf())
|
||||
keys[i] = genValue(c.child[0])
|
||||
values[i] = genValue(c.child[1])
|
||||
if n.typ.key.cat == interfaceT {
|
||||
keys[i] = genValueInterface(c.child[0])
|
||||
} else {
|
||||
keys[i] = genValue(c.child[0])
|
||||
}
|
||||
if n.typ.val.cat == interfaceT {
|
||||
values[i] = genValueInterface(c.child[1])
|
||||
} else {
|
||||
values[i] = genValue(c.child[1])
|
||||
}
|
||||
}
|
||||
|
||||
n.exec = func(f *frame) bltn {
|
||||
@@ -1717,6 +1818,7 @@ func doCompositeLit(n *node, hasType bool) {
|
||||
}
|
||||
}
|
||||
|
||||
i := n.findex
|
||||
n.exec = func(f *frame) bltn {
|
||||
a := reflect.New(n.typ.TypeOf()).Elem()
|
||||
for i, v := range values {
|
||||
@@ -1728,7 +1830,7 @@ func doCompositeLit(n *node, hasType bool) {
|
||||
case destInterface:
|
||||
d.Set(reflect.ValueOf(valueInterface{n, a}))
|
||||
default:
|
||||
d.Set(a)
|
||||
f.data[i] = a
|
||||
}
|
||||
return next
|
||||
}
|
||||
@@ -1867,7 +1969,11 @@ func rangeMap(n *node) {
|
||||
return fnext
|
||||
}
|
||||
f.data[index0].Set(iter.Key())
|
||||
f.data[index1].Set(iter.Value().Elem())
|
||||
if e := iter.Value().Elem(); e.Type().AssignableTo(valueInterfaceType) {
|
||||
f.data[index1].Set(e)
|
||||
} else {
|
||||
f.data[index1].Set(reflect.ValueOf(valueInterface{n, e}))
|
||||
}
|
||||
return tnext
|
||||
}
|
||||
} else {
|
||||
@@ -1962,11 +2068,12 @@ func _case(n *node) {
|
||||
// match against multiple types: assign var to interface value
|
||||
n.exec = func(f *frame) bltn {
|
||||
val := srcValue(f)
|
||||
vid := val.Interface().(valueInterface).node.typ.id()
|
||||
for _, typ := range types {
|
||||
if vid == typ.id() {
|
||||
destValue(f).Set(val)
|
||||
return tnext
|
||||
if v := srcValue(f).Interface().(valueInterface).node; v != nil {
|
||||
for _, typ := range types {
|
||||
if v.typ.id() == typ.id() {
|
||||
destValue(f).Set(val)
|
||||
return tnext
|
||||
}
|
||||
}
|
||||
}
|
||||
return fnext
|
||||
@@ -1978,10 +2085,11 @@ func _case(n *node) {
|
||||
n.exec = func(f *frame) bltn { return tnext }
|
||||
} else {
|
||||
n.exec = func(f *frame) bltn {
|
||||
vtyp := srcValue(f).Interface().(valueInterface).node.typ
|
||||
for _, typ := range types {
|
||||
if vtyp.id() == typ.id() {
|
||||
return tnext
|
||||
if v := srcValue(f).Interface().(valueInterface).node; v != nil {
|
||||
for _, typ := range types {
|
||||
if v.typ.id() == typ.id() {
|
||||
return tnext
|
||||
}
|
||||
}
|
||||
}
|
||||
return fnext
|
||||
@@ -2012,7 +2120,7 @@ func _case(n *node) {
|
||||
}
|
||||
|
||||
func appendSlice(n *node) {
|
||||
dest := genValue(n)
|
||||
dest := genValueOutput(n, n.typ.rtype)
|
||||
next := getExec(n.tnext)
|
||||
value := genValue(n.child[1])
|
||||
value0 := genValue(n.child[2])
|
||||
@@ -2037,7 +2145,7 @@ func _append(n *node) {
|
||||
appendSlice(n)
|
||||
return
|
||||
}
|
||||
dest := genValue(n)
|
||||
dest := genValueOutput(n, n.typ.rtype)
|
||||
value := genValue(n.child[1])
|
||||
next := getExec(n.tnext)
|
||||
|
||||
@@ -2087,7 +2195,7 @@ func _append(n *node) {
|
||||
}
|
||||
|
||||
func _cap(n *node) {
|
||||
dest := genValue(n)
|
||||
dest := genValueOutput(n, reflect.TypeOf(int(0)))
|
||||
value := genValue(n.child[1])
|
||||
next := getExec(n.tnext)
|
||||
|
||||
@@ -2098,7 +2206,7 @@ func _cap(n *node) {
|
||||
}
|
||||
|
||||
func _copy(n *node) {
|
||||
dest := genValue(n)
|
||||
dest := genValueOutput(n, reflect.TypeOf(int(0)))
|
||||
value0 := genValueArray(n.child[1])
|
||||
value1 := genValue(n.child[2])
|
||||
next := getExec(n.tnext)
|
||||
@@ -2120,7 +2228,7 @@ func _close(n *node) {
|
||||
}
|
||||
|
||||
func _complex(n *node) {
|
||||
dest := genValue(n)
|
||||
dest := genValueOutput(n, reflect.TypeOf(complex(0, 0)))
|
||||
c1, c2 := n.child[1], n.child[2]
|
||||
convertLiteralValue(c1, floatType)
|
||||
convertLiteralValue(c2, floatType)
|
||||
@@ -2143,7 +2251,7 @@ func _complex(n *node) {
|
||||
}
|
||||
|
||||
func _imag(n *node) {
|
||||
dest := genValue(n)
|
||||
dest := genValueOutput(n, reflect.TypeOf(float64(0)))
|
||||
convertLiteralValue(n.child[1], complexType)
|
||||
value := genValue(n.child[1])
|
||||
next := getExec(n.tnext)
|
||||
@@ -2155,7 +2263,7 @@ func _imag(n *node) {
|
||||
}
|
||||
|
||||
func _real(n *node) {
|
||||
dest := genValue(n)
|
||||
dest := genValueOutput(n, reflect.TypeOf(float64(0)))
|
||||
convertLiteralValue(n.child[1], complexType)
|
||||
value := genValue(n.child[1])
|
||||
next := getExec(n.tnext)
|
||||
@@ -2179,7 +2287,7 @@ func _delete(n *node) {
|
||||
}
|
||||
|
||||
func _len(n *node) {
|
||||
dest := genValue(n)
|
||||
dest := genValueOutput(n, reflect.TypeOf(int(0)))
|
||||
value := genValue(n.child[1])
|
||||
next := getExec(n.tnext)
|
||||
|
||||
@@ -2190,9 +2298,9 @@ func _len(n *node) {
|
||||
}
|
||||
|
||||
func _new(n *node) {
|
||||
dest := genValue(n)
|
||||
next := getExec(n.tnext)
|
||||
typ := n.child[1].typ.TypeOf()
|
||||
dest := genValueOutput(n, reflect.PtrTo(typ))
|
||||
|
||||
n.exec = func(f *frame) bltn {
|
||||
dest(f).Set(reflect.New(typ))
|
||||
@@ -2202,9 +2310,9 @@ func _new(n *node) {
|
||||
|
||||
// _make allocates and initializes a slice, a map or a chan.
|
||||
func _make(n *node) {
|
||||
dest := genValue(n)
|
||||
next := getExec(n.tnext)
|
||||
typ := n.child[1].typ.frameType()
|
||||
dest := genValueOutput(n, typ)
|
||||
|
||||
switch typ.Kind() {
|
||||
case reflect.Array, reflect.Slice:
|
||||
@@ -2482,21 +2590,40 @@ func _select(n *node) {
|
||||
assignedValues := make([]func(*frame) reflect.Value, nbClause)
|
||||
okValues := make([]func(*frame) reflect.Value, nbClause)
|
||||
cases := make([]reflect.SelectCase, nbClause+1)
|
||||
next := getExec(n.tnext)
|
||||
|
||||
for i := 0; i < nbClause; i++ {
|
||||
if len(n.child[i].child) > 1 {
|
||||
clause[i] = getExec(n.child[i].child[1].start)
|
||||
chans[i], assigned[i], ok[i], cases[i].Dir = clauseChanDir(n.child[i])
|
||||
chanValues[i] = genValue(chans[i])
|
||||
if assigned[i] != nil {
|
||||
assignedValues[i] = genValue(assigned[i])
|
||||
}
|
||||
if ok[i] != nil {
|
||||
okValues[i] = genValue(ok[i])
|
||||
}
|
||||
} else {
|
||||
clause[i] = getExec(n.child[i].child[0].start)
|
||||
if len(n.child[i].child) == 0 {
|
||||
// The comm clause is an empty default, exit select.
|
||||
cases[i].Dir = reflect.SelectDefault
|
||||
clause[i] = func(*frame) bltn { return next }
|
||||
} else {
|
||||
switch c0 := n.child[i].child[0]; {
|
||||
case len(n.child[i].child) > 1:
|
||||
// The comm clause contains a channel operation and a clause body.
|
||||
clause[i] = getExec(n.child[i].child[1].start)
|
||||
chans[i], assigned[i], ok[i], cases[i].Dir = clauseChanDir(n.child[i])
|
||||
chanValues[i] = genValue(chans[i])
|
||||
if assigned[i] != nil {
|
||||
assignedValues[i] = genValue(assigned[i])
|
||||
}
|
||||
if ok[i] != nil {
|
||||
okValues[i] = genValue(ok[i])
|
||||
}
|
||||
case c0.kind == exprStmt && len(c0.child) == 1 && c0.child[0].action == aRecv:
|
||||
// The comm clause has an empty body clause after channel receive.
|
||||
chanValues[i] = genValue(c0.child[0].child[0])
|
||||
cases[i].Dir = reflect.SelectRecv
|
||||
case c0.kind == sendStmt:
|
||||
// The comm clause as an empty body clause after channel send.
|
||||
chanValues[i] = genValue(c0.child[0])
|
||||
cases[i].Dir = reflect.SelectSend
|
||||
assignedValues[i] = genValue(c0.child[1])
|
||||
default:
|
||||
// The comm clause has a default clause.
|
||||
clause[i] = getExec(c0.start)
|
||||
cases[i].Dir = reflect.SelectDefault
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -83,6 +83,7 @@ type scope struct {
|
||||
level int // Frame level: number of frame indirections to access var during execution
|
||||
sym map[string]*symbol // Map of symbols defined in this current scope
|
||||
global bool // true if scope refers to global space (single frame for universe and package level scopes)
|
||||
iota int // iota value in this scope
|
||||
}
|
||||
|
||||
// push creates a new scope and chain it to the current one
|
||||
|
||||
325
interp/type.go
325
interp/type.go
@@ -239,26 +239,36 @@ func nodeType(interp *Interpreter, sc *scope, n *node) (*itype, error) {
|
||||
t, err = nodeType(interp, sc, n.child[0])
|
||||
|
||||
case binaryExpr:
|
||||
if a := n.anc; a.kind == defineStmt && len(a.child) > a.nleft+a.nright {
|
||||
t, err = nodeType(interp, sc, a.child[a.nleft])
|
||||
} else {
|
||||
if t, err = nodeType(interp, sc, n.child[0]); err != nil {
|
||||
return nil, err
|
||||
}
|
||||
// Shift operator type is inherited from first parameter only
|
||||
// For other operators, infer type in from 2nd parameter in case of untyped first
|
||||
if t.untyped && !isShiftNode(n) {
|
||||
var t1 *itype
|
||||
t1, err = nodeType(interp, sc, n.child[1])
|
||||
if !(t1.untyped && isInt(t1.TypeOf()) && isFloat(t.TypeOf())) {
|
||||
t = t1
|
||||
}
|
||||
// Get type of first operand.
|
||||
if t, err = nodeType(interp, sc, n.child[0]); err != nil {
|
||||
return nil, err
|
||||
}
|
||||
// For operators other than shift, get the type from the 2nd operand if the first is untyped.
|
||||
if t.untyped && !isShiftNode(n) {
|
||||
var t1 *itype
|
||||
t1, err = nodeType(interp, sc, n.child[1])
|
||||
if !(t1.untyped && isInt(t1.TypeOf()) && isFloat(t.TypeOf())) {
|
||||
t = t1
|
||||
}
|
||||
}
|
||||
// If the node is to be assigned or returned, the node type is the destination type.
|
||||
dt := t
|
||||
switch a := n.anc; {
|
||||
case a.kind == defineStmt && len(a.child) > a.nleft+a.nright:
|
||||
if dt, err = nodeType(interp, sc, a.child[a.nleft]); err != nil {
|
||||
return nil, err
|
||||
}
|
||||
case a.kind == returnStmt:
|
||||
dt = sc.def.typ.ret[childPos(n)]
|
||||
}
|
||||
if isInterface(dt) {
|
||||
dt.val = t
|
||||
}
|
||||
t = dt
|
||||
|
||||
case callExpr:
|
||||
if interp.isBuiltinCall(n) {
|
||||
// builtin types are special and may depend from their call arguments
|
||||
// Builtin types are special and may depend from their input arguments.
|
||||
t.cat = builtinT
|
||||
switch n.child[0].ident {
|
||||
case "complex":
|
||||
@@ -278,7 +288,7 @@ func nodeType(interp *Interpreter, sc *scope, n *node) (*itype, error) {
|
||||
case isFloat64(t0) && isFloat64(t1):
|
||||
t = sc.getType("complex128")
|
||||
case nt0.untyped && isNumber(t0) && nt1.untyped && isNumber(t1):
|
||||
t = &itype{cat: valueT, rtype: complexType}
|
||||
t = &itype{cat: valueT, rtype: complexType, scope: sc}
|
||||
case nt0.untyped && isFloat32(t1) || nt1.untyped && isFloat32(t0):
|
||||
t = sc.getType("complex64")
|
||||
case nt0.untyped && isFloat64(t1) || nt1.untyped && isFloat64(t0):
|
||||
@@ -301,7 +311,7 @@ func nodeType(interp *Interpreter, sc *scope, n *node) (*itype, error) {
|
||||
case k == reflect.Complex128:
|
||||
t = sc.getType("float64")
|
||||
case t.untyped && isNumber(t.TypeOf()):
|
||||
t = &itype{cat: valueT, rtype: floatType, untyped: true}
|
||||
t = &itype{cat: valueT, rtype: floatType, untyped: true, scope: sc}
|
||||
default:
|
||||
err = n.cfgErrorf("invalid complex type %s", k)
|
||||
}
|
||||
@@ -312,7 +322,7 @@ func nodeType(interp *Interpreter, sc *scope, n *node) (*itype, error) {
|
||||
t, err = nodeType(interp, sc, n.child[1])
|
||||
case "new":
|
||||
t, err = nodeType(interp, sc, n.child[1])
|
||||
t = &itype{cat: ptrT, val: t, incomplete: t.incomplete}
|
||||
t = &itype{cat: ptrT, val: t, incomplete: t.incomplete, scope: sc}
|
||||
case "recover":
|
||||
t = sc.getType("interface{}")
|
||||
}
|
||||
@@ -325,8 +335,8 @@ func nodeType(interp *Interpreter, sc *scope, n *node) (*itype, error) {
|
||||
}
|
||||
switch t.cat {
|
||||
case valueT:
|
||||
if t.rtype.NumOut() == 1 {
|
||||
t = &itype{cat: valueT, rtype: t.rtype.Out(0)}
|
||||
if rt := t.rtype; rt.Kind() == reflect.Func && rt.NumOut() == 1 {
|
||||
t = &itype{cat: valueT, rtype: rt.Out(0), scope: sc}
|
||||
}
|
||||
default:
|
||||
if len(t.ret) == 1 {
|
||||
@@ -423,6 +433,7 @@ func nodeType(interp *Interpreter, sc *scope, n *node) (*itype, error) {
|
||||
|
||||
case interfaceType:
|
||||
t.cat = interfaceT
|
||||
var incomplete bool
|
||||
if sname := typeName(n); sname != "" {
|
||||
if sym, _, found := sc.lookup(sname); found && sym.kind == typeSym {
|
||||
sym.typ = t
|
||||
@@ -435,16 +446,17 @@ func nodeType(interp *Interpreter, sc *scope, n *node) (*itype, error) {
|
||||
return nil, err
|
||||
}
|
||||
t.field = append(t.field, structField{name: fieldName(field.child[0]), embed: true, typ: typ})
|
||||
t.incomplete = t.incomplete || typ.incomplete
|
||||
incomplete = incomplete || typ.incomplete
|
||||
} else {
|
||||
typ, err := nodeType(interp, sc, field.child[1])
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
t.field = append(t.field, structField{name: field.child[0].ident, typ: typ})
|
||||
t.incomplete = t.incomplete || typ.incomplete
|
||||
incomplete = incomplete || typ.incomplete
|
||||
}
|
||||
}
|
||||
t.incomplete = incomplete
|
||||
|
||||
case landExpr, lorExpr:
|
||||
t.cat = boolT
|
||||
@@ -497,11 +509,11 @@ func nodeType(interp *Interpreter, sc *scope, n *node) (*itype, error) {
|
||||
if m, _ := lt.lookupMethod(name); m != nil {
|
||||
t, err = nodeType(interp, sc, m.child[2])
|
||||
} else if bm, _, _, ok := lt.lookupBinMethod(name); ok {
|
||||
t = &itype{cat: valueT, rtype: bm.Type, isBinMethod: true}
|
||||
t = &itype{cat: valueT, rtype: bm.Type, isBinMethod: true, scope: sc}
|
||||
} else if ti := lt.lookupField(name); len(ti) > 0 {
|
||||
t = lt.fieldSeq(ti)
|
||||
} else if bs, _, ok := lt.lookupBinField(name); ok {
|
||||
t = &itype{cat: valueT, rtype: bs.Type}
|
||||
t = &itype{cat: valueT, rtype: bs.Type, scope: sc}
|
||||
} else {
|
||||
err = lt.node.cfgErrorf("undefined selector %s", name)
|
||||
}
|
||||
@@ -627,7 +639,10 @@ func init() {
|
||||
zeroValues[uintptrT] = reflect.ValueOf(uintptr(0))
|
||||
}
|
||||
|
||||
// if type is incomplete, re-parse it.
|
||||
// Finalize returns a type pointer and error. It reparses a type from the
|
||||
// partial AST if necessary (after missing dependecy data is available).
|
||||
// If error is nil, the type is guarranteed to be completely defined and
|
||||
// usable for CFG.
|
||||
func (t *itype) finalize() (*itype, error) {
|
||||
var err error
|
||||
if t.incomplete {
|
||||
@@ -654,6 +669,113 @@ func (t *itype) finalize() (*itype, error) {
|
||||
return t, err
|
||||
}
|
||||
|
||||
// ReferTo returns true if the type contains a reference to a
|
||||
// full type name. It allows to asses a type recursive status.
|
||||
func (t *itype) referTo(name string, seen map[*itype]bool) bool {
|
||||
if t.path+"/"+t.name == name {
|
||||
return true
|
||||
}
|
||||
if seen[t] {
|
||||
return false
|
||||
}
|
||||
seen[t] = true
|
||||
switch t.cat {
|
||||
case aliasT, arrayT, chanT, ptrT:
|
||||
return t.val.referTo(name, seen)
|
||||
case funcT:
|
||||
for _, a := range t.arg {
|
||||
if a.referTo(name, seen) {
|
||||
return true
|
||||
}
|
||||
}
|
||||
for _, a := range t.ret {
|
||||
if a.referTo(name, seen) {
|
||||
return true
|
||||
}
|
||||
}
|
||||
case mapT:
|
||||
return t.key.referTo(name, seen) || t.val.referTo(name, seen)
|
||||
case structT, interfaceT:
|
||||
for _, f := range t.field {
|
||||
if f.typ.referTo(name, seen) {
|
||||
return true
|
||||
}
|
||||
}
|
||||
}
|
||||
return false
|
||||
}
|
||||
|
||||
func (t *itype) numOut() int {
|
||||
if t.cat == valueT {
|
||||
return t.rtype.NumOut()
|
||||
}
|
||||
return len(t.ret)
|
||||
}
|
||||
|
||||
func (t *itype) concrete() *itype {
|
||||
if isInterface(t) && t.val != nil {
|
||||
return t.val.concrete()
|
||||
}
|
||||
return t
|
||||
}
|
||||
|
||||
// IsRecursive returns true if type is recursive.
|
||||
// Only a named struct or interface can be recursive.
|
||||
func (t *itype) isRecursive() bool {
|
||||
if t.name == "" {
|
||||
return false
|
||||
}
|
||||
switch t.cat {
|
||||
case structT, interfaceT:
|
||||
for _, f := range t.field {
|
||||
if f.typ.referTo(t.path+"/"+t.name, map[*itype]bool{}) {
|
||||
return true
|
||||
}
|
||||
}
|
||||
}
|
||||
return false
|
||||
}
|
||||
|
||||
// isComplete returns true if type definition is complete.
|
||||
func (t *itype) isComplete() bool { return isComplete(t, map[string]bool{}) }
|
||||
|
||||
func isComplete(t *itype, visited map[string]bool) bool {
|
||||
if t.incomplete {
|
||||
return false
|
||||
}
|
||||
name := t.path + "/" + t.name
|
||||
if visited[name] {
|
||||
return !t.incomplete
|
||||
}
|
||||
if t.name != "" {
|
||||
visited[name] = true
|
||||
}
|
||||
switch t.cat {
|
||||
case aliasT, arrayT, chanT, ptrT:
|
||||
return isComplete(t.val, visited)
|
||||
case funcT:
|
||||
complete := true
|
||||
for _, a := range t.arg {
|
||||
complete = complete && isComplete(a, visited)
|
||||
}
|
||||
for _, a := range t.ret {
|
||||
complete = complete && isComplete(a, visited)
|
||||
}
|
||||
return complete
|
||||
case interfaceT, structT:
|
||||
complete := true
|
||||
for _, f := range t.field {
|
||||
complete = complete && isComplete(f.typ, visited)
|
||||
}
|
||||
return complete
|
||||
case mapT:
|
||||
return isComplete(t.key, visited) && isComplete(t.val, visited)
|
||||
case nilT:
|
||||
return false
|
||||
}
|
||||
return true
|
||||
}
|
||||
|
||||
// Equals returns true if the given type is identical to the receiver one.
|
||||
func (t *itype) equals(o *itype) bool {
|
||||
switch ti, oi := isInterface(t), isInterface(o); {
|
||||
@@ -723,17 +845,43 @@ func (t *itype) methods() methodSet {
|
||||
}
|
||||
|
||||
// id returns a unique type identificator string
|
||||
func (t *itype) id() string {
|
||||
// TODO: if res is nil, build identity from String()
|
||||
|
||||
res := ""
|
||||
func (t *itype) id() (res string) {
|
||||
if t.name != "" {
|
||||
return t.path + "." + t.name
|
||||
}
|
||||
switch t.cat {
|
||||
case valueT:
|
||||
res = t.rtype.PkgPath() + "." + t.rtype.Name()
|
||||
case arrayT:
|
||||
res = "[" + strconv.Itoa(t.size) + "]" + t.val.id()
|
||||
case chanT:
|
||||
res = "<-" + t.val.id()
|
||||
case funcT:
|
||||
res = "func("
|
||||
for _, t := range t.arg {
|
||||
res += t.id() + ","
|
||||
}
|
||||
res += ")("
|
||||
for _, t := range t.ret {
|
||||
res += t.id() + ","
|
||||
}
|
||||
res += ")"
|
||||
case interfaceT:
|
||||
res = "interface{"
|
||||
for _, t := range t.field {
|
||||
res += t.name + " " + t.typ.id() + ";"
|
||||
}
|
||||
res += "}"
|
||||
case mapT:
|
||||
res = "map[" + t.key.id() + "]" + t.val.id()
|
||||
case ptrT:
|
||||
res = "*" + t.val.id()
|
||||
default:
|
||||
res = t.path + "." + t.name
|
||||
case structT:
|
||||
res = "struct{"
|
||||
for _, t := range t.field {
|
||||
res += t.name + " " + t.typ.id() + ";"
|
||||
}
|
||||
res += "}"
|
||||
case valueT:
|
||||
res = t.rtype.PkgPath() + "." + t.rtype.Name()
|
||||
}
|
||||
return res
|
||||
}
|
||||
@@ -748,7 +896,7 @@ func (t *itype) zero() (v reflect.Value, err error) {
|
||||
v, err = t.val.zero()
|
||||
|
||||
case arrayT, ptrT, structT:
|
||||
v = reflect.New(t.TypeOf()).Elem()
|
||||
v = reflect.New(t.frameType()).Elem()
|
||||
|
||||
case valueT:
|
||||
v = reflect.New(t.rtype).Elem()
|
||||
@@ -761,7 +909,8 @@ func (t *itype) zero() (v reflect.Value, err error) {
|
||||
|
||||
// fieldIndex returns the field index from name in a struct, or -1 if not found
|
||||
func (t *itype) fieldIndex(name string) int {
|
||||
if t.cat == ptrT {
|
||||
switch t.cat {
|
||||
case aliasT, ptrT:
|
||||
return t.val.fieldIndex(name)
|
||||
}
|
||||
for i, field := range t.field {
|
||||
@@ -786,6 +935,10 @@ func (t *itype) fieldSeq(seq []int) *itype {
|
||||
|
||||
// lookupField returns a list of indices, i.e. a path to access a field in a struct object
|
||||
func (t *itype) lookupField(name string) []int {
|
||||
switch t.cat {
|
||||
case aliasT, ptrT:
|
||||
return t.val.lookupField(name)
|
||||
}
|
||||
if fi := t.fieldIndex(name); fi >= 0 {
|
||||
return []int{fi}
|
||||
}
|
||||
@@ -824,7 +977,7 @@ func (t *itype) lookupBinField(name string) (s reflect.StructField, index []int,
|
||||
return s, index, ok
|
||||
}
|
||||
|
||||
// methodCallType returns a method function type without the receiver defined.
|
||||
// MethodCallType returns a method function type without the receiver defined.
|
||||
// The input type must be a method function type with the receiver as the first input argument.
|
||||
func (t *itype) methodCallType() reflect.Type {
|
||||
it := []reflect.Type{}
|
||||
@@ -840,7 +993,7 @@ func (t *itype) methodCallType() reflect.Type {
|
||||
return reflect.FuncOf(it, ot, t.rtype.IsVariadic())
|
||||
}
|
||||
|
||||
// getMethod returns a pointer to the method definition
|
||||
// GetMethod returns a pointer to the method definition.
|
||||
func (t *itype) getMethod(name string) *node {
|
||||
for _, m := range t.method {
|
||||
if name == m.ident {
|
||||
@@ -850,8 +1003,8 @@ func (t *itype) getMethod(name string) *node {
|
||||
return nil
|
||||
}
|
||||
|
||||
// lookupMethod returns a pointer to method definition associated to type t
|
||||
// and the list of indices to access the right struct field, in case of an embedded method
|
||||
// LookupMethod returns a pointer to method definition associated to type t
|
||||
// and the list of indices to access the right struct field, in case of an embedded method.
|
||||
func (t *itype) lookupMethod(name string) (*node, []int) {
|
||||
if t.cat == ptrT {
|
||||
return t.val.lookupMethod(name)
|
||||
@@ -871,7 +1024,7 @@ func (t *itype) lookupMethod(name string) (*node, []int) {
|
||||
return m, index
|
||||
}
|
||||
|
||||
// lookupBinMethod returns a method and a path to access a field in a struct object (the receiver)
|
||||
// LookupBinMethod returns a method and a path to access a field in a struct object (the receiver).
|
||||
func (t *itype) lookupBinMethod(name string) (m reflect.Method, index []int, isPtr bool, ok bool) {
|
||||
if t.cat == ptrT {
|
||||
return t.val.lookupBinMethod(name)
|
||||
@@ -901,27 +1054,48 @@ func exportName(s string) string {
|
||||
return "X" + s
|
||||
}
|
||||
|
||||
var interf = reflect.TypeOf(new(interface{})).Elem()
|
||||
var interf = reflect.TypeOf((*interface{})(nil)).Elem()
|
||||
|
||||
// RefType returns a reflect.Type representation from an interpereter type.
|
||||
// In simple cases, reflect types are directly mapped from the interpreter
|
||||
// counterpart.
|
||||
// For recursive named struct or interfaces, as reflect does not permit to
|
||||
// create a recursive named struct, an interface{} is returned in place to
|
||||
// avoid infinitely nested structs.
|
||||
func (t *itype) refType(defined map[string]*itype, wrapRecursive bool) reflect.Type {
|
||||
if t.rtype != nil {
|
||||
if wrapRecursive && t.cat == structT && defined[t.name] != nil {
|
||||
return interf
|
||||
}
|
||||
return t.rtype
|
||||
}
|
||||
|
||||
if t.incomplete || t.cat == nilT {
|
||||
var err error
|
||||
if t, err = t.finalize(); err != nil {
|
||||
panic(err)
|
||||
}
|
||||
}
|
||||
if t.val != nil && defined[t.val.name] != nil && !t.val.incomplete && t.val.rtype == nil {
|
||||
recursive := false
|
||||
name := t.path + "/" + t.name
|
||||
// Predefined types from universe or runtime may have a nil scope.
|
||||
if t.scope != nil {
|
||||
if st := t.scope.sym[t.name]; st != nil {
|
||||
// Update the type recursive status. Several copies of type
|
||||
// may exist per symbol, as a new type is created at each GTA
|
||||
// pass (several needed due to out of order declarations), and
|
||||
// a node can still point to a previous copy.
|
||||
st.typ.recursive = st.typ.recursive || st.typ.isRecursive()
|
||||
recursive = st.typ.isRecursive()
|
||||
}
|
||||
}
|
||||
if wrapRecursive && t.recursive {
|
||||
return interf
|
||||
}
|
||||
if t.rtype != nil {
|
||||
return t.rtype
|
||||
}
|
||||
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 {
|
||||
// Replace reference to self (direct or indirect) by an interface{} to handle
|
||||
// recursive types with reflect.
|
||||
t.val.rtype = interf
|
||||
defined[t.val.name].recursive = true
|
||||
recursive = true
|
||||
}
|
||||
switch t.cat {
|
||||
case aliasT:
|
||||
@@ -937,9 +1111,11 @@ func (t *itype) refType(defined map[string]*itype, wrapRecursive bool) reflect.T
|
||||
case errorT:
|
||||
t.rtype = reflect.TypeOf(new(error)).Elem()
|
||||
case funcT:
|
||||
if t.name != "" {
|
||||
defined[name] = t
|
||||
}
|
||||
in := make([]reflect.Type, len(t.arg))
|
||||
out := make([]reflect.Type, len(t.ret))
|
||||
//wrap := false
|
||||
for i, v := range t.arg {
|
||||
in[i] = v.refType(defined, true)
|
||||
}
|
||||
@@ -955,14 +1131,17 @@ func (t *itype) refType(defined map[string]*itype, wrapRecursive bool) reflect.T
|
||||
t.rtype = reflect.PtrTo(t.val.refType(defined, wrapRecursive))
|
||||
case structT:
|
||||
if t.name != "" {
|
||||
defined[t.name] = t
|
||||
if defined[name] != nil {
|
||||
recursive = true
|
||||
}
|
||||
defined[name] = t
|
||||
}
|
||||
var fields []reflect.StructField
|
||||
for _, f := range t.field {
|
||||
field := reflect.StructField{Name: exportName(f.name), Type: f.typ.refType(defined, wrapRecursive), Tag: reflect.StructTag(f.tag)}
|
||||
fields = append(fields, field)
|
||||
}
|
||||
if t.recursive && wrapRecursive {
|
||||
if recursive && wrapRecursive {
|
||||
t.rtype = interf
|
||||
} else {
|
||||
t.rtype = reflect.StructOf(fields)
|
||||
@@ -1030,6 +1209,23 @@ func isShiftNode(n *node) bool {
|
||||
return false
|
||||
}
|
||||
|
||||
// chanElement returns the channel element type.
|
||||
func chanElement(t *itype) *itype {
|
||||
switch t.cat {
|
||||
case aliasT:
|
||||
return chanElement(t.val)
|
||||
case chanT:
|
||||
return t.val
|
||||
case valueT:
|
||||
return &itype{cat: valueT, rtype: t.rtype.Elem(), node: t.node, scope: t.scope}
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
func isBool(t *itype) bool { return t.TypeOf().Kind() == reflect.Bool }
|
||||
func isChan(t *itype) bool { return t.TypeOf().Kind() == reflect.Chan }
|
||||
func isMap(t *itype) bool { return t.TypeOf().Kind() == reflect.Map }
|
||||
|
||||
func isInterfaceSrc(t *itype) bool {
|
||||
return t.cat == interfaceT || (t.cat == aliasT && isInterfaceSrc(t.val))
|
||||
}
|
||||
@@ -1054,9 +1250,10 @@ func isStruct(t *itype) bool {
|
||||
}
|
||||
}
|
||||
|
||||
func isBool(t *itype) bool { return t.TypeOf().Kind() == reflect.Bool }
|
||||
|
||||
func isInt(t reflect.Type) bool {
|
||||
if t == nil {
|
||||
return false
|
||||
}
|
||||
switch t.Kind() {
|
||||
case reflect.Int, reflect.Int8, reflect.Int16, reflect.Int32, reflect.Int64, reflect.Uint, reflect.Uint8, reflect.Uint16, reflect.Uint32, reflect.Uint64, reflect.Uintptr:
|
||||
return true
|
||||
@@ -1065,6 +1262,9 @@ func isInt(t reflect.Type) bool {
|
||||
}
|
||||
|
||||
func isUint(t reflect.Type) bool {
|
||||
if t == nil {
|
||||
return false
|
||||
}
|
||||
switch t.Kind() {
|
||||
case reflect.Uint, reflect.Uint8, reflect.Uint16, reflect.Uint32, reflect.Uint64, reflect.Uintptr:
|
||||
return true
|
||||
@@ -1073,6 +1273,9 @@ func isUint(t reflect.Type) bool {
|
||||
}
|
||||
|
||||
func isComplex(t reflect.Type) bool {
|
||||
if t == nil {
|
||||
return false
|
||||
}
|
||||
switch t.Kind() {
|
||||
case reflect.Complex64, reflect.Complex128:
|
||||
return true
|
||||
@@ -1081,6 +1284,9 @@ func isComplex(t reflect.Type) bool {
|
||||
}
|
||||
|
||||
func isFloat(t reflect.Type) bool {
|
||||
if t == nil {
|
||||
return false
|
||||
}
|
||||
switch t.Kind() {
|
||||
case reflect.Float32, reflect.Float64:
|
||||
return true
|
||||
@@ -1089,11 +1295,14 @@ func isFloat(t reflect.Type) bool {
|
||||
}
|
||||
|
||||
func isByteArray(t reflect.Type) bool {
|
||||
if t == nil {
|
||||
return false
|
||||
}
|
||||
k := t.Kind()
|
||||
return (k == reflect.Array || k == reflect.Slice) && t.Elem().Kind() == reflect.Uint8
|
||||
}
|
||||
|
||||
func isFloat32(t reflect.Type) bool { return t.Kind() == reflect.Float32 }
|
||||
func isFloat64(t reflect.Type) bool { return t.Kind() == reflect.Float64 }
|
||||
func isFloat32(t reflect.Type) bool { return t != nil && t.Kind() == reflect.Float32 }
|
||||
func isFloat64(t reflect.Type) bool { return t != nil && t.Kind() == reflect.Float64 }
|
||||
func isNumber(t reflect.Type) bool { return isInt(t) || isFloat(t) || isComplex(t) }
|
||||
func isString(t reflect.Type) bool { return t.Kind() == reflect.String }
|
||||
func isString(t reflect.Type) bool { return t != nil && t.Kind() == reflect.String }
|
||||
|
||||
@@ -79,7 +79,7 @@ func genValue(n *node) func(*frame) reflect.Value {
|
||||
case basicLit:
|
||||
v := n.rval
|
||||
if !v.IsValid() {
|
||||
v = reflect.New(reflect.TypeOf((*interface{})(nil)).Elem()).Elem()
|
||||
v = reflect.New(interf).Elem()
|
||||
}
|
||||
return func(f *frame) reflect.Value { return v }
|
||||
case funcDecl:
|
||||
@@ -149,10 +149,9 @@ func genValueRangeArray(n *node) func(*frame) reflect.Value {
|
||||
|
||||
func genValueInterfacePtr(n *node) func(*frame) reflect.Value {
|
||||
value := genValue(n)
|
||||
it := reflect.TypeOf((*interface{})(nil)).Elem()
|
||||
|
||||
return func(f *frame) reflect.Value {
|
||||
v := reflect.New(it).Elem()
|
||||
v := reflect.New(interf).Elem()
|
||||
v.Set(value(f))
|
||||
return v.Addr()
|
||||
}
|
||||
@@ -179,10 +178,28 @@ func genValueInterface(n *node) func(*frame) reflect.Value {
|
||||
|
||||
func zeroInterfaceValue() reflect.Value {
|
||||
n := &node{kind: basicLit, typ: &itype{cat: nilT, untyped: true}}
|
||||
v := reflect.New(reflect.TypeOf((*interface{})(nil)).Elem()).Elem()
|
||||
v := reflect.New(interf).Elem()
|
||||
return reflect.ValueOf(valueInterface{n, v})
|
||||
}
|
||||
|
||||
func genValueOutput(n *node, t reflect.Type) func(*frame) reflect.Value {
|
||||
value := genValue(n)
|
||||
switch {
|
||||
case n.anc.action == aAssign && n.anc.typ.cat == interfaceT:
|
||||
fallthrough
|
||||
case n.anc.kind == returnStmt && n.anc.val.(*node).typ.ret[0].cat == interfaceT:
|
||||
// The result of the builtin has to be returned as an interface type.
|
||||
// Wrap it in a valueInterface and return the dereferenced value.
|
||||
return func(f *frame) reflect.Value {
|
||||
d := value(f)
|
||||
v := reflect.New(t).Elem()
|
||||
d.Set(reflect.ValueOf(valueInterface{n, v}))
|
||||
return v
|
||||
}
|
||||
}
|
||||
return value
|
||||
}
|
||||
|
||||
func genValueInterfaceValue(n *node) func(*frame) reflect.Value {
|
||||
value := genValue(n)
|
||||
|
||||
|
||||
Reference in New Issue
Block a user