vm: removed logging to fix #457

This commit is contained in:
Vsevolod Brekelov 2019-11-22 17:16:52 +03:00
parent 03ff2976ed
commit f5e2401984
4 changed files with 64 additions and 46 deletions

View file

@ -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
}

View file

@ -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.

View 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)

View file

@ -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)
}