forked from TrueCloudLab/neoneo-go
Merge pull request #467 from nspcc-dev/errcheck_297
This patchset closes #297 and #457.
This commit is contained in:
commit
f48228ef7d
25 changed files with 278 additions and 225 deletions
|
@ -177,8 +177,7 @@ func dumpDB(ctx *cli.Context) error {
|
||||||
buf := io.NewBufBinWriter()
|
buf := io.NewBufBinWriter()
|
||||||
b.EncodeBinary(buf.BinWriter)
|
b.EncodeBinary(buf.BinWriter)
|
||||||
bytes := buf.Bytes()
|
bytes := buf.Bytes()
|
||||||
writer.WriteLE(uint32(len(bytes)))
|
writer.WriteVarBytes(bytes)
|
||||||
writer.WriteLE(bytes)
|
|
||||||
if writer.Err != nil {
|
if writer.Err != nil {
|
||||||
return cli.NewExitError(err, 1)
|
return cli.NewExitError(err, 1)
|
||||||
}
|
}
|
||||||
|
|
|
@ -330,9 +330,11 @@ func contractCompile(ctx *cli.Context) error {
|
||||||
Debug: ctx.Bool("debug"),
|
Debug: ctx.Bool("debug"),
|
||||||
}
|
}
|
||||||
|
|
||||||
if err := compiler.CompileAndSave(src, o); err != nil {
|
result, err := compiler.CompileAndSave(src, o)
|
||||||
|
if err != nil {
|
||||||
return cli.NewExitError(err, 1)
|
return cli.NewExitError(err, 1)
|
||||||
}
|
}
|
||||||
|
fmt.Println(hex.EncodeToString(result))
|
||||||
|
|
||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
|
|
|
@ -169,7 +169,7 @@ func (p Payload) EncodeBinaryUnsigned(w *io.BinWriter) {
|
||||||
|
|
||||||
ww := io.NewBufBinWriter()
|
ww := io.NewBufBinWriter()
|
||||||
p.message.EncodeBinary(ww.BinWriter)
|
p.message.EncodeBinary(ww.BinWriter)
|
||||||
w.WriteBytes(ww.Bytes())
|
w.WriteVarBytes(ww.Bytes())
|
||||||
}
|
}
|
||||||
|
|
||||||
// EncodeBinary implements io.Serializable interface.
|
// EncodeBinary implements io.Serializable interface.
|
||||||
|
|
|
@ -100,7 +100,7 @@ func (p *changeViewCompact) EncodeBinary(w *io.BinWriter) {
|
||||||
w.WriteLE(p.ValidatorIndex)
|
w.WriteLE(p.ValidatorIndex)
|
||||||
w.WriteLE(p.OriginalViewNumber)
|
w.WriteLE(p.OriginalViewNumber)
|
||||||
w.WriteLE(p.Timestamp)
|
w.WriteLE(p.Timestamp)
|
||||||
w.WriteBytes(p.InvocationScript)
|
w.WriteVarBytes(p.InvocationScript)
|
||||||
}
|
}
|
||||||
|
|
||||||
// DecodeBinary implements io.Serializable interface.
|
// DecodeBinary implements io.Serializable interface.
|
||||||
|
@ -116,7 +116,7 @@ func (p *commitCompact) EncodeBinary(w *io.BinWriter) {
|
||||||
w.WriteLE(p.ViewNumber)
|
w.WriteLE(p.ViewNumber)
|
||||||
w.WriteLE(p.ValidatorIndex)
|
w.WriteLE(p.ValidatorIndex)
|
||||||
w.WriteBE(p.Signature)
|
w.WriteBE(p.Signature)
|
||||||
w.WriteBytes(p.InvocationScript)
|
w.WriteVarBytes(p.InvocationScript)
|
||||||
}
|
}
|
||||||
|
|
||||||
// DecodeBinary implements io.Serializable interface.
|
// DecodeBinary implements io.Serializable interface.
|
||||||
|
@ -128,7 +128,7 @@ func (p *preparationCompact) DecodeBinary(r *io.BinReader) {
|
||||||
// EncodeBinary implements io.Serializable interface.
|
// EncodeBinary implements io.Serializable interface.
|
||||||
func (p *preparationCompact) EncodeBinary(w *io.BinWriter) {
|
func (p *preparationCompact) EncodeBinary(w *io.BinWriter) {
|
||||||
w.WriteLE(p.ValidatorIndex)
|
w.WriteLE(p.ValidatorIndex)
|
||||||
w.WriteBytes(p.InvocationScript)
|
w.WriteVarBytes(p.InvocationScript)
|
||||||
}
|
}
|
||||||
|
|
||||||
// AddPayload implements payload.RecoveryMessage interface.
|
// AddPayload implements payload.RecoveryMessage interface.
|
||||||
|
|
|
@ -1508,7 +1508,7 @@ func (bc *Blockchain) verifyBlockWitnesses(block *Block, prevHeader *Header) err
|
||||||
|
|
||||||
func hashAndIndexToBytes(h util.Uint256, index uint32) []byte {
|
func hashAndIndexToBytes(h util.Uint256, index uint32) []byte {
|
||||||
buf := io.NewBufBinWriter()
|
buf := io.NewBufBinWriter()
|
||||||
buf.WriteLE(h.BytesReverse())
|
buf.WriteBytes(h.BytesReverse())
|
||||||
buf.WriteLE(index)
|
buf.WriteLE(index)
|
||||||
return buf.Bytes()
|
return buf.Bytes()
|
||||||
}
|
}
|
||||||
|
|
|
@ -69,7 +69,7 @@ func (state *BlockChainState) storeAsBlock(block *Block, sysFee uint32) error {
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
buf.WriteLE(b)
|
buf.WriteBytes(b)
|
||||||
if buf.Err != nil {
|
if buf.Err != nil {
|
||||||
return buf.Err
|
return buf.Err
|
||||||
}
|
}
|
||||||
|
@ -79,7 +79,7 @@ func (state *BlockChainState) storeAsBlock(block *Block, sysFee uint32) error {
|
||||||
// storeAsCurrentBlock stores the given block witch prefix SYSCurrentBlock.
|
// storeAsCurrentBlock stores the given block witch prefix SYSCurrentBlock.
|
||||||
func (state *BlockChainState) storeAsCurrentBlock(block *Block) error {
|
func (state *BlockChainState) storeAsCurrentBlock(block *Block) error {
|
||||||
buf := io.NewBufBinWriter()
|
buf := io.NewBufBinWriter()
|
||||||
buf.WriteLE(block.Hash().BytesReverse())
|
buf.WriteBytes(block.Hash().BytesReverse())
|
||||||
buf.WriteLE(block.Index)
|
buf.WriteLE(block.Index)
|
||||||
return state.store.Put(storage.SYSCurrentBlock.Bytes(), buf.Bytes())
|
return state.store.Put(storage.SYSCurrentBlock.Bytes(), buf.Bytes())
|
||||||
}
|
}
|
||||||
|
|
|
@ -52,7 +52,7 @@ func (cs *ContractState) DecodeBinary(br *io.BinReader) {
|
||||||
|
|
||||||
// EncodeBinary implements Serializable interface.
|
// EncodeBinary implements Serializable interface.
|
||||||
func (cs *ContractState) EncodeBinary(bw *io.BinWriter) {
|
func (cs *ContractState) EncodeBinary(bw *io.BinWriter) {
|
||||||
bw.WriteBytes(cs.Script)
|
bw.WriteVarBytes(cs.Script)
|
||||||
bw.WriteArray(cs.ParamList)
|
bw.WriteArray(cs.ParamList)
|
||||||
bw.WriteLE(cs.ReturnType)
|
bw.WriteLE(cs.ReturnType)
|
||||||
bw.WriteLE(cs.Properties)
|
bw.WriteLE(cs.Properties)
|
||||||
|
|
|
@ -53,7 +53,7 @@ func deleteStorageItemInStore(s storage.Store, scripthash util.Uint160, key []by
|
||||||
|
|
||||||
// EncodeBinary implements Serializable interface.
|
// EncodeBinary implements Serializable interface.
|
||||||
func (si *StorageItem) EncodeBinary(w *io.BinWriter) {
|
func (si *StorageItem) EncodeBinary(w *io.BinWriter) {
|
||||||
w.WriteBytes(si.Value)
|
w.WriteVarBytes(si.Value)
|
||||||
w.WriteLE(si.IsConst)
|
w.WriteLE(si.IsConst)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -55,18 +55,18 @@ func (attr *Attribute) EncodeBinary(bw *io.BinWriter) {
|
||||||
bw.WriteLE(&attr.Usage)
|
bw.WriteLE(&attr.Usage)
|
||||||
switch attr.Usage {
|
switch attr.Usage {
|
||||||
case ECDH02, ECDH03:
|
case ECDH02, ECDH03:
|
||||||
bw.WriteLE(attr.Data[1:])
|
bw.WriteBytes(attr.Data[1:])
|
||||||
case Description, Remark, Remark1, Remark2, Remark3, Remark4,
|
case Description, Remark, Remark1, Remark2, Remark3, Remark4,
|
||||||
Remark5, Remark6, Remark7, Remark8, Remark9, Remark10, Remark11,
|
Remark5, Remark6, Remark7, Remark8, Remark9, Remark10, Remark11,
|
||||||
Remark12, Remark13, Remark14, Remark15:
|
Remark12, Remark13, Remark14, Remark15:
|
||||||
bw.WriteBytes(attr.Data)
|
bw.WriteVarBytes(attr.Data)
|
||||||
case DescriptionURL:
|
case DescriptionURL:
|
||||||
var urllen = uint8(len(attr.Data))
|
var urllen = uint8(len(attr.Data))
|
||||||
bw.WriteLE(urllen)
|
bw.WriteLE(urllen)
|
||||||
fallthrough
|
fallthrough
|
||||||
case Script, ContractHash, Vote, Hash1, Hash2, Hash3, Hash4, Hash5, Hash6,
|
case Script, ContractHash, Vote, Hash1, Hash2, Hash3, Hash4, Hash5, Hash6,
|
||||||
Hash7, Hash8, Hash9, Hash10, Hash11, Hash12, Hash13, Hash14, Hash15:
|
Hash7, Hash8, Hash9, Hash10, Hash11, Hash12, Hash13, Hash14, Hash15:
|
||||||
bw.WriteLE(attr.Data)
|
bw.WriteBytes(attr.Data)
|
||||||
default:
|
default:
|
||||||
bw.Err = fmt.Errorf("failed encoding TX attribute usage: 0x%2x", attr.Usage)
|
bw.Err = fmt.Errorf("failed encoding TX attribute usage: 0x%2x", attr.Usage)
|
||||||
}
|
}
|
||||||
|
|
|
@ -45,7 +45,7 @@ func (tx *InvocationTX) DecodeBinary(br *io.BinReader) {
|
||||||
|
|
||||||
// EncodeBinary implements Serializable interface.
|
// EncodeBinary implements Serializable interface.
|
||||||
func (tx *InvocationTX) EncodeBinary(bw *io.BinWriter) {
|
func (tx *InvocationTX) EncodeBinary(bw *io.BinWriter) {
|
||||||
bw.WriteBytes(tx.Script)
|
bw.WriteVarBytes(tx.Script)
|
||||||
if tx.Version >= 1 {
|
if tx.Version >= 1 {
|
||||||
bw.WriteLE(tx.Gas)
|
bw.WriteLE(tx.Gas)
|
||||||
}
|
}
|
||||||
|
|
|
@ -51,7 +51,7 @@ func (tx *PublishTX) DecodeBinary(br *io.BinReader) {
|
||||||
|
|
||||||
// EncodeBinary implements Serializable interface.
|
// EncodeBinary implements Serializable interface.
|
||||||
func (tx *PublishTX) EncodeBinary(bw *io.BinWriter) {
|
func (tx *PublishTX) EncodeBinary(bw *io.BinWriter) {
|
||||||
bw.WriteBytes(tx.Script)
|
bw.WriteVarBytes(tx.Script)
|
||||||
bw.WriteVarUint(uint64(len(tx.ParamList)))
|
bw.WriteVarUint(uint64(len(tx.ParamList)))
|
||||||
for _, param := range tx.ParamList {
|
for _, param := range tx.ParamList {
|
||||||
bw.WriteLE(uint8(param))
|
bw.WriteLE(uint8(param))
|
||||||
|
|
|
@ -49,6 +49,6 @@ func (tx *RegisterTX) EncodeBinary(bw *io.BinWriter) {
|
||||||
bw.WriteString(tx.Name)
|
bw.WriteString(tx.Name)
|
||||||
bw.WriteLE(tx.Amount)
|
bw.WriteLE(tx.Amount)
|
||||||
bw.WriteLE(tx.Precision)
|
bw.WriteLE(tx.Precision)
|
||||||
bw.WriteLE(tx.Owner.Bytes())
|
bw.WriteBytes(tx.Owner.Bytes())
|
||||||
bw.WriteLE(tx.Admin)
|
bw.WriteLE(tx.Admin)
|
||||||
}
|
}
|
||||||
|
|
|
@ -33,7 +33,7 @@ func (s *StateDescriptor) DecodeBinary(r *io.BinReader) {
|
||||||
// EncodeBinary implements Serializable interface.
|
// EncodeBinary implements Serializable interface.
|
||||||
func (s *StateDescriptor) EncodeBinary(w *io.BinWriter) {
|
func (s *StateDescriptor) EncodeBinary(w *io.BinWriter) {
|
||||||
w.WriteLE(s.Type)
|
w.WriteLE(s.Type)
|
||||||
w.WriteBytes(s.Key)
|
w.WriteVarBytes(s.Key)
|
||||||
w.WriteBytes(s.Value)
|
w.WriteVarBytes(s.Value)
|
||||||
w.WriteString(s.Field)
|
w.WriteString(s.Field)
|
||||||
}
|
}
|
||||||
|
|
|
@ -23,8 +23,8 @@ func (w *Witness) DecodeBinary(br *io.BinReader) {
|
||||||
|
|
||||||
// EncodeBinary implements Serializable interface.
|
// EncodeBinary implements Serializable interface.
|
||||||
func (w *Witness) EncodeBinary(bw *io.BinWriter) {
|
func (w *Witness) EncodeBinary(bw *io.BinWriter) {
|
||||||
bw.WriteBytes(w.InvocationScript)
|
bw.WriteVarBytes(w.InvocationScript)
|
||||||
bw.WriteBytes(w.VerificationScript)
|
bw.WriteVarBytes(w.VerificationScript)
|
||||||
}
|
}
|
||||||
|
|
||||||
// MarshalJSON implements the json marshaller interface.
|
// MarshalJSON implements the json marshaller interface.
|
||||||
|
|
|
@ -219,7 +219,7 @@ func (p *PublicKey) DecodeBinary(r *io.BinReader) {
|
||||||
|
|
||||||
// EncodeBinary encodes a PublicKey to the given BinWriter.
|
// EncodeBinary encodes a PublicKey to the given BinWriter.
|
||||||
func (p *PublicKey) EncodeBinary(w *io.BinWriter) {
|
func (p *PublicKey) EncodeBinary(w *io.BinWriter) {
|
||||||
w.WriteLE(p.Bytes())
|
w.WriteBytes(p.Bytes())
|
||||||
}
|
}
|
||||||
|
|
||||||
// Signature returns a NEO-specific hash of the key.
|
// Signature returns a NEO-specific hash of the key.
|
||||||
|
|
|
@ -19,6 +19,11 @@ func NewBufBinWriter() *BufBinWriter {
|
||||||
return &BufBinWriter{BinWriter: NewBinWriterFromIO(b), buf: b}
|
return &BufBinWriter{BinWriter: NewBinWriterFromIO(b), buf: b}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Len returns the number of bytes of the unread portion of the buffer.
|
||||||
|
func (bw *BufBinWriter) Len() int {
|
||||||
|
return bw.buf.Len()
|
||||||
|
}
|
||||||
|
|
||||||
// Bytes returns resulting buffer and makes future writes return an error.
|
// Bytes returns resulting buffer and makes future writes return an error.
|
||||||
func (bw *BufBinWriter) Bytes() []byte {
|
func (bw *BufBinWriter) Bytes() []byte {
|
||||||
if bw.Err != nil {
|
if bw.Err != nil {
|
||||||
|
|
|
@ -93,13 +93,18 @@ func (w *BinWriter) WriteVarUint(val uint64) {
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// WriteBytes writes a variable length byte array into the underlying io.Writer.
|
// WriteBytes writes a variable byte into the underlying io.Writer without prefix.
|
||||||
func (w *BinWriter) WriteBytes(b []byte) {
|
func (w *BinWriter) WriteBytes(b []byte) {
|
||||||
|
w.WriteLE(b)
|
||||||
|
}
|
||||||
|
|
||||||
|
// WriteVarBytes writes a variable length byte array into the underlying io.Writer.
|
||||||
|
func (w *BinWriter) WriteVarBytes(b []byte) {
|
||||||
w.WriteVarUint(uint64(len(b)))
|
w.WriteVarUint(uint64(len(b)))
|
||||||
w.WriteLE(b)
|
w.WriteLE(b)
|
||||||
}
|
}
|
||||||
|
|
||||||
// WriteString writes a variable length string into the underlying io.Writer.
|
// WriteString writes a variable length string into the underlying io.Writer.
|
||||||
func (w *BinWriter) WriteString(s string) {
|
func (w *BinWriter) WriteString(s string) {
|
||||||
w.WriteBytes([]byte(s))
|
w.WriteVarBytes([]byte(s))
|
||||||
}
|
}
|
||||||
|
|
|
@ -53,6 +53,13 @@ func TestWriteBE(t *testing.T) {
|
||||||
assert.Equal(t, val, readval)
|
assert.Equal(t, val, readval)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func TestBufBinWriter_Len(t *testing.T) {
|
||||||
|
val := []byte{0xde}
|
||||||
|
bw := NewBufBinWriter()
|
||||||
|
bw.WriteLE(val)
|
||||||
|
require.Equal(t, 1, bw.Len())
|
||||||
|
}
|
||||||
|
|
||||||
func TestWriterErrHandling(t *testing.T) {
|
func TestWriterErrHandling(t *testing.T) {
|
||||||
var badio = &badRW{}
|
var badio = &badRW{}
|
||||||
bw := NewBinWriterFromIO(badio)
|
bw := NewBinWriterFromIO(badio)
|
||||||
|
@ -62,7 +69,7 @@ func TestWriterErrHandling(t *testing.T) {
|
||||||
bw.WriteLE(uint32(0))
|
bw.WriteLE(uint32(0))
|
||||||
bw.WriteBE(uint32(0))
|
bw.WriteBE(uint32(0))
|
||||||
bw.WriteVarUint(0)
|
bw.WriteVarUint(0)
|
||||||
bw.WriteBytes([]byte{0x55, 0xaa})
|
bw.WriteVarBytes([]byte{0x55, 0xaa})
|
||||||
bw.WriteString("neo")
|
bw.WriteString("neo")
|
||||||
assert.NotNil(t, bw.Err)
|
assert.NotNil(t, bw.Err)
|
||||||
}
|
}
|
||||||
|
|
|
@ -31,5 +31,5 @@ func (m *MerkleBlock) EncodeBinary(bw *io.BinWriter) {
|
||||||
|
|
||||||
bw.WriteVarUint(uint64(m.TxCount))
|
bw.WriteVarUint(uint64(m.TxCount))
|
||||||
bw.WriteArray(m.Hashes)
|
bw.WriteArray(m.Hashes)
|
||||||
bw.WriteBytes(m.Flags)
|
bw.WriteVarBytes(m.Flags)
|
||||||
}
|
}
|
||||||
|
|
|
@ -73,7 +73,7 @@ func (p *Version) EncodeBinary(br *io.BinWriter) {
|
||||||
br.WriteLE(p.Port)
|
br.WriteLE(p.Port)
|
||||||
br.WriteLE(p.Nonce)
|
br.WriteLE(p.Nonce)
|
||||||
|
|
||||||
br.WriteBytes(p.UserAgent)
|
br.WriteVarBytes(p.UserAgent)
|
||||||
br.WriteLE(p.StartHeight)
|
br.WriteLE(p.StartHeight)
|
||||||
br.WriteLE(&p.Relay)
|
br.WriteLE(&p.Relay)
|
||||||
}
|
}
|
||||||
|
|
|
@ -1,10 +1,10 @@
|
||||||
package compiler
|
package compiler
|
||||||
|
|
||||||
import (
|
import (
|
||||||
|
"fmt"
|
||||||
"go/ast"
|
"go/ast"
|
||||||
"go/constant"
|
"go/constant"
|
||||||
"go/types"
|
"go/types"
|
||||||
"log"
|
|
||||||
|
|
||||||
"golang.org/x/tools/go/loader"
|
"golang.org/x/tools/go/loader"
|
||||||
)
|
)
|
||||||
|
@ -19,7 +19,7 @@ var (
|
||||||
)
|
)
|
||||||
|
|
||||||
// typeAndValueForField returns a zero initialized typeAndValue for the given type.Var.
|
// typeAndValueForField returns a zero initialized typeAndValue for the given type.Var.
|
||||||
func typeAndValueForField(fld *types.Var) types.TypeAndValue {
|
func typeAndValueForField(fld *types.Var) (types.TypeAndValue, error) {
|
||||||
switch t := fld.Type().(type) {
|
switch t := fld.Type().(type) {
|
||||||
case *types.Basic:
|
case *types.Basic:
|
||||||
switch t.Kind() {
|
switch t.Kind() {
|
||||||
|
@ -27,22 +27,22 @@ func typeAndValueForField(fld *types.Var) types.TypeAndValue {
|
||||||
return types.TypeAndValue{
|
return types.TypeAndValue{
|
||||||
Type: t,
|
Type: t,
|
||||||
Value: constant.MakeInt64(0),
|
Value: constant.MakeInt64(0),
|
||||||
}
|
}, nil
|
||||||
case types.String:
|
case types.String:
|
||||||
return types.TypeAndValue{
|
return types.TypeAndValue{
|
||||||
Type: t,
|
Type: t,
|
||||||
Value: constant.MakeString(""),
|
Value: constant.MakeString(""),
|
||||||
}
|
}, nil
|
||||||
case types.Bool, types.UntypedBool:
|
case types.Bool, types.UntypedBool:
|
||||||
return types.TypeAndValue{
|
return types.TypeAndValue{
|
||||||
Type: t,
|
Type: t,
|
||||||
Value: constant.MakeBool(false),
|
Value: constant.MakeBool(false),
|
||||||
}
|
}, nil
|
||||||
default:
|
default:
|
||||||
log.Fatalf("could not initialize struct field %s to zero, type: %s", fld.Name(), t)
|
return types.TypeAndValue{}, fmt.Errorf("could not initialize struct field %s to zero, type: %s", fld.Name(), t)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
return types.TypeAndValue{}
|
return types.TypeAndValue{}, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
// countGlobals counts the global variables in the program to add
|
// countGlobals counts the global variables in the program to add
|
||||||
|
@ -69,7 +69,7 @@ func isIdentBool(ident *ast.Ident) bool {
|
||||||
}
|
}
|
||||||
|
|
||||||
// makeBoolFromIdent creates a bool type from an *ast.Ident.
|
// makeBoolFromIdent creates a bool type from an *ast.Ident.
|
||||||
func makeBoolFromIdent(ident *ast.Ident, tinfo *types.Info) types.TypeAndValue {
|
func makeBoolFromIdent(ident *ast.Ident, tinfo *types.Info) (types.TypeAndValue, error) {
|
||||||
var b bool
|
var b bool
|
||||||
switch ident.Name {
|
switch ident.Name {
|
||||||
case "true":
|
case "true":
|
||||||
|
@ -77,12 +77,12 @@ func makeBoolFromIdent(ident *ast.Ident, tinfo *types.Info) types.TypeAndValue {
|
||||||
case "false":
|
case "false":
|
||||||
b = false
|
b = false
|
||||||
default:
|
default:
|
||||||
log.Fatalf("givent identifier cannot be converted to a boolean => %s", ident.Name)
|
return types.TypeAndValue{}, fmt.Errorf("givent identifier cannot be converted to a boolean => %s", ident.Name)
|
||||||
}
|
}
|
||||||
return types.TypeAndValue{
|
return types.TypeAndValue{
|
||||||
Type: tinfo.ObjectOf(ident).Type(),
|
Type: tinfo.ObjectOf(ident).Type(),
|
||||||
Value: constant.MakeBool(b),
|
Value: constant.MakeBool(b),
|
||||||
}
|
}, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
// resolveEntryPoint returns the function declaration of the entrypoint and the corresponding file.
|
// resolveEntryPoint returns the function declaration of the entrypoint and the corresponding file.
|
||||||
|
|
|
@ -1,18 +1,18 @@
|
||||||
package compiler
|
package compiler
|
||||||
|
|
||||||
import (
|
import (
|
||||||
"bytes"
|
|
||||||
"encoding/binary"
|
"encoding/binary"
|
||||||
|
"fmt"
|
||||||
"go/ast"
|
"go/ast"
|
||||||
"go/constant"
|
"go/constant"
|
||||||
"go/token"
|
"go/token"
|
||||||
"go/types"
|
"go/types"
|
||||||
"log"
|
|
||||||
"sort"
|
"sort"
|
||||||
"strconv"
|
"strconv"
|
||||||
"strings"
|
"strings"
|
||||||
|
|
||||||
"github.com/CityOfZion/neo-go/pkg/crypto"
|
"github.com/CityOfZion/neo-go/pkg/crypto"
|
||||||
|
"github.com/CityOfZion/neo-go/pkg/io"
|
||||||
"github.com/CityOfZion/neo-go/pkg/vm"
|
"github.com/CityOfZion/neo-go/pkg/vm"
|
||||||
)
|
)
|
||||||
|
|
||||||
|
@ -24,7 +24,7 @@ type codegen struct {
|
||||||
buildInfo *buildInfo
|
buildInfo *buildInfo
|
||||||
|
|
||||||
// prog holds the output buffer.
|
// prog holds the output buffer.
|
||||||
prog *bytes.Buffer
|
prog *io.BufBinWriter
|
||||||
|
|
||||||
// Type information.
|
// Type information.
|
||||||
typeInfo *types.Info
|
typeInfo *types.Info
|
||||||
|
@ -56,66 +56,73 @@ func (c *codegen) pc() int {
|
||||||
}
|
}
|
||||||
|
|
||||||
func (c *codegen) emitLoadConst(t types.TypeAndValue) {
|
func (c *codegen) emitLoadConst(t types.TypeAndValue) {
|
||||||
|
if c.prog.Err != nil {
|
||||||
|
return
|
||||||
|
}
|
||||||
switch typ := t.Type.Underlying().(type) {
|
switch typ := t.Type.Underlying().(type) {
|
||||||
case *types.Basic:
|
case *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, val)
|
emitInt(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, val)
|
emitString(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, val)
|
emitBool(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, []byte{b})
|
emitBytes(c.prog.BinWriter, []byte{b})
|
||||||
default:
|
default:
|
||||||
log.Fatalf("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
|
||||||
}
|
}
|
||||||
default:
|
default:
|
||||||
log.Fatalf("compiler doesn't know how to convert this constant: %v", t)
|
c.prog.Err = fmt.Errorf("compiler doesn't know how to convert this constant: %v", t)
|
||||||
|
return
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
func (c *codegen) emitLoadLocal(name string) {
|
func (c *codegen) emitLoadLocal(name string) {
|
||||||
pos := c.scope.loadLocal(name)
|
pos := c.scope.loadLocal(name)
|
||||||
if pos < 0 {
|
if pos < 0 {
|
||||||
log.Fatalf("cannot load local variable with position: %d", pos)
|
c.prog.Err = fmt.Errorf("cannot load local variable with position: %d", pos)
|
||||||
|
return
|
||||||
}
|
}
|
||||||
c.emitLoadLocalPos(pos)
|
c.emitLoadLocalPos(pos)
|
||||||
}
|
}
|
||||||
|
|
||||||
func (c *codegen) emitLoadLocalPos(pos int) {
|
func (c *codegen) emitLoadLocalPos(pos int) {
|
||||||
emitOpcode(c.prog, vm.DUPFROMALTSTACK)
|
emitOpcode(c.prog.BinWriter, vm.DUPFROMALTSTACK)
|
||||||
emitInt(c.prog, int64(pos))
|
emitInt(c.prog.BinWriter, int64(pos))
|
||||||
emitOpcode(c.prog, vm.PICKITEM)
|
emitOpcode(c.prog.BinWriter, vm.PICKITEM)
|
||||||
}
|
}
|
||||||
|
|
||||||
func (c *codegen) emitStoreLocal(pos int) {
|
func (c *codegen) emitStoreLocal(pos int) {
|
||||||
emitOpcode(c.prog, vm.DUPFROMALTSTACK)
|
emitOpcode(c.prog.BinWriter, vm.DUPFROMALTSTACK)
|
||||||
|
|
||||||
if pos < 0 {
|
if pos < 0 {
|
||||||
log.Fatalf("invalid position to store local: %d", pos)
|
c.prog.Err = fmt.Errorf("invalid position to store local: %d", pos)
|
||||||
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
emitInt(c.prog, int64(pos))
|
emitInt(c.prog.BinWriter, int64(pos))
|
||||||
emitInt(c.prog, 2)
|
emitInt(c.prog.BinWriter, 2)
|
||||||
emitOpcode(c.prog, vm.ROLL)
|
emitOpcode(c.prog.BinWriter, vm.ROLL)
|
||||||
emitOpcode(c.prog, vm.SETITEM)
|
emitOpcode(c.prog.BinWriter, vm.SETITEM)
|
||||||
}
|
}
|
||||||
|
|
||||||
func (c *codegen) emitLoadField(i int) {
|
func (c *codegen) emitLoadField(i int) {
|
||||||
emitInt(c.prog, int64(i))
|
emitInt(c.prog.BinWriter, int64(i))
|
||||||
emitOpcode(c.prog, vm.PICKITEM)
|
emitOpcode(c.prog.BinWriter, vm.PICKITEM)
|
||||||
}
|
}
|
||||||
|
|
||||||
func (c *codegen) emitStoreStructField(i int) {
|
func (c *codegen) emitStoreStructField(i int) {
|
||||||
emitInt(c.prog, int64(i))
|
emitInt(c.prog.BinWriter, int64(i))
|
||||||
emitOpcode(c.prog, vm.ROT)
|
emitOpcode(c.prog.BinWriter, vm.ROT)
|
||||||
emitOpcode(c.prog, vm.SETITEM)
|
emitOpcode(c.prog.BinWriter, vm.SETITEM)
|
||||||
}
|
}
|
||||||
|
|
||||||
// convertGlobals traverses the AST and only converts global declarations.
|
// convertGlobals traverses the AST and only converts global declarations.
|
||||||
|
@ -155,9 +162,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, f.stackSize()+countGlobals(file))
|
emitInt(c.prog.BinWriter, f.stackSize()+countGlobals(file))
|
||||||
emitOpcode(c.prog, vm.NEWARRAY)
|
emitOpcode(c.prog.BinWriter, vm.NEWARRAY)
|
||||||
emitOpcode(c.prog, vm.TOALTSTACK)
|
emitOpcode(c.prog.BinWriter, vm.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.
|
||||||
|
@ -171,7 +178,8 @@ func (c *codegen) convertFuncDecl(file ast.Node, decl *ast.FuncDecl) {
|
||||||
// Currently only method receives for struct types is supported.
|
// Currently only method receives for struct types is supported.
|
||||||
_, ok := c.typeInfo.Defs[ident].Type().Underlying().(*types.Struct)
|
_, ok := c.typeInfo.Defs[ident].Type().Underlying().(*types.Struct)
|
||||||
if !ok {
|
if !ok {
|
||||||
log.Fatal("method receives for non-struct types is not yet supported")
|
c.prog.Err = fmt.Errorf("method receives for non-struct types is not yet supported")
|
||||||
|
return
|
||||||
}
|
}
|
||||||
l := c.scope.newLocal(ident.Name)
|
l := c.scope.newLocal(ident.Name)
|
||||||
c.emitStoreLocal(l)
|
c.emitStoreLocal(l)
|
||||||
|
@ -194,13 +202,16 @@ 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, vm.FROMALTSTACK)
|
emitOpcode(c.prog.BinWriter, vm.FROMALTSTACK)
|
||||||
emitOpcode(c.prog, vm.DROP)
|
emitOpcode(c.prog.BinWriter, vm.DROP)
|
||||||
emitOpcode(c.prog, vm.RET)
|
emitOpcode(c.prog.BinWriter, vm.RET)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
func (c *codegen) Visit(node ast.Node) ast.Visitor {
|
func (c *codegen) Visit(node ast.Node) ast.Visitor {
|
||||||
|
if c.prog.Err != nil {
|
||||||
|
return nil
|
||||||
|
}
|
||||||
switch n := node.(type) {
|
switch n := node.(type) {
|
||||||
|
|
||||||
// General declarations.
|
// General declarations.
|
||||||
|
@ -248,7 +259,8 @@ func (c *codegen) Visit(node ast.Node) ast.Visitor {
|
||||||
c.emitStoreStructField(i) // store the field
|
c.emitStoreStructField(i) // store the field
|
||||||
}
|
}
|
||||||
default:
|
default:
|
||||||
log.Fatal("nested selector assigns not supported yet")
|
c.prog.Err = fmt.Errorf("nested selector assigns not supported yet")
|
||||||
|
return nil
|
||||||
}
|
}
|
||||||
|
|
||||||
// Assignments to index expressions.
|
// Assignments to index expressions.
|
||||||
|
@ -262,7 +274,8 @@ func (c *codegen) Visit(node ast.Node) ast.Visitor {
|
||||||
indexStr := t.Index.(*ast.BasicLit).Value
|
indexStr := t.Index.(*ast.BasicLit).Value
|
||||||
index, err := strconv.Atoi(indexStr)
|
index, err := strconv.Atoi(indexStr)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
log.Fatal("failed to convert slice index to integer")
|
c.prog.Err = fmt.Errorf("failed to convert slice index to integer")
|
||||||
|
return nil
|
||||||
}
|
}
|
||||||
c.emitStoreStructField(index)
|
c.emitStoreStructField(index)
|
||||||
}
|
}
|
||||||
|
@ -271,7 +284,8 @@ func (c *codegen) Visit(node ast.Node) ast.Visitor {
|
||||||
|
|
||||||
case *ast.ReturnStmt:
|
case *ast.ReturnStmt:
|
||||||
if len(n.Results) > 1 {
|
if len(n.Results) > 1 {
|
||||||
log.Fatal("multiple returns not supported.")
|
c.prog.Err = fmt.Errorf("multiple returns not supported")
|
||||||
|
return nil
|
||||||
}
|
}
|
||||||
|
|
||||||
l := c.newLabel()
|
l := c.newLabel()
|
||||||
|
@ -281,9 +295,9 @@ func (c *codegen) Visit(node ast.Node) ast.Visitor {
|
||||||
ast.Walk(c, n.Results[0])
|
ast.Walk(c, n.Results[0])
|
||||||
}
|
}
|
||||||
|
|
||||||
emitOpcode(c.prog, vm.FROMALTSTACK)
|
emitOpcode(c.prog.BinWriter, vm.FROMALTSTACK)
|
||||||
emitOpcode(c.prog, vm.DROP) // Cleanup the stack.
|
emitOpcode(c.prog.BinWriter, vm.DROP) // Cleanup the stack.
|
||||||
emitOpcode(c.prog, vm.RET)
|
emitOpcode(c.prog.BinWriter, vm.RET)
|
||||||
return nil
|
return nil
|
||||||
|
|
||||||
case *ast.IfStmt:
|
case *ast.IfStmt:
|
||||||
|
@ -293,13 +307,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, vm.JMPIFNOT, int16(lElse))
|
emitJmp(c.prog.BinWriter, vm.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, vm.JMP, int16(lElseEnd))
|
emitJmp(c.prog.BinWriter, vm.JMP, int16(lElseEnd))
|
||||||
}
|
}
|
||||||
|
|
||||||
c.setLabel(lElse)
|
c.setLabel(lElse)
|
||||||
|
@ -315,7 +329,12 @@ func (c *codegen) Visit(node ast.Node) ast.Visitor {
|
||||||
|
|
||||||
case *ast.Ident:
|
case *ast.Ident:
|
||||||
if isIdentBool(n) {
|
if isIdentBool(n) {
|
||||||
c.emitLoadConst(makeBoolFromIdent(n, c.typeInfo))
|
value, err := makeBoolFromIdent(n, c.typeInfo)
|
||||||
|
if err != nil {
|
||||||
|
c.prog.Err = err
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
c.emitLoadConst(value)
|
||||||
} else {
|
} else {
|
||||||
c.emitLoadLocal(n.Name)
|
c.emitLoadLocal(n.Name)
|
||||||
}
|
}
|
||||||
|
@ -339,8 +358,8 @@ func (c *codegen) Visit(node ast.Node) ast.Visitor {
|
||||||
for i := ln - 1; i >= 0; i-- {
|
for i := ln - 1; i >= 0; i-- {
|
||||||
c.emitLoadConst(c.typeInfo.Types[n.Elts[i]])
|
c.emitLoadConst(c.typeInfo.Types[n.Elts[i]])
|
||||||
}
|
}
|
||||||
emitInt(c.prog, int64(ln))
|
emitInt(c.prog.BinWriter, int64(ln))
|
||||||
emitOpcode(c.prog, vm.PACK)
|
emitOpcode(c.prog.BinWriter, vm.PACK)
|
||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -355,13 +374,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, vm.JMPIFNOT, int16(len(c.l)-1))
|
emitJmp(c.prog.BinWriter, vm.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, vm.JMPIF, int16(len(c.l)-3))
|
emitJmp(c.prog.BinWriter, vm.JMPIF, int16(len(c.l)-3))
|
||||||
ast.Walk(c, n.Y)
|
ast.Walk(c, n.Y)
|
||||||
return nil
|
return nil
|
||||||
|
|
||||||
|
@ -386,24 +405,24 @@ 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, vm.CAT)
|
emitOpcode(c.prog.BinWriter, vm.CAT)
|
||||||
} else {
|
} else {
|
||||||
emitOpcode(c.prog, vm.ADD)
|
emitOpcode(c.prog.BinWriter, vm.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
|
||||||
if isStringType(c.typeInfo.Types[n.X].Type) {
|
if isStringType(c.typeInfo.Types[n.X].Type) {
|
||||||
emitOpcode(c.prog, vm.EQUAL)
|
emitOpcode(c.prog.BinWriter, vm.EQUAL)
|
||||||
} else {
|
} else {
|
||||||
emitOpcode(c.prog, vm.NUMEQUAL)
|
emitOpcode(c.prog.BinWriter, vm.NUMEQUAL)
|
||||||
}
|
}
|
||||||
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, vm.EQUAL)
|
emitOpcode(c.prog.BinWriter, vm.EQUAL)
|
||||||
emitOpcode(c.prog, vm.NOT)
|
emitOpcode(c.prog.BinWriter, vm.NOT)
|
||||||
} else {
|
} else {
|
||||||
emitOpcode(c.prog, vm.NUMNOTEQUAL)
|
emitOpcode(c.prog.BinWriter, vm.NUMNOTEQUAL)
|
||||||
}
|
}
|
||||||
default:
|
default:
|
||||||
c.convertToken(n.Op)
|
c.convertToken(n.Op)
|
||||||
|
@ -423,7 +442,8 @@ func (c *codegen) Visit(node ast.Node) ast.Visitor {
|
||||||
case *ast.Ident:
|
case *ast.Ident:
|
||||||
f, ok = c.funcs[fun.Name]
|
f, ok = c.funcs[fun.Name]
|
||||||
if !ok && !isBuiltin {
|
if !ok && !isBuiltin {
|
||||||
log.Fatalf("could not resolve function %s", fun.Name)
|
c.prog.Err = fmt.Errorf("could not resolve function %s", fun.Name)
|
||||||
|
return nil
|
||||||
}
|
}
|
||||||
case *ast.SelectorExpr:
|
case *ast.SelectorExpr:
|
||||||
// If this is a method call we need to walk the AST to load the struct locally.
|
// If this is a method call we need to walk the AST to load the struct locally.
|
||||||
|
@ -439,7 +459,8 @@ func (c *codegen) Visit(node ast.Node) ast.Visitor {
|
||||||
// @FIXME this could cause runtime errors.
|
// @FIXME this could cause runtime errors.
|
||||||
f.selector = fun.X.(*ast.Ident)
|
f.selector = fun.X.(*ast.Ident)
|
||||||
if !ok {
|
if !ok {
|
||||||
log.Fatalf("could not resolve function %s", fun.Sel.Name)
|
c.prog.Err = fmt.Errorf("could not resolve function %s", fun.Sel.Name)
|
||||||
|
return nil
|
||||||
}
|
}
|
||||||
case *ast.ArrayType:
|
case *ast.ArrayType:
|
||||||
// For now we will assume that there is only 1 argument passed which
|
// For now we will assume that there is only 1 argument passed which
|
||||||
|
@ -457,14 +478,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, vm.SWAP)
|
emitOpcode(c.prog.BinWriter, vm.SWAP)
|
||||||
} else if numArgs == 3 {
|
} else if numArgs == 3 {
|
||||||
emitInt(c.prog, 2)
|
emitInt(c.prog.BinWriter, 2)
|
||||||
emitOpcode(c.prog, vm.XSWAP)
|
emitOpcode(c.prog.BinWriter, vm.XSWAP)
|
||||||
} else {
|
} else {
|
||||||
for i := 1; i < numArgs; i++ {
|
for i := 1; i < numArgs; i++ {
|
||||||
emitInt(c.prog, int64(i))
|
emitInt(c.prog.BinWriter, int64(i))
|
||||||
emitOpcode(c.prog, vm.ROLL)
|
emitOpcode(c.prog.BinWriter, vm.ROLL)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -478,7 +499,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, vm.CALL, int16(f.label))
|
emitCall(c.prog.BinWriter, vm.CALL, int16(f.label))
|
||||||
}
|
}
|
||||||
|
|
||||||
return nil
|
return nil
|
||||||
|
@ -493,7 +514,8 @@ func (c *codegen) Visit(node ast.Node) ast.Visitor {
|
||||||
c.emitLoadField(i) // load the field
|
c.emitLoadField(i) // load the field
|
||||||
}
|
}
|
||||||
default:
|
default:
|
||||||
log.Fatal("nested selectors not supported yet")
|
c.prog.Err = fmt.Errorf("nested selectors not supported yet")
|
||||||
|
return nil
|
||||||
}
|
}
|
||||||
return nil
|
return nil
|
||||||
|
|
||||||
|
@ -507,13 +529,14 @@ 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, vm.NEGATE)
|
emitOpcode(c.prog.BinWriter, vm.NEGATE)
|
||||||
case token.NOT:
|
case token.NOT:
|
||||||
emitOpcode(c.prog, vm.NOT)
|
emitOpcode(c.prog.BinWriter, vm.NOT)
|
||||||
case token.XOR:
|
case token.XOR:
|
||||||
emitOpcode(c.prog, vm.INVERT)
|
emitOpcode(c.prog.BinWriter, vm.INVERT)
|
||||||
default:
|
default:
|
||||||
log.Fatalf("invalid unary operator: %s", n.Op)
|
c.prog.Err = fmt.Errorf("invalid unary operator: %s", n.Op)
|
||||||
|
return nil
|
||||||
}
|
}
|
||||||
return nil
|
return nil
|
||||||
|
|
||||||
|
@ -542,7 +565,7 @@ func (c *codegen) Visit(node ast.Node) ast.Visitor {
|
||||||
c.emitLoadField(int(val))
|
c.emitLoadField(int(val))
|
||||||
default:
|
default:
|
||||||
ast.Walk(c, n.Index)
|
ast.Walk(c, n.Index)
|
||||||
emitOpcode(c.prog, vm.PICKITEM) // just pickitem here
|
emitOpcode(c.prog.BinWriter, vm.PICKITEM) // just pickitem here
|
||||||
}
|
}
|
||||||
return nil
|
return nil
|
||||||
|
|
||||||
|
@ -560,14 +583,14 @@ 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, vm.JMPIFNOT, int16(fend))
|
emitJmp(c.prog.BinWriter, vm.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)
|
||||||
ast.Walk(c, n.Post)
|
ast.Walk(c, n.Post)
|
||||||
|
|
||||||
// Jump back to condition.
|
// Jump back to condition.
|
||||||
emitJmp(c.prog, vm.JMP, int16(fstart))
|
emitJmp(c.prog.BinWriter, vm.JMP, int16(fstart))
|
||||||
c.setLabel(fend)
|
c.setLabel(fend)
|
||||||
|
|
||||||
return nil
|
return nil
|
||||||
|
@ -586,13 +609,14 @@ func (c *codegen) Visit(node ast.Node) ast.Visitor {
|
||||||
func (c *codegen) convertSyscall(api, name string) {
|
func (c *codegen) convertSyscall(api, name string) {
|
||||||
api, ok := syscalls[api][name]
|
api, ok := syscalls[api][name]
|
||||||
if !ok {
|
if !ok {
|
||||||
log.Fatalf("unknown VM syscall api: %s", name)
|
c.prog.Err = fmt.Errorf("unknown VM syscall api: %s", name)
|
||||||
|
return
|
||||||
}
|
}
|
||||||
emitSyscall(c.prog, api)
|
emitSyscall(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, vm.NOP)
|
emitOpcode(c.prog.BinWriter, vm.NOP)
|
||||||
}
|
}
|
||||||
|
|
||||||
func (c *codegen) convertBuiltin(expr *ast.CallExpr) {
|
func (c *codegen) convertBuiltin(expr *ast.CallExpr) {
|
||||||
|
@ -609,32 +633,32 @@ 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, vm.SIZE)
|
emitOpcode(c.prog.BinWriter, vm.SIZE)
|
||||||
} else {
|
} else {
|
||||||
emitOpcode(c.prog, vm.ARRAYSIZE)
|
emitOpcode(c.prog.BinWriter, vm.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, vm.CAT)
|
emitOpcode(c.prog.BinWriter, vm.CAT)
|
||||||
} else {
|
} else {
|
||||||
emitOpcode(c.prog, vm.SWAP)
|
emitOpcode(c.prog.BinWriter, vm.SWAP)
|
||||||
emitOpcode(c.prog, vm.DUP)
|
emitOpcode(c.prog.BinWriter, vm.DUP)
|
||||||
emitOpcode(c.prog, vm.PUSH2)
|
emitOpcode(c.prog.BinWriter, vm.PUSH2)
|
||||||
emitOpcode(c.prog, vm.XSWAP)
|
emitOpcode(c.prog.BinWriter, vm.XSWAP)
|
||||||
emitOpcode(c.prog, vm.APPEND)
|
emitOpcode(c.prog.BinWriter, vm.APPEND)
|
||||||
}
|
}
|
||||||
case "SHA256":
|
case "SHA256":
|
||||||
emitOpcode(c.prog, vm.SHA256)
|
emitOpcode(c.prog.BinWriter, vm.SHA256)
|
||||||
case "SHA1":
|
case "SHA1":
|
||||||
emitOpcode(c.prog, vm.SHA1)
|
emitOpcode(c.prog.BinWriter, vm.SHA1)
|
||||||
case "Hash256":
|
case "Hash256":
|
||||||
emitOpcode(c.prog, vm.HASH256)
|
emitOpcode(c.prog.BinWriter, vm.HASH256)
|
||||||
case "Hash160":
|
case "Hash160":
|
||||||
emitOpcode(c.prog, vm.HASH160)
|
emitOpcode(c.prog.BinWriter, vm.HASH160)
|
||||||
case "Equals":
|
case "Equals":
|
||||||
emitOpcode(c.prog, vm.EQUAL)
|
emitOpcode(c.prog.BinWriter, vm.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
|
||||||
|
@ -643,10 +667,11 @@ func (c *codegen) convertBuiltin(expr *ast.CallExpr) {
|
||||||
addressStr = strings.Replace(addressStr, "\"", "", 2)
|
addressStr = strings.Replace(addressStr, "\"", "", 2)
|
||||||
uint160, err := crypto.Uint160DecodeAddress(addressStr)
|
uint160, err := crypto.Uint160DecodeAddress(addressStr)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
log.Fatal(err)
|
c.prog.Err = err
|
||||||
|
return
|
||||||
}
|
}
|
||||||
bytes := uint160.Bytes()
|
bytes := uint160.Bytes()
|
||||||
emitBytes(c.prog, bytes)
|
emitBytes(c.prog.BinWriter, bytes)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -657,7 +682,7 @@ 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, buf)
|
emitBytes(c.prog.BinWriter, buf)
|
||||||
}
|
}
|
||||||
|
|
||||||
func (c *codegen) convertStruct(lit *ast.CompositeLit) {
|
func (c *codegen) convertStruct(lit *ast.CompositeLit) {
|
||||||
|
@ -665,13 +690,14 @@ func (c *codegen) convertStruct(lit *ast.CompositeLit) {
|
||||||
// the positions of its variables.
|
// the positions of its variables.
|
||||||
strct, ok := c.typeInfo.TypeOf(lit).Underlying().(*types.Struct)
|
strct, ok := c.typeInfo.TypeOf(lit).Underlying().(*types.Struct)
|
||||||
if !ok {
|
if !ok {
|
||||||
log.Fatalf("the given literal is not of type struct: %v", lit)
|
c.prog.Err = fmt.Errorf("the given literal is not of type struct: %v", lit)
|
||||||
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
emitOpcode(c.prog, vm.NOP)
|
emitOpcode(c.prog.BinWriter, vm.NOP)
|
||||||
emitInt(c.prog, int64(strct.NumFields()))
|
emitInt(c.prog.BinWriter, int64(strct.NumFields()))
|
||||||
emitOpcode(c.prog, vm.NEWSTRUCT)
|
emitOpcode(c.prog.BinWriter, vm.NEWSTRUCT)
|
||||||
emitOpcode(c.prog, vm.TOALTSTACK)
|
emitOpcode(c.prog.BinWriter, vm.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.
|
||||||
|
@ -696,61 +722,66 @@ func (c *codegen) convertStruct(lit *ast.CompositeLit) {
|
||||||
continue
|
continue
|
||||||
}
|
}
|
||||||
|
|
||||||
typeAndVal := typeAndValueForField(sField)
|
typeAndVal, err := typeAndValueForField(sField)
|
||||||
|
if err != nil {
|
||||||
|
c.prog.Err = err
|
||||||
|
return
|
||||||
|
}
|
||||||
c.emitLoadConst(typeAndVal)
|
c.emitLoadConst(typeAndVal)
|
||||||
c.emitStoreLocal(i)
|
c.emitStoreLocal(i)
|
||||||
}
|
}
|
||||||
emitOpcode(c.prog, vm.FROMALTSTACK)
|
emitOpcode(c.prog.BinWriter, vm.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, vm.ADD)
|
emitOpcode(c.prog.BinWriter, vm.ADD)
|
||||||
case token.SUB_ASSIGN:
|
case token.SUB_ASSIGN:
|
||||||
emitOpcode(c.prog, vm.SUB)
|
emitOpcode(c.prog.BinWriter, vm.SUB)
|
||||||
case token.MUL_ASSIGN:
|
case token.MUL_ASSIGN:
|
||||||
emitOpcode(c.prog, vm.MUL)
|
emitOpcode(c.prog.BinWriter, vm.MUL)
|
||||||
case token.QUO_ASSIGN:
|
case token.QUO_ASSIGN:
|
||||||
emitOpcode(c.prog, vm.DIV)
|
emitOpcode(c.prog.BinWriter, vm.DIV)
|
||||||
case token.ADD:
|
case token.ADD:
|
||||||
emitOpcode(c.prog, vm.ADD)
|
emitOpcode(c.prog.BinWriter, vm.ADD)
|
||||||
case token.SUB:
|
case token.SUB:
|
||||||
emitOpcode(c.prog, vm.SUB)
|
emitOpcode(c.prog.BinWriter, vm.SUB)
|
||||||
case token.MUL:
|
case token.MUL:
|
||||||
emitOpcode(c.prog, vm.MUL)
|
emitOpcode(c.prog.BinWriter, vm.MUL)
|
||||||
case token.QUO:
|
case token.QUO:
|
||||||
emitOpcode(c.prog, vm.DIV)
|
emitOpcode(c.prog.BinWriter, vm.DIV)
|
||||||
case token.LSS:
|
case token.LSS:
|
||||||
emitOpcode(c.prog, vm.LT)
|
emitOpcode(c.prog.BinWriter, vm.LT)
|
||||||
case token.LEQ:
|
case token.LEQ:
|
||||||
emitOpcode(c.prog, vm.LTE)
|
emitOpcode(c.prog.BinWriter, vm.LTE)
|
||||||
case token.GTR:
|
case token.GTR:
|
||||||
emitOpcode(c.prog, vm.GT)
|
emitOpcode(c.prog.BinWriter, vm.GT)
|
||||||
case token.GEQ:
|
case token.GEQ:
|
||||||
emitOpcode(c.prog, vm.GTE)
|
emitOpcode(c.prog.BinWriter, vm.GTE)
|
||||||
case token.EQL:
|
case token.EQL:
|
||||||
emitOpcode(c.prog, vm.NUMEQUAL)
|
emitOpcode(c.prog.BinWriter, vm.NUMEQUAL)
|
||||||
case token.NEQ:
|
case token.NEQ:
|
||||||
emitOpcode(c.prog, vm.NUMNOTEQUAL)
|
emitOpcode(c.prog.BinWriter, vm.NUMNOTEQUAL)
|
||||||
case token.DEC:
|
case token.DEC:
|
||||||
emitOpcode(c.prog, vm.DEC)
|
emitOpcode(c.prog.BinWriter, vm.DEC)
|
||||||
case token.INC:
|
case token.INC:
|
||||||
emitOpcode(c.prog, vm.INC)
|
emitOpcode(c.prog.BinWriter, vm.INC)
|
||||||
case token.NOT:
|
case token.NOT:
|
||||||
emitOpcode(c.prog, vm.NOT)
|
emitOpcode(c.prog.BinWriter, vm.NOT)
|
||||||
case token.AND:
|
case token.AND:
|
||||||
emitOpcode(c.prog, vm.AND)
|
emitOpcode(c.prog.BinWriter, vm.AND)
|
||||||
case token.OR:
|
case token.OR:
|
||||||
emitOpcode(c.prog, vm.OR)
|
emitOpcode(c.prog.BinWriter, vm.OR)
|
||||||
case token.SHL:
|
case token.SHL:
|
||||||
emitOpcode(c.prog, vm.SHL)
|
emitOpcode(c.prog.BinWriter, vm.SHL)
|
||||||
case token.SHR:
|
case token.SHR:
|
||||||
emitOpcode(c.prog, vm.SHR)
|
emitOpcode(c.prog.BinWriter, vm.SHR)
|
||||||
case token.XOR:
|
case token.XOR:
|
||||||
emitOpcode(c.prog, vm.XOR)
|
emitOpcode(c.prog.BinWriter, vm.XOR)
|
||||||
default:
|
default:
|
||||||
log.Fatalf("compiler could not convert token: %s", tok)
|
c.prog.Err = fmt.Errorf("compiler could not convert token: %s", tok)
|
||||||
|
return
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -761,11 +792,11 @@ func (c *codegen) newFunc(decl *ast.FuncDecl) *funcScope {
|
||||||
}
|
}
|
||||||
|
|
||||||
// CodeGen compiles the program to bytecode.
|
// CodeGen compiles the program to bytecode.
|
||||||
func CodeGen(info *buildInfo) (*bytes.Buffer, error) {
|
func CodeGen(info *buildInfo) ([]byte, error) {
|
||||||
pkg := info.program.Package(info.initialPackage)
|
pkg := info.program.Package(info.initialPackage)
|
||||||
c := &codegen{
|
c := &codegen{
|
||||||
buildInfo: info,
|
buildInfo: info,
|
||||||
prog: new(bytes.Buffer),
|
prog: io.NewBufBinWriter(),
|
||||||
l: []int{},
|
l: []int{},
|
||||||
funcs: map[string]*funcScope{},
|
funcs: map[string]*funcScope{},
|
||||||
typeInfo: &pkg.Info,
|
typeInfo: &pkg.Info,
|
||||||
|
@ -774,7 +805,8 @@ func CodeGen(info *buildInfo) (*bytes.Buffer, error) {
|
||||||
// Resolve the entrypoint of the program.
|
// Resolve the entrypoint of the program.
|
||||||
main, mainFile := resolveEntryPoint(mainIdent, pkg)
|
main, mainFile := resolveEntryPoint(mainIdent, pkg)
|
||||||
if main == nil {
|
if main == nil {
|
||||||
log.Fatal("could not find func main. Did you forget to declare it?")
|
c.prog.Err = fmt.Errorf("could not find func main. Did you forget to declare it? ")
|
||||||
|
return []byte{}, c.prog.Err
|
||||||
}
|
}
|
||||||
|
|
||||||
funUsage := analyzeFuncUsage(info.program.AllPackages)
|
funUsage := analyzeFuncUsage(info.program.AllPackages)
|
||||||
|
@ -815,9 +847,12 @@ func CodeGen(info *buildInfo) (*bytes.Buffer, error) {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
c.writeJumps()
|
if c.prog.Err != nil {
|
||||||
|
return nil, c.prog.Err
|
||||||
return c.prog, nil
|
}
|
||||||
|
buf := c.prog.Bytes()
|
||||||
|
c.writeJumps(buf)
|
||||||
|
return buf, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
func (c *codegen) resolveFuncDecls(f *ast.File) {
|
func (c *codegen) resolveFuncDecls(f *ast.File) {
|
||||||
|
@ -831,8 +866,7 @@ func (c *codegen) resolveFuncDecls(f *ast.File) {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
func (c *codegen) writeJumps() {
|
func (c *codegen) writeJumps(b []byte) {
|
||||||
b := c.prog.Bytes()
|
|
||||||
for i, op := range b {
|
for i, op := range b {
|
||||||
j := i + 1
|
j := i + 1
|
||||||
switch vm.Instruction(op) {
|
switch vm.Instruction(op) {
|
||||||
|
|
|
@ -2,7 +2,6 @@ package compiler
|
||||||
|
|
||||||
import (
|
import (
|
||||||
"bytes"
|
"bytes"
|
||||||
"encoding/hex"
|
|
||||||
"fmt"
|
"fmt"
|
||||||
"go/ast"
|
"go/ast"
|
||||||
"go/build"
|
"go/build"
|
||||||
|
@ -10,7 +9,6 @@ import (
|
||||||
"go/types"
|
"go/types"
|
||||||
"io"
|
"io"
|
||||||
"io/ioutil"
|
"io/ioutil"
|
||||||
"log"
|
|
||||||
"os"
|
"os"
|
||||||
"strings"
|
"strings"
|
||||||
|
|
||||||
|
@ -60,7 +58,7 @@ func Compile(r io.Reader) ([]byte, error) {
|
||||||
return nil, err
|
return nil, err
|
||||||
}
|
}
|
||||||
|
|
||||||
return buf.Bytes(), nil
|
return buf, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
type archive struct {
|
type archive struct {
|
||||||
|
@ -69,9 +67,9 @@ type archive struct {
|
||||||
}
|
}
|
||||||
|
|
||||||
// CompileAndSave will compile and save the file to disk.
|
// CompileAndSave will compile and save the file to disk.
|
||||||
func CompileAndSave(src string, o *Options) error {
|
func CompileAndSave(src string, o *Options) ([]byte, error) {
|
||||||
if !strings.HasSuffix(src, ".go") {
|
if !strings.HasSuffix(src, ".go") {
|
||||||
return fmt.Errorf("%s is not a Go file", src)
|
return nil, fmt.Errorf("%s is not a Go file", src)
|
||||||
}
|
}
|
||||||
o.Outfile = strings.TrimSuffix(o.Outfile, fmt.Sprintf(".%s", fileExt))
|
o.Outfile = strings.TrimSuffix(o.Outfile, fmt.Sprintf(".%s", fileExt))
|
||||||
if len(o.Outfile) == 0 {
|
if len(o.Outfile) == 0 {
|
||||||
|
@ -82,17 +80,15 @@ func CompileAndSave(src string, o *Options) error {
|
||||||
}
|
}
|
||||||
b, err := ioutil.ReadFile(src)
|
b, err := ioutil.ReadFile(src)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return err
|
return nil, err
|
||||||
}
|
}
|
||||||
b, err = Compile(bytes.NewReader(b))
|
b, err = Compile(bytes.NewReader(b))
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return fmt.Errorf("error while trying to compile smart contract file: %v", err)
|
return nil, fmt.Errorf("error while trying to compile smart contract file: %v", err)
|
||||||
}
|
}
|
||||||
|
|
||||||
log.Println(hex.EncodeToString(b))
|
|
||||||
|
|
||||||
out := fmt.Sprintf("%s.%s", o.Outfile, o.Ext)
|
out := fmt.Sprintf("%s.%s", o.Outfile, o.Ext)
|
||||||
return ioutil.WriteFile(out, b, os.ModePerm)
|
return b, ioutil.WriteFile(out, b, os.ModePerm)
|
||||||
}
|
}
|
||||||
|
|
||||||
func gopath() string {
|
func gopath() string {
|
||||||
|
@ -102,7 +98,3 @@ func gopath() string {
|
||||||
}
|
}
|
||||||
return gopath
|
return gopath
|
||||||
}
|
}
|
||||||
|
|
||||||
func init() {
|
|
||||||
log.SetFlags(0)
|
|
||||||
}
|
|
||||||
|
|
|
@ -1,105 +1,114 @@
|
||||||
package compiler
|
package compiler
|
||||||
|
|
||||||
import (
|
import (
|
||||||
"bytes"
|
|
||||||
"encoding/binary"
|
"encoding/binary"
|
||||||
"errors"
|
"errors"
|
||||||
"fmt"
|
"fmt"
|
||||||
"io"
|
|
||||||
"math/big"
|
"math/big"
|
||||||
|
|
||||||
|
"github.com/CityOfZion/neo-go/pkg/io"
|
||||||
"github.com/CityOfZion/neo-go/pkg/util"
|
"github.com/CityOfZion/neo-go/pkg/util"
|
||||||
"github.com/CityOfZion/neo-go/pkg/vm"
|
"github.com/CityOfZion/neo-go/pkg/vm"
|
||||||
)
|
)
|
||||||
|
|
||||||
func emit(w *bytes.Buffer, instr vm.Instruction, b []byte) error {
|
// emit a VM Instruction with data to the given buffer.
|
||||||
if err := w.WriteByte(byte(instr)); err != nil {
|
func emit(w *io.BinWriter, instr vm.Instruction, b []byte) {
|
||||||
return err
|
emitOpcode(w, instr)
|
||||||
}
|
w.WriteBytes(b)
|
||||||
_, err := w.Write(b)
|
|
||||||
return err
|
|
||||||
}
|
}
|
||||||
|
|
||||||
func emitOpcode(w io.ByteWriter, instr vm.Instruction) error {
|
// emitOpcode emits a single VM Instruction the given buffer.
|
||||||
return w.WriteByte(byte(instr))
|
func emitOpcode(w *io.BinWriter, instr vm.Instruction) {
|
||||||
|
w.WriteLE(byte(instr))
|
||||||
}
|
}
|
||||||
|
|
||||||
func emitBool(w io.ByteWriter, ok bool) error {
|
// emitBool emits a bool type the given buffer.
|
||||||
|
func emitBool(w *io.BinWriter, ok bool) {
|
||||||
if ok {
|
if ok {
|
||||||
return emitOpcode(w, vm.PUSHT)
|
emitOpcode(w, vm.PUSHT)
|
||||||
|
return
|
||||||
}
|
}
|
||||||
return emitOpcode(w, vm.PUSHF)
|
emitOpcode(w, vm.PUSHF)
|
||||||
}
|
}
|
||||||
|
|
||||||
func emitInt(w *bytes.Buffer, i int64) error {
|
// emitInt emits a int type to the given buffer.
|
||||||
if i == -1 {
|
func emitInt(w *io.BinWriter, i int64) {
|
||||||
return emitOpcode(w, vm.PUSHM1)
|
switch {
|
||||||
}
|
case i == -1:
|
||||||
if i == 0 {
|
emitOpcode(w, vm.PUSHM1)
|
||||||
return emitOpcode(w, vm.PUSHF)
|
return
|
||||||
}
|
case i == 0:
|
||||||
if i > 0 && i < 16 {
|
emitOpcode(w, vm.PUSHF)
|
||||||
|
return
|
||||||
|
case i > 0 && i < 16:
|
||||||
val := vm.Instruction(int(vm.PUSH1) - 1 + int(i))
|
val := vm.Instruction(int(vm.PUSH1) - 1 + int(i))
|
||||||
return emitOpcode(w, val)
|
emitOpcode(w, val)
|
||||||
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
bInt := big.NewInt(i)
|
bInt := big.NewInt(i)
|
||||||
val := util.ArrayReverse(bInt.Bytes())
|
val := util.ArrayReverse(bInt.Bytes())
|
||||||
return emitBytes(w, val)
|
emitBytes(w, val)
|
||||||
}
|
}
|
||||||
|
|
||||||
func emitString(w *bytes.Buffer, s string) error {
|
// emitString emits a string to the given buffer.
|
||||||
return emitBytes(w, []byte(s))
|
func emitString(w *io.BinWriter, s string) {
|
||||||
|
emitBytes(w, []byte(s))
|
||||||
}
|
}
|
||||||
|
|
||||||
func emitBytes(w *bytes.Buffer, b []byte) error {
|
// emitBytes emits a byte array to the given buffer.
|
||||||
var (
|
func emitBytes(w *io.BinWriter, b []byte) {
|
||||||
err error
|
n := len(b)
|
||||||
n = len(b)
|
|
||||||
)
|
|
||||||
|
|
||||||
switch {
|
switch {
|
||||||
case n <= int(vm.PUSHBYTES75):
|
case n <= int(vm.PUSHBYTES75):
|
||||||
return emit(w, vm.Instruction(n), b)
|
emit(w, vm.Instruction(n), b)
|
||||||
|
return
|
||||||
case n < 0x100:
|
case n < 0x100:
|
||||||
err = emit(w, vm.PUSHDATA1, []byte{byte(n)})
|
emit(w, vm.PUSHDATA1, []byte{byte(n)})
|
||||||
case n < 0x10000:
|
case n < 0x10000:
|
||||||
buf := make([]byte, 2)
|
buf := make([]byte, 2)
|
||||||
binary.LittleEndian.PutUint16(buf, uint16(n))
|
binary.LittleEndian.PutUint16(buf, uint16(n))
|
||||||
err = emit(w, vm.PUSHDATA2, buf)
|
emit(w, vm.PUSHDATA2, buf)
|
||||||
default:
|
default:
|
||||||
buf := make([]byte, 4)
|
buf := make([]byte, 4)
|
||||||
binary.LittleEndian.PutUint32(buf, uint32(n))
|
binary.LittleEndian.PutUint32(buf, uint32(n))
|
||||||
err = emit(w, vm.PUSHDATA4, buf)
|
emit(w, vm.PUSHDATA4, buf)
|
||||||
|
if w.Err != nil {
|
||||||
|
return
|
||||||
|
}
|
||||||
}
|
}
|
||||||
if err != nil {
|
|
||||||
return err
|
w.WriteBytes(b)
|
||||||
}
|
|
||||||
_, err = w.Write(b)
|
|
||||||
return err
|
|
||||||
}
|
}
|
||||||
|
|
||||||
func emitSyscall(w *bytes.Buffer, api string) error {
|
// 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 {
|
if len(api) == 0 {
|
||||||
return errors.New("syscall api cannot be of length 0")
|
w.Err = errors.New("syscall api cannot be of length 0")
|
||||||
|
return
|
||||||
}
|
}
|
||||||
buf := make([]byte, len(api)+1)
|
buf := make([]byte, len(api)+1)
|
||||||
buf[0] = byte(len(api))
|
buf[0] = byte(len(api))
|
||||||
copy(buf[1:], api)
|
copy(buf[1:], api)
|
||||||
return emit(w, vm.SYSCALL, buf)
|
emit(w, vm.SYSCALL, buf)
|
||||||
}
|
}
|
||||||
|
|
||||||
func emitCall(w *bytes.Buffer, instr vm.Instruction, label int16) error {
|
// emitCall emits a call Instruction with label to the given buffer.
|
||||||
return emitJmp(w, instr, label)
|
func emitCall(w *io.BinWriter, instr vm.Instruction, label int16) {
|
||||||
|
emitJmp(w, instr, label)
|
||||||
}
|
}
|
||||||
|
|
||||||
func emitJmp(w *bytes.Buffer, instr vm.Instruction, label int16) error {
|
// emitJmp emits a jump Instruction along with label to the given buffer.
|
||||||
|
func emitJmp(w *io.BinWriter, instr vm.Instruction, label int16) {
|
||||||
if !isInstrJmp(instr) {
|
if !isInstrJmp(instr) {
|
||||||
return fmt.Errorf("opcode %s is not a jump or call type", instr)
|
w.Err = fmt.Errorf("opcode %s is not a jump or call type", instr)
|
||||||
|
return
|
||||||
}
|
}
|
||||||
buf := make([]byte, 2)
|
buf := make([]byte, 2)
|
||||||
binary.LittleEndian.PutUint16(buf, uint16(label))
|
binary.LittleEndian.PutUint16(buf, uint16(label))
|
||||||
return emit(w, instr, buf)
|
emit(w, instr, buf)
|
||||||
}
|
}
|
||||||
|
|
||||||
func isInstrJmp(instr vm.Instruction) bool {
|
func isInstrJmp(instr vm.Instruction) bool {
|
||||||
|
|
|
@ -44,13 +44,13 @@ func serializeItemTo(item StackItem, w *io.BinWriter, seen map[StackItem]bool) {
|
||||||
switch t := item.(type) {
|
switch t := item.(type) {
|
||||||
case *ByteArrayItem:
|
case *ByteArrayItem:
|
||||||
w.WriteLE(byte(byteArrayT))
|
w.WriteLE(byte(byteArrayT))
|
||||||
w.WriteBytes(t.value)
|
w.WriteVarBytes(t.value)
|
||||||
case *BoolItem:
|
case *BoolItem:
|
||||||
w.WriteLE(byte(booleanT))
|
w.WriteLE(byte(booleanT))
|
||||||
w.WriteLE(t.value)
|
w.WriteLE(t.value)
|
||||||
case *BigIntegerItem:
|
case *BigIntegerItem:
|
||||||
w.WriteLE(byte(integerT))
|
w.WriteLE(byte(integerT))
|
||||||
w.WriteBytes(t.Bytes())
|
w.WriteVarBytes(t.Bytes())
|
||||||
case *InteropItem:
|
case *InteropItem:
|
||||||
w.Err = errors.New("not supported")
|
w.Err = errors.New("not supported")
|
||||||
case *ArrayItem, *StructItem:
|
case *ArrayItem, *StructItem:
|
||||||
|
|
Loading…
Reference in a new issue