Fix handling of closures
This commit is contained in:
17
_test/closure0.go
Normal file
17
_test/closure0.go
Normal 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
20
_test/closure1.go
Normal 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
16
_test/closure2.go
Normal 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))
|
||||
}
|
||||
}
|
||||
@@ -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)
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -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{})
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user