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"
|
import "github.com/containous/dyngo/_test/provider"
|
||||||
|
|
||||||
func main() {
|
func main() {
|
||||||
provider.F1()
|
f := provider.Bar
|
||||||
|
f()
|
||||||
}
|
}
|
||||||
|
|
||||||
// Output:
|
// Output:
|
||||||
// SomeString: constant string
|
// Hello from Foo
|
||||||
|
|||||||
@@ -13,3 +13,6 @@ func main() {
|
|||||||
a := T{}
|
a := T{}
|
||||||
println(a.i, a.opt.b)
|
println(a.i, a.opt.b)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Output:
|
||||||
|
// 0 false
|
||||||
|
|||||||
@@ -19,9 +19,7 @@ func f(i int) int { return i * i }
|
|||||||
|
|
||||||
func main() {
|
func main() {
|
||||||
a := T{5, 7, T2{8, T3{9}}}
|
a := T{5, 7, T2{8, T3{9}}}
|
||||||
//println(a.f, a.g, a.T2.h, a.T2.T3.k)
|
println(a.f, a.g, a.T2.h, a.T2.T3.k)
|
||||||
//fmt.Println(a.T2)
|
|
||||||
println(a.h)
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// Output:
|
// Output:
|
||||||
|
|||||||
@@ -184,7 +184,6 @@ const (
|
|||||||
Add
|
Add
|
||||||
And
|
And
|
||||||
Call
|
Call
|
||||||
CallF
|
|
||||||
Case
|
Case
|
||||||
CompositeLit
|
CompositeLit
|
||||||
Dec
|
Dec
|
||||||
@@ -224,7 +223,6 @@ var actions = [...]string{
|
|||||||
Add: "+",
|
Add: "+",
|
||||||
And: "&",
|
And: "&",
|
||||||
Call: "call",
|
Call: "call",
|
||||||
CallF: "call",
|
|
||||||
Case: "case",
|
Case: "case",
|
||||||
CompositeLit: "compositeLit",
|
CompositeLit: "compositeLit",
|
||||||
Dec: "--",
|
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 {
|
func (interp *Interpreter) Cfg(root *Node) []*Node {
|
||||||
scope := interp.universe
|
scope := interp.universe
|
||||||
var loop, loopRestart *Node
|
var loop, loopRestart *Node
|
||||||
var funcDef bool // True if a function is defined in the current frame context
|
|
||||||
var initNodes []*Node
|
var initNodes []*Node
|
||||||
var exports *BinMap
|
var exports *BinMap
|
||||||
var expval *ValueMap
|
var expval *ValueMap
|
||||||
@@ -173,7 +172,6 @@ func (interp *Interpreter) Cfg(root *Node) []*Node {
|
|||||||
// allocate entries for return values at start of frame
|
// allocate entries for return values at start of frame
|
||||||
scope.size += len(n.child[2].child[1].child)
|
scope.size += len(n.child[2].child[1].child)
|
||||||
}
|
}
|
||||||
funcDef = false
|
|
||||||
|
|
||||||
case If0, If1, If2, If3:
|
case If0, If1, If2, If3:
|
||||||
scope = scope.push(0)
|
scope = scope.push(0)
|
||||||
@@ -369,7 +367,9 @@ func (interp *Interpreter) Cfg(root *Node) []*Node {
|
|||||||
case CallExpr:
|
case CallExpr:
|
||||||
wireChild(n)
|
wireChild(n)
|
||||||
n.findex = scope.inc(interp)
|
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 {
|
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.gen = n.child[0].sym.builtin
|
||||||
n.child[0].typ = &Type{cat: BuiltinT}
|
n.child[0].typ = &Type{cat: BuiltinT}
|
||||||
switch n.child[0].ident {
|
switch n.child[0].ident {
|
||||||
@@ -383,7 +383,7 @@ func (interp *Interpreter) Cfg(root *Node) []*Node {
|
|||||||
n.child[1].kind = BasicLit
|
n.child[1].kind = BasicLit
|
||||||
}
|
}
|
||||||
} else if n.child[0].isType(scope) {
|
} 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
|
n.typ = n.child[0].typ
|
||||||
if n.typ.cat == AliasT {
|
if n.typ.cat == AliasT {
|
||||||
n.gen = convert
|
n.gen = convert
|
||||||
@@ -396,113 +396,9 @@ func (interp *Interpreter) Cfg(root *Node) []*Node {
|
|||||||
n.gen = convertBin
|
n.gen = convertBin
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
} else if n.child[0].kind == SelectorImport {
|
} else if n.child[0].typ.cat == ValueT {
|
||||||
// TODO: Should process according to child type, not kind.
|
log.Println(n.index, "callBin", n.child[0].val)
|
||||||
n.fsize = n.child[0].fsize
|
n.gen = callBin
|
||||||
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)
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
// Reserve entries in frame to store results of call
|
// Reserve entries in frame to store results of call
|
||||||
scope.size += n.fsize
|
scope.size += n.fsize
|
||||||
@@ -512,11 +408,117 @@ func (interp *Interpreter) Cfg(root *Node) []*Node {
|
|||||||
} else {
|
} else {
|
||||||
scope.size += n.fsize
|
scope.size += n.fsize
|
||||||
}
|
}
|
||||||
|
n.recv = n.child[0].recv
|
||||||
|
|
||||||
if funcDef {
|
/*
|
||||||
// Trigger frame indirection to handle nested functions
|
else if n.child[0].kind == SelectorImport {
|
||||||
n.action = CallF
|
// 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:
|
case CaseClause:
|
||||||
n.findex = scope.inc(interp)
|
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].kind = Func
|
||||||
interp.scope[pkgName].sym[funcName].node = n
|
interp.scope[pkgName].sym[funcName].node = n
|
||||||
n.types = frameTypes(n, n.flen)
|
n.types = frameTypes(n, n.flen)
|
||||||
|
genFun(n)
|
||||||
|
|
||||||
case FuncLit:
|
case FuncLit:
|
||||||
n.typ = n.child[2].typ
|
n.typ = n.child[2].typ
|
||||||
n.val = n
|
n.val = n
|
||||||
n.flen = scope.size + 1
|
n.flen = scope.size + 1
|
||||||
scope = scope.pop()
|
scope = scope.pop()
|
||||||
funcDef = true
|
|
||||||
n.types = frameTypes(n, n.flen)
|
n.types = frameTypes(n, n.flen)
|
||||||
n.framepos = n.child[2].framepos
|
n.framepos = n.child[2].framepos
|
||||||
|
|
||||||
@@ -682,12 +684,13 @@ func (interp *Interpreter) Cfg(root *Node) []*Node {
|
|||||||
|
|
||||||
case Ident:
|
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) {
|
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 {
|
} 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
|
// Create a new local symbol for func argument
|
||||||
n.findex = scope.inc(interp)
|
n.findex = scope.inc(interp)
|
||||||
scope.sym[n.ident] = &Symbol{index: scope.size, kind: Var}
|
scope.sym[n.ident] = &Symbol{index: scope.size, kind: Var}
|
||||||
} else if sym, level, ok := scope.lookup(n.ident); ok {
|
} 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
|
n.typ, n.findex, n.level = sym.typ, sym.index, level
|
||||||
if n.findex < 0 {
|
if n.findex < 0 {
|
||||||
n.val = sym.node
|
n.val = sym.node
|
||||||
@@ -705,7 +708,6 @@ func (interp *Interpreter) Cfg(root *Node) []*Node {
|
|||||||
n.val = nil
|
n.val = nil
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
n.recv = n
|
|
||||||
} else {
|
} else {
|
||||||
if n.ident == "_" || n.anc.kind == Define || n.anc.kind == DefineX || n.anc.kind == RangeStmt || n.anc.kind == ValueSpec {
|
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
|
// 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 {
|
if n.typ == nil {
|
||||||
log.Fatal("typ should not be nil:", n.index, n.child[0])
|
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 {
|
if n.typ.cat == ValueT {
|
||||||
// Handle object defined in runtime
|
// Handle object defined in runtime
|
||||||
if method, ok := n.typ.rtype.MethodByName(n.child[1].ident); ok {
|
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
|
name := n.child[1].ident
|
||||||
pkg := n.child[0].sym.path
|
pkg := n.child[0].sym.path
|
||||||
if s, ok := interp.binValue[pkg][name]; ok {
|
if s, ok := interp.binValue[pkg][name]; ok {
|
||||||
n.kind = SelectorImport
|
n.kind = Rvalue
|
||||||
n.val = s
|
n.rval = s
|
||||||
if typ := s.Type(); typ.Kind() == reflect.Func {
|
n.typ = &Type{cat: ValueT, rtype: s.Type()}
|
||||||
n.typ = &Type{cat: ValueT, rtype: typ}
|
if s.Kind() == reflect.Func {
|
||||||
n.fsize = typ.NumOut()
|
n.fsize = n.typ.rtype.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.gen = nop
|
n.gen = nop
|
||||||
} else if s, ok := interp.binType[pkg][name]; ok {
|
} else if s, ok := interp.binType[pkg][name]; ok {
|
||||||
//n.kind = SelectorImport
|
|
||||||
n.kind = Rtype
|
n.kind = Rtype
|
||||||
n.typ = &Type{cat: ValueT, rtype: s}
|
n.typ = &Type{cat: ValueT, rtype: s}
|
||||||
n.gen = nop
|
n.gen = nop
|
||||||
if s.Kind() == reflect.Func {
|
if s.Kind() == reflect.Func {
|
||||||
n.fsize = s.NumOut()
|
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 {
|
} 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 {
|
} else if m, lind := n.typ.lookupMethod(n.child[1].ident); m != nil {
|
||||||
// Handle method
|
// Handle method
|
||||||
n.gen = nop
|
n.gen = nop
|
||||||
|
//n.kind = BasicLit
|
||||||
n.val = m
|
n.val = m
|
||||||
n.child[1].val = lind
|
n.child[1].val = lind
|
||||||
n.typ = m.typ
|
n.typ = m.typ
|
||||||
|
n.recv = n.child[0]
|
||||||
|
log.Println(n.index, "method recv", m.index, n.recv.index, lind)
|
||||||
} else {
|
} else {
|
||||||
// Handle promoted field in embedded struct
|
// Handle promoted field in embedded struct
|
||||||
if ti := n.typ.lookupField(n.child[1].ident); len(ti) > 0 {
|
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 {
|
func genValue(n *Node) func(*Frame) reflect.Value {
|
||||||
switch n.kind {
|
switch n.kind {
|
||||||
case BasicLit, FuncDecl, SelectorSrc:
|
case BasicLit, FuncDecl, SelectorSrc:
|
||||||
@@ -1139,6 +1138,35 @@ func genValue(n *Node) func(*Frame) reflect.Value {
|
|||||||
return nil
|
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
|
// Experimental, temporary & incomplete
|
||||||
func getValue(n *Node) (int, reflect.Value, bool) {
|
func getValue(n *Node) (int, reflect.Value, bool) {
|
||||||
var index int
|
var index int
|
||||||
|
|||||||
@@ -29,9 +29,10 @@ type Node struct {
|
|||||||
action Action // action
|
action Action // action
|
||||||
exec Builtin // generated function to execute
|
exec Builtin // generated function to execute
|
||||||
gen BuiltinGenerator // generator function to produce above bltn
|
gen BuiltinGenerator // generator function to produce above bltn
|
||||||
val interface{} // static generic value (CFG execution)
|
fun func(*Frame, []reflect.Value, bool) []reflect.Value
|
||||||
rval reflect.Value // reflection value to let runtime access interpreter (CFG)
|
val interface{} // static generic value (CFG execution)
|
||||||
ident string // set if node is a var or func
|
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
|
// Frame contains values for the current execution level
|
||||||
|
|||||||
@@ -510,8 +510,10 @@ package main
|
|||||||
type adder func(int, int) int
|
type adder func(int, int) int
|
||||||
|
|
||||||
func genAdd(k int) adder {
|
func genAdd(k int) adder {
|
||||||
|
println("k:", k)
|
||||||
return func(i, j int) int {
|
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)
|
i.Eval(src)
|
||||||
|
|
||||||
// Output:
|
// Output:
|
||||||
// 7
|
// 12
|
||||||
}
|
}
|
||||||
|
|
||||||
func Example_closure1() {
|
func Example_closure1() {
|
||||||
@@ -569,7 +571,8 @@ func adder() func(int) int {
|
|||||||
func main() {
|
func main() {
|
||||||
pos, neg := adder(), adder()
|
pos, neg := adder(), adder()
|
||||||
for i := 0; i < 10; i++ {
|
for i := 0; i < 10; i++ {
|
||||||
println(pos(i), neg(-2*i))
|
println(pos(i), neg(0-2*i))
|
||||||
|
|
||||||
}
|
}
|
||||||
}`
|
}`
|
||||||
i := NewInterpreter(Opt{Entry: "main"})
|
i := NewInterpreter(Opt{Entry: "main"})
|
||||||
@@ -3234,10 +3237,13 @@ type T struct {
|
|||||||
func main() {
|
func main() {
|
||||||
a := T{}
|
a := T{}
|
||||||
println(a.i, a.opt.b)
|
println(a.i, a.opt.b)
|
||||||
}`
|
}
|
||||||
|
`
|
||||||
i := NewInterpreter(Opt{Entry: "main"})
|
i := NewInterpreter(Opt{Entry: "main"})
|
||||||
i.Eval(src)
|
i.Eval(src)
|
||||||
|
|
||||||
|
// Output:
|
||||||
|
// 0 false
|
||||||
}
|
}
|
||||||
|
|
||||||
func Example_struct8() {
|
func Example_struct8() {
|
||||||
@@ -3263,9 +3269,7 @@ func f(i int) int { return i * i }
|
|||||||
|
|
||||||
func main() {
|
func main() {
|
||||||
a := T{5, 7, T2{8, T3{9}}}
|
a := T{5, 7, T2{8, T3{9}}}
|
||||||
//println(a.f, a.g, a.T2.h, a.T2.T3.k)
|
println(a.f, a.g, a.T2.h, a.T2.T3.k)
|
||||||
//fmt.Println(a.T2)
|
|
||||||
println(a.h)
|
|
||||||
}
|
}
|
||||||
`
|
`
|
||||||
i := NewInterpreter(Opt{Entry: "main"})
|
i := NewInterpreter(Opt{Entry: "main"})
|
||||||
|
|||||||
@@ -21,7 +21,6 @@ var builtin = [...]BuiltinGenerator{
|
|||||||
Add: add,
|
Add: add,
|
||||||
And: and,
|
And: and,
|
||||||
Call: call,
|
Call: call,
|
||||||
CallF: call,
|
|
||||||
Case: _case,
|
Case: _case,
|
||||||
CompositeLit: arrayLit,
|
CompositeLit: arrayLit,
|
||||||
Dec: nop,
|
Dec: nop,
|
||||||
@@ -453,21 +452,64 @@ func (n *Node) wrapNode(in []reflect.Value) []reflect.Value {
|
|||||||
return result
|
return result
|
||||||
}
|
}
|
||||||
|
|
||||||
// FIXME: handle case where func return a boolean
|
func call2(n *Node) {
|
||||||
func call(n *Node) {
|
next := getExec(n.tnext)
|
||||||
//var recv *Node
|
value := genValue(n.child[0])
|
||||||
//var rseq []int
|
child := n.child[1:]
|
||||||
//forkFrame := n.action == CallF // add a frame indirection for closure
|
|
||||||
goroutine := n.anc.kind == GoStmt
|
goroutine := n.anc.kind == GoStmt
|
||||||
|
|
||||||
|
// Compute input argument value functions
|
||||||
var values []func(*Frame) reflect.Value
|
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
|
//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
|
//if n.child[0].kind == SelectorExpr && n.child[0].typ.cat != SrcPkgT && n.child[0].typ.cat != BinPkgT {
|
||||||
recv = n.child[0].recv
|
// // compute method object receiver
|
||||||
//rseq = n.child[0].child[1].val.([]int)
|
// recv = n.child[0].recv
|
||||||
values = append(values, genValue(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)
|
next := getExec(n.tnext)
|
||||||
@@ -488,6 +530,7 @@ func call(n *Node) {
|
|||||||
|
|
||||||
n.exec = func(f *Frame) Builtin {
|
n.exec = func(f *Frame) Builtin {
|
||||||
def := value(f).Interface().(*Node)
|
def := value(f).Interface().(*Node)
|
||||||
|
log.Println(n.index, "def.recv:", def)
|
||||||
anc := f
|
anc := f
|
||||||
if def.frame != nil {
|
if def.frame != nil {
|
||||||
// Get closure frame context (if any)
|
// Get closure frame context (if any)
|
||||||
@@ -503,6 +546,7 @@ func call(n *Node) {
|
|||||||
}
|
}
|
||||||
// copy input parameters from caller
|
// copy input parameters from caller
|
||||||
for i, v := range values {
|
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))
|
nf.data[def.framepos[i]].Set(v(f))
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -699,10 +743,12 @@ func getIndexAddr(n *Node) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
func getPtrIndex(n *Node) {
|
func getPtrIndex(n *Node) {
|
||||||
//i := n.findex
|
i := n.findex
|
||||||
//value0 := n.child[0].value
|
//value0 := n.child[0].value
|
||||||
//value1 := n.child[1].value
|
//value1 := n.child[1].value
|
||||||
next := getExec(n.tnext)
|
next := getExec(n.tnext)
|
||||||
|
fi := n.child[1].val.(int)
|
||||||
|
value := genValue(n.child[0])
|
||||||
|
|
||||||
n.exec = func(f *Frame) Builtin {
|
n.exec = func(f *Frame) Builtin {
|
||||||
log.Println(n.index, "in getPtrIndex")
|
log.Println(n.index, "in getPtrIndex")
|
||||||
@@ -713,6 +759,7 @@ func getPtrIndex(n *Node) {
|
|||||||
// a := value0(f).([]interface{})
|
// a := value0(f).([]interface{})
|
||||||
// f.data[i] = a[value1(f).(int)]
|
// f.data[i] = a[value1(f).(int)]
|
||||||
//}
|
//}
|
||||||
|
f.data[i] = value(f).Elem().Field(fi)
|
||||||
return next
|
return next
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -828,13 +875,13 @@ func getIndexMap2(n *Node) {
|
|||||||
func getFunc(n *Node) {
|
func getFunc(n *Node) {
|
||||||
i := n.findex
|
i := n.findex
|
||||||
next := getExec(n.tnext)
|
next := getExec(n.tnext)
|
||||||
|
genFun(n)
|
||||||
|
|
||||||
n.exec = func(f *Frame) Builtin {
|
n.exec = func(f *Frame) Builtin {
|
||||||
|
frame := *f
|
||||||
node := *n
|
node := *n
|
||||||
node.val = &node
|
node.val = &node
|
||||||
frame := *f
|
|
||||||
node.frame = &frame
|
node.frame = &frame
|
||||||
//n.frame = &frame
|
|
||||||
f.data[i] = reflect.ValueOf(&node)
|
f.data[i] = reflect.ValueOf(&node)
|
||||||
return next
|
return next
|
||||||
}
|
}
|
||||||
|
|||||||
Reference in New Issue
Block a user