aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--cli/cmd/lex.go28
-rw-r--r--driver/lexer.go61
-rw-r--r--log/logger.go42
3 files changed, 126 insertions, 5 deletions
diff --git a/cli/cmd/lex.go b/cli/cmd/lex.go
index b16ae14..7efc814 100644
--- a/cli/cmd/lex.go
+++ b/cli/cmd/lex.go
@@ -3,8 +3,10 @@ package cmd
import (
"encoding/json"
"fmt"
+ "io"
"io/ioutil"
"os"
+ "time"
"github.com/nihei9/maleeni/driver"
"github.com/nihei9/maleeni/spec"
@@ -24,7 +26,7 @@ As use ` + "`maleeni compile`" + `, you can generate the specification.`,
rootCmd.AddCommand(cmd)
}
-func runLex(cmd *cobra.Command, args []string) error {
+func runLex(cmd *cobra.Command, args []string) (retErr error) {
var clspec *spec.CompiledLexSpec
{
clspecPath := args[0]
@@ -42,7 +44,28 @@ func runLex(cmd *cobra.Command, args []string) error {
return err
}
}
- lex, err := driver.NewLexer(clspec, os.Stdin)
+ var w io.Writer
+ {
+ f, err := os.OpenFile("maleeni-lex.log", os.O_WRONLY|os.O_CREATE|os.O_TRUNC, 0644)
+ if err != nil {
+ return err
+ }
+ defer f.Close()
+ w = f
+ }
+ fmt.Fprintf(w, `maleeni lex starts.
+Date time: %v
+---
+`, time.Now().Format(time.RFC3339))
+ defer func() {
+ fmt.Fprintf(w, "---\n")
+ if retErr != nil {
+ fmt.Fprintf(w, "maleeni lex failed: %v\n", retErr)
+ } else {
+ fmt.Fprintf(w, "maleeni lex succeeded.\n")
+ }
+ }()
+ lex, err := driver.NewLexer(clspec, os.Stdin, driver.EnableLogging(w))
if err != nil {
return err
}
@@ -61,5 +84,6 @@ func runLex(cmd *cobra.Command, args []string) error {
}
fmt.Fprintf(os.Stdout, "\"%v\"\n", string(tok.Match))
}
+
return nil
}
diff --git a/driver/lexer.go b/driver/lexer.go
index 3a6f039..750fec1 100644
--- a/driver/lexer.go
+++ b/driver/lexer.go
@@ -5,6 +5,7 @@ import (
"io"
"io/ioutil"
+ "github.com/nihei9/maleeni/log"
"github.com/nihei9/maleeni/spec"
)
@@ -24,6 +25,16 @@ func newToken(id int, kind string, match []byte) *Token {
}
}
+func (t *Token) String() string {
+ if t.Invalid {
+ return fmt.Sprintf("!{text: %v, byte: %v}", string(t.Match), t.Match)
+ }
+ if t.EOF {
+ return "{eof}"
+ }
+ return fmt.Sprintf("{id: %v, kind: %v, text: %v, byte: %v}", t.ID, t.Kind, string(t.Match), t.Match)
+}
+
func newEOFToken() *Token {
return &Token{
ID: 0,
@@ -39,51 +50,95 @@ func newInvalidToken(match []byte) *Token {
}
}
+type lexerOption func(l *lexer) error
+
+func EnableLogging(w io.Writer) lexerOption {
+ return func(l *lexer) error {
+ logger, err := log.NewLogger(w)
+ if err != nil {
+ return err
+ }
+ l.logger = logger
+ return nil
+ }
+}
+
type lexer struct {
clspec *spec.CompiledLexSpec
src []byte
srcPtr int
tokBuf []*Token
+ logger log.Logger
}
-func NewLexer(clspec *spec.CompiledLexSpec, src io.Reader) (*lexer, error) {
+func NewLexer(clspec *spec.CompiledLexSpec, src io.Reader, opts ...lexerOption) (*lexer, error) {
b, err := ioutil.ReadAll(src)
if err != nil {
return nil, err
}
- return &lexer{
+ l := &lexer{
clspec: clspec,
src: b,
srcPtr: 0,
- }, nil
+ logger: log.NewNopLogger(),
+ }
+ for _, opt := range opts {
+ err := opt(l)
+ if err != nil {
+ return nil, err
+ }
+ }
+ l.logger.Log("Initializing the lexer finished.")
+
+ return l, nil
}
func (l *lexer) Next() (*Token, error) {
+ l.logger.Log(`lexer#Next():
+ State:
+ pointer: %v
+ token buffer: %v`, l.srcPtr, l.tokBuf)
+
if len(l.tokBuf) > 0 {
tok := l.tokBuf[0]
l.tokBuf = l.tokBuf[1:]
+ l.logger.Log(` Returns a buffered token:
+ token: %v
+ token buffer: %v`, tok, l.tokBuf)
return tok, nil
}
tok, err := l.next()
if err != nil {
+ l.logger.Log(" Detectes an error: %v", err)
return nil, err
}
+ l.logger.Log(" Detects a token: %v", tok)
if !tok.Invalid {
+ l.logger.Log(` Returns a token:
+ token: %v
+ token buffer: %v`, tok, l.tokBuf)
return tok, nil
}
errTok := tok
for {
tok, err = l.next()
if err != nil {
+ l.logger.Log(" Detectes an error: %v", err)
return nil, err
}
+ l.logger.Log(" Detects a token: %v", tok)
if !tok.Invalid {
break
}
errTok.Match = append(errTok.Match, tok.Match...)
+ l.logger.Log(" error token: %v", errTok)
}
l.tokBuf = append(l.tokBuf, tok)
+ l.logger.Log(` Returns a token:
+ token: %v
+ token buffer: %v`, errTok, l.tokBuf)
+
return errTok, nil
}
diff --git a/log/logger.go b/log/logger.go
new file mode 100644
index 0000000..770f1c1
--- /dev/null
+++ b/log/logger.go
@@ -0,0 +1,42 @@
+package log
+
+import (
+ "fmt"
+ "io"
+)
+
+type Logger interface {
+ Log(format string, a ...interface{})
+}
+
+var (
+ _ Logger = &logger{}
+ _ Logger = &nopLogger{}
+)
+
+type logger struct {
+ w io.Writer
+}
+
+func NewLogger(w io.Writer) (*logger, error) {
+ if w == nil {
+ return nil, fmt.Errorf("w is nil; NewLogger() needs a writer")
+ }
+ return &logger{
+ w: w,
+ }, nil
+}
+
+func (l *logger) Log(format string, a ...interface{}) {
+ fmt.Fprintf(l.w, format+"\n", a...)
+}
+
+type nopLogger struct {
+}
+
+func NewNopLogger() *nopLogger {
+ return &nopLogger{}
+}
+
+func (l *nopLogger) Log(format string, a ...interface{}) {
+}