Speed improvement work.

This commit is contained in:
Maurice Makaay 2019-07-08 21:57:32 +00:00
parent 5fa0b5eace
commit 7795588fe6
2 changed files with 40 additions and 33 deletions

View File

@ -68,14 +68,23 @@ import (
// can lead to hard to track bugs. I much prefer this forking method, since // can lead to hard to track bugs. I much prefer this forking method, since
// no bookkeeping has to be implemented when implementing a parser. // no bookkeeping has to be implemented when implementing a parser.
type API struct { type API struct {
state *apiState // shared API state data reader *read.Buffer // the input data reader
stackLevel int // the stack level for this API object lastRune rune // the rune as retrieved by the last NextRune() calll
lastRuneErr error // the error for the last NextRune() call
runeRead bool // whether or not a rune was read using NextRune()
runes []rune // the rune stack
tokens []Token // the token stack
runeStart int
runeEnd int
tokenStart int
tokenEnd int
stackLevel int // the stack level for this API object
state *apiState // shared API state data
} }
type apiState struct { type apiState struct {
reader *read.Buffer stack []Result // the stack, used for forking / merging the API.
stack []Result // the stack, used for forking / merging the API. top int // the index of the current top item in the stack
top int // the index of the current top item in the stack
} }
// initialAPIstackDepth determines the initial stack depth for the API. // initialAPIstackDepth determines the initial stack depth for the API.
@ -90,10 +99,14 @@ const initialAPIstackDepth = 10
func NewAPI(input interface{}) API { func NewAPI(input interface{}) API {
stack := make([]Result, 1, initialAPIstackDepth) stack := make([]Result, 1, initialAPIstackDepth)
state := apiState{ state := apiState{
reader: read.New(input), stack: stack,
stack: stack, }
return API{
runes: make([]rune, initialAPIstackDepth),
tokens: make([]Token, initialAPIstackDepth),
reader: read.New(input),
state: &state,
} }
return API{state: &state}
} }
// NextRune returns the rune at the current read offset. // NextRune returns the rune at the current read offset.
@ -114,15 +127,15 @@ func (i *API) NextRune() (rune, error) {
} }
result := &(i.state.stack[i.stackLevel]) result := &(i.state.stack[i.stackLevel])
if result.runeRead { if i.runeRead {
callerPanic("NextRune", "tokenize.API.{name}(): {name}() called at {caller} "+ callerPanic("NextRune", "tokenize.API.{name}(): {name}() called at {caller} "+
"without a prior call to Accept()") "without a prior call to Accept()")
} }
readRune, err := i.state.reader.RuneAt(result.offset) readRune, err := i.reader.RuneAt(result.offset)
result.lastRune.r = readRune i.lastRune = readRune
result.lastRune.err = err i.lastRuneErr = err
result.runeRead = true i.runeRead = true
i.DisposeChilds() i.DisposeChilds()
@ -142,16 +155,16 @@ func (i *API) Accept() {
} }
result := &(i.state.stack[i.stackLevel]) result := &(i.state.stack[i.stackLevel])
if !result.runeRead { if !i.runeRead {
callerPanic("Accept", "tokenize.API.{name}(): {name}() called at {caller} without first calling NextRune()") callerPanic("Accept", "tokenize.API.{name}(): {name}() called at {caller} without first calling NextRune()")
} else if result.lastRune.err != nil { } else if i.lastRuneErr != nil {
callerPanic("Accept", "tokenize.API.{name}(): {name}() called at {caller}, but the prior call to NextRune() failed") callerPanic("Accept", "tokenize.API.{name}(): {name}() called at {caller}, but the prior call to NextRune() failed")
} }
result.runes = append(result.runes, result.lastRune.r) result.runes = append(result.runes, i.lastRune)
result.cursor.moveByRune(result.lastRune.r) result.cursor.moveByRune(i.lastRune)
result.offset++ result.offset++
result.runeRead = false i.runeRead = false
} }
// Fork forks off a child of the API struct. It will reuse the same // Fork forks off a child of the API struct. It will reuse the same
@ -194,6 +207,7 @@ func (i *API) Fork() API {
child := API{ child := API{
state: i.state, state: i.state,
stackLevel: i.stackLevel + 1, stackLevel: i.stackLevel + 1,
reader: i.reader,
} }
childResult := Result{ childResult := Result{
cursor: result.cursor, cursor: result.cursor,
@ -203,7 +217,7 @@ func (i *API) Fork() API {
//i.state.stack[i.stackLevel+1] = childResult //i.state.stack[i.stackLevel+1] = childResult
// Invalidate parent's last read rune. // Invalidate parent's last read rune.
result.runeRead = false i.runeRead = false
i.state.top = child.stackLevel i.state.top = child.stackLevel
@ -264,7 +278,7 @@ func (i *API) DisposeChilds() {
func (i *API) Reset() { func (i *API) Reset() {
result := &(i.state.stack[i.stackLevel]) result := &(i.state.stack[i.stackLevel])
result.runeRead = false i.runeRead = false
result.runes = result.runes[:0] result.runes = result.runes[:0]
result.tokens = result.tokens[:0] result.tokens = result.tokens[:0]
result.err = nil result.err = nil
@ -280,7 +294,7 @@ func (i *API) Reset() {
func (i API) FlushInput() bool { func (i API) FlushInput() bool {
result := &(i.state.stack[i.stackLevel]) result := &(i.state.stack[i.stackLevel])
if result.offset > 0 { if result.offset > 0 {
i.state.reader.Flush(result.offset) i.reader.Flush(result.offset)
result.offset = 0 result.offset = 0
return true return true
} }

View File

@ -8,18 +8,11 @@ import (
// by a tokenize.Handler. It also provides the API that Handlers and Parsers // by a tokenize.Handler. It also provides the API that Handlers and Parsers
// can use to store and retrieve the results. // can use to store and retrieve the results.
type Result struct { type Result struct {
lastRune runeInfo // information about the last rune read using NextRune() runes []rune // runes as added to the result by tokenize.Handler functions
runeRead bool // whether or not a rune was read using NextRune() tokens []Token // Tokens as added to the result by tokenize.Handler functions
runes []rune // runes as added to the result by tokenize.Handler functions cursor Cursor // current read cursor position, relative to the start of the file
tokens []Token // Tokens as added to the result by tokenize.Handler functions offset int // current rune offset relative to the Reader's sliding window
cursor Cursor // current read cursor position, relative to the start of the file err error // can be used by a Handler to report a specific issue with the input
offset int // current rune offset relative to the Reader's sliding window
err error // can be used by a Handler to report a specific issue with the input
}
type runeInfo struct {
r rune
err error
} }
// Token defines a lexical token as produced by tokenize.Handlers. // Token defines a lexical token as produced by tokenize.Handlers.