diff --git a/cmd/evm/blockrunner.go b/cmd/evm/blockrunner.go index 6612680dc4..0be5f69711 100644 --- a/cmd/evm/blockrunner.go +++ b/cmd/evm/blockrunner.go @@ -25,6 +25,7 @@ import ( "github.com/ethereum/go-ethereum/core/rawdb" "github.com/ethereum/go-ethereum/core/vm" "github.com/ethereum/go-ethereum/eth/tracers/logger" + "github.com/ethereum/go-ethereum/log" "github.com/ethereum/go-ethereum/tests" "github.com/urfave/cli/v2" ) @@ -40,7 +41,10 @@ func blockTestCmd(ctx *cli.Context) error { if len(ctx.Args().First()) == 0 { return errors.New("path-to-test argument required") } - + // Configure the go-ethereum logger + glogger := log.NewGlogHandler(log.StreamHandler(os.Stderr, log.TerminalFormat(false))) + glogger.Verbosity(log.Lvl(ctx.Int(VerbosityFlag.Name))) + log.Root().SetHandler(glogger) var tracer vm.EVMLogger // Configure the EVM logger if ctx.Bool(MachineFlag.Name) { diff --git a/cmd/evm/main.go b/cmd/evm/main.go index 1f6500b78c..024be62b9c 100644 --- a/cmd/evm/main.go +++ b/cmd/evm/main.go @@ -23,116 +23,107 @@ import ( "os" "github.com/ethereum/go-ethereum/cmd/evm/internal/t8ntool" - "github.com/ethereum/go-ethereum/internal/debug" "github.com/ethereum/go-ethereum/internal/flags" "github.com/urfave/cli/v2" ) var ( DebugFlag = &cli.BoolFlag{ - Name: "debug", - Usage: "output full trace logs", - Category: flags.VMCategory, + Name: "debug", + Usage: "output full trace logs", + } + MemProfileFlag = &cli.StringFlag{ + Name: "memprofile", + Usage: "creates a memory profile at the given path", + } + CPUProfileFlag = &cli.StringFlag{ + Name: "cpuprofile", + Usage: "creates a CPU profile at the given path", } StatDumpFlag = &cli.BoolFlag{ - Name: "statdump", - Usage: "displays stack and heap memory information", - Category: flags.VMCategory, + Name: "statdump", + Usage: "displays stack and heap memory information", } CodeFlag = &cli.StringFlag{ - Name: "code", - Usage: "EVM code", - Category: flags.VMCategory, + Name: "code", + Usage: "EVM code", } CodeFileFlag = &cli.StringFlag{ - Name: "codefile", - Usage: "File containing EVM code. If '-' is specified, code is read from stdin ", - Category: flags.VMCategory, + Name: "codefile", + Usage: "File containing EVM code. If '-' is specified, code is read from stdin ", } GasFlag = &cli.Uint64Flag{ - Name: "gas", - Usage: "gas limit for the evm", - Value: 10000000000, - Category: flags.VMCategory, + Name: "gas", + Usage: "gas limit for the evm", + Value: 10000000000, } PriceFlag = &flags.BigFlag{ - Name: "price", - Usage: "price set for the evm", - Value: new(big.Int), - Category: flags.VMCategory, + Name: "price", + Usage: "price set for the evm", + Value: new(big.Int), } ValueFlag = &flags.BigFlag{ - Name: "value", - Usage: "value set for the evm", - Value: new(big.Int), - Category: flags.VMCategory, + Name: "value", + Usage: "value set for the evm", + Value: new(big.Int), } DumpFlag = &cli.BoolFlag{ - Name: "dump", - Usage: "dumps the state after the run", - Category: flags.VMCategory, + Name: "dump", + Usage: "dumps the state after the run", } InputFlag = &cli.StringFlag{ - Name: "input", - Usage: "input for the EVM", - Category: flags.VMCategory, + Name: "input", + Usage: "input for the EVM", } InputFileFlag = &cli.StringFlag{ - Name: "inputfile", - Usage: "file containing input for the EVM", - Category: flags.VMCategory, + Name: "inputfile", + Usage: "file containing input for the EVM", + } + VerbosityFlag = &cli.IntFlag{ + Name: "verbosity", + Usage: "sets the verbosity level", } BenchFlag = &cli.BoolFlag{ - Name: "bench", - Usage: "benchmark the execution", - Category: flags.VMCategory, + Name: "bench", + Usage: "benchmark the execution", } CreateFlag = &cli.BoolFlag{ - Name: "create", - Usage: "indicates the action should be create rather than call", - Category: flags.VMCategory, + Name: "create", + Usage: "indicates the action should be create rather than call", } GenesisFlag = &cli.StringFlag{ - Name: "prestate", - Usage: "JSON file with prestate (genesis) config", - Category: flags.VMCategory, + Name: "prestate", + Usage: "JSON file with prestate (genesis) config", } MachineFlag = &cli.BoolFlag{ - Name: "json", - Usage: "output trace logs in machine readable format (json)", - Category: flags.VMCategory, + Name: "json", + Usage: "output trace logs in machine readable format (json)", } SenderFlag = &cli.StringFlag{ - Name: "sender", - Usage: "The transaction origin", - Category: flags.VMCategory, + Name: "sender", + Usage: "The transaction origin", } ReceiverFlag = &cli.StringFlag{ - Name: "receiver", - Usage: "The transaction receiver (execution context)", - Category: flags.VMCategory, + Name: "receiver", + Usage: "The transaction receiver (execution context)", } DisableMemoryFlag = &cli.BoolFlag{ - Name: "nomemory", - Value: true, - Usage: "disable memory output", - Category: flags.VMCategory, + Name: "nomemory", + Value: true, + Usage: "disable memory output", } DisableStackFlag = &cli.BoolFlag{ - Name: "nostack", - Usage: "disable stack output", - Category: flags.VMCategory, + Name: "nostack", + Usage: "disable stack output", } DisableStorageFlag = &cli.BoolFlag{ - Name: "nostorage", - Usage: "disable storage output", - Category: flags.VMCategory, + Name: "nostorage", + Usage: "disable storage output", } DisableReturnDataFlag = &cli.BoolFlag{ - Name: "noreturndata", - Value: true, - Usage: "enable return data output", - Category: flags.VMCategory, + Name: "noreturndata", + Value: true, + Usage: "enable return data output", } ) @@ -192,38 +183,34 @@ var blockBuilderCommand = &cli.Command{ }, } -// vmFlags contains flags related to running the EVM. -var vmFlags = []cli.Flag{ - CodeFlag, - CodeFileFlag, - CreateFlag, - GasFlag, - PriceFlag, - ValueFlag, - InputFlag, - InputFileFlag, - GenesisFlag, - SenderFlag, - ReceiverFlag, -} - -// traceFlags contains flags that configure tracing output. -var traceFlags = []cli.Flag{ - BenchFlag, - DebugFlag, - DumpFlag, - MachineFlag, - StatDumpFlag, - DisableMemoryFlag, - DisableStackFlag, - DisableStorageFlag, - DisableReturnDataFlag, -} - var app = flags.NewApp("the evm command line interface") func init() { - app.Flags = flags.Merge(vmFlags, traceFlags, debug.Flags) + app.Flags = []cli.Flag{ + BenchFlag, + CreateFlag, + DebugFlag, + VerbosityFlag, + CodeFlag, + CodeFileFlag, + GasFlag, + PriceFlag, + ValueFlag, + DumpFlag, + InputFlag, + InputFileFlag, + MemProfileFlag, + CPUProfileFlag, + StatDumpFlag, + GenesisFlag, + MachineFlag, + SenderFlag, + ReceiverFlag, + DisableMemoryFlag, + DisableStackFlag, + DisableStorageFlag, + DisableReturnDataFlag, + } app.Commands = []*cli.Command{ compileCommand, disasmCommand, @@ -234,14 +221,6 @@ func init() { transactionCommand, blockBuilderCommand, } - app.Before = func(ctx *cli.Context) error { - flags.MigrateGlobalFlags(ctx) - return debug.Setup(ctx) - } - app.After = func(ctx *cli.Context) error { - debug.Exit() - return nil - } } func main() { diff --git a/cmd/evm/runner.go b/cmd/evm/runner.go index 017388efb5..ac8432badb 100644 --- a/cmd/evm/runner.go +++ b/cmd/evm/runner.go @@ -24,6 +24,7 @@ import ( "math/big" "os" goruntime "runtime" + "runtime/pprof" "testing" "time" @@ -33,10 +34,12 @@ import ( "github.com/ethereum/go-ethereum/core" "github.com/ethereum/go-ethereum/core/rawdb" "github.com/ethereum/go-ethereum/core/state" + "github.com/ethereum/go-ethereum/core/types" "github.com/ethereum/go-ethereum/core/vm" "github.com/ethereum/go-ethereum/core/vm/runtime" "github.com/ethereum/go-ethereum/eth/tracers/logger" "github.com/ethereum/go-ethereum/internal/flags" + "github.com/ethereum/go-ethereum/log" "github.com/ethereum/go-ethereum/params" "github.com/ethereum/go-ethereum/trie" "github.com/ethereum/go-ethereum/trie/triedb/hashdb" @@ -49,7 +52,6 @@ var runCommand = &cli.Command{ Usage: "run arbitrary evm binary", ArgsUsage: "", Description: `The run command runs arbitrary EVM code.`, - Flags: flags.Merge(vmFlags, traceFlags), } // readGenesis will read the given JSON format genesis file and return @@ -107,6 +109,9 @@ func timedExec(bench bool, execFunc func() ([]byte, uint64, error)) (output []by } func runCmd(ctx *cli.Context) error { + glogger := log.NewGlogHandler(log.StreamHandler(os.Stderr, log.TerminalFormat(false))) + glogger.Verbosity(log.Lvl(ctx.Int(VerbosityFlag.Name))) + log.Root().SetHandler(glogger) logconfig := &logger.Config{ EnableMemory: !ctx.Bool(DisableMemoryFlag.Name), DisableStack: ctx.Bool(DisableStackFlag.Name), @@ -116,14 +121,15 @@ func runCmd(ctx *cli.Context) error { } var ( - tracer vm.EVMLogger - debugLogger *logger.StructLogger - statedb *state.StateDB - chainConfig *params.ChainConfig - sender = common.BytesToAddress([]byte("sender")) - receiver = common.BytesToAddress([]byte("receiver")) - preimages = ctx.Bool(DumpFlag.Name) - blobHashes []common.Hash // TODO (MariusVanDerWijden) implement blob hashes in state tests + tracer vm.EVMLogger + debugLogger *logger.StructLogger + statedb *state.StateDB + chainConfig *params.ChainConfig + sender = common.BytesToAddress([]byte("sender")) + receiver = common.BytesToAddress([]byte("receiver")) + genesisConfig *core.Genesis + preimages = ctx.Bool(DumpFlag.Name) + blobHashes []common.Hash // TODO (MariusVanDerWijden) implement blob hashes in state tests ) if ctx.Bool(MachineFlag.Name) { tracer = logger.NewJSONLogger(logconfig, os.Stdout) @@ -133,30 +139,30 @@ func runCmd(ctx *cli.Context) error { } else { debugLogger = logger.NewStructLogger(logconfig) } - - initialGas := ctx.Uint64(GasFlag.Name) - genesisConfig := new(core.Genesis) - genesisConfig.GasLimit = initialGas if ctx.String(GenesisFlag.Name) != "" { - genesisConfig = readGenesis(ctx.String(GenesisFlag.Name)) - if genesisConfig.GasLimit != 0 { - initialGas = genesisConfig.GasLimit - } + gen := readGenesis(ctx.String(GenesisFlag.Name)) + genesisConfig = gen + db := rawdb.NewMemoryDatabase() + triedb := trie.NewDatabase(db, &trie.Config{ + Preimages: preimages, + HashDB: hashdb.Defaults, + }) + defer triedb.Close() + genesis := gen.MustCommit(db, triedb) + sdb := state.NewDatabaseWithNodeDB(db, triedb) + statedb, _ = state.New(genesis.Root(), sdb, nil) + chainConfig = gen.Config } else { - genesisConfig.Config = params.AllEthashProtocolChanges + db := rawdb.NewMemoryDatabase() + triedb := trie.NewDatabase(db, &trie.Config{ + Preimages: preimages, + HashDB: hashdb.Defaults, + }) + defer triedb.Close() + sdb := state.NewDatabaseWithNodeDB(db, triedb) + statedb, _ = state.New(types.EmptyRootHash, sdb, nil) + genesisConfig = new(core.Genesis) } - - db := rawdb.NewMemoryDatabase() - triedb := trie.NewDatabase(db, &trie.Config{ - Preimages: preimages, - HashDB: hashdb.Defaults, - }) - defer triedb.Close() - genesis := genesisConfig.MustCommit(db, triedb) - sdb := state.NewDatabaseWithNodeDB(db, triedb) - statedb, _ = state.New(genesis.Root(), sdb, nil) - chainConfig = genesisConfig.Config - if ctx.String(SenderFlag.Name) != "" { sender = common.HexToAddress(ctx.String(SenderFlag.Name)) } @@ -210,6 +216,10 @@ func runCmd(ctx *cli.Context) error { } code = common.Hex2Bytes(bin) } + initialGas := ctx.Uint64(GasFlag.Name) + if genesisConfig.GasLimit != 0 { + initialGas = genesisConfig.GasLimit + } runtimeConfig := runtime.Config{ Origin: sender, State: statedb, @@ -226,6 +236,19 @@ func runCmd(ctx *cli.Context) error { }, } + if cpuProfilePath := ctx.String(CPUProfileFlag.Name); cpuProfilePath != "" { + f, err := os.Create(cpuProfilePath) + if err != nil { + fmt.Println("could not create CPU profile: ", err) + os.Exit(1) + } + if err := pprof.StartCPUProfile(f); err != nil { + fmt.Println("could not start CPU profile: ", err) + os.Exit(1) + } + defer pprof.StopCPUProfile() + } + if chainConfig != nil { runtimeConfig.ChainConfig = chainConfig } else { @@ -273,6 +296,19 @@ func runCmd(ctx *cli.Context) error { fmt.Println(string(statedb.Dump(nil))) } + if memProfilePath := ctx.String(MemProfileFlag.Name); memProfilePath != "" { + f, err := os.Create(memProfilePath) + if err != nil { + fmt.Println("could not create memory profile: ", err) + os.Exit(1) + } + if err := pprof.WriteHeapProfile(f); err != nil { + fmt.Println("could not write memory profile: ", err) + os.Exit(1) + } + f.Close() + } + if ctx.Bool(DebugFlag.Name) { if debugLogger != nil { fmt.Fprintln(os.Stderr, "#### TRACE ####") diff --git a/cmd/evm/staterunner.go b/cmd/evm/staterunner.go index 8a07fccdf8..85931f0406 100644 --- a/cmd/evm/staterunner.go +++ b/cmd/evm/staterunner.go @@ -28,6 +28,7 @@ import ( "github.com/ethereum/go-ethereum/core/state/snapshot" "github.com/ethereum/go-ethereum/core/vm" "github.com/ethereum/go-ethereum/eth/tracers/logger" + "github.com/ethereum/go-ethereum/log" "github.com/ethereum/go-ethereum/tests" "github.com/urfave/cli/v2" ) @@ -51,6 +52,11 @@ type StatetestResult struct { } func stateTestCmd(ctx *cli.Context) error { + // Configure the go-ethereum logger + glogger := log.NewGlogHandler(log.StreamHandler(os.Stderr, log.TerminalFormat(false))) + glogger.Verbosity(log.Lvl(ctx.Int(VerbosityFlag.Name))) + log.Root().SetHandler(glogger) + // Configure the EVM logger config := &logger.Config{ EnableMemory: !ctx.Bool(DisableMemoryFlag.Name), diff --git a/core/asm/compiler.go b/core/asm/compiler.go index 75bf726c96..4b1d379206 100644 --- a/core/asm/compiler.go +++ b/core/asm/compiler.go @@ -17,8 +17,6 @@ package asm import ( - "encoding/hex" - "errors" "fmt" "math/big" "os" @@ -32,7 +30,7 @@ import ( // and holds the tokens for the program. type Compiler struct { tokens []token - out []byte + binary []interface{} labels map[string]int @@ -52,10 +50,12 @@ func NewCompiler(debug bool) *Compiler { // Feed feeds tokens in to ch and are interpreted by // the compiler. // -// feed is the first pass in the compile stage as it collects the used labels in the -// program and keeps a program counter which is used to determine the locations of the -// jump dests. The labels can than be used in the second stage to push labels and -// determine the right position. +// feed is the first pass in the compile stage as it +// collects the used labels in the program and keeps a +// program counter which is used to determine the locations +// of the jump dests. The labels can than be used in the +// second stage to push labels and determine the right +// position. func (c *Compiler) Feed(ch <-chan token) { var prev token for i := range ch { @@ -79,6 +79,7 @@ func (c *Compiler) Feed(ch <-chan token) { c.pc++ } } + c.tokens = append(c.tokens, i) prev = i } @@ -87,11 +88,12 @@ func (c *Compiler) Feed(ch <-chan token) { } } -// Compile compiles the current tokens and returns a binary string that can be interpreted -// by the EVM and an error if it failed. +// Compile compiles the current tokens and returns a +// binary string that can be interpreted by the EVM +// and an error if it failed. // -// compile is the second stage in the compile phase which compiles the tokens to EVM -// instructions. +// compile is the second stage in the compile phase +// which compiles the tokens to EVM instructions. func (c *Compiler) Compile() (string, []error) { var errors []error // continue looping over the tokens until @@ -103,8 +105,16 @@ func (c *Compiler) Compile() (string, []error) { } // turn the binary to hex - h := hex.EncodeToString(c.out) - return h, errors + var bin strings.Builder + for _, v := range c.binary { + switch v := v.(type) { + case vm.OpCode: + bin.WriteString(fmt.Sprintf("%x", []byte{byte(v)})) + case []byte: + bin.WriteString(fmt.Sprintf("%x", v)) + } + } + return bin.String(), errors } // next returns the next token and increments the @@ -146,114 +156,87 @@ func (c *Compiler) compileLine() error { return nil } -// parseNumber compiles the number to bytes -func parseNumber(tok token) ([]byte, error) { - if tok.typ != number { - panic("parseNumber of non-number token") +// compileNumber compiles the number to bytes +func (c *Compiler) compileNumber(element token) { + num := math.MustParseBig256(element.text).Bytes() + if len(num) == 0 { + num = []byte{0} } - num, ok := math.ParseBig256(tok.text) - if !ok { - return nil, errors.New("invalid number") - } - bytes := num.Bytes() - if len(bytes) == 0 { - bytes = []byte{0} - } - return bytes, nil + c.pushBin(num) } // compileElement compiles the element (push & label or both) // to a binary representation and may error if incorrect statements // where fed. func (c *Compiler) compileElement(element token) error { - switch { - case isJump(element.text): - return c.compileJump(element.text) - case isPush(element.text): - return c.compilePush() - default: - c.outputOpcode(toBinary(element.text)) + // check for a jump. jumps must be read and compiled + // from right to left. + if isJump(element.text) { + rvalue := c.next() + switch rvalue.typ { + case number: + // TODO figure out how to return the error properly + c.compileNumber(rvalue) + case stringValue: + // strings are quoted, remove them. + c.pushBin(rvalue.text[1 : len(rvalue.text)-2]) + case label: + c.pushBin(vm.PUSH4) + pos := big.NewInt(int64(c.labels[rvalue.text])).Bytes() + pos = append(make([]byte, 4-len(pos)), pos...) + c.pushBin(pos) + case lineEnd: + c.pos-- + default: + return compileErr(rvalue, rvalue.text, "number, string or label") + } + // push the operation + c.pushBin(toBinary(element.text)) return nil - } -} + } else if isPush(element.text) { + // handle pushes. pushes are read from left to right. + var value []byte -func (c *Compiler) compileJump(jumpType string) error { - rvalue := c.next() - switch rvalue.typ { - case number: - numBytes, err := parseNumber(rvalue) - if err != nil { - return err + rvalue := c.next() + switch rvalue.typ { + case number: + value = math.MustParseBig256(rvalue.text).Bytes() + if len(value) == 0 { + value = []byte{0} + } + case stringValue: + value = []byte(rvalue.text[1 : len(rvalue.text)-1]) + case label: + value = big.NewInt(int64(c.labels[rvalue.text])).Bytes() + value = append(make([]byte, 4-len(value)), value...) + default: + return compileErr(rvalue, rvalue.text, "number, string or label") } - c.outputBytes(numBytes) - case stringValue: - // strings are quoted, remove them. - str := rvalue.text[1 : len(rvalue.text)-2] - c.outputBytes([]byte(str)) - - case label: - c.outputOpcode(vm.PUSH4) - pos := big.NewInt(int64(c.labels[rvalue.text])).Bytes() - pos = append(make([]byte, 4-len(pos)), pos...) - c.outputBytes(pos) - - case lineEnd: - // push without argument is supported, it just takes the destination from the stack. - c.pos-- - - default: - return compileErr(rvalue, rvalue.text, "number, string or label") - } - // push the operation - c.outputOpcode(toBinary(jumpType)) - return nil -} - -func (c *Compiler) compilePush() error { - // handle pushes. pushes are read from left to right. - var value []byte - rvalue := c.next() - switch rvalue.typ { - case number: - value = math.MustParseBig256(rvalue.text).Bytes() - if len(value) == 0 { - value = []byte{0} + if len(value) > 32 { + return fmt.Errorf("%d type error: unsupported string or number with size > 32", rvalue.lineno) } - case stringValue: - value = []byte(rvalue.text[1 : len(rvalue.text)-1]) - case label: - value = big.NewInt(int64(c.labels[rvalue.text])).Bytes() - value = append(make([]byte, 4-len(value)), value...) - default: - return compileErr(rvalue, rvalue.text, "number, string or label") + + c.pushBin(vm.OpCode(int(vm.PUSH1) - 1 + len(value))) + c.pushBin(value) + } else { + c.pushBin(toBinary(element.text)) } - if len(value) > 32 { - return fmt.Errorf("%d: string or number size > 32 bytes", rvalue.lineno+1) - } - c.outputOpcode(vm.OpCode(int(vm.PUSH1) - 1 + len(value))) - c.outputBytes(value) + return nil } // compileLabel pushes a jumpdest to the binary slice. func (c *Compiler) compileLabel() { - c.outputOpcode(vm.JUMPDEST) + c.pushBin(vm.JUMPDEST) } -func (c *Compiler) outputOpcode(op vm.OpCode) { +// pushBin pushes the value v to the binary stack. +func (c *Compiler) pushBin(v interface{}) { if c.debug { - fmt.Printf("%d: %v\n", len(c.out), op) + fmt.Printf("%d: %v\n", len(c.binary), v) } - c.out = append(c.out, byte(op)) -} - -// output pushes the value v to the binary stack. -func (c *Compiler) outputBytes(b []byte) { - if c.debug { - fmt.Printf("%d: %x\n", len(c.out), b) - } - c.out = append(c.out, b...) + c.binary = append(c.binary, v) } // isPush returns whether the string op is either any of @@ -280,13 +263,13 @@ type compileError struct { } func (err compileError) Error() string { - return fmt.Sprintf("%d: syntax error: unexpected %v, expected %v", err.lineno, err.got, err.want) + return fmt.Sprintf("%d syntax error: unexpected %v, expected %v", err.lineno, err.got, err.want) } func compileErr(c token, got, want string) error { return compileError{ got: got, want: want, - lineno: c.lineno + 1, + lineno: c.lineno, } } diff --git a/core/asm/compiler_test.go b/core/asm/compiler_test.go index 3d64c96bc8..ce9df436bd 100644 --- a/core/asm/compiler_test.go +++ b/core/asm/compiler_test.go @@ -54,14 +54,6 @@ func TestCompiler(t *testing.T) { `, output: "6300000006565b", }, - { - input: ` - JUMP @label -label: ;; comment - ADD ;; comment -`, - output: "6300000006565b01", - }, } for _, test := range tests { ch := Lex([]byte(test.input), false) diff --git a/core/asm/lex_test.go b/core/asm/lex_test.go index 173031521f..53e05fbbba 100644 --- a/core/asm/lex_test.go +++ b/core/asm/lex_test.go @@ -72,16 +72,6 @@ func TestLexer(t *testing.T) { input: "@label123", tokens: []token{{typ: lineStart}, {typ: label, text: "label123"}, {typ: eof}}, }, - // comment after label - { - input: "@label123 ;; comment", - tokens: []token{{typ: lineStart}, {typ: label, text: "label123"}, {typ: eof}}, - }, - // comment after instruction - { - input: "push 3 ;; comment\nadd", - tokens: []token{{typ: lineStart}, {typ: element, text: "push"}, {typ: number, text: "3"}, {typ: lineEnd, text: "\n"}, {typ: lineStart, lineno: 1}, {typ: element, lineno: 1, text: "add"}, {typ: eof, lineno: 1}}, - }, } for _, test := range tests { diff --git a/core/asm/lexer.go b/core/asm/lexer.go index e025c6f363..d1b79a1fb9 100644 --- a/core/asm/lexer.go +++ b/core/asm/lexer.go @@ -42,8 +42,6 @@ type token struct { // is able to parse and return. type tokenType int -//go:generate go run golang.org/x/tools/cmd/stringer -type tokenType - const ( eof tokenType = iota // end of file lineStart // emitted when a line starts @@ -54,13 +52,31 @@ const ( labelDef // label definition is emitted when a new label is found number // number is emitted when a number is found stringValue // stringValue is emitted when a string has been found + + Numbers = "1234567890" // characters representing any decimal number + HexadecimalNumbers = Numbers + "aAbBcCdDeEfF" // characters representing any hexadecimal + Alpha = "abcdefghijklmnopqrstuwvxyzABCDEFGHIJKLMNOPQRSTUWVXYZ" // characters representing alphanumeric ) -const ( - decimalNumbers = "1234567890" // characters representing any decimal number - hexNumbers = decimalNumbers + "aAbBcCdDeEfF" // characters representing any hexadecimal - alpha = "abcdefghijklmnopqrstuwvxyzABCDEFGHIJKLMNOPQRSTUWVXYZ" // characters representing alphanumeric -) +// String implements stringer +func (it tokenType) String() string { + if int(it) > len(stringtokenTypes) { + return "invalid" + } + return stringtokenTypes[it] +} + +var stringtokenTypes = []string{ + eof: "EOF", + lineStart: "new line", + lineEnd: "end of line", + invalidStatement: "invalid statement", + element: "element", + label: "label", + labelDef: "label definition", + number: "number", + stringValue: "string", +} // lexer is the basic construct for parsing // source code and turning them in to tokens. @@ -184,6 +200,7 @@ func lexLine(l *lexer) stateFn { l.emit(lineEnd) l.ignore() l.lineno++ + l.emit(lineStart) case r == ';' && l.peek() == ';': return lexComment @@ -208,7 +225,6 @@ func lexLine(l *lexer) stateFn { // of the line and discards the text. func lexComment(l *lexer) stateFn { l.acceptRunUntil('\n') - l.backup() l.ignore() return lexLine @@ -218,7 +234,7 @@ func lexComment(l *lexer) stateFn { // the lex text state function to advance the parsing // process. func lexLabel(l *lexer) stateFn { - l.acceptRun(alpha + "_" + decimalNumbers) + l.acceptRun(Alpha + "_" + Numbers) l.emit(label) @@ -237,9 +253,9 @@ func lexInsideString(l *lexer) stateFn { } func lexNumber(l *lexer) stateFn { - acceptance := decimalNumbers + acceptance := Numbers if l.accept("xX") { - acceptance = hexNumbers + acceptance = HexadecimalNumbers } l.acceptRun(acceptance) @@ -249,7 +265,7 @@ func lexNumber(l *lexer) stateFn { } func lexElement(l *lexer) stateFn { - l.acceptRun(alpha + "_" + decimalNumbers) + l.acceptRun(Alpha + "_" + Numbers) if l.peek() == ':' { l.emit(labelDef) diff --git a/core/asm/tokentype_string.go b/core/asm/tokentype_string.go deleted file mode 100644 index ade76aa360..0000000000 --- a/core/asm/tokentype_string.go +++ /dev/null @@ -1,31 +0,0 @@ -// Code generated by "stringer -type tokenType"; DO NOT EDIT. - -package asm - -import "strconv" - -func _() { - // An "invalid array index" compiler error signifies that the constant values have changed. - // Re-run the stringer command to generate them again. - var x [1]struct{} - _ = x[eof-0] - _ = x[lineStart-1] - _ = x[lineEnd-2] - _ = x[invalidStatement-3] - _ = x[element-4] - _ = x[label-5] - _ = x[labelDef-6] - _ = x[number-7] - _ = x[stringValue-8] -} - -const _tokenType_name = "eoflineStartlineEndinvalidStatementelementlabellabelDefnumberstringValue" - -var _tokenType_index = [...]uint8{0, 3, 12, 19, 35, 42, 47, 55, 61, 72} - -func (i tokenType) String() string { - if i < 0 || i >= tokenType(len(_tokenType_index)-1) { - return "tokenType(" + strconv.FormatInt(int64(i), 10) + ")" - } - return _tokenType_name[_tokenType_index[i]:_tokenType_index[i+1]] -}