Compare commits
18 Commits
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
cdf4622421 | ||
|
|
b9720d15e1 | ||
|
|
7fab75fbe4 | ||
|
|
7eac6955b3 | ||
|
|
7070367d21 | ||
|
|
22dfc8b10a | ||
|
|
7fba3fe580 | ||
|
|
ff36ec58b1 | ||
|
|
f6c8b8b14f | ||
|
|
e12c8b72c4 | ||
|
|
e4acba031d | ||
|
|
7d56fb067e | ||
|
|
1feece61ce | ||
|
|
01e2e4600e | ||
|
|
92eebbade2 | ||
|
|
a6389aca5e | ||
|
|
de8cb7dc3b | ||
|
|
18b843646c |
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
|
||||
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
|
||||
19
_test/fun13.go
Normal file
19
_test/fun13.go
Normal file
@@ -0,0 +1,19 @@
|
||||
package main
|
||||
|
||||
import "fmt"
|
||||
|
||||
type T struct{}
|
||||
|
||||
func newT() (T, error) { return T{}, nil }
|
||||
|
||||
func main() {
|
||||
var (
|
||||
i interface{}
|
||||
err error
|
||||
)
|
||||
i, err = newT()
|
||||
fmt.Println(i, err)
|
||||
}
|
||||
|
||||
// Output:
|
||||
// {} <nil>
|
||||
13
_test/fun14.go
Normal file
13
_test/fun14.go
Normal file
@@ -0,0 +1,13 @@
|
||||
package main
|
||||
|
||||
func f() (bool, int) { return true, 2 }
|
||||
|
||||
func g() (bool, int) { return f() }
|
||||
|
||||
func main() {
|
||||
b, i := g()
|
||||
println(b, i)
|
||||
}
|
||||
|
||||
// Output:
|
||||
// true 2
|
||||
11
_test/fun15.go
Normal file
11
_test/fun15.go
Normal file
@@ -0,0 +1,11 @@
|
||||
package main
|
||||
|
||||
func f1(a int) interface{} { return a + 1 }
|
||||
|
||||
func main() {
|
||||
c := f1(3)
|
||||
println(c.(int))
|
||||
}
|
||||
|
||||
// Output:
|
||||
// 4
|
||||
13
_test/fun16.go
Normal file
13
_test/fun16.go
Normal file
@@ -0,0 +1,13 @@
|
||||
package main
|
||||
|
||||
func f1(a int) int { return a + 1 }
|
||||
|
||||
func f2(a int) interface{} { return f1(a) }
|
||||
|
||||
func main() {
|
||||
c := f2(3)
|
||||
println(c.(int))
|
||||
}
|
||||
|
||||
// Output:
|
||||
// 4
|
||||
13
_test/fun17.go
Normal file
13
_test/fun17.go
Normal file
@@ -0,0 +1,13 @@
|
||||
package main
|
||||
|
||||
func f1(a int) interface{} { return a + 1 }
|
||||
|
||||
func f2(a int) interface{} { return f1(a) }
|
||||
|
||||
func main() {
|
||||
c := f2(3)
|
||||
println(c.(int))
|
||||
}
|
||||
|
||||
// Output:
|
||||
// 4
|
||||
12
_test/fun18.go
Normal file
12
_test/fun18.go
Normal file
@@ -0,0 +1,12 @@
|
||||
package main
|
||||
|
||||
var m = map[string]int{"foo": 1, "bar": 2}
|
||||
|
||||
func f(s string) interface{} { return m[s] }
|
||||
|
||||
func main() {
|
||||
println(f("foo").(int))
|
||||
}
|
||||
|
||||
// Output:
|
||||
// 1
|
||||
17
_test/fun19.go
Normal file
17
_test/fun19.go
Normal file
@@ -0,0 +1,17 @@
|
||||
package main
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
)
|
||||
|
||||
func foo() ([]string, error) {
|
||||
return nil, fmt.Errorf("bar")
|
||||
}
|
||||
|
||||
func main() {
|
||||
a, b := foo()
|
||||
fmt.Println(a, b)
|
||||
}
|
||||
|
||||
// Output:
|
||||
// [] bar
|
||||
19
_test/fun20.go
Normal file
19
_test/fun20.go
Normal file
@@ -0,0 +1,19 @@
|
||||
package main
|
||||
|
||||
import "fmt"
|
||||
|
||||
var myerr error = fmt.Errorf("bar")
|
||||
|
||||
func ferr() error { return myerr }
|
||||
|
||||
func foo() ([]string, error) {
|
||||
return nil, ferr()
|
||||
}
|
||||
|
||||
func main() {
|
||||
a, b := foo()
|
||||
fmt.Println(a, b)
|
||||
}
|
||||
|
||||
// Output:
|
||||
// [] bar
|
||||
14
_test/imag0.go
Normal file
14
_test/imag0.go
Normal file
@@ -0,0 +1,14 @@
|
||||
package main
|
||||
|
||||
import "fmt"
|
||||
|
||||
func f(c complex128) interface{} { return imag(c) }
|
||||
|
||||
func main() {
|
||||
c := complex(3, 2)
|
||||
a := f(c)
|
||||
fmt.Println(a.(float64))
|
||||
}
|
||||
|
||||
// Output:
|
||||
// 2
|
||||
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
|
||||
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
|
||||
11
_test/map26.go
Normal file
11
_test/map26.go
Normal file
@@ -0,0 +1,11 @@
|
||||
package main
|
||||
|
||||
var m = map[string]int{"foo": 1, "bar": 2}
|
||||
|
||||
func main() {
|
||||
var a interface{} = m["foo"]
|
||||
println(a.(int))
|
||||
}
|
||||
|
||||
// Output:
|
||||
// 1
|
||||
24
_test/map27.go
Normal file
24
_test/map27.go
Normal file
@@ -0,0 +1,24 @@
|
||||
package main
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"text/template"
|
||||
)
|
||||
|
||||
type fm map[string]interface{}
|
||||
|
||||
type foo struct{}
|
||||
|
||||
func main() {
|
||||
a := make(fm)
|
||||
a["foo"] = &foo{}
|
||||
fmt.Println(a["foo"])
|
||||
|
||||
b := make(template.FuncMap) // type FuncMap map[string]interface{}
|
||||
b["foo"] = &foo{}
|
||||
fmt.Println(b["foo"])
|
||||
}
|
||||
|
||||
// Output:
|
||||
// &{}
|
||||
// &{}
|
||||
13
_test/new2.go
Normal file
13
_test/new2.go
Normal file
@@ -0,0 +1,13 @@
|
||||
package main
|
||||
|
||||
func f() interface{} {
|
||||
return new(int)
|
||||
}
|
||||
|
||||
func main() {
|
||||
a := f()
|
||||
println(*(a.(*int)))
|
||||
}
|
||||
|
||||
// Output:
|
||||
// 0
|
||||
12
_test/nil2.go
Normal file
12
_test/nil2.go
Normal file
@@ -0,0 +1,12 @@
|
||||
package main
|
||||
|
||||
func test() error { return nil }
|
||||
|
||||
func main() {
|
||||
if err := test(); nil == err {
|
||||
println("err is nil")
|
||||
}
|
||||
}
|
||||
|
||||
// Output:
|
||||
// err is nil
|
||||
@@ -1,15 +1,15 @@
|
||||
package main
|
||||
|
||||
func main() {
|
||||
a := 0
|
||||
b := true
|
||||
a := 0
|
||||
b := true
|
||||
c := false
|
||||
if (b && c) {
|
||||
a = 1
|
||||
} else {
|
||||
a = -1
|
||||
}
|
||||
println(a)
|
||||
if b && c {
|
||||
a = 1
|
||||
} else {
|
||||
a = -1
|
||||
}
|
||||
println(a)
|
||||
}
|
||||
|
||||
// Output:
|
||||
|
||||
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
|
||||
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
|
||||
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
|
||||
@@ -13,3 +13,6 @@ type T struct {
|
||||
func main() {
|
||||
println(foo().Name)
|
||||
}
|
||||
|
||||
// Output:
|
||||
// foo
|
||||
|
||||
20
_test/variadic6.go
Normal file
20
_test/variadic6.go
Normal file
@@ -0,0 +1,20 @@
|
||||
package main
|
||||
|
||||
import "fmt"
|
||||
|
||||
type A struct {
|
||||
}
|
||||
|
||||
func (a A) f(vals ...bool) {
|
||||
for _, v := range vals {
|
||||
fmt.Println(v)
|
||||
}
|
||||
}
|
||||
func main() {
|
||||
bools := []bool{true}
|
||||
a := A{}
|
||||
a.f(bools...)
|
||||
}
|
||||
|
||||
// Output:
|
||||
// true
|
||||
@@ -1,22 +1,66 @@
|
||||
/*
|
||||
Yaegi interprets Go programs.
|
||||
|
||||
Yaegi reads Go language programs from its standard input or from a file
|
||||
and evaluates them.
|
||||
Yaegi reads Go language programs from standard input, string
|
||||
parameters or files and run them.
|
||||
|
||||
If invoked with no arguments, it processes the standard input
|
||||
in a Read-Eval-Print-Loop. A prompt is displayed if standard input
|
||||
is a terminal.
|
||||
If invoked with no arguments, it processes the standard input in
|
||||
a Read-Eval-Print-Loop. A prompt is displayed if standard input is
|
||||
a terminal.
|
||||
|
||||
Given a file, it operates on that file. If the first line starts with
|
||||
"#!/usr/bin/env yaegi", and the file has exec permission, then the file
|
||||
can be invoked directly from the shell.
|
||||
File Mode
|
||||
|
||||
In file mode, as in standard Go, files are read entirely, then parsed,
|
||||
then evaluated. In REPL mode, each line is parsed and evaluated separately,
|
||||
at global level in an implicit main package.
|
||||
In file mode, as in a standard Go compiler, source files are read entirely
|
||||
before being parsed, then evaluated. It allows to handle forward
|
||||
declarations and to have package code split in multiple source files.
|
||||
|
||||
Go specifications fully apply in this mode.
|
||||
|
||||
All files are interpreted in file mode except the initial file if it
|
||||
starts with "#!" characters (the shebang pattern to allow executable
|
||||
scripts), for example "#!/usr/bin/env yaegi". In that case, the initial
|
||||
file is interpreted in REPL mode.
|
||||
|
||||
REPL mode
|
||||
|
||||
In REPL mode, the interpreter parses the code incrementally. As soon
|
||||
as a statement is complete, it evaluates it. This makes the interpreter
|
||||
suitable for interactive command line and scripts.
|
||||
|
||||
Go specifications apply with the following differences:
|
||||
|
||||
All local and global declarations (const, var, type, func) are allowed,
|
||||
including in short form, except that all identifiers must be defined
|
||||
before use (as declarations inside a standard Go function).
|
||||
|
||||
The statements are evaluated in the global space, within an implicit
|
||||
"main" package.
|
||||
|
||||
It is not necessary to have a package statement, or a main function in
|
||||
REPL mode. Import statements for preloaded binary packages can also
|
||||
be avoided (i.e. all the standard library except the few packages
|
||||
where default names collide, as "math/rand" and "crypto/rand", for which
|
||||
an explicit import is still necessary).
|
||||
|
||||
Note that the source packages are always interpreted in file mode,
|
||||
even if imported from REPL.
|
||||
|
||||
The following extract is a valid executable script:
|
||||
|
||||
#!/usr/bin/env yaegi
|
||||
helloHandler := func(w http.ResponseWriter, req *http.Request) {
|
||||
io.WriteString(w, "Hello, world!\n")
|
||||
}
|
||||
http.HandleFunc("/hello", helloHandler)
|
||||
log.Fatal(http.ListenAndServe(":8080", nil))
|
||||
|
||||
Example of a one liner:
|
||||
|
||||
$ yaegi -e 'println(reflect.TypeOf(fmt.Print))'
|
||||
|
||||
Options:
|
||||
-e string
|
||||
evaluate the string and return.
|
||||
-i
|
||||
start an interactive REPL after file execution.
|
||||
-tags tag,list
|
||||
@@ -86,15 +130,18 @@ func main() {
|
||||
|
||||
s := string(b)
|
||||
if s[:2] == "#!" {
|
||||
// Allow executable go scripts, but fix them prior to parse
|
||||
// Allow executable go scripts, Have the same behavior as in interactive mode.
|
||||
s = strings.Replace(s, "#!", "//", 1)
|
||||
}
|
||||
|
||||
i.Name = args[0]
|
||||
if _, err := i.Eval(s); err != nil {
|
||||
fmt.Println(err)
|
||||
if p, ok := err.(interp.Panic); ok {
|
||||
fmt.Println(string(p.Stack))
|
||||
i.REPL(strings.NewReader(s), os.Stdout)
|
||||
} else {
|
||||
// Files not starting with "#!" are supposed to be pure Go, directly Evaled.
|
||||
i.Name = args[0]
|
||||
_, err := i.Eval(s)
|
||||
if err != nil {
|
||||
fmt.Println(err)
|
||||
if p, ok := err.(interp.Panic); ok {
|
||||
fmt.Println(string(p.Stack))
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -84,7 +84,7 @@ func TestYaegiCmdCancel(t *testing.T) {
|
||||
continue
|
||||
}
|
||||
|
||||
if outBuf.String() != "context canceled\n2\n" {
|
||||
if outBuf.String() != "context canceled\n" {
|
||||
t.Errorf("unexpected output: %q", &outBuf)
|
||||
}
|
||||
}
|
||||
|
||||
@@ -17,9 +17,9 @@ import "reflect"
|
||||
// Arithmetic operators
|
||||
{{range $name, $op := .Arithmetic}}
|
||||
func {{$name}}(n *node) {
|
||||
dest := genValue(n)
|
||||
next := getExec(n.tnext)
|
||||
typ := n.typ.TypeOf()
|
||||
typ := n.typ.concrete().TypeOf()
|
||||
dest := genValueOutput(n, typ)
|
||||
c0, c1 := n.child[0], n.child[1]
|
||||
|
||||
switch typ.Kind() {
|
||||
@@ -379,7 +379,7 @@ func {{$name}}Const(n *node) {
|
||||
{{range $name, $op := .Comparison}}
|
||||
func {{$name}}(n *node) {
|
||||
tnext := getExec(n.tnext)
|
||||
dest := genValue(n)
|
||||
dest := genValueOutput(n, reflect.TypeOf(true))
|
||||
c0, c1 := n.child[0], n.child[1]
|
||||
|
||||
switch t0, t1 := c0.typ.TypeOf(), c1.typ.TypeOf(); {
|
||||
|
||||
@@ -199,12 +199,14 @@ const (
|
||||
aCall
|
||||
aCase
|
||||
aCompositeLit
|
||||
aConvert
|
||||
aDec
|
||||
aEqual
|
||||
aGreater
|
||||
aGreaterEqual
|
||||
aGetFunc
|
||||
aGetIndex
|
||||
aGetSym
|
||||
aInc
|
||||
aLand
|
||||
aLor
|
||||
@@ -257,11 +259,13 @@ var actions = [...]string{
|
||||
aCall: "call",
|
||||
aCase: "case",
|
||||
aCompositeLit: "compositeLit",
|
||||
aConvert: "convert",
|
||||
aDec: "--",
|
||||
aEqual: "==",
|
||||
aGreater: ">",
|
||||
aGetFunc: "getFunc",
|
||||
aGetIndex: "getIndex",
|
||||
aGetSym: ".",
|
||||
aInc: "++",
|
||||
aLand: "&&",
|
||||
aLor: "||",
|
||||
|
||||
179
interp/cfg.go
179
interp/cfg.go
@@ -50,7 +50,6 @@ var identifier = regexp.MustCompile(`([\pL_][\pL_\d]*)$`)
|
||||
func (interp *Interpreter) cfg(root *node, pkgID string) ([]*node, error) {
|
||||
sc := interp.initScopePkg(pkgID)
|
||||
var initNodes []*node
|
||||
var iotaValue int
|
||||
var err error
|
||||
|
||||
root.Walk(func(n *node) bool {
|
||||
@@ -204,7 +203,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 +369,18 @@ func (interp *Interpreter) cfg(root *node, pkgID string) ([]*node, error) {
|
||||
}
|
||||
return false
|
||||
|
||||
case constDecl:
|
||||
// Early parse of constDecl subtrees, to compute all constant
|
||||
// values which may be used in further declarations.
|
||||
if !sc.global {
|
||||
for _, c := range n.child {
|
||||
if _, err = interp.cfg(c, pkgID); err != nil {
|
||||
// No error processing here, to allow recovery in subtree nodes.
|
||||
err = nil
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
case arrayType, basicLit, chanType, funcType, mapType, structType:
|
||||
n.typ, err = nodeType(interp, sc, n)
|
||||
return false
|
||||
@@ -525,7 +536,11 @@ func (interp *Interpreter) cfg(root *node, pkgID string) ([]*node, error) {
|
||||
}
|
||||
if n.anc.kind == constDecl {
|
||||
sc.sym[dest.ident].kind = constSym
|
||||
iotaValue++
|
||||
if childPos(n) == len(n.anc.child)-1 {
|
||||
sc.iota = 0
|
||||
} else {
|
||||
sc.iota++
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -542,22 +557,28 @@ func (interp *Interpreter) cfg(root *node, pkgID string) ([]*node, error) {
|
||||
case assignXStmt:
|
||||
wireChild(n)
|
||||
l := len(n.child) - 1
|
||||
switch n.child[l].kind {
|
||||
switch lc := n.child[l]; lc.kind {
|
||||
case callExpr:
|
||||
if n.child[l-1].isType(sc) {
|
||||
l--
|
||||
}
|
||||
if r := lc.child[0].typ.numOut(); r != l {
|
||||
err = n.cfgErrorf("assignment mismatch: %d variables but %s returns %d values", l, lc.child[0].name(), r)
|
||||
}
|
||||
n.gen = nop
|
||||
case indexExpr:
|
||||
n.child[l].gen = getIndexMap2
|
||||
lc.gen = getIndexMap2
|
||||
n.gen = nop
|
||||
case typeAssertExpr:
|
||||
if n.child[0].ident == "_" {
|
||||
n.child[l].gen = typeAssertStatus
|
||||
lc.gen = typeAssertStatus
|
||||
} else {
|
||||
n.child[l].gen = typeAssert2
|
||||
lc.gen = typeAssert2
|
||||
}
|
||||
n.gen = nop
|
||||
case unaryExpr:
|
||||
if n.child[l].action == aRecv {
|
||||
n.child[l].gen = recv2
|
||||
if lc.action == aRecv {
|
||||
lc.gen = recv2
|
||||
n.gen = nop
|
||||
}
|
||||
}
|
||||
@@ -565,7 +586,7 @@ func (interp *Interpreter) cfg(root *node, pkgID string) ([]*node, error) {
|
||||
case defineXStmt:
|
||||
wireChild(n)
|
||||
if sc.def == nil {
|
||||
// in global scope, type definition already handled by GTA
|
||||
// In global scope, type definition already handled by GTA.
|
||||
break
|
||||
}
|
||||
err = compDefineX(sc, n)
|
||||
@@ -575,8 +596,8 @@ func (interp *Interpreter) cfg(root *node, pkgID string) ([]*node, error) {
|
||||
nilSym := interp.universe.sym["nil"]
|
||||
c0, c1 := n.child[0], n.child[1]
|
||||
t0, t1 := c0.typ.TypeOf(), c1.typ.TypeOf()
|
||||
// Shift operator type is inherited from first parameter only
|
||||
// All other binary operators require both parameter types to be the same
|
||||
// Shift operator type is inherited from first parameter only.
|
||||
// All other binary operators require both parameter types to be the same.
|
||||
if !isShiftNode(n) && !c0.typ.untyped && !c1.typ.untyped && !c0.typ.equals(c1.typ) {
|
||||
err = n.cfgErrorf("mismatched types %s and %s", c0.typ.id(), c1.typ.id())
|
||||
break
|
||||
@@ -625,33 +646,35 @@ func (interp *Interpreter) cfg(root *node, pkgID string) ([]*node, error) {
|
||||
if err != nil {
|
||||
break
|
||||
}
|
||||
if c0.rval.IsValid() && c1.rval.IsValid() && constOp[n.action] != nil {
|
||||
if n.typ == nil {
|
||||
if n.typ, err = nodeType(interp, sc, n); err != nil {
|
||||
return
|
||||
}
|
||||
if n.typ == nil {
|
||||
if n.typ, err = nodeType(interp, sc, n); err != nil {
|
||||
break
|
||||
}
|
||||
n.typ.TypeOf() // init reflect type
|
||||
constOp[n.action](n)
|
||||
}
|
||||
if c0.rval.IsValid() && c1.rval.IsValid() && !isInterface(n.typ) && constOp[n.action] != nil {
|
||||
n.typ.TypeOf() // Force compute of reflection type.
|
||||
constOp[n.action](n) // Compute a constant result now rather than during exec.
|
||||
}
|
||||
switch {
|
||||
case n.rval.IsValid():
|
||||
// This operation involved constants, and the result is already computed
|
||||
// by constOp and available in n.rval. Nothing else to do at execution.
|
||||
n.gen = nop
|
||||
n.findex = -1
|
||||
case n.anc.kind == assignStmt && n.anc.action == aAssign:
|
||||
// To avoid a copy in frame, if the result is to be assigned, store it directly
|
||||
// at the frame location of destination.
|
||||
dest := n.anc.child[childPos(n)-n.anc.nright]
|
||||
n.typ = dest.typ
|
||||
n.findex = dest.findex
|
||||
case n.anc.kind == returnStmt:
|
||||
// To avoid a copy in frame, if the result is to be returned, store it directly
|
||||
// at the frame location reserved for output arguments.
|
||||
pos := childPos(n)
|
||||
n.typ = sc.def.typ.ret[pos]
|
||||
n.findex = pos
|
||||
default:
|
||||
if n.typ == nil {
|
||||
if n.typ, err = nodeType(interp, sc, n); err != nil {
|
||||
return
|
||||
}
|
||||
}
|
||||
// Allocate a new location in frame, and store the result here.
|
||||
n.findex = sc.add(n.typ)
|
||||
}
|
||||
|
||||
@@ -707,11 +730,7 @@ func (interp *Interpreter) cfg(root *node, pkgID string) ([]*node, error) {
|
||||
}
|
||||
sc = sc.pop()
|
||||
|
||||
case constDecl:
|
||||
iotaValue = 0
|
||||
wireChild(n)
|
||||
|
||||
case varDecl:
|
||||
case constDecl, varDecl:
|
||||
wireChild(n)
|
||||
|
||||
case declStmt, exprStmt, sendStmt:
|
||||
@@ -754,14 +773,18 @@ func (interp *Interpreter) cfg(root *node, pkgID string) ([]*node, error) {
|
||||
if n.typ, err = nodeType(interp, sc, n); err != nil {
|
||||
return
|
||||
}
|
||||
if n.typ.cat == builtinT {
|
||||
switch {
|
||||
case n.typ.cat == builtinT:
|
||||
n.findex = -1
|
||||
n.val = nil
|
||||
} else {
|
||||
case n.anc.kind == returnStmt:
|
||||
// Store result directly to frame output location, to avoid a frame copy.
|
||||
n.findex = 0
|
||||
default:
|
||||
n.findex = sc.add(n.typ)
|
||||
}
|
||||
if op, ok := constBltn[n.child[0].ident]; ok && n.anc.action != aAssign {
|
||||
op(n) // pre-compute non-assigned constant builtin calls
|
||||
op(n) // pre-compute non-assigned constant :
|
||||
}
|
||||
|
||||
case n.child[0].isType(sc):
|
||||
@@ -769,6 +792,7 @@ func (interp *Interpreter) cfg(root *node, pkgID string) ([]*node, error) {
|
||||
if isInt(n.child[0].typ.TypeOf()) && n.child[1].kind == basicLit && isFloat(n.child[1].typ.TypeOf()) {
|
||||
err = n.cfgErrorf("truncated to integer")
|
||||
}
|
||||
n.action = aConvert
|
||||
if isInterface(n.child[0].typ) && !n.child[1].isNil() {
|
||||
// Convert to interface: just check that all required methods are defined by concrete type.
|
||||
c0, c1 := n.child[0], n.child[1]
|
||||
@@ -799,22 +823,30 @@ func (interp *Interpreter) cfg(root *node, pkgID string) ([]*node, error) {
|
||||
}
|
||||
} else {
|
||||
n.typ = &itype{cat: valueT, rtype: typ.Out(0)}
|
||||
n.findex = sc.add(n.typ)
|
||||
for i := 1; i < typ.NumOut(); i++ {
|
||||
sc.add(&itype{cat: valueT, rtype: typ.Out(i)})
|
||||
if n.anc.kind == returnStmt {
|
||||
n.findex = childPos(n)
|
||||
} else {
|
||||
n.findex = sc.add(n.typ)
|
||||
for i := 1; i < typ.NumOut(); i++ {
|
||||
sc.add(&itype{cat: valueT, rtype: typ.Out(i)})
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
default:
|
||||
if n.child[0].action == aGetFunc {
|
||||
// allocate frame entry for anonymous function
|
||||
// Allocate a frame entry to store the anonymous function definition.
|
||||
sc.add(n.child[0].typ)
|
||||
}
|
||||
if typ := n.child[0].typ; len(typ.ret) > 0 {
|
||||
n.typ = typ.ret[0]
|
||||
n.findex = sc.add(n.typ)
|
||||
for _, t := range typ.ret[1:] {
|
||||
sc.add(t)
|
||||
if n.anc.kind == returnStmt {
|
||||
n.findex = childPos(n)
|
||||
} else {
|
||||
n.findex = sc.add(n.typ)
|
||||
for _, t := range typ.ret[1:] {
|
||||
sc.add(t)
|
||||
}
|
||||
}
|
||||
} else {
|
||||
n.findex = -1
|
||||
@@ -827,7 +859,7 @@ func (interp *Interpreter) cfg(root *node, pkgID string) ([]*node, error) {
|
||||
case typeSwichAssign(n) && len(n.child) > 1:
|
||||
n.start = n.child[1].start
|
||||
case len(n.child) == 0:
|
||||
// empty case body: jump to switch node (exit node)
|
||||
// Empty case body: jump to switch node (exit node).
|
||||
n.start = n.anc.anc.anc
|
||||
default:
|
||||
n.start = n.child[0].start
|
||||
@@ -838,10 +870,14 @@ 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()
|
||||
@@ -1003,7 +1039,7 @@ func (interp *Interpreter) cfg(root *node, pkgID string) ([]*node, error) {
|
||||
n.rval = sym.rval
|
||||
n.kind = basicLit
|
||||
case n.ident == "iota":
|
||||
n.rval = reflect.ValueOf(iotaValue)
|
||||
n.rval = reflect.ValueOf(sc.iota)
|
||||
n.kind = basicLit
|
||||
case n.ident == "nil":
|
||||
n.kind = basicLit
|
||||
@@ -1256,6 +1292,7 @@ func (interp *Interpreter) cfg(root *node, pkgID string) ([]*node, error) {
|
||||
n.typ = &itype{cat: valueT, rtype: s.Type(), untyped: isValueUntyped(s)}
|
||||
n.rval = s
|
||||
}
|
||||
n.action = aGetSym
|
||||
n.gen = nop
|
||||
} else {
|
||||
err = n.cfgErrorf("package %s \"%s\" has no symbol %s", n.child[0].ident, pkg, name)
|
||||
@@ -1267,6 +1304,7 @@ func (interp *Interpreter) cfg(root *node, pkgID string) ([]*node, error) {
|
||||
n.findex = sym.index
|
||||
n.val = sym.node
|
||||
n.gen = nop
|
||||
n.action = aGetSym
|
||||
n.typ = sym.typ
|
||||
n.sym = sym
|
||||
n.rval = sym.rval
|
||||
@@ -1344,14 +1382,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 {
|
||||
@@ -1447,6 +1486,7 @@ func (interp *Interpreter) cfg(root *node, pkgID string) ([]*node, error) {
|
||||
}
|
||||
}
|
||||
c := clauses[l-1] // Last clause.
|
||||
c.fnext = n
|
||||
if len(c.child) == 0 {
|
||||
c.tnext = n // Clause body is empty, exit.
|
||||
} else {
|
||||
@@ -1549,13 +1589,13 @@ func (interp *Interpreter) cfg(root *node, pkgID string) ([]*node, error) {
|
||||
return
|
||||
}
|
||||
}
|
||||
// TODO: Optimisation: avoid allocation if boolean branch op (i.e. '!' in an 'if' expr)
|
||||
if n.child[0].rval.IsValid() && constOp[n.action] != nil {
|
||||
if n.typ == nil {
|
||||
if n.typ, err = nodeType(interp, sc, n); err != nil {
|
||||
return
|
||||
}
|
||||
if n.typ == nil {
|
||||
if n.typ, err = nodeType(interp, sc, n); err != nil {
|
||||
return
|
||||
}
|
||||
}
|
||||
// TODO: Optimisation: avoid allocation if boolean branch op (i.e. '!' in an 'if' expr)
|
||||
if n.child[0].rval.IsValid() && !isInterface(n.typ) && constOp[n.action] != nil {
|
||||
n.typ.TypeOf() // init reflect type
|
||||
constOp[n.action](n)
|
||||
}
|
||||
@@ -1572,11 +1612,6 @@ func (interp *Interpreter) cfg(root *node, pkgID string) ([]*node, error) {
|
||||
n.typ = sc.def.typ.ret[pos]
|
||||
n.findex = pos
|
||||
default:
|
||||
if n.typ == nil {
|
||||
if n.typ, err = nodeType(interp, sc, n); err != nil {
|
||||
return
|
||||
}
|
||||
}
|
||||
n.findex = sc.add(n.typ)
|
||||
}
|
||||
|
||||
@@ -1627,6 +1662,12 @@ func compDefineX(sc *scope, n *node) error {
|
||||
} else {
|
||||
types = funtype.ret
|
||||
}
|
||||
if n.child[l-1].isType(sc) {
|
||||
l--
|
||||
}
|
||||
if len(types) != l {
|
||||
return n.cfgErrorf("assignment mismatch: %d variables but %s returns %d values", l, src.child[0].name(), len(types))
|
||||
}
|
||||
n.gen = nop
|
||||
|
||||
case indexExpr:
|
||||
@@ -1811,6 +1852,16 @@ func wireChild(n *node) {
|
||||
}
|
||||
}
|
||||
|
||||
func (n *node) name() (s string) {
|
||||
switch {
|
||||
case n.ident != "":
|
||||
s = n.ident
|
||||
case n.action == aGetSym:
|
||||
s = n.child[0].ident + "." + n.child[1].ident
|
||||
}
|
||||
return s
|
||||
}
|
||||
|
||||
// isInteger returns true if node type is integer, false otherwise
|
||||
func (n *node) isInteger() bool {
|
||||
if isInt(n.typ.TypeOf()) {
|
||||
@@ -1927,7 +1978,7 @@ func isMethod(n *node) bool {
|
||||
}
|
||||
|
||||
func isMapEntry(n *node) bool {
|
||||
return n.action == aGetIndex && n.child[0].typ.cat == mapT
|
||||
return n.action == aGetIndex && isMap(n.child[0].typ)
|
||||
}
|
||||
|
||||
func isBinCall(n *node) bool {
|
||||
|
||||
@@ -9,7 +9,6 @@ import "reflect"
|
||||
func (interp *Interpreter) gta(root *node, rpath, pkgID string) ([]*node, error) {
|
||||
sc := interp.initScopePkg(pkgID)
|
||||
var err error
|
||||
var iotaValue int
|
||||
var revisit []*node
|
||||
|
||||
root.Walk(func(n *node) bool {
|
||||
@@ -18,9 +17,8 @@ func (interp *Interpreter) gta(root *node, rpath, pkgID string) ([]*node, error)
|
||||
}
|
||||
switch n.kind {
|
||||
case constDecl:
|
||||
iotaValue = 0
|
||||
// Early parse of constDecl subtree, to compute all constant
|
||||
// values which may be necessary in further declarations.
|
||||
// values which may be used in further declarations.
|
||||
if _, err = interp.cfg(n, pkgID); err != nil {
|
||||
// No error processing here, to allow recovery in subtree nodes.
|
||||
err = nil
|
||||
@@ -47,7 +45,7 @@ func (interp *Interpreter) gta(root *node, rpath, pkgID string) ([]*node, error)
|
||||
|
||||
for i := 0; i < n.nleft; i++ {
|
||||
dest, src := n.child[i], n.child[sbase+i]
|
||||
val := reflect.ValueOf(iotaValue)
|
||||
val := reflect.ValueOf(sc.iota)
|
||||
if n.anc.kind == constDecl {
|
||||
if _, err2 := interp.cfg(n, pkgID); err2 != nil {
|
||||
// Constant value can not be computed yet.
|
||||
@@ -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
|
||||
|
||||
@@ -455,16 +455,34 @@ func (interp *Interpreter) Use(values Exports) {
|
||||
// REPL performs a Read-Eval-Print-Loop on input reader.
|
||||
// Results are printed on output writer.
|
||||
func (interp *Interpreter) REPL(in io.Reader, out io.Writer) {
|
||||
s := bufio.NewScanner(in)
|
||||
// Preimport used bin packages, to avoid having to import these packages manually
|
||||
// in REPL mode. These packages are already loaded anyway.
|
||||
sc := interp.universe
|
||||
for k := range interp.binPkg {
|
||||
name := identifier.FindString(k)
|
||||
if name == "" || name == "rand" || name == "scanner" || name == "template" || name == "pprof" {
|
||||
// Skip any package with an ambiguous name (i.e crypto/rand vs math/rand).
|
||||
// Those will have to be imported explicitly.
|
||||
continue
|
||||
}
|
||||
sc.sym[name] = &symbol{kind: pkgSym, typ: &itype{cat: binPkgT, path: k, scope: sc}}
|
||||
}
|
||||
|
||||
// Set prompt.
|
||||
var v reflect.Value
|
||||
var err error
|
||||
prompt := getPrompt(in, out)
|
||||
prompt()
|
||||
prompt(v)
|
||||
|
||||
// Read, Eval, Print in a Loop.
|
||||
src := ""
|
||||
s := bufio.NewScanner(in)
|
||||
for s.Scan() {
|
||||
src += s.Text() + "\n"
|
||||
ctx, cancel := context.WithCancel(context.Background())
|
||||
defer cancel()
|
||||
handleSignal(ctx, cancel)
|
||||
v, err := interp.EvalWithContext(ctx, src)
|
||||
v, err = interp.EvalWithContext(ctx, src)
|
||||
signal.Reset()
|
||||
if err != nil {
|
||||
switch e := err.(type) {
|
||||
@@ -479,11 +497,9 @@ func (interp *Interpreter) REPL(in io.Reader, out io.Writer) {
|
||||
default:
|
||||
fmt.Fprintln(out, err)
|
||||
}
|
||||
} else if v.IsValid() {
|
||||
fmt.Fprintln(out, v)
|
||||
}
|
||||
src = ""
|
||||
prompt()
|
||||
prompt(v)
|
||||
}
|
||||
}
|
||||
|
||||
@@ -495,16 +511,21 @@ func (interp *Interpreter) Repl(in, out *os.File) {
|
||||
}
|
||||
|
||||
// getPrompt returns a function which prints a prompt only if input is a terminal.
|
||||
func getPrompt(in io.Reader, out io.Writer) func() {
|
||||
func getPrompt(in io.Reader, out io.Writer) func(reflect.Value) {
|
||||
s, ok := in.(interface{ Stat() (os.FileInfo, error) })
|
||||
if !ok {
|
||||
return func() {}
|
||||
return func(reflect.Value) {}
|
||||
}
|
||||
stat, err := s.Stat()
|
||||
if err == nil && stat.Mode()&os.ModeCharDevice != 0 {
|
||||
return func() { fmt.Fprint(out, "> ") }
|
||||
return func(v reflect.Value) {
|
||||
if v.IsValid() {
|
||||
fmt.Fprintln(out, ":", v)
|
||||
}
|
||||
fmt.Fprint(out, "> ")
|
||||
}
|
||||
}
|
||||
return func() {}
|
||||
return func(reflect.Value) {}
|
||||
}
|
||||
|
||||
// handleSignal wraps signal handling for eval cancellation.
|
||||
|
||||
@@ -32,6 +32,8 @@ func TestInterpConsistencyBuild(t *testing.T) {
|
||||
|
||||
for _, file := range files {
|
||||
if filepath.Ext(file.Name()) != ".go" ||
|
||||
file.Name() == "assign11.go" || // expect error
|
||||
file.Name() == "assign12.go" || // expect error
|
||||
file.Name() == "bad0.go" || // expect error
|
||||
file.Name() == "const9.go" || // expect error
|
||||
file.Name() == "export1.go" || // non-main package
|
||||
@@ -134,6 +136,16 @@ func TestInterpErrorConsistency(t *testing.T) {
|
||||
expectedInterp string
|
||||
expectedExec string
|
||||
}{
|
||||
{
|
||||
fileName: "assign11.go",
|
||||
expectedInterp: "6:2: assignment mismatch: 3 variables but fmt.Println returns 2 values",
|
||||
expectedExec: "6:10: assignment mismatch: 3 variables but fmt.Println returns 2 values",
|
||||
},
|
||||
{
|
||||
fileName: "assign12.go",
|
||||
expectedInterp: "6:2: assignment mismatch: 3 variables but fmt.Println returns 2 values",
|
||||
expectedExec: "6:10: assignment mismatch: 3 variables but fmt.Println returns 2 values",
|
||||
},
|
||||
{
|
||||
fileName: "bad0.go",
|
||||
expectedInterp: "1:1: expected 'package', found println",
|
||||
|
||||
56
interp/op.go
56
interp/op.go
@@ -7,9 +7,9 @@ import "reflect"
|
||||
// Arithmetic operators
|
||||
|
||||
func add(n *node) {
|
||||
dest := genValue(n)
|
||||
next := getExec(n.tnext)
|
||||
typ := n.typ.TypeOf()
|
||||
typ := n.typ.concrete().TypeOf()
|
||||
dest := genValueOutput(n, typ)
|
||||
c0, c1 := n.child[0], n.child[1]
|
||||
|
||||
switch typ.Kind() {
|
||||
@@ -167,9 +167,9 @@ func addConst(n *node) {
|
||||
}
|
||||
|
||||
func and(n *node) {
|
||||
dest := genValue(n)
|
||||
next := getExec(n.tnext)
|
||||
typ := n.typ.TypeOf()
|
||||
typ := n.typ.concrete().TypeOf()
|
||||
dest := genValueOutput(n, typ)
|
||||
c0, c1 := n.child[0], n.child[1]
|
||||
|
||||
switch typ.Kind() {
|
||||
@@ -245,9 +245,9 @@ func andConst(n *node) {
|
||||
}
|
||||
|
||||
func andNot(n *node) {
|
||||
dest := genValue(n)
|
||||
next := getExec(n.tnext)
|
||||
typ := n.typ.TypeOf()
|
||||
typ := n.typ.concrete().TypeOf()
|
||||
dest := genValueOutput(n, typ)
|
||||
c0, c1 := n.child[0], n.child[1]
|
||||
|
||||
switch typ.Kind() {
|
||||
@@ -323,9 +323,9 @@ func andNotConst(n *node) {
|
||||
}
|
||||
|
||||
func mul(n *node) {
|
||||
dest := genValue(n)
|
||||
next := getExec(n.tnext)
|
||||
typ := n.typ.TypeOf()
|
||||
typ := n.typ.concrete().TypeOf()
|
||||
dest := genValueOutput(n, typ)
|
||||
c0, c1 := n.child[0], n.child[1]
|
||||
|
||||
switch typ.Kind() {
|
||||
@@ -457,9 +457,9 @@ func mulConst(n *node) {
|
||||
}
|
||||
|
||||
func or(n *node) {
|
||||
dest := genValue(n)
|
||||
next := getExec(n.tnext)
|
||||
typ := n.typ.TypeOf()
|
||||
typ := n.typ.concrete().TypeOf()
|
||||
dest := genValueOutput(n, typ)
|
||||
c0, c1 := n.child[0], n.child[1]
|
||||
|
||||
switch typ.Kind() {
|
||||
@@ -535,9 +535,9 @@ func orConst(n *node) {
|
||||
}
|
||||
|
||||
func quo(n *node) {
|
||||
dest := genValue(n)
|
||||
next := getExec(n.tnext)
|
||||
typ := n.typ.TypeOf()
|
||||
typ := n.typ.concrete().TypeOf()
|
||||
dest := genValueOutput(n, typ)
|
||||
c0, c1 := n.child[0], n.child[1]
|
||||
|
||||
switch typ.Kind() {
|
||||
@@ -669,9 +669,9 @@ func quoConst(n *node) {
|
||||
}
|
||||
|
||||
func rem(n *node) {
|
||||
dest := genValue(n)
|
||||
next := getExec(n.tnext)
|
||||
typ := n.typ.TypeOf()
|
||||
typ := n.typ.concrete().TypeOf()
|
||||
dest := genValueOutput(n, typ)
|
||||
c0, c1 := n.child[0], n.child[1]
|
||||
|
||||
switch typ.Kind() {
|
||||
@@ -747,9 +747,9 @@ func remConst(n *node) {
|
||||
}
|
||||
|
||||
func shl(n *node) {
|
||||
dest := genValue(n)
|
||||
next := getExec(n.tnext)
|
||||
typ := n.typ.TypeOf()
|
||||
typ := n.typ.concrete().TypeOf()
|
||||
dest := genValueOutput(n, typ)
|
||||
c0, c1 := n.child[0], n.child[1]
|
||||
|
||||
switch typ.Kind() {
|
||||
@@ -825,9 +825,9 @@ func shlConst(n *node) {
|
||||
}
|
||||
|
||||
func shr(n *node) {
|
||||
dest := genValue(n)
|
||||
next := getExec(n.tnext)
|
||||
typ := n.typ.TypeOf()
|
||||
typ := n.typ.concrete().TypeOf()
|
||||
dest := genValueOutput(n, typ)
|
||||
c0, c1 := n.child[0], n.child[1]
|
||||
|
||||
switch typ.Kind() {
|
||||
@@ -903,9 +903,9 @@ func shrConst(n *node) {
|
||||
}
|
||||
|
||||
func sub(n *node) {
|
||||
dest := genValue(n)
|
||||
next := getExec(n.tnext)
|
||||
typ := n.typ.TypeOf()
|
||||
typ := n.typ.concrete().TypeOf()
|
||||
dest := genValueOutput(n, typ)
|
||||
c0, c1 := n.child[0], n.child[1]
|
||||
|
||||
switch typ.Kind() {
|
||||
@@ -1037,9 +1037,9 @@ func subConst(n *node) {
|
||||
}
|
||||
|
||||
func xor(n *node) {
|
||||
dest := genValue(n)
|
||||
next := getExec(n.tnext)
|
||||
typ := n.typ.TypeOf()
|
||||
typ := n.typ.concrete().TypeOf()
|
||||
dest := genValueOutput(n, typ)
|
||||
c0, c1 := n.child[0], n.child[1]
|
||||
|
||||
switch typ.Kind() {
|
||||
@@ -1917,7 +1917,7 @@ func posConst(n *node) {
|
||||
|
||||
func equal(n *node) {
|
||||
tnext := getExec(n.tnext)
|
||||
dest := genValue(n)
|
||||
dest := genValueOutput(n, reflect.TypeOf(true))
|
||||
c0, c1 := n.child[0], n.child[1]
|
||||
|
||||
switch t0, t1 := c0.typ.TypeOf(), c1.typ.TypeOf(); {
|
||||
@@ -2346,7 +2346,7 @@ func equal(n *node) {
|
||||
|
||||
func greater(n *node) {
|
||||
tnext := getExec(n.tnext)
|
||||
dest := genValue(n)
|
||||
dest := genValueOutput(n, reflect.TypeOf(true))
|
||||
c0, c1 := n.child[0], n.child[1]
|
||||
|
||||
switch t0, t1 := c0.typ.TypeOf(), c1.typ.TypeOf(); {
|
||||
@@ -2635,7 +2635,7 @@ func greater(n *node) {
|
||||
|
||||
func greaterEqual(n *node) {
|
||||
tnext := getExec(n.tnext)
|
||||
dest := genValue(n)
|
||||
dest := genValueOutput(n, reflect.TypeOf(true))
|
||||
c0, c1 := n.child[0], n.child[1]
|
||||
|
||||
switch t0, t1 := c0.typ.TypeOf(), c1.typ.TypeOf(); {
|
||||
@@ -2924,7 +2924,7 @@ func greaterEqual(n *node) {
|
||||
|
||||
func lower(n *node) {
|
||||
tnext := getExec(n.tnext)
|
||||
dest := genValue(n)
|
||||
dest := genValueOutput(n, reflect.TypeOf(true))
|
||||
c0, c1 := n.child[0], n.child[1]
|
||||
|
||||
switch t0, t1 := c0.typ.TypeOf(), c1.typ.TypeOf(); {
|
||||
@@ -3213,7 +3213,7 @@ func lower(n *node) {
|
||||
|
||||
func lowerEqual(n *node) {
|
||||
tnext := getExec(n.tnext)
|
||||
dest := genValue(n)
|
||||
dest := genValueOutput(n, reflect.TypeOf(true))
|
||||
c0, c1 := n.child[0], n.child[1]
|
||||
|
||||
switch t0, t1 := c0.typ.TypeOf(), c1.typ.TypeOf(); {
|
||||
@@ -3502,7 +3502,7 @@ func lowerEqual(n *node) {
|
||||
|
||||
func notEqual(n *node) {
|
||||
tnext := getExec(n.tnext)
|
||||
dest := genValue(n)
|
||||
dest := genValueOutput(n, reflect.TypeOf(true))
|
||||
c0, c1 := n.child[0], n.child[1]
|
||||
|
||||
switch t0, t1 := c0.typ.TypeOf(), c1.typ.TypeOf(); {
|
||||
|
||||
181
interp/run.go
181
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] }
|
||||
@@ -792,7 +821,11 @@ func call(n *node) {
|
||||
d.Set(src)
|
||||
}
|
||||
case variadic >= 0 && i >= variadic:
|
||||
vararg.Set(reflect.Append(vararg, v(f)))
|
||||
if v(f).Type() == vararg.Type() {
|
||||
vararg.Set(v(f))
|
||||
} else {
|
||||
vararg.Set(reflect.Append(vararg, v(f)))
|
||||
}
|
||||
default:
|
||||
dest[i].Set(v(f))
|
||||
}
|
||||
@@ -908,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
|
||||
@@ -922,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]
|
||||
@@ -944,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)
|
||||
@@ -1528,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 {
|
||||
@@ -1556,15 +1606,15 @@ func _return(n *node) {
|
||||
|
||||
switch len(child) {
|
||||
case 0:
|
||||
n.exec = func(f *frame) bltn { return next }
|
||||
n.exec = nil
|
||||
case 1:
|
||||
if child[0].kind == binaryExpr {
|
||||
n.exec = func(f *frame) bltn { return next }
|
||||
if child[0].kind == binaryExpr || child[0].action == aCall {
|
||||
n.exec = nil
|
||||
} else {
|
||||
v := values[0]
|
||||
n.exec = func(f *frame) bltn {
|
||||
f.data[0].Set(v(f))
|
||||
return next
|
||||
return nil
|
||||
}
|
||||
}
|
||||
case 2:
|
||||
@@ -1572,14 +1622,14 @@ func _return(n *node) {
|
||||
n.exec = func(f *frame) bltn {
|
||||
f.data[0].Set(v0(f))
|
||||
f.data[1].Set(v1(f))
|
||||
return next
|
||||
return nil
|
||||
}
|
||||
default:
|
||||
n.exec = func(f *frame) bltn {
|
||||
for i, value := range values {
|
||||
f.data[i].Set(value(f))
|
||||
}
|
||||
return next
|
||||
return nil
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -2018,11 +2068,12 @@ func _case(n *node) {
|
||||
// match against multiple types: assign var to interface value
|
||||
n.exec = func(f *frame) bltn {
|
||||
val := srcValue(f)
|
||||
vid := val.Interface().(valueInterface).node.typ.id()
|
||||
for _, typ := range types {
|
||||
if vid == typ.id() {
|
||||
destValue(f).Set(val)
|
||||
return tnext
|
||||
if v := srcValue(f).Interface().(valueInterface).node; v != nil {
|
||||
for _, typ := range types {
|
||||
if v.typ.id() == typ.id() {
|
||||
destValue(f).Set(val)
|
||||
return tnext
|
||||
}
|
||||
}
|
||||
}
|
||||
return fnext
|
||||
@@ -2034,10 +2085,11 @@ func _case(n *node) {
|
||||
n.exec = func(f *frame) bltn { return tnext }
|
||||
} else {
|
||||
n.exec = func(f *frame) bltn {
|
||||
vtyp := srcValue(f).Interface().(valueInterface).node.typ
|
||||
for _, typ := range types {
|
||||
if vtyp.id() == typ.id() {
|
||||
return tnext
|
||||
if v := srcValue(f).Interface().(valueInterface).node; v != nil {
|
||||
for _, typ := range types {
|
||||
if v.typ.id() == typ.id() {
|
||||
return tnext
|
||||
}
|
||||
}
|
||||
}
|
||||
return fnext
|
||||
@@ -2068,7 +2120,7 @@ func _case(n *node) {
|
||||
}
|
||||
|
||||
func appendSlice(n *node) {
|
||||
dest := genValue(n)
|
||||
dest := genValueOutput(n, n.typ.rtype)
|
||||
next := getExec(n.tnext)
|
||||
value := genValue(n.child[1])
|
||||
value0 := genValue(n.child[2])
|
||||
@@ -2093,7 +2145,7 @@ func _append(n *node) {
|
||||
appendSlice(n)
|
||||
return
|
||||
}
|
||||
dest := genValue(n)
|
||||
dest := genValueOutput(n, n.typ.rtype)
|
||||
value := genValue(n.child[1])
|
||||
next := getExec(n.tnext)
|
||||
|
||||
@@ -2143,7 +2195,7 @@ func _append(n *node) {
|
||||
}
|
||||
|
||||
func _cap(n *node) {
|
||||
dest := genValue(n)
|
||||
dest := genValueOutput(n, reflect.TypeOf(int(0)))
|
||||
value := genValue(n.child[1])
|
||||
next := getExec(n.tnext)
|
||||
|
||||
@@ -2154,7 +2206,7 @@ func _cap(n *node) {
|
||||
}
|
||||
|
||||
func _copy(n *node) {
|
||||
dest := genValue(n)
|
||||
dest := genValueOutput(n, reflect.TypeOf(int(0)))
|
||||
value0 := genValueArray(n.child[1])
|
||||
value1 := genValue(n.child[2])
|
||||
next := getExec(n.tnext)
|
||||
@@ -2176,7 +2228,7 @@ func _close(n *node) {
|
||||
}
|
||||
|
||||
func _complex(n *node) {
|
||||
dest := genValue(n)
|
||||
dest := genValueOutput(n, reflect.TypeOf(complex(0, 0)))
|
||||
c1, c2 := n.child[1], n.child[2]
|
||||
convertLiteralValue(c1, floatType)
|
||||
convertLiteralValue(c2, floatType)
|
||||
@@ -2199,7 +2251,7 @@ func _complex(n *node) {
|
||||
}
|
||||
|
||||
func _imag(n *node) {
|
||||
dest := genValue(n)
|
||||
dest := genValueOutput(n, reflect.TypeOf(float64(0)))
|
||||
convertLiteralValue(n.child[1], complexType)
|
||||
value := genValue(n.child[1])
|
||||
next := getExec(n.tnext)
|
||||
@@ -2211,7 +2263,7 @@ func _imag(n *node) {
|
||||
}
|
||||
|
||||
func _real(n *node) {
|
||||
dest := genValue(n)
|
||||
dest := genValueOutput(n, reflect.TypeOf(float64(0)))
|
||||
convertLiteralValue(n.child[1], complexType)
|
||||
value := genValue(n.child[1])
|
||||
next := getExec(n.tnext)
|
||||
@@ -2235,7 +2287,7 @@ func _delete(n *node) {
|
||||
}
|
||||
|
||||
func _len(n *node) {
|
||||
dest := genValue(n)
|
||||
dest := genValueOutput(n, reflect.TypeOf(int(0)))
|
||||
value := genValue(n.child[1])
|
||||
next := getExec(n.tnext)
|
||||
|
||||
@@ -2246,9 +2298,9 @@ func _len(n *node) {
|
||||
}
|
||||
|
||||
func _new(n *node) {
|
||||
dest := genValue(n)
|
||||
next := getExec(n.tnext)
|
||||
typ := n.child[1].typ.TypeOf()
|
||||
dest := genValueOutput(n, reflect.PtrTo(typ))
|
||||
|
||||
n.exec = func(f *frame) bltn {
|
||||
dest(f).Set(reflect.New(typ))
|
||||
@@ -2258,9 +2310,9 @@ func _new(n *node) {
|
||||
|
||||
// _make allocates and initializes a slice, a map or a chan.
|
||||
func _make(n *node) {
|
||||
dest := genValue(n)
|
||||
next := getExec(n.tnext)
|
||||
typ := n.child[1].typ.frameType()
|
||||
dest := genValueOutput(n, typ)
|
||||
|
||||
switch typ.Kind() {
|
||||
case reflect.Array, reflect.Slice:
|
||||
@@ -2538,33 +2590,40 @@ func _select(n *node) {
|
||||
assignedValues := make([]func(*frame) reflect.Value, nbClause)
|
||||
okValues := make([]func(*frame) reflect.Value, nbClause)
|
||||
cases := make([]reflect.SelectCase, nbClause+1)
|
||||
next := getExec(n.tnext)
|
||||
|
||||
for i := 0; i < nbClause; i++ {
|
||||
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
|
||||
|
||||
136
interp/type.go
136
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,20 @@ func (t *itype) referTo(name string, seen map[*itype]bool) bool {
|
||||
return false
|
||||
}
|
||||
|
||||
func (t *itype) numOut() int {
|
||||
if t.cat == valueT {
|
||||
return t.rtype.NumOut()
|
||||
}
|
||||
return len(t.ret)
|
||||
}
|
||||
|
||||
func (t *itype) concrete() *itype {
|
||||
if isInterface(t) && t.val != nil {
|
||||
return t.val.concrete()
|
||||
}
|
||||
return t
|
||||
}
|
||||
|
||||
// IsRecursive returns true if type is recursive.
|
||||
// Only a named struct or interface can be recursive.
|
||||
func (t *itype) isRecursive() bool {
|
||||
@@ -819,17 +845,43 @@ func (t *itype) methods() methodSet {
|
||||
}
|
||||
|
||||
// id returns a unique type identificator string
|
||||
func (t *itype) id() string {
|
||||
// TODO: if res is nil, build identity from String()
|
||||
|
||||
res := ""
|
||||
func (t *itype) id() (res string) {
|
||||
if t.name != "" {
|
||||
return t.path + "." + t.name
|
||||
}
|
||||
switch t.cat {
|
||||
case valueT:
|
||||
res = t.rtype.PkgPath() + "." + t.rtype.Name()
|
||||
case arrayT:
|
||||
res = "[" + strconv.Itoa(t.size) + "]" + t.val.id()
|
||||
case chanT:
|
||||
res = "<-" + t.val.id()
|
||||
case funcT:
|
||||
res = "func("
|
||||
for _, t := range t.arg {
|
||||
res += t.id() + ","
|
||||
}
|
||||
res += ")("
|
||||
for _, t := range t.ret {
|
||||
res += t.id() + ","
|
||||
}
|
||||
res += ")"
|
||||
case interfaceT:
|
||||
res = "interface{"
|
||||
for _, t := range t.field {
|
||||
res += t.name + " " + t.typ.id() + ";"
|
||||
}
|
||||
res += "}"
|
||||
case mapT:
|
||||
res = "map[" + t.key.id() + "]" + t.val.id()
|
||||
case ptrT:
|
||||
res = "*" + t.val.id()
|
||||
default:
|
||||
res = t.path + "." + t.name
|
||||
case structT:
|
||||
res = "struct{"
|
||||
for _, t := range t.field {
|
||||
res += t.name + " " + t.typ.id() + ";"
|
||||
}
|
||||
res += "}"
|
||||
case valueT:
|
||||
res = t.rtype.PkgPath() + "." + t.rtype.Name()
|
||||
}
|
||||
return res
|
||||
}
|
||||
@@ -1170,10 +1222,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 +1250,10 @@ func isStruct(t *itype) bool {
|
||||
}
|
||||
}
|
||||
|
||||
func isBool(t *itype) bool { return t.TypeOf().Kind() == reflect.Bool }
|
||||
|
||||
func isInt(t reflect.Type) bool {
|
||||
if t == nil {
|
||||
return false
|
||||
}
|
||||
switch t.Kind() {
|
||||
case reflect.Int, reflect.Int8, reflect.Int16, reflect.Int32, reflect.Int64, reflect.Uint, reflect.Uint8, reflect.Uint16, reflect.Uint32, reflect.Uint64, reflect.Uintptr:
|
||||
return true
|
||||
@@ -1210,6 +1262,9 @@ func isInt(t reflect.Type) bool {
|
||||
}
|
||||
|
||||
func isUint(t reflect.Type) bool {
|
||||
if t == nil {
|
||||
return false
|
||||
}
|
||||
switch t.Kind() {
|
||||
case reflect.Uint, reflect.Uint8, reflect.Uint16, reflect.Uint32, reflect.Uint64, reflect.Uintptr:
|
||||
return true
|
||||
@@ -1218,6 +1273,9 @@ func isUint(t reflect.Type) bool {
|
||||
}
|
||||
|
||||
func isComplex(t reflect.Type) bool {
|
||||
if t == nil {
|
||||
return false
|
||||
}
|
||||
switch t.Kind() {
|
||||
case reflect.Complex64, reflect.Complex128:
|
||||
return true
|
||||
@@ -1226,6 +1284,9 @@ func isComplex(t reflect.Type) bool {
|
||||
}
|
||||
|
||||
func isFloat(t reflect.Type) bool {
|
||||
if t == nil {
|
||||
return false
|
||||
}
|
||||
switch t.Kind() {
|
||||
case reflect.Float32, reflect.Float64:
|
||||
return true
|
||||
@@ -1234,11 +1295,14 @@ func isFloat(t reflect.Type) bool {
|
||||
}
|
||||
|
||||
func isByteArray(t reflect.Type) bool {
|
||||
if t == nil {
|
||||
return false
|
||||
}
|
||||
k := t.Kind()
|
||||
return (k == reflect.Array || k == reflect.Slice) && t.Elem().Kind() == reflect.Uint8
|
||||
}
|
||||
|
||||
func isFloat32(t reflect.Type) bool { return t.Kind() == reflect.Float32 }
|
||||
func isFloat64(t reflect.Type) bool { return t.Kind() == reflect.Float64 }
|
||||
func isFloat32(t reflect.Type) bool { return t != nil && t.Kind() == reflect.Float32 }
|
||||
func isFloat64(t reflect.Type) bool { return t != nil && t.Kind() == reflect.Float64 }
|
||||
func isNumber(t reflect.Type) bool { return isInt(t) || isFloat(t) || isComplex(t) }
|
||||
func isString(t reflect.Type) bool { return t.Kind() == reflect.String }
|
||||
func isString(t reflect.Type) bool { return t != nil && t.Kind() == reflect.String }
|
||||
|
||||
@@ -182,6 +182,24 @@ func zeroInterfaceValue() reflect.Value {
|
||||
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