Compare commits
8 Commits
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
e78650d359 | ||
|
|
7327ff2811 | ||
|
|
ebde09b47d | ||
|
|
4995654e04 | ||
|
|
0a99eb48c3 | ||
|
|
4a22635585 | ||
|
|
b52dd8cc08 | ||
|
|
daaeac6e2c |
@@ -18,7 +18,7 @@ It powers executable Go scripts and plugins, in embedded interpreters or interac
|
||||
* Works everywhere Go works
|
||||
* All Go & runtime resources accessible from script (with control)
|
||||
* Security: `unsafe` and `syscall` packages neither used nor exported by default
|
||||
* Support Go 1.12 and Go 1.13 (the latest 2 major releases)
|
||||
* Support Go 1.13 and Go 1.14 (the latest 2 major releases)
|
||||
|
||||
## Install
|
||||
|
||||
|
||||
59
_test/cli2.go
Normal file
59
_test/cli2.go
Normal file
@@ -0,0 +1,59 @@
|
||||
package main
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"io/ioutil"
|
||||
"log"
|
||||
"net"
|
||||
"net/http"
|
||||
)
|
||||
|
||||
type T struct {
|
||||
ln net.Listener
|
||||
}
|
||||
|
||||
func (t *T) Close() {
|
||||
t.ln.Close()
|
||||
}
|
||||
|
||||
func client(uri string) {
|
||||
resp, err := http.Get(uri)
|
||||
if err != nil {
|
||||
log.Fatal(err)
|
||||
}
|
||||
body, err := ioutil.ReadAll(resp.Body)
|
||||
if err != nil {
|
||||
log.Fatal(err)
|
||||
}
|
||||
fmt.Println(string(body))
|
||||
}
|
||||
|
||||
func server(ln net.Listener, ready chan bool) {
|
||||
http.HandleFunc("/hello", func(w http.ResponseWriter, r *http.Request) {
|
||||
var r1 *http.Request = r
|
||||
fmt.Fprintln(w, "Welcome to my website!", r1.RequestURI)
|
||||
})
|
||||
|
||||
go http.Serve(ln, nil)
|
||||
ready <- true
|
||||
}
|
||||
|
||||
func main() {
|
||||
ln, err := net.Listen("tcp", "localhost:0")
|
||||
t := &T{ln}
|
||||
if err != nil {
|
||||
log.Fatal(err)
|
||||
}
|
||||
defer t.Close()
|
||||
// defer ln.Close()
|
||||
|
||||
ready := make(chan bool)
|
||||
go server(ln, ready)
|
||||
<-ready
|
||||
|
||||
client(fmt.Sprintf("http://%s/hello", ln.Addr().String()))
|
||||
http.DefaultServeMux = &http.ServeMux{}
|
||||
}
|
||||
|
||||
// Output:
|
||||
// Welcome to my website! /hello
|
||||
13
_test/for10.go
Normal file
13
_test/for10.go
Normal file
@@ -0,0 +1,13 @@
|
||||
package main
|
||||
|
||||
func main() {
|
||||
for a := 0; false; {
|
||||
println("nok", a)
|
||||
a++
|
||||
break
|
||||
}
|
||||
println("bye")
|
||||
}
|
||||
|
||||
// Output:
|
||||
// bye
|
||||
14
_test/for11.go
Normal file
14
_test/for11.go
Normal file
@@ -0,0 +1,14 @@
|
||||
package main
|
||||
|
||||
func main() {
|
||||
a := 0
|
||||
for ; true; a++ {
|
||||
println("nok", a)
|
||||
break
|
||||
}
|
||||
println("bye", a)
|
||||
}
|
||||
|
||||
// Output:
|
||||
// nok 0
|
||||
// bye 0
|
||||
12
_test/for12.go
Normal file
12
_test/for12.go
Normal file
@@ -0,0 +1,12 @@
|
||||
package main
|
||||
|
||||
func main() {
|
||||
for a := 0; false; a++ {
|
||||
println("nok", a)
|
||||
break
|
||||
}
|
||||
println("bye")
|
||||
}
|
||||
|
||||
// Output:
|
||||
// bye
|
||||
13
_test/for13.go
Normal file
13
_test/for13.go
Normal file
@@ -0,0 +1,13 @@
|
||||
package main
|
||||
|
||||
func main() {
|
||||
a := 0
|
||||
for ; false; a++ {
|
||||
println("nok", a)
|
||||
break
|
||||
}
|
||||
println("bye", a)
|
||||
}
|
||||
|
||||
// Output:
|
||||
// bye 0
|
||||
16
_test/for14.go
Normal file
16
_test/for14.go
Normal file
@@ -0,0 +1,16 @@
|
||||
package main
|
||||
|
||||
func main() {
|
||||
for a := 0; true; a++ {
|
||||
println(a)
|
||||
if a > 0 {
|
||||
break
|
||||
}
|
||||
}
|
||||
println("bye")
|
||||
}
|
||||
|
||||
// Output:
|
||||
// 0
|
||||
// 1
|
||||
// bye
|
||||
12
_test/for9.go
Normal file
12
_test/for9.go
Normal file
@@ -0,0 +1,12 @@
|
||||
package main
|
||||
|
||||
func main() {
|
||||
for false {
|
||||
println("nok")
|
||||
break
|
||||
}
|
||||
println("bye")
|
||||
}
|
||||
|
||||
// Output:
|
||||
// bye
|
||||
17
_test/if3.go
Normal file
17
_test/if3.go
Normal file
@@ -0,0 +1,17 @@
|
||||
package main
|
||||
|
||||
func main() {
|
||||
a := 0
|
||||
if false {
|
||||
println("false")
|
||||
a = 1
|
||||
} else {
|
||||
println("true")
|
||||
a = -1
|
||||
}
|
||||
println(a)
|
||||
}
|
||||
|
||||
// Output:
|
||||
// true
|
||||
// -1
|
||||
19
_test/if4.go
Normal file
19
_test/if4.go
Normal file
@@ -0,0 +1,19 @@
|
||||
package main
|
||||
|
||||
const bad = false
|
||||
|
||||
func main() {
|
||||
a := 0
|
||||
if bad {
|
||||
println("false")
|
||||
a = 1
|
||||
} else {
|
||||
println("true")
|
||||
a = -1
|
||||
}
|
||||
println(a)
|
||||
}
|
||||
|
||||
// Output:
|
||||
// true
|
||||
// -1
|
||||
12
_test/if5.go
Normal file
12
_test/if5.go
Normal file
@@ -0,0 +1,12 @@
|
||||
package main
|
||||
|
||||
func main() {
|
||||
if true {
|
||||
println("ok")
|
||||
}
|
||||
println("bye")
|
||||
}
|
||||
|
||||
// Output:
|
||||
// ok
|
||||
// bye
|
||||
11
_test/if6.go
Normal file
11
_test/if6.go
Normal file
@@ -0,0 +1,11 @@
|
||||
package main
|
||||
|
||||
func main() {
|
||||
if false {
|
||||
println("nok")
|
||||
}
|
||||
println("bye")
|
||||
}
|
||||
|
||||
// Output:
|
||||
// bye
|
||||
15
_test/if7.go
Normal file
15
_test/if7.go
Normal file
@@ -0,0 +1,15 @@
|
||||
package main
|
||||
|
||||
func main() {
|
||||
a := 0
|
||||
b := false
|
||||
if (b) {
|
||||
a = 1
|
||||
} else {
|
||||
a = -1
|
||||
}
|
||||
println(a)
|
||||
}
|
||||
|
||||
// Output:
|
||||
// -1
|
||||
12
_test/interface27.go
Normal file
12
_test/interface27.go
Normal file
@@ -0,0 +1,12 @@
|
||||
package main
|
||||
|
||||
import "fmt"
|
||||
|
||||
var errs = map[int]error{0: nil}
|
||||
|
||||
func main() {
|
||||
fmt.Println(errs)
|
||||
}
|
||||
|
||||
// Output:
|
||||
// map[0:<nil>]
|
||||
12
_test/interface28.go
Normal file
12
_test/interface28.go
Normal file
@@ -0,0 +1,12 @@
|
||||
package main
|
||||
|
||||
import "fmt"
|
||||
|
||||
var errs = []error{nil}
|
||||
|
||||
func main() {
|
||||
fmt.Println(errs)
|
||||
}
|
||||
|
||||
// Output:
|
||||
// [<nil>]
|
||||
9
_test/interface29.go
Normal file
9
_test/interface29.go
Normal file
@@ -0,0 +1,9 @@
|
||||
package main
|
||||
|
||||
func main() {
|
||||
var a interface{}
|
||||
println(a == nil)
|
||||
}
|
||||
|
||||
// Output:
|
||||
// true
|
||||
9
_test/interface30.go
Normal file
9
_test/interface30.go
Normal file
@@ -0,0 +1,9 @@
|
||||
package main
|
||||
|
||||
func main() {
|
||||
var a interface{}
|
||||
println(a != nil)
|
||||
}
|
||||
|
||||
// Output:
|
||||
// false
|
||||
24
_test/struct38.go
Normal file
24
_test/struct38.go
Normal file
@@ -0,0 +1,24 @@
|
||||
package main
|
||||
|
||||
type T struct {
|
||||
f func(t *T1)
|
||||
y *xxx
|
||||
}
|
||||
|
||||
type T1 struct {
|
||||
T
|
||||
}
|
||||
|
||||
type xxx struct{}
|
||||
|
||||
var (
|
||||
x1 *T1 = x
|
||||
x = &T1{}
|
||||
)
|
||||
|
||||
func main() {
|
||||
println("ok")
|
||||
}
|
||||
|
||||
// Output:
|
||||
// ok
|
||||
16
_test/switch27.go
Normal file
16
_test/switch27.go
Normal file
@@ -0,0 +1,16 @@
|
||||
package main
|
||||
|
||||
func main() {
|
||||
//a := false
|
||||
switch false {
|
||||
case true:
|
||||
println("true")
|
||||
case false:
|
||||
println("false")
|
||||
}
|
||||
println("bye")
|
||||
}
|
||||
|
||||
// Output:
|
||||
// false
|
||||
// bye
|
||||
15
_test/switch28.go
Normal file
15
_test/switch28.go
Normal file
@@ -0,0 +1,15 @@
|
||||
package main
|
||||
|
||||
func main() {
|
||||
switch {
|
||||
case true:
|
||||
println("true")
|
||||
case false:
|
||||
println("false")
|
||||
}
|
||||
println("bye")
|
||||
}
|
||||
|
||||
// Output:
|
||||
// true
|
||||
// bye
|
||||
14
_test/switch29.go
Normal file
14
_test/switch29.go
Normal file
@@ -0,0 +1,14 @@
|
||||
package main
|
||||
|
||||
func main() {
|
||||
a := 3
|
||||
switch a {
|
||||
case 3:
|
||||
println("three")
|
||||
}
|
||||
println("bye")
|
||||
}
|
||||
|
||||
// Output:
|
||||
// three
|
||||
// bye
|
||||
16
_test/switch30.go
Normal file
16
_test/switch30.go
Normal file
@@ -0,0 +1,16 @@
|
||||
package main
|
||||
|
||||
func main() {
|
||||
a := 3
|
||||
switch a {
|
||||
default:
|
||||
//println("default")
|
||||
case 3:
|
||||
println("three")
|
||||
}
|
||||
println("bye")
|
||||
}
|
||||
|
||||
// Output:
|
||||
// three
|
||||
// bye
|
||||
10
_test/switch31.go
Normal file
10
_test/switch31.go
Normal file
@@ -0,0 +1,10 @@
|
||||
package main
|
||||
|
||||
func main() {
|
||||
switch {
|
||||
}
|
||||
println("bye")
|
||||
}
|
||||
|
||||
// Output:
|
||||
// bye
|
||||
11
_test/switch32.go
Normal file
11
_test/switch32.go
Normal file
@@ -0,0 +1,11 @@
|
||||
package main
|
||||
|
||||
func main() {
|
||||
a := 1
|
||||
switch a {
|
||||
}
|
||||
println("bye", a)
|
||||
}
|
||||
|
||||
// Output:
|
||||
// bye 1
|
||||
11
_test/switch33.go
Normal file
11
_test/switch33.go
Normal file
@@ -0,0 +1,11 @@
|
||||
package main
|
||||
|
||||
func main() {
|
||||
var a interface{}
|
||||
switch a.(type) {
|
||||
}
|
||||
println("bye")
|
||||
}
|
||||
|
||||
// Output:
|
||||
// bye
|
||||
187
interp/cfg.go
187
interp/cfg.go
@@ -317,7 +317,7 @@ func (interp *Interpreter) cfg(root *node, pkgID string) ([]*node, error) {
|
||||
sc = sc.pushBloc()
|
||||
|
||||
case switchStmt, switchIfStmt, typeSwitch:
|
||||
// Make sure default clause is in last position
|
||||
// Make sure default clause is in last position.
|
||||
c := n.lastChild().child
|
||||
if i, l := getDefault(n), len(c)-1; i >= 0 && i != l {
|
||||
c[i], c[l] = c[l], c[i]
|
||||
@@ -863,10 +863,18 @@ func (interp *Interpreter) cfg(root *node, pkgID string) ([]*node, error) {
|
||||
if !isBool(cond.typ) {
|
||||
err = cond.cfgErrorf("non-bool used as for condition")
|
||||
}
|
||||
n.start = cond.start
|
||||
cond.tnext = body.start
|
||||
if cond.rval.IsValid() {
|
||||
// Condition is known at compile time, bypass test.
|
||||
if cond.rval.Bool() {
|
||||
n.start = body.start
|
||||
body.tnext = body.start
|
||||
}
|
||||
} else {
|
||||
n.start = cond.start
|
||||
cond.tnext = body.start
|
||||
body.tnext = cond.start
|
||||
}
|
||||
cond.fnext = n
|
||||
body.tnext = cond.start
|
||||
sc = sc.pop()
|
||||
|
||||
case forStmt2: // for init; cond; {}
|
||||
@@ -875,10 +883,20 @@ func (interp *Interpreter) cfg(root *node, pkgID string) ([]*node, error) {
|
||||
err = cond.cfgErrorf("non-bool used as for condition")
|
||||
}
|
||||
n.start = init.start
|
||||
init.tnext = cond.start
|
||||
if cond.rval.IsValid() {
|
||||
// Condition is known at compile time, bypass test.
|
||||
if cond.rval.Bool() {
|
||||
init.tnext = body.start
|
||||
body.tnext = body.start
|
||||
} else {
|
||||
init.tnext = n
|
||||
}
|
||||
} else {
|
||||
init.tnext = cond.start
|
||||
body.tnext = cond.start
|
||||
}
|
||||
cond.tnext = body.start
|
||||
cond.fnext = n
|
||||
body.tnext = cond.start
|
||||
sc = sc.pop()
|
||||
|
||||
case forStmt3: // for ; cond; post {}
|
||||
@@ -886,14 +904,22 @@ func (interp *Interpreter) cfg(root *node, pkgID string) ([]*node, error) {
|
||||
if !isBool(cond.typ) {
|
||||
err = cond.cfgErrorf("non-bool used as for condition")
|
||||
}
|
||||
n.start = cond.start
|
||||
if cond.rval.IsValid() {
|
||||
// Condition is known at compile time, bypass test.
|
||||
if cond.rval.Bool() {
|
||||
n.start = body.start
|
||||
post.tnext = body.start
|
||||
}
|
||||
} else {
|
||||
n.start = cond.start
|
||||
post.tnext = cond.start
|
||||
}
|
||||
cond.tnext = body.start
|
||||
cond.fnext = n
|
||||
body.tnext = post.start
|
||||
post.tnext = cond.start
|
||||
sc = sc.pop()
|
||||
|
||||
case forStmt3a: // for int; ; post {}
|
||||
case forStmt3a: // for init; ; post {}
|
||||
init, post, body := n.child[0], n.child[1], n.child[2]
|
||||
n.start = init.start
|
||||
init.tnext = body.start
|
||||
@@ -907,11 +933,21 @@ func (interp *Interpreter) cfg(root *node, pkgID string) ([]*node, error) {
|
||||
err = cond.cfgErrorf("non-bool used as for condition")
|
||||
}
|
||||
n.start = init.start
|
||||
init.tnext = cond.start
|
||||
if cond.rval.IsValid() {
|
||||
// Condition is known at compile time, bypass test.
|
||||
if cond.rval.Bool() {
|
||||
init.tnext = body.start
|
||||
post.tnext = body.start
|
||||
} else {
|
||||
init.tnext = n
|
||||
}
|
||||
} else {
|
||||
init.tnext = cond.start
|
||||
post.tnext = cond.start
|
||||
}
|
||||
cond.tnext = body.start
|
||||
cond.fnext = n
|
||||
body.tnext = post.start
|
||||
post.tnext = cond.start
|
||||
sc = sc.pop()
|
||||
|
||||
case forRangeStmt:
|
||||
@@ -968,10 +1004,7 @@ func (interp *Interpreter) cfg(root *node, pkgID string) ([]*node, error) {
|
||||
}
|
||||
}
|
||||
if sym.kind == varSym && sym.typ != nil && sym.typ.TypeOf().Kind() == reflect.Bool {
|
||||
switch n.anc.kind {
|
||||
case ifStmt0, ifStmt1, ifStmt2, ifStmt3, forStmt1, forStmt2, forStmt3, forStmt4:
|
||||
n.gen = branch
|
||||
}
|
||||
fixBranch(n)
|
||||
}
|
||||
}
|
||||
if n.sym != nil {
|
||||
@@ -986,8 +1019,15 @@ func (interp *Interpreter) cfg(root *node, pkgID string) ([]*node, error) {
|
||||
if !isBool(cond.typ) {
|
||||
err = cond.cfgErrorf("non-bool used as if condition")
|
||||
}
|
||||
n.start = cond.start
|
||||
cond.tnext = tbody.start
|
||||
if cond.rval.IsValid() {
|
||||
// Condition is known at compile time, bypass test.
|
||||
if cond.rval.Bool() {
|
||||
n.start = tbody.start
|
||||
}
|
||||
} else {
|
||||
n.start = cond.start
|
||||
cond.tnext = tbody.start
|
||||
}
|
||||
cond.fnext = n
|
||||
tbody.tnext = n
|
||||
sc = sc.pop()
|
||||
@@ -997,9 +1037,18 @@ func (interp *Interpreter) cfg(root *node, pkgID string) ([]*node, error) {
|
||||
if !isBool(cond.typ) {
|
||||
err = cond.cfgErrorf("non-bool used as if condition")
|
||||
}
|
||||
n.start = cond.start
|
||||
cond.tnext = tbody.start
|
||||
cond.fnext = fbody.start
|
||||
if cond.rval.IsValid() {
|
||||
// Condition is known at compile time, bypass test and the useless branch.
|
||||
if cond.rval.Bool() {
|
||||
n.start = tbody.start
|
||||
} else {
|
||||
n.start = fbody.start
|
||||
}
|
||||
} else {
|
||||
n.start = cond.start
|
||||
cond.tnext = tbody.start
|
||||
cond.fnext = fbody.start
|
||||
}
|
||||
tbody.tnext = n
|
||||
fbody.tnext = n
|
||||
sc = sc.pop()
|
||||
@@ -1010,9 +1059,18 @@ func (interp *Interpreter) cfg(root *node, pkgID string) ([]*node, error) {
|
||||
err = cond.cfgErrorf("non-bool used as if condition")
|
||||
}
|
||||
n.start = init.start
|
||||
if cond.rval.IsValid() {
|
||||
// Condition is known at compile time, bypass test.
|
||||
if cond.rval.Bool() {
|
||||
init.tnext = tbody.start
|
||||
} else {
|
||||
init.tnext = n
|
||||
}
|
||||
} else {
|
||||
init.tnext = cond.start
|
||||
cond.tnext = tbody.start
|
||||
}
|
||||
tbody.tnext = n
|
||||
init.tnext = cond.start
|
||||
cond.tnext = tbody.start
|
||||
cond.fnext = n
|
||||
sc = sc.pop()
|
||||
|
||||
@@ -1022,9 +1080,18 @@ func (interp *Interpreter) cfg(root *node, pkgID string) ([]*node, error) {
|
||||
err = cond.cfgErrorf("non-bool used as if condition")
|
||||
}
|
||||
n.start = init.start
|
||||
init.tnext = cond.start
|
||||
cond.tnext = tbody.start
|
||||
cond.fnext = fbody.start
|
||||
if cond.rval.IsValid() {
|
||||
// Condition is known at compile time, bypass test.
|
||||
if cond.rval.Bool() {
|
||||
init.tnext = tbody.start
|
||||
} else {
|
||||
init.tnext = fbody.start
|
||||
}
|
||||
} else {
|
||||
init.tnext = cond.start
|
||||
cond.tnext = tbody.start
|
||||
cond.fnext = fbody.start
|
||||
}
|
||||
tbody.tnext = n
|
||||
fbody.tnext = n
|
||||
sc = sc.pop()
|
||||
@@ -1308,33 +1375,56 @@ func (interp *Interpreter) cfg(root *node, pkgID string) ([]*node, error) {
|
||||
fallthrough
|
||||
|
||||
case switchStmt:
|
||||
sc = sc.pop()
|
||||
sbn := n.lastChild() // switch block node
|
||||
clauses := sbn.child
|
||||
l := len(clauses)
|
||||
// Chain case clauses
|
||||
if l == 0 {
|
||||
// Switch is empty
|
||||
break
|
||||
}
|
||||
// Chain case clauses.
|
||||
for i, c := range clauses[:l-1] {
|
||||
c.fnext = clauses[i+1] // chain to next clause
|
||||
body := c.lastChild()
|
||||
c.tnext = body.start
|
||||
if len(body.child) > 0 && body.lastChild().kind == fallthroughtStmt {
|
||||
if n.kind == typeSwitch {
|
||||
err = body.lastChild().cfgErrorf("cannot fallthrough in type switch")
|
||||
}
|
||||
body.tnext = clauses[i+1].lastChild().start
|
||||
c.fnext = clauses[i+1] // Chain to next clause.
|
||||
if len(c.child) == 0 {
|
||||
c.tnext = n // Clause body is empty, exit.
|
||||
} else {
|
||||
body.tnext = n
|
||||
body := c.lastChild()
|
||||
c.tnext = body.start
|
||||
if len(body.child) > 0 && body.lastChild().kind == fallthroughtStmt {
|
||||
if n.kind == typeSwitch {
|
||||
err = body.lastChild().cfgErrorf("cannot fallthrough in type switch")
|
||||
}
|
||||
if len(clauses[i+1].child) == 0 {
|
||||
body.tnext = n // Fallthrough to next with empty body, just exit.
|
||||
} else {
|
||||
body.tnext = clauses[i+1].lastChild().start
|
||||
}
|
||||
} else {
|
||||
body.tnext = n // Exit switch at end of clause body.
|
||||
}
|
||||
}
|
||||
}
|
||||
c := clauses[l-1]
|
||||
c.tnext = c.lastChild().start
|
||||
c := clauses[l-1] // Last clause.
|
||||
if len(c.child) == 0 {
|
||||
c.tnext = n // Clause body is empty, exit.
|
||||
} else {
|
||||
body := c.lastChild()
|
||||
c.tnext = body.start
|
||||
body.tnext = n
|
||||
}
|
||||
n.start = n.child[0].start
|
||||
n.child[0].tnext = sbn.start
|
||||
sc = sc.pop()
|
||||
|
||||
case switchIfStmt: // like an if-else chain
|
||||
sc = sc.pop()
|
||||
sbn := n.lastChild() // switch block node
|
||||
clauses := sbn.child
|
||||
l := len(clauses)
|
||||
if l == 0 {
|
||||
// Switch is empty
|
||||
break
|
||||
}
|
||||
// Wire case clauses in reverse order so the next start node is already resolved when used.
|
||||
for i := l - 1; i >= 0; i-- {
|
||||
c := clauses[i]
|
||||
@@ -1362,7 +1452,6 @@ func (interp *Interpreter) cfg(root *node, pkgID string) ([]*node, error) {
|
||||
sbn.start = clauses[0].start
|
||||
n.start = n.child[0].start
|
||||
n.child[0].tnext = sbn.start
|
||||
sc = sc.pop()
|
||||
|
||||
case typeAssertExpr:
|
||||
if len(n.child) > 1 {
|
||||
@@ -1576,11 +1665,27 @@ func genRun(nod *node) error {
|
||||
return err
|
||||
}
|
||||
|
||||
// Find default case clause index of a switch statement, if any
|
||||
// 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)
|
||||
}
|
||||
}
|
||||
|
||||
// GetDefault return the index of default case clause in a switch statement, or -1.
|
||||
func getDefault(n *node) int {
|
||||
for i, c := range n.lastChild().child {
|
||||
if len(c.child) == 1 {
|
||||
switch len(c.child) {
|
||||
case 0:
|
||||
return i
|
||||
case 1:
|
||||
if c.child[0].kind == caseBody {
|
||||
return i
|
||||
}
|
||||
}
|
||||
}
|
||||
return -1
|
||||
|
||||
@@ -1,8 +1,6 @@
|
||||
package interp
|
||||
|
||||
import (
|
||||
"reflect"
|
||||
)
|
||||
import "reflect"
|
||||
|
||||
// gta performs a global types analysis on the AST, registering types,
|
||||
// variables and functions symbols at package level, prior to CFG.
|
||||
|
||||
104
interp/run.go
104
interp/run.go
@@ -669,6 +669,10 @@ func call(n *node) {
|
||||
if n.anc.kind == deferStmt {
|
||||
// Store function call in frame for deferred execution.
|
||||
value = genFunctionWrapper(n.child[0])
|
||||
if method {
|
||||
// The receiver is already passed in the function wrapper, skip it.
|
||||
values = values[1:]
|
||||
}
|
||||
n.exec = func(f *frame) bltn {
|
||||
val := make([]reflect.Value, len(values)+1)
|
||||
val[0] = value(f)
|
||||
@@ -2393,14 +2397,16 @@ func recv2(n *node) {
|
||||
}
|
||||
|
||||
func convertLiteralValue(n *node, t reflect.Type) {
|
||||
// Skip non-constant values, undefined target type or interface target type.
|
||||
if !(n.kind == basicLit || n.rval.IsValid()) || t == nil || t.Kind() == reflect.Interface {
|
||||
return
|
||||
}
|
||||
if n.rval.IsValid() {
|
||||
switch {
|
||||
case n.typ.cat == nilT:
|
||||
// Create a zero value of target type.
|
||||
n.rval = reflect.New(t).Elem()
|
||||
case !(n.kind == basicLit || n.rval.IsValid()) || t == nil || t.Kind() == reflect.Interface:
|
||||
// Skip non-constant values, undefined target type or interface target type.
|
||||
case n.rval.IsValid():
|
||||
// Convert constant value to target type.
|
||||
n.rval = n.rval.Convert(t)
|
||||
} else {
|
||||
default:
|
||||
// Create a zero value of target type.
|
||||
n.rval = reflect.New(t).Elem()
|
||||
}
|
||||
@@ -2588,56 +2594,94 @@ func slice0(n *node) {
|
||||
|
||||
func isNil(n *node) {
|
||||
var value func(*frame) reflect.Value
|
||||
if n.child[0].typ.cat == funcT {
|
||||
value = genValueAsFunctionWrapper(n.child[0])
|
||||
c0 := n.child[0]
|
||||
if c0.typ.cat == funcT {
|
||||
value = genValueAsFunctionWrapper(c0)
|
||||
} else {
|
||||
value = genValue(n.child[0])
|
||||
value = genValue(c0)
|
||||
}
|
||||
tnext := getExec(n.tnext)
|
||||
dest := genValue(n)
|
||||
|
||||
if n.fnext != nil {
|
||||
fnext := getExec(n.fnext)
|
||||
n.exec = func(f *frame) bltn {
|
||||
if value(f).IsNil() {
|
||||
dest(f).SetBool(true)
|
||||
return tnext
|
||||
if c0.typ.cat == interfaceT {
|
||||
n.exec = func(f *frame) bltn {
|
||||
if (value(f).Interface().(valueInterface) == valueInterface{}) {
|
||||
dest(f).SetBool(true)
|
||||
return tnext
|
||||
}
|
||||
dest(f).SetBool(false)
|
||||
return fnext
|
||||
}
|
||||
} else {
|
||||
n.exec = func(f *frame) bltn {
|
||||
if value(f).IsNil() {
|
||||
dest(f).SetBool(true)
|
||||
return tnext
|
||||
}
|
||||
dest(f).SetBool(false)
|
||||
return fnext
|
||||
}
|
||||
dest(f).SetBool(false)
|
||||
return fnext
|
||||
}
|
||||
} else {
|
||||
n.exec = func(f *frame) bltn {
|
||||
dest(f).SetBool(value(f).IsNil())
|
||||
return tnext
|
||||
if c0.typ.cat == interfaceT {
|
||||
n.exec = func(f *frame) bltn {
|
||||
dest(f).SetBool(value(f).Interface().(valueInterface) == valueInterface{})
|
||||
return tnext
|
||||
}
|
||||
} else {
|
||||
n.exec = func(f *frame) bltn {
|
||||
dest(f).SetBool(value(f).IsNil())
|
||||
return tnext
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
func isNotNil(n *node) {
|
||||
var value func(*frame) reflect.Value
|
||||
if n.child[0].typ.cat == funcT {
|
||||
value = genValueAsFunctionWrapper(n.child[0])
|
||||
c0 := n.child[0]
|
||||
if c0.typ.cat == funcT {
|
||||
value = genValueAsFunctionWrapper(c0)
|
||||
} else {
|
||||
value = genValue(n.child[0])
|
||||
value = genValue(c0)
|
||||
}
|
||||
tnext := getExec(n.tnext)
|
||||
dest := genValue(n)
|
||||
|
||||
if n.fnext != nil {
|
||||
fnext := getExec(n.fnext)
|
||||
n.exec = func(f *frame) bltn {
|
||||
if value(f).IsNil() {
|
||||
dest(f).SetBool(false)
|
||||
return fnext
|
||||
if c0.typ.cat == interfaceT {
|
||||
n.exec = func(f *frame) bltn {
|
||||
if (value(f).Interface().(valueInterface) == valueInterface{}) {
|
||||
dest(f).SetBool(false)
|
||||
return fnext
|
||||
}
|
||||
dest(f).SetBool(true)
|
||||
return tnext
|
||||
}
|
||||
} else {
|
||||
n.exec = func(f *frame) bltn {
|
||||
if value(f).IsNil() {
|
||||
dest(f).SetBool(false)
|
||||
return fnext
|
||||
}
|
||||
dest(f).SetBool(true)
|
||||
return tnext
|
||||
}
|
||||
dest(f).SetBool(true)
|
||||
return tnext
|
||||
}
|
||||
} else {
|
||||
n.exec = func(f *frame) bltn {
|
||||
dest(f).SetBool(!value(f).IsNil())
|
||||
return tnext
|
||||
if c0.typ.cat == interfaceT {
|
||||
n.exec = func(f *frame) bltn {
|
||||
dest(f).SetBool(!(value(f).Interface().(valueInterface) == valueInterface{}))
|
||||
return tnext
|
||||
}
|
||||
} else {
|
||||
n.exec = func(f *frame) bltn {
|
||||
dest(f).SetBool(!value(f).IsNil())
|
||||
return tnext
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -905,6 +905,9 @@ var interf = reflect.TypeOf(new(interface{})).Elem()
|
||||
|
||||
func (t *itype) refType(defined map[string]*itype, wrapRecursive bool) reflect.Type {
|
||||
if t.rtype != nil {
|
||||
if wrapRecursive && t.cat == structT && defined[t.name] != nil {
|
||||
return interf
|
||||
}
|
||||
return t.rtype
|
||||
}
|
||||
|
||||
|
||||
Reference in New Issue
Block a user