Backup work for next refactoring step.

This commit is contained in:
Maurice Makaay 2019-07-22 22:16:28 +00:00
parent 070e6a13a7
commit cf679b2225
11 changed files with 277 additions and 330 deletions

View File

@ -30,9 +30,8 @@ func (p *API) Peek(tokenHandler tokenize.Handler) bool {
forkedAPI, ok := p.invokeHandler("Peek", tokenHandler) forkedAPI, ok := p.invokeHandler("Peek", tokenHandler)
t := p.tokenAPI t := p.tokenAPI
if ok { if ok {
r := p.Result p.Result.Tokens = t.Output.Tokens()
r.Tokens = t.Output.Tokens() p.Result.Runes = t.Output.Runes()
r.Runes = t.Output.Runes()
} }
t.Dispose(forkedAPI) t.Dispose(forkedAPI)
return ok return ok
@ -44,16 +43,13 @@ func (p *API) Peek(tokenHandler tokenize.Handler) bool {
// and the read cursor will stay at the same position. // and the read cursor will stay at the same position.
// //
// After calling this method, you can retrieve the results using the Result() method. // After calling this method, you can retrieve the results using the Result() method.
// TODO lessen indirection by introducing a := p.tokenAPI (maybe some other parser funcs too?)
// TODO Eh why keep these results all the time? Same for Peek!
func (p *API) Accept(tokenHandler tokenize.Handler) bool { func (p *API) Accept(tokenHandler tokenize.Handler) bool {
t := p.tokenAPI t := p.tokenAPI
forkedAPI, ok := p.invokeHandler("Accept", tokenHandler) forkedAPI, ok := p.invokeHandler("Accept", tokenHandler)
if ok { if ok {
// Keep track of the results. // Keep track of the results as produced by this child.
r := p.Result p.Result.Tokens = t.Output.Tokens()
r.Tokens = t.Output.Tokens() p.Result.Runes = t.Output.Runes()
r.Runes = t.Output.Runes()
// Merge to the parent level. // Merge to the parent level.
t.Merge(forkedAPI) t.Merge(forkedAPI)

View File

@ -76,10 +76,10 @@ type API struct {
stackFrames []stackFrame // the stack frames, containing stack level-specific data stackFrames []stackFrame // the stack frames, containing stack level-specific data
stackLevel int // the current stack level stackLevel int // the current stack level
stackFrame *stackFrame // the current stack frame stackFrame *stackFrame // the current stack frame
Byte ByteMode // byte-mode operations
Input *Input // provides input-related functionality
reader *read.Buffer // the buffered input reader reader *read.Buffer // the buffered input reader
Output *Output // provides output-related functionality Byte ByteMode // access to a set of byte-based input methods
Rune RuneMode // access to a set of rune-based input methods
Output Output // provides output-related functionality
outputTokens []Token // accepted tokens outputTokens []Token // accepted tokens
outputData []byte // accepted data outputData []byte // accepted data
} }
@ -110,8 +110,8 @@ func NewAPI(input interface{}) *API {
stackFrames: make([]stackFrame, initialStackDepth), stackFrames: make([]stackFrame, initialStackDepth),
} }
api.Byte = ByteMode{api: api} api.Byte = ByteMode{api: api}
api.Input = &Input{api: api} api.Rune = RuneMode{api: api}
api.Output = &Output{api: api} api.Output = Output{api: api}
api.stackFrame = &api.stackFrames[0] api.stackFrame = &api.stackFrames[0]
return api return api

View File

@ -1,6 +1,6 @@
package tokenize package tokenize
// Input provides input-related functionality for the tokenize API. // ByteMode provides byte-driven input/output functionality for the tokenize API.
type ByteMode struct { type ByteMode struct {
api *API api *API
} }
@ -87,6 +87,6 @@ func (api *API) dataAddByte(b byte) {
} }
func (api *API) dataSetBytes(bytes ...byte) { func (api *API) dataSetBytes(bytes ...byte) {
api.dataClear() api.Output.ClearData()
api.Byte.AppendMulti(bytes...) api.Byte.AppendMulti(bytes...)
} }

View File

@ -9,152 +9,110 @@ type Output struct {
api *API api *API
} }
func (o *Output) String() string { func (o Output) String() string {
return o.api.dataAsString() a := o.api
} f := a.stackFrame
func (api *API) dataAsString() string { bytes := a.outputData[f.bytesStart:f.bytesEnd]
bytes := api.outputData[api.stackFrame.bytesStart:api.stackFrame.bytesEnd]
return string(bytes) return string(bytes)
} }
func (o *Output) Runes() []rune { func (o Output) Runes() []rune {
return o.api.dataAsRunes() return []rune(o.String())
} }
func (api *API) dataAsRunes() []rune { func (o Output) Rune(offset int) rune {
bytes := api.outputData[api.stackFrame.bytesStart:api.stackFrame.bytesEnd] a := o.api
return []rune(string(bytes)) r, _ := utf8.DecodeRune(a.outputData[a.stackFrame.bytesStart+offset:])
}
func (o *Output) Rune(offset int) rune {
return o.api.dataRune(offset)
}
func (api *API) dataRune(offset int) rune {
r, _ := utf8.DecodeRune(api.outputData[api.stackFrame.bytesStart+offset:])
return r return r
} }
func (o *Output) ClearData() { func (o Output) ClearData() {
o.api.dataClear() f := o.api.stackFrame
f.bytesEnd = f.bytesStart
} }
func (api *API) dataClear() { func (o Output) SetBytes(bytes ...byte) {
api.stackFrame.bytesEnd = api.stackFrame.bytesStart o.ClearData()
}
func (o *Output) SetBytes(bytes ...byte) {
o.api.dataSetBytes(bytes...) o.api.dataSetBytes(bytes...)
} }
func (o *Output) AddByte(b byte) { func (o Output) AddByte(b byte) {
o.api.dataAddByte(b) o.api.dataAddByte(b)
} }
func (o *Output) AddBytes(bytes ...byte) { func (o Output) AddBytes(bytes ...byte) {
o.api.Byte.AppendMulti(bytes...) o.api.Byte.AppendMulti(bytes...)
} }
func (o *Output) SetRunes(runes ...rune) { func (o Output) SetRunes(runes ...rune) {
o.api.dataSetRunes(runes...) o.ClearData()
o.AddRunes(runes...)
} }
func (api *API) dataSetRunes(runes ...rune) { func (o Output) AddRunes(runes ...rune) {
api.dataClear() a := o.api
api.dataAddRunes(runes...) f := a.stackFrame
}
func (o *Output) AddRunes(runes ...rune) {
o.api.dataAddRunes(runes...)
}
func (api *API) dataAddRunes(runes ...rune) {
runesAsString := string(runes) runesAsString := string(runes)
newBytesEnd := api.stackFrame.bytesEnd + len(runesAsString) newBytesEnd := f.bytesEnd + len(runesAsString)
api.growOutputData(newBytesEnd) a.growOutputData(newBytesEnd)
copy(api.outputData[api.stackFrame.bytesEnd:], runesAsString) copy(a.outputData[f.bytesEnd:], runesAsString)
api.stackFrame.bytesEnd = newBytesEnd f.bytesEnd = newBytesEnd
} }
func (o *Output) AddString(s string) { func (o Output) AddString(s string) {
o.api.dataAddString(s) o.api.Byte.AppendMulti([]byte(s)...)
} }
func (api *API) dataAddString(s string) { func (o Output) SetString(s string) {
api.Byte.AppendMulti([]byte(s)...) o.ClearData()
o.AddBytes([]byte(s)...)
} }
func (o *Output) SetString(s string) { func (o Output) Tokens() []Token {
o.api.dataSetString(s) a := o.api
f := a.stackFrame
return a.outputTokens[f.tokenStart:f.tokenEnd]
} }
func (api *API) dataSetString(s string) { func (o Output) Token(offset int) Token {
api.dataClear() a := o.api
api.dataSetBytes([]byte(s)...) return a.outputTokens[a.stackFrame.tokenStart+offset]
} }
func (o *Output) Tokens() []Token { func (o Output) TokenValue(offset int) interface{} {
return o.api.tokens() a := o.api
return a.outputTokens[a.stackFrame.tokenStart+offset].Value
} }
func (api *API) tokens() []Token { func (o Output) ClearTokens() {
return api.outputTokens[api.stackFrame.tokenStart:api.stackFrame.tokenEnd] f := o.api.stackFrame
f.tokenEnd = f.tokenStart
} }
func (o *Output) Token(offset int) Token { func (o Output) SetTokens(tokens ...Token) {
return o.api.token(offset) o.ClearTokens()
o.AddTokens(tokens...)
} }
func (api *API) token(offset int) Token { func (o Output) AddToken(token Token) {
return api.outputTokens[api.stackFrame.tokenStart+offset] a := o.api
f := a.stackFrame
tokenEnd := f.tokenEnd
a.growOutputTokens(tokenEnd + 1)
a.outputTokens[tokenEnd] = token
f.tokenEnd++
} }
func (o *Output) TokenValue(offset int) interface{} { func (o Output) AddTokens(tokens ...Token) {
return o.api.tokenValue(offset) a := o.api
} f := a.stackFrame
a.growOutputTokens(f.tokenEnd + len(tokens))
func (api *API) tokenValue(offset int) interface{} { for _, t := range tokens {
return api.outputTokens[api.stackFrame.tokenStart+offset].Value a.outputTokens[f.tokenEnd] = t
} f.tokenEnd++
func (o *Output) ClearTokens() {
o.api.tokensClear()
}
func (api *API) tokensClear() {
api.stackFrame.tokenEnd = api.stackFrame.tokenStart
}
func (o *Output) SetTokens(tokens ...Token) {
o.api.tokensSet(tokens...)
}
func (api *API) tokensSet(tokens ...Token) {
api.tokensClear()
api.tokensAdd(tokens...)
type Func func(input interface{}) (*Result, error)
// Result holds the runes and tokens as produced by the tokenizer.
type Result struct {
Tokens []Token
Runes []rune
} }
} }
func (o *Output) AddTokens(tokens ...Token) {
o.api.tokensAdd(tokens...)
}
func (api *API) tokensAdd(tokens ...Token) {
// Grow the tokens capacity when needed.
newTokenEnd := api.stackFrame.tokenEnd + len(tokens)
api.growOutputTokens(newTokenEnd)
for offset, t := range tokens {
api.outputTokens[api.stackFrame.tokenEnd+offset] = t
}
api.stackFrame.tokenEnd = newTokenEnd
}
func (api *API) growOutputTokens(requiredTokens int) { func (api *API) growOutputTokens(requiredTokens int) {
if cap(api.outputTokens) < requiredTokens { if cap(api.outputTokens) < requiredTokens {
newTokens := make([]Token, requiredTokens*2) newTokens := make([]Token, requiredTokens*2)

View File

@ -4,12 +4,12 @@ import (
"unicode/utf8" "unicode/utf8"
) )
// Input provides input-related functionality for the tokenize API. // RuneMode provides (UTF8) rune-driven input/output functionality for the tokenize API.
type Input struct { type RuneMode struct {
api *API api *API
} }
// PeekRune returns the UTF8 rune at the provided byte offset, including its byte width. // Peek returns the UTF8 rune at the provided byte offset, including its byte width.
// //
// The byte width is useful to know what byte offset you'll have to use to peek // The byte width is useful to know what byte offset you'll have to use to peek
// the next byte or rune. Some UTF8 runes take up 4 bytes of data, so when the // the next byte or rune. Some UTF8 runes take up 4 bytes of data, so when the
@ -22,15 +22,12 @@ type Input struct {
// When an error occurs during reading the input, an error will be returned. // When an error occurs during reading the input, an error will be returned.
// When an offset is requested that is beyond the length of the available input // When an offset is requested that is beyond the length of the available input
// data, then the error will be io.EOF. // data, then the error will be io.EOF.
func (i *Input) PeekRune(offset int) (rune, int, error) { func (runeMode RuneMode) Peek(offset int) (rune, int, error) {
return i.api.peekRune(offset) a := runeMode.api
return a.reader.RuneAt(a.stackFrame.offset + offset)
} }
func (api *API) peekRune(offset int) (rune, int, error) { // Skip is used to skip over a single rune that was read from the input.
return api.reader.RuneAt(api.stackFrame.offset + offset)
}
// SkipRune is used to skip over a single rune that was read from the input.
// This tells the tokenizer: "I've seen this rune. It is of no interest. // This tells the tokenizer: "I've seen this rune. It is of no interest.
// I will now continue reading after this rune." // I will now continue reading after this rune."
// //
@ -40,16 +37,13 @@ func (api *API) peekRune(offset int) (rune, int, error) {
// //
// After the call, byte offset 0 for PeekByte() and PeekRune() will point at // After the call, byte offset 0 for PeekByte() and PeekRune() will point at
// the first byte after the skipped rune. // the first byte after the skipped rune.
func (i *Input) SkipRune(r rune) { func (runeMode *RuneMode) Skip(r rune) {
i.api.skipRune(r) f := runeMode.api.stackFrame
f.moveCursorByRune(r)
f.offset += utf8.RuneLen(r)
} }
func (api *API) skipRune(r rune) { // SkipMulti is used to skip over one or more runes that were read from the input.
api.stackFrame.moveCursorByRune(r)
api.stackFrame.offset += utf8.RuneLen(r)
}
// SkipRunes is used to skip over one or more runes that were read from the input.
// This tells the tokenizer: "I've seen these runes. They are of no interest. // This tells the tokenizer: "I've seen these runes. They are of no interest.
// I will now continue reading after these runes." // I will now continue reading after these runes."
// //
@ -59,18 +53,15 @@ func (api *API) skipRune(r rune) {
// //
// After the call, byte offset 0 for PeekByte() and PeekRune() will point at // After the call, byte offset 0 for PeekByte() and PeekRune() will point at
// the first byte after the skipped runes. // the first byte after the skipped runes.
func (i *Input) SkipRunes(runes ...rune) { func (runeMode *RuneMode) SkipMulti(runes ...rune) {
i.api.skipRunes(runes...) f := runeMode.api.stackFrame
}
func (api *API) skipRunes(runes ...rune) {
for _, r := range runes { for _, r := range runes {
api.stackFrame.moveCursorByRune(r) f.moveCursorByRune(r)
api.stackFrame.offset += utf8.RuneLen(r) f.offset += utf8.RuneLen(r)
} }
} }
// AcceptRune is used to accept a single rune that was read from the input. // Accept is used to accept a single rune that was read from the input.
// This tells the tokenizer: "I've seen this rune. I want to make use of it // This tells the tokenizer: "I've seen this rune. I want to make use of it
// for the final output, so please remember it for me. I will now continue // for the final output, so please remember it for me. I will now continue
// reading after this rune." // reading after this rune."
@ -81,23 +72,21 @@ func (api *API) skipRunes(runes ...rune) {
// //
// After the call, byte offset 0 for PeekByte() and PeekRune() will point at // After the call, byte offset 0 for PeekByte() and PeekRune() will point at
// the first byte after the accepted rune. // the first byte after the accepted rune.
func (i *Input) AcceptRune(r rune) { func (runeMode *RuneMode) Accept(r rune) {
i.api.acceptRune(r) a := runeMode.api
} f := a.stackFrame
curBytesEnd := f.bytesEnd
func (api *API) acceptRune(r rune) {
curBytesEnd := api.stackFrame.bytesEnd
maxRequiredBytes := curBytesEnd + utf8.UTFMax maxRequiredBytes := curBytesEnd + utf8.UTFMax
api.growOutputData(maxRequiredBytes) a.growOutputData(maxRequiredBytes)
w := utf8.EncodeRune(api.outputData[curBytesEnd:], r) w := utf8.EncodeRune(a.outputData[curBytesEnd:], r)
api.stackFrame.bytesEnd += w f.bytesEnd += w
api.stackFrame.offset += w f.offset += w
api.stackFrame.moveCursorByRune(r) f.moveCursorByRune(r)
} }
// AcceptRunes is used to accept one or more runes that were read from the input. // AcceptMulti is used to accept one or more runes that were read from the input.
// This tells the tokenizer: "I've seen these runes. I want to make use of them // This tells the tokenizer: "I've seen these runes. I want to make use of them
// for the final output, so please remember them for me. I will now continue // for the final output, so please remember them for me. I will now continue
// reading after these runes." // reading after these runes."
@ -108,22 +97,20 @@ func (api *API) acceptRune(r rune) {
// //
// After the call, byte offset 0 for PeekByte() and PeekRune() will point at // After the call, byte offset 0 for PeekByte() and PeekRune() will point at
// the first byte after the accepted runes. // the first byte after the accepted runes.
func (i *Input) AcceptRunes(runes ...rune) { func (runeMode *RuneMode) AcceptMulti(runes ...rune) {
i.api.acceptRunes(runes...) a := runeMode.api
} f := a.stackFrame
func (api *API) acceptRunes(runes ...rune) {
runesAsString := string(runes) runesAsString := string(runes)
byteLen := len(runesAsString) byteLen := len(runesAsString)
curBytesEnd := api.stackFrame.bytesEnd curBytesEnd := f.bytesEnd
newBytesEnd := curBytesEnd + byteLen newBytesEnd := curBytesEnd + byteLen
api.growOutputData(newBytesEnd) a.growOutputData(newBytesEnd)
copy(api.outputData[curBytesEnd:], runesAsString) copy(a.outputData[curBytesEnd:], runesAsString)
api.stackFrame.bytesEnd = newBytesEnd f.bytesEnd = newBytesEnd
api.stackFrame.offset += byteLen f.offset += byteLen
for _, r := range runes { for _, r := range runes {
api.stackFrame.moveCursorByRune(r) f.moveCursorByRune(r)
} }
} }

View File

@ -15,10 +15,10 @@ func ExampleNewAPI() {
func ExampleAPI_PeekByte() { func ExampleAPI_PeekByte() {
api := tokenize.NewAPI("The input that the API will handle") api := tokenize.NewAPI("The input that the API will handle")
r1, _, err := api.Input.PeekRune(19) // 'A', r1, _, err := api.Rune.Peek(19) // 'A',
r2, _, err := api.Input.PeekRune(20) // 'P' r2, _, err := api.Rune.Peek(20) // 'P'
r3, _, err := api.Input.PeekRune(21) // 'I' r3, _, err := api.Rune.Peek(21) // 'I'
_, _, err = api.Input.PeekRune(100) // EOF _, _, err = api.Rune.Peek(100) // EOF
fmt.Printf("%c%c%c %s\n", r1, r2, r3, err) fmt.Printf("%c%c%c %s\n", r1, r2, r3, err)
@ -29,10 +29,10 @@ func ExampleAPI_PeekByte() {
func ExampleAPI_PeekRune() { func ExampleAPI_PeekRune() {
api := tokenize.NewAPI("The input that the ДPI will handle") api := tokenize.NewAPI("The input that the ДPI will handle")
r1, _, err := api.Input.PeekRune(19) // 'Д', 2 bytes so next rune starts at 21 r1, _, err := api.Rune.Peek(19) // 'Д', 2 bytes so next rune starts at 21
r2, _, err := api.Input.PeekRune(21) // 'P' r2, _, err := api.Rune.Peek(21) // 'P'
r3, _, err := api.Input.PeekRune(22) // 'I' r3, _, err := api.Rune.Peek(22) // 'I'
_, _, err = api.Input.PeekRune(100) // EOF _, _, err = api.Rune.Peek(100) // EOF
fmt.Printf("%c%c%c %s\n", r1, r2, r3, err) fmt.Printf("%c%c%c %s\n", r1, r2, r3, err)
@ -44,15 +44,15 @@ func ExampleAPI_AcceptRune() {
api := tokenize.NewAPI("The input that the ДPI will handle") api := tokenize.NewAPI("The input that the ДPI will handle")
// Reads 'T' and accepts it to the API output data. // Reads 'T' and accepts it to the API output data.
r, _, _ := api.Input.PeekRune(0) r, _, _ := api.Rune.Peek(0)
api.Input.AcceptRune(r) api.Rune.Accept(r)
// Reads 'h' and accepts it to the API output data. // Reads 'h' and accepts it to the API output data.
r, _, _ = api.Input.PeekRune(0) r, _, _ = api.Rune.Peek(0)
api.Input.AcceptRune(r) api.Rune.Accept(r)
// Reads 'e', but does not accept it to the API output data. // Reads 'e', but does not accept it to the API output data.
r, _, _ = api.Input.PeekRune(0) r, _, _ = api.Rune.Peek(0)
fmt.Printf("API results: %q\n", api.Output.String()) fmt.Printf("API results: %q\n", api.Output.String())
@ -64,14 +64,14 @@ func ExampleAPI_AcceptRunes() {
api := tokenize.NewAPI("The input that the API will handle") api := tokenize.NewAPI("The input that the API will handle")
// Peeks at the first two runes 'T' and 'h'. // Peeks at the first two runes 'T' and 'h'.
r0, _, _ := api.Input.PeekRune(0) r0, _, _ := api.Rune.Peek(0)
r1, _, _ := api.Input.PeekRune(1) r1, _, _ := api.Rune.Peek(1)
// Peeks at the third rune 'e'. // Peeks at the third rune 'e'.
api.Input.PeekRune(2) api.Rune.Peek(2)
// Accepts only 'T' and 'h' into the API results. // Accepts only 'T' and 'h' into the API results.
api.Input.AcceptRunes(r0, r1) api.Rune.AcceptMulti(r0, r1)
fmt.Printf("API results: %q\n", api.Output.String()) fmt.Printf("API results: %q\n", api.Output.String())
@ -83,7 +83,7 @@ func ExampleAPI_SkipRune() {
api := tokenize.NewAPI("The input that the API will handle") api := tokenize.NewAPI("The input that the API will handle")
for { for {
r, _, err := api.Input.PeekRune(0) r, _, err := api.Rune.Peek(0)
// EOF reached. // EOF reached.
if err != nil { if err != nil {
@ -92,9 +92,9 @@ func ExampleAPI_SkipRune() {
// Only accept runes that are vowels. // Only accept runes that are vowels.
if strings.ContainsRune("aeiouAEIOU", r) { if strings.ContainsRune("aeiouAEIOU", r) {
api.Input.AcceptRune(r) api.Rune.Accept(r)
} else { } else {
api.Input.SkipRune(r) api.Rune.Skip(r)
} }
} }
@ -122,10 +122,10 @@ func ExampleAPI_modifyingResults() {
fmt.Printf("API result runes: %q\n", api.Output.Runes()) fmt.Printf("API result runes: %q\n", api.Output.Runes())
fmt.Printf("API third rune: %q\n", api.Output.Rune(2)) fmt.Printf("API third rune: %q\n", api.Output.Rune(2))
api.Output.AddTokens(tokenize.Token{ api.Output.AddToken(tokenize.Token{
Type: 42, Type: 42,
Value: "towel"}) Value: "towel"})
api.Output.AddTokens(tokenize.Token{ api.Output.AddToken(tokenize.Token{
Type: 73, Type: 73,
Value: "Zaphod"}) Value: "Zaphod"})
fmt.Printf("API result tokens: %v\n", api.Output.Tokens()) fmt.Printf("API result tokens: %v\n", api.Output.Tokens())
@ -144,10 +144,10 @@ func ExampleAPI_modifyingResults() {
func ExampleAPI_Reset() { func ExampleAPI_Reset() {
api := tokenize.NewAPI("Very important input!") api := tokenize.NewAPI("Very important input!")
r, _, _ := api.Input.PeekRune(0) // read 'V' r, _, _ := api.Rune.Peek(0) // read 'V'
api.Input.AcceptRune(r) api.Rune.Accept(r)
r, _, _ = api.Input.PeekRune(0) // read 'e' r, _, _ = api.Rune.Peek(0) // read 'e'
api.Input.AcceptRune(r) api.Rune.Accept(r)
fmt.Printf("API results: %q at %s\n", api.Output.String(), api.Cursor()) fmt.Printf("API results: %q at %s\n", api.Output.String(), api.Cursor())
// Reset clears the results. // Reset clears the results.
@ -155,10 +155,10 @@ func ExampleAPI_Reset() {
fmt.Printf("API results: %q at %s\n", api.Output.String(), api.Cursor()) fmt.Printf("API results: %q at %s\n", api.Output.String(), api.Cursor())
// So then doing the same read operations, the same data are read. // So then doing the same read operations, the same data are read.
r, _, _ = api.Input.PeekRune(0) // read 'V' r, _, _ = api.Rune.Peek(0) // read 'V'
api.Input.AcceptRune(r) api.Rune.Accept(r)
r, _, _ = api.Input.PeekRune(0) // read 'e' r, _, _ = api.Rune.Peek(0) // read 'e'
api.Input.AcceptRune(r) api.Rune.Accept(r)
fmt.Printf("API results: %q at %s\n", api.Output.String(), api.Cursor()) fmt.Printf("API results: %q at %s\n", api.Output.String(), api.Cursor())
// Output: // Output:
@ -210,14 +210,14 @@ func ExampleAPI_Fork() {
func ExampleAPI_Merge() { func ExampleAPI_Merge() {
tokenHandler := func(t *tokenize.API) bool { tokenHandler := func(t *tokenize.API) bool {
child1 := t.Fork() child1 := t.Fork()
r0, _, _ := t.Input.PeekRune(0) // reads 'H' r0, _, _ := t.Rune.Peek(0) // reads 'H'
r1, _, _ := t.Input.PeekRune(1) // reads 'i' r1, _, _ := t.Rune.Peek(1) // reads 'i'
t.Input.AcceptRunes(r0, r1) // these runes are accepted in the API results for child1 t.Rune.AcceptMulti(r0, r1) // these runes are accepted in the API results for child1
child2 := t.Fork() child2 := t.Fork()
r0, _, _ = t.Input.PeekRune(0) // reads ' ' r0, _, _ = t.Rune.Peek(0) // reads ' '
r1, _, _ = t.Input.PeekRune(1) // reads 'm' r1, _, _ = t.Rune.Peek(1) // reads 'm'
t.Input.AcceptRunes(r0, r1) // these runes are accepted in the API results for child2 t.Rune.AcceptMulti(r0, r1) // these runes are accepted in the API results for child2
t.Dispose(child2) // but they are not merged and thefore not used by child1 t.Dispose(child2) // but they are not merged and thefore not used by child1
t.Merge(child1) // We merge child1, which has read 'H' and 'i' only. t.Merge(child1) // We merge child1, which has read 'H' and 'i' only.
@ -242,15 +242,15 @@ func TestMultipleLevelsOfForksAndMerges(t *testing.T) {
child4 := api.Fork() child4 := api.Fork()
// Read a rune 'a' from child4. // Read a rune 'a' from child4.
r, _, _ := api.Input.PeekRune(0) r, _, _ := api.Rune.Peek(0)
AssertEqual(t, 'a', r, "child4 rune 1") AssertEqual(t, 'a', r, "child4 rune 1")
api.Input.AcceptRune(r) api.Rune.Accept(r)
AssertEqual(t, "a", api.Output.String(), "child4 runes after rune 1") AssertEqual(t, "a", api.Output.String(), "child4 runes after rune 1")
// Read another rune 'b' from child4. // Read another rune 'b' from child4.
r, _, _ = api.Input.PeekRune(0) r, _, _ = api.Rune.Peek(0)
AssertEqual(t, 'b', r, "child4 rune 2") AssertEqual(t, 'b', r, "child4 rune 2")
api.Input.AcceptRune(r) api.Rune.Accept(r)
AssertEqual(t, "ab", api.Output.String(), "child4 runes after rune 2") AssertEqual(t, "ab", api.Output.String(), "child4 runes after rune 2")
// Merge "ab" from child4 to child3. // Merge "ab" from child4 to child3.
@ -258,9 +258,9 @@ func TestMultipleLevelsOfForksAndMerges(t *testing.T) {
AssertEqual(t, "", api.Output.String(), "child4 runes after first merge") AssertEqual(t, "", api.Output.String(), "child4 runes after first merge")
// Read some more from child4. // Read some more from child4.
r, _, _ = api.Input.PeekRune(0) r, _, _ = api.Rune.Peek(0)
AssertEqual(t, 'c', r, "child4 rune 3") AssertEqual(t, 'c', r, "child4 rune 3")
api.Input.AcceptRune(r) api.Rune.Accept(r)
AssertEqual(t, "c", api.Output.String(), "child4 runes after rune 1") AssertEqual(t, "c", api.Output.String(), "child4 runes after rune 1")
AssertEqual(t, "line 1, column 4", api.Cursor(), "cursor child4 rune 3") AssertEqual(t, "line 1, column 4", api.Cursor(), "cursor child4 rune 3")
@ -275,29 +275,29 @@ func TestMultipleLevelsOfForksAndMerges(t *testing.T) {
AssertEqual(t, "line 1, column 4", api.Cursor(), "cursor child3 rune 3, after merge of child4") AssertEqual(t, "line 1, column 4", api.Cursor(), "cursor child3 rune 3, after merge of child4")
// Now read some data from child3. // Now read some data from child3.
r, _, _ = api.Input.PeekRune(0) r, _, _ = api.Rune.Peek(0)
AssertEqual(t, 'd', r, "child3 rune 5") AssertEqual(t, 'd', r, "child3 rune 5")
api.Input.AcceptRune(r) api.Rune.Accept(r)
r, _, _ = api.Input.PeekRune(0) r, _, _ = api.Rune.Peek(0)
AssertEqual(t, 'e', r, "child3 rune 5") AssertEqual(t, 'e', r, "child3 rune 5")
api.Input.AcceptRune(r) api.Rune.Accept(r)
r, _, _ = api.Input.PeekRune(0) r, _, _ = api.Rune.Peek(0)
AssertEqual(t, 'f', r, "child3 rune 5") AssertEqual(t, 'f', r, "child3 rune 5")
api.Input.AcceptRune(r) api.Rune.Accept(r)
AssertEqual(t, "abcdef", api.Output.String(), "child3 total result after rune 6") AssertEqual(t, "abcdef", api.Output.String(), "child3 total result after rune 6")
// Temporarily go some new forks from here, but don't use their outcome. // Temporarily go some new forks from here, but don't use their outcome.
child3sub1 := api.Fork() child3sub1 := api.Fork()
r, _, _ = api.Input.PeekRune(0) r, _, _ = api.Rune.Peek(0)
api.Input.AcceptRune(r) api.Rune.Accept(r)
r, _, _ = api.Input.PeekRune(0) r, _, _ = api.Rune.Peek(0)
api.Input.AcceptRune(r) api.Rune.Accept(r)
child3sub2 := api.Fork() child3sub2 := api.Fork()
r, _, _ = api.Input.PeekRune(0) r, _, _ = api.Rune.Peek(0)
api.Input.AcceptRune(r) api.Rune.Accept(r)
api.Merge(child3sub2) // do merge sub2 down to sub1 api.Merge(child3sub2) // do merge sub2 down to sub1
api.Dispose(child3sub2) // and dispose of sub2 api.Dispose(child3sub2) // and dispose of sub2
api.Dispose(child3sub1) // but dispose of sub1 without merging api.Dispose(child3sub1) // but dispose of sub1 without merging
@ -324,8 +324,8 @@ func TestMultipleLevelsOfForksAndMerges(t *testing.T) {
api.Dispose(child1) api.Dispose(child1)
// Read some data from the top level api. // Read some data from the top level api.
r, _, _ = api.Input.PeekRune(0) r, _, _ = api.Rune.Peek(0)
api.Input.AcceptRune(r) api.Rune.Accept(r)
AssertEqual(t, "abcdefg", api.Output.String(), "api string end result") AssertEqual(t, "abcdefg", api.Output.String(), "api string end result")
AssertEqual(t, "line 1, column 8", api.Cursor(), "api cursor end result") AssertEqual(t, "line 1, column 8", api.Cursor(), "api cursor end result")
@ -333,15 +333,15 @@ func TestMultipleLevelsOfForksAndMerges(t *testing.T) {
func TestClearData(t *testing.T) { func TestClearData(t *testing.T) {
api := tokenize.NewAPI("Laphroaig") api := tokenize.NewAPI("Laphroaig")
r, _, _ := api.Input.PeekRune(0) // Read 'L' r, _, _ := api.Rune.Peek(0) // Read 'L'
api.Input.AcceptRune(r) // Add to runes api.Rune.Accept(r) // Add to runes
r, _, _ = api.Input.PeekRune(0) // Read 'a' r, _, _ = api.Rune.Peek(0) // Read 'a'
api.Input.AcceptRune(r) // Add to runes api.Rune.Accept(r) // Add to runes
api.Output.ClearData() // Clear the runes, giving us a fresh start. api.Output.ClearData() // Clear the runes, giving us a fresh start.
r, _, _ = api.Input.PeekRune(0) // Read 'p' r, _, _ = api.Rune.Peek(0) // Read 'p'
api.Input.AcceptRune(r) // Add to runes api.Rune.Accept(r) // Add to runes
r, _, _ = api.Input.PeekRune(0) // Read 'r' r, _, _ = api.Rune.Peek(0) // Read 'r'
api.Input.AcceptRune(r) // Add to runes api.Rune.Accept(r) // Add to runes
AssertEqual(t, "ph", api.Output.String(), "api string end result") AssertEqual(t, "ph", api.Output.String(), "api string end result")
} }
@ -363,7 +363,7 @@ func TestMergeScenariosForTokens(t *testing.T) {
tokens = api.Output.Tokens() tokens = api.Output.Tokens()
AssertEqual(t, 0, len(tokens), "Tokens 2") AssertEqual(t, 0, len(tokens), "Tokens 2")
api.Output.AddTokens(token2) api.Output.AddToken(token2)
api.Merge(child) api.Merge(child)
api.Dispose(child) api.Dispose(child)
@ -372,9 +372,9 @@ func TestMergeScenariosForTokens(t *testing.T) {
AssertEqual(t, 2, len(tokens), "Tokens 3") AssertEqual(t, 2, len(tokens), "Tokens 3")
child = api.Fork() child = api.Fork()
api.Output.AddTokens(token3) api.Output.AddToken(token3)
api.Reset() api.Reset()
api.Output.AddTokens(token4) api.Output.AddToken(token4)
api.Merge(child) api.Merge(child)
api.Dispose(child) api.Dispose(child)

View File

@ -365,9 +365,9 @@ func MatchRune(expected rune) Handler {
return MatchByte(byte(expected)) return MatchByte(byte(expected))
} }
return func(t *API) bool { return func(t *API) bool {
r, _, err := t.peekRune(0) r, _, err := t.Rune.Peek(0)
if err == nil && r == expected { if err == nil && r == expected {
t.acceptRune(r) t.Rune.Accept(r)
return true return true
} }
return false return false
@ -408,13 +408,13 @@ func MatchRunes(expected ...rune) Handler {
return MatchBytes(expectedBytes...) return MatchBytes(expectedBytes...)
} }
return func(t *API) bool { return func(t *API) bool {
r, _, err := t.peekRune(0) r, _, err := t.Rune.Peek(0)
if err != nil { if err != nil {
return false return false
} }
for _, e := range expected { for _, e := range expected {
if r == e { if r == e {
t.acceptRune(r) t.Rune.Accept(r)
return true return true
} }
} }
@ -458,9 +458,9 @@ func MatchRuneRange(start rune, end rune) Handler {
return MatchByteRange(byte(start), byte(end)) return MatchByteRange(byte(start), byte(end))
} }
return func(t *API) bool { return func(t *API) bool {
r, _, err := t.peekRune(0) r, _, err := t.Rune.Peek(0)
if err == nil && r >= start && r <= end { if err == nil && r >= start && r <= end {
t.acceptRune(r) t.Rune.Accept(r)
return true return true
} }
return false return false
@ -605,9 +605,9 @@ func MatchByteByCallback(callback func(byte) bool) Handler {
// so those can be used. E.g. MatchRuneByCallback(unicode.IsLower). // so those can be used. E.g. MatchRuneByCallback(unicode.IsLower).
func MatchRuneByCallback(callback func(rune) bool) Handler { func MatchRuneByCallback(callback func(rune) bool) Handler {
return func(t *API) bool { return func(t *API) bool {
r, _, err := t.peekRune(0) r, _, err := t.Rune.Peek(0)
if err == nil && callback(r) { if err == nil && callback(r) {
t.acceptRune(r) t.Rune.Accept(r)
return true return true
} }
return false return false
@ -650,14 +650,14 @@ func MatchStr(expected string) Handler {
} }
offset++ offset++
} else { } else {
r, w, err := t.peekRune(offset) r, w, err := t.Rune.Peek(offset)
if err != nil || e != r { if err != nil || e != r {
return false return false
} }
offset += w offset += w
} }
} }
t.acceptRunes(expectedRunes...) t.Rune.AcceptMulti(expectedRunes...)
return true return true
} }
} }
@ -680,7 +680,7 @@ func MatchStrNoCase(expected string) Handler {
matches[i] = rune(b) matches[i] = rune(b)
width++ width++
} else { } else {
r, w, err := t.peekRune(width) r, w, err := t.Rune.Peek(width)
if err != nil || (r != e && unicode.ToUpper(r) != unicode.ToUpper(e)) { if err != nil || (r != e && unicode.ToUpper(r) != unicode.ToUpper(e)) {
return false return false
} }
@ -689,7 +689,7 @@ func MatchStrNoCase(expected string) Handler {
} }
i++ i++
} }
t.acceptRunes(matches...) t.Rune.AcceptMulti(matches...)
return true return true
} }
} }
@ -762,9 +762,9 @@ func MatchNot(handler Handler) Handler {
return false return false
} }
t.Dispose(child) t.Dispose(child)
r, _, err := t.peekRune(0) r, _, err := t.Rune.Peek(0)
if err == nil { if err == nil {
t.acceptRune(r) t.Rune.Accept(r)
return true return true
} }
return false return false
@ -988,7 +988,7 @@ func MatchIntegerBetween(min int64, max int64) Handler {
if !digits(t) { if !digits(t) {
return false return false
} }
value, _ := strconv.ParseInt(t.dataAsString(), 10, 64) value, _ := strconv.ParseInt(t.Output.String(), 10, 64)
if value < min || value > max { if value < min || value > max {
return false return false
} }
@ -1032,9 +1032,9 @@ func MatchAnyByte() Handler {
// replacement rune \uFFFD (i.e. utf8.RuneError), which displays as <20>. // replacement rune \uFFFD (i.e. utf8.RuneError), which displays as <20>.
func MatchAnyRune() Handler { func MatchAnyRune() Handler {
return func(t *API) bool { return func(t *API) bool {
r, _, err := t.peekRune(0) r, _, err := t.Rune.Peek(0)
if err == nil { if err == nil {
t.acceptRune(r) t.Rune.Accept(r)
return true return true
} }
return false return false
@ -1045,9 +1045,9 @@ func MatchAnyRune() Handler {
// UTF8 rune can be read from the input. // UTF8 rune can be read from the input.
func MatchValidRune() Handler { func MatchValidRune() Handler {
return func(t *API) bool { return func(t *API) bool {
r, _, err := t.peekRune(0) r, _, err := t.Rune.Peek(0)
if err == nil && r != utf8.RuneError { if err == nil && r != utf8.RuneError {
t.acceptRune(r) t.Rune.Accept(r)
return true return true
} }
return false return false
@ -1058,9 +1058,9 @@ func MatchValidRune() Handler {
// UTF8 rune can be read from the input. // UTF8 rune can be read from the input.
func MatchInvalidRune() Handler { func MatchInvalidRune() Handler {
return func(t *API) bool { return func(t *API) bool {
r, _, err := t.peekRune(0) r, _, err := t.Rune.Peek(0)
if err == nil && r == utf8.RuneError { if err == nil && r == utf8.RuneError {
t.acceptRune(r) t.Rune.Accept(r)
return true return true
} }
return false return false
@ -1427,13 +1427,14 @@ func MatchIPv4Netmask(normalize bool) Handler {
} }
// Check if the mask is provided in canonical form (at the binary level, ones followed by zeroes). // Check if the mask is provided in canonical form (at the binary level, ones followed by zeroes).
mask := net.IPv4Mask(t.tokenValue(0).(byte), t.tokenValue(1).(byte), t.tokenValue(2).(byte), t.tokenValue(3).(byte)) val := t.Output.TokenValue
mask := net.IPv4Mask(val(0).(byte), val(1).(byte), val(2).(byte), val(3).(byte))
ones, bits := mask.Size() ones, bits := mask.Size()
if ones == 0 && bits == 0 { if ones == 0 && bits == 0 {
return false return false
} }
t.tokensClear() t.Output.ClearTokens()
return true return true
} }
} }
@ -1462,18 +1463,19 @@ func MatchIPv4Net(normalize bool) Handler {
return true return true
} }
maskToken := t.token(1) maskToken := t.Output.Token(1)
val := t.Output.TokenValue
if maskToken.Type == "cidr" { if maskToken.Type == "cidr" {
t.dataSetString(fmt.Sprintf("%s/%d", t.tokenValue(0), t.tokenValue(1).(uint8))) t.Output.SetString(fmt.Sprintf("%s/%d", val(0), val(1).(uint8)))
} else { } else {
o := strings.Split(t.tokenValue(1).(string), ".") o := strings.Split(val(1).(string), ".")
b := func(idx int) byte { i, _ := strconv.Atoi(o[idx]); return byte(i) } b := func(idx int) byte { i, _ := strconv.Atoi(o[idx]); return byte(i) }
mask := net.IPv4Mask(b(0), b(1), b(2), b(3)) mask := net.IPv4Mask(b(0), b(1), b(2), b(3))
bits, _ := mask.Size() bits, _ := mask.Size()
t.dataSetString(fmt.Sprintf("%s/%d", t.tokenValue(0), bits)) t.Output.SetString(fmt.Sprintf("%s/%d", val(0), bits))
} }
t.tokensClear() t.Output.ClearTokens()
return true return true
} }
} }
@ -1502,13 +1504,13 @@ func MatchIPv6(normalize bool) Handler {
} }
// Invalid IPv6, when net.ParseIP() cannot handle it. // Invalid IPv6, when net.ParseIP() cannot handle it.
parsed := net.ParseIP(t.dataAsString()) parsed := net.ParseIP(t.Output.String())
if parsed == nil { if parsed == nil {
return false return false
} }
if normalize { if normalize {
t.dataSetString(parsed.String()) t.Output.SetString(parsed.String())
} }
return true return true
} }
@ -1531,8 +1533,8 @@ func matchCIDRMask(bits int64, normalize bool) Handler {
if !mask(t) { if !mask(t) {
return false return false
} }
bits, _ := strconv.Atoi(t.dataAsString()) bits, _ := strconv.Atoi(t.Output.String())
t.dataSetString(fmt.Sprintf("%d", bits)) t.Output.SetString(fmt.Sprintf("%d", bits))
return true return true
} }
} }
@ -1673,8 +1675,11 @@ func ModifyByCallback(handler Handler, modfunc func(string) string) Handler {
return func(t *API) bool { return func(t *API) bool {
child := t.Fork() child := t.Fork()
if handler(t) { if handler(t) {
s := modfunc(t.dataAsString()) origS := t.Output.String()
t.dataSetString(s) s := modfunc(origS)
if s != origS {
t.Output.SetString(s)
}
t.Merge(child) t.Merge(child)
t.Dispose(child) t.Dispose(child)
return true return true
@ -1691,7 +1696,7 @@ func ModifyByCallback(handler Handler, modfunc func(string) string) Handler {
// an 'n'-character). // an 'n'-character).
func MakeStrLiteralToken(toktype interface{}, handler Handler) Handler { func MakeStrLiteralToken(toktype interface{}, handler Handler) Handler {
return MakeTokenByCallback(toktype, handler, func(t *API) interface{} { return MakeTokenByCallback(toktype, handler, func(t *API) interface{} {
literal := t.dataAsString() literal := t.Output.String()
return literal return literal
}) })
} }
@ -1703,7 +1708,7 @@ func MakeStrLiteralToken(toktype interface{}, handler Handler) Handler {
func MakeStrInterpretedToken(toktype interface{}, handler Handler) Handler { func MakeStrInterpretedToken(toktype interface{}, handler Handler) Handler {
return MakeTokenByCallback(toktype, handler, func(t *API) interface{} { return MakeTokenByCallback(toktype, handler, func(t *API) interface{} {
// TODO ERROR HANDLING // TODO ERROR HANDLING
interpreted, _ := interpretString(t.dataAsString()) interpreted, _ := interpretString(t.Output.String())
return interpreted return interpreted
}) })
} }
@ -1727,7 +1732,7 @@ func interpretString(str string) (string, error) {
func MakeRuneToken(toktype interface{}, handler Handler) Handler { func MakeRuneToken(toktype interface{}, handler Handler) Handler {
return MakeTokenByCallback(toktype, handler, func(t *API) interface{} { return MakeTokenByCallback(toktype, handler, func(t *API) interface{} {
// TODO ERROR HANDLING --- not a 1 rune input // TODO ERROR HANDLING --- not a 1 rune input
return t.dataRune(0) return t.Output.Rune(0)
}) })
} }
@ -1737,7 +1742,7 @@ func MakeRuneToken(toktype interface{}, handler Handler) Handler {
func MakeByteToken(toktype interface{}, handler Handler) Handler { func MakeByteToken(toktype interface{}, handler Handler) Handler {
return MakeTokenByCallback(toktype, handler, func(t *API) interface{} { return MakeTokenByCallback(toktype, handler, func(t *API) interface{} {
// TODO ERROR HANDLING --- not a 1 byte input // TODO ERROR HANDLING --- not a 1 byte input
return byte(t.dataRune(0)) return byte(t.Output.Rune(0))
}) })
} }
@ -1942,7 +1947,7 @@ func MakeBooleanToken(toktype interface{}, handler Handler) Handler {
func makeStrconvToken(name string, toktype interface{}, handler Handler, convert func(s string) (interface{}, error)) Handler { func makeStrconvToken(name string, toktype interface{}, handler Handler, convert func(s string) (interface{}, error)) Handler {
return MakeTokenByCallback(toktype, handler, func(t *API) interface{} { return MakeTokenByCallback(toktype, handler, func(t *API) interface{} {
value, err := convert(t.dataAsString()) value, err := convert(t.Output.String())
if err != nil { if err != nil {
// TODO meh, panic feels so bad here. Maybe just turn this case into "no match"? // TODO meh, panic feels so bad here. Maybe just turn this case into "no match"?
panic(fmt.Sprintf("%s token invalid (%s)", name, err)) panic(fmt.Sprintf("%s token invalid (%s)", name, err))
@ -1973,7 +1978,7 @@ func MakeTokenByCallback(toktype interface{}, handler Handler, makeValue func(t
// tokens will end up in the order "date", "year", "month", "day". When we'd add the // tokens will end up in the order "date", "year", "month", "day". When we'd add the
// token to the child here, the order would have been "year", "month", "day", "date". // token to the child here, the order would have been "year", "month", "day", "date".
token := Token{Type: toktype, Value: makeValue(t)} token := Token{Type: toktype, Value: makeValue(t)}
t.tokensAdd(token) t.Output.AddToken(token)
t.Merge(child) t.Merge(child)
t.Dispose(child) t.Dispose(child)
@ -1990,10 +1995,10 @@ func MakeTokenGroup(toktype interface{}, handler Handler) Handler {
return func(t *API) bool { return func(t *API) bool {
child := t.Fork() child := t.Fork()
if handler(t) { if handler(t) {
tokens := t.tokens() tokens := t.Output.Tokens()
tokensCopy := make([]Token, len(tokens)) tokensCopy := make([]Token, len(tokens))
copy(tokensCopy, tokens) copy(tokensCopy, tokens)
t.tokensSet(Token{Type: toktype, Value: tokensCopy}) t.Output.SetTokens(Token{Type: toktype, Value: tokensCopy})
t.Merge(child) t.Merge(child)
t.Dispose(child) t.Dispose(child)
return true return true

View File

@ -7,6 +7,7 @@ import (
tokenize "git.makaay.nl/mauricem/go-parsekit/tokenize" tokenize "git.makaay.nl/mauricem/go-parsekit/tokenize"
) )
// TODO cleanup when I'm finished with these.
func TestCombinatorsTempDebug(t *testing.T) { func TestCombinatorsTempDebug(t *testing.T) {
var a = tokenize.A var a = tokenize.A
AssertHandlers(t, []HandlerT{ AssertHandlers(t, []HandlerT{

View File

@ -47,8 +47,8 @@ func New(tokenHandler Handler) Func {
return nil, err return nil, err
} }
result := &Result{ result := &Result{
Runes: api.dataAsRunes(), Runes: api.Output.Runes(),
Tokens: api.tokens(), Tokens: api.Output.Tokens(),
} }
return result, nil return result, nil
} }

View File

@ -55,19 +55,19 @@ func ExampleNew() {
func TestCallingPeekRune_PeeksRuneOnInput(t *testing.T) { func TestCallingPeekRune_PeeksRuneOnInput(t *testing.T) {
api := makeTokenizeAPI() api := makeTokenizeAPI()
r, _, _ := api.Input.PeekRune(0) r, _, _ := api.Rune.Peek(0)
AssertEqual(t, 'T', r, "first rune") AssertEqual(t, 'T', r, "first rune")
} }
func TestInputCanAcceptRunesFromReader(t *testing.T) { func TestInputCanAcceptRunesFromReader(t *testing.T) {
i := makeTokenizeAPI() i := makeTokenizeAPI()
r0, _, _ := i.Input.PeekRune(0) r0, _, _ := i.Rune.Peek(0)
i.Input.AcceptRune(r0) i.Rune.Accept(r0)
r1, _, _ := i.Input.PeekRune(0) // 0, because read offset resets to 0 after Accept* calls. r1, _, _ := i.Rune.Peek(0) // 0, because read offset resets to 0 after Accept* calls.
r2, _, _ := i.Input.PeekRune(1) r2, _, _ := i.Rune.Peek(1)
i.Input.AcceptRunes(r1, r2) i.Rune.AcceptMulti(r1, r2)
AssertEqual(t, "Tes", i.Output.String(), "i.String()") AssertEqual(t, "Tes", i.Output.String(), "i.String()")
} }
@ -136,13 +136,13 @@ func TestAccept_UpdatesCursor(t *testing.T) {
i := tokenize.NewAPI(strings.NewReader("input\r\nwith\r\nnewlines")) i := tokenize.NewAPI(strings.NewReader("input\r\nwith\r\nnewlines"))
AssertEqual(t, "start of file", i.Cursor(), "cursor 1") AssertEqual(t, "start of file", i.Cursor(), "cursor 1")
for j := 0; j < 6; j++ { // read "input\r", cursor end up at "\n" for j := 0; j < 6; j++ { // read "input\r", cursor end up at "\n"
r, _, _ := i.Input.PeekRune(0) r, _, _ := i.Rune.Peek(0)
i.Input.AcceptRune(r) i.Rune.Accept(r)
} }
AssertEqual(t, "line 1, column 7", i.Cursor(), "cursor 2") AssertEqual(t, "line 1, column 7", i.Cursor(), "cursor 2")
r, _, _ := i.Input.PeekRune(0) // read "\n", cursor ends up at start of new line r, _, _ := i.Rune.Peek(0) // read "\n", cursor ends up at start of new line
i.Input.AcceptRune(r) i.Rune.Accept(r)
AssertEqual(t, "line 2, column 1", i.Cursor(), "cursor 3") AssertEqual(t, "line 2, column 1", i.Cursor(), "cursor 3")
for j := 0; j < 10; j++ { // read "with\r\nnewl", cursor end up at "i" for j := 0; j < 10; j++ { // read "with\r\nnewl", cursor end up at "i"
@ -154,9 +154,9 @@ func TestAccept_UpdatesCursor(t *testing.T) {
func TestWhenCallingPeekruneAtEndOfFile_EOFIsReturned(t *testing.T) { func TestWhenCallingPeekruneAtEndOfFile_EOFIsReturned(t *testing.T) {
i := tokenize.NewAPI(strings.NewReader("X")) i := tokenize.NewAPI(strings.NewReader("X"))
r, _, _ := i.Input.PeekRune(0) r, _, _ := i.Rune.Peek(0)
i.Input.AcceptRune(r) i.Rune.Accept(r)
r, _, err := i.Input.PeekRune(0) r, _, err := i.Rune.Peek(0)
AssertEqual(t, true, r == utf8.RuneError, "returned rune from NextRune()") AssertEqual(t, true, r == utf8.RuneError, "returned rune from NextRune()")
AssertEqual(t, true, err == io.EOF, "returned error from NextRune()") AssertEqual(t, true, err == io.EOF, "returned error from NextRune()")
@ -167,9 +167,9 @@ func TestAfterReadingruneAtEndOfFile_EarlierRunesCanStillBeAccessed(t *testing.T
child := i.Fork() child := i.Fork()
// To to the EOF. // To to the EOF.
r, _, _ := i.Input.PeekRune(0) r, _, _ := i.Rune.Peek(0)
i.Input.AcceptRune(r) i.Rune.Accept(r)
r, _, err := i.Input.PeekRune(0) r, _, err := i.Rune.Peek(0)
AssertEqual(t, true, r == utf8.RuneError, "returned rune from 2nd NextRune()") AssertEqual(t, true, r == utf8.RuneError, "returned rune from 2nd NextRune()")
AssertEqual(t, true, err == io.EOF, "returned error from 2nd NextRune()") AssertEqual(t, true, err == io.EOF, "returned error from 2nd NextRune()")
@ -177,7 +177,7 @@ func TestAfterReadingruneAtEndOfFile_EarlierRunesCanStillBeAccessed(t *testing.T
i.Dispose(child) i.Dispose(child)
// So here we should see the same input data as before. // So here we should see the same input data as before.
r, _, err = i.Input.PeekRune(0) r, _, err = i.Rune.Peek(0)
AssertEqual(t, 'X', r, "returned rune from 2nd NextRune()") AssertEqual(t, 'X', r, "returned rune from 2nd NextRune()")
AssertEqual(t, true, err == nil, "returned error from 2nd NextRune()") AssertEqual(t, true, err == nil, "returned error from 2nd NextRune()")
} }

View File

@ -7,9 +7,9 @@ import (
func TestFork_CreatesForkOfInputAtSameCursorPosition(t *testing.T) { func TestFork_CreatesForkOfInputAtSameCursorPosition(t *testing.T) {
// Create input, accept the first rune. // Create input, accept the first rune.
i := NewAPI("Testing") i := NewAPI("Testing")
r, _, _ := i.Input.PeekRune(0) r, _, _ := i.Rune.Peek(0)
i.Input.AcceptRune(r) // T i.Rune.Accept(r) // T
AssertEqual(t, "T", i.dataAsString(), "accepted rune in input") AssertEqual(t, "T", i.Output.String(), "accepted rune in input")
// Fork // Fork
child := i.Fork() child := i.Fork()
@ -17,44 +17,44 @@ func TestFork_CreatesForkOfInputAtSameCursorPosition(t *testing.T) {
AssertEqual(t, 1, i.stackFrame.offset, "child offset") AssertEqual(t, 1, i.stackFrame.offset, "child offset")
// Accept two runes via fork. // Accept two runes via fork.
r, _, _ = i.Input.PeekRune(0) r, _, _ = i.Rune.Peek(0)
i.Input.AcceptRune(r) // e i.Rune.Accept(r) // e
r, _, _ = i.Input.PeekRune(0) r, _, _ = i.Rune.Peek(0)
i.Input.AcceptRune(r) // s i.Rune.Accept(r) // s
AssertEqual(t, "es", i.dataAsString(), "result runes in fork") AssertEqual(t, "es", i.Output.String(), "result runes in fork")
AssertEqual(t, 1, i.stackFrames[i.stackLevel-1].offset, "parent offset") AssertEqual(t, 1, i.stackFrames[i.stackLevel-1].offset, "parent offset")
AssertEqual(t, 3, i.stackFrame.offset, "child offset") AssertEqual(t, 3, i.stackFrame.offset, "child offset")
// Merge fork back into parent // Merge fork back into parent
i.Merge(child) i.Merge(child)
i.Dispose(child) i.Dispose(child)
AssertEqual(t, "Tes", i.dataAsString(), "result runes in parent Input after Merge()") AssertEqual(t, "Tes", i.Output.String(), "result runes in parent Input after Merge()")
AssertEqual(t, 3, i.stackFrame.offset, "parent offset") AssertEqual(t, 3, i.stackFrame.offset, "parent offset")
} }
func TestGivenForkedChildWhichAcceptedRune_AfterMerging_RuneEndsUpInParentResult(t *testing.T) { func TestGivenForkedChildWhichAcceptedRune_AfterMerging_RuneEndsUpInParentResult(t *testing.T) {
i := NewAPI("Testing") i := NewAPI("Testing")
r, _, _ := i.Input.PeekRune(0) r, _, _ := i.Rune.Peek(0)
i.Input.AcceptRune(r) // T i.Rune.Accept(r) // T
f1 := i.Fork() f1 := i.Fork()
r, _, _ = i.Input.PeekRune(0) r, _, _ = i.Rune.Peek(0)
i.Input.AcceptRune(r) // e i.Rune.Accept(r) // e
f2 := i.Fork() f2 := i.Fork()
r, _, _ = i.Input.PeekRune(0) r, _, _ = i.Rune.Peek(0)
i.Input.AcceptRune(r) // s i.Rune.Accept(r) // s
AssertEqual(t, "s", i.dataAsString(), "f2 String()") AssertEqual(t, "s", i.Output.String(), "f2 String()")
AssertEqual(t, 3, i.stackFrame.offset, "f2.offset A") AssertEqual(t, 3, i.stackFrame.offset, "f2.offset A")
i.Merge(f2) i.Merge(f2)
i.Dispose(f2) i.Dispose(f2)
AssertEqual(t, "es", i.dataAsString(), "f1 String()") AssertEqual(t, "es", i.Output.String(), "f1 String()")
AssertEqual(t, 3, i.stackFrame.offset, "f1.offset A") AssertEqual(t, 3, i.stackFrame.offset, "f1.offset A")
i.Merge(f1) i.Merge(f1)
i.Dispose(f1) i.Dispose(f1)
AssertEqual(t, "Tes", i.dataAsString(), "top-level API String()") AssertEqual(t, "Tes", i.Output.String(), "top-level API String()")
AssertEqual(t, 3, i.stackFrame.offset, "f1.offset A") AssertEqual(t, 3, i.stackFrame.offset, "f1.offset A")
} }
@ -65,10 +65,10 @@ func TestFlushInput(t *testing.T) {
// false in this case, and nothing else happens. // false in this case, and nothing else happens.
AssertTrue(t, i.FlushInput() == false, "flush input at start") AssertTrue(t, i.FlushInput() == false, "flush input at start")
r, _, _ := i.Input.PeekRune(0) r, _, _ := i.Rune.Peek(0)
i.Input.AcceptRune(r) // c i.Rune.Accept(r) // c
r, _, _ = i.Input.PeekRune(0) r, _, _ = i.Rune.Peek(0)
i.Input.AcceptRune(r) // o i.Rune.Accept(r) // o
AssertTrue(t, i.FlushInput() == true, "flush input after reading some data") AssertTrue(t, i.FlushInput() == true, "flush input after reading some data")
AssertEqual(t, 0, i.stackFrame.offset, "offset after flush input") AssertEqual(t, 0, i.stackFrame.offset, "offset after flush input")
@ -78,12 +78,12 @@ func TestFlushInput(t *testing.T) {
// Read offset is now zero, but reading should continue after "co". // Read offset is now zero, but reading should continue after "co".
// The output so far isn't modified, so the following accept calls // The output so far isn't modified, so the following accept calls
// will add their runes to the already accepted string "co". // will add their runes to the already accepted string "co".
r, _, _ = i.Input.PeekRune(0) r, _, _ = i.Rune.Peek(0)
i.Input.AcceptRune(r) // o i.Rune.Accept(r) // o
r, _, _ = i.Input.PeekRune(0) r, _, _ = i.Rune.Peek(0)
i.Input.AcceptRune(r) // o i.Rune.Accept(r) // o
AssertEqual(t, "cool", i.dataAsString(), "end result") AssertEqual(t, "cool", i.Output.String(), "end result")
} }
func TestInputFlusherWrapper(t *testing.T) { func TestInputFlusherWrapper(t *testing.T) {
@ -92,19 +92,19 @@ func TestInputFlusherWrapper(t *testing.T) {
api := NewAPI("abaab") api := NewAPI("abaab")
runeA(api) runeA(api)
AssertEqual(t, 1, api.stackFrame.offset, "offset after 1 read") AssertEqual(t, 1, api.stackFrame.offset, "offset after 1 read")
AssertEqual(t, "a", api.dataAsString(), "runes after 1 read") AssertEqual(t, "a", api.Output.String(), "runes after 1 read")
flushB(api) flushB(api)
AssertEqual(t, 0, api.stackFrame.offset, "offset after 2 reads + input flush") AssertEqual(t, 0, api.stackFrame.offset, "offset after 2 reads + input flush")
AssertEqual(t, "ab", api.dataAsString(), "runes after 2 reads") AssertEqual(t, "ab", api.Output.String(), "runes after 2 reads")
runeA(api) runeA(api)
AssertEqual(t, 1, api.stackFrame.offset, "offset after 3 reads") AssertEqual(t, 1, api.stackFrame.offset, "offset after 3 reads")
AssertEqual(t, "aba", api.dataAsString(), "runes after 3 reads") AssertEqual(t, "aba", api.Output.String(), "runes after 3 reads")
runeA(api) runeA(api)
AssertEqual(t, 2, api.stackFrame.offset, "offset after 4 reads") AssertEqual(t, 2, api.stackFrame.offset, "offset after 4 reads")
AssertEqual(t, "abaa", api.dataAsString(), "runes after 4 reads") AssertEqual(t, "abaa", api.Output.String(), "runes after 4 reads")
flushB(api) flushB(api)
AssertEqual(t, 0, api.stackFrame.offset, "offset after 5 reads + input flush") AssertEqual(t, 0, api.stackFrame.offset, "offset after 5 reads + input flush")
AssertEqual(t, "abaab", api.dataAsString(), "runes after 5 reads") AssertEqual(t, "abaab", api.Output.String(), "runes after 5 reads")
} }
func AssertEqual(t *testing.T, expected interface{}, actual interface{}, forWhat string) { func AssertEqual(t *testing.T, expected interface{}, actual interface{}, forWhat string) {