fix out of order method resolution

This commit is contained in:
Marc Vertes
2018-09-21 16:04:30 +02:00
parent 2ce194d6d8
commit b19876e4e2
5 changed files with 54 additions and 50 deletions

View File

@@ -10,3 +10,6 @@ func main() {
}
func (c Coord) dist() int { return c.x*c.x + c.y*c.y }
// Output:
// 25

View File

@@ -4,8 +4,7 @@ import "fmt"
const (
SomeString = "constant string"
// SomeInt = 1
SomeInt = 1
)
type T1 struct {

View File

@@ -169,28 +169,6 @@ func (interp *Interpreter) Cfg(root *Node) []*Node {
if n.child[1].ident == "init" {
initNodes = append(initNodes, n)
}
if len(n.child[0].child) > 0 {
// function is a method, add it to the related type
var t *Type
var tname string
n.ident = n.child[1].ident
recv := n.child[0].child[0]
if len(recv.child) < 2 {
// Receiver var name is skipped in method declaration (fix that in AST ?)
tname = recv.child[0].ident
} else {
tname = recv.child[1].ident
}
if tname == "" {
tname = recv.child[1].child[0].ident
elemtype := scope.getType(tname)
t = &Type{cat: PtrT, val: elemtype}
elemtype.method = append(elemtype.method, n)
} else {
t = scope.getType(tname)
}
t.method = append(t.method, n)
}
if len(n.child[2].child) == 2 {
// allocate entries for return values at start of frame
scope.size += len(n.child[2].child[1].child)
@@ -459,15 +437,20 @@ func (interp *Interpreter) Cfg(root *Node) []*Node {
n.fsize = l
}
} else {
// Resolve method and receiver path, store them in node static value for run
methodDecl := n.child[0].val.(*Node)
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
// 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 {
n.fsize = 0
log.Println(n.index, "resolve method")
// 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)
}

View File

@@ -16,20 +16,12 @@ func (interp *Interpreter) Gta(root *Node) {
root.Walk(func(n *Node) bool {
switch n.kind {
case Define:
varName := n.child[0].ident
scope.sym[varName] = &Symbol{kind: Var, global: true, index: scope.inc(interp)}
if len(n.child) > 1 {
scope.sym[n.child[0].ident] = &Symbol{
kind: Var,
global: scope.global,
index: scope.inc(interp),
typ: nodeType(interp, scope, n.child[1]),
}
scope.sym[varName].typ = nodeType(interp, scope, n.child[1])
} else {
scope.sym[n.child[0].ident] = &Symbol{
kind: Var,
global: scope.global,
index: scope.inc(interp),
typ: nodeType(interp, scope, n.anc.child[0].child[1]),
}
scope.sym[varName].typ = nodeType(interp, scope, n.anc.child[0].child[1])
}
return false
@@ -41,10 +33,29 @@ func (interp *Interpreter) Gta(root *Node) {
scope = interp.scope[pkgName]
case FuncDecl:
scope.sym[n.child[1].ident] = &Symbol{
kind: Func,
typ: nodeType(interp, scope, n.child[2]),
node: n,
n.typ = nodeType(interp, scope, n.child[2])
scope.sym[n.child[1].ident] = &Symbol{kind: Func, typ: n.typ, node: n}
if len(n.child[0].child) > 0 {
// function is a method, add it to the related type
var t *Type
var typeName string
n.ident = n.child[1].ident
recv := n.child[0].child[0]
if len(recv.child) < 2 {
// Receiver var name is skipped in method declaration (fix that in AST ?)
typeName = recv.child[0].ident
} else {
typeName = recv.child[1].ident
}
if typeName == "" {
typeName = recv.child[1].child[0].ident
elemtype := scope.getType(typeName)
t = &Type{cat: PtrT, val: elemtype}
elemtype.method = append(elemtype.method, n)
} else {
t = scope.getType(typeName)
}
t.method = append(t.method, n)
}
return false
@@ -72,12 +83,17 @@ func (interp *Interpreter) Gta(root *Node) {
}
case TypeSpec:
typeName := n.child[0].ident
if n.child[1].kind == Ident {
n.typ = &Type{cat: AliasT, val: nodeType(interp, scope, n.child[1])}
} else {
n.typ = nodeType(interp, scope, n.child[1])
}
scope.sym[n.child[0].ident] = &Symbol{kind: Typ, typ: n.typ}
// Type may already be declared for a receiver in a method function
if scope.sym[typeName] == nil {
scope.sym[typeName] = &Symbol{kind: Typ}
}
scope.sym[typeName].typ = n.typ
return false
}

View File

@@ -1704,10 +1704,13 @@ func main() {
println(o.dist())
}
func (c Coord) dist() int { return c.x*c.x + c.y*c.y }`
func (c Coord) dist() int { return c.x*c.x + c.y*c.y }
`
i := NewInterpreter(Opt{Entry: "main"})
i.Eval(src)
// Output:
// 25
}
func Example_neg0() {