From 4d013e4686220864a7b024f4fe3a21542a0dd2fe Mon Sep 17 00:00:00 2001 From: Nicholas Wiersma Date: Thu, 25 Jun 2020 09:28:03 +0200 Subject: [PATCH] fix: handle defer in builtins --- _test/defer5.go | 32 +++++++++++++++++ _test/defer6.go | 27 ++++++++++++++ _test/defer7.go | 18 ++++++++++ _test/defer8.go | 24 +++++++++++++ _test/defer9.go | 21 +++++++++++ interp/run.go | 96 +++++++++++++++++++++++++++++++++---------------- 6 files changed, 187 insertions(+), 31 deletions(-) create mode 100644 _test/defer5.go create mode 100644 _test/defer6.go create mode 100644 _test/defer7.go create mode 100644 _test/defer8.go create mode 100644 _test/defer9.go diff --git a/_test/defer5.go b/_test/defer5.go new file mode 100644 index 00000000..382427e8 --- /dev/null +++ b/_test/defer5.go @@ -0,0 +1,32 @@ +package main + +func f1() { + defer println("f1-begin") + f2() + defer println("f1-end") +} + +func f2() { + defer println("f2-begin") + f3() + defer println("f2-end") +} + +func f3() { + defer println("f3-begin") + println("hello") + defer println("f3-end") +} + +func main() { + f1() +} + +// Output: +// hello +// f3-end +// f3-begin +// f2-end +// f2-begin +// f1-end +// f1-begin diff --git a/_test/defer6.go b/_test/defer6.go new file mode 100644 index 00000000..65a8d933 --- /dev/null +++ b/_test/defer6.go @@ -0,0 +1,27 @@ +package main + +func f1() { + defer print("f1-begin ") + f2() + defer print("f1-end ") +} + +func f2() { + defer print("f2-begin ") + f3() + defer print("f2-end ") +} + +func f3() { + defer print("f3-begin ") + print("hello ") + defer print("f3-end ") +} + +func main() { + f1() + println() +} + +// Output: +// hello f3-end f3-begin f2-end f2-begin f1-end f1-begin diff --git a/_test/defer7.go b/_test/defer7.go new file mode 100644 index 00000000..47a5569b --- /dev/null +++ b/_test/defer7.go @@ -0,0 +1,18 @@ +package main + +import "fmt" + +func f1(in, out []string) { + defer copy(out, in) +} + +func main() { + in := []string{"foo", "bar"} + out := make([]string, 2) + f1(in, out) + + fmt.Println(out) +} + +// Output: +// [foo bar] diff --git a/_test/defer8.go b/_test/defer8.go new file mode 100644 index 00000000..8755f8df --- /dev/null +++ b/_test/defer8.go @@ -0,0 +1,24 @@ +package main + +import "fmt" + +func f1(m map[string]string) { + defer delete(m, "foo") + defer delete(m, "test") + + fmt.Println(m) +} + +func main() { + m := map[string]string{ + "foo": "bar", + "baz": "bat", + } + f1(m) + + fmt.Println(m) +} + +// Output: +// map[baz:bat foo:bar] +// map[baz:bat] diff --git a/_test/defer9.go b/_test/defer9.go new file mode 100644 index 00000000..e9b54ef5 --- /dev/null +++ b/_test/defer9.go @@ -0,0 +1,21 @@ +package main + +import "fmt" + +func f1(ch chan string) { + defer close(ch) + + ch <- "foo" +} + +func main() { + ch := make(chan string, 1) + f1(ch) + + for s := range ch { + fmt.Println(s) + } +} + +// Output: +// foo diff --git a/interp/run.go b/interp/run.go index e7fbd772..99afa401 100644 --- a/interp/run.go +++ b/interp/run.go @@ -525,41 +525,39 @@ func deref(n *node) { func _print(n *node) { child := n.child[1:] - next := getExec(n.tnext) values := make([]func(*frame) reflect.Value, len(child)) for i, c := range child { values[i] = genValue(c) } - n.exec = func(f *frame) bltn { - for i, value := range values { + genBuiltinDeferWrapper(n, values, nil, func(args []reflect.Value) []reflect.Value { + for i, value := range args { if i > 0 { fmt.Printf(" ") } - fmt.Printf("%v", value(f)) + fmt.Printf("%v", value) } - return next - } + return nil + }) } func _println(n *node) { child := n.child[1:] - next := getExec(n.tnext) values := make([]func(*frame) reflect.Value, len(child)) for i, c := range child { values[i] = genValue(c) } - n.exec = func(f *frame) bltn { - for i, value := range values { + genBuiltinDeferWrapper(n, values, nil, func(args []reflect.Value) []reflect.Value { + for i, value := range args { if i > 0 { fmt.Printf(" ") } - fmt.Printf("%v", value(f)) + fmt.Printf("%v", value) } fmt.Println("") - return next - } + return nil + }) } func _recover(n *node) { @@ -585,6 +583,45 @@ func _panic(n *node) { } } +func genBuiltinDeferWrapper(n *node, in, out []func(*frame) reflect.Value, fn func([]reflect.Value) []reflect.Value) { + next := getExec(n.tnext) + + if n.anc.kind == deferStmt { + n.exec = func(f *frame) bltn { + val := make([]reflect.Value, len(in)+1) + inTypes := make([]reflect.Type, len(in)) + for i, v := range in { + val[i+1] = v(f) + inTypes[i] = val[i+1].Type() + } + outTypes := make([]reflect.Type, len(out)) + for i, v := range out { + outTypes[i] = v(f).Type() + } + + funcType := reflect.FuncOf(inTypes, outTypes, false) + val[0] = reflect.MakeFunc(funcType, fn) + f.deferred = append([][]reflect.Value{val}, f.deferred...) + return next + } + return + } + + n.exec = func(f *frame) bltn { + val := make([]reflect.Value, len(in)) + for i, v := range in { + val[i] = v(f) + } + + dests := fn(val) + + for i, dest := range dests { + out[i](f).Set(dest) + } + return next + } +} + func genFunctionWrapper(n *node) func(*frame) reflect.Value { var def *node var ok bool @@ -2344,25 +2381,22 @@ func _cap(n *node) { } func _copy(n *node) { - dest := genValueOutput(n, reflect.TypeOf(int(0))) - value0 := genValueArray(n.child[1]) - value1 := genValue(n.child[2]) - next := getExec(n.tnext) + in := []func(*frame) reflect.Value{genValueArray(n.child[1]), genValue(n.child[2])} + out := []func(*frame) reflect.Value{genValueOutput(n, reflect.TypeOf(0))} - n.exec = func(f *frame) bltn { - dest(f).SetInt(int64(reflect.Copy(value0(f), value1(f)))) - return next - } + genBuiltinDeferWrapper(n, in, out, func(args []reflect.Value) []reflect.Value { + cnt := reflect.Copy(args[0], args[1]) + return []reflect.Value{reflect.ValueOf(cnt)} + }) } func _close(n *node) { - value := genValue(n.child[1]) - next := getExec(n.tnext) + in := []func(*frame) reflect.Value{genValue(n.child[1])} - n.exec = func(f *frame) bltn { - value(f).Close() - return next - } + genBuiltinDeferWrapper(n, in, nil, func(args []reflect.Value) []reflect.Value { + args[0].Close() + return nil + }) } func _complex(n *node) { @@ -2415,13 +2449,13 @@ func _real(n *node) { func _delete(n *node) { value0 := genValue(n.child[1]) // map value1 := genValue(n.child[2]) // key - next := getExec(n.tnext) + in := []func(*frame) reflect.Value{value0, value1} var z reflect.Value - n.exec = func(f *frame) bltn { - value0(f).SetMapIndex(value1(f), z) - return next - } + genBuiltinDeferWrapper(n, in, nil, func(args []reflect.Value) []reflect.Value { + args[0].SetMapIndex(args[1], z) + return nil + }) } func _len(n *node) {