Rework function calls, in progress
This commit is contained in:
11
_test/bin.go
Normal file
11
_test/bin.go
Normal file
@@ -0,0 +1,11 @@
|
||||
package main
|
||||
|
||||
import "fmt"
|
||||
|
||||
func main() {
|
||||
f := fmt.Println
|
||||
f("Hello")
|
||||
}
|
||||
|
||||
// Output:
|
||||
// Hello
|
||||
6
_test/bltn.go
Normal file
6
_test/bltn.go
Normal file
@@ -0,0 +1,6 @@
|
||||
package main
|
||||
|
||||
func main() {
|
||||
f := println
|
||||
f("Hello")
|
||||
}
|
||||
23
_test/closure4.go
Normal file
23
_test/closure4.go
Normal 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
23
_test/closure5.go
Normal 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
24
_test/closure6.go
Normal 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
16
_test/method12.go
Normal 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
|
||||
@@ -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
|
||||
|
||||
@@ -13,3 +13,6 @@ func main() {
|
||||
a := T{}
|
||||
println(a.i, a.opt.b)
|
||||
}
|
||||
|
||||
// Output:
|
||||
// 0 false
|
||||
|
||||
@@ -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:
|
||||
|
||||
@@ -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: "--",
|
||||
|
||||
296
interp/cfg.go
296
interp/cfg.go
@@ -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
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -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"})
|
||||
|
||||
@@ -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
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user