treerack/context.go

177 lines
2.8 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"
2017-12-29 18:36:58 +01:00
"strings"
2017-06-25 17:51:08 +02:00
"unicode"
)
type context struct {
2017-11-25 17:37:05 +01:00
reader io.RuneReader
2019-02-02 18:07:10 +01:00
keywords []parser
2017-11-25 17:37:05 +01:00
offset int
readOffset int
consumed int
2019-02-02 18:07:10 +01:00
offsetLimit int
2017-11-25 17:37:05 +01:00
failOffset int
failingParser parser
readErr error
eof bool
results *results
tokens []rune
matchLast bool
2017-06-25 17:51:08 +02:00
}
2019-02-02 18:07:10 +01:00
func newContext(r io.RuneReader, keywords []parser) *context {
2017-06-25 17:51:08 +02:00
return &context{
2019-02-02 18:07:10 +01:00
reader: r,
keywords: keywords,
results: &results{},
offsetLimit: -1,
failOffset: -1,
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) {
2019-02-02 18:07:10 +01:00
if c.offset == c.offsetLimit {
return 0, false
}
2017-06-25 17:51:08 +02:00
if c.offset == c.readOffset {
if !c.read() {
return 0, false
}
}
return c.tokens[c.offset], true
}
2017-11-25 17:37:05 +01:00
func (c *context) fromResults(p parser) bool {
to, m, ok := c.results.longestResult(c.offset, p.nodeID())
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 {
2017-11-25 22:01:02 +01:00
c.fail(c.offset)
2017-06-25 17:51:08 +02:00
}
2017-07-30 05:10:46 +02:00
return true
2017-06-25 17:51:08 +02:00
}
2019-02-02 18:07:10 +01:00
func (c *context) isKeyword(from, to int) bool {
ol := c.offsetLimit
c.offsetLimit = to
defer func() { c.offsetLimit = ol }()
for _, kw := range c.keywords {
c.offset = from
kw.parse(c)
if c.matchLast && c.offset == to {
return true
}
}
return false
}
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-11-25 17:37:05 +01:00
if to > c.consumed {
c.consumed = to
}
2017-07-17 01:41:38 +02:00
}
2017-11-25 22:01:02 +01:00
func (c *context) fail(offset int) {
2017-06-25 17:51:08 +02:00
c.offset = offset
2017-11-02 20:49:49 +01:00
c.matchLast = false
2017-11-25 22:01:02 +01:00
}
2017-11-25 17:37:05 +01:00
func findLine(tokens []rune, offset int) (line, column int) {
tokens = tokens[:offset]
for i := range tokens {
column++
if tokens[i] == '\n' {
column = 0
line++
}
}
return
2017-06-25 17:51:08 +02:00
}
2017-11-25 22:01:02 +01:00
func (c *context) parseError(p parser) error {
definition := p.nodeName()
2017-12-29 18:36:58 +01:00
flagIndex := strings.Index(definition, ":")
if flagIndex > 0 {
definition = definition[:flagIndex]
}
2017-11-25 17:37:05 +01:00
if c.failingParser == nil {
c.failOffset = c.consumed
}
line, col := findLine(c.tokens, c.failOffset)
return &ParseError{
Offset: c.failOffset,
Line: line,
Column: col,
Definition: definition,
}
}
func (c *context) finalizeParse(root parser) error {
2018-01-05 19:06:10 +01:00
fp := c.failingParser
if fp == nil {
fp = root
2017-11-02 22:55:19 +01:00
}
2017-11-25 17:37:05 +01:00
to, match, found := c.results.longestResult(0, root.nodeID())
2017-12-31 17:34:10 +01:00
if !found || !match || found && match && to < c.readOffset {
2018-01-05 19:06:10 +01:00
return c.parseError(fp)
2017-06-25 17:51:08 +02:00
}
2017-12-31 17:34:10 +01:00
c.read()
if c.eof {
return nil
2017-11-25 22:01:02 +01:00
}
2017-12-31 17:34:10 +01:00
if c.readErr != nil {
return c.readErr
2017-06-25 17:51:08 +02:00
}
2017-12-31 17:34:10 +01:00
return c.parseError(root)
2017-06-25 17:51:08 +02:00
}