compiler: replace emit* instructions with those from emit/ package

This commit is contained in:
Evgenii Stratonikov 2020-02-03 17:58:21 +03:00
parent 8243a8b3a7
commit dbc41b3044
2 changed files with 112 additions and 230 deletions

View file

@ -14,6 +14,7 @@ import (
"github.com/CityOfZion/neo-go/pkg/encoding/address" "github.com/CityOfZion/neo-go/pkg/encoding/address"
"github.com/CityOfZion/neo-go/pkg/io" "github.com/CityOfZion/neo-go/pkg/io"
"github.com/CityOfZion/neo-go/pkg/vm/emit"
"github.com/CityOfZion/neo-go/pkg/vm/opcode" "github.com/CityOfZion/neo-go/pkg/vm/opcode"
) )
@ -73,17 +74,17 @@ func (c *codegen) convertBasicType(t types.TypeAndValue, typ *types.Basic) {
switch typ.Kind() { switch typ.Kind() {
case types.Int, types.UntypedInt, types.Uint: case types.Int, types.UntypedInt, types.Uint:
val, _ := constant.Int64Val(t.Value) val, _ := constant.Int64Val(t.Value)
emitInt(c.prog.BinWriter, val) emit.Int(c.prog.BinWriter, val)
case types.String, types.UntypedString: case types.String, types.UntypedString:
val := constant.StringVal(t.Value) val := constant.StringVal(t.Value)
emitString(c.prog.BinWriter, val) emit.String(c.prog.BinWriter, val)
case types.Bool, types.UntypedBool: case types.Bool, types.UntypedBool:
val := constant.BoolVal(t.Value) val := constant.BoolVal(t.Value)
emitBool(c.prog.BinWriter, val) emit.Bool(c.prog.BinWriter, val)
case types.Byte: case types.Byte:
val, _ := constant.Int64Val(t.Value) val, _ := constant.Int64Val(t.Value)
b := byte(val) b := byte(val)
emitBytes(c.prog.BinWriter, []byte{b}) emit.Bytes(c.prog.BinWriter, []byte{b})
default: default:
c.prog.Err = fmt.Errorf("compiler doesn't know how to convert this basic type: %v", t) c.prog.Err = fmt.Errorf("compiler doesn't know how to convert this basic type: %v", t)
return return
@ -100,33 +101,33 @@ func (c *codegen) emitLoadLocal(name string) {
} }
func (c *codegen) emitLoadLocalPos(pos int) { func (c *codegen) emitLoadLocalPos(pos int) {
emitOpcode(c.prog.BinWriter, opcode.DUPFROMALTSTACK) emit.Opcode(c.prog.BinWriter, opcode.DUPFROMALTSTACK)
emitInt(c.prog.BinWriter, int64(pos)) emit.Int(c.prog.BinWriter, int64(pos))
emitOpcode(c.prog.BinWriter, opcode.PICKITEM) emit.Opcode(c.prog.BinWriter, opcode.PICKITEM)
} }
func (c *codegen) emitStoreLocal(pos int) { func (c *codegen) emitStoreLocal(pos int) {
emitOpcode(c.prog.BinWriter, opcode.DUPFROMALTSTACK) emit.Opcode(c.prog.BinWriter, opcode.DUPFROMALTSTACK)
if pos < 0 { if pos < 0 {
c.prog.Err = fmt.Errorf("invalid position to store local: %d", pos) c.prog.Err = fmt.Errorf("invalid position to store local: %d", pos)
return return
} }
emitInt(c.prog.BinWriter, int64(pos)) emit.Int(c.prog.BinWriter, int64(pos))
emitOpcode(c.prog.BinWriter, opcode.ROT) emit.Opcode(c.prog.BinWriter, opcode.ROT)
emitOpcode(c.prog.BinWriter, opcode.SETITEM) emit.Opcode(c.prog.BinWriter, opcode.SETITEM)
} }
func (c *codegen) emitLoadField(i int) { func (c *codegen) emitLoadField(i int) {
emitInt(c.prog.BinWriter, int64(i)) emit.Int(c.prog.BinWriter, int64(i))
emitOpcode(c.prog.BinWriter, opcode.PICKITEM) emit.Opcode(c.prog.BinWriter, opcode.PICKITEM)
} }
func (c *codegen) emitStoreStructField(i int) { func (c *codegen) emitStoreStructField(i int) {
emitInt(c.prog.BinWriter, int64(i)) emit.Int(c.prog.BinWriter, int64(i))
emitOpcode(c.prog.BinWriter, opcode.ROT) emit.Opcode(c.prog.BinWriter, opcode.ROT)
emitOpcode(c.prog.BinWriter, opcode.SETITEM) emit.Opcode(c.prog.BinWriter, opcode.SETITEM)
} }
// convertGlobals traverses the AST and only converts global declarations. // convertGlobals traverses the AST and only converts global declarations.
@ -170,9 +171,9 @@ func (c *codegen) convertFuncDecl(file ast.Node, decl *ast.FuncDecl) {
// All globals copied into the scope of the function need to be added // All globals copied into the scope of the function need to be added
// to the stack size of the function. // to the stack size of the function.
emitInt(c.prog.BinWriter, f.stackSize()+countGlobals(file)) emit.Int(c.prog.BinWriter, f.stackSize()+countGlobals(file))
emitOpcode(c.prog.BinWriter, opcode.NEWARRAY) emit.Opcode(c.prog.BinWriter, opcode.NEWARRAY)
emitOpcode(c.prog.BinWriter, opcode.TOALTSTACK) emit.Opcode(c.prog.BinWriter, opcode.TOALTSTACK)
// We need to handle methods, which in Go, is just syntactic sugar. // We need to handle methods, which in Go, is just syntactic sugar.
// The method receiver will be passed in as first argument. // The method receiver will be passed in as first argument.
@ -210,9 +211,9 @@ func (c *codegen) convertFuncDecl(file ast.Node, decl *ast.FuncDecl) {
// If this function returns the void (no return stmt) we will cleanup its junk on the stack. // If this function returns the void (no return stmt) we will cleanup its junk on the stack.
if !hasReturnStmt(decl) { if !hasReturnStmt(decl) {
emitOpcode(c.prog.BinWriter, opcode.FROMALTSTACK) emit.Opcode(c.prog.BinWriter, opcode.FROMALTSTACK)
emitOpcode(c.prog.BinWriter, opcode.DROP) emit.Opcode(c.prog.BinWriter, opcode.DROP)
emitOpcode(c.prog.BinWriter, opcode.RET) emit.Opcode(c.prog.BinWriter, opcode.RET)
} }
} }
@ -258,7 +259,7 @@ func (c *codegen) Visit(node ast.Node) ast.Visitor {
} }
if t.Name == "_" { if t.Name == "_" {
emitOpcode(c.prog.BinWriter, opcode.DROP) emit.Opcode(c.prog.BinWriter, opcode.DROP)
} else { } else {
l := c.scope.loadLocal(t.Name) l := c.scope.loadLocal(t.Name)
c.emitStoreLocal(l) c.emitStoreLocal(l)
@ -297,8 +298,8 @@ func (c *codegen) Visit(node ast.Node) ast.Visitor {
c.emitStoreStructField(index) c.emitStoreStructField(index)
case *ast.Ident: case *ast.Ident:
c.emitLoadLocal(ind.Name) c.emitLoadLocal(ind.Name)
emitOpcode(c.prog.BinWriter, opcode.ROT) emit.Opcode(c.prog.BinWriter, opcode.ROT)
emitOpcode(c.prog.BinWriter, opcode.SETITEM) emit.Opcode(c.prog.BinWriter, opcode.SETITEM)
default: default:
c.prog.Err = fmt.Errorf("unsupported index expression") c.prog.Err = fmt.Errorf("unsupported index expression")
return nil return nil
@ -316,9 +317,9 @@ func (c *codegen) Visit(node ast.Node) ast.Visitor {
ast.Walk(c, n.Results[i]) ast.Walk(c, n.Results[i])
} }
emitOpcode(c.prog.BinWriter, opcode.FROMALTSTACK) emit.Opcode(c.prog.BinWriter, opcode.FROMALTSTACK)
emitOpcode(c.prog.BinWriter, opcode.DROP) // Cleanup the stack. emit.Opcode(c.prog.BinWriter, opcode.DROP) // Cleanup the stack.
emitOpcode(c.prog.BinWriter, opcode.RET) emit.Opcode(c.prog.BinWriter, opcode.RET)
return nil return nil
case *ast.IfStmt: case *ast.IfStmt:
@ -328,13 +329,13 @@ func (c *codegen) Visit(node ast.Node) ast.Visitor {
if n.Cond != nil { if n.Cond != nil {
ast.Walk(c, n.Cond) ast.Walk(c, n.Cond)
emitJmp(c.prog.BinWriter, opcode.JMPIFNOT, int16(lElse)) emit.Jmp(c.prog.BinWriter, opcode.JMPIFNOT, int16(lElse))
} }
c.setLabel(lIf) c.setLabel(lIf)
ast.Walk(c, n.Body) ast.Walk(c, n.Body)
if n.Else != nil { if n.Else != nil {
emitJmp(c.prog.BinWriter, opcode.JMP, int16(lElseEnd)) emit.Jmp(c.prog.BinWriter, opcode.JMP, int16(lElseEnd))
} }
c.setLabel(lElse) c.setLabel(lElse)
@ -358,13 +359,13 @@ func (c *codegen) Visit(node ast.Node) ast.Visitor {
if l := len(cc.List); l != 0 { // if not `default` if l := len(cc.List); l != 0 { // if not `default`
for j := range cc.List { for j := range cc.List {
emitOpcode(c.prog.BinWriter, opcode.DUP) emit.Opcode(c.prog.BinWriter, opcode.DUP)
ast.Walk(c, cc.List[j]) ast.Walk(c, cc.List[j])
emitOpcode(c.prog.BinWriter, eqOpcode) emit.Opcode(c.prog.BinWriter, eqOpcode)
if j == l-1 { if j == l-1 {
emitJmp(c.prog.BinWriter, opcode.JMPIFNOT, int16(lEnd)) emit.Jmp(c.prog.BinWriter, opcode.JMPIFNOT, int16(lEnd))
} else { } else {
emitJmp(c.prog.BinWriter, opcode.JMPIF, int16(lStart)) emit.Jmp(c.prog.BinWriter, opcode.JMPIF, int16(lStart))
} }
} }
} }
@ -373,12 +374,12 @@ func (c *codegen) Visit(node ast.Node) ast.Visitor {
for _, stmt := range cc.Body { for _, stmt := range cc.Body {
ast.Walk(c, stmt) ast.Walk(c, stmt)
} }
emitJmp(c.prog.BinWriter, opcode.JMP, int16(switchEnd)) emit.Jmp(c.prog.BinWriter, opcode.JMP, int16(switchEnd))
c.setLabel(lEnd) c.setLabel(lEnd)
} }
c.setLabel(switchEnd) c.setLabel(switchEnd)
emitOpcode(c.prog.BinWriter, opcode.DROP) emit.Opcode(c.prog.BinWriter, opcode.DROP)
return nil return nil
@ -421,8 +422,8 @@ func (c *codegen) Visit(node ast.Node) ast.Visitor {
for i := ln - 1; i >= 0; i-- { for i := ln - 1; i >= 0; i-- {
ast.Walk(c, n.Elts[i]) ast.Walk(c, n.Elts[i])
} }
emitInt(c.prog.BinWriter, int64(ln)) emit.Int(c.prog.BinWriter, int64(ln))
emitOpcode(c.prog.BinWriter, opcode.PACK) emit.Opcode(c.prog.BinWriter, opcode.PACK)
return nil return nil
} }
@ -439,13 +440,13 @@ func (c *codegen) Visit(node ast.Node) ast.Visitor {
switch n.Op { switch n.Op {
case token.LAND: case token.LAND:
ast.Walk(c, n.X) ast.Walk(c, n.X)
emitJmp(c.prog.BinWriter, opcode.JMPIFNOT, int16(len(c.l)-1)) emit.Jmp(c.prog.BinWriter, opcode.JMPIFNOT, int16(len(c.l)-1))
ast.Walk(c, n.Y) ast.Walk(c, n.Y)
return nil return nil
case token.LOR: case token.LOR:
ast.Walk(c, n.X) ast.Walk(c, n.X)
emitJmp(c.prog.BinWriter, opcode.JMPIF, int16(len(c.l)-3)) emit.Jmp(c.prog.BinWriter, opcode.JMPIF, int16(len(c.l)-3))
ast.Walk(c, n.Y) ast.Walk(c, n.Y)
return nil return nil
@ -470,21 +471,21 @@ func (c *codegen) Visit(node ast.Node) ast.Visitor {
case n.Op == token.ADD: case n.Op == token.ADD:
// VM has separate opcodes for number and string concatenation // VM has separate opcodes for number and string concatenation
if isStringType(tinfo.Type) { if isStringType(tinfo.Type) {
emitOpcode(c.prog.BinWriter, opcode.CAT) emit.Opcode(c.prog.BinWriter, opcode.CAT)
} else { } else {
emitOpcode(c.prog.BinWriter, opcode.ADD) emit.Opcode(c.prog.BinWriter, opcode.ADD)
} }
case n.Op == token.EQL: case n.Op == token.EQL:
// VM has separate opcodes for number and string equality // VM has separate opcodes for number and string equality
op := c.getEqualityOpcode(n.X) op := c.getEqualityOpcode(n.X)
emitOpcode(c.prog.BinWriter, op) emit.Opcode(c.prog.BinWriter, op)
case n.Op == token.NEQ: case n.Op == token.NEQ:
// VM has separate opcodes for number and string equality // VM has separate opcodes for number and string equality
if isStringType(c.typeInfo.Types[n.X].Type) { if isStringType(c.typeInfo.Types[n.X].Type) {
emitOpcode(c.prog.BinWriter, opcode.EQUAL) emit.Opcode(c.prog.BinWriter, opcode.EQUAL)
emitOpcode(c.prog.BinWriter, opcode.NOT) emit.Opcode(c.prog.BinWriter, opcode.NOT)
} else { } else {
emitOpcode(c.prog.BinWriter, opcode.NUMNOTEQUAL) emit.Opcode(c.prog.BinWriter, opcode.NUMNOTEQUAL)
} }
default: default:
c.convertToken(n.Op) c.convertToken(n.Op)
@ -540,14 +541,14 @@ func (c *codegen) Visit(node ast.Node) ast.Visitor {
// Do not swap for builtin functions. // Do not swap for builtin functions.
if !isBuiltin { if !isBuiltin {
if numArgs == 2 { if numArgs == 2 {
emitOpcode(c.prog.BinWriter, opcode.SWAP) emit.Opcode(c.prog.BinWriter, opcode.SWAP)
} else if numArgs == 3 { } else if numArgs == 3 {
emitInt(c.prog.BinWriter, 2) emit.Int(c.prog.BinWriter, 2)
emitOpcode(c.prog.BinWriter, opcode.XSWAP) emit.Opcode(c.prog.BinWriter, opcode.XSWAP)
} else { } else {
for i := 1; i < numArgs; i++ { for i := 1; i < numArgs; i++ {
emitInt(c.prog.BinWriter, int64(i)) emit.Int(c.prog.BinWriter, int64(i))
emitOpcode(c.prog.BinWriter, opcode.ROLL) emit.Opcode(c.prog.BinWriter, opcode.ROLL)
} }
} }
} }
@ -561,7 +562,7 @@ func (c *codegen) Visit(node ast.Node) ast.Visitor {
case isSyscall(f): case isSyscall(f):
c.convertSyscall(f.selector.Name, f.name) c.convertSyscall(f.selector.Name, f.name)
default: default:
emitCall(c.prog.BinWriter, opcode.CALL, int16(f.label)) emit.Call(c.prog.BinWriter, opcode.CALL, int16(f.label))
} }
return nil return nil
@ -591,11 +592,11 @@ func (c *codegen) Visit(node ast.Node) ast.Visitor {
case token.ADD: case token.ADD:
// +10 == 10, no need to do anything in this case // +10 == 10, no need to do anything in this case
case token.SUB: case token.SUB:
emitOpcode(c.prog.BinWriter, opcode.NEGATE) emit.Opcode(c.prog.BinWriter, opcode.NEGATE)
case token.NOT: case token.NOT:
emitOpcode(c.prog.BinWriter, opcode.NOT) emit.Opcode(c.prog.BinWriter, opcode.NOT)
case token.XOR: case token.XOR:
emitOpcode(c.prog.BinWriter, opcode.INVERT) emit.Opcode(c.prog.BinWriter, opcode.INVERT)
default: default:
c.prog.Err = fmt.Errorf("invalid unary operator: %s", n.Op) c.prog.Err = fmt.Errorf("invalid unary operator: %s", n.Op)
return nil return nil
@ -634,7 +635,7 @@ func (c *codegen) Visit(node ast.Node) ast.Visitor {
ast.Walk(c, n.Index) ast.Walk(c, n.Index)
} }
emitOpcode(c.prog.BinWriter, opcode.PICKITEM) // just pickitem here emit.Opcode(c.prog.BinWriter, opcode.PICKITEM) // just pickitem here
return nil return nil
@ -654,7 +655,7 @@ func (c *codegen) Visit(node ast.Node) ast.Visitor {
ast.Walk(c, n.Cond) ast.Walk(c, n.Cond)
// Jump if the condition is false // Jump if the condition is false
emitJmp(c.prog.BinWriter, opcode.JMPIFNOT, int16(fend)) emit.Jmp(c.prog.BinWriter, opcode.JMPIFNOT, int16(fend))
// Walk body followed by the iterator (post stmt). // Walk body followed by the iterator (post stmt).
ast.Walk(c, n.Body) ast.Walk(c, n.Body)
@ -663,7 +664,7 @@ func (c *codegen) Visit(node ast.Node) ast.Visitor {
} }
// Jump back to condition. // Jump back to condition.
emitJmp(c.prog.BinWriter, opcode.JMP, int16(fstart)) emit.Jmp(c.prog.BinWriter, opcode.JMP, int16(fstart))
c.setLabel(fend) c.setLabel(fend)
return nil return nil
@ -721,11 +722,11 @@ func (c *codegen) convertSyscall(api, name string) {
c.prog.Err = fmt.Errorf("unknown VM syscall api: %s", name) c.prog.Err = fmt.Errorf("unknown VM syscall api: %s", name)
return return
} }
emitSyscall(c.prog.BinWriter, api) emit.Syscall(c.prog.BinWriter, api)
// This NOP instruction is basically not needed, but if we do, we have a // This NOP instruction is basically not needed, but if we do, we have a
// one to one matching avm file with neo-python which is very nice for debugging. // one to one matching avm file with neo-python which is very nice for debugging.
emitOpcode(c.prog.BinWriter, opcode.NOP) emit.Opcode(c.prog.BinWriter, opcode.NOP)
} }
func (c *codegen) convertBuiltin(expr *ast.CallExpr) { func (c *codegen) convertBuiltin(expr *ast.CallExpr) {
@ -742,44 +743,44 @@ func (c *codegen) convertBuiltin(expr *ast.CallExpr) {
arg := expr.Args[0] arg := expr.Args[0]
typ := c.typeInfo.Types[arg].Type typ := c.typeInfo.Types[arg].Type
if isStringType(typ) { if isStringType(typ) {
emitOpcode(c.prog.BinWriter, opcode.SIZE) emit.Opcode(c.prog.BinWriter, opcode.SIZE)
} else { } else {
emitOpcode(c.prog.BinWriter, opcode.ARRAYSIZE) emit.Opcode(c.prog.BinWriter, opcode.ARRAYSIZE)
} }
case "append": case "append":
arg := expr.Args[0] arg := expr.Args[0]
typ := c.typeInfo.Types[arg].Type typ := c.typeInfo.Types[arg].Type
if isByteArrayType(typ) { if isByteArrayType(typ) {
emitOpcode(c.prog.BinWriter, opcode.CAT) emit.Opcode(c.prog.BinWriter, opcode.CAT)
} else { } else {
emitOpcode(c.prog.BinWriter, opcode.OVER) emit.Opcode(c.prog.BinWriter, opcode.OVER)
emitOpcode(c.prog.BinWriter, opcode.SWAP) emit.Opcode(c.prog.BinWriter, opcode.SWAP)
emitOpcode(c.prog.BinWriter, opcode.APPEND) emit.Opcode(c.prog.BinWriter, opcode.APPEND)
} }
case "panic": case "panic":
arg := expr.Args[0] arg := expr.Args[0]
if isExprNil(arg) { if isExprNil(arg) {
emitOpcode(c.prog.BinWriter, opcode.DROP) emit.Opcode(c.prog.BinWriter, opcode.DROP)
emitOpcode(c.prog.BinWriter, opcode.THROW) emit.Opcode(c.prog.BinWriter, opcode.THROW)
} else if isStringType(c.typeInfo.Types[arg].Type) { } else if isStringType(c.typeInfo.Types[arg].Type) {
ast.Walk(c, arg) ast.Walk(c, arg)
emitSyscall(c.prog.BinWriter, "Neo.Runtime.Log") emit.Syscall(c.prog.BinWriter, "Neo.Runtime.Log")
emitOpcode(c.prog.BinWriter, opcode.THROW) emit.Opcode(c.prog.BinWriter, opcode.THROW)
} else { } else {
c.prog.Err = errors.New("panic should have string or nil argument") c.prog.Err = errors.New("panic should have string or nil argument")
} }
case "SHA256": case "SHA256":
emitOpcode(c.prog.BinWriter, opcode.SHA256) emit.Opcode(c.prog.BinWriter, opcode.SHA256)
case "SHA1": case "SHA1":
emitOpcode(c.prog.BinWriter, opcode.SHA1) emit.Opcode(c.prog.BinWriter, opcode.SHA1)
case "Hash256": case "Hash256":
emitOpcode(c.prog.BinWriter, opcode.HASH256) emit.Opcode(c.prog.BinWriter, opcode.HASH256)
case "Hash160": case "Hash160":
emitOpcode(c.prog.BinWriter, opcode.HASH160) emit.Opcode(c.prog.BinWriter, opcode.HASH160)
case "VerifySignature": case "VerifySignature":
emitOpcode(c.prog.BinWriter, opcode.VERIFY) emit.Opcode(c.prog.BinWriter, opcode.VERIFY)
case "AppCall": case "AppCall":
emitOpcode(c.prog.BinWriter, opcode.APPCALL) emit.Opcode(c.prog.BinWriter, opcode.APPCALL)
buf := c.getByteArray(expr.Args[0]) buf := c.getByteArray(expr.Args[0])
if len(buf) != 20 { if len(buf) != 20 {
c.prog.Err = errors.New("invalid script hash") c.prog.Err = errors.New("invalid script hash")
@ -787,7 +788,7 @@ func (c *codegen) convertBuiltin(expr *ast.CallExpr) {
c.prog.WriteBytes(buf) c.prog.WriteBytes(buf)
case "Equals": case "Equals":
emitOpcode(c.prog.BinWriter, opcode.EQUAL) emit.Opcode(c.prog.BinWriter, opcode.EQUAL)
case "FromAddress": case "FromAddress":
// We can be sure that this is a ast.BasicLit just containing a simple // We can be sure that this is a ast.BasicLit just containing a simple
// address string. Note that the string returned from calling Value will // address string. Note that the string returned from calling Value will
@ -800,7 +801,7 @@ func (c *codegen) convertBuiltin(expr *ast.CallExpr) {
return return
} }
bytes := uint160.BytesBE() bytes := uint160.BytesBE()
emitBytes(c.prog.BinWriter, bytes) emit.Bytes(c.prog.BinWriter, bytes)
} }
} }
@ -835,17 +836,17 @@ func (c *codegen) convertByteArray(lit *ast.CompositeLit) {
val, _ := constant.Int64Val(t.Value) val, _ := constant.Int64Val(t.Value)
buf[i] = byte(val) buf[i] = byte(val)
} }
emitBytes(c.prog.BinWriter, buf) emit.Bytes(c.prog.BinWriter, buf)
} }
func (c *codegen) convertMap(lit *ast.CompositeLit) { func (c *codegen) convertMap(lit *ast.CompositeLit) {
emitOpcode(c.prog.BinWriter, opcode.NEWMAP) emit.Opcode(c.prog.BinWriter, opcode.NEWMAP)
for i := range lit.Elts { for i := range lit.Elts {
elem := lit.Elts[i].(*ast.KeyValueExpr) elem := lit.Elts[i].(*ast.KeyValueExpr)
emitOpcode(c.prog.BinWriter, opcode.DUP) emit.Opcode(c.prog.BinWriter, opcode.DUP)
ast.Walk(c, elem.Key) ast.Walk(c, elem.Key)
ast.Walk(c, elem.Value) ast.Walk(c, elem.Value)
emitOpcode(c.prog.BinWriter, opcode.SETITEM) emit.Opcode(c.prog.BinWriter, opcode.SETITEM)
} }
} }
@ -858,10 +859,10 @@ func (c *codegen) convertStruct(lit *ast.CompositeLit) {
return return
} }
emitOpcode(c.prog.BinWriter, opcode.NOP) emit.Opcode(c.prog.BinWriter, opcode.NOP)
emitInt(c.prog.BinWriter, int64(strct.NumFields())) emit.Int(c.prog.BinWriter, int64(strct.NumFields()))
emitOpcode(c.prog.BinWriter, opcode.NEWSTRUCT) emit.Opcode(c.prog.BinWriter, opcode.NEWSTRUCT)
emitOpcode(c.prog.BinWriter, opcode.TOALTSTACK) emit.Opcode(c.prog.BinWriter, opcode.TOALTSTACK)
// We need to locally store all the fields, even if they are not initialized. // We need to locally store all the fields, even if they are not initialized.
// We will initialize all fields to their "zero" value. // We will initialize all fields to their "zero" value.
@ -894,59 +895,59 @@ func (c *codegen) convertStruct(lit *ast.CompositeLit) {
c.emitLoadConst(typeAndVal) c.emitLoadConst(typeAndVal)
c.emitStoreLocal(i) c.emitStoreLocal(i)
} }
emitOpcode(c.prog.BinWriter, opcode.FROMALTSTACK) emit.Opcode(c.prog.BinWriter, opcode.FROMALTSTACK)
} }
func (c *codegen) convertToken(tok token.Token) { func (c *codegen) convertToken(tok token.Token) {
switch tok { switch tok {
case token.ADD_ASSIGN: case token.ADD_ASSIGN:
emitOpcode(c.prog.BinWriter, opcode.ADD) emit.Opcode(c.prog.BinWriter, opcode.ADD)
case token.SUB_ASSIGN: case token.SUB_ASSIGN:
emitOpcode(c.prog.BinWriter, opcode.SUB) emit.Opcode(c.prog.BinWriter, opcode.SUB)
case token.MUL_ASSIGN: case token.MUL_ASSIGN:
emitOpcode(c.prog.BinWriter, opcode.MUL) emit.Opcode(c.prog.BinWriter, opcode.MUL)
case token.QUO_ASSIGN: case token.QUO_ASSIGN:
emitOpcode(c.prog.BinWriter, opcode.DIV) emit.Opcode(c.prog.BinWriter, opcode.DIV)
case token.REM_ASSIGN: case token.REM_ASSIGN:
emitOpcode(c.prog.BinWriter, opcode.MOD) emit.Opcode(c.prog.BinWriter, opcode.MOD)
case token.ADD: case token.ADD:
emitOpcode(c.prog.BinWriter, opcode.ADD) emit.Opcode(c.prog.BinWriter, opcode.ADD)
case token.SUB: case token.SUB:
emitOpcode(c.prog.BinWriter, opcode.SUB) emit.Opcode(c.prog.BinWriter, opcode.SUB)
case token.MUL: case token.MUL:
emitOpcode(c.prog.BinWriter, opcode.MUL) emit.Opcode(c.prog.BinWriter, opcode.MUL)
case token.QUO: case token.QUO:
emitOpcode(c.prog.BinWriter, opcode.DIV) emit.Opcode(c.prog.BinWriter, opcode.DIV)
case token.REM: case token.REM:
emitOpcode(c.prog.BinWriter, opcode.MOD) emit.Opcode(c.prog.BinWriter, opcode.MOD)
case token.LSS: case token.LSS:
emitOpcode(c.prog.BinWriter, opcode.LT) emit.Opcode(c.prog.BinWriter, opcode.LT)
case token.LEQ: case token.LEQ:
emitOpcode(c.prog.BinWriter, opcode.LTE) emit.Opcode(c.prog.BinWriter, opcode.LTE)
case token.GTR: case token.GTR:
emitOpcode(c.prog.BinWriter, opcode.GT) emit.Opcode(c.prog.BinWriter, opcode.GT)
case token.GEQ: case token.GEQ:
emitOpcode(c.prog.BinWriter, opcode.GTE) emit.Opcode(c.prog.BinWriter, opcode.GTE)
case token.EQL: case token.EQL:
emitOpcode(c.prog.BinWriter, opcode.NUMEQUAL) emit.Opcode(c.prog.BinWriter, opcode.NUMEQUAL)
case token.NEQ: case token.NEQ:
emitOpcode(c.prog.BinWriter, opcode.NUMNOTEQUAL) emit.Opcode(c.prog.BinWriter, opcode.NUMNOTEQUAL)
case token.DEC: case token.DEC:
emitOpcode(c.prog.BinWriter, opcode.DEC) emit.Opcode(c.prog.BinWriter, opcode.DEC)
case token.INC: case token.INC:
emitOpcode(c.prog.BinWriter, opcode.INC) emit.Opcode(c.prog.BinWriter, opcode.INC)
case token.NOT: case token.NOT:
emitOpcode(c.prog.BinWriter, opcode.NOT) emit.Opcode(c.prog.BinWriter, opcode.NOT)
case token.AND: case token.AND:
emitOpcode(c.prog.BinWriter, opcode.AND) emit.Opcode(c.prog.BinWriter, opcode.AND)
case token.OR: case token.OR:
emitOpcode(c.prog.BinWriter, opcode.OR) emit.Opcode(c.prog.BinWriter, opcode.OR)
case token.SHL: case token.SHL:
emitOpcode(c.prog.BinWriter, opcode.SHL) emit.Opcode(c.prog.BinWriter, opcode.SHL)
case token.SHR: case token.SHR:
emitOpcode(c.prog.BinWriter, opcode.SHR) emit.Opcode(c.prog.BinWriter, opcode.SHR)
case token.XOR: case token.XOR:
emitOpcode(c.prog.BinWriter, opcode.XOR) emit.Opcode(c.prog.BinWriter, opcode.XOR)
default: default:
c.prog.Err = fmt.Errorf("compiler could not convert token: %s", tok) c.prog.Err = fmt.Errorf("compiler could not convert token: %s", tok)
return return

View file

@ -1,119 +0,0 @@
package compiler
import (
"encoding/binary"
"errors"
"fmt"
"math/big"
"github.com/CityOfZion/neo-go/pkg/io"
"github.com/CityOfZion/neo-go/pkg/vm"
"github.com/CityOfZion/neo-go/pkg/vm/opcode"
)
// emit a VM Instruction with data to the given buffer.
func emit(w *io.BinWriter, instr opcode.Opcode, b []byte) {
emitOpcode(w, instr)
w.WriteBytes(b)
}
// emitOpcode emits a single VM Instruction the given buffer.
func emitOpcode(w *io.BinWriter, instr opcode.Opcode) {
w.WriteBytes([]byte{byte(instr)})
}
// emitBool emits a bool type the given buffer.
func emitBool(w *io.BinWriter, ok bool) {
if ok {
emitOpcode(w, opcode.PUSHT)
return
}
emitOpcode(w, opcode.PUSHF)
}
// emitInt emits a int type to the given buffer.
func emitInt(w *io.BinWriter, i int64) {
switch {
case i == -1:
emitOpcode(w, opcode.PUSHM1)
return
case i == 0:
emitOpcode(w, opcode.PUSHF)
return
case i > 0 && i < 16:
val := opcode.Opcode(int(opcode.PUSH1) - 1 + int(i))
emitOpcode(w, val)
return
}
bInt := big.NewInt(i)
val := vm.IntToBytes(bInt)
emitBytes(w, val)
}
// emitString emits a string to the given buffer.
func emitString(w *io.BinWriter, s string) {
emitBytes(w, []byte(s))
}
// emitBytes emits a byte array to the given buffer.
func emitBytes(w *io.BinWriter, b []byte) {
n := len(b)
switch {
case n <= int(opcode.PUSHBYTES75):
emit(w, opcode.Opcode(n), b)
return
case n < 0x100:
emit(w, opcode.PUSHDATA1, []byte{byte(n)})
case n < 0x10000:
buf := make([]byte, 2)
binary.LittleEndian.PutUint16(buf, uint16(n))
emit(w, opcode.PUSHDATA2, buf)
default:
buf := make([]byte, 4)
binary.LittleEndian.PutUint32(buf, uint32(n))
emit(w, opcode.PUSHDATA4, buf)
if w.Err != nil {
return
}
}
w.WriteBytes(b)
}
// emitSyscall emits the syscall API to the given buffer.
// Syscall API string cannot be 0.
func emitSyscall(w *io.BinWriter, api string) {
if len(api) == 0 {
w.Err = errors.New("syscall api cannot be of length 0")
return
}
buf := make([]byte, len(api)+1)
buf[0] = byte(len(api))
copy(buf[1:], api)
emit(w, opcode.SYSCALL, buf)
}
// emitCall emits a call Instruction with label to the given buffer.
func emitCall(w *io.BinWriter, instr opcode.Opcode, label int16) {
emitJmp(w, instr, label)
}
// emitJmp emits a jump Instruction along with label to the given buffer.
func emitJmp(w *io.BinWriter, instr opcode.Opcode, label int16) {
if !isInstrJmp(instr) {
w.Err = fmt.Errorf("opcode %s is not a jump or call type", instr)
return
}
buf := make([]byte, 2)
binary.LittleEndian.PutUint16(buf, uint16(label))
emit(w, instr, buf)
}
func isInstrJmp(instr opcode.Opcode) bool {
if instr == opcode.JMP || instr == opcode.JMPIFNOT || instr == opcode.JMPIF || instr == opcode.CALL {
return true
}
return false
}