Fix handling of closures

This commit is contained in:
Marc Vertes
2018-07-05 18:57:53 +02:00
parent e5ca673fec
commit 8ab3c06e5a
8 changed files with 156 additions and 11 deletions

17
_test/closure0.go Normal file
View File

@@ -0,0 +1,17 @@
package main
type adder func(int, int) int
func genAdd(k int) adder {
return func(i, j int) int {
return i + j
}
}
func main() {
f := genAdd(5)
println(f(3, 4))
}
// Output:
// 7

20
_test/closure1.go Normal file
View File

@@ -0,0 +1,20 @@
package main
type adder func(int, int) int
func genAdd(k int) adder {
return func(i, j int) int {
return i + j + k
}
}
func main() {
f := genAdd(5)
g := genAdd(8)
println(f(3, 4))
println(g(3, 4))
}
// Output:
// 12
// 15

16
_test/closure2.go Normal file
View File

@@ -0,0 +1,16 @@
package main
func adder() func(int) int {
sum := 0
return func(x int) int {
sum = sum + x
return sum
}
}
func main() {
pos, neg := adder(), adder()
for i := 0; i < 10; i++ {
println(pos(i), neg(-2*i))
}
}

View File

@@ -188,6 +188,7 @@ const (
Dec
Equal
Greater
GetFunc
GetIndex
Inc
Land
@@ -226,6 +227,7 @@ var actions = [...]string{
Dec: "--",
Equal: "==",
Greater: ">",
GetFunc: "getFunc",
GetIndex: "getIndex",
Inc: "++",
Land: "&&",
@@ -500,7 +502,7 @@ func (interp *Interpreter) Ast(src string, pre *NodeMap) (*Node, *NodeMap) {
st.push(n)
case *ast.FuncLit:
n := addChild(&root, anc, &index, FuncLit, Nop)
n := addChild(&root, anc, &index, FuncLit, GetFunc)
addChild(&root, n, &index, FieldList, Nop)
addChild(&root, n, &index, Undef, Nop)
st.push(n)

View File

@@ -533,7 +533,7 @@ func (interp *Interpreter) Cfg(root *Node, sdef *NodeMap) []*Node {
scope = scope.anc
case FuncDecl:
n.findex = frameIndex.max + 1
n.flen = frameIndex.max + 1
if len(n.child[0].child) > 0 {
// Store receiver frame location (used at run)
n.child[0].findex = n.child[0].child[0].child[0].findex
@@ -552,8 +552,7 @@ func (interp *Interpreter) Cfg(root *Node, sdef *NodeMap) []*Node {
case FuncLit:
n.typ = n.child[2].typ
n.val = n
n.findex = -1
n.findex = frameIndex.max + 1
n.flen = frameIndex.max + 1
scope = scope.anc
frameIndex = frameIndex.anc
funcDef = true
@@ -867,7 +866,7 @@ func wireChild(n *Node) {
// Set start node, in subtree (propagated to ancestors by post-order processing)
for _, child := range n.child {
switch child.kind {
case ArrayType, ChanType, FuncDecl, MapType, BasicLit, FuncLit, Ident:
case ArrayType, ChanType, FuncDecl, MapType, BasicLit, Ident:
continue
default:
n.start = child.start
@@ -883,7 +882,7 @@ func wireChild(n *Node) {
// Chain subtree next to self
for i := len(n.child) - 1; i >= 0; i-- {
switch n.child[i].kind {
case ArrayType, ChanType, MapType, FuncDecl, FuncLit, BasicLit, Ident:
case ArrayType, ChanType, MapType, FuncDecl, BasicLit, Ident:
continue
case Break, Continue, ReturnStmt:
// tnext is already computed, no change

View File

@@ -16,6 +16,7 @@ type Node struct {
index int // node index (dot display)
findex int // index of value in frame or frame size (func def, type def)
fsize int // number of entries in frame (call expressions)
flen int // frame length (function definition)
level int // number of frame indirections to access value
kind Kind // kind of node
typ *Type // type of value in frame, or nil

View File

@@ -378,6 +378,83 @@ func main() {
// ping
}
func Example_closure0() {
src := `
package main
type adder func(int, int) int
func genAdd(k int) adder {
return func(i, j int) int {
return i + j
}
}
func main() {
f := genAdd(5)
println(f(3, 4))
}
`
i := NewInterpreter(Opt{Entry: "main"})
i.ImportBin(export.Pkg)
i.Eval(src)
// Output:
// 7
}
func Example_closure1() {
src := `
package main
type adder func(int, int) int
func genAdd(k int) adder {
return func(i, j int) int {
return i + j + k
}
}
func main() {
f := genAdd(5)
g := genAdd(8)
println(f(3, 4))
println(g(3, 4))
}
`
i := NewInterpreter(Opt{Entry: "main"})
i.ImportBin(export.Pkg)
i.Eval(src)
// Output:
// 12
// 15
}
func Example_closure2() {
src := `
package main
func adder() func(int) int {
sum := 0
return func(x int) int {
sum = sum + x
return sum
}
}
func main() {
pos, neg := adder(), adder()
for i := 0; i < 10; i++ {
println(pos(i), neg(-2*i))
}
}`
i := NewInterpreter(Opt{Entry: "main"})
i.ImportBin(export.Pkg)
i.Eval(src)
}
func Example_const0() {
src := `
package main

View File

@@ -24,8 +24,9 @@ var builtin = [...]Builtin{
CompositeLit: arrayLit,
Dec: nop,
Equal: equal,
Greater: greater,
GetFunc: getFunc,
GetIndex: getIndex,
Greater: greater,
Inc: inc,
Land: land,
Lor: lor,
@@ -57,13 +58,15 @@ var goBuiltin = map[string]Builtin{
// Run a Go function
func Run(def *Node, cf *Frame, recv *Node, rseq []int, args []*Node, rets []int, fork bool, goroutine bool) {
// log.Println("run", def.index, def.child[1].ident, "allocate", def.findex)
//log.Println("run", def.index, def.child[1].ident, "allocate", def.flen)
// Allocate a new Frame to store local variables
anc := cf.anc
if fork {
anc = cf
} else if def.frame != nil {
anc = def.frame
}
f := Frame{anc: anc, data: make([]interface{}, def.findex)}
f := Frame{anc: anc, data: make([]interface{}, def.flen)}
// Assign receiver value, if defined (for methods)
if recv != nil {
@@ -119,11 +122,12 @@ func Run(def *Node, cf *Frame, recv *Node, rseq []int, args []*Node, rets []int,
func value(n *Node, f *Frame) interface{} {
switch n.kind {
case BasicLit, FuncDecl, FuncLit, SelectorSrc:
case BasicLit, FuncDecl, SelectorSrc:
return n.val
case Rvalue:
return n.rval
default:
//log.Println(n.index, n.findex, n.level, f)
for level := n.level; level > 0; level-- {
f = f.anc
}
@@ -136,7 +140,7 @@ func value(n *Node, f *Frame) interface{} {
func addrValue(n *Node, f *Frame) *interface{} {
switch n.kind {
case BasicLit, FuncDecl, FuncLit, Rvalue:
case BasicLit, FuncDecl, Rvalue:
return &n.val
default:
for level := n.level; level > 0; level-- {
@@ -473,6 +477,15 @@ func getIndexMap(n *Node, f *Frame) {
}
}
func getFunc(n *Node, f *Frame) {
node := *n
node.val = &node
frame := *f
node.frame = &frame
f.data[n.findex] = &node
}
func getMap(n *Node, f *Frame) {
f.data[n.findex] = value(n.child[0], f).(map[interface{}]interface{})
}