forked from TrueCloudLab/neoneo-go
Compiler update (basic sc ready) (#31)
* refactored structs, the scope is not needed anymore + fix passing struct in func arguments. * implemented byte arrays and added runtime tests * Added sc examples in compiler README + added quick nested if test. * Updated README
This commit is contained in:
parent
de3395fb51
commit
2345858238
19 changed files with 464 additions and 215 deletions
|
@ -89,13 +89,6 @@ func (c *codegen) emitLoadLocal(name string) {
|
|||
emitOpcode(c.prog, vm.Opickitem)
|
||||
}
|
||||
|
||||
func (c *codegen) emitLoadStructField(sName, fName string) {
|
||||
strct := c.scope.loadStruct(sName)
|
||||
pos := strct.loadField(fName)
|
||||
emitInt(c.prog, int64(pos))
|
||||
emitOpcode(c.prog, vm.Opickitem)
|
||||
}
|
||||
|
||||
func (c *codegen) emitStoreLocal(pos int) {
|
||||
emitOpcode(c.prog, vm.Ofromaltstack)
|
||||
emitOpcode(c.prog, vm.Odup)
|
||||
|
@ -111,10 +104,13 @@ func (c *codegen) emitStoreLocal(pos int) {
|
|||
emitOpcode(c.prog, vm.Osetitem)
|
||||
}
|
||||
|
||||
func (c *codegen) emitStoreStructField(sName, fName string) {
|
||||
strct := c.scope.loadStruct(sName)
|
||||
pos := strct.loadField(fName)
|
||||
emitInt(c.prog, int64(pos))
|
||||
func (c *codegen) emitLoadStructField(i int) {
|
||||
emitInt(c.prog, int64(i))
|
||||
emitOpcode(c.prog, vm.Opickitem)
|
||||
}
|
||||
|
||||
func (c *codegen) emitStoreStructField(i int) {
|
||||
emitInt(c.prog, int64(i))
|
||||
emitOpcode(c.prog, vm.Orot)
|
||||
emitOpcode(c.prog, vm.Osetitem)
|
||||
}
|
||||
|
@ -178,11 +174,11 @@ func (c *codegen) convertFuncDecl(file *ast.File, decl *ast.FuncDecl) {
|
|||
if decl.Recv != nil {
|
||||
for _, arg := range decl.Recv.List {
|
||||
ident := arg.Names[0]
|
||||
t, ok := c.typeInfo.Defs[ident].Type().Underlying().(*types.Struct)
|
||||
// Currently only method receives for struct types is supported.
|
||||
_, ok := c.typeInfo.Defs[ident].Type().Underlying().(*types.Struct)
|
||||
if !ok {
|
||||
log.Fatal("method receiver is not a struct type")
|
||||
log.Fatal("method receives for non-struct types is not yet supported")
|
||||
}
|
||||
c.scope.newStruct(t)
|
||||
l := c.scope.newLocal(ident.Name)
|
||||
c.emitStoreLocal(l)
|
||||
}
|
||||
|
@ -235,12 +231,12 @@ func (c *codegen) Visit(node ast.Node) ast.Visitor {
|
|||
switch n.Tok {
|
||||
case token.ADD_ASSIGN, token.SUB_ASSIGN, token.MUL_ASSIGN, token.QUO_ASSIGN:
|
||||
c.emitLoadLocal(t.Name)
|
||||
ast.Walk(c, n.Rhs[0])
|
||||
ast.Walk(c, n.Rhs[0]) // can only add assign to 1 expr on the RHS
|
||||
c.convertToken(n.Tok)
|
||||
l := c.scope.loadLocal(t.Name)
|
||||
c.emitStoreLocal(l)
|
||||
default:
|
||||
ast.Walk(c, n.Rhs[0])
|
||||
ast.Walk(c, n.Rhs[i])
|
||||
l := c.scope.loadLocal(t.Name)
|
||||
c.emitStoreLocal(l)
|
||||
}
|
||||
|
@ -249,8 +245,12 @@ func (c *codegen) Visit(node ast.Node) ast.Visitor {
|
|||
switch expr := t.X.(type) {
|
||||
case *ast.Ident:
|
||||
ast.Walk(c, n.Rhs[i])
|
||||
c.emitLoadLocal(expr.Name) // load the struct
|
||||
c.emitStoreStructField(expr.Name, t.Sel.Name) // store the field
|
||||
typ := c.typeInfo.ObjectOf(expr).Type().Underlying()
|
||||
if strct, ok := typ.(*types.Struct); ok {
|
||||
c.emitLoadLocal(expr.Name) // load the struct
|
||||
i := indexOfStruct(strct, t.Sel.Name) // get the index of the field
|
||||
c.emitStoreStructField(i) // store the field
|
||||
}
|
||||
default:
|
||||
log.Fatal("nested selector assigns not supported yet")
|
||||
}
|
||||
|
@ -320,6 +320,11 @@ func (c *codegen) Visit(node ast.Node) ast.Visitor {
|
|||
typ = c.typeInfo.ObjectOf(t.Sel).Type().Underlying()
|
||||
default:
|
||||
ln := len(n.Elts)
|
||||
// ByteArrays need a different approach then normal arrays.
|
||||
if isByteArray(n, c.typeInfo) {
|
||||
c.convertByteArray(n)
|
||||
return nil
|
||||
}
|
||||
for i := ln - 1; i >= 0; i-- {
|
||||
c.emitLoadConst(c.typeInfo.Types[n.Elts[i]])
|
||||
}
|
||||
|
@ -430,17 +435,18 @@ func (c *codegen) Visit(node ast.Node) ast.Visitor {
|
|||
switch t := n.X.(type) {
|
||||
case *ast.Ident:
|
||||
typ := c.typeInfo.ObjectOf(t).Type().Underlying()
|
||||
switch typ.(type) {
|
||||
case *types.Struct:
|
||||
c.emitLoadLocal(t.Name) // load the struct
|
||||
c.emitLoadStructField(t.Name, n.Sel.Name) // load the field
|
||||
default:
|
||||
log.Fatal("non struct import selections not yet implemented, please use functions instead")
|
||||
if strct, ok := typ.(*types.Struct); ok {
|
||||
c.emitLoadLocal(t.Name) // load the struct
|
||||
i := indexOfStruct(strct, n.Sel.Name)
|
||||
c.emitLoadStructField(i) // load the field
|
||||
}
|
||||
default:
|
||||
log.Fatal("nested selectors not supported yet")
|
||||
}
|
||||
return nil
|
||||
|
||||
case *ast.UnaryExpr:
|
||||
// fmt.Println(n)
|
||||
}
|
||||
return c
|
||||
}
|
||||
|
@ -454,24 +460,33 @@ func (c *codegen) convertSyscall(name string) {
|
|||
emitOpcode(c.prog, vm.Onop)
|
||||
}
|
||||
|
||||
func (c *codegen) convertByteArray(lit *ast.CompositeLit) {
|
||||
buf := make([]byte, len(lit.Elts))
|
||||
for i := 0; i < len(lit.Elts); i++ {
|
||||
t := c.typeInfo.Types[lit.Elts[i]]
|
||||
val, _ := constant.Int64Val(t.Value)
|
||||
buf[i] = byte(val)
|
||||
}
|
||||
emitBytes(c.prog, buf)
|
||||
}
|
||||
|
||||
func (c *codegen) convertStruct(lit *ast.CompositeLit) {
|
||||
// Create a new structScope to initialize and store
|
||||
// the positions of its variables.
|
||||
t, ok := c.typeInfo.TypeOf(lit).Underlying().(*types.Struct)
|
||||
strct, ok := c.typeInfo.TypeOf(lit).Underlying().(*types.Struct)
|
||||
if !ok {
|
||||
log.Fatalf("the given literal is not of type struct: %v", lit)
|
||||
}
|
||||
strct := c.scope.newStruct(t)
|
||||
|
||||
emitOpcode(c.prog, vm.Onop)
|
||||
emitInt(c.prog, int64(strct.t.NumFields()))
|
||||
emitInt(c.prog, int64(strct.NumFields()))
|
||||
emitOpcode(c.prog, vm.Onewstruct)
|
||||
emitOpcode(c.prog, vm.Otoaltstack)
|
||||
|
||||
// We need to locally store all the fields, even if they are not initialized.
|
||||
// We will initialize all fields to their "zero" value.
|
||||
for i := 0; i < strct.t.NumFields(); i++ {
|
||||
sField := strct.t.Field(i)
|
||||
for i := 0; i < strct.NumFields(); i++ {
|
||||
sField := strct.Field(i)
|
||||
fieldAdded := false
|
||||
|
||||
// Fields initialized by the program.
|
||||
|
@ -481,7 +496,7 @@ func (c *codegen) convertStruct(lit *ast.CompositeLit) {
|
|||
|
||||
if sField.Name() == fieldName {
|
||||
ast.Walk(c, f.Value)
|
||||
pos := strct.loadField(fieldName)
|
||||
pos := indexOfStruct(strct, fieldName)
|
||||
c.emitStoreLocal(pos)
|
||||
fieldAdded = true
|
||||
break
|
||||
|
@ -490,7 +505,9 @@ func (c *codegen) convertStruct(lit *ast.CompositeLit) {
|
|||
if fieldAdded {
|
||||
continue
|
||||
}
|
||||
c.emitLoadConst(strct.typeAndValues[sField.Name()])
|
||||
|
||||
typeAndVal := typeAndValueForField(sField)
|
||||
c.emitLoadConst(typeAndVal)
|
||||
c.emitStoreLocal(i)
|
||||
}
|
||||
emitOpcode(c.prog, vm.Ofromaltstack)
|
||||
|
@ -552,6 +569,8 @@ func CodeGen(info *buildInfo) (*bytes.Buffer, error) {
|
|||
log.Fatal("could not find func main. did you forgot to declare it?")
|
||||
}
|
||||
|
||||
funUsage := analyzeFuncUsage(info.program.AllPackages)
|
||||
|
||||
// Bring all imported functions into scope
|
||||
for _, pkg := range info.program.AllPackages {
|
||||
for _, f := range pkg.Files {
|
||||
|
@ -565,11 +584,14 @@ func CodeGen(info *buildInfo) (*bytes.Buffer, error) {
|
|||
// Generate the code for the program
|
||||
for _, pkg := range info.program.AllPackages {
|
||||
c.typeInfo = &pkg.Info
|
||||
|
||||
for _, f := range pkg.Files {
|
||||
for _, decl := range f.Decls {
|
||||
switch n := decl.(type) {
|
||||
case *ast.FuncDecl:
|
||||
if n.Name.Name != mainIdent {
|
||||
// Dont convert the function if its not used. This will save alot
|
||||
// of bytecode space.
|
||||
if n.Name.Name != mainIdent && funUsage.funcUsed(n.Name.Name) {
|
||||
c.convertFuncDecl(f, n)
|
||||
}
|
||||
}
|
||||
|
|
Loading…
Add table
Add a link
Reference in a new issue