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() == ':' {