Compare commits

...

33 Commits

Author SHA1 Message Date
Marc Vertes
cdf4622421 fix: assign an element in a map from runtime 2020-05-05 22:46:04 +02:00
Marc Vertes
b9720d15e1 fix: improve setting results in multiple output functions 2020-05-05 22:34:03 +02:00
Marc Vertes
7fab75fbe4 fix: correct assign from function returning an interface value (#625) 2020-05-05 13:54:36 +02:00
Marc Vertes
7eac6955b3 feature: pre-import used packages in REPL mode. 2020-05-04 16:18:05 +02:00
Marc Vertes
7070367d21 fix: handle constant declarations inside function scopes 2020-05-03 18:56:04 +02:00
Marc Vertes
22dfc8b10a fix: handle set of variadic arg list for a ... value 2020-05-03 18:44:04 +02:00
Marc Vertes
7fba3fe580 fix: improve generation of interface wrapper 2020-05-03 18:32:04 +02:00
Marc Vertes
ff36ec58b1 fix: improve switch and type switch statement processing 2020-05-03 18:20:04 +02:00
Marc Vertes
f6c8b8b14f fix: check that a function returns the correct number of values 2020-05-03 18:08:03 +02:00
Marc Vertes
e12c8b72c4 fix: store the result of a bin function call in frame 2020-05-03 17:56:04 +02:00
Marc Vertes
e4acba031d fix: improving handling of functions returning interfaces 2020-05-03 17:46:03 +02:00
Marc Vertes
7d56fb067e fix: improve setting of interface objects 2020-04-30 17:44:04 +02:00
Marc Vertes
1feece61ce fix: improve handling of function return values 2020-04-30 10:32:04 +02:00
Marc Vertes
01e2e4600e fix: handle default comm clause in select 2020-04-25 17:40:08 +02:00
Marc Vertes
92eebbade2 fix: handle function output value assigned to interface var 2020-04-25 17:28:04 +02:00
Marc Vertes
a6389aca5e fix: improve handling of nil 2020-04-25 17:16:03 +02:00
Marc Vertes
de8cb7dc3b fix: handle type conversion from pre-compiled types. 2020-04-23 19:20:04 +02:00
Marc Vertes
18b843646c fix: parsing of recursive interface types 2020-04-22 19:26:05 +02:00
Marc Vertes
71f730b3d7 fix: handle forward declaration for aliased type 2020-04-22 10:50:05 +02:00
Marc Vertes
7b2d91bcb5 fix: handling values in map of interfaces 2020-04-22 10:34:05 +02:00
Marc Vertes
3ed4ec3f6f fix: correct type assertion for bin func types (#588) 2020-04-20 23:01:01 +02:00
Marc Vertes
5e142fdedd fix: do not attempt to copy data in empty frame at func call 2020-04-18 18:36:04 +02:00
Marc Vertes
94d44e7265 fix: do not convert literal float to int at parse 2020-04-17 17:54:03 +02:00
Marc Vertes
56925e6fea fix: correct branch control flow graph for parenthesis expressions (#583) 2020-04-17 14:40:56 +02:00
Marc Vertes
c580dfdbc8 fix: correct handling of interface types in composite literals 2020-04-16 19:54:03 +02:00
Marc Vertes
29e1777d82 fix: assign composite literal by reference 2020-04-16 12:24:04 +02:00
Marc Vertes
50a34fd2a7 fix: correct control flow graph for select blocks 2020-04-15 12:24:04 +02:00
Marc Vertes
465cb578e7 fix: lookup embededded field on struct pointer 2020-04-09 01:26:03 +02:00
Marc Vertes
12942b59a0 fix: remove ambiguities in recursive type processing 2020-04-09 01:14:03 +02:00
Marc Vertes
3e76267f8e fix: method search on struct pointer in interface wrapper 2020-04-07 17:22:04 +02:00
Marc Vertes
988f0c9672 fix: better handling of recursive types and forward declarations 2020-04-07 13:06:03 +02:00
Marc Vertes
b0053c874f fix: incomplete type analysis 2020-04-03 04:14:04 +02:00
Marc Vertes
b20ad3a01d fix: checks that value implements a binary type in type assert 2020-04-03 04:02:04 +02:00
84 changed files with 2040 additions and 347 deletions

9
_test/add0.go Normal file
View 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
View 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
View 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
View 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
View 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
View 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
View 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
View 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
View 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
View 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
View 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
View 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
View 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
View 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
View 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
View 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
View 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
View 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
View 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
View 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
View 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
View 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
View 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
View 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
View 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
View 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
View 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
View 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
View 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
View 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
View 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
View 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
View 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
View 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
View 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
View 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
View 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, &params); err != nil {
panic("marshal failed.")
}
fmt.Println(params["foo"], params["property"])
}
// Output:
// 1 test

26
_test/map25.go Normal file
View 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, &params); 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
View 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
View 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
View 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
View 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
View 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
View 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
View 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
View File

@@ -0,0 +1,10 @@
package main
import "fmt"
func main() {
fmt.Printf("%g\n", 1.0)
}
// Output:
// 1

View File

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

View File

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

View File

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

View File

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

View File

@@ -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(); {

View File

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

View File

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

View File

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

View File

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

View File

@@ -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",

View File

@@ -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(); {

View File

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

View File

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

View File

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

View File

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