Update compiler (#22)
* refactor to use ast.Walk for recursive converting * added lots of test cases * added a new way to handle jump labels * function calls with multiple arguments * binary expression (LOR LAND) * struct types + method receives * cleaner opcode dumps, side by side diff for debugging test cases
This commit is contained in:
parent
b257a06f3e
commit
8fe079ec8e
19 changed files with 1298 additions and 1064 deletions
89
pkg/vm/compiler/func_scope.go
Normal file
89
pkg/vm/compiler/func_scope.go
Normal file
|
@ -0,0 +1,89 @@
|
|||
package compiler
|
||||
|
||||
import (
|
||||
"go/ast"
|
||||
"log"
|
||||
)
|
||||
|
||||
// A funcScope represents a scope within the function context.
|
||||
// It holds al the local variables along with the initialized struct positions.
|
||||
type funcScope struct {
|
||||
// function identifier
|
||||
name string
|
||||
|
||||
// The declaration of the function in the AST
|
||||
decl *ast.FuncDecl
|
||||
|
||||
// program label of the function
|
||||
label int
|
||||
|
||||
// local scope of the function
|
||||
scope map[string]int
|
||||
|
||||
// mapping of structs positions with their scope
|
||||
structs map[int]*structScope
|
||||
|
||||
// local variable counter
|
||||
i int
|
||||
}
|
||||
|
||||
func newFuncScope(decl *ast.FuncDecl, label int) *funcScope {
|
||||
return &funcScope{
|
||||
name: decl.Name.Name,
|
||||
decl: decl,
|
||||
label: label,
|
||||
scope: map[string]int{},
|
||||
structs: map[int]*structScope{},
|
||||
i: -1,
|
||||
}
|
||||
}
|
||||
|
||||
func (c *funcScope) stackSize() int64 {
|
||||
size := 0
|
||||
ast.Inspect(c.decl, func(n ast.Node) bool {
|
||||
switch n.(type) {
|
||||
case *ast.AssignStmt, *ast.ReturnStmt, *ast.IfStmt:
|
||||
size++
|
||||
}
|
||||
return true
|
||||
})
|
||||
|
||||
numArgs := len(c.decl.Type.Params.List)
|
||||
// Also take care of struct methods recv: e.g. (t Token).Foo().
|
||||
if c.decl.Recv != nil {
|
||||
numArgs += len(c.decl.Recv.List)
|
||||
}
|
||||
return int64(size + numArgs)
|
||||
}
|
||||
|
||||
func (c *funcScope) newStruct() *structScope {
|
||||
strct := newStructScope()
|
||||
c.structs[len(c.scope)] = strct
|
||||
return strct
|
||||
}
|
||||
|
||||
func (c *funcScope) loadStruct(name string) *structScope {
|
||||
l := c.loadLocal(name)
|
||||
strct, ok := c.structs[l]
|
||||
if !ok {
|
||||
log.Fatalf("could not resolve struct %s", name)
|
||||
}
|
||||
return strct
|
||||
}
|
||||
|
||||
// newLocal creates a new local variable into the scope of the function.
|
||||
func (c *funcScope) newLocal(name string) int {
|
||||
c.i++
|
||||
c.scope[name] = c.i
|
||||
return c.i
|
||||
}
|
||||
|
||||
// loadLocal loads the position of a local variable inside the scope of the function.
|
||||
func (c *funcScope) loadLocal(name string) int {
|
||||
i, ok := c.scope[name]
|
||||
if !ok {
|
||||
// should emit a compiler warning.
|
||||
return c.newLocal(name)
|
||||
}
|
||||
return i
|
||||
}
|
Loading…
Add table
Add a link
Reference in a new issue