forked from TrueCloudLab/neoneo-go
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"),
|
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
|
||||||
}
|
}
|
||||||
|
|
|
@ -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.
|
||||||
|
|
|
@ -2,11 +2,11 @@ package compiler
|
||||||
|
|
||||||
import (
|
import (
|
||||||
"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"
|
||||||
|
@ -57,7 +57,6 @@ func (c *codegen) pc() int {
|
||||||
|
|
||||||
func (c *codegen) emitLoadConst(t types.TypeAndValue) {
|
func (c *codegen) emitLoadConst(t types.TypeAndValue) {
|
||||||
if c.prog.Err != nil {
|
if c.prog.Err != nil {
|
||||||
log.Fatal(c.prog.Err)
|
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
switch typ := t.Type.Underlying().(type) {
|
switch typ := t.Type.Underlying().(type) {
|
||||||
|
@ -77,17 +76,20 @@ func (c *codegen) emitLoadConst(t types.TypeAndValue) {
|
||||||
b := byte(val)
|
b := byte(val)
|
||||||
emitBytes(c.prog, []byte{b})
|
emitBytes(c.prog, []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)
|
||||||
}
|
}
|
||||||
|
@ -102,7 +104,8 @@ func (c *codegen) emitStoreLocal(pos int) {
|
||||||
emitOpcode(c.prog, vm.DUPFROMALTSTACK)
|
emitOpcode(c.prog, 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, 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.
|
// 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)
|
||||||
|
@ -206,7 +210,6 @@ func (c *codegen) convertFuncDecl(file ast.Node, decl *ast.FuncDecl) {
|
||||||
|
|
||||||
func (c *codegen) Visit(node ast.Node) ast.Visitor {
|
func (c *codegen) Visit(node ast.Node) ast.Visitor {
|
||||||
if c.prog.Err != nil {
|
if c.prog.Err != nil {
|
||||||
log.Fatal(c.prog.Err)
|
|
||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
switch n := node.(type) {
|
switch n := node.(type) {
|
||||||
|
@ -256,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.
|
||||||
|
@ -270,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)
|
||||||
}
|
}
|
||||||
|
@ -279,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()
|
||||||
|
@ -323,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)
|
||||||
}
|
}
|
||||||
|
@ -431,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.
|
||||||
|
@ -447,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
|
||||||
|
@ -501,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
|
||||||
|
|
||||||
|
@ -521,7 +535,8 @@ func (c *codegen) Visit(node ast.Node) ast.Visitor {
|
||||||
case token.XOR:
|
case token.XOR:
|
||||||
emitOpcode(c.prog, vm.INVERT)
|
emitOpcode(c.prog, 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
|
||||||
|
|
||||||
|
@ -594,7 +609,8 @@ 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, api)
|
||||||
|
|
||||||
|
@ -651,7 +667,8 @@ 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, bytes)
|
||||||
|
@ -673,7 +690,8 @@ 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, vm.NOP)
|
||||||
|
@ -704,7 +722,11 @@ 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)
|
||||||
}
|
}
|
||||||
|
@ -758,7 +780,8 @@ func (c *codegen) convertToken(tok token.Token) {
|
||||||
case token.XOR:
|
case token.XOR:
|
||||||
emitOpcode(c.prog, vm.XOR)
|
emitOpcode(c.prog, 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
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -782,7 +805,8 @@ func CodeGen(info *buildInfo) ([]byte, 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)
|
||||||
|
|
|
@ -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"
|
||||||
|
|
||||||
|
@ -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)
|
|
||||||
}
|
|
||||||
|
|
Loading…
Reference in a new issue