Further performance optimization and code cleanup.
This commit is contained in:
parent
56b8df3aab
commit
17935b7534
|
@ -67,7 +67,6 @@ func (p *API) invokeHandler(name string, tokenHandler tokenize.Handler) (int, bo
|
||||||
callerPanic(name, "parsekit.parse.API.{name}(): {name}() called with nil tokenHandler argument at {caller}")
|
callerPanic(name, "parsekit.parse.API.{name}(): {name}() called with nil tokenHandler argument at {caller}")
|
||||||
}
|
}
|
||||||
|
|
||||||
p.tokenAPI.Reset() // TODO uh, why did I do this again? Just for i.runeRead = false ?
|
|
||||||
child := p.tokenAPI.Fork()
|
child := p.tokenAPI.Fork()
|
||||||
ok := tokenHandler(p.tokenAPI)
|
ok := tokenHandler(p.tokenAPI)
|
||||||
|
|
||||||
|
|
|
@ -94,9 +94,9 @@ type stackFrame struct {
|
||||||
err error // can be used by a Handler to report a specific issue with the input
|
err error // can be used by a Handler to report a specific issue with the input
|
||||||
}
|
}
|
||||||
|
|
||||||
const initialStackDepth = 10
|
const initialStackDepth = 64
|
||||||
const initialTokenDepth = 10
|
const initialTokenStoreLength = 32
|
||||||
const initialRuneDepth = 10
|
const initialRuneStoreLength = 128
|
||||||
|
|
||||||
// NewAPI initializes a new API struct, wrapped around the provided input.
|
// NewAPI initializes a new API struct, wrapped around the provided input.
|
||||||
// For an overview of allowed inputs, take a look at the documentation
|
// For an overview of allowed inputs, take a look at the documentation
|
||||||
|
@ -104,8 +104,8 @@ const initialRuneDepth = 10
|
||||||
func NewAPI(input interface{}) *API {
|
func NewAPI(input interface{}) *API {
|
||||||
api := &API{
|
api := &API{
|
||||||
reader: read.New(input),
|
reader: read.New(input),
|
||||||
runes: make([]rune, 0, initialRuneDepth),
|
runes: make([]rune, 0, initialRuneStoreLength),
|
||||||
tokens: make([]Token, 0, initialTokenDepth),
|
tokens: make([]Token, 0, initialTokenStoreLength),
|
||||||
stackFrames: make([]stackFrame, 1, initialStackDepth),
|
stackFrames: make([]stackFrame, 1, initialStackDepth),
|
||||||
}
|
}
|
||||||
api.stackFrame = &api.stackFrames[0]
|
api.stackFrame = &api.stackFrames[0]
|
||||||
|
@ -305,6 +305,17 @@ func (i *API) Dispose(stackLevel int) {
|
||||||
|
|
||||||
func (i *API) Reset() {
|
func (i *API) Reset() {
|
||||||
i.runeRead = false
|
i.runeRead = false
|
||||||
|
if i.stackLevel == 0 {
|
||||||
|
i.stackFrame.column = 0
|
||||||
|
i.stackFrame.line = 0
|
||||||
|
i.stackFrame.offset = 0
|
||||||
|
} else {
|
||||||
|
// TODO simplify! Store line/column/offset using a 0-based index in a fork. On merge add them to the parent's offsets?
|
||||||
|
parent := i.stackFrames[i.stackLevel-1]
|
||||||
|
i.stackFrame.column = parent.column
|
||||||
|
i.stackFrame.line = parent.line
|
||||||
|
i.stackFrame.offset = parent.offset
|
||||||
|
}
|
||||||
i.stackFrame.runeEnd = i.stackFrame.runeStart
|
i.stackFrame.runeEnd = i.stackFrame.runeStart
|
||||||
i.stackFrame.tokenEnd = i.stackFrame.tokenStart
|
i.stackFrame.tokenEnd = i.stackFrame.tokenStart
|
||||||
i.stackFrame.err = nil
|
i.stackFrame.err = nil
|
||||||
|
|
|
@ -94,26 +94,27 @@ func ExampleAPI_modifyingResults() {
|
||||||
func ExampleAPI_Reset() {
|
func ExampleAPI_Reset() {
|
||||||
api := tokenize.NewAPI("Very important input!")
|
api := tokenize.NewAPI("Very important input!")
|
||||||
|
|
||||||
api.NextRune()
|
api.NextRune() // read 'V'
|
||||||
api.Accept()
|
api.Accept()
|
||||||
api.NextRune()
|
api.NextRune() // read 'e'
|
||||||
api.Accept()
|
api.Accept()
|
||||||
fmt.Printf("API results: %q at %s\n", api.String(), api.Cursor())
|
fmt.Printf("API results: %q at %s\n", api.String(), api.Cursor())
|
||||||
|
|
||||||
// Reset clears the results, but keeps the cursor position.
|
// Reset clears the results.
|
||||||
api.Reset()
|
api.Reset()
|
||||||
fmt.Printf("API results: %q at %s\n", api.String(), api.Cursor())
|
fmt.Printf("API results: %q at %s\n", api.String(), api.Cursor())
|
||||||
|
|
||||||
api.NextRune()
|
// So then doing the same read operations, the same data are read.
|
||||||
|
api.NextRune() // read 'V'
|
||||||
api.Accept()
|
api.Accept()
|
||||||
api.NextRune()
|
api.NextRune() // read 'e'
|
||||||
api.Accept()
|
api.Accept()
|
||||||
fmt.Printf("API results: %q at %s\n", api.String(), api.Cursor())
|
fmt.Printf("API results: %q at %s\n", api.String(), api.Cursor())
|
||||||
|
|
||||||
// Output:
|
// Output:
|
||||||
// API results: "Ve" at line 1, column 3
|
// API results: "Ve" at line 1, column 3
|
||||||
// API results: "" at line 1, column 3
|
// API results: "" at start of file
|
||||||
// API results: "ry" at line 1, column 5
|
// API results: "Ve" at line 1, column 3
|
||||||
}
|
}
|
||||||
|
|
||||||
func ExampleAPI_Fork() {
|
func ExampleAPI_Fork() {
|
||||||
|
@ -316,9 +317,6 @@ func TestMergeScenariosForTokens(t *testing.T) {
|
||||||
|
|
||||||
api.AddTokens(token2)
|
api.AddTokens(token2)
|
||||||
|
|
||||||
// Here we can merge by expanding the token slice on the parent,
|
|
||||||
// because the end of the parent slice and the start of the child
|
|
||||||
// slice align.
|
|
||||||
api.Merge(child)
|
api.Merge(child)
|
||||||
api.Dispose(child)
|
api.Dispose(child)
|
||||||
|
|
||||||
|
@ -330,9 +328,6 @@ func TestMergeScenariosForTokens(t *testing.T) {
|
||||||
api.Reset()
|
api.Reset()
|
||||||
api.AddTokens(token4)
|
api.AddTokens(token4)
|
||||||
|
|
||||||
// Here the merge means that token4 will be copied to the end of
|
|
||||||
// the token slice of the parent, since there's a gap at the place
|
|
||||||
// where token3 used to be.
|
|
||||||
api.Merge(child)
|
api.Merge(child)
|
||||||
api.Dispose(child)
|
api.Dispose(child)
|
||||||
|
|
||||||
|
|
|
@ -609,7 +609,7 @@ func MatchAny(handlers ...Handler) Handler {
|
||||||
t.Dispose(child)
|
t.Dispose(child)
|
||||||
return true
|
return true
|
||||||
}
|
}
|
||||||
t.Dispose(child) // TODO switch to Reset() and move forking outside the loop?
|
t.Dispose(child)
|
||||||
}
|
}
|
||||||
|
|
||||||
return false
|
return false
|
||||||
|
@ -957,91 +957,35 @@ func MatchBoolean() Handler {
|
||||||
t.accept(r1)
|
t.accept(r1)
|
||||||
return true
|
return true
|
||||||
}
|
}
|
||||||
if r1 == 't' {
|
if r1 == 't' || r1 == 'T' {
|
||||||
r2, err := t.PeekRune(1)
|
r2, _ := t.PeekRune(1)
|
||||||
if err == nil && r2 == 'r' {
|
r3, _ := t.PeekRune(2)
|
||||||
r3, err := t.PeekRune(2)
|
r4, err := t.PeekRune(3)
|
||||||
if err == nil && r3 == 'u' {
|
if err == nil && r2 == 'r' && r3 == 'u' && r4 == 'e' {
|
||||||
r4, err := t.PeekRune(3)
|
t.accept(r1, r2, r3, r4)
|
||||||
if err == nil && r4 == 'e' {
|
return true
|
||||||
t.accept(r1, r2, r3, r4)
|
}
|
||||||
return true
|
if err == nil && r1 == 'T' && r2 == 'R' && r3 == 'U' && r4 == 'E' {
|
||||||
}
|
t.accept(r1, r2, r3, r4)
|
||||||
}
|
return true
|
||||||
}
|
}
|
||||||
t.accept(r1)
|
t.accept(r1)
|
||||||
return true
|
return true
|
||||||
}
|
}
|
||||||
if r1 == 'T' {
|
|
||||||
r2, err := t.PeekRune(1)
|
if r1 == 'f' || r1 == 'F' {
|
||||||
if err == nil && r2 == 'r' {
|
r2, _ := t.PeekRune(1)
|
||||||
r3, err := t.PeekRune(2)
|
r3, _ := t.PeekRune(2)
|
||||||
if err == nil && r3 == 'u' {
|
r4, _ := t.PeekRune(3)
|
||||||
r4, err := t.PeekRune(3)
|
r5, err := t.PeekRune(4)
|
||||||
if err == nil && r4 == 'e' {
|
|
||||||
t.accept(r1, r2, r3, r4)
|
if err == nil && r2 == 'a' && r3 == 'l' && r4 == 's' && r5 == 'e' {
|
||||||
return true
|
t.accept(r1, r2, r3, r4, r5)
|
||||||
}
|
return true
|
||||||
}
|
|
||||||
}
|
}
|
||||||
if err == nil && r2 == 'R' {
|
if err == nil && r1 == 'F' && r2 == 'A' && r3 == 'L' && r4 == 'S' && r5 == 'E' {
|
||||||
r3, err := t.PeekRune(2)
|
t.accept(r1, r2, r3, r4, r5)
|
||||||
if err == nil && r3 == 'U' {
|
return true
|
||||||
r4, err := t.PeekRune(3)
|
|
||||||
if err == nil && r4 == 'E' {
|
|
||||||
t.accept(r1, r2, r3, r4)
|
|
||||||
return true
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
t.accept(r1)
|
|
||||||
return true
|
|
||||||
}
|
|
||||||
if r1 == 'f' {
|
|
||||||
r2, err := t.PeekRune(1)
|
|
||||||
if err == nil && r2 == 'a' {
|
|
||||||
r3, err := t.PeekRune(2)
|
|
||||||
if err == nil && r3 == 'l' {
|
|
||||||
r4, err := t.PeekRune(3)
|
|
||||||
if err == nil && r4 == 's' {
|
|
||||||
r5, err := t.PeekRune(4)
|
|
||||||
if err == nil && r5 == 'e' {
|
|
||||||
t.accept(r1, r2, r3, r4, r5)
|
|
||||||
return true
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
t.accept(r1)
|
|
||||||
return true
|
|
||||||
}
|
|
||||||
if r1 == 'F' {
|
|
||||||
r2, err := t.PeekRune(1)
|
|
||||||
if err == nil && r2 == 'a' {
|
|
||||||
r3, err := t.PeekRune(2)
|
|
||||||
if err == nil && r3 == 'l' {
|
|
||||||
r4, err := t.PeekRune(3)
|
|
||||||
if err == nil && r4 == 's' {
|
|
||||||
r5, err := t.PeekRune(4)
|
|
||||||
if err == nil && r5 == 'e' {
|
|
||||||
t.accept(r1, r2, r3, r4, r5)
|
|
||||||
return true
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
if err == nil && r2 == 'A' {
|
|
||||||
r3, err := t.PeekRune(2)
|
|
||||||
if err == nil && r3 == 'L' {
|
|
||||||
r4, err := t.PeekRune(3)
|
|
||||||
if err == nil && r4 == 'S' {
|
|
||||||
r5, err := t.PeekRune(4)
|
|
||||||
if err == nil && r5 == 'E' {
|
|
||||||
t.accept(r1, r2, r3, r4, r5)
|
|
||||||
return true
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
t.accept(r1)
|
t.accept(r1)
|
||||||
return true
|
return true
|
||||||
|
@ -1300,7 +1244,8 @@ func ModifyDrop(handler Handler) Handler {
|
||||||
child := t.Fork()
|
child := t.Fork()
|
||||||
if handler(t) {
|
if handler(t) {
|
||||||
// Do a partial merge: only move the cursor and read offset forward.
|
// Do a partial merge: only move the cursor and read offset forward.
|
||||||
// Otherwise we'd have to do a Reset() + Merge() call to get the same result.
|
// Any produced runes and tokens are ignored and not merged to the parent
|
||||||
|
// (since we're dropping those here).
|
||||||
parent := &t.stackFrames[t.stackLevel-1]
|
parent := &t.stackFrames[t.stackLevel-1]
|
||||||
parent.offset = t.stackFrame.offset
|
parent.offset = t.stackFrame.offset
|
||||||
parent.line = t.stackFrame.line
|
parent.line = t.stackFrame.line
|
||||||
|
|
Loading…
Reference in New Issue