vm: removed logging to fix #457
This commit is contained in:
parent
03ff2976ed
commit
f5e2401984
4 changed files with 64 additions and 46 deletions
|
@ -280,9 +280,11 @@ func contractCompile(ctx *cli.Context) error {
|
|||
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)
|
||||
}
|
||||
fmt.Println(hex.EncodeToString(result))
|
||||
|
||||
return nil
|
||||
}
|
||||
|
|
|
@ -1,10 +1,10 @@
|
|||
package compiler
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"go/ast"
|
||||
"go/constant"
|
||||
"go/types"
|
||||
"log"
|
||||
|
||||
"golang.org/x/tools/go/loader"
|
||||
)
|
||||
|
@ -19,7 +19,7 @@ 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) {
|
||||
case *types.Basic:
|
||||
switch t.Kind() {
|
||||
|
@ -27,22 +27,22 @@ func typeAndValueForField(fld *types.Var) types.TypeAndValue {
|
|||
return types.TypeAndValue{
|
||||
Type: t,
|
||||
Value: constant.MakeInt64(0),
|
||||
}
|
||||
}, nil
|
||||
case types.String:
|
||||
return types.TypeAndValue{
|
||||
Type: t,
|
||||
Value: constant.MakeString(""),
|
||||
}
|
||||
}, nil
|
||||
case types.Bool, types.UntypedBool:
|
||||
return types.TypeAndValue{
|
||||
Type: t,
|
||||
Value: constant.MakeBool(false),
|
||||
}
|
||||
}, nil
|
||||
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
|
||||
|
@ -69,7 +69,7 @@ func isIdentBool(ident *ast.Ident) bool {
|
|||
}
|
||||
|
||||
// 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
|
||||
switch ident.Name {
|
||||
case "true":
|
||||
|
@ -77,12 +77,12 @@ func makeBoolFromIdent(ident *ast.Ident, tinfo *types.Info) types.TypeAndValue {
|
|||
case "false":
|
||||
b = false
|
||||
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{
|
||||
Type: tinfo.ObjectOf(ident).Type(),
|
||||
Value: constant.MakeBool(b),
|
||||
}
|
||||
}, nil
|
||||
}
|
||||
|
||||
// resolveEntryPoint returns the function declaration of the entrypoint and the corresponding file.
|
||||
|
|
|
@ -2,11 +2,11 @@ package compiler
|
|||
|
||||
import (
|
||||
"encoding/binary"
|
||||
"fmt"
|
||||
"go/ast"
|
||||
"go/constant"
|
||||
"go/token"
|
||||
"go/types"
|
||||
"log"
|
||||
"sort"
|
||||
"strconv"
|
||||
"strings"
|
||||
|
@ -57,7 +57,6 @@ func (c *codegen) pc() int {
|
|||
|
||||
func (c *codegen) emitLoadConst(t types.TypeAndValue) {
|
||||
if c.prog.Err != nil {
|
||||
log.Fatal(c.prog.Err)
|
||||
return
|
||||
}
|
||||
switch typ := t.Type.Underlying().(type) {
|
||||
|
@ -77,17 +76,20 @@ func (c *codegen) emitLoadConst(t types.TypeAndValue) {
|
|||
b := byte(val)
|
||||
emitBytes(c.prog, []byte{b})
|
||||
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:
|
||||
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) {
|
||||
pos := c.scope.loadLocal(name)
|
||||
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)
|
||||
}
|
||||
|
@ -102,7 +104,8 @@ func (c *codegen) emitStoreLocal(pos int) {
|
|||
emitOpcode(c.prog, vm.DUPFROMALTSTACK)
|
||||
|
||||
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))
|
||||
|
@ -175,7 +178,8 @@ func (c *codegen) convertFuncDecl(file ast.Node, decl *ast.FuncDecl) {
|
|||
// Currently only method receives for struct types is supported.
|
||||
_, ok := c.typeInfo.Defs[ident].Type().Underlying().(*types.Struct)
|
||||
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)
|
||||
c.emitStoreLocal(l)
|
||||
|
@ -206,7 +210,6 @@ func (c *codegen) convertFuncDecl(file ast.Node, decl *ast.FuncDecl) {
|
|||
|
||||
func (c *codegen) Visit(node ast.Node) ast.Visitor {
|
||||
if c.prog.Err != nil {
|
||||
log.Fatal(c.prog.Err)
|
||||
return nil
|
||||
}
|
||||
switch n := node.(type) {
|
||||
|
@ -256,7 +259,8 @@ func (c *codegen) Visit(node ast.Node) ast.Visitor {
|
|||
c.emitStoreStructField(i) // store the field
|
||||
}
|
||||
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.
|
||||
|
@ -270,7 +274,8 @@ func (c *codegen) Visit(node ast.Node) ast.Visitor {
|
|||
indexStr := t.Index.(*ast.BasicLit).Value
|
||||
index, err := strconv.Atoi(indexStr)
|
||||
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)
|
||||
}
|
||||
|
@ -279,7 +284,8 @@ func (c *codegen) Visit(node ast.Node) ast.Visitor {
|
|||
|
||||
case *ast.ReturnStmt:
|
||||
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()
|
||||
|
@ -323,7 +329,12 @@ func (c *codegen) Visit(node ast.Node) ast.Visitor {
|
|||
|
||||
case *ast.Ident:
|
||||
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 {
|
||||
c.emitLoadLocal(n.Name)
|
||||
}
|
||||
|
@ -431,7 +442,8 @@ func (c *codegen) Visit(node ast.Node) ast.Visitor {
|
|||
case *ast.Ident:
|
||||
f, ok = c.funcs[fun.Name]
|
||||
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:
|
||||
// If this is a method call we need to walk the AST to load the struct locally.
|
||||
|
@ -447,7 +459,8 @@ func (c *codegen) Visit(node ast.Node) ast.Visitor {
|
|||
// @FIXME this could cause runtime errors.
|
||||
f.selector = fun.X.(*ast.Ident)
|
||||
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:
|
||||
// For now we will assume that there is only 1 argument passed which
|
||||
|
@ -501,7 +514,8 @@ func (c *codegen) Visit(node ast.Node) ast.Visitor {
|
|||
c.emitLoadField(i) // load the field
|
||||
}
|
||||
default:
|
||||
log.Fatal("nested selectors not supported yet")
|
||||
c.prog.Err = fmt.Errorf("nested selectors not supported yet")
|
||||
return nil
|
||||
}
|
||||
return nil
|
||||
|
||||
|
@ -521,7 +535,8 @@ func (c *codegen) Visit(node ast.Node) ast.Visitor {
|
|||
case token.XOR:
|
||||
emitOpcode(c.prog, vm.INVERT)
|
||||
default:
|
||||
log.Fatalf("invalid unary operator: %s", n.Op)
|
||||
c.prog.Err = fmt.Errorf("invalid unary operator: %s", n.Op)
|
||||
return nil
|
||||
}
|
||||
return nil
|
||||
|
||||
|
@ -594,7 +609,8 @@ func (c *codegen) Visit(node ast.Node) ast.Visitor {
|
|||
func (c *codegen) convertSyscall(api, name string) {
|
||||
api, ok := syscalls[api][name]
|
||||
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)
|
||||
|
||||
|
@ -651,7 +667,8 @@ func (c *codegen) convertBuiltin(expr *ast.CallExpr) {
|
|||
addressStr = strings.Replace(addressStr, "\"", "", 2)
|
||||
uint160, err := crypto.Uint160DecodeAddress(addressStr)
|
||||
if err != nil {
|
||||
log.Fatal(err)
|
||||
c.prog.Err = err
|
||||
return
|
||||
}
|
||||
bytes := uint160.Bytes()
|
||||
emitBytes(c.prog, bytes)
|
||||
|
@ -673,7 +690,8 @@ func (c *codegen) convertStruct(lit *ast.CompositeLit) {
|
|||
// the positions of its variables.
|
||||
strct, ok := c.typeInfo.TypeOf(lit).Underlying().(*types.Struct)
|
||||
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)
|
||||
|
@ -704,7 +722,11 @@ func (c *codegen) convertStruct(lit *ast.CompositeLit) {
|
|||
continue
|
||||
}
|
||||
|
||||
typeAndVal := typeAndValueForField(sField)
|
||||
typeAndVal, err := typeAndValueForField(sField)
|
||||
if err != nil {
|
||||
c.prog.Err = err
|
||||
return
|
||||
}
|
||||
c.emitLoadConst(typeAndVal)
|
||||
c.emitStoreLocal(i)
|
||||
}
|
||||
|
@ -758,7 +780,8 @@ func (c *codegen) convertToken(tok token.Token) {
|
|||
case token.XOR:
|
||||
emitOpcode(c.prog, vm.XOR)
|
||||
default:
|
||||
log.Fatalf("compiler could not convert token: %s", tok)
|
||||
c.prog.Err = fmt.Errorf("compiler could not convert token: %s", tok)
|
||||
return
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -782,7 +805,8 @@ func CodeGen(info *buildInfo) ([]byte, error) {
|
|||
// Resolve the entrypoint of the program.
|
||||
main, mainFile := resolveEntryPoint(mainIdent, pkg)
|
||||
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)
|
||||
|
|
|
@ -2,7 +2,6 @@ package compiler
|
|||
|
||||
import (
|
||||
"bytes"
|
||||
"encoding/hex"
|
||||
"fmt"
|
||||
"go/ast"
|
||||
"go/build"
|
||||
|
@ -10,7 +9,6 @@ import (
|
|||
"go/types"
|
||||
"io"
|
||||
"io/ioutil"
|
||||
"log"
|
||||
"os"
|
||||
"strings"
|
||||
|
||||
|
@ -69,9 +67,9 @@ type archive struct {
|
|||
}
|
||||
|
||||
// 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") {
|
||||
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))
|
||||
if len(o.Outfile) == 0 {
|
||||
|
@ -82,17 +80,15 @@ func CompileAndSave(src string, o *Options) error {
|
|||
}
|
||||
b, err := ioutil.ReadFile(src)
|
||||
if err != nil {
|
||||
return err
|
||||
return nil, err
|
||||
}
|
||||
b, err = Compile(bytes.NewReader(b))
|
||||
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)
|
||||
return ioutil.WriteFile(out, b, os.ModePerm)
|
||||
return b, ioutil.WriteFile(out, b, os.ModePerm)
|
||||
}
|
||||
|
||||
func gopath() string {
|
||||
|
@ -102,7 +98,3 @@ func gopath() string {
|
|||
}
|
||||
return gopath
|
||||
}
|
||||
|
||||
func init() {
|
||||
log.SetFlags(0)
|
||||
}
|
||||
|
|
Loading…
Reference in a new issue