treerack/context.go

152 lines
2.3 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-06-26 02:20:23 +02:00
store *store
2017-06-25 17:51:08 +02:00
tokens []rune
match bool
node *Node
2017-07-15 21:49:08 +02:00
isExcluded []*idSet
2017-06-25 17:51:08 +02:00
}
func newContext(r io.RuneReader) *context {
return &context{
reader: r,
2017-06-26 02:20:23 +02:00
store: &store{},
2017-06-25 17:51:08 +02:00
}
}
func (c *context) read() bool {
if c.eof || c.readErr != nil {
return false
}
t, n, err := c.reader.ReadRune()
if err != nil {
if err == io.EOF {
if n == 0 {
c.eof = true
return false
}
} else {
c.readErr = err
return false
}
}
c.readOffset++
if t == unicode.ReplacementChar {
2017-06-26 02:20:23 +02:00
c.readErr = ErrInvalidUnicodeCharacter
2017-06-25 17:51:08 +02:00
return false
}
c.tokens = append(c.tokens, t)
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-07-15 21:49:08 +02:00
func (c *context) excluded(offset int, id int) bool {
if len(c.isExcluded) <= offset || c.isExcluded[offset] == nil {
2017-06-25 17:51:08 +02:00
return false
}
2017-07-15 21:49:08 +02:00
return c.isExcluded[offset].has(id)
2017-06-25 17:51:08 +02:00
}
2017-07-15 21:49:08 +02:00
func (c *context) exclude(offset int, id int) {
if c.excluded(offset, id) {
2017-06-26 01:21:46 +02:00
return
}
2017-06-25 17:51:08 +02:00
if len(c.isExcluded) <= offset {
c.isExcluded = append(c.isExcluded, nil)
if cap(c.isExcluded) > offset {
c.isExcluded = c.isExcluded[:offset+1]
} else {
c.isExcluded = append(
c.isExcluded[:cap(c.isExcluded)],
2017-07-15 21:49:08 +02:00
make([]*idSet, offset+1-cap(c.isExcluded))...,
2017-06-25 17:51:08 +02:00
)
}
}
2017-07-15 21:49:08 +02:00
if c.isExcluded[offset] == nil {
c.isExcluded[offset] = &idSet{}
}
c.isExcluded[offset].set(id)
2017-06-25 17:51:08 +02:00
}
2017-07-15 21:49:08 +02:00
func (c *context) include(offset int, id int) {
if len(c.isExcluded) <= offset || c.isExcluded[offset] == nil {
2017-06-25 17:51:08 +02:00
return
}
2017-07-15 21:49:08 +02:00
c.isExcluded[offset].unset(id)
2017-06-25 17:51:08 +02:00
}
2017-07-15 23:00:43 +02:00
func (c *context) fromStore(id int) (bool, bool) {
n, m, ok := c.store.get(c.offset, id)
2017-06-25 17:51:08 +02:00
if !ok {
return false, false
}
if m {
c.success(n)
} else {
c.fail(c.offset)
}
return m, true
}
func (c *context) success(n *Node) {
c.node = n
2017-06-26 01:21:46 +02:00
c.offset = n.To
2017-06-25 17:51:08 +02:00
c.match = true
}
func (c *context) fail(offset int) {
c.offset = offset
c.match = false
}
func (c *context) finalize() error {
2017-06-26 01:21:46 +02:00
if c.node.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
}
}
2017-06-26 01:21:46 +02:00
c.node.commit(c.tokens)
2017-06-25 17:51:08 +02:00
return nil
}