Compare commits
30 Commits
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
4a068ea452 | ||
|
|
8605c238ef | ||
|
|
4f39eaf893 | ||
|
|
4f8e1de267 | ||
|
|
6f4643ff19 | ||
|
|
bb1be9e6e1 | ||
|
|
cdf4622421 | ||
|
|
b9720d15e1 | ||
|
|
7fab75fbe4 | ||
|
|
7eac6955b3 | ||
|
|
7070367d21 | ||
|
|
22dfc8b10a | ||
|
|
7fba3fe580 | ||
|
|
ff36ec58b1 | ||
|
|
f6c8b8b14f | ||
|
|
e12c8b72c4 | ||
|
|
e4acba031d | ||
|
|
7d56fb067e | ||
|
|
1feece61ce | ||
|
|
01e2e4600e | ||
|
|
92eebbade2 | ||
|
|
a6389aca5e | ||
|
|
de8cb7dc3b | ||
|
|
18b843646c | ||
|
|
71f730b3d7 | ||
|
|
7b2d91bcb5 | ||
|
|
3ed4ec3f6f | ||
|
|
5e142fdedd | ||
|
|
94d44e7265 | ||
|
|
56925e6fea |
@@ -39,7 +39,7 @@ install:
|
||||
- go mod download
|
||||
|
||||
before_script:
|
||||
- rm -f interp/op.go interp/interp_test.go
|
||||
- rm -f interp/op.go
|
||||
- make generate
|
||||
- git update-index -q --refresh
|
||||
- CHANGED=$(git diff-index --name-only HEAD --)
|
||||
|
||||
9
_test/add0.go
Normal file
9
_test/add0.go
Normal file
@@ -0,0 +1,9 @@
|
||||
package main
|
||||
|
||||
func main() {
|
||||
var a interface{} = 2 + 5
|
||||
println(a.(int))
|
||||
}
|
||||
|
||||
// Output:
|
||||
// 7
|
||||
10
_test/add1.go
Normal file
10
_test/add1.go
Normal file
@@ -0,0 +1,10 @@
|
||||
package main
|
||||
|
||||
func main() {
|
||||
b := 2
|
||||
var a interface{} = 5 + b
|
||||
println(a.(int))
|
||||
}
|
||||
|
||||
// Output:
|
||||
// 7
|
||||
12
_test/add2.go
Normal file
12
_test/add2.go
Normal file
@@ -0,0 +1,12 @@
|
||||
package main
|
||||
|
||||
type iface interface{}
|
||||
|
||||
func main() {
|
||||
b := 2
|
||||
var a iface = 5 + b
|
||||
println(a.(int))
|
||||
}
|
||||
|
||||
// Output:
|
||||
// 7
|
||||
14
_test/append0.go
Normal file
14
_test/append0.go
Normal file
@@ -0,0 +1,14 @@
|
||||
package main
|
||||
|
||||
import "fmt"
|
||||
|
||||
func f(a []int, b int) interface{} { return append(a, b) }
|
||||
|
||||
func main() {
|
||||
a := []int{1, 2}
|
||||
r := f(a, 3)
|
||||
fmt.Println(r.([]int))
|
||||
}
|
||||
|
||||
// Output:
|
||||
// [1 2 3]
|
||||
10
_test/assign11.go
Normal file
10
_test/assign11.go
Normal file
@@ -0,0 +1,10 @@
|
||||
package main
|
||||
|
||||
import "fmt"
|
||||
|
||||
func main() {
|
||||
_, _, _ = fmt.Println("test")
|
||||
}
|
||||
|
||||
// Error:
|
||||
// 6:2: assignment mismatch: 3 variables but fmt.Println returns 2 values
|
||||
11
_test/assign12.go
Normal file
11
_test/assign12.go
Normal file
@@ -0,0 +1,11 @@
|
||||
package main
|
||||
|
||||
import "fmt"
|
||||
|
||||
func main() {
|
||||
a, b, c := fmt.Println("test")
|
||||
println(a, b, c)
|
||||
}
|
||||
|
||||
// Error:
|
||||
// 6:2: assignment mismatch: 3 variables but fmt.Println returns 2 values
|
||||
18
_test/bin4.go
Normal file
18
_test/bin4.go
Normal file
@@ -0,0 +1,18 @@
|
||||
package main
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"strings"
|
||||
)
|
||||
|
||||
func Bar(s string) bool {
|
||||
a := strings.HasPrefix("fas", "f")
|
||||
b := strings.HasPrefix("aaaaa", "a")
|
||||
a_and_b := strings.HasPrefix("fas", "f") && strings.HasPrefix("aaaaa", "a")
|
||||
fmt.Println(a, b, a && b, a_and_b)
|
||||
return a && b
|
||||
}
|
||||
|
||||
func main() {
|
||||
println(Bar("kung"))
|
||||
}
|
||||
15
_test/bin5.go
Normal file
15
_test/bin5.go
Normal file
@@ -0,0 +1,15 @@
|
||||
package main
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"net"
|
||||
)
|
||||
|
||||
func main() {
|
||||
addr := net.TCPAddr{IP: net.IPv4(1, 1, 1, 1), Port: 80}
|
||||
var s fmt.Stringer = &addr
|
||||
fmt.Println(s.String())
|
||||
}
|
||||
|
||||
// Output:
|
||||
// 1.1.1.1:80
|
||||
13
_test/cap0.go
Normal file
13
_test/cap0.go
Normal file
@@ -0,0 +1,13 @@
|
||||
package main
|
||||
|
||||
func f(a []int) interface{} {
|
||||
return cap(a)
|
||||
}
|
||||
|
||||
func main() {
|
||||
a := []int{1, 2}
|
||||
println(f(a).(int))
|
||||
}
|
||||
|
||||
// Output:
|
||||
// 2
|
||||
9
_test/comp1.go
Normal file
9
_test/comp1.go
Normal file
@@ -0,0 +1,9 @@
|
||||
package main
|
||||
|
||||
func main() {
|
||||
var a interface{} = 1 < 2
|
||||
println(a.(bool))
|
||||
}
|
||||
|
||||
// Output:
|
||||
// true
|
||||
13
_test/complex4.go
Normal file
13
_test/complex4.go
Normal file
@@ -0,0 +1,13 @@
|
||||
package main
|
||||
|
||||
import "fmt"
|
||||
|
||||
func f(a, b float64) interface{} { return complex(a, b) }
|
||||
|
||||
func main() {
|
||||
a := f(3, 2)
|
||||
fmt.Println(a.(complex128))
|
||||
}
|
||||
|
||||
// Output:
|
||||
// (3+2i)
|
||||
13
_test/const11.go
Normal file
13
_test/const11.go
Normal file
@@ -0,0 +1,13 @@
|
||||
package main
|
||||
|
||||
func main() {
|
||||
const (
|
||||
x = 2 * iota
|
||||
dim
|
||||
)
|
||||
var t [dim * 2]int
|
||||
println(t[0], len(t))
|
||||
}
|
||||
|
||||
// Output:
|
||||
// 0 4
|
||||
17
_test/const12.go
Normal file
17
_test/const12.go
Normal file
@@ -0,0 +1,17 @@
|
||||
package main
|
||||
|
||||
type Kind int
|
||||
|
||||
const (
|
||||
None Kind = 0
|
||||
Left Kind = 1 << iota
|
||||
Right
|
||||
Both Kind = Left | Right
|
||||
)
|
||||
|
||||
func main() {
|
||||
println(None, Left, Right, Both)
|
||||
}
|
||||
|
||||
// Output:
|
||||
// 0 2 4 6
|
||||
16
_test/copy2.go
Normal file
16
_test/copy2.go
Normal file
@@ -0,0 +1,16 @@
|
||||
package main
|
||||
|
||||
import "fmt"
|
||||
|
||||
func f(a, b []int) interface{} { return copy(a, b) }
|
||||
|
||||
func main() {
|
||||
a := []int{10, 20, 30}
|
||||
b := [4]int{}
|
||||
c := b[:]
|
||||
r := f(c, a)
|
||||
fmt.Println(r.(int))
|
||||
}
|
||||
|
||||
// Output:
|
||||
// 3
|
||||
12
_test/fun12.go
Normal file
12
_test/fun12.go
Normal file
@@ -0,0 +1,12 @@
|
||||
package main
|
||||
|
||||
func use(interface{}) {}
|
||||
|
||||
func main() {
|
||||
z := map[string]interface{}{"a": 5}
|
||||
use(z)
|
||||
println("bye")
|
||||
}
|
||||
|
||||
// Output:
|
||||
// bye
|
||||
19
_test/fun13.go
Normal file
19
_test/fun13.go
Normal file
@@ -0,0 +1,19 @@
|
||||
package main
|
||||
|
||||
import "fmt"
|
||||
|
||||
type T struct{}
|
||||
|
||||
func newT() (T, error) { return T{}, nil }
|
||||
|
||||
func main() {
|
||||
var (
|
||||
i interface{}
|
||||
err error
|
||||
)
|
||||
i, err = newT()
|
||||
fmt.Println(i, err)
|
||||
}
|
||||
|
||||
// Output:
|
||||
// {} <nil>
|
||||
13
_test/fun14.go
Normal file
13
_test/fun14.go
Normal file
@@ -0,0 +1,13 @@
|
||||
package main
|
||||
|
||||
func f() (bool, int) { return true, 2 }
|
||||
|
||||
func g() (bool, int) { return f() }
|
||||
|
||||
func main() {
|
||||
b, i := g()
|
||||
println(b, i)
|
||||
}
|
||||
|
||||
// Output:
|
||||
// true 2
|
||||
11
_test/fun15.go
Normal file
11
_test/fun15.go
Normal file
@@ -0,0 +1,11 @@
|
||||
package main
|
||||
|
||||
func f1(a int) interface{} { return a + 1 }
|
||||
|
||||
func main() {
|
||||
c := f1(3)
|
||||
println(c.(int))
|
||||
}
|
||||
|
||||
// Output:
|
||||
// 4
|
||||
13
_test/fun16.go
Normal file
13
_test/fun16.go
Normal file
@@ -0,0 +1,13 @@
|
||||
package main
|
||||
|
||||
func f1(a int) int { return a + 1 }
|
||||
|
||||
func f2(a int) interface{} { return f1(a) }
|
||||
|
||||
func main() {
|
||||
c := f2(3)
|
||||
println(c.(int))
|
||||
}
|
||||
|
||||
// Output:
|
||||
// 4
|
||||
13
_test/fun17.go
Normal file
13
_test/fun17.go
Normal file
@@ -0,0 +1,13 @@
|
||||
package main
|
||||
|
||||
func f1(a int) interface{} { return a + 1 }
|
||||
|
||||
func f2(a int) interface{} { return f1(a) }
|
||||
|
||||
func main() {
|
||||
c := f2(3)
|
||||
println(c.(int))
|
||||
}
|
||||
|
||||
// Output:
|
||||
// 4
|
||||
12
_test/fun18.go
Normal file
12
_test/fun18.go
Normal file
@@ -0,0 +1,12 @@
|
||||
package main
|
||||
|
||||
var m = map[string]int{"foo": 1, "bar": 2}
|
||||
|
||||
func f(s string) interface{} { return m[s] }
|
||||
|
||||
func main() {
|
||||
println(f("foo").(int))
|
||||
}
|
||||
|
||||
// Output:
|
||||
// 1
|
||||
17
_test/fun19.go
Normal file
17
_test/fun19.go
Normal file
@@ -0,0 +1,17 @@
|
||||
package main
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
)
|
||||
|
||||
func foo() ([]string, error) {
|
||||
return nil, fmt.Errorf("bar")
|
||||
}
|
||||
|
||||
func main() {
|
||||
a, b := foo()
|
||||
fmt.Println(a, b)
|
||||
}
|
||||
|
||||
// Output:
|
||||
// [] bar
|
||||
19
_test/fun20.go
Normal file
19
_test/fun20.go
Normal file
@@ -0,0 +1,19 @@
|
||||
package main
|
||||
|
||||
import "fmt"
|
||||
|
||||
var myerr error = fmt.Errorf("bar")
|
||||
|
||||
func ferr() error { return myerr }
|
||||
|
||||
func foo() ([]string, error) {
|
||||
return nil, ferr()
|
||||
}
|
||||
|
||||
func main() {
|
||||
a, b := foo()
|
||||
fmt.Println(a, b)
|
||||
}
|
||||
|
||||
// Output:
|
||||
// [] bar
|
||||
12
_test/fun21.go
Normal file
12
_test/fun21.go
Normal file
@@ -0,0 +1,12 @@
|
||||
package main
|
||||
|
||||
func Bar() string {
|
||||
return
|
||||
}
|
||||
|
||||
func main() {
|
||||
println(Bar())
|
||||
}
|
||||
|
||||
// Error:
|
||||
// 4:2: not enough arguments to return
|
||||
10
_test/fun22.go
Normal file
10
_test/fun22.go
Normal file
@@ -0,0 +1,10 @@
|
||||
package main
|
||||
|
||||
import "time"
|
||||
|
||||
func main() {
|
||||
time.Date()
|
||||
}
|
||||
|
||||
// Error:
|
||||
// 6:2: not enough arguments in call to time.Date
|
||||
14
_test/imag0.go
Normal file
14
_test/imag0.go
Normal file
@@ -0,0 +1,14 @@
|
||||
package main
|
||||
|
||||
import "fmt"
|
||||
|
||||
func f(c complex128) interface{} { return imag(c) }
|
||||
|
||||
func main() {
|
||||
c := complex(3, 2)
|
||||
a := f(c)
|
||||
fmt.Println(a.(float64))
|
||||
}
|
||||
|
||||
// Output:
|
||||
// 2
|
||||
37
_test/interface36.go
Normal file
37
_test/interface36.go
Normal file
@@ -0,0 +1,37 @@
|
||||
package main
|
||||
|
||||
import "fmt"
|
||||
|
||||
var (
|
||||
t *S
|
||||
_ I = t
|
||||
_ J = t
|
||||
)
|
||||
|
||||
type S struct {
|
||||
Name string
|
||||
}
|
||||
|
||||
func (s *S) F() int { return len(s.Name) }
|
||||
func (s *S) G() int { return s.F() }
|
||||
func (s *S) Ri() I { return s }
|
||||
func (s *S) Rj() J { return s }
|
||||
|
||||
type J interface {
|
||||
I
|
||||
G() int
|
||||
Rj() J
|
||||
}
|
||||
|
||||
type I interface {
|
||||
F() int
|
||||
Ri() I
|
||||
}
|
||||
|
||||
func main() {
|
||||
var j J
|
||||
fmt.Println(j)
|
||||
}
|
||||
|
||||
// Output:
|
||||
// <nil>
|
||||
23
_test/interface37.go
Normal file
23
_test/interface37.go
Normal file
@@ -0,0 +1,23 @@
|
||||
package main
|
||||
|
||||
type I interface {
|
||||
A() string
|
||||
B() string
|
||||
}
|
||||
|
||||
type s struct{}
|
||||
|
||||
func NewS() (I, error) {
|
||||
return &s{}, nil
|
||||
}
|
||||
|
||||
func (c *s) A() string { return "a" }
|
||||
func (c *s) B() string { return "b" }
|
||||
|
||||
func main() {
|
||||
s, _ := NewS()
|
||||
println(s.A())
|
||||
}
|
||||
|
||||
// Output:
|
||||
// a
|
||||
19
_test/interface38.go
Normal file
19
_test/interface38.go
Normal file
@@ -0,0 +1,19 @@
|
||||
package main
|
||||
|
||||
import "fmt"
|
||||
|
||||
type foo struct {
|
||||
bar string
|
||||
}
|
||||
|
||||
func (f foo) String() string {
|
||||
return "Hello from " + f.bar
|
||||
}
|
||||
|
||||
func main() {
|
||||
var f fmt.Stringer = foo{bar: "bar"}
|
||||
fmt.Println(f)
|
||||
}
|
||||
|
||||
// Output:
|
||||
// Hello from bar
|
||||
19
_test/interface39.go
Normal file
19
_test/interface39.go
Normal file
@@ -0,0 +1,19 @@
|
||||
package main
|
||||
|
||||
import "fmt"
|
||||
|
||||
type foo struct {
|
||||
bar string
|
||||
}
|
||||
|
||||
func (f *foo) String() string {
|
||||
return "Hello from " + f.bar
|
||||
}
|
||||
|
||||
func main() {
|
||||
var f fmt.Stringer = &foo{bar: "bar"}
|
||||
fmt.Println(f)
|
||||
}
|
||||
|
||||
// Output:
|
||||
// Hello from bar
|
||||
23
_test/interface40.go
Normal file
23
_test/interface40.go
Normal file
@@ -0,0 +1,23 @@
|
||||
package main
|
||||
|
||||
import "fmt"
|
||||
|
||||
type foo struct {
|
||||
bar string
|
||||
}
|
||||
|
||||
func (f foo) String() string {
|
||||
return "Hello from " + f.bar
|
||||
}
|
||||
|
||||
func Foo(s string) fmt.Stringer {
|
||||
return foo{s}
|
||||
}
|
||||
|
||||
func main() {
|
||||
f := Foo("bar")
|
||||
fmt.Println(f)
|
||||
}
|
||||
|
||||
// Output:
|
||||
// Hello from bar
|
||||
23
_test/interface41.go
Normal file
23
_test/interface41.go
Normal file
@@ -0,0 +1,23 @@
|
||||
package main
|
||||
|
||||
import "fmt"
|
||||
|
||||
type foo struct {
|
||||
bar string
|
||||
}
|
||||
|
||||
func (f *foo) String() string {
|
||||
return "Hello from " + f.bar
|
||||
}
|
||||
|
||||
func Foo(s string) fmt.Stringer {
|
||||
return &foo{s}
|
||||
}
|
||||
|
||||
func main() {
|
||||
f := Foo("bar")
|
||||
fmt.Println(f)
|
||||
}
|
||||
|
||||
// Output:
|
||||
// Hello from bar
|
||||
13
_test/len0.go
Normal file
13
_test/len0.go
Normal file
@@ -0,0 +1,13 @@
|
||||
package main
|
||||
|
||||
func f(a []int) interface{} {
|
||||
return len(a)
|
||||
}
|
||||
|
||||
func main() {
|
||||
a := []int{1, 2}
|
||||
println(f(a).(int))
|
||||
}
|
||||
|
||||
// Output:
|
||||
// 2
|
||||
13
_test/make0.go
Normal file
13
_test/make0.go
Normal file
@@ -0,0 +1,13 @@
|
||||
package main
|
||||
|
||||
func f() interface{} {
|
||||
return make([]int, 2)
|
||||
}
|
||||
|
||||
func main() {
|
||||
a := f()
|
||||
println(len(a.([]int)))
|
||||
}
|
||||
|
||||
// Output:
|
||||
// 2
|
||||
15
_test/make1.go
Normal file
15
_test/make1.go
Normal file
@@ -0,0 +1,15 @@
|
||||
package main
|
||||
|
||||
import "fmt"
|
||||
|
||||
func f() interface{} {
|
||||
return make(map[int]int)
|
||||
}
|
||||
|
||||
func main() {
|
||||
a, ok := f().(map[int]int)
|
||||
fmt.Println(a, ok)
|
||||
}
|
||||
|
||||
// Output:
|
||||
// map[] true
|
||||
18
_test/map24.go
Normal file
18
_test/map24.go
Normal file
@@ -0,0 +1,18 @@
|
||||
package main
|
||||
|
||||
import (
|
||||
"encoding/json"
|
||||
"fmt"
|
||||
)
|
||||
|
||||
func main() {
|
||||
jb := []byte(`{"property": "test"}`)
|
||||
params := map[string]interface{}{"foo": 1}
|
||||
if err := json.Unmarshal(jb, ¶ms); err != nil {
|
||||
panic("marshal failed.")
|
||||
}
|
||||
fmt.Println(params["foo"], params["property"])
|
||||
}
|
||||
|
||||
// Output:
|
||||
// 1 test
|
||||
26
_test/map25.go
Normal file
26
_test/map25.go
Normal file
@@ -0,0 +1,26 @@
|
||||
package main
|
||||
|
||||
import (
|
||||
"encoding/json"
|
||||
"strconv"
|
||||
)
|
||||
|
||||
func main() {
|
||||
jb := []byte(`{"num": "2"}`)
|
||||
params := map[string]interface{}{"foo": "1"}
|
||||
if err := json.Unmarshal(jb, ¶ms); err != nil {
|
||||
panic(err)
|
||||
}
|
||||
sum := 0
|
||||
for _, v := range params {
|
||||
i, err := strconv.Atoi(v.(string))
|
||||
if err != nil {
|
||||
panic(err)
|
||||
}
|
||||
sum += i
|
||||
}
|
||||
println(sum)
|
||||
}
|
||||
|
||||
// Output:
|
||||
// 3
|
||||
11
_test/map26.go
Normal file
11
_test/map26.go
Normal file
@@ -0,0 +1,11 @@
|
||||
package main
|
||||
|
||||
var m = map[string]int{"foo": 1, "bar": 2}
|
||||
|
||||
func main() {
|
||||
var a interface{} = m["foo"]
|
||||
println(a.(int))
|
||||
}
|
||||
|
||||
// Output:
|
||||
// 1
|
||||
24
_test/map27.go
Normal file
24
_test/map27.go
Normal file
@@ -0,0 +1,24 @@
|
||||
package main
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"text/template"
|
||||
)
|
||||
|
||||
type fm map[string]interface{}
|
||||
|
||||
type foo struct{}
|
||||
|
||||
func main() {
|
||||
a := make(fm)
|
||||
a["foo"] = &foo{}
|
||||
fmt.Println(a["foo"])
|
||||
|
||||
b := make(template.FuncMap) // type FuncMap map[string]interface{}
|
||||
b["foo"] = &foo{}
|
||||
fmt.Println(b["foo"])
|
||||
}
|
||||
|
||||
// Output:
|
||||
// &{}
|
||||
// &{}
|
||||
21
_test/map28.go
Normal file
21
_test/map28.go
Normal file
@@ -0,0 +1,21 @@
|
||||
package main
|
||||
|
||||
import (
|
||||
"net/url"
|
||||
)
|
||||
|
||||
func main() {
|
||||
value1 := url.Values{}
|
||||
|
||||
value1.Set("first", "v1")
|
||||
value1.Set("second", "v2")
|
||||
|
||||
l := 0
|
||||
for k, v := range value1 {
|
||||
l += len(k) + len(v)
|
||||
}
|
||||
println(l)
|
||||
}
|
||||
|
||||
// Output:
|
||||
// 13
|
||||
13
_test/new2.go
Normal file
13
_test/new2.go
Normal file
@@ -0,0 +1,13 @@
|
||||
package main
|
||||
|
||||
func f() interface{} {
|
||||
return new(int)
|
||||
}
|
||||
|
||||
func main() {
|
||||
a := f()
|
||||
println(*(a.(*int)))
|
||||
}
|
||||
|
||||
// Output:
|
||||
// 0
|
||||
12
_test/nil2.go
Normal file
12
_test/nil2.go
Normal file
@@ -0,0 +1,12 @@
|
||||
package main
|
||||
|
||||
func test() error { return nil }
|
||||
|
||||
func main() {
|
||||
if err := test(); nil == err {
|
||||
println("err is nil")
|
||||
}
|
||||
}
|
||||
|
||||
// Output:
|
||||
// err is nil
|
||||
16
_test/not0.go
Normal file
16
_test/not0.go
Normal file
@@ -0,0 +1,16 @@
|
||||
package main
|
||||
|
||||
func main() {
|
||||
a := 0
|
||||
b := true
|
||||
c := false
|
||||
if b && c {
|
||||
a = 1
|
||||
} else {
|
||||
a = -1
|
||||
}
|
||||
println(a)
|
||||
}
|
||||
|
||||
// Output:
|
||||
// -1
|
||||
15
_test/not1.go
Normal file
15
_test/not1.go
Normal file
@@ -0,0 +1,15 @@
|
||||
package main
|
||||
|
||||
func main() {
|
||||
a := 0
|
||||
b := true
|
||||
if (!b) {
|
||||
a = 1
|
||||
} else {
|
||||
a = -1
|
||||
}
|
||||
println(a)
|
||||
}
|
||||
|
||||
// Output:
|
||||
// -1
|
||||
9
_test/not2.go
Normal file
9
_test/not2.go
Normal file
@@ -0,0 +1,9 @@
|
||||
package main
|
||||
|
||||
func main() {
|
||||
var b interface{} = !(1 == 2)
|
||||
println(b.(bool))
|
||||
}
|
||||
|
||||
// Output:
|
||||
// true
|
||||
10
_test/num0.go
Normal file
10
_test/num0.go
Normal file
@@ -0,0 +1,10 @@
|
||||
package main
|
||||
|
||||
import "fmt"
|
||||
|
||||
func main() {
|
||||
fmt.Printf("%g\n", 1.0)
|
||||
}
|
||||
|
||||
// Output:
|
||||
// 1
|
||||
@@ -1,9 +1,9 @@
|
||||
package main
|
||||
|
||||
func main() {
|
||||
i := 100
|
||||
println(i % 1e2)
|
||||
i := 102
|
||||
println(i % -1e2)
|
||||
}
|
||||
|
||||
// Output:
|
||||
// 0
|
||||
// 2
|
||||
|
||||
12
_test/op5.go
Normal file
12
_test/op5.go
Normal file
@@ -0,0 +1,12 @@
|
||||
package main
|
||||
|
||||
import "fmt"
|
||||
|
||||
func main() {
|
||||
i := 100
|
||||
j := i % 1e2
|
||||
fmt.Printf("%T %v\n", j, j)
|
||||
}
|
||||
|
||||
// Output:
|
||||
// int 0
|
||||
14
_test/real0.go
Normal file
14
_test/real0.go
Normal file
@@ -0,0 +1,14 @@
|
||||
package main
|
||||
|
||||
import "fmt"
|
||||
|
||||
func f(c complex128) interface{} { return real(c) }
|
||||
|
||||
func main() {
|
||||
c := complex(3, 2)
|
||||
a := f(c)
|
||||
fmt.Println(a.(float64))
|
||||
}
|
||||
|
||||
// Output:
|
||||
// 3
|
||||
14
_test/select10.go
Normal file
14
_test/select10.go
Normal file
@@ -0,0 +1,14 @@
|
||||
package main
|
||||
|
||||
func main() {
|
||||
c := make(chan string)
|
||||
select {
|
||||
case <-c:
|
||||
println("unexpected")
|
||||
default:
|
||||
}
|
||||
println("bye")
|
||||
}
|
||||
|
||||
// Output:
|
||||
// bye
|
||||
16
_test/select11.go
Normal file
16
_test/select11.go
Normal file
@@ -0,0 +1,16 @@
|
||||
package main
|
||||
|
||||
func main() {
|
||||
c := make(chan string)
|
||||
select {
|
||||
case <-c:
|
||||
println("unexpected")
|
||||
default:
|
||||
println("nothing received")
|
||||
}
|
||||
println("bye")
|
||||
}
|
||||
|
||||
// Output:
|
||||
// nothing received
|
||||
// bye
|
||||
@@ -15,3 +15,6 @@ func main() {
|
||||
_, err := c.Get("url")
|
||||
println(strings.Contains(err.Error(), "unsupported protocol scheme"))
|
||||
}
|
||||
|
||||
// Output:
|
||||
// true
|
||||
|
||||
@@ -14,4 +14,5 @@ func main() {
|
||||
println(t.b)
|
||||
}
|
||||
|
||||
// Output: true
|
||||
// Output:
|
||||
// true
|
||||
|
||||
13
_test/switch34.go
Normal file
13
_test/switch34.go
Normal file
@@ -0,0 +1,13 @@
|
||||
package main
|
||||
|
||||
func main() {
|
||||
var a interface{}
|
||||
switch a.(type) {
|
||||
case []int:
|
||||
case []string:
|
||||
}
|
||||
println("bye")
|
||||
}
|
||||
|
||||
// Output:
|
||||
// bye
|
||||
17
_test/switch35.go
Normal file
17
_test/switch35.go
Normal file
@@ -0,0 +1,17 @@
|
||||
package main
|
||||
|
||||
func main() {
|
||||
a := 2
|
||||
switch {
|
||||
case a == 1:
|
||||
println(1)
|
||||
case a == 2:
|
||||
println(2)
|
||||
default:
|
||||
}
|
||||
println("bye")
|
||||
}
|
||||
|
||||
// Output:
|
||||
// 2
|
||||
// bye
|
||||
14
_test/switch36.go
Normal file
14
_test/switch36.go
Normal file
@@ -0,0 +1,14 @@
|
||||
package main
|
||||
|
||||
func main() {
|
||||
a := 2
|
||||
switch {
|
||||
case a == 1:
|
||||
println(1)
|
||||
case a == 2:
|
||||
}
|
||||
println("bye")
|
||||
}
|
||||
|
||||
// Output:
|
||||
// bye
|
||||
15
_test/switch37.go
Normal file
15
_test/switch37.go
Normal file
@@ -0,0 +1,15 @@
|
||||
package main
|
||||
|
||||
func main() {
|
||||
a := 2
|
||||
switch {
|
||||
case a == 1:
|
||||
println(1)
|
||||
case a == 3:
|
||||
default:
|
||||
}
|
||||
println("bye")
|
||||
}
|
||||
|
||||
// Output:
|
||||
// bye
|
||||
15
_test/time12.go
Normal file
15
_test/time12.go
Normal file
@@ -0,0 +1,15 @@
|
||||
package main
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"time"
|
||||
)
|
||||
|
||||
var twentyFourHours = time.Duration(24 * time.Hour)
|
||||
|
||||
func main() {
|
||||
fmt.Println(twentyFourHours.Hours())
|
||||
}
|
||||
|
||||
// Output:
|
||||
// 24
|
||||
16
_test/type21.go
Normal file
16
_test/type21.go
Normal file
@@ -0,0 +1,16 @@
|
||||
package main
|
||||
|
||||
import (
|
||||
"reflect"
|
||||
"time"
|
||||
)
|
||||
|
||||
func main() {
|
||||
t := time.Date(2009, time.November, 10, 23, 4, 5, 0, time.UTC)
|
||||
v := reflect.ValueOf(t.String)
|
||||
f := v.Interface().(func() string)
|
||||
println(f())
|
||||
}
|
||||
|
||||
// Output:
|
||||
// 2009-11-10 23:04:05 +0000 UTC
|
||||
18
_test/type22.go
Normal file
18
_test/type22.go
Normal file
@@ -0,0 +1,18 @@
|
||||
package main
|
||||
|
||||
type T1 T
|
||||
|
||||
func foo() T1 {
|
||||
return T1(T{"foo"})
|
||||
}
|
||||
|
||||
type T struct {
|
||||
Name string
|
||||
}
|
||||
|
||||
func main() {
|
||||
println(foo().Name)
|
||||
}
|
||||
|
||||
// Output:
|
||||
// foo
|
||||
20
_test/variadic6.go
Normal file
20
_test/variadic6.go
Normal file
@@ -0,0 +1,20 @@
|
||||
package main
|
||||
|
||||
import "fmt"
|
||||
|
||||
type A struct {
|
||||
}
|
||||
|
||||
func (a A) f(vals ...bool) {
|
||||
for _, v := range vals {
|
||||
fmt.Println(v)
|
||||
}
|
||||
}
|
||||
func main() {
|
||||
bools := []bool{true}
|
||||
a := A{}
|
||||
a.f(bools...)
|
||||
}
|
||||
|
||||
// Output:
|
||||
// true
|
||||
@@ -1,22 +1,66 @@
|
||||
/*
|
||||
Yaegi interprets Go programs.
|
||||
|
||||
Yaegi reads Go language programs from its standard input or from a file
|
||||
and evaluates them.
|
||||
Yaegi reads Go language programs from standard input, string
|
||||
parameters or files and run them.
|
||||
|
||||
If invoked with no arguments, it processes the standard input
|
||||
in a Read-Eval-Print-Loop. A prompt is displayed if standard input
|
||||
is a terminal.
|
||||
If invoked with no arguments, it processes the standard input in
|
||||
a Read-Eval-Print-Loop. A prompt is displayed if standard input is
|
||||
a terminal.
|
||||
|
||||
Given a file, it operates on that file. If the first line starts with
|
||||
"#!/usr/bin/env yaegi", and the file has exec permission, then the file
|
||||
can be invoked directly from the shell.
|
||||
File Mode
|
||||
|
||||
In file mode, as in standard Go, files are read entirely, then parsed,
|
||||
then evaluated. In REPL mode, each line is parsed and evaluated separately,
|
||||
at global level in an implicit main package.
|
||||
In file mode, as in a standard Go compiler, source files are read entirely
|
||||
before being parsed, then evaluated. It allows to handle forward
|
||||
declarations and to have package code split in multiple source files.
|
||||
|
||||
Go specifications fully apply in this mode.
|
||||
|
||||
All files are interpreted in file mode except the initial file if it
|
||||
starts with "#!" characters (the shebang pattern to allow executable
|
||||
scripts), for example "#!/usr/bin/env yaegi". In that case, the initial
|
||||
file is interpreted in REPL mode.
|
||||
|
||||
REPL mode
|
||||
|
||||
In REPL mode, the interpreter parses the code incrementally. As soon
|
||||
as a statement is complete, it evaluates it. This makes the interpreter
|
||||
suitable for interactive command line and scripts.
|
||||
|
||||
Go specifications apply with the following differences:
|
||||
|
||||
All local and global declarations (const, var, type, func) are allowed,
|
||||
including in short form, except that all identifiers must be defined
|
||||
before use (as declarations inside a standard Go function).
|
||||
|
||||
The statements are evaluated in the global space, within an implicit
|
||||
"main" package.
|
||||
|
||||
It is not necessary to have a package statement, or a main function in
|
||||
REPL mode. Import statements for preloaded binary packages can also
|
||||
be avoided (i.e. all the standard library except the few packages
|
||||
where default names collide, as "math/rand" and "crypto/rand", for which
|
||||
an explicit import is still necessary).
|
||||
|
||||
Note that the source packages are always interpreted in file mode,
|
||||
even if imported from REPL.
|
||||
|
||||
The following extract is a valid executable script:
|
||||
|
||||
#!/usr/bin/env yaegi
|
||||
helloHandler := func(w http.ResponseWriter, req *http.Request) {
|
||||
io.WriteString(w, "Hello, world!\n")
|
||||
}
|
||||
http.HandleFunc("/hello", helloHandler)
|
||||
log.Fatal(http.ListenAndServe(":8080", nil))
|
||||
|
||||
Example of a one liner:
|
||||
|
||||
$ yaegi -e 'println(reflect.TypeOf(fmt.Print))'
|
||||
|
||||
Options:
|
||||
-e string
|
||||
evaluate the string and return.
|
||||
-i
|
||||
start an interactive REPL after file execution.
|
||||
-tags tag,list
|
||||
@@ -84,17 +128,19 @@ func main() {
|
||||
log.Fatal("Could not read file: ", args[0])
|
||||
}
|
||||
|
||||
s := string(b)
|
||||
if s[:2] == "#!" {
|
||||
// Allow executable go scripts, but fix them prior to parse
|
||||
if s := string(b); strings.HasPrefix(s, "#!") {
|
||||
// Allow executable go scripts, Have the same behavior as in interactive mode.
|
||||
s = strings.Replace(s, "#!", "//", 1)
|
||||
}
|
||||
|
||||
i.Name = args[0]
|
||||
if _, err := i.Eval(s); err != nil {
|
||||
fmt.Println(err)
|
||||
if p, ok := err.(interp.Panic); ok {
|
||||
fmt.Println(string(p.Stack))
|
||||
i.REPL(strings.NewReader(s), os.Stdout)
|
||||
} else {
|
||||
// Files not starting with "#!" are supposed to be pure Go, directly Evaled.
|
||||
i.Name = args[0]
|
||||
_, err := i.Eval(s)
|
||||
if err != nil {
|
||||
fmt.Println(err)
|
||||
if p, ok := err.(interp.Panic); ok {
|
||||
fmt.Println(string(p.Stack))
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -84,7 +84,7 @@ func TestYaegiCmdCancel(t *testing.T) {
|
||||
continue
|
||||
}
|
||||
|
||||
if outBuf.String() != "context canceled\n2\n" {
|
||||
if outBuf.String() != "context canceled\n" {
|
||||
t.Errorf("unexpected output: %q", &outBuf)
|
||||
}
|
||||
}
|
||||
|
||||
@@ -17,9 +17,9 @@ import "reflect"
|
||||
// Arithmetic operators
|
||||
{{range $name, $op := .Arithmetic}}
|
||||
func {{$name}}(n *node) {
|
||||
dest := genValue(n)
|
||||
next := getExec(n.tnext)
|
||||
typ := n.typ.TypeOf()
|
||||
typ := n.typ.concrete().TypeOf()
|
||||
dest := genValueOutput(n, typ)
|
||||
c0, c1 := n.child[0], n.child[1]
|
||||
|
||||
switch typ.Kind() {
|
||||
@@ -379,7 +379,7 @@ func {{$name}}Const(n *node) {
|
||||
{{range $name, $op := .Comparison}}
|
||||
func {{$name}}(n *node) {
|
||||
tnext := getExec(n.tnext)
|
||||
dest := genValue(n)
|
||||
dest := genValueOutput(n, reflect.TypeOf(true))
|
||||
c0, c1 := n.child[0], n.child[1]
|
||||
|
||||
switch t0, t1 := c0.typ.TypeOf(), c1.typ.TypeOf(); {
|
||||
|
||||
@@ -6,7 +6,6 @@ import (
|
||||
"go/parser"
|
||||
"go/scanner"
|
||||
"go/token"
|
||||
"math"
|
||||
"reflect"
|
||||
"strconv"
|
||||
"sync/atomic"
|
||||
@@ -196,15 +195,19 @@ const (
|
||||
aAndNot
|
||||
aAndNotAssign
|
||||
aBitNot
|
||||
aBranch
|
||||
aCall
|
||||
aCase
|
||||
aCompositeLit
|
||||
aConvert
|
||||
aDec
|
||||
aEqual
|
||||
aGreater
|
||||
aGreaterEqual
|
||||
aGetFunc
|
||||
aGetIndex
|
||||
aGetMethod
|
||||
aGetSym
|
||||
aInc
|
||||
aLand
|
||||
aLor
|
||||
@@ -253,14 +256,18 @@ var actions = [...]string{
|
||||
aAndNot: "&^",
|
||||
aAndNotAssign: "&^=",
|
||||
aBitNot: "^",
|
||||
aBranch: "branch",
|
||||
aCall: "call",
|
||||
aCase: "case",
|
||||
aCompositeLit: "compositeLit",
|
||||
aConvert: "convert",
|
||||
aDec: "--",
|
||||
aEqual: "==",
|
||||
aGreater: ">",
|
||||
aGetFunc: "getFunc",
|
||||
aGetIndex: "getIndex",
|
||||
aGetMethod: "getMethod",
|
||||
aGetSym: ".",
|
||||
aInc: "++",
|
||||
aLand: "&&",
|
||||
aLor: "||",
|
||||
@@ -464,11 +471,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))
|
||||
|
||||
342
interp/cfg.go
342
interp/cfg.go
@@ -50,7 +50,6 @@ var identifier = regexp.MustCompile(`([\pL_][\pL_\d]*)$`)
|
||||
func (interp *Interpreter) cfg(root *node, pkgID string) ([]*node, error) {
|
||||
sc := interp.initScopePkg(pkgID)
|
||||
var initNodes []*node
|
||||
var iotaValue int
|
||||
var err error
|
||||
|
||||
root.Walk(func(n *node) bool {
|
||||
@@ -90,6 +89,8 @@ func (interp *Interpreter) cfg(root *node, pkgID string) ([]*node, error) {
|
||||
switch typ.Kind() {
|
||||
case reflect.Map:
|
||||
n.anc.gen = rangeMap
|
||||
ityp := &itype{cat: valueT, rtype: reflect.TypeOf((*reflect.MapIter)(nil))}
|
||||
sc.add(ityp)
|
||||
ktyp = &itype{cat: valueT, rtype: typ.Key()}
|
||||
vtyp = &itype{cat: valueT, rtype: typ.Elem()}
|
||||
case reflect.String:
|
||||
@@ -204,7 +205,7 @@ 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]
|
||||
var typ *itype
|
||||
if typ, err = nodeType(interp, sc, ch); err != nil {
|
||||
@@ -370,6 +371,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
|
||||
@@ -496,6 +509,12 @@ func (interp *Interpreter) cfg(root *node, pkgID string) ([]*node, error) {
|
||||
src.findex = dest.findex // Set recv address to LHS
|
||||
dest.typ = src.typ
|
||||
case n.action == aAssign && src.action == aCompositeLit:
|
||||
if dest.typ.cat == valueT && dest.typ.rtype.Kind() == reflect.Interface {
|
||||
// No optimisation attempt for assigned binary interface
|
||||
break
|
||||
}
|
||||
// Skip the assign operation entirely, the source frame index is set
|
||||
// to destination index, avoiding extra memory alloc and duplication.
|
||||
n.gen = nop
|
||||
src.findex = dest.findex
|
||||
src.level = level
|
||||
@@ -525,7 +544,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++
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -542,22 +565,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
|
||||
}
|
||||
}
|
||||
@@ -565,7 +594,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)
|
||||
@@ -575,8 +604,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
|
||||
@@ -590,10 +619,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)
|
||||
@@ -620,33 +654,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)
|
||||
}
|
||||
|
||||
@@ -654,7 +690,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()}
|
||||
@@ -702,11 +738,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:
|
||||
@@ -749,14 +781,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):
|
||||
@@ -764,6 +800,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]
|
||||
@@ -783,7 +820,23 @@ func (interp *Interpreter) cfg(root *node, pkgID string) ([]*node, error) {
|
||||
}
|
||||
case isBinCall(n):
|
||||
n.gen = callBin
|
||||
if typ := n.child[0].typ.rtype; typ.NumOut() > 0 {
|
||||
typ := n.child[0].typ.rtype
|
||||
numIn := len(n.child) - 1
|
||||
tni := typ.NumIn()
|
||||
if numIn == 1 && n.child[1].action == aCall {
|
||||
numIn = n.child[1].typ.numOut()
|
||||
}
|
||||
if n.child[0].action == aGetMethod {
|
||||
tni-- // The first argument is the method receiver.
|
||||
}
|
||||
if typ.IsVariadic() {
|
||||
tni-- // The last argument could be empty.
|
||||
}
|
||||
if numIn < tni {
|
||||
err = n.cfgErrorf("not enough arguments in call to %v", n.child[0].name())
|
||||
break
|
||||
}
|
||||
if typ.NumOut() > 0 {
|
||||
if funcType := n.child[0].typ.val; funcType != nil {
|
||||
// Use the original unwrapped function type, to allow future field and
|
||||
// methods resolutions, otherwise impossible on the opaque bin type.
|
||||
@@ -794,22 +847,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
|
||||
@@ -822,7 +883,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
|
||||
@@ -833,19 +894,21 @@ 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
|
||||
sc = sc.pop()
|
||||
|
||||
case compositeLitExpr:
|
||||
wireChild(n)
|
||||
if n.anc.action != aAssign {
|
||||
n.findex = sc.add(n.typ)
|
||||
}
|
||||
n.findex = sc.add(n.typ)
|
||||
// TODO: Check that composite literal expr matches corresponding type
|
||||
n.gen = compositeGenerator(n, sc)
|
||||
|
||||
@@ -881,7 +944,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; {}
|
||||
@@ -903,7 +966,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 {}
|
||||
@@ -922,7 +985,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()
|
||||
|
||||
@@ -953,13 +1016,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:
|
||||
@@ -998,7 +1061,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
|
||||
@@ -1010,9 +1073,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
|
||||
@@ -1035,7 +1095,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()
|
||||
|
||||
@@ -1054,7 +1114,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
|
||||
@@ -1078,7 +1138,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 {}
|
||||
@@ -1097,7 +1157,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
|
||||
@@ -1109,7 +1169,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)
|
||||
@@ -1120,7 +1180,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)
|
||||
@@ -1158,6 +1218,16 @@ func (interp *Interpreter) cfg(root *node, pkgID string) ([]*node, error) {
|
||||
}
|
||||
|
||||
case returnStmt:
|
||||
if mustReturnValue(sc.def.child[2]) {
|
||||
nret := len(n.child)
|
||||
if nret == 1 && n.child[0].action == aCall {
|
||||
nret = n.child[0].child[0].typ.numOut()
|
||||
}
|
||||
if nret < sc.def.typ.numOut() {
|
||||
err = n.cfgErrorf("not enough arguments to return")
|
||||
break
|
||||
}
|
||||
}
|
||||
wireChild(n)
|
||||
n.tnext = nil
|
||||
n.val = sc.def
|
||||
@@ -1194,6 +1264,7 @@ func (interp *Interpreter) cfg(root *node, pkgID string) ([]*node, error) {
|
||||
case ok:
|
||||
n.val = method.Index
|
||||
n.gen = getIndexBinMethod
|
||||
n.action = aGetMethod
|
||||
n.recv = &receiver{node: n.child[0]}
|
||||
n.typ = &itype{cat: valueT, rtype: method.Type, isBinMethod: true}
|
||||
case n.typ.rtype.Kind() == reflect.Ptr:
|
||||
@@ -1217,6 +1288,7 @@ func (interp *Interpreter) cfg(root *node, pkgID string) ([]*node, error) {
|
||||
n.gen = getIndexBinPtrMethod
|
||||
n.typ = &itype{cat: valueT, rtype: m2.Type}
|
||||
n.recv = &receiver{node: n.child[0]}
|
||||
n.action = aGetMethod
|
||||
} else {
|
||||
err = n.cfgErrorf("undefined field or method: %s", n.child[1].ident)
|
||||
}
|
||||
@@ -1231,11 +1303,13 @@ func (interp *Interpreter) cfg(root *node, pkgID string) ([]*node, error) {
|
||||
n.typ = &itype{cat: valueT, rtype: method.Type}
|
||||
n.recv = &receiver{node: n.child[0]}
|
||||
n.gen = getIndexBinMethod
|
||||
n.action = aGetMethod
|
||||
} else if method, ok := reflect.PtrTo(n.typ.val.rtype).MethodByName(n.child[1].ident); ok {
|
||||
n.val = method.Index
|
||||
n.gen = getIndexBinMethod
|
||||
n.typ = &itype{cat: valueT, rtype: method.Type}
|
||||
n.recv = &receiver{node: n.child[0]}
|
||||
n.action = aGetMethod
|
||||
} else if field, ok := n.typ.val.rtype.FieldByName(n.child[1].ident); ok {
|
||||
n.typ = &itype{cat: valueT, rtype: field.Type}
|
||||
n.val = field.Index
|
||||
@@ -1254,6 +1328,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)
|
||||
@@ -1265,6 +1340,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
|
||||
@@ -1272,6 +1348,7 @@ func (interp *Interpreter) cfg(root *node, pkgID string) ([]*node, error) {
|
||||
err = n.cfgErrorf("undefined selector: %s.%s", pkg, name)
|
||||
}
|
||||
} else if m, lind := n.typ.lookupMethod(n.child[1].ident); m != nil {
|
||||
n.action = aGetMethod
|
||||
if n.child[0].isType(sc) {
|
||||
// Handle method as a function with receiver in 1st argument
|
||||
n.val = m
|
||||
@@ -1288,6 +1365,7 @@ func (interp *Interpreter) cfg(root *node, pkgID string) ([]*node, error) {
|
||||
n.recv = &receiver{node: n.child[0], index: lind}
|
||||
}
|
||||
} else if m, lind, isPtr, ok := n.typ.lookupBinMethod(n.child[1].ident); ok {
|
||||
n.action = aGetMethod
|
||||
if isPtr && n.typ.fieldSeq(lind).cat != ptrT {
|
||||
n.gen = getIndexSeqPtrMethod
|
||||
} else {
|
||||
@@ -1342,14 +1420,15 @@ func (interp *Interpreter) cfg(root *node, pkgID string) ([]*node, error) {
|
||||
var cur *node
|
||||
for _, c := range n.child[0].child {
|
||||
var an *node // channel init action node
|
||||
c0 := c.child[0]
|
||||
switch {
|
||||
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 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 {
|
||||
@@ -1423,7 +1502,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 {
|
||||
@@ -1444,6 +1524,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 {
|
||||
@@ -1467,24 +1548,29 @@ func (interp *Interpreter) cfg(root *node, pkgID string) ([]*node, error) {
|
||||
for i := l - 1; i >= 0; i-- {
|
||||
c := clauses[i]
|
||||
c.gen = nop
|
||||
body := c.lastChild()
|
||||
if len(c.child) > 1 {
|
||||
cond := c.child[0]
|
||||
cond.tnext = body.start
|
||||
if i == l-1 {
|
||||
cond.fnext = n
|
||||
if len(c.child) == 0 {
|
||||
c.tnext = n
|
||||
c.fnext = n
|
||||
} else {
|
||||
body := c.lastChild()
|
||||
if len(c.child) > 1 {
|
||||
cond := c.child[0]
|
||||
cond.tnext = body.start
|
||||
if i == l-1 {
|
||||
setFNext(cond, n)
|
||||
} else {
|
||||
setFNext(cond, clauses[i+1].start)
|
||||
}
|
||||
c.start = cond.start
|
||||
} else {
|
||||
cond.fnext = clauses[i+1].start
|
||||
c.start = body.start
|
||||
}
|
||||
// If last case body statement is a fallthrough, then jump to next case body
|
||||
if i < l-1 && len(body.child) > 0 && body.lastChild().kind == fallthroughtStmt {
|
||||
body.tnext = clauses[i+1].lastChild().start
|
||||
} else {
|
||||
body.tnext = n
|
||||
}
|
||||
c.start = cond.start
|
||||
} else {
|
||||
c.start = body.start
|
||||
}
|
||||
// If last case body statement is a fallthrough, then jump to next case body
|
||||
if i < l-1 && len(body.child) > 0 && body.lastChild().kind == fallthroughtStmt {
|
||||
body.tnext = clauses[i+1].lastChild().start
|
||||
} else {
|
||||
body.tnext = n
|
||||
}
|
||||
}
|
||||
sbn.start = clauses[0].start
|
||||
@@ -1500,7 +1586,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 {
|
||||
@@ -1541,13 +1632,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)
|
||||
}
|
||||
@@ -1564,11 +1655,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)
|
||||
}
|
||||
|
||||
@@ -1619,6 +1705,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:
|
||||
@@ -1703,15 +1795,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.
|
||||
@@ -1799,12 +1895,22 @@ 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()) {
|
||||
return true
|
||||
}
|
||||
if n.typ.untyped && n.rval.IsValid() {
|
||||
if n.rval.IsValid() {
|
||||
t := n.rval.Type()
|
||||
if isInt(t) {
|
||||
return true
|
||||
@@ -1827,7 +1933,7 @@ func (n *node) isNatural() bool {
|
||||
if isUint(n.typ.TypeOf()) {
|
||||
return true
|
||||
}
|
||||
if n.typ.untyped && n.rval.IsValid() {
|
||||
if n.rval.IsValid() {
|
||||
t := n.rval.Type()
|
||||
if isUint(t) {
|
||||
return true
|
||||
@@ -1915,13 +2021,25 @@ 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 {
|
||||
return n.kind == callExpr && n.child[0].typ.cat == valueT && n.child[0].typ.rtype.Kind() == reflect.Func
|
||||
}
|
||||
|
||||
func mustReturnValue(n *node) bool {
|
||||
if len(n.child) < 2 {
|
||||
return false
|
||||
}
|
||||
for _, f := range n.child[1].child {
|
||||
if len(f.child) > 1 {
|
||||
return false
|
||||
}
|
||||
}
|
||||
return true
|
||||
}
|
||||
|
||||
func isRegularCall(n *node) bool {
|
||||
return n.kind == callExpr && n.child[0].typ.cat == funcT
|
||||
}
|
||||
|
||||
@@ -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.
|
||||
@@ -80,7 +78,11 @@ func (interp *Interpreter) gta(root *node, rpath, 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++
|
||||
}
|
||||
}
|
||||
}
|
||||
return false
|
||||
@@ -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, scope: sc}
|
||||
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
|
||||
|
||||
@@ -455,16 +455,34 @@ func (interp *Interpreter) Use(values Exports) {
|
||||
// REPL performs a Read-Eval-Print-Loop on input reader.
|
||||
// Results are printed on output writer.
|
||||
func (interp *Interpreter) REPL(in io.Reader, out io.Writer) {
|
||||
s := bufio.NewScanner(in)
|
||||
// Preimport used bin packages, to avoid having to import these packages manually
|
||||
// in REPL mode. These packages are already loaded anyway.
|
||||
sc := interp.universe
|
||||
for k := range interp.binPkg {
|
||||
name := identifier.FindString(k)
|
||||
if name == "" || name == "rand" || name == "scanner" || name == "template" || name == "pprof" {
|
||||
// Skip any package with an ambiguous name (i.e crypto/rand vs math/rand).
|
||||
// Those will have to be imported explicitly.
|
||||
continue
|
||||
}
|
||||
sc.sym[name] = &symbol{kind: pkgSym, typ: &itype{cat: binPkgT, path: k, scope: sc}}
|
||||
}
|
||||
|
||||
// Set prompt.
|
||||
var v reflect.Value
|
||||
var err error
|
||||
prompt := getPrompt(in, out)
|
||||
prompt()
|
||||
prompt(v)
|
||||
|
||||
// Read, Eval, Print in a Loop.
|
||||
src := ""
|
||||
s := bufio.NewScanner(in)
|
||||
for s.Scan() {
|
||||
src += s.Text() + "\n"
|
||||
ctx, cancel := context.WithCancel(context.Background())
|
||||
defer cancel()
|
||||
handleSignal(ctx, cancel)
|
||||
v, err := interp.EvalWithContext(ctx, src)
|
||||
v, err = interp.EvalWithContext(ctx, src)
|
||||
signal.Reset()
|
||||
if err != nil {
|
||||
switch e := err.(type) {
|
||||
@@ -479,11 +497,9 @@ func (interp *Interpreter) REPL(in io.Reader, out io.Writer) {
|
||||
default:
|
||||
fmt.Fprintln(out, err)
|
||||
}
|
||||
} else if v.IsValid() {
|
||||
fmt.Fprintln(out, v)
|
||||
}
|
||||
src = ""
|
||||
prompt()
|
||||
prompt(v)
|
||||
}
|
||||
}
|
||||
|
||||
@@ -495,16 +511,21 @@ func (interp *Interpreter) Repl(in, out *os.File) {
|
||||
}
|
||||
|
||||
// getPrompt returns a function which prints a prompt only if input is a terminal.
|
||||
func getPrompt(in io.Reader, out io.Writer) func() {
|
||||
func getPrompt(in io.Reader, out io.Writer) func(reflect.Value) {
|
||||
s, ok := in.(interface{ Stat() (os.FileInfo, error) })
|
||||
if !ok {
|
||||
return func() {}
|
||||
return func(reflect.Value) {}
|
||||
}
|
||||
stat, err := s.Stat()
|
||||
if err == nil && stat.Mode()&os.ModeCharDevice != 0 {
|
||||
return func() { fmt.Fprint(out, "> ") }
|
||||
return func(v reflect.Value) {
|
||||
if v.IsValid() {
|
||||
fmt.Fprintln(out, ":", v)
|
||||
}
|
||||
fmt.Fprint(out, "> ")
|
||||
}
|
||||
}
|
||||
return func() {}
|
||||
return func(reflect.Value) {}
|
||||
}
|
||||
|
||||
// handleSignal wraps signal handling for eval cancellation.
|
||||
|
||||
@@ -32,11 +32,15 @@ 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
|
||||
file.Name() == "export0.go" || // non-main package
|
||||
file.Name() == "for7.go" || // expect error
|
||||
file.Name() == "fun21.go" || // expect error
|
||||
file.Name() == "fun22.go" || // expect error
|
||||
file.Name() == "if2.go" || // expect error
|
||||
file.Name() == "import6.go" || // expect error
|
||||
file.Name() == "io0.go" || // use random number
|
||||
@@ -134,6 +138,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",
|
||||
@@ -154,6 +168,16 @@ func TestInterpErrorConsistency(t *testing.T) {
|
||||
expectedInterp: "4:14: non-bool used as for condition",
|
||||
expectedExec: "4:2: non-bool i (type int) used as for condition",
|
||||
},
|
||||
{
|
||||
fileName: "fun21.go",
|
||||
expectedInterp: "4:2: not enough arguments to return",
|
||||
expectedExec: "4:2: not enough arguments to return",
|
||||
},
|
||||
{
|
||||
fileName: "fun22.go",
|
||||
expectedInterp: "6:2: not enough arguments in call to time.Date",
|
||||
expectedExec: "6:11: not enough arguments in call to time.Date",
|
||||
},
|
||||
{
|
||||
fileName: "op1.go",
|
||||
expectedInterp: "5:2: illegal operand types for '+=' operator",
|
||||
|
||||
190
interp/interp_test.go
Normal file
190
interp/interp_test.go
Normal file
@@ -0,0 +1,190 @@
|
||||
package interp
|
||||
|
||||
import (
|
||||
"log"
|
||||
"reflect"
|
||||
"testing"
|
||||
)
|
||||
|
||||
func init() { log.SetFlags(log.Lshortfile) }
|
||||
|
||||
func TestIsNatural(t *testing.T) {
|
||||
tests := []struct {
|
||||
desc string
|
||||
n *node
|
||||
expected bool
|
||||
}{
|
||||
{
|
||||
desc: "positive uint var",
|
||||
n: &node{
|
||||
typ: &itype{
|
||||
rtype: func() reflect.Type {
|
||||
var x uint = 3
|
||||
return reflect.TypeOf(x)
|
||||
}(),
|
||||
},
|
||||
rval: func() reflect.Value {
|
||||
var x uint = 3
|
||||
return reflect.ValueOf(x)
|
||||
}(),
|
||||
},
|
||||
expected: true,
|
||||
},
|
||||
{
|
||||
desc: "positive untyped var",
|
||||
n: &node{
|
||||
typ: &itype{
|
||||
rtype: func() reflect.Type {
|
||||
var x = 3
|
||||
return reflect.TypeOf(x)
|
||||
}(),
|
||||
},
|
||||
rval: func() reflect.Value {
|
||||
var x = 3
|
||||
return reflect.ValueOf(x)
|
||||
}(),
|
||||
},
|
||||
expected: true,
|
||||
},
|
||||
{
|
||||
desc: "positive int var",
|
||||
n: &node{
|
||||
typ: &itype{
|
||||
rtype: func() reflect.Type {
|
||||
var x int = 3
|
||||
return reflect.TypeOf(x)
|
||||
}(),
|
||||
},
|
||||
rval: func() reflect.Value {
|
||||
var x int = 3
|
||||
return reflect.ValueOf(x)
|
||||
}(),
|
||||
},
|
||||
expected: true,
|
||||
},
|
||||
{
|
||||
desc: "positive float var, null decimal",
|
||||
n: &node{
|
||||
typ: &itype{
|
||||
rtype: func() reflect.Type {
|
||||
var x float64 = 3.0
|
||||
return reflect.TypeOf(x)
|
||||
}(),
|
||||
},
|
||||
rval: func() reflect.Value {
|
||||
var x float64 = 3.0
|
||||
return reflect.ValueOf(x)
|
||||
}(),
|
||||
},
|
||||
expected: true,
|
||||
},
|
||||
{
|
||||
desc: "positive float var, with decimal",
|
||||
n: &node{
|
||||
typ: &itype{
|
||||
rtype: func() reflect.Type {
|
||||
var x float64 = 3.14
|
||||
return reflect.TypeOf(x)
|
||||
}(),
|
||||
},
|
||||
rval: func() reflect.Value {
|
||||
var x float64 = 3.14
|
||||
return reflect.ValueOf(x)
|
||||
}(),
|
||||
},
|
||||
expected: false,
|
||||
},
|
||||
{
|
||||
desc: "negative int var",
|
||||
n: &node{
|
||||
typ: &itype{
|
||||
rtype: func() reflect.Type {
|
||||
var x int = -3
|
||||
return reflect.TypeOf(x)
|
||||
}(),
|
||||
},
|
||||
rval: func() reflect.Value {
|
||||
var x int = -3
|
||||
return reflect.ValueOf(x)
|
||||
}(),
|
||||
},
|
||||
expected: false,
|
||||
},
|
||||
{
|
||||
desc: "positive typed const",
|
||||
n: &node{
|
||||
typ: &itype{
|
||||
rtype: func() reflect.Type {
|
||||
const a uint = 3
|
||||
return reflect.TypeOf(a)
|
||||
}(),
|
||||
},
|
||||
rval: func() reflect.Value {
|
||||
const a uint = 3
|
||||
return reflect.ValueOf(a)
|
||||
}(),
|
||||
},
|
||||
expected: true,
|
||||
},
|
||||
{
|
||||
desc: "positive untyped const",
|
||||
n: &node{
|
||||
typ: &itype{
|
||||
rtype: func() reflect.Type {
|
||||
const a = 3
|
||||
return reflect.TypeOf(a)
|
||||
}(),
|
||||
},
|
||||
rval: func() reflect.Value {
|
||||
const a = 3
|
||||
return reflect.ValueOf(a)
|
||||
}(),
|
||||
},
|
||||
expected: true,
|
||||
},
|
||||
{
|
||||
desc: "positive untyped const (iota)",
|
||||
n: &node{
|
||||
typ: &itype{
|
||||
rtype: func() reflect.Type {
|
||||
const (
|
||||
zero = iota
|
||||
a
|
||||
)
|
||||
return reflect.TypeOf(a)
|
||||
}(),
|
||||
},
|
||||
rval: func() reflect.Value {
|
||||
const (
|
||||
zero = iota
|
||||
a
|
||||
)
|
||||
return reflect.ValueOf(a)
|
||||
}(),
|
||||
},
|
||||
expected: true,
|
||||
},
|
||||
{
|
||||
desc: "negative const",
|
||||
n: &node{
|
||||
typ: &itype{
|
||||
rtype: func() reflect.Type {
|
||||
const a = -3
|
||||
return reflect.TypeOf(a)
|
||||
}(),
|
||||
},
|
||||
rval: func() reflect.Value {
|
||||
const a = -3
|
||||
return reflect.ValueOf(a)
|
||||
}(),
|
||||
},
|
||||
expected: false,
|
||||
},
|
||||
}
|
||||
for _, test := range tests {
|
||||
got := test.n.isNatural()
|
||||
if test.expected != got {
|
||||
t.Fatalf("%s: got %v, wanted %v", test.desc, got, test.expected)
|
||||
}
|
||||
}
|
||||
}
|
||||
56
interp/op.go
56
interp/op.go
@@ -7,9 +7,9 @@ import "reflect"
|
||||
// Arithmetic operators
|
||||
|
||||
func add(n *node) {
|
||||
dest := genValue(n)
|
||||
next := getExec(n.tnext)
|
||||
typ := n.typ.TypeOf()
|
||||
typ := n.typ.concrete().TypeOf()
|
||||
dest := genValueOutput(n, typ)
|
||||
c0, c1 := n.child[0], n.child[1]
|
||||
|
||||
switch typ.Kind() {
|
||||
@@ -167,9 +167,9 @@ func addConst(n *node) {
|
||||
}
|
||||
|
||||
func and(n *node) {
|
||||
dest := genValue(n)
|
||||
next := getExec(n.tnext)
|
||||
typ := n.typ.TypeOf()
|
||||
typ := n.typ.concrete().TypeOf()
|
||||
dest := genValueOutput(n, typ)
|
||||
c0, c1 := n.child[0], n.child[1]
|
||||
|
||||
switch typ.Kind() {
|
||||
@@ -245,9 +245,9 @@ func andConst(n *node) {
|
||||
}
|
||||
|
||||
func andNot(n *node) {
|
||||
dest := genValue(n)
|
||||
next := getExec(n.tnext)
|
||||
typ := n.typ.TypeOf()
|
||||
typ := n.typ.concrete().TypeOf()
|
||||
dest := genValueOutput(n, typ)
|
||||
c0, c1 := n.child[0], n.child[1]
|
||||
|
||||
switch typ.Kind() {
|
||||
@@ -323,9 +323,9 @@ func andNotConst(n *node) {
|
||||
}
|
||||
|
||||
func mul(n *node) {
|
||||
dest := genValue(n)
|
||||
next := getExec(n.tnext)
|
||||
typ := n.typ.TypeOf()
|
||||
typ := n.typ.concrete().TypeOf()
|
||||
dest := genValueOutput(n, typ)
|
||||
c0, c1 := n.child[0], n.child[1]
|
||||
|
||||
switch typ.Kind() {
|
||||
@@ -457,9 +457,9 @@ func mulConst(n *node) {
|
||||
}
|
||||
|
||||
func or(n *node) {
|
||||
dest := genValue(n)
|
||||
next := getExec(n.tnext)
|
||||
typ := n.typ.TypeOf()
|
||||
typ := n.typ.concrete().TypeOf()
|
||||
dest := genValueOutput(n, typ)
|
||||
c0, c1 := n.child[0], n.child[1]
|
||||
|
||||
switch typ.Kind() {
|
||||
@@ -535,9 +535,9 @@ func orConst(n *node) {
|
||||
}
|
||||
|
||||
func quo(n *node) {
|
||||
dest := genValue(n)
|
||||
next := getExec(n.tnext)
|
||||
typ := n.typ.TypeOf()
|
||||
typ := n.typ.concrete().TypeOf()
|
||||
dest := genValueOutput(n, typ)
|
||||
c0, c1 := n.child[0], n.child[1]
|
||||
|
||||
switch typ.Kind() {
|
||||
@@ -669,9 +669,9 @@ func quoConst(n *node) {
|
||||
}
|
||||
|
||||
func rem(n *node) {
|
||||
dest := genValue(n)
|
||||
next := getExec(n.tnext)
|
||||
typ := n.typ.TypeOf()
|
||||
typ := n.typ.concrete().TypeOf()
|
||||
dest := genValueOutput(n, typ)
|
||||
c0, c1 := n.child[0], n.child[1]
|
||||
|
||||
switch typ.Kind() {
|
||||
@@ -747,9 +747,9 @@ func remConst(n *node) {
|
||||
}
|
||||
|
||||
func shl(n *node) {
|
||||
dest := genValue(n)
|
||||
next := getExec(n.tnext)
|
||||
typ := n.typ.TypeOf()
|
||||
typ := n.typ.concrete().TypeOf()
|
||||
dest := genValueOutput(n, typ)
|
||||
c0, c1 := n.child[0], n.child[1]
|
||||
|
||||
switch typ.Kind() {
|
||||
@@ -825,9 +825,9 @@ func shlConst(n *node) {
|
||||
}
|
||||
|
||||
func shr(n *node) {
|
||||
dest := genValue(n)
|
||||
next := getExec(n.tnext)
|
||||
typ := n.typ.TypeOf()
|
||||
typ := n.typ.concrete().TypeOf()
|
||||
dest := genValueOutput(n, typ)
|
||||
c0, c1 := n.child[0], n.child[1]
|
||||
|
||||
switch typ.Kind() {
|
||||
@@ -903,9 +903,9 @@ func shrConst(n *node) {
|
||||
}
|
||||
|
||||
func sub(n *node) {
|
||||
dest := genValue(n)
|
||||
next := getExec(n.tnext)
|
||||
typ := n.typ.TypeOf()
|
||||
typ := n.typ.concrete().TypeOf()
|
||||
dest := genValueOutput(n, typ)
|
||||
c0, c1 := n.child[0], n.child[1]
|
||||
|
||||
switch typ.Kind() {
|
||||
@@ -1037,9 +1037,9 @@ func subConst(n *node) {
|
||||
}
|
||||
|
||||
func xor(n *node) {
|
||||
dest := genValue(n)
|
||||
next := getExec(n.tnext)
|
||||
typ := n.typ.TypeOf()
|
||||
typ := n.typ.concrete().TypeOf()
|
||||
dest := genValueOutput(n, typ)
|
||||
c0, c1 := n.child[0], n.child[1]
|
||||
|
||||
switch typ.Kind() {
|
||||
@@ -1917,7 +1917,7 @@ func posConst(n *node) {
|
||||
|
||||
func equal(n *node) {
|
||||
tnext := getExec(n.tnext)
|
||||
dest := genValue(n)
|
||||
dest := genValueOutput(n, reflect.TypeOf(true))
|
||||
c0, c1 := n.child[0], n.child[1]
|
||||
|
||||
switch t0, t1 := c0.typ.TypeOf(), c1.typ.TypeOf(); {
|
||||
@@ -2346,7 +2346,7 @@ func equal(n *node) {
|
||||
|
||||
func greater(n *node) {
|
||||
tnext := getExec(n.tnext)
|
||||
dest := genValue(n)
|
||||
dest := genValueOutput(n, reflect.TypeOf(true))
|
||||
c0, c1 := n.child[0], n.child[1]
|
||||
|
||||
switch t0, t1 := c0.typ.TypeOf(), c1.typ.TypeOf(); {
|
||||
@@ -2635,7 +2635,7 @@ func greater(n *node) {
|
||||
|
||||
func greaterEqual(n *node) {
|
||||
tnext := getExec(n.tnext)
|
||||
dest := genValue(n)
|
||||
dest := genValueOutput(n, reflect.TypeOf(true))
|
||||
c0, c1 := n.child[0], n.child[1]
|
||||
|
||||
switch t0, t1 := c0.typ.TypeOf(), c1.typ.TypeOf(); {
|
||||
@@ -2924,7 +2924,7 @@ func greaterEqual(n *node) {
|
||||
|
||||
func lower(n *node) {
|
||||
tnext := getExec(n.tnext)
|
||||
dest := genValue(n)
|
||||
dest := genValueOutput(n, reflect.TypeOf(true))
|
||||
c0, c1 := n.child[0], n.child[1]
|
||||
|
||||
switch t0, t1 := c0.typ.TypeOf(), c1.typ.TypeOf(); {
|
||||
@@ -3213,7 +3213,7 @@ func lower(n *node) {
|
||||
|
||||
func lowerEqual(n *node) {
|
||||
tnext := getExec(n.tnext)
|
||||
dest := genValue(n)
|
||||
dest := genValueOutput(n, reflect.TypeOf(true))
|
||||
c0, c1 := n.child[0], n.child[1]
|
||||
|
||||
switch t0, t1 := c0.typ.TypeOf(), c1.typ.TypeOf(); {
|
||||
@@ -3502,7 +3502,7 @@ func lowerEqual(n *node) {
|
||||
|
||||
func notEqual(n *node) {
|
||||
tnext := getExec(n.tnext)
|
||||
dest := genValue(n)
|
||||
dest := genValueOutput(n, reflect.TypeOf(true))
|
||||
c0, c1 := n.child[0], n.child[1]
|
||||
|
||||
switch t0, t1 := c0.typ.TypeOf(), c1.typ.TypeOf(); {
|
||||
|
||||
277
interp/run.go
277
interp/run.go
@@ -594,9 +594,13 @@ func genInterfaceWrapper(n *node, typ reflect.Type) func(*frame) reflect.Value {
|
||||
w := reflect.New(wrap).Elem()
|
||||
for i, m := range methods {
|
||||
if m == nil {
|
||||
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(o.MethodByName(names[i]))
|
||||
w.Field(i).Set(r)
|
||||
} else {
|
||||
log.Println(n.cfgErrorf("genInterfaceWrapper error, no method %s", names[i]))
|
||||
}
|
||||
@@ -616,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
|
||||
}
|
||||
@@ -630,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] })
|
||||
@@ -664,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] }
|
||||
@@ -762,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))
|
||||
}
|
||||
}
|
||||
|
||||
@@ -907,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
|
||||
@@ -921,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]
|
||||
@@ -943,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)
|
||||
@@ -1031,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)
|
||||
@@ -1056,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)
|
||||
}
|
||||
@@ -1090,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)
|
||||
}
|
||||
@@ -1136,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())
|
||||
@@ -1168,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())
|
||||
@@ -1508,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 {
|
||||
@@ -1525,6 +1595,12 @@ func _return(n *node) {
|
||||
values[i] = genValue(c)
|
||||
case interfaceT:
|
||||
values[i] = genValueInterface(c)
|
||||
case valueT:
|
||||
if t.rtype.Kind() == reflect.Interface {
|
||||
values[i] = genInterfaceWrapper(c, t.rtype)
|
||||
break
|
||||
}
|
||||
fallthrough
|
||||
default:
|
||||
if c.typ.untyped {
|
||||
values[i] = genValueAs(c, def.typ.ret[i].TypeOf())
|
||||
@@ -1536,15 +1612,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:
|
||||
@@ -1552,14 +1628,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
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -1899,7 +1975,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 {
|
||||
@@ -1994,11 +2074,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
|
||||
@@ -2010,10 +2091,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
|
||||
@@ -2044,7 +2126,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])
|
||||
@@ -2069,7 +2151,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)
|
||||
|
||||
@@ -2119,7 +2201,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)
|
||||
|
||||
@@ -2130,7 +2212,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)
|
||||
@@ -2152,7 +2234,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)
|
||||
@@ -2175,7 +2257,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)
|
||||
@@ -2187,7 +2269,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)
|
||||
@@ -2211,7 +2293,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)
|
||||
|
||||
@@ -2222,9 +2304,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))
|
||||
@@ -2234,9 +2316,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:
|
||||
@@ -2514,33 +2596,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++ {
|
||||
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)
|
||||
if len(n.child[i].child) == 0 {
|
||||
// The comm clause is an empty default, exit select.
|
||||
cases[i].Dir = reflect.SelectDefault
|
||||
clause[i] = func(*frame) bltn { return next }
|
||||
} else {
|
||||
switch c0 := n.child[i].child[0]; {
|
||||
case len(n.child[i].child) > 1:
|
||||
// The comm clause contains a channel operation and a clause body.
|
||||
clause[i] = getExec(n.child[i].child[1].start)
|
||||
chans[i], assigned[i], ok[i], cases[i].Dir = clauseChanDir(n.child[i])
|
||||
chanValues[i] = genValue(chans[i])
|
||||
if assigned[i] != nil {
|
||||
assignedValues[i] = genValue(assigned[i])
|
||||
}
|
||||
if ok[i] != nil {
|
||||
okValues[i] = genValue(ok[i])
|
||||
}
|
||||
case c0.kind == exprStmt && len(c0.child) == 1 && c0.child[0].action == aRecv:
|
||||
// The comm clause has an empty body clause after channel receive.
|
||||
chanValues[i] = genValue(c0.child[0].child[0])
|
||||
cases[i].Dir = reflect.SelectRecv
|
||||
case c0.kind == sendStmt:
|
||||
// The comm clause as an empty body clause after channel send.
|
||||
chanValues[i] = genValue(c0.child[0])
|
||||
cases[i].Dir = reflect.SelectSend
|
||||
assignedValues[i] = genValue(c0.child[1])
|
||||
default:
|
||||
// The comm clause has a default clause.
|
||||
clause[i] = getExec(c0.start)
|
||||
cases[i].Dir = reflect.SelectDefault
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -83,6 +83,7 @@ type scope struct {
|
||||
level int // Frame level: number of frame indirections to access var during execution
|
||||
sym map[string]*symbol // Map of symbols defined in this current scope
|
||||
global bool // true if scope refers to global space (single frame for universe and package level scopes)
|
||||
iota int // iota value in this scope
|
||||
}
|
||||
|
||||
// push creates a new scope and chain it to the current one
|
||||
|
||||
141
interp/type.go
141
interp/type.go
@@ -239,26 +239,36 @@ func nodeType(interp *Interpreter, sc *scope, n *node) (*itype, error) {
|
||||
t, err = nodeType(interp, sc, n.child[0])
|
||||
|
||||
case binaryExpr:
|
||||
if a := n.anc; a.kind == defineStmt && len(a.child) > a.nleft+a.nright {
|
||||
t, err = nodeType(interp, sc, a.child[a.nleft])
|
||||
} else {
|
||||
if t, err = nodeType(interp, sc, n.child[0]); err != nil {
|
||||
return nil, err
|
||||
}
|
||||
// Shift operator type is inherited from first parameter only
|
||||
// For other operators, infer type in from 2nd parameter in case of untyped first
|
||||
if t.untyped && !isShiftNode(n) {
|
||||
var t1 *itype
|
||||
t1, err = nodeType(interp, sc, n.child[1])
|
||||
if !(t1.untyped && isInt(t1.TypeOf()) && isFloat(t.TypeOf())) {
|
||||
t = t1
|
||||
}
|
||||
// Get type of first operand.
|
||||
if t, err = nodeType(interp, sc, n.child[0]); err != nil {
|
||||
return nil, err
|
||||
}
|
||||
// For operators other than shift, get the type from the 2nd operand if the first is untyped.
|
||||
if t.untyped && !isShiftNode(n) {
|
||||
var t1 *itype
|
||||
t1, err = nodeType(interp, sc, n.child[1])
|
||||
if !(t1.untyped && isInt(t1.TypeOf()) && isFloat(t.TypeOf())) {
|
||||
t = t1
|
||||
}
|
||||
}
|
||||
// If the node is to be assigned or returned, the node type is the destination type.
|
||||
dt := t
|
||||
switch a := n.anc; {
|
||||
case a.kind == defineStmt && len(a.child) > a.nleft+a.nright:
|
||||
if dt, err = nodeType(interp, sc, a.child[a.nleft]); err != nil {
|
||||
return nil, err
|
||||
}
|
||||
case a.kind == returnStmt:
|
||||
dt = sc.def.typ.ret[childPos(n)]
|
||||
}
|
||||
if isInterface(dt) {
|
||||
dt.val = t
|
||||
}
|
||||
t = dt
|
||||
|
||||
case callExpr:
|
||||
if interp.isBuiltinCall(n) {
|
||||
// builtin types are special and may depend from their call arguments
|
||||
// Builtin types are special and may depend from their input arguments.
|
||||
t.cat = builtinT
|
||||
switch n.child[0].ident {
|
||||
case "complex":
|
||||
@@ -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), scope: sc}
|
||||
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
|
||||
@@ -693,6 +705,25 @@ func (t *itype) referTo(name string, seen map[*itype]bool) bool {
|
||||
return false
|
||||
}
|
||||
|
||||
func (t *itype) numOut() int {
|
||||
switch t.cat {
|
||||
case funcT:
|
||||
return len(t.ret)
|
||||
case valueT:
|
||||
if t.rtype.Kind() == reflect.Func {
|
||||
return t.rtype.NumOut()
|
||||
}
|
||||
}
|
||||
return 1
|
||||
}
|
||||
|
||||
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 {
|
||||
@@ -819,17 +850,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
|
||||
}
|
||||
@@ -1170,10 +1227,9 @@ func chanElement(t *itype) *itype {
|
||||
return nil
|
||||
}
|
||||
|
||||
// isChan returns true if type is of channel kind.
|
||||
func isChan(t *itype) bool {
|
||||
return t.TypeOf().Kind() == reflect.Chan
|
||||
}
|
||||
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))
|
||||
@@ -1199,9 +1255,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
|
||||
@@ -1210,6 +1267,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
|
||||
@@ -1218,6 +1278,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
|
||||
@@ -1226,6 +1289,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
|
||||
@@ -1234,11 +1300,14 @@ func isFloat(t reflect.Type) bool {
|
||||
}
|
||||
|
||||
func isByteArray(t reflect.Type) bool {
|
||||
if t == nil {
|
||||
return false
|
||||
}
|
||||
k := t.Kind()
|
||||
return (k == reflect.Array || k == reflect.Slice) && t.Elem().Kind() == reflect.Uint8
|
||||
}
|
||||
|
||||
func isFloat32(t reflect.Type) bool { return t.Kind() == reflect.Float32 }
|
||||
func isFloat64(t reflect.Type) bool { return t.Kind() == reflect.Float64 }
|
||||
func isFloat32(t reflect.Type) bool { return t != nil && t.Kind() == reflect.Float32 }
|
||||
func isFloat64(t reflect.Type) bool { return t != nil && t.Kind() == reflect.Float64 }
|
||||
func isNumber(t reflect.Type) bool { return isInt(t) || isFloat(t) || isComplex(t) }
|
||||
func isString(t reflect.Type) bool { return t.Kind() == reflect.String }
|
||||
func isString(t reflect.Type) bool { return t != nil && t.Kind() == reflect.String }
|
||||
|
||||
@@ -79,7 +79,7 @@ func genValue(n *node) func(*frame) reflect.Value {
|
||||
case basicLit:
|
||||
v := n.rval
|
||||
if !v.IsValid() {
|
||||
v = reflect.New(reflect.TypeOf((*interface{})(nil)).Elem()).Elem()
|
||||
v = reflect.New(interf).Elem()
|
||||
}
|
||||
return func(f *frame) reflect.Value { return v }
|
||||
case funcDecl:
|
||||
@@ -149,10 +149,9 @@ func genValueRangeArray(n *node) func(*frame) reflect.Value {
|
||||
|
||||
func genValueInterfacePtr(n *node) func(*frame) reflect.Value {
|
||||
value := genValue(n)
|
||||
it := reflect.TypeOf((*interface{})(nil)).Elem()
|
||||
|
||||
return func(f *frame) reflect.Value {
|
||||
v := reflect.New(it).Elem()
|
||||
v := reflect.New(interf).Elem()
|
||||
v.Set(value(f))
|
||||
return v.Addr()
|
||||
}
|
||||
@@ -179,10 +178,28 @@ func genValueInterface(n *node) func(*frame) reflect.Value {
|
||||
|
||||
func zeroInterfaceValue() reflect.Value {
|
||||
n := &node{kind: basicLit, typ: &itype{cat: nilT, untyped: true}}
|
||||
v := reflect.New(reflect.TypeOf((*interface{})(nil)).Elem()).Elem()
|
||||
v := reflect.New(interf).Elem()
|
||||
return reflect.ValueOf(valueInterface{n, v})
|
||||
}
|
||||
|
||||
func genValueOutput(n *node, t reflect.Type) func(*frame) reflect.Value {
|
||||
value := genValue(n)
|
||||
switch {
|
||||
case n.anc.action == aAssign && n.anc.typ.cat == interfaceT:
|
||||
fallthrough
|
||||
case n.anc.kind == returnStmt && n.anc.val.(*node).typ.ret[0].cat == interfaceT:
|
||||
// The result of the builtin has to be returned as an interface type.
|
||||
// Wrap it in a valueInterface and return the dereferenced value.
|
||||
return func(f *frame) reflect.Value {
|
||||
d := value(f)
|
||||
v := reflect.New(t).Elem()
|
||||
d.Set(reflect.ValueOf(valueInterface{n, v}))
|
||||
return v
|
||||
}
|
||||
}
|
||||
return value
|
||||
}
|
||||
|
||||
func genValueInterfaceValue(n *node) func(*frame) reflect.Value {
|
||||
value := genValue(n)
|
||||
|
||||
|
||||
Reference in New Issue
Block a user