treerack/context.go

159 lines
2.5 KiB
Go
Raw Normal View History

2017-07-15 21:49:08 +02:00
package treerack
2017-06-25 17:51:08 +02:00
import (
"io"
"unicode"
)
type context struct {
reader io.RuneReader
offset int
readOffset int
readErr error
eof bool
2017-11-02 20:49:49 +01:00
results *results
2017-06-25 17:51:08 +02:00
tokens []rune
2017-11-02 20:49:49 +01:00
matchLast bool
isPending [][]int
2017-06-25 17:51:08 +02:00
}
func newContext(r io.RuneReader) *context {
return &context{
2017-11-02 20:49:49 +01:00
reader: r,
results: &results{},
2017-06-25 17:51:08 +02:00
}
}
func (c *context) read() bool {
if c.eof || c.readErr != nil {
return false
}
2017-11-02 22:55:19 +01:00
token, n, err := c.reader.ReadRune()
2017-06-25 17:51:08 +02:00
if err != nil {
if err == io.EOF {
if n == 0 {
c.eof = true
return false
}
} else {
c.readErr = err
return false
}
}
c.readOffset++
2017-11-02 22:55:19 +01:00
if token == unicode.ReplacementChar {
2017-06-26 02:20:23 +02:00
c.readErr = ErrInvalidUnicodeCharacter
2017-06-25 17:51:08 +02:00
return false
}
2017-11-02 22:55:19 +01:00
c.tokens = append(c.tokens, token)
2017-06-25 17:51:08 +02:00
return true
}
func (c *context) token() (rune, bool) {
if c.offset == c.readOffset {
if !c.read() {
return 0, false
}
}
return c.tokens[c.offset], true
}
2017-11-02 20:49:49 +01:00
func (c *context) pending(offset int, id int) bool {
if len(c.isPending) <= id {
2017-06-25 17:51:08 +02:00
return false
}
2017-11-02 20:49:49 +01:00
for i := range c.isPending[id] {
if c.isPending[id][i] == offset {
return true
}
}
return false
2017-06-25 17:51:08 +02:00
}
2017-11-02 20:49:49 +01:00
func (c *context) markPending(offset int, id int) {
if len(c.isPending) <= id {
if cap(c.isPending) > id {
c.isPending = c.isPending[:id+1]
2017-06-25 17:51:08 +02:00
} else {
2017-11-02 20:49:49 +01:00
c.isPending = c.isPending[:cap(c.isPending)]
for i := cap(c.isPending); i <= id; i++ {
c.isPending = append(c.isPending, nil)
}
2017-06-25 17:51:08 +02:00
}
}
2017-11-02 20:49:49 +01:00
for i := range c.isPending[id] {
if c.isPending[id][i] == -1 {
c.isPending[id][i] = offset
2017-07-30 02:35:51 +02:00
return
}
}
2017-11-02 20:49:49 +01:00
c.isPending[id] = append(c.isPending[id], offset)
2017-06-25 17:51:08 +02:00
}
2017-11-02 20:49:49 +01:00
func (c *context) unmarkPending(offset int, id int) {
for i := range c.isPending[id] {
if c.isPending[id][i] == offset {
c.isPending[id][i] = -1
break
}
2017-06-25 17:51:08 +02:00
}
}
2017-11-02 20:49:49 +01:00
func (c *context) fromResults(id int) bool {
to, m, ok := c.results.getMatch(c.offset, id)
2017-06-25 17:51:08 +02:00
if !ok {
2017-07-30 05:10:46 +02:00
return false
2017-06-25 17:51:08 +02:00
}
if m {
2017-07-17 04:23:29 +02:00
c.success(to)
2017-06-25 17:51:08 +02:00
} else {
c.fail(c.offset)
}
2017-07-30 05:10:46 +02:00
return true
2017-06-25 17:51:08 +02:00
}
2017-07-17 04:23:29 +02:00
func (c *context) success(to int) {
c.offset = to
2017-11-02 20:49:49 +01:00
c.matchLast = true
2017-07-17 01:41:38 +02:00
}
2017-06-25 17:51:08 +02:00
func (c *context) fail(offset int) {
c.offset = offset
2017-11-02 20:49:49 +01:00
c.matchLast = false
2017-06-25 17:51:08 +02:00
}
2017-11-02 22:55:19 +01:00
func (c *context) finalizeParse(rootID int) error {
if !c.matchLast {
return ErrInvalidInput
}
2017-11-02 20:49:49 +01:00
to, match, found := c.results.getMatch(0, rootID)
2017-07-29 16:25:17 +02:00
if !found || !match || to < c.readOffset {
2017-06-25 17:51:08 +02:00
return ErrUnexpectedCharacter
}
if !c.eof {
c.read()
if !c.eof {
if c.readErr != nil {
return c.readErr
}
return ErrUnexpectedCharacter
}
}
return nil
}