diff --git a/choice.go b/choice.go index fbbd061..d195414 100644 --- a/choice.go +++ b/choice.go @@ -139,12 +139,12 @@ func (p *choiceParser) parse(c *context) { return } - if c.pending(c.offset, p.id) { + if c.results.pending(c.offset, p.id) { c.fail(c.offset) return } - c.markPending(c.offset, p.id) + c.results.markPending(c.offset, p.id) from := c.offset to := c.offset @@ -180,13 +180,13 @@ func (p *choiceParser) parse(c *context) { if match { c.success(to) - c.unmarkPending(from, p.id) + c.results.unmarkPending(from, p.id) return } c.results.setNoMatch(from, p.id) c.fail(from) - c.unmarkPending(from, p.id) + c.results.unmarkPending(from, p.id) } func (b *choiceBuilder) nodeName() string { return b.name } @@ -204,11 +204,11 @@ func (b *choiceBuilder) build(c *context) ([]*Node, bool) { if parsed { c.results.dropMatchTo(c.offset, b.id, to) } else { - if c.pending(c.offset, b.id) { + if c.results.pending(c.offset, b.id) { return nil, false } - c.markPending(c.offset, b.id) + c.results.markPending(c.offset, b.id) } var option builder @@ -221,7 +221,7 @@ func (b *choiceBuilder) build(c *context) ([]*Node, bool) { n, _ := option.build(c) if !parsed { - c.unmarkPending(from, b.id) + c.results.unmarkPending(from, b.id) } if b.commit&Alias != 0 { diff --git a/context.go b/context.go index 4b29c29..ff9bbf5 100644 --- a/context.go +++ b/context.go @@ -14,7 +14,6 @@ type context struct { results *results tokens []rune matchLast bool - isPending [][]int } func newContext(r io.RuneReader) *context { @@ -78,11 +77,6 @@ func (c *context) fromResults(id int) bool { return true } -// TODO: -// - try to move this to the parsers -// - try to move more -// - if doens't help performance, try move more from there to here - func (c *context) success(to int) { c.offset = to c.matchLast = true diff --git a/context_test.go b/context_test.go index a2288dc..1ab3649 100644 --- a/context_test.go +++ b/context_test.go @@ -66,33 +66,3 @@ func TestFailingRead(t *testing.T) { } }) } - -func TestPendingWithinCap(t *testing.T) { - c := newContext(bytes.NewBuffer(nil)) - - t.Run("parse", func(t *testing.T) { - for i := 0; i < 16; i++ { - c.markPending(0, i) - } - - for i := 0; i < 16; i++ { - if !c.pending(0, i) { - t.Error("failed to mark pending") - } - } - }) - - c.resetPending() - - t.Run("parse", func(t *testing.T) { - for i := 0; i < 16; i++ { - c.markPending(0, i) - } - - for i := 0; i < 16; i++ { - if !c.pending(0, i) { - t.Error("failed to mark build pending") - } - } - }) -} diff --git a/test.mml b/examples/test.mml similarity index 100% rename from test.mml rename to examples/test.mml diff --git a/mml_test.go b/mml_test.go index 37e8729..14b6807 100644 --- a/mml_test.go +++ b/mml_test.go @@ -2977,7 +2977,7 @@ func TestMMLFile(t *testing.T) { s.Init() - f, err := os.Open("test.mml") + f, err := os.Open("examples/test.mml") if err != nil { t.Error(err) return diff --git a/results.go b/results.go index d1a3c22..d491d06 100644 --- a/results.go +++ b/results.go @@ -1,8 +1,9 @@ package treerack type results struct { - noMatch []*idSet - match [][]int + noMatch []*idSet + match [][]int + isPending [][]int } func (r *results) ensureOffset(offset int) { @@ -126,17 +127,17 @@ func (r *results) dropMatchTo(offset, id, to int) { } } -func (c *context) resetPending() { - c.isPending = nil +func (r *results) resetPending() { + r.isPending = nil } -func (c *context) pending(offset, id int) bool { - if len(c.isPending) <= id { +func (r *results) pending(offset, id int) bool { + if len(r.isPending) <= id { return false } - for i := range c.isPending[id] { - if c.isPending[id][i] == offset { + for i := range r.isPending[id] { + if r.isPending[id][i] == offset { return true } } @@ -144,32 +145,32 @@ func (c *context) pending(offset, id int) bool { return false } -func (c *context) markPending(offset, id int) { - if len(c.isPending) <= id { - if cap(c.isPending) > id { - c.isPending = c.isPending[:id+1] +func (r *results) markPending(offset, id int) { + if len(r.isPending) <= id { + if cap(r.isPending) > id { + r.isPending = r.isPending[:id+1] } else { - c.isPending = c.isPending[:cap(c.isPending)] - for i := cap(c.isPending); i <= id; i++ { - c.isPending = append(c.isPending, nil) + r.isPending = r.isPending[:cap(r.isPending)] + for i := cap(r.isPending); i <= id; i++ { + r.isPending = append(r.isPending, nil) } } } - for i := range c.isPending[id] { - if c.isPending[id][i] == -1 { - c.isPending[id][i] = offset + for i := range r.isPending[id] { + if r.isPending[id][i] == -1 { + r.isPending[id][i] = offset return } } - c.isPending[id] = append(c.isPending[id], offset) + r.isPending[id] = append(r.isPending[id], offset) } -func (c *context) unmarkPending(offset, id int) { - for i := range c.isPending[id] { - if c.isPending[id][i] == offset { - c.isPending[id][i] = -1 +func (r *results) unmarkPending(offset, id int) { + for i := range r.isPending[id] { + if r.isPending[id][i] == offset { + r.isPending[id][i] = -1 break } } diff --git a/results_test.go b/results_test.go index 9e97951..f5cdf1a 100644 --- a/results_test.go +++ b/results_test.go @@ -19,3 +19,33 @@ func TestResults(t *testing.T) { } }) } + +func TestPendingWithinCap(t *testing.T) { + r := &results{} + + t.Run("parse", func(t *testing.T) { + for i := 0; i < 16; i++ { + r.markPending(0, i) + } + + for i := 0; i < 16; i++ { + if !r.pending(0, i) { + t.Error("failed to mark pending") + } + } + }) + + r.resetPending() + + t.Run("parse", func(t *testing.T) { + for i := 0; i < 16; i++ { + r.markPending(0, i) + } + + for i := 0; i < 16; i++ { + if !r.pending(0, i) { + t.Error("failed to mark build pending") + } + } + }) +} diff --git a/sequence.go b/sequence.go index b5ff16c..8287a52 100644 --- a/sequence.go +++ b/sequence.go @@ -173,12 +173,12 @@ func (p *sequenceParser) nodeID() int { return p.id } func (p *sequenceParser) parse(c *context) { if !p.allChars { - if c.pending(c.offset, p.id) { + if c.results.pending(c.offset, p.id) { c.fail(c.offset) return } - c.markPending(c.offset, p.id) + c.results.markPending(c.offset, p.id) } itemIndex := 0 @@ -192,9 +192,8 @@ func (p *sequenceParser) parse(c *context) { if !c.matchLast { if currentCount < p.ranges[itemIndex][0] { c.fail(from) - if !p.allChars { - c.unmarkPending(from, p.id) + c.results.unmarkPending(from, p.id) } return @@ -219,7 +218,7 @@ func (p *sequenceParser) parse(c *context) { } for _, g := range p.generalizations { - if c.pending(from, g) { + if c.results.pending(from, g) { c.results.setMatch(from, g, to) } } @@ -227,7 +226,7 @@ func (p *sequenceParser) parse(c *context) { c.results.setMatch(from, p.id, to) c.success(to) if !p.allChars { - c.unmarkPending(from, p.id) + c.results.unmarkPending(from, p.id) } } @@ -258,11 +257,11 @@ func (b *sequenceBuilder) build(c *context) ([]*Node, bool) { } else if parsed { c.results.dropMatchTo(c.offset, b.id, to) } else { - if c.pending(c.offset, b.id) { + if c.results.pending(c.offset, b.id) { return nil, false } - c.markPending(c.offset, b.id) + c.results.markPending(c.offset, b.id) } var ( @@ -303,7 +302,7 @@ func (b *sequenceBuilder) build(c *context) ([]*Node, bool) { } if !parsed { - c.unmarkPending(from, b.id) + c.results.unmarkPending(from, b.id) } if b.commit&Alias != 0 { diff --git a/syntax.go b/syntax.go index cda27ed..c7d933d 100644 --- a/syntax.go +++ b/syntax.go @@ -320,7 +320,7 @@ func (s *Syntax) Parse(r io.Reader) (*Node, error) { } c.offset = 0 - c.resetPending() + c.results.resetPending() n, _ := s.builder.build(c) return n[0], nil