diff --git a/choice.go b/choice.go index f64fe99..fc6a46b 100644 --- a/choice.go +++ b/choice.go @@ -131,24 +131,6 @@ func (d *choiceDefinition) parser() parser { func (d *choiceDefinition) builder() builder { return d.cbuilder } -func (d *choiceDefinition) format(r *registry, f formatFlags) string { - var chars []rune - for i := range d.options { - if i > 0 { - chars = append(chars, []rune(" | ")...) - } - - optionDef, _ := r.definition(d.options[i]) - if optionDef.commitType()&userDefined != 0 { - chars = append(chars, []rune(optionDef.nodeName())...) - } else { - chars = append(chars, []rune(optionDef.format(r, f))...) - } - } - - return string(chars) -} - func (p *choiceParser) nodeName() string { return p.name } func (p *choiceParser) nodeID() int { return p.id } func (p *choiceParser) commitType() CommitType { return p.commit } @@ -164,17 +146,19 @@ func (p *choiceParser) parse(c *context) { } c.results.markPending(c.offset, p.id) + + var ( + match bool + optionIndex int + foundMatch bool + failingParser parser + ) + from := c.offset to := c.offset - - var match bool - var optionIndex int - var foundMatch bool - initialFailOffset := c.failOffset initialFailingParser := c.failingParser failOffset := initialFailOffset - var failingParser parser for { foundMatch = false @@ -288,3 +272,21 @@ func (b *choiceBuilder) build(c *context) ([]*Node, bool) { tokens: c.tokens, }}, true } + +func (d *choiceDefinition) format(r *registry, f formatFlags) string { + var chars []rune + for i := range d.options { + if i > 0 { + chars = append(chars, []rune(" | ")...) + } + + optionDef, _ := r.definition(d.options[i]) + if optionDef.commitType()&userDefined != 0 { + chars = append(chars, []rune(optionDef.nodeName())...) + } else { + chars = append(chars, []rune(optionDef.format(r, f))...) + } + } + + return string(chars) +} diff --git a/context.go b/context.go index e575a82..ee8a150 100644 --- a/context.go +++ b/context.go @@ -136,25 +136,18 @@ func (c *context) finalizeParse(root parser) error { } to, match, found := c.results.longestResult(0, root.nodeID()) - - if found && match && to < c.readOffset { + if !found || !match || found && match && to < c.readOffset { return c.parseError(p) } - if !found || !match { - return c.parseError(p) + c.read() + if c.eof { + return nil } - if !c.eof { - c.read() - if !c.eof { - if c.readErr != nil { - return c.readErr - } - - return c.parseError(root) - } + if c.readErr != nil { + return c.readErr } - return nil + return c.parseError(root) } diff --git a/errors_test.go b/errors_test.go index bde940f..ecb050e 100644 --- a/errors_test.go +++ b/errors_test.go @@ -13,12 +13,6 @@ type errorTestItem struct { perr ParseError } -func checkParseError(left, right ParseError) bool { - left.registry = nil - right.registry = nil - return reflect.DeepEqual(left, right) -} - func testParseErrorItem(s *Syntax, test errorTestItem) func(t *testing.T) { return func(t *testing.T) { _, err := s.Parse(bytes.NewBufferString(test.doc)) @@ -32,9 +26,8 @@ func testParseErrorItem(s *Syntax, test errorTestItem) func(t *testing.T) { } perr.Input = "" - perr.registry = nil - if !checkParseError(*perr, test.perr) { + if !reflect.DeepEqual(*perr, test.perr) { t.Error("invalid error returned") t.Log("got: ", *perr) t.Log("expected:", test.perr) diff --git a/results.go b/results.go index d491d06..38eea6f 100644 --- a/results.go +++ b/results.go @@ -6,24 +6,44 @@ type results struct { isPending [][]int } -func (r *results) ensureOffset(offset int) { - if len(r.match) > offset { - return +func ensureOffsetInts(ints [][]int, offset int) [][]int { + if len(ints) > offset { + return ints } - if cap(r.match) > offset { - r.match = r.match[:offset+1] - return + if cap(ints) > offset { + ints = ints[:offset+1] + return ints } - r.match = r.match[:cap(r.match)] - for i := len(r.match); i <= offset; i++ { - r.match = append(r.match, nil) + ints = ints[:cap(ints)] + for i := len(ints); i <= offset; i++ { + ints = append(ints, nil) } + + return ints +} + +func ensureOffsetIDs(ids []*idSet, offset int) []*idSet { + if len(ids) > offset { + return ids + } + + if cap(ids) > offset { + ids = ids[:offset+1] + return ids + } + + ids = ids[:cap(ids)] + for i := len(ids); i <= offset; i++ { + ids = append(ids, nil) + } + + return ids } func (r *results) setMatch(offset, id, to int) { - r.ensureOffset(offset) + r.match = ensureOffsetInts(r.match, offset) for i := 0; i < len(r.match[offset]); i += 2 { if r.match[offset][i] != id || r.match[offset][i+1] != to { @@ -47,17 +67,7 @@ func (r *results) setNoMatch(offset, id int) { } } - if len(r.noMatch) <= offset { - if cap(r.noMatch) > offset { - r.noMatch = r.noMatch[:offset+1] - } else { - r.noMatch = r.noMatch[:cap(r.noMatch)] - for i := cap(r.noMatch); i <= offset; i++ { - r.noMatch = append(r.noMatch, nil) - } - } - } - + r.noMatch = ensureOffsetIDs(r.noMatch, offset) if r.noMatch[offset] == nil { r.noMatch[offset] = &idSet{} } @@ -146,17 +156,7 @@ func (r *results) pending(offset, id int) bool { } func (r *results) markPending(offset, id int) { - if len(r.isPending) <= id { - if cap(r.isPending) > id { - r.isPending = r.isPending[:id+1] - } else { - r.isPending = r.isPending[:cap(r.isPending)] - for i := cap(r.isPending); i <= id; i++ { - r.isPending = append(r.isPending, nil) - } - } - } - + r.isPending = ensureOffsetInts(r.isPending, id) for i := range r.isPending[id] { if r.isPending[id][i] == -1 { r.isPending[id][i] = offset diff --git a/sequence.go b/sequence.go index 98c22b4..ac1cbfb 100644 --- a/sequence.go +++ b/sequence.go @@ -196,34 +196,37 @@ func (p *sequenceParser) parse(c *context) { c.results.markPending(c.offset, p.id) } + var ( + currentCount int + parsed bool + ) + itemIndex := 0 - var currentCount int from := c.offset to := c.offset - var parsed bool for itemIndex < len(p.items) { p.items[itemIndex].parse(c) if !c.matchLast { - if currentCount < p.ranges[itemIndex][0] { - if c.failingParser == nil && - p.commitType()&userDefined != 0 && - p.commitType()&Whitespace == 0 && - p.commitType()&FailPass == 0 { - c.failingParser = p - } - - c.fail(from) - if !p.allChars { - c.results.unmarkPending(from, p.id) - } - - return + if currentCount >= p.ranges[itemIndex][0] { + itemIndex++ + currentCount = 0 + continue } - itemIndex++ - currentCount = 0 - continue + if c.failingParser == nil && + p.commitType()&userDefined != 0 && + p.commitType()&Whitespace == 0 && + p.commitType()&FailPass == 0 { + c.failingParser = p + } + + c.fail(from) + if !p.allChars { + c.results.unmarkPending(from, p.id) + } + + return } parsed = c.offset > to diff --git a/syntax.go b/syntax.go index f022058..bf20d27 100644 --- a/syntax.go +++ b/syntax.go @@ -61,8 +61,6 @@ type ParseError struct { // Definition tells the right-most unmatched parser definition. Definition string - - registry *registry } type Syntax struct { @@ -442,7 +440,6 @@ func (s *Syntax) Parse(r io.Reader) (*Node, error) { if err := c.finalizeParse(s.parser); err != nil { if perr, ok := err.(*ParseError); ok { perr.Input = "" - perr.registry = s.registry } return nil, err