diff --git a/cmd/easm/examples/auto_push.asm b/cmd/easm/examples/auto_push.asm deleted file mode 100644 index 7ebd5b9bea..0000000000 --- a/cmd/easm/examples/auto_push.asm +++ /dev/null @@ -1 +0,0 @@ - push 256 diff --git a/cmd/easm/examples/jump.asm b/cmd/easm/examples/jump.asm deleted file mode 100644 index 154fadcb6b..0000000000 --- a/cmd/easm/examples/jump.asm +++ /dev/null @@ -1,8 +0,0 @@ -jump @main - push 1 -other: - push 0 - push 0 - mstore -main: - push 1 diff --git a/cmd/easm/examples/large_string.asm b/cmd/easm/examples/large_string.asm deleted file mode 100644 index 8c359dbd5c..0000000000 --- a/cmd/easm/examples/large_string.asm +++ /dev/null @@ -1,2 +0,0 @@ - push "hellooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooo" - diff --git a/cmd/easm/examples/prog.asm b/cmd/easm/examples/prog.asm deleted file mode 100644 index 6b99b9ef1d..0000000000 --- a/cmd/easm/examples/prog.asm +++ /dev/null @@ -1,17 +0,0 @@ - jump @main -my_label: - push 0 - push 1 - mstore - - push 0 - push 5 - push 10 - log1 - stop -main: - push 1 - push 1 - eq - - jumpi @my_label diff --git a/cmd/easm/examples/push.asm b/cmd/easm/examples/push.asm deleted file mode 100644 index 4ae02681a7..0000000000 --- a/cmd/easm/examples/push.asm +++ /dev/null @@ -1,3 +0,0 @@ -push 1 -push 2 -add diff --git a/cmd/easm/examples/string.asm b/cmd/easm/examples/string.asm deleted file mode 100644 index b5d54cc3f9..0000000000 --- a/cmd/easm/examples/string.asm +++ /dev/null @@ -1,3 +0,0 @@ - push "hello" - push 0 - mstore diff --git a/cmd/easm/lex_test.go b/cmd/easm/lex_test.go deleted file mode 100644 index a1b513c49e..0000000000 --- a/cmd/easm/lex_test.go +++ /dev/null @@ -1,20 +0,0 @@ -package main - -import "testing" - -func lexAll(src string) []item { - ch := lex("test.asm", []byte(src), false) - - var tokens []item - for i := range ch { - tokens = append(tokens, i) - } - return tokens -} - -func TestComment(t *testing.T) { - tokens := lexAll(";; this is a comment") - if len(tokens) != 2 { // {new line, EOF} - t.Error("expected no tokens") - } -} diff --git a/cmd/evm/compiler.go b/cmd/evm/compiler.go new file mode 100644 index 0000000000..c019a2fe70 --- /dev/null +++ b/cmd/evm/compiler.go @@ -0,0 +1,55 @@ +// Copyright 2017 The go-ethereum Authors +// This file is part of go-ethereum. +// +// go-ethereum is free software: you can redistribute it and/or modify +// it under the terms of the GNU General Public License as published by +// the Free Software Foundation, either version 3 of the License, or +// (at your option) any later version. +// +// go-ethereum is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +// GNU General Public License for more details. +// +// You should have received a copy of the GNU General Public License +// along with go-ethereum. If not, see . + +package main + +import ( + "errors" + "fmt" + "io/ioutil" + + "github.com/ethereum/go-ethereum/cmd/evm/internal/compiler" + + cli "gopkg.in/urfave/cli.v1" +) + +var compileCommand = cli.Command{ + Action: compileCmd, + Name: "compile", + Usage: "compiles easm source to evm binary", + ArgsUsage: "", +} + +func compileCmd(ctx *cli.Context) error { + debug := ctx.GlobalBool(DebugFlag.Name) + + if len(ctx.Args().First()) == 0 { + return errors.New("filename required") + } + + fn := ctx.Args().First() + src, err := ioutil.ReadFile(fn) + if err != nil { + return err + } + + bin, err := compiler.Compile(fn, src, debug) + if err != nil { + return err + } + fmt.Println(bin) + return nil +} diff --git a/cmd/evm/internal/compiler/compiler.go b/cmd/evm/internal/compiler/compiler.go new file mode 100644 index 0000000000..753ca62264 --- /dev/null +++ b/cmd/evm/internal/compiler/compiler.go @@ -0,0 +1,39 @@ +// Copyright 2017 The go-ethereum Authors +// This file is part of go-ethereum. +// +// go-ethereum is free software: you can redistribute it and/or modify +// it under the terms of the GNU General Public License as published by +// the Free Software Foundation, either version 3 of the License, or +// (at your option) any later version. +// +// go-ethereum is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +// GNU General Public License for more details. +// +// You should have received a copy of the GNU General Public License +// along with go-ethereum. If not, see . + +package compiler + +import ( + "errors" + "fmt" + + "github.com/ethereum/go-ethereum/core/asm" +) + +func Compile(fn string, src []byte, debug bool) (string, error) { + compiler := asm.NewCompiler(debug) + compiler.Feed(asm.Lex(fn, src, debug)) + + bin, compileErrors := compiler.Compile() + if len(compileErrors) > 0 { + // report errors + for _, err := range compileErrors { + fmt.Printf("%s:%v\n", fn, err) + } + return "", errors.New("compiling failed") + } + return bin, nil +} diff --git a/cmd/evm/main.go b/cmd/evm/main.go index 1fe5afd2b6..5ce45b9ca6 100644 --- a/cmd/evm/main.go +++ b/cmd/evm/main.go @@ -18,21 +18,11 @@ package main import ( - "bytes" "fmt" - "io/ioutil" "math/big" "os" - goruntime "runtime" - "time" "github.com/ethereum/go-ethereum/cmd/utils" - "github.com/ethereum/go-ethereum/common" - "github.com/ethereum/go-ethereum/core/state" - "github.com/ethereum/go-ethereum/core/vm" - "github.com/ethereum/go-ethereum/core/vm/runtime" - "github.com/ethereum/go-ethereum/ethdb" - "github.com/ethereum/go-ethereum/log" "gopkg.in/urfave/cli.v1" ) @@ -109,113 +99,10 @@ func init() { InputFlag, DisableGasMeteringFlag, } - app.Action = run -} - -func run(ctx *cli.Context) error { - glogger := log.NewGlogHandler(log.StreamHandler(os.Stderr, log.TerminalFormat(false))) - glogger.Verbosity(log.Lvl(ctx.GlobalInt(VerbosityFlag.Name))) - log.Root().SetHandler(glogger) - - var ( - db, _ = ethdb.NewMemDatabase() - statedb, _ = state.New(common.Hash{}, db) - address = common.StringToAddress("sender") - sender = vm.AccountRef(address) - ) - statedb.CreateAccount(common.StringToAddress("sender")) - - logger := vm.NewStructLogger(nil) - - tstart := time.Now() - - var ( - code []byte - ret []byte - err error - ) - - if ctx.GlobalString(CodeFlag.Name) != "" { - code = common.Hex2Bytes(ctx.GlobalString(CodeFlag.Name)) - } else { - var hexcode []byte - if ctx.GlobalString(CodeFileFlag.Name) != "" { - var err error - hexcode, err = ioutil.ReadFile(ctx.GlobalString(CodeFileFlag.Name)) - if err != nil { - fmt.Printf("Could not load code from file: %v\n", err) - os.Exit(1) - } - } else { - var err error - hexcode, err = ioutil.ReadAll(os.Stdin) - if err != nil { - fmt.Printf("Could not load code from stdin: %v\n", err) - os.Exit(1) - } - } - code = common.Hex2Bytes(string(bytes.TrimRight(hexcode, "\n"))) + app.Commands = []cli.Command{ + compileCommand, + runCommand, } - - if ctx.GlobalBool(CreateFlag.Name) { - input := append(code, common.Hex2Bytes(ctx.GlobalString(InputFlag.Name))...) - ret, _, err = runtime.Create(input, &runtime.Config{ - Origin: sender.Address(), - State: statedb, - GasLimit: ctx.GlobalUint64(GasFlag.Name), - GasPrice: utils.GlobalBig(ctx, PriceFlag.Name), - Value: utils.GlobalBig(ctx, ValueFlag.Name), - EVMConfig: vm.Config{ - Tracer: logger, - Debug: ctx.GlobalBool(DebugFlag.Name), - DisableGasMetering: ctx.GlobalBool(DisableGasMeteringFlag.Name), - }, - }) - } else { - receiverAddress := common.StringToAddress("receiver") - statedb.CreateAccount(receiverAddress) - statedb.SetCode(receiverAddress, code) - - ret, err = runtime.Call(receiverAddress, common.Hex2Bytes(ctx.GlobalString(InputFlag.Name)), &runtime.Config{ - Origin: sender.Address(), - State: statedb, - GasLimit: ctx.GlobalUint64(GasFlag.Name), - GasPrice: utils.GlobalBig(ctx, PriceFlag.Name), - Value: utils.GlobalBig(ctx, ValueFlag.Name), - EVMConfig: vm.Config{ - Tracer: logger, - Debug: ctx.GlobalBool(DebugFlag.Name), - DisableGasMetering: ctx.GlobalBool(DisableGasMeteringFlag.Name), - }, - }) - } - vmdone := time.Since(tstart) - - if ctx.GlobalBool(DumpFlag.Name) { - statedb.Commit(true) - fmt.Println(string(statedb.Dump())) - } - vm.StdErrFormat(logger.StructLogs()) - - if ctx.GlobalBool(SysStatFlag.Name) { - var mem goruntime.MemStats - goruntime.ReadMemStats(&mem) - fmt.Printf("vm took %v\n", vmdone) - fmt.Printf(`alloc: %d -tot alloc: %d -no. malloc: %d -heap alloc: %d -heap objs: %d -num gc: %d -`, mem.Alloc, mem.TotalAlloc, mem.Mallocs, mem.HeapAlloc, mem.HeapObjects, mem.NumGC) - } - - fmt.Printf("OUT: 0x%x", ret) - if err != nil { - fmt.Printf(" error: %v", err) - } - fmt.Println() - return nil } func main() { diff --git a/cmd/evm/runner.go b/cmd/evm/runner.go new file mode 100644 index 0000000000..0bed46894b --- /dev/null +++ b/cmd/evm/runner.go @@ -0,0 +1,145 @@ +// Copyright 2017 The go-ethereum Authors +// This file is part of go-ethereum. +// +// go-ethereum is free software: you can redistribute it and/or modify +// it under the terms of the GNU General Public License as published by +// the Free Software Foundation, either version 3 of the License, or +// (at your option) any later version. +// +// go-ethereum is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +// GNU General Public License for more details. +// +// You should have received a copy of the GNU General Public License +// along with go-ethereum. If not, see . + +package main + +import ( + "bytes" + "fmt" + "io/ioutil" + "os" + "time" + + goruntime "runtime" + + "github.com/ethereum/go-ethereum/cmd/utils" + "github.com/ethereum/go-ethereum/common" + "github.com/ethereum/go-ethereum/core/state" + "github.com/ethereum/go-ethereum/core/vm" + "github.com/ethereum/go-ethereum/core/vm/runtime" + "github.com/ethereum/go-ethereum/ethdb" + "github.com/ethereum/go-ethereum/log" + cli "gopkg.in/urfave/cli.v1" +) + +var runCommand = cli.Command{ + Action: runCmd, + Name: "run", + Usage: "run arbitrary evm binary", + ArgsUsage: "", + Description: `The run command runs arbitrary EVM code.`, +} + +func runCmd(ctx *cli.Context) error { + glogger := log.NewGlogHandler(log.StreamHandler(os.Stderr, log.TerminalFormat(false))) + glogger.Verbosity(log.Lvl(ctx.GlobalInt(VerbosityFlag.Name))) + log.Root().SetHandler(glogger) + + var ( + db, _ = ethdb.NewMemDatabase() + statedb, _ = state.New(common.Hash{}, db) + sender = common.StringToAddress("sender") + logger = vm.NewStructLogger(nil) + tstart = time.Now() + ) + statedb.CreateAccount(sender) + + var ( + code []byte + ret []byte + err error + ) + if ctx.GlobalString(CodeFlag.Name) != "" { + code = common.Hex2Bytes(ctx.GlobalString(CodeFlag.Name)) + } else { + var hexcode []byte + if ctx.GlobalString(CodeFileFlag.Name) != "" { + var err error + hexcode, err = ioutil.ReadFile(ctx.GlobalString(CodeFileFlag.Name)) + if err != nil { + fmt.Printf("Could not load code from file: %v\n", err) + os.Exit(1) + } + } else { + var err error + hexcode, err = ioutil.ReadAll(os.Stdin) + if err != nil { + fmt.Printf("Could not load code from stdin: %v\n", err) + os.Exit(1) + } + } + code = common.Hex2Bytes(string(bytes.TrimRight(hexcode, "\n"))) + } + + if ctx.GlobalBool(CreateFlag.Name) { + input := append(code, common.Hex2Bytes(ctx.GlobalString(InputFlag.Name))...) + ret, _, err = runtime.Create(input, &runtime.Config{ + Origin: sender, + State: statedb, + GasLimit: ctx.GlobalUint64(GasFlag.Name), + GasPrice: utils.GlobalBig(ctx, PriceFlag.Name), + Value: utils.GlobalBig(ctx, ValueFlag.Name), + EVMConfig: vm.Config{ + Tracer: logger, + Debug: ctx.GlobalBool(DebugFlag.Name), + DisableGasMetering: ctx.GlobalBool(DisableGasMeteringFlag.Name), + }, + }) + } else { + receiver := common.StringToAddress("receiver") + statedb.SetCode(receiver, code) + + ret, err = runtime.Call(receiver, common.Hex2Bytes(ctx.GlobalString(InputFlag.Name)), &runtime.Config{ + Origin: sender, + State: statedb, + GasLimit: ctx.GlobalUint64(GasFlag.Name), + GasPrice: utils.GlobalBig(ctx, PriceFlag.Name), + Value: utils.GlobalBig(ctx, ValueFlag.Name), + EVMConfig: vm.Config{ + Tracer: logger, + Debug: ctx.GlobalBool(DebugFlag.Name), + DisableGasMetering: ctx.GlobalBool(DisableGasMeteringFlag.Name), + }, + }) + } + vmdone := time.Since(tstart) + + if ctx.GlobalBool(DumpFlag.Name) { + statedb.Commit(true) + fmt.Println(string(statedb.Dump())) + } + vm.StdErrFormat(logger.StructLogs()) + + if ctx.GlobalBool(SysStatFlag.Name) { + var mem goruntime.MemStats + goruntime.ReadMemStats(&mem) + fmt.Printf("vm took %v\n", vmdone) + fmt.Printf(`alloc: %d +tot alloc: %d +no. malloc: %d +heap alloc: %d +heap objs: %d +num gc: %d +`, mem.Alloc, mem.TotalAlloc, mem.Mallocs, mem.HeapAlloc, mem.HeapObjects, mem.NumGC) + } + + fmt.Printf("OUT: 0x%x", ret) + if err != nil { + fmt.Printf(" error: %v", err) + } + fmt.Println() + return nil +} diff --git a/cmd/easm/main.go b/core/asm/compiler.go similarity index 76% rename from cmd/easm/main.go rename to core/asm/compiler.go index a13039c167..b2c85375cc 100644 --- a/cmd/easm/main.go +++ b/core/asm/compiler.go @@ -1,84 +1,32 @@ -package main +// Copyright 2017 The go-ethereum Authors +// This file is part of the go-ethereum library. +// +// The go-ethereum library is free software: you can redistribute it and/or modify +// it under the terms of the GNU Lesser General Public License as published by +// the Free Software Foundation, either version 3 of the License, or +// (at your option) any later version. +// +// The go-ethereum library is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +// GNU Lesser General Public License for more details. +// +// You should have received a copy of the GNU Lesser General Public License +// along with the go-ethereum library. If not, see . + +package asm import ( "errors" "fmt" - "io/ioutil" "math/big" "os" - "path/filepath" "strings" - cli "gopkg.in/urfave/cli.v1" - - "github.com/ethereum/go-ethereum/common" + "github.com/ethereum/go-ethereum/common/math" "github.com/ethereum/go-ethereum/core/vm" - "github.com/ethereum/go-ethereum/logger/glog" ) -var ( - app *cli.App - - DebugFlag = cli.BoolFlag{ - Name: "debug", - Usage: "outputs lexer and compiler debug output", - } - LexFlag = cli.BoolFlag{ - Name: "lex", - Usage: "displays lex token output", - } -) - -func init() { - app = cli.NewApp() - app.Name = filepath.Base(os.Args[0]) - app.Author = "" - app.Email = "" - app.Version = "0.1" - - app.Flags = []cli.Flag{ - DebugFlag, - } - app.Action = run -} - -func run(ctx *cli.Context) { - var ( - debug = ctx.GlobalBool(DebugFlag.Name) - lexDebug = ctx.GlobalBool(LexFlag.Name) - ) - - if len(ctx.Args()) == 0 { - glog.Exitln("err: required") - } - - fn := ctx.Args().First() - src, err := ioutil.ReadFile(fn) - if err != nil { - glog.Exitln("err:", err) - } - - compiler := newCompiler(debug) - compiler.feed(lex(fn, src, lexDebug)) - - bin, errors := compiler.compile() - if len(errors) > 0 { - // report errors - for _, err := range errors { - fmt.Printf("%s:%v\n", fn, err) - } - os.Exit(1) - } - fmt.Println(bin) -} - -func main() { - if err := app.Run(os.Args); err != nil { - fmt.Fprintln(os.Stderr, err) - os.Exit(1) - } -} - // Compiler contains information about the parsed source // and holds the tokens for the program. type Compiler struct { @@ -93,14 +41,14 @@ type Compiler struct { } // newCompiler returns a new allocated compiler. -func newCompiler(debug bool) *Compiler { +func NewCompiler(debug bool) *Compiler { return &Compiler{ labels: make(map[string]int), debug: debug, } } -// feed feeds tokens in to ch and are interpreted by +// Feed feeds tokens in to ch and are interpreted by // the compiler. // // feed is the first pass in the compile stage as it @@ -109,11 +57,11 @@ func newCompiler(debug bool) *Compiler { // 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) { +func (c *Compiler) Feed(ch <-chan token) { for i := range ch { switch i.typ { case number: - num := common.String2Big(i.text).Bytes() + num := math.MustParseBig256(i.text).Bytes() if len(num) == 0 { num = []byte{0} } @@ -132,17 +80,17 @@ func (c *Compiler) feed(ch <-chan token) { c.tokens = append(c.tokens, i) } if c.debug { - fmt.Sprintln(os.Stderr, "found", len(c.labels), "labels") + fmt.Fprintln(os.Stderr, "found", len(c.labels), "labels") } } -// compile compiles the current tokens and returns a +// 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. -func (c *Compiler) compile() (string, []error) { +func (c *Compiler) Compile() (string, []error) { var errors []error // continue looping over the tokens until // the stack has been exhausted. @@ -206,7 +154,7 @@ func (c *Compiler) compileLine() error { // compileNumber compiles the number to bytes func (c *Compiler) compileNumber(element token) (int, error) { - num := common.String2Big(element.text).Bytes() + num := math.MustParseBig256(element.text).Bytes() if len(num) == 0 { num = []byte{0} } @@ -247,7 +195,7 @@ func (c *Compiler) compileElement(element token) error { rvalue := c.next() switch rvalue.typ { case number: - value = common.String2Big(rvalue.text).Bytes() + value = math.MustParseBig256(rvalue.text).Bytes() if len(value) == 0 { value = []byte{0} } diff --git a/core/asm/lex_test.go b/core/asm/lex_test.go new file mode 100644 index 0000000000..36e67bcf7e --- /dev/null +++ b/core/asm/lex_test.go @@ -0,0 +1,36 @@ +// Copyright 2017 The go-ethereum Authors +// This file is part of the go-ethereum library. +// +// The go-ethereum library is free software: you can redistribute it and/or modify +// it under the terms of the GNU Lesser General Public License as published by +// the Free Software Foundation, either version 3 of the License, or +// (at your option) any later version. +// +// The go-ethereum library is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +// GNU Lesser General Public License for more details. +// +// You should have received a copy of the GNU Lesser General Public License +// along with the go-ethereum library. If not, see . + +package asm + +import "testing" + +func lexAll(src string) []token { + ch := Lex("test.asm", []byte(src), false) + + var tokens []token + for i := range ch { + tokens = append(tokens, i) + } + return tokens +} + +func TestComment(t *testing.T) { + tokens := lexAll(";; this is a comment") + if len(tokens) != 2 { // {new line, EOF} + t.Error("expected no tokens") + } +} diff --git a/cmd/easm/lexer.go b/core/asm/lexer.go similarity index 78% rename from cmd/easm/lexer.go rename to core/asm/lexer.go index 7d69da4df9..2770bd35fc 100644 --- a/cmd/easm/lexer.go +++ b/core/asm/lexer.go @@ -1,4 +1,20 @@ -package main +// Copyright 2017 The go-ethereum Authors +// This file is part of the go-ethereum library. +// +// The go-ethereum library is free software: you can redistribute it and/or modify +// it under the terms of the GNU Lesser General Public License as published by +// the Free Software Foundation, either version 3 of the License, or +// (at your option) any later version. +// +// The go-ethereum library is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +// GNU Lesser General Public License for more details. +// +// You should have received a copy of the GNU Lesser General Public License +// along with the go-ethereum library. If not, see . + +package asm import ( "fmt" @@ -11,7 +27,7 @@ import ( // stateFn is used through the lifetime of the // lexer to parse the different values at the // current state. -type stateFn func(*Lexer) stateFn +type stateFn func(*lexer) stateFn // token is emitted when the lexer has discovered // a new parsable token. These are delivered over @@ -62,10 +78,10 @@ var stringtokenTypes = []string{ stringValue: "string", } -// Lexer is the basic construct for parsing +// lexer is the basic construct for parsing // source code and turning them in to tokens. // Tokens are interpreted by the compiler. -type Lexer struct { +type lexer struct { input string // input contains the source code of the program tokens chan token // tokens is used to deliver tokens to the listener @@ -79,9 +95,9 @@ type Lexer struct { // lex lexes the program by name with the given source. It returns a // channel on which the tokens are delivered. -func lex(name string, source []byte, debug bool) <-chan token { +func Lex(name string, source []byte, debug bool) <-chan token { ch := make(chan token) - l := &Lexer{ + l := &lexer{ input: string(source), tokens: ch, state: lexLine, @@ -100,7 +116,7 @@ func lex(name string, source []byte, debug bool) <-chan token { } // next returns the next rune in the program's source. -func (l *Lexer) next() (rune rune) { +func (l *lexer) next() (rune rune) { if l.pos >= len(l.input) { l.width = 0 return 0 @@ -111,24 +127,24 @@ func (l *Lexer) next() (rune rune) { } // backup backsup the last parsed element (multi-character) -func (l *Lexer) backup() { +func (l *lexer) backup() { l.pos -= l.width } // peek returns the next rune but does not advance the seeker -func (l *Lexer) peek() rune { +func (l *lexer) peek() rune { r := l.next() l.backup() return r } // ignore advances the seeker and ignores the value -func (l *Lexer) ignore() { +func (l *lexer) ignore() { l.start = l.pos } // Accepts checks whether the given input matches the next rune -func (l *Lexer) accept(valid string) bool { +func (l *lexer) accept(valid string) bool { if strings.IndexRune(valid, l.next()) >= 0 { return true } @@ -140,7 +156,7 @@ func (l *Lexer) accept(valid string) bool { // acceptRun will continue to advance the seeker until valid // can no longer be met. -func (l *Lexer) acceptRun(valid string) { +func (l *lexer) acceptRun(valid string) { for strings.IndexRune(valid, l.next()) >= 0 { } l.backup() @@ -148,7 +164,7 @@ func (l *Lexer) acceptRun(valid string) { // acceptRunUntil is the inverse of acceptRun and will continue // to advance the seeker until the rune has been found. -func (l *Lexer) acceptRunUntil(until rune) bool { +func (l *lexer) acceptRunUntil(until rune) bool { // Continues running until a rune is found for i := l.next(); strings.IndexRune(string(until), i) == -1; i = l.next() { if i == 0 { @@ -160,12 +176,12 @@ func (l *Lexer) acceptRunUntil(until rune) bool { } // blob returns the current value -func (l *Lexer) blob() string { +func (l *lexer) blob() string { return l.input[l.start:l.pos] } // Emits a new token on to token channel for processing -func (l *Lexer) emit(t tokenType) { +func (l *lexer) emit(t tokenType) { token := token{t, l.lineno, l.blob()} if l.debug { @@ -177,7 +193,7 @@ func (l *Lexer) emit(t tokenType) { } // lexLine is state function for lexing lines -func lexLine(l *Lexer) stateFn { +func lexLine(l *lexer) stateFn { for { switch r := l.next(); { case r == '\n': @@ -207,7 +223,7 @@ func lexLine(l *Lexer) stateFn { // lexComment parses the current position until the end // of the line and discards the text. -func lexComment(l *Lexer) stateFn { +func lexComment(l *lexer) stateFn { l.acceptRunUntil('\n') l.ignore() @@ -217,7 +233,7 @@ func lexComment(l *Lexer) stateFn { // lexLabel parses the current label, emits and returns // the lex text state function to advance the parsing // process. -func lexLabel(l *Lexer) stateFn { +func lexLabel(l *lexer) stateFn { l.acceptRun(Alpha + "_") l.emit(label) @@ -228,7 +244,7 @@ func lexLabel(l *Lexer) stateFn { // lexInsideString lexes the inside of a string until // until the state function finds the closing quote. // It returns the lex text state function. -func lexInsideString(l *Lexer) stateFn { +func lexInsideString(l *lexer) stateFn { if l.acceptRunUntil('"') { l.emit(stringValue) } @@ -236,7 +252,7 @@ func lexInsideString(l *Lexer) stateFn { return lexLine } -func lexNumber(l *Lexer) stateFn { +func lexNumber(l *lexer) stateFn { acceptance := Numbers if l.accept("0") && l.accept("xX") { acceptance = HexadecimalNumbers @@ -248,7 +264,7 @@ func lexNumber(l *Lexer) stateFn { return lexLine } -func lexElement(l *Lexer) stateFn { +func lexElement(l *lexer) stateFn { l.acceptRun(Alpha + "_" + Numbers) if l.peek() == ':' {