Rework function calls, in progress

This commit is contained in:
Marc Vertes
2018-10-31 19:35:26 +01:00
parent 4b48a14748
commit 1592679f36
14 changed files with 349 additions and 166 deletions

11
_test/bin.go Normal file
View File

@@ -0,0 +1,11 @@
package main
import "fmt"
func main() {
f := fmt.Println
f("Hello")
}
// Output:
// Hello

6
_test/bltn.go Normal file
View File

@@ -0,0 +1,6 @@
package main
func main() {
f := println
f("Hello")
}

23
_test/closure4.go Normal file
View File

@@ -0,0 +1,23 @@
package main
type T1 struct {
Name string
}
func (t *T1) genAdd(k int) func(int) int {
return func(i int) int {
println(t.Name)
return i + k
}
}
var t = T1{"test"}
func main() {
f := t.genAdd(4)
println(f(5))
}
// Output:
// test
// 9

23
_test/closure5.go Normal file
View File

@@ -0,0 +1,23 @@
package main
type T1 struct {
Name string
}
func (t T1) genAdd(k int) func(int) int {
return func(i int) int {
println(t.Name)
return i + k
}
}
var t = T1{"test"}
func main() {
f := t.genAdd(4)
println(f(5))
}
// Output:
// test
// 9

24
_test/closure6.go Normal file
View File

@@ -0,0 +1,24 @@
package main
type T1 struct {
Name string
}
func (t *T1) genAdd(k int) func(int) int {
return func(i int) int {
println(t.Name)
return i + k
}
}
var t = &T1{"test"}
func main() {
f := t.genAdd(4)
//g := f(4)
println(g(5))
}
// Output:
// test
// 9

16
_test/method12.go Normal file
View File

@@ -0,0 +1,16 @@
package main
type Coord struct {
x, y int
}
func (c Coord) dist() int { return c.x*c.x + c.y*c.y }
func main() {
o := Coord{3, 4}
f := o.dist
println(f())
}
// Output:
// 25

View File

@@ -3,8 +3,9 @@ package main
import "github.com/containous/dyngo/_test/provider"
func main() {
provider.F1()
f := provider.Bar
f()
}
// Output:
// SomeString: constant string
// Hello from Foo

View File

@@ -13,3 +13,6 @@ func main() {
a := T{}
println(a.i, a.opt.b)
}
// Output:
// 0 false

View File

@@ -19,9 +19,7 @@ func f(i int) int { return i * i }
func main() {
a := T{5, 7, T2{8, T3{9}}}
//println(a.f, a.g, a.T2.h, a.T2.T3.k)
//fmt.Println(a.T2)
println(a.h)
println(a.f, a.g, a.T2.h, a.T2.T3.k)
}
// Output:

View File

@@ -184,7 +184,6 @@ const (
Add
And
Call
CallF
Case
CompositeLit
Dec
@@ -224,7 +223,6 @@ var actions = [...]string{
Add: "+",
And: "&",
Call: "call",
CallF: "call",
Case: "case",
CompositeLit: "compositeLit",
Dec: "--",

View File

@@ -115,7 +115,6 @@ func (scope *Scope) inc(interp *Interpreter) int {
func (interp *Interpreter) Cfg(root *Node) []*Node {
scope := interp.universe
var loop, loopRestart *Node
var funcDef bool // True if a function is defined in the current frame context
var initNodes []*Node
var exports *BinMap
var expval *ValueMap
@@ -173,7 +172,6 @@ func (interp *Interpreter) Cfg(root *Node) []*Node {
// allocate entries for return values at start of frame
scope.size += len(n.child[2].child[1].child)
}
funcDef = false
case If0, If1, If2, If3:
scope = scope.push(0)
@@ -369,7 +367,9 @@ func (interp *Interpreter) Cfg(root *Node) []*Node {
case CallExpr:
wireChild(n)
n.findex = scope.inc(interp)
log.Println(n.index, "call", n.child[0].typ)
if n.child[0].sym != nil && n.child[0].sym.kind == Bltn {
// Call an internal go builtin
n.gen = n.child[0].sym.builtin
n.child[0].typ = &Type{cat: BuiltinT}
switch n.child[0].ident {
@@ -383,7 +383,7 @@ func (interp *Interpreter) Cfg(root *Node) []*Node {
n.child[1].kind = BasicLit
}
} else if n.child[0].isType(scope) {
// Call expression is in fact a type conversion expression
// Type conversion expression
n.typ = n.child[0].typ
if n.typ.cat == AliasT {
n.gen = convert
@@ -396,113 +396,9 @@ func (interp *Interpreter) Cfg(root *Node) []*Node {
n.gen = convertBin
}
}
} else if n.child[0].kind == SelectorImport {
// TODO: Should process according to child type, not kind.
n.fsize = n.child[0].fsize
var rtype reflect.Type
switch t := n.child[0].val.(type) {
case reflect.Type:
rtype = n.child[0].val.(reflect.Type)
case reflect.Value:
rtype = n.child[0].val.(reflect.Value).Type()
default:
log.Printf("unexpected type %T\n", t)
}
//rtype := n.child[0].val.(reflect.Value).Type()
if rtype.NumOut() > 0 {
n.typ = &Type{cat: ValueT, rtype: rtype.Out(0)}
}
n.child[0].kind = BasicLit
for i, c := range n.child[1:] {
// Wrap function defintion so it can be called from runtime
if c.kind == FuncLit {
n.child[1+i].rval = reflect.MakeFunc(rtype.In(i), c.wrapNode)
n.child[1+i].kind = Rvalue
} else if c.ident == "nil" {
n.child[1+i].rval = reflect.New(rtype.In(i)).Elem()
n.child[1+i].kind = Rvalue
} else if c.typ != nil && c.typ.cat == FuncT {
n.child[1+i].rval = reflect.MakeFunc(rtype.In(i), c.wrapNode)
n.child[1+i].kind = Rvalue
}
}
// TODO: handle multiple return value
if len(n.child) == 2 && n.child[1].fsize > 1 {
n.gen = callBinX
} else {
n.gen = callBin
}
} else if n.child[0].kind == SelectorExpr {
if n.child[0].typ.cat == ValueT {
n.gen = callBinMethod
// TODO: handle multiple return value (_test/time2.go)
n.child[0].kind = BasicLit // Temporary hack for force value() to return n.val at run
n.typ = &Type{cat: ValueT, rtype: n.child[0].typ.rtype}
n.fsize = n.child[0].fsize
} else if n.child[0].typ.cat == PtrT && n.child[0].typ.val.cat == ValueT {
n.gen = callBinMethod
n.child[0].kind = BasicLit // Temporary hack for force value() to return n.val at run
n.fsize = n.child[0].fsize
// TODO: handle type ?
} else if n.child[0].typ.cat == SrcPkgT {
n.val = n.child[0].val
if def := n.val.(*Node); def != nil {
// Reserve as many frame entries as nb of ret values for called function
// node frame index should point to the first entry
j := len(def.child[2].child) - 1
l := len(def.child[2].child[j].child) // Number of return values for def
if l == 1 {
// If def returns exactly one value, propagate its type in call node.
// Multiple return values will be handled differently through AssignX.
n.typ = scope.getType(def.child[2].child[j].child[0].child[0].ident)
}
n.fsize = l
}
} else {
// Get method and receiver path, store them in node static value for run
if methodDecl, ok := n.child[0].val.(*Node); ok {
// method is already resolved, use it
if len(methodDecl.child[2].child) > 1 {
// Allocate frame for method return values (if any)
n.fsize = len(methodDecl.child[2].child[1].child)
n.typ = methodDecl.typ.ret[0]
// TODO: handle multiple return values
} else {
n.fsize = 0
}
} else {
log.Println(n.index, "unresolve call")
// method must be resolved here due to declaration after use
}
n.child[0].findex = -1 // To force reading value from node instead of frame (methods)
}
} else if sym, _, _ := scope.lookup(n.child[0].ident); sym != nil {
if sym.typ != nil && sym.typ.cat == BinT {
n.gen = callBin
n.typ = &Type{cat: ValueT}
r := sym.val.(reflect.Value)
n.child[0].fsize = r.Type().NumOut()
n.child[0].val = r
n.child[0].kind = BasicLit
} else if sym.typ != nil && sym.typ.cat == ValueT {
n.gen = callDirectBin
n.typ = &Type{cat: ValueT}
} else {
n.val = sym.node
n.fsize = len(sym.typ.ret)
if n.fsize == 1 {
// If called func returns exactly one value, propagate its type in call node.
// Multiple return values will be handled differently through AssignX.
n.typ = sym.typ.ret[0]
}
}
} else if n.child[0].kind == SelectorSrc {
// Forward type of first returned value
// Multiple return values will be handled differently through AssignX.
if len(n.child[0].typ.ret) > 0 {
n.typ = n.child[0].typ.ret[0]
n.fsize = len(n.child[0].typ.ret)
}
} else if n.child[0].typ.cat == ValueT {
log.Println(n.index, "callBin", n.child[0].val)
n.gen = callBin
}
// Reserve entries in frame to store results of call
scope.size += n.fsize
@@ -512,11 +408,117 @@ func (interp *Interpreter) Cfg(root *Node) []*Node {
} else {
scope.size += n.fsize
}
n.recv = n.child[0].recv
if funcDef {
// Trigger frame indirection to handle nested functions
n.action = CallF
}
/*
else if n.child[0].kind == SelectorImport {
// TODO: Should process according to child type, not kind.
n.fsize = n.child[0].fsize
var rtype reflect.Type
switch t := n.child[0].val.(type) {
case reflect.Type:
rtype = n.child[0].val.(reflect.Type)
case reflect.Value:
rtype = n.child[0].val.(reflect.Value).Type()
default:
log.Printf("unexpected type %T\n", t)
}
if rtype.NumOut() > 0 {
n.typ = &Type{cat: ValueT, rtype: rtype.Out(0)}
}
n.child[0].kind = BasicLit
for i, c := range n.child[1:] {
// Wrap function defintion so it can be called from runtime
if c.kind == FuncLit {
n.child[1+i].rval = reflect.MakeFunc(rtype.In(i), c.wrapNode)
n.child[1+i].kind = Rvalue
} else if c.ident == "nil" {
n.child[1+i].rval = reflect.New(rtype.In(i)).Elem()
n.child[1+i].kind = Rvalue
} else if c.typ != nil && c.typ.cat == FuncT {
n.child[1+i].rval = reflect.MakeFunc(rtype.In(i), c.wrapNode)
n.child[1+i].kind = Rvalue
}
}
// TODO: handle multiple return value
if len(n.child) == 2 && n.child[1].fsize > 1 {
n.gen = callBinX
} else {
n.gen = callBin
}
} else if n.child[0].kind == SelectorExpr {
if n.child[0].typ.cat == ValueT {
n.gen = callBinMethod
// TODO: handle multiple return value (_test/time2.go)
n.child[0].kind = BasicLit // Temporary hack for force value() to return n.val at run
n.typ = &Type{cat: ValueT, rtype: n.child[0].typ.rtype}
n.fsize = n.child[0].fsize
} else if n.child[0].typ.cat == PtrT && n.child[0].typ.val.cat == ValueT {
n.gen = callBinMethod
n.child[0].kind = BasicLit // Temporary hack for force value() to return n.val at run
n.fsize = n.child[0].fsize
// TODO: handle type ?
} else if n.child[0].typ.cat == SrcPkgT {
n.val = n.child[0].val
if def := n.val.(*Node); def != nil {
// Reserve as many frame entries as nb of ret values for called function
// node frame index should point to the first entry
j := len(def.child[2].child) - 1
l := len(def.child[2].child[j].child) // Number of return values for def
if l == 1 {
// If def returns exactly one value, propagate its type in call node.
// Multiple return values will be handled differently through AssignX.
n.typ = scope.getType(def.child[2].child[j].child[0].child[0].ident)
}
n.fsize = l
}
} else {
// Get method and receiver path, store them in node static value for run
if methodDecl, ok := n.child[0].val.(*Node); ok {
// method is already resolved, use it
if len(methodDecl.child[2].child) > 1 {
// Allocate frame for method return values (if any)
n.fsize = len(methodDecl.child[2].child[1].child)
n.typ = methodDecl.typ.ret[0]
// TODO: handle multiple return values
} else {
n.fsize = 0
}
} else {
log.Println(n.index, "unresolve call")
// method must be resolved here due to declaration after use
}
n.child[0].findex = -1 // To force reading value from node instead of frame (methods)
}
} else if sym, _, _ := scope.lookup(n.child[0].ident); sym != nil {
if sym.typ != nil && sym.typ.cat == BinT {
n.gen = callBin
n.typ = &Type{cat: ValueT}
r := sym.val.(reflect.Value)
n.child[0].fsize = r.Type().NumOut()
n.child[0].val = r
n.child[0].kind = BasicLit
} else if sym.typ != nil && sym.typ.cat == ValueT {
n.gen = callDirectBin
n.typ = &Type{cat: ValueT}
} else {
n.val = sym.node
n.fsize = len(sym.typ.ret)
if n.fsize == 1 {
// If called func returns exactly one value, propagate its type in call node.
// Multiple return values will be handled differently through AssignX.
n.typ = sym.typ.ret[0]
}
}
} else if n.child[0].kind == SelectorSrc {
// Forward type of first returned value
// Multiple return values will be handled differently through AssignX.
if len(n.child[0].typ.ret) > 0 {
n.typ = n.child[0].typ.ret[0]
n.fsize = len(n.child[0].typ.ret)
}
}
*/
case CaseClause:
n.findex = scope.inc(interp)
@@ -656,13 +658,13 @@ func (interp *Interpreter) Cfg(root *Node) []*Node {
interp.scope[pkgName].sym[funcName].kind = Func
interp.scope[pkgName].sym[funcName].node = n
n.types = frameTypes(n, n.flen)
genFun(n)
case FuncLit:
n.typ = n.child[2].typ
n.val = n
n.flen = scope.size + 1
scope = scope.pop()
funcDef = true
n.types = frameTypes(n, n.flen)
n.framepos = n.child[2].framepos
@@ -682,12 +684,13 @@ func (interp *Interpreter) Cfg(root *Node) []*Node {
case Ident:
if n.anc.kind == File || (n.anc.kind == SelectorExpr && n.anc.child[0] != n) || (n.anc.kind == KeyValueExpr && n.anc.child[0] == n) {
// skip symbol creation/lookup for idents used as key
// Skip symbol creation/lookup for idents used as key
} else if l := len(n.anc.child); n.anc.kind == Field && l > 1 && n.anc.child[l-1] != n {
// Create a new local symbol for func argument
n.findex = scope.inc(interp)
scope.sym[n.ident] = &Symbol{index: scope.size, kind: Var}
} else if sym, level, ok := scope.lookup(n.ident); ok {
// Found symbol, populate node info
n.typ, n.findex, n.level = sym.typ, sym.index, level
if n.findex < 0 {
n.val = sym.node
@@ -705,7 +708,6 @@ func (interp *Interpreter) Cfg(root *Node) []*Node {
n.val = nil
}
}
n.recv = n
} else {
if n.ident == "_" || n.anc.kind == Define || n.anc.kind == DefineX || n.anc.kind == RangeStmt || n.anc.kind == ValueSpec {
// Create a new local symbol for func argument or local var definition
@@ -803,7 +805,7 @@ func (interp *Interpreter) Cfg(root *Node) []*Node {
if n.typ == nil {
log.Fatal("typ should not be nil:", n.index, n.child[0])
}
//log.Println(n.index, "selector", n.child[0].ident+"."+n.child[1].ident, n.typ.cat)
log.Println(n.index, "selector", n.child[0].ident+"."+n.child[1].ident, n.typ.cat)
if n.typ.cat == ValueT {
// Handle object defined in runtime
if method, ok := n.typ.rtype.MethodByName(n.child[1].ident); ok {
@@ -843,30 +845,19 @@ func (interp *Interpreter) Cfg(root *Node) []*Node {
name := n.child[1].ident
pkg := n.child[0].sym.path
if s, ok := interp.binValue[pkg][name]; ok {
n.kind = SelectorImport
n.val = s
if typ := s.Type(); typ.Kind() == reflect.Func {
n.typ = &Type{cat: ValueT, rtype: typ}
n.fsize = typ.NumOut()
//} else if typ.Kind() == reflect.Ptr {
// a symbol of kind pointer must be dereferenced to access type
// n.typ = &Type{cat: ValueT, rtype: typ.Elem(), rzero: n.val.(reflect.Value).Elem()}
} else {
n.typ = &Type{cat: ValueT, rtype: typ}
n.rval = n.val.(reflect.Value)
n.kind = Rvalue
n.kind = Rvalue
n.rval = s
n.typ = &Type{cat: ValueT, rtype: s.Type()}
if s.Kind() == reflect.Func {
n.fsize = n.typ.rtype.NumOut()
}
n.gen = nop
} else if s, ok := interp.binType[pkg][name]; ok {
//n.kind = SelectorImport
n.kind = Rtype
n.typ = &Type{cat: ValueT, rtype: s}
n.gen = nop
if s.Kind() == reflect.Func {
n.fsize = s.NumOut()
//} else if typ.Kind() == reflect.Ptr {
// a symbol of kind pointer must be dereferenced to access type
// n.typ = &Type{cat: ValueT, rtype: typ.Elem(), rzero: n.val.(reflect.Value).Elem()}
}
}
} else if n.typ.cat == ArrayT {
@@ -894,9 +885,12 @@ func (interp *Interpreter) Cfg(root *Node) []*Node {
} else if m, lind := n.typ.lookupMethod(n.child[1].ident); m != nil {
// Handle method
n.gen = nop
//n.kind = BasicLit
n.val = m
n.child[1].val = lind
n.typ = m.typ
n.recv = n.child[0]
log.Println(n.index, "method recv", m.index, n.recv.index, lind)
} else {
// Handle promoted field in embedded struct
if ti := n.typ.lookupField(n.child[1].ident); len(ti) > 0 {
@@ -1099,6 +1093,11 @@ func valueGenerator(n *Node, i int) func(*Frame) reflect.Value {
}
}
func genValuePtr(n *Node) func(*Frame) reflect.Value {
v := genValue(n)
return func(f *Frame) reflect.Value { return v(f).Addr() }
}
func genValue(n *Node) func(*Frame) reflect.Value {
switch n.kind {
case BasicLit, FuncDecl, SelectorSrc:
@@ -1139,6 +1138,35 @@ func genValue(n *Node) func(*Frame) reflect.Value {
return nil
}
func genFun(n *Node) {
start := n.child[3].start
framepos := n.framepos
flen := n.flen
types := n.types
nout := len(n.typ.ret)
n.fun = func(f *Frame, in []reflect.Value, goroutine bool) []reflect.Value {
// Allocate local frame
nf := Frame{anc: f, data: make([]reflect.Value, flen)}
for i, t := range types {
if t != nil {
nf.data[i] = reflect.New(t).Elem()
}
}
// Copy input parameters from caller frame to local
for i, pos := range framepos {
nf.data[pos].Set(in[i])
}
if goroutine {
go runCfg(start, &nf)
} else {
runCfg(start, &nf)
}
// Propagate return values to caller
return nf.data[:nout]
}
}
// Experimental, temporary & incomplete
func getValue(n *Node) (int, reflect.Value, bool) {
var index int

View File

@@ -29,9 +29,10 @@ type Node struct {
action Action // action
exec Builtin // generated function to execute
gen BuiltinGenerator // generator function to produce above bltn
val interface{} // static generic value (CFG execution)
rval reflect.Value // reflection value to let runtime access interpreter (CFG)
ident string // set if node is a var or func
fun func(*Frame, []reflect.Value, bool) []reflect.Value
val interface{} // static generic value (CFG execution)
rval reflect.Value // reflection value to let runtime access interpreter (CFG)
ident string // set if node is a var or func
}
// Frame contains values for the current execution level

View File

@@ -510,8 +510,10 @@ package main
type adder func(int, int) int
func genAdd(k int) adder {
println("k:", k)
return func(i, j int) int {
return i + j
println("#1 k:", k)
return i + j + k
}
}
@@ -524,7 +526,7 @@ func main() {
i.Eval(src)
// Output:
// 7
// 12
}
func Example_closure1() {
@@ -569,7 +571,8 @@ func adder() func(int) int {
func main() {
pos, neg := adder(), adder()
for i := 0; i < 10; i++ {
println(pos(i), neg(-2*i))
println(pos(i), neg(0-2*i))
}
}`
i := NewInterpreter(Opt{Entry: "main"})
@@ -3234,10 +3237,13 @@ type T struct {
func main() {
a := T{}
println(a.i, a.opt.b)
}`
}
`
i := NewInterpreter(Opt{Entry: "main"})
i.Eval(src)
// Output:
// 0 false
}
func Example_struct8() {
@@ -3263,9 +3269,7 @@ func f(i int) int { return i * i }
func main() {
a := T{5, 7, T2{8, T3{9}}}
//println(a.f, a.g, a.T2.h, a.T2.T3.k)
//fmt.Println(a.T2)
println(a.h)
println(a.f, a.g, a.T2.h, a.T2.T3.k)
}
`
i := NewInterpreter(Opt{Entry: "main"})

View File

@@ -21,7 +21,6 @@ var builtin = [...]BuiltinGenerator{
Add: add,
And: and,
Call: call,
CallF: call,
Case: _case,
CompositeLit: arrayLit,
Dec: nop,
@@ -453,21 +452,64 @@ func (n *Node) wrapNode(in []reflect.Value) []reflect.Value {
return result
}
// FIXME: handle case where func return a boolean
func call(n *Node) {
//var recv *Node
//var rseq []int
//forkFrame := n.action == CallF // add a frame indirection for closure
func call2(n *Node) {
next := getExec(n.tnext)
value := genValue(n.child[0])
child := n.child[1:]
goroutine := n.anc.kind == GoStmt
// Compute input argument value functions
var values []func(*Frame) reflect.Value
var recv *Node
for _, c := range child {
values = append(values, genValue(c))
}
// compute frame indexes for return values
ret := make([]int, len(n.child[0].typ.ret))
for i := range n.child[0].typ.ret {
ret[i] = n.findex + i
}
n.exec = func(f *Frame) Builtin {
def := value(f).Interface().(*Node)
in := make([]reflect.Value, len(child))
if def.frame != nil {
f = def.frame
}
for i, v := range values {
in[i] = v(f)
}
out := def.fun(f, in, goroutine)
log.Println(n.index, "out:", out, ret, f.data)
// Propagate return values to caller frame
for i, r := range ret {
log.Println(n.index, out[i], r)
f.data[r] = out[i]
}
return next
}
}
// FIXME: handle case where func return a boolean
func call(n *Node) {
goroutine := n.anc.kind == GoStmt
var values []func(*Frame) reflect.Value
//var recv *Node
//var rseq []int
if n.child[0].kind == SelectorExpr && n.child[0].typ.cat != SrcPkgT && n.child[0].typ.cat != BinPkgT {
// compute method object receiver
recv = n.child[0].recv
//rseq = n.child[0].child[1].val.([]int)
values = append(values, genValue(recv))
//if n.child[0].kind == SelectorExpr && n.child[0].typ.cat != SrcPkgT && n.child[0].typ.cat != BinPkgT {
// // compute method object receiver
// recv = n.child[0].recv
// //rseq = n.child[0].child[1].val.([]int)
// log.Println(n.index, "recv typ", recv.typ.cat, n.child[0].typ.cat)
// //if recv.typ.cat == StructT {
// // values = append(values, genValuePtr(recv))
// //} else {
// values = append(values, genValue(recv))
// //}
//}
if n.child[0].recv != nil {
values = append(values, genValue(n.child[0].recv))
}
next := getExec(n.tnext)
@@ -488,6 +530,7 @@ func call(n *Node) {
n.exec = func(f *Frame) Builtin {
def := value(f).Interface().(*Node)
log.Println(n.index, "def.recv:", def)
anc := f
if def.frame != nil {
// Get closure frame context (if any)
@@ -503,6 +546,7 @@ func call(n *Node) {
}
// copy input parameters from caller
for i, v := range values {
//log.Println(n.index, i, def.framepos[i], nf.data[def.framepos[i]].Kind(), v(f).Kind())
nf.data[def.framepos[i]].Set(v(f))
}
@@ -699,10 +743,12 @@ func getIndexAddr(n *Node) {
}
func getPtrIndex(n *Node) {
//i := n.findex
i := n.findex
//value0 := n.child[0].value
//value1 := n.child[1].value
next := getExec(n.tnext)
fi := n.child[1].val.(int)
value := genValue(n.child[0])
n.exec = func(f *Frame) Builtin {
log.Println(n.index, "in getPtrIndex")
@@ -713,6 +759,7 @@ func getPtrIndex(n *Node) {
// a := value0(f).([]interface{})
// f.data[i] = a[value1(f).(int)]
//}
f.data[i] = value(f).Elem().Field(fi)
return next
}
}
@@ -828,13 +875,13 @@ func getIndexMap2(n *Node) {
func getFunc(n *Node) {
i := n.findex
next := getExec(n.tnext)
genFun(n)
n.exec = func(f *Frame) Builtin {
frame := *f
node := *n
node.val = &node
frame := *f
node.frame = &frame
//n.frame = &frame
f.data[i] = reflect.ValueOf(&node)
return next
}