mirror of
https://github.com/ethereum/go-ethereum.git
synced 2026-07-26 14:46:42 +00:00
cmd/easm: error reporting
This commit is contained in:
parent
c995328881
commit
10a090a75a
4 changed files with 46 additions and 31 deletions
1
cmd/easm/examples/auto_push.asm
Normal file
1
cmd/easm/examples/auto_push.asm
Normal file
|
|
@ -0,0 +1 @@
|
||||||
|
push 256
|
||||||
2
cmd/easm/examples/large_string.asm
Normal file
2
cmd/easm/examples/large_string.asm
Normal file
|
|
@ -0,0 +1,2 @@
|
||||||
|
push "hellooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooo"
|
||||||
|
|
||||||
1
cmd/easm/examples/string.asm
Normal file
1
cmd/easm/examples/string.asm
Normal file
|
|
@ -0,0 +1 @@
|
||||||
|
push "hello"
|
||||||
|
|
@ -23,6 +23,10 @@ var (
|
||||||
Name: "debug",
|
Name: "debug",
|
||||||
Usage: "outputs lexer and compiler debug output",
|
Usage: "outputs lexer and compiler debug output",
|
||||||
}
|
}
|
||||||
|
LexFlag = cli.BoolFlag{
|
||||||
|
Name: "lex",
|
||||||
|
Usage: "displays lex token output",
|
||||||
|
}
|
||||||
)
|
)
|
||||||
|
|
||||||
func init() {
|
func init() {
|
||||||
|
|
@ -39,7 +43,10 @@ func init() {
|
||||||
}
|
}
|
||||||
|
|
||||||
func run(ctx *cli.Context) {
|
func run(ctx *cli.Context) {
|
||||||
debug := ctx.GlobalBool(DebugFlag.Name)
|
var (
|
||||||
|
debug = ctx.GlobalBool(DebugFlag.Name)
|
||||||
|
lexDebug = ctx.GlobalBool(LexFlag.Name)
|
||||||
|
)
|
||||||
|
|
||||||
if len(ctx.Args()) == 0 {
|
if len(ctx.Args()) == 0 {
|
||||||
glog.Exitln("err: <filename> required")
|
glog.Exitln("err: <filename> required")
|
||||||
|
|
@ -52,14 +59,13 @@ func run(ctx *cli.Context) {
|
||||||
}
|
}
|
||||||
|
|
||||||
compiler := newCompiler(debug)
|
compiler := newCompiler(debug)
|
||||||
compiler.feed(lex(fn, src, debug))
|
compiler.feed(lex(fn, src, lexDebug))
|
||||||
|
|
||||||
bin, errors := compiler.compile()
|
bin, errors := compiler.compile()
|
||||||
if len(errors) > 0 {
|
if len(errors) > 0 {
|
||||||
// report errors
|
// report errors
|
||||||
for _, err := range errors {
|
for _, err := range errors {
|
||||||
got, want := err.Error()
|
fmt.Printf("%s:%v\n", fn, err)
|
||||||
fmt.Printf("%s:%d: syntax error: unexpected %v, expected %v\n", fn, err.Lineno(), got, want)
|
|
||||||
}
|
}
|
||||||
os.Exit(1)
|
os.Exit(1)
|
||||||
}
|
}
|
||||||
|
|
@ -105,6 +111,7 @@ func newCompiler(debug bool) *Compiler {
|
||||||
// position.
|
// position.
|
||||||
func (c *Compiler) feed(ch <-chan item) {
|
func (c *Compiler) feed(ch <-chan item) {
|
||||||
for i := range ch {
|
for i := range ch {
|
||||||
|
fmt.Println(c.pc, i.text)
|
||||||
switch i.typ {
|
switch i.typ {
|
||||||
case number:
|
case number:
|
||||||
num := common.String2Big(i.text).Bytes()
|
num := common.String2Big(i.text).Bytes()
|
||||||
|
|
@ -136,8 +143,8 @@ func (c *Compiler) feed(ch <-chan item) {
|
||||||
//
|
//
|
||||||
// compile is the second stage in the compile phase
|
// compile is the second stage in the compile phase
|
||||||
// which compiles the tokens to EVM instructions.
|
// which compiles the tokens to EVM instructions.
|
||||||
func (c *Compiler) compile() (string, []cerror) {
|
func (c *Compiler) compile() (string, []error) {
|
||||||
var errors []cerror
|
var errors []error
|
||||||
// continue looping over the tokens until
|
// continue looping over the tokens until
|
||||||
// the stack has been exhausted.
|
// the stack has been exhausted.
|
||||||
for c.pos < len(c.tokens) {
|
for c.pos < len(c.tokens) {
|
||||||
|
|
@ -169,7 +176,7 @@ func (c *Compiler) next() item {
|
||||||
|
|
||||||
// compile line compiles a single line instruction e.g.
|
// compile line compiles a single line instruction e.g.
|
||||||
// "push 1", "jump @labal".
|
// "push 1", "jump @labal".
|
||||||
func (c *Compiler) compileLine() cerror {
|
func (c *Compiler) compileLine() error {
|
||||||
n := c.next()
|
n := c.next()
|
||||||
if n.typ != lineStart {
|
if n.typ != lineStart {
|
||||||
return compileErr(n, n.typ.String(), lineStart.String())
|
return compileErr(n, n.typ.String(), lineStart.String())
|
||||||
|
|
@ -211,7 +218,7 @@ func (c *Compiler) compileNumber(element item) (int, error) {
|
||||||
// compileElement compiles the element (push & label or both)
|
// compileElement compiles the element (push & label or both)
|
||||||
// to a binary representation and may error if incorrect statements
|
// to a binary representation and may error if incorrect statements
|
||||||
// where fed.
|
// where fed.
|
||||||
func (c *Compiler) compileElement(element item) cerror {
|
func (c *Compiler) compileElement(element item) error {
|
||||||
// check for a jump. jumps must be read and compiled
|
// check for a jump. jumps must be read and compiled
|
||||||
// from right to left.
|
// from right to left.
|
||||||
if isJump(element.text) {
|
if isJump(element.text) {
|
||||||
|
|
@ -231,37 +238,45 @@ func (c *Compiler) compileElement(element item) cerror {
|
||||||
default:
|
default:
|
||||||
return compileErr(rvalue, rvalue.text, "number, string or label")
|
return compileErr(rvalue, rvalue.text, "number, string or label")
|
||||||
}
|
}
|
||||||
}
|
// push the operation
|
||||||
// push the operation
|
c.pushBin(toBinary(element.text))
|
||||||
c.pushBin(toBinary(element.text))
|
return nil
|
||||||
|
} else if isPush(element.text) {
|
||||||
|
// handle pushes. pushes are read from left to right.
|
||||||
|
var value []byte
|
||||||
|
|
||||||
// handle pushes. pushes are read from left to right.
|
|
||||||
if isPush(element.text) {
|
|
||||||
rvalue := c.next()
|
rvalue := c.next()
|
||||||
switch rvalue.typ {
|
switch rvalue.typ {
|
||||||
case number:
|
case number:
|
||||||
// TODO figure out how to return the error properly
|
value = common.String2Big(rvalue.text).Bytes()
|
||||||
c.compileNumber(rvalue)
|
if len(value) == 0 {
|
||||||
|
value = []byte{0}
|
||||||
|
}
|
||||||
case stringValue:
|
case stringValue:
|
||||||
// strings are quoted, remove them.
|
value = []byte(rvalue.text[1 : len(rvalue.text)-1])
|
||||||
c.pushBin(rvalue.text[1 : len(rvalue.text)-1])
|
|
||||||
case label:
|
case label:
|
||||||
c.pushBin(vm.PUSH4)
|
value = make([]byte, 4)
|
||||||
pos := make([]byte, 4)
|
copy(value, big.NewInt(int64(c.labels[rvalue.text])).Bytes())
|
||||||
copy(pos, big.NewInt(int64(c.labels[rvalue.text])).Bytes())
|
|
||||||
c.pushBin(pos)
|
|
||||||
default:
|
default:
|
||||||
return compileErr(rvalue, rvalue.text, "number, string or label")
|
return compileErr(rvalue, rvalue.text, "number, string or label")
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if len(value) > 32 {
|
||||||
|
return fmt.Errorf("%d type error: unsupported string or number with size > 32", rvalue.lineno)
|
||||||
|
}
|
||||||
|
|
||||||
|
c.pushBin(vm.OpCode(int(vm.PUSH1) - 1 + len(value)))
|
||||||
|
c.pushBin(value)
|
||||||
|
} else {
|
||||||
|
c.pushBin(toBinary(element.text))
|
||||||
}
|
}
|
||||||
|
|
||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
|
|
||||||
// compileLabel pushes a jumpdest to the binary slice.
|
// compileLabel pushes a jumpdest to the binary slice.
|
||||||
func (c *Compiler) compileLabel() cerror {
|
func (c *Compiler) compileLabel() {
|
||||||
c.pushBin(vm.JUMPDEST)
|
c.pushBin(vm.JUMPDEST)
|
||||||
return nil
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// pushBin pushes the value v to the binary stack.
|
// pushBin pushes the value v to the binary stack.
|
||||||
|
|
@ -294,11 +309,6 @@ func toBinary(text string) vm.OpCode {
|
||||||
return vm.StringToOp(strings.ToUpper(text))
|
return vm.StringToOp(strings.ToUpper(text))
|
||||||
}
|
}
|
||||||
|
|
||||||
type cerror interface {
|
|
||||||
Error() (string, string)
|
|
||||||
Lineno() int
|
|
||||||
}
|
|
||||||
|
|
||||||
type compileError struct {
|
type compileError struct {
|
||||||
got string
|
got string
|
||||||
want string
|
want string
|
||||||
|
|
@ -306,15 +316,16 @@ type compileError struct {
|
||||||
lineno int
|
lineno int
|
||||||
}
|
}
|
||||||
|
|
||||||
func (c compileError) Error() (string, string) { return c.got, c.want }
|
func (err compileError) Error() string {
|
||||||
func (c compileError) Lineno() int { return c.lineno }
|
return fmt.Sprintf("%d syntax error: unexpected %v, expected %v", err.lineno, err.got, err.want)
|
||||||
|
}
|
||||||
|
|
||||||
var (
|
var (
|
||||||
errExpBol = errors.New("expected beginning of line")
|
errExpBol = errors.New("expected beginning of line")
|
||||||
errExpElementOrLabel = errors.New("expected beginning of line")
|
errExpElementOrLabel = errors.New("expected beginning of line")
|
||||||
)
|
)
|
||||||
|
|
||||||
func compileErr(c item, got, want string) cerror {
|
func compileErr(c item, got, want string) error {
|
||||||
return compileError{
|
return compileError{
|
||||||
got: got,
|
got: got,
|
||||||
want: want,
|
want: want,
|
||||||
|
|
|
||||||
Loading…
Reference in a new issue