Fix calls of functions returning multiple values
This commit is contained in:
11
_test/ret4.go
Normal file
11
_test/ret4.go
Normal file
@@ -0,0 +1,11 @@
|
||||
package main
|
||||
|
||||
func r() int { return 1 }
|
||||
|
||||
func main() {
|
||||
a := r()
|
||||
println(a)
|
||||
}
|
||||
|
||||
// Output:
|
||||
// 1
|
||||
@@ -445,7 +445,7 @@ func (interp *Interpreter) Ast(src, name string) (string, *Node) {
|
||||
st.push(addChild(&root, anc, ChanType, Nop))
|
||||
|
||||
case *ast.CompositeLit:
|
||||
st.push(addChild(&root, anc, CompositeLitExpr, Nop))
|
||||
st.push(addChild(&root, anc, CompositeLitExpr, CompositeLit))
|
||||
|
||||
case *ast.DeclStmt:
|
||||
st.push(addChild(&root, anc, DeclStmt, Nop))
|
||||
|
||||
165
interp/cfg.go
165
interp/cfg.go
@@ -203,23 +203,25 @@ func (interp *Interpreter) Cfg(root *Node) []*Node {
|
||||
|
||||
case Define, AssignStmt:
|
||||
wireChild(n)
|
||||
name := n.child[0].ident
|
||||
sym, level, _ := scope.lookup(name)
|
||||
if n.kind == Define {
|
||||
// Force definition of assigned ident in current scope
|
||||
name := n.child[0].ident
|
||||
scope.inc(interp)
|
||||
//scope.inc(interp)
|
||||
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 = scope.size
|
||||
if scope.global {
|
||||
if sym, _, ok := scope.lookup(name); ok {
|
||||
n.child[0].findex = sym.index
|
||||
} else {
|
||||
scope.sym[name] = &Symbol{index: scope.size, global: true, kind: Var}
|
||||
}
|
||||
} else {
|
||||
scope.sym[name] = &Symbol{index: scope.size, kind: Var}
|
||||
}
|
||||
n.child[0].findex = sym.index
|
||||
//n.child[0].findex = scope.size
|
||||
//if scope.global {
|
||||
// if sym, _, ok := scope.lookup(name); ok {
|
||||
// n.child[0].findex = sym.index
|
||||
// } else {
|
||||
// scope.sym[name] = &Symbol{index: scope.size, global: true, kind: Var}
|
||||
// }
|
||||
//} else {
|
||||
// scope.sym[name] = &Symbol{index: scope.size, kind: Var}
|
||||
//}
|
||||
if n.child[1].action == GetFunc {
|
||||
scope.sym[name].index = -1
|
||||
scope.sym[name].node = n.child[1]
|
||||
@@ -237,13 +239,17 @@ func (interp *Interpreter) Cfg(root *Node) []*Node {
|
||||
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
|
||||
} else if n.child[1].action == CompositeLit {
|
||||
n.gen = nop
|
||||
n.child[1].findex = n.child[0].findex
|
||||
}
|
||||
n.typ = n.child[0].typ
|
||||
if sym, level, ok := scope.lookup(n.child[0].ident); ok {
|
||||
if sym != nil {
|
||||
sym.typ = n.typ
|
||||
sym.recv = n.child[1].recv
|
||||
n.level = level
|
||||
}
|
||||
n.level = level
|
||||
//log.Println(n.index, "assign", n.child[0].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 {
|
||||
@@ -256,6 +262,7 @@ func (interp *Interpreter) Cfg(root *Node) []*Node {
|
||||
}
|
||||
} 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 {
|
||||
@@ -265,6 +272,7 @@ func (interp *Interpreter) Cfg(root *Node) []*Node {
|
||||
case IncDecStmt:
|
||||
wireChild(n)
|
||||
n.findex = n.child[0].findex
|
||||
n.level = n.child[0].level
|
||||
n.child[0].typ = scope.getType("int")
|
||||
n.typ = n.child[0].typ
|
||||
if sym, level, ok := scope.lookup(n.child[0].ident); ok {
|
||||
@@ -273,46 +281,57 @@ func (interp *Interpreter) Cfg(root *Node) []*Node {
|
||||
}
|
||||
if n.child[0].action == Star {
|
||||
n.findex = n.child[0].child[0].findex
|
||||
n.level = n.child[0].child[0].level
|
||||
n.gen = indirectInc
|
||||
}
|
||||
|
||||
case DefineX, AssignXStmt:
|
||||
wireChild(n)
|
||||
l := len(n.child) - 1
|
||||
if n.kind == DefineX {
|
||||
// retrieve assigned value types from call signature
|
||||
var types []*Type
|
||||
switch n.child[l].kind {
|
||||
case CallExpr:
|
||||
if funtype := n.child[l].child[0].typ; funtype.cat == ValueT {
|
||||
// Handle functions imported from runtime
|
||||
for i := 0; i < funtype.rtype.NumOut(); i++ {
|
||||
types = append(types, &Type{cat: ValueT, rtype: funtype.rtype.Out(i)})
|
||||
}
|
||||
} else {
|
||||
types = funtype.ret
|
||||
}
|
||||
|
||||
case IndexExpr:
|
||||
types = append(types, n.child[l].child[0].typ.val, scope.getType("bool"))
|
||||
n.child[l].gen = getIndexMap2
|
||||
n.gen = nop
|
||||
|
||||
case TypeAssertExpr:
|
||||
types = append(types, n.child[l].child[1].typ, scope.getType("error"))
|
||||
|
||||
default:
|
||||
log.Fatalln(n.index, "Assign expression unsupported:", n.child[l].kind)
|
||||
}
|
||||
// Force definition of assigned idents in current scope
|
||||
for i, c := range n.child[:l] {
|
||||
c.findex = scope.inc(interp)
|
||||
scope.sym[c.ident] = &Symbol{index: scope.size, global: scope.global, kind: Var}
|
||||
if i < len(types) {
|
||||
scope.sym[c.ident].typ = types[i]
|
||||
//if n.kind == DefineX {
|
||||
// retrieve assigned value types from call signature
|
||||
var types []*Type
|
||||
switch n.child[l].kind {
|
||||
case CallExpr:
|
||||
if funtype := n.child[l].child[0].typ; funtype.cat == ValueT {
|
||||
// Handle functions imported from runtime
|
||||
for i := 0; i < funtype.rtype.NumOut(); i++ {
|
||||
types = append(types, &Type{cat: ValueT, rtype: funtype.rtype.Out(i)})
|
||||
}
|
||||
log.Println(n.index, "assignX", types[0].rtype, types[1].rtype)
|
||||
} else {
|
||||
types = funtype.ret
|
||||
log.Println(n.index, "funtype", types[0].cat, types[1].cat)
|
||||
}
|
||||
|
||||
case IndexExpr:
|
||||
types = append(types, n.child[l].child[0].typ.val, scope.getType("bool"))
|
||||
n.child[l].gen = getIndexMap2
|
||||
n.gen = nop
|
||||
|
||||
case TypeAssertExpr:
|
||||
types = append(types, n.child[l].child[1].typ, scope.getType("error"))
|
||||
|
||||
default:
|
||||
log.Fatalln(n.index, "Assign expression unsupported:", n.child[l].kind)
|
||||
}
|
||||
// Force definition of assigned idents in current scope
|
||||
for i, c := range n.child[:l] {
|
||||
sym, _, ok := scope.lookup(c.ident)
|
||||
if !ok {
|
||||
log.Panic("symbol not found", c.ident)
|
||||
}
|
||||
sym.typ = types[i]
|
||||
c.typ = sym.typ
|
||||
log.Println(n.index, c.ident, c.findex, c.typ.cat)
|
||||
//c.findex = scope.inc(interp)
|
||||
//scope.sym[c.ident] = &Symbol{index: scope.size, global: scope.global, kind: Var}
|
||||
//if i < len(types) {
|
||||
// log.Println(n.index, c.ident, c.findex, types[i].cat)
|
||||
// scope.sym[c.ident].typ = types[i]
|
||||
//}
|
||||
}
|
||||
//}
|
||||
|
||||
case BinaryExpr:
|
||||
wireChild(n)
|
||||
@@ -398,13 +417,15 @@ func (interp *Interpreter) Cfg(root *Node) []*Node {
|
||||
}
|
||||
} else if n.child[0].typ.cat == ValueT {
|
||||
n.gen = callBin
|
||||
n.fsize = n.child[0].fsize
|
||||
} else {
|
||||
if typ := n.child[0].typ; len(typ.ret) > 0 {
|
||||
n.typ = n.child[0].typ.ret[0]
|
||||
n.fsize = len(typ.ret)
|
||||
}
|
||||
}
|
||||
// Reserve entries in frame to store results of call
|
||||
scope.size += n.fsize
|
||||
//scope.size += n.fsize
|
||||
if scope.global {
|
||||
interp.fsize += n.fsize
|
||||
scope.size = interp.fsize
|
||||
@@ -528,7 +549,9 @@ func (interp *Interpreter) Cfg(root *Node) []*Node {
|
||||
|
||||
case CompositeLitExpr:
|
||||
wireChild(n)
|
||||
n.findex = scope.inc(interp)
|
||||
if n.anc.action != Assign {
|
||||
n.findex = scope.inc(interp)
|
||||
}
|
||||
if n.child[0].typ == nil {
|
||||
n.child[0].typ = nodeType(interp, scope, n.child[0])
|
||||
}
|
||||
@@ -693,11 +716,11 @@ func (interp *Interpreter) Cfg(root *Node) []*Node {
|
||||
case Ident:
|
||||
if isKey(n) {
|
||||
// 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 isFuncArg(n) {
|
||||
// Create a new local symbol for func argument
|
||||
} else if isFuncArg(n) || isNewDefine(n) {
|
||||
// Create a new symbol in current scope, type to be set by parent node
|
||||
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, global: scope.global}
|
||||
n.sym = scope.sym[n.ident]
|
||||
} 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
|
||||
@@ -732,15 +755,20 @@ func (interp *Interpreter) Cfg(root *Node) []*Node {
|
||||
n.recv = n.sym.recv
|
||||
}
|
||||
} 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
|
||||
n.findex = scope.inc(interp)
|
||||
scope.sym[n.ident] = &Symbol{index: scope.size, global: scope.global, kind: Var}
|
||||
n.sym = scope.sym[n.ident]
|
||||
} else {
|
||||
log.Println(n.index, "unresolved global symbol", n.ident)
|
||||
}
|
||||
log.Println(n.index, "unresolved symbol", n.ident)
|
||||
}
|
||||
//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
|
||||
// // Symbol type will be set in parent node
|
||||
// n.findex = scope.inc(interp)
|
||||
// scope.sym[n.ident] = &Symbol{index: scope.size, global: scope.global, kind: Var}
|
||||
// n.sym = scope.sym[n.ident]
|
||||
// log.Println(n.index, "defined ", n.ident, n.findex)
|
||||
//} else {
|
||||
// log.Println(n.index, "unresolved global symbol", n.ident)
|
||||
//}
|
||||
//}
|
||||
|
||||
case If0: // if cond {}
|
||||
cond, tbody := n.child[0], n.child[1]
|
||||
@@ -1045,6 +1073,25 @@ func isKey(n *Node) bool {
|
||||
(n.anc.kind == KeyValueExpr && n.anc.child[0] == n)
|
||||
}
|
||||
|
||||
func isNewDefine(n *Node) bool {
|
||||
if n.ident == "_" {
|
||||
return true
|
||||
}
|
||||
if n.anc.kind == Define && n.anc.child[0] == n {
|
||||
return true
|
||||
}
|
||||
if n.anc.kind == DefineX && n.anc.child[len(n.anc.child)-1] != n {
|
||||
return true
|
||||
}
|
||||
if n.anc.kind == RangeStmt && (n.anc.child[0] == n || n.anc.child[1] == n) {
|
||||
return true
|
||||
}
|
||||
if n.anc.kind == ValueSpec {
|
||||
return true
|
||||
}
|
||||
return false
|
||||
}
|
||||
|
||||
func isFuncArg(n *Node) bool {
|
||||
if n.anc.kind != Field {
|
||||
return false
|
||||
|
||||
@@ -191,7 +191,7 @@ func (i *Interpreter) Eval(src string) string {
|
||||
// Execute CFG
|
||||
if !i.NoRun {
|
||||
genRun(root)
|
||||
//i.fsize++
|
||||
i.fsize++
|
||||
i.resizeFrame()
|
||||
i.run(root, nil)
|
||||
|
||||
|
||||
@@ -57,7 +57,7 @@ func (interp *Interpreter) run(n *Node, cf *Frame) {
|
||||
f = &Frame{anc: cf, data: make([]reflect.Value, n.flen)}
|
||||
}
|
||||
for i, t := range n.types {
|
||||
if t != nil {
|
||||
if t != nil && i < len(f.data) {
|
||||
f.data[i] = reflect.New(t).Elem()
|
||||
}
|
||||
}
|
||||
@@ -201,7 +201,10 @@ func assignX(n *Node) {
|
||||
|
||||
n.exec = func(f *Frame) Builtin {
|
||||
for i, value := range values {
|
||||
value(f).Set(f.data[b+i])
|
||||
log.Println(n.index, "in assignX", i, value(f), f.data[b+i], b)
|
||||
if f.data[b+i].IsValid() {
|
||||
value(f).Set(f.data[b+i])
|
||||
}
|
||||
}
|
||||
return next
|
||||
}
|
||||
@@ -227,6 +230,7 @@ func assign(n *Node) {
|
||||
next := getExec(n.tnext)
|
||||
|
||||
n.exec = func(f *Frame) Builtin {
|
||||
log.Println(n.index, "in assign")
|
||||
value(f).Set(value1(f))
|
||||
return next
|
||||
}
|
||||
@@ -643,14 +647,17 @@ func callBin(n *Node) {
|
||||
for i, c := range child {
|
||||
values[i] = genValue(c)
|
||||
}
|
||||
fsize := n.child[0].fsize
|
||||
|
||||
n.exec = func(f *Frame) Builtin {
|
||||
in := make([]reflect.Value, l)
|
||||
for i, v := range values {
|
||||
in[i] = v(f)
|
||||
}
|
||||
//log.Println(n.index, "callbin", value(f).Type())
|
||||
v := value(f).Call(in)
|
||||
for i := 0; i < n.fsize; i++ {
|
||||
//log.Println(n.index, "callBin, res:", v, fsize, n.findex)
|
||||
for i := 0; i < fsize; i++ {
|
||||
f.data[n.findex+i] = v[i]
|
||||
}
|
||||
return next
|
||||
|
||||
Reference in New Issue
Block a user