fix out of order method resolution
This commit is contained in:
@@ -10,3 +10,6 @@ func main() {
|
||||
}
|
||||
|
||||
func (c Coord) dist() int { return c.x*c.x + c.y*c.y }
|
||||
|
||||
// Output:
|
||||
// 25
|
||||
|
||||
@@ -4,8 +4,7 @@ import "fmt"
|
||||
|
||||
const (
|
||||
SomeString = "constant string"
|
||||
|
||||
// SomeInt = 1
|
||||
SomeInt = 1
|
||||
)
|
||||
|
||||
type T1 struct {
|
||||
|
||||
@@ -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)
|
||||
}
|
||||
|
||||
@@ -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
|
||||
|
||||
}
|
||||
|
||||
@@ -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() {
|
||||
|
||||
Reference in New Issue
Block a user