Fix assignement of function call, code clean

This commit is contained in:
Marc Vertes
2018-11-16 16:51:31 +01:00
parent 9212167392
commit eff6d5f73b
2 changed files with 106 additions and 250 deletions

View File

@@ -205,62 +205,53 @@ func (interp *Interpreter) Cfg(root *Node) []*Node {
case Define, AssignStmt:
wireChild(n)
name := n.child[0].ident
sym, level, _ := scope.lookup(name)
dest, src := n.child[0], n.child[1]
sym, level, _ := scope.lookup(dest.ident)
if n.kind == Define {
n.child[0].val = n.child[1].val
n.child[0].typ = n.child[1].typ
n.child[0].recv = n.child[1].recv
n.child[0].findex = sym.index
if n.child[1].action == GetFunc {
dest.val = src.val
dest.typ = src.typ
dest.recv = src.recv
dest.findex = sym.index
if src.action == GetFunc {
sym.index = -1
sym.node = n.child[1]
sym.node = src
}
if n.child[1].kind == BasicLit {
sym.val = n.child[1].val
} else if n.child[1].kind == CallExpr {
if src.kind == BasicLit {
sym.val = src.val
} else if isRegularCall(src) || isBinCall(src) {
// propagate call return value type
n.child[0].typ = getReturnedType(n.child[1].child[0])
sym.typ = n.child[0].typ
dest.typ = getReturnedType(src.child[0])
sym.typ = dest.typ
}
}
n.findex = n.child[0].findex
n.val = n.child[0].val
n.findex = dest.findex
n.val = dest.val
// Propagate type
// TODO: Check that existing destination type matches source type
if n.child[1].action == Recv {
// Assign by reading from a receiving channel
n.gen = nop
n.child[1].findex = n.child[0].findex // Set recv address to LHS
n.child[0].typ = n.child[1].typ.val
src.findex = dest.findex // Set recv address to LHS
dest.typ = src.typ.val
} else if n.child[1].action == CompositeLit {
n.gen = nop
n.child[1].findex = n.child[0].findex
n.child[1].level = level
src.findex = dest.findex
src.level = level
}
n.typ = n.child[0].typ
n.typ = dest.typ
if sym != nil {
sym.typ = n.typ
sym.recv = n.child[1].recv
sym.recv = src.recv
}
n.level = level
//log.Println(n.index, "assign", n.child[0].ident, n.typ.cat, n.findex, n.level)
//log.Println(n.index, "assign", dest.ident, n.typ.cat, n.findex, n.level)
// If LHS is an indirection, get reference instead of value, to allow setting
if n.child[0].action == GetIndex {
if n.child[0].child[0].typ.cat == MapT {
if dest.action == GetIndex {
if dest.child[0].typ.cat == MapT {
n.gen = assignMap
n.child[0].gen = nop // skip getIndexMap
dest.gen = nop // skip getIndexMap
}
}
//} else if n.child[0].child[0].typ.cat == PtrT {
// // Handle the case where the receiver is a pointer to an object
// n.child[0].gen = getPtrIndexAddr
// n.gen = assignPtrField
//} else if n.child[0].action == Star {
// n.findex = n.child[0].child[0].findex
// n.level = n.child[0].child[0].level
// n.gen = indirectAssign
// }
if n.anc.kind == ConstDecl {
iotaValue++
}
@@ -733,7 +724,6 @@ func (interp *Interpreter) Cfg(root *Node) []*Node {
n.kind = Rvalue
}
n.typ = sym.typ
log.Println(n.index, "ident", n.ident, n.typ.rtype)
if n.typ.rtype.Kind() == reflect.Func {
n.fsize = n.typ.rtype.NumOut()
}
@@ -1090,11 +1080,12 @@ func isBuiltinCall(n *Node) bool {
}
func isBinCall(n *Node) bool {
return n.kind == CallExpr && n.child[0].typ.cat == ValueT
return n.kind == CallExpr && n.child[0].typ.cat == ValueT &&
n.child[0].typ.rtype.Kind() == reflect.Func
}
func isRegularCall(n *Node) bool {
return n.kind == CallExpr && n.child[0].typ.cat != ValueT && (n.child[0].sym == nil || n.child[0].sym.kind != Bltn)
return n.kind == CallExpr && n.child[0].typ.cat == FuncT
}
func variadicPos(n *Node) int {
@@ -1295,7 +1286,10 @@ func getValue(n *Node) (int, reflect.Value, bool) {
}
func getReturnedType(n *Node) *Type {
if n.typ.cat == ValueT {
switch n.typ.cat {
case BuiltinT:
return n.anc.typ
case ValueT:
return &Type{cat: ValueT, rtype: n.typ.rtype.Out(0)}
}
return n.typ.ret[0]

View File

@@ -211,19 +211,6 @@ func assignX(n *Node) {
}
}
//func indirectAssign(n *Node) {
// i := n.findex
// value := genValue(n.child[1])
// next := getExec(n.tnext)
//
// n.exec = func(f *Frame) Builtin {
// //*(f.data[i].(*interface{})) = value(f)
// log.Println(n.index, "in IndirectAssign")
// f.data[i].Elem().Set(value(f))
// return next
// }
//}
// assign implements single value assignement
func assign(n *Node) {
value := genValue(n)
@@ -255,31 +242,6 @@ func assign0(n *Node) {
}
}
//func assignField(n *Node) Builtin {
// i := n.findex
// value := genValue(n.child[1])
// next := getExec(n.tnext)
//
// log.Println(n.index, "gen assignField")
// return func(f *Frame) Builtin {
// //(*f.data[i].(*interface{})) = value(f)
// f.data[i].Set(value(f))
// log.Println(n.index, "in assignField", f.data[i], value(f), i, f.data, f.data[2], f.data[3])
// return next
// }
//}
//func assignPtrField(n *Node) {
// //i := n.findex
// //value := n.child[1].value
// next := getExec(n.tnext)
//
// n.exec = func(f *Frame) Builtin {
// //(*f.data[i].(*interface{})) = value(f)
// return next
// }
//}
func assignMap(n *Node) {
value := genValue(n.child[0].child[0]) // map
value0 := genValue(n.child[0].child[1]) // key
@@ -458,44 +420,6 @@ func (n *Node) wrapNode(in []reflect.Value) []reflect.Value {
return result
}
//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
// 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
@@ -629,33 +553,33 @@ func call(n *Node) {
// Call a function from a bin import, accessible through reflect
// FIXME: handle case where func return a boolean
func callDirectBin(n *Node) {
next := getExec(n.tnext)
child := n.child[1:]
value := genValue(n.child[0])
values := make([]func(*Frame) reflect.Value, len(child))
for i, c := range child {
values[i] = genValue(c)
}
n.exec = func(f *Frame) Builtin {
in := make([]reflect.Value, len(n.child)-1)
for i, v := range values {
if child[i].kind == Rvalue {
in[i] = v(f)
child[i].frame = f
} else {
in[i] = v(f)
}
}
fun := value(f)
v := fun.Call(in)
for i := 0; i < n.fsize; i++ {
f.data[n.findex+i] = v[i]
}
return next
}
}
//func callDirectBin(n *Node) {
// next := getExec(n.tnext)
// child := n.child[1:]
// value := genValue(n.child[0])
// values := make([]func(*Frame) reflect.Value, len(child))
// for i, c := range child {
// values[i] = genValue(c)
// }
//
// n.exec = func(f *Frame) Builtin {
// in := make([]reflect.Value, len(n.child)-1)
// for i, v := range values {
// if child[i].kind == Rvalue {
// in[i] = v(f)
// child[i].frame = f
// } else {
// in[i] = v(f)
// }
// }
// fun := value(f)
// v := fun.Call(in)
// for i := 0; i < n.fsize; i++ {
// f.data[n.findex+i] = v[i]
// }
// return next
// }
//}
// FIXME: handle case where func return a boolean
// Call a function from a bin import, accessible through reflect
@@ -695,53 +619,53 @@ func callBin(n *Node) {
// Call a method defined by an interface type on an object returned by a bin import, through reflect.
// In that case, the method func value can be resolved only at execution from the actual value
// of node, not during CFG.
func callBinInterfaceMethod(n *Node, f *Frame) {}
// Call a method on an object returned by a bin import function, through reflect
// FIXME: handle case where func return a boolean
func callBinMethod(n *Node) {
next := getExec(n.tnext)
child := n.child[1:]
values := make([]func(*Frame) reflect.Value, len(child))
for i, c := range child {
values[i] = genValue(c)
}
rvalue := genValue(n.child[0].child[0])
log.Println(n.index, "in callBinMethod")
n.exec = func(f *Frame) Builtin {
fun := n.child[0].rval
in := make([]reflect.Value, len(n.child))
//val := n.child[0].child[0].value(f)
//switch val.(type) {
//case reflect.Value:
// in[0] = val.(reflect.Value)
//default:
// in[0] = reflect.ValueOf(val)
//}
in[0] = rvalue(f)
for i, c := range n.child[1:] {
if c.kind == Rvalue {
//in[i+1] = c.value(f).(reflect.Value)
in[i+1] = values[i](f)
c.frame = f
} else {
//in[i+1] = reflect.ValueOf(c.value(f))
in[i+1] = values[i](f)
}
}
//log.Println(n.index, "in callBinMethod", n.ident, in)
if !fun.IsValid() {
fun = in[0].MethodByName(n.child[0].child[1].ident)
in = in[1:]
}
v := fun.Call(in)
for i := 0; i < n.fsize; i++ {
f.data[n.findex+i] = v[i]
}
return next
}
}
//func callBinInterfaceMethod(n *Node, f *Frame) {}
//
//// Call a method on an object returned by a bin import function, through reflect
//// FIXME: handle case where func return a boolean
//func callBinMethod(n *Node) {
// next := getExec(n.tnext)
// child := n.child[1:]
// values := make([]func(*Frame) reflect.Value, len(child))
// for i, c := range child {
// values[i] = genValue(c)
// }
// rvalue := genValue(n.child[0].child[0])
//
// log.Println(n.index, "in callBinMethod")
// n.exec = func(f *Frame) Builtin {
// fun := n.child[0].rval
// in := make([]reflect.Value, len(n.child))
// //val := n.child[0].child[0].value(f)
// //switch val.(type) {
// //case reflect.Value:
// // in[0] = val.(reflect.Value)
// //default:
// // in[0] = reflect.ValueOf(val)
// //}
// in[0] = rvalue(f)
// for i, c := range n.child[1:] {
// if c.kind == Rvalue {
// //in[i+1] = c.value(f).(reflect.Value)
// in[i+1] = values[i](f)
// c.frame = f
// } else {
// //in[i+1] = reflect.ValueOf(c.value(f))
// in[i+1] = values[i](f)
// }
// }
// //log.Println(n.index, "in callBinMethod", n.ident, in)
// if !fun.IsValid() {
// fun = in[0].MethodByName(n.child[0].child[1].ident)
// in = in[1:]
// }
// v := fun.Call(in)
// for i := 0; i < n.fsize; i++ {
// f.data[n.findex+i] = v[i]
// }
// return next
// }
//}
// Same as callBinMethod, but for handling f(g()) where g returns multiple values
// FIXME: handle case where func return a boolean
@@ -780,36 +704,13 @@ func callBinMethod(n *Node) {
// }
//}
func getIndexAddr(n *Node) {
//i := n.findex
//value0 := n.child[0].value
//value1 := n.child[1].value
next := getExec(n.tnext)
n.exec = func(f *Frame) Builtin {
log.Println(n.index, "in getIndexAddr")
//a := value0(f).([]interface{})
//f.data[i] = &a[value1(f).(int)]
return next
}
}
func getPtrIndex(n *Node) {
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 {
// if error, fallback to getIndex, to make receiver methods work both with pointers and objects
//if a, ok := value0(f).(*interface{}); ok {
// f.data[i] = (*a).([]interface{})[value1(f).(int)]
//} else {
// a := value0(f).([]interface{})
// f.data[i] = a[value1(f).(int)]
//}
f.data[i] = value(f).Elem().Field(fi)
return next
}
@@ -841,34 +742,6 @@ func getIndexBinMethod(n *Node) {
}
}
func getIndexBin(n *Node) {
i := n.findex
fi := n.val.([]int)
value := genValue(n.child[0])
next := getExec(n.tnext)
n.exec = func(f *Frame) Builtin {
a := reflect.ValueOf(value(f))
f.data[i] = a.FieldByIndex(fi)
return next
}
}
/*
func getIndex(n *Node) Builtin {
//i := n.findex
//value0 := n.child[0].value
//value1 := n.child[1].value
next := getExec(n.tnext)
return func(f *Frame) Builtin {
//a := value0(f).([]interface{})
//f.data[i] = a[value1(f).(int)]
return next
}
}
*/
func getIndex(n *Node) {
i := n.findex
next := getExec(n.tnext)
@@ -1074,17 +947,6 @@ func notEqual(n *Node) {
}
}
func indirectInc(n *Node) {
//i := n.findex
//value := n.child[0].value
next := getExec(n.tnext)
n.exec = func(f *Frame) Builtin {
//*(f.data[i].(*interface{})) = value(f).(int) + 1
return next
}
}
func inc(n *Node) {
value := genValue(n)
value0 := genValue(n.child[0])