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-18 00:38:44 +02:00
|
|
|
isExcluded [][]int
|
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 {
|
2017-07-18 00:38:44 +02:00
|
|
|
if len(c.isExcluded) <= id {
|
2017-06-25 17:51:08 +02:00
|
|
|
return false
|
|
|
|
}
|
|
|
|
|
2017-07-18 00:38:44 +02:00
|
|
|
for i := range c.isExcluded[id] {
|
|
|
|
if c.isExcluded[id][i] == offset {
|
|
|
|
return true
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
return false
|
2017-06-25 17:51:08 +02:00
|
|
|
}
|
|
|
|
|
2017-07-15 21:49:08 +02:00
|
|
|
func (c *context) exclude(offset int, id int) {
|
2017-07-18 00:38:44 +02:00
|
|
|
if len(c.isExcluded) <= id {
|
|
|
|
if cap(c.isExcluded) > id {
|
|
|
|
c.isExcluded = c.isExcluded[:id+1]
|
2017-06-25 17:51:08 +02:00
|
|
|
} else {
|
2017-07-18 00:38:44 +02:00
|
|
|
c.isExcluded = c.isExcluded[:cap(c.isExcluded)]
|
|
|
|
for i := cap(c.isExcluded); i <= id; i++ {
|
|
|
|
c.isExcluded = append(c.isExcluded, nil)
|
|
|
|
}
|
2017-06-25 17:51:08 +02:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2017-07-18 00:38:44 +02:00
|
|
|
c.isExcluded[id] = append(c.isExcluded[id], offset)
|
2017-06-25 17:51:08 +02:00
|
|
|
}
|
|
|
|
|
2017-07-15 21:49:08 +02:00
|
|
|
func (c *context) include(offset int, id int) {
|
2017-07-18 00:38:44 +02:00
|
|
|
for i := range c.isExcluded[id] {
|
|
|
|
if c.isExcluded[id][i] == offset {
|
|
|
|
c.isExcluded[id] = append(c.isExcluded[id][:i], c.isExcluded[id][i+1:]...)
|
|
|
|
break
|
|
|
|
}
|
2017-06-25 17:51:08 +02:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2017-07-15 23:00:43 +02:00
|
|
|
func (c *context) fromStore(id int) (bool, bool) {
|
2017-07-17 21:58:03 +02:00
|
|
|
to, m, ok := c.store.getMatch(c.offset, id)
|
2017-06-25 17:51:08 +02:00
|
|
|
if !ok {
|
|
|
|
return false, false
|
|
|
|
}
|
|
|
|
|
|
|
|
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)
|
|
|
|
}
|
|
|
|
|
|
|
|
return m, true
|
|
|
|
}
|
|
|
|
|
2017-07-17 04:23:29 +02:00
|
|
|
func (c *context) success(to int) {
|
|
|
|
c.offset = to
|
2017-07-17 01:41:38 +02:00
|
|
|
c.match = true
|
|
|
|
}
|
|
|
|
|
2017-06-25 17:51:08 +02:00
|
|
|
func (c *context) fail(offset int) {
|
|
|
|
c.offset = offset
|
|
|
|
c.match = false
|
|
|
|
}
|
|
|
|
|
2017-07-29 16:25:17 +02:00
|
|
|
func (c *context) finalize(root parser) error {
|
|
|
|
rootID := root.nodeID()
|
|
|
|
to, match, found := c.store.getMatch(0, rootID)
|
|
|
|
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
|
|
|
|
}
|