simplify build time pending check

This commit is contained in:
Arpad Ryszka 2017-11-06 11:41:00 +01:00
parent 1ed65518e6
commit 062ad5b046
9 changed files with 71 additions and 77 deletions

View File

@ -139,12 +139,12 @@ func (p *choiceParser) parse(c *context) {
return return
} }
if c.pending(c.offset, p.id) { if c.results.pending(c.offset, p.id) {
c.fail(c.offset) c.fail(c.offset)
return return
} }
c.markPending(c.offset, p.id) c.results.markPending(c.offset, p.id)
from := c.offset from := c.offset
to := c.offset to := c.offset
@ -180,13 +180,13 @@ func (p *choiceParser) parse(c *context) {
if match { if match {
c.success(to) c.success(to)
c.unmarkPending(from, p.id) c.results.unmarkPending(from, p.id)
return return
} }
c.results.setNoMatch(from, p.id) c.results.setNoMatch(from, p.id)
c.fail(from) c.fail(from)
c.unmarkPending(from, p.id) c.results.unmarkPending(from, p.id)
} }
func (b *choiceBuilder) nodeName() string { return b.name } func (b *choiceBuilder) nodeName() string { return b.name }
@ -204,11 +204,11 @@ func (b *choiceBuilder) build(c *context) ([]*Node, bool) {
if parsed { if parsed {
c.results.dropMatchTo(c.offset, b.id, to) c.results.dropMatchTo(c.offset, b.id, to)
} else { } else {
if c.pending(c.offset, b.id) { if c.results.pending(c.offset, b.id) {
return nil, false return nil, false
} }
c.markPending(c.offset, b.id) c.results.markPending(c.offset, b.id)
} }
var option builder var option builder
@ -221,7 +221,7 @@ func (b *choiceBuilder) build(c *context) ([]*Node, bool) {
n, _ := option.build(c) n, _ := option.build(c)
if !parsed { if !parsed {
c.unmarkPending(from, b.id) c.results.unmarkPending(from, b.id)
} }
if b.commit&Alias != 0 { if b.commit&Alias != 0 {

View File

@ -14,7 +14,6 @@ type context struct {
results *results results *results
tokens []rune tokens []rune
matchLast bool matchLast bool
isPending [][]int
} }
func newContext(r io.RuneReader) *context { func newContext(r io.RuneReader) *context {
@ -78,11 +77,6 @@ func (c *context) fromResults(id int) bool {
return true 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) { func (c *context) success(to int) {
c.offset = to c.offset = to
c.matchLast = true c.matchLast = true

View File

@ -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")
}
}
})
}

View File

@ -2977,7 +2977,7 @@ func TestMMLFile(t *testing.T) {
s.Init() s.Init()
f, err := os.Open("test.mml") f, err := os.Open("examples/test.mml")
if err != nil { if err != nil {
t.Error(err) t.Error(err)
return return

View File

@ -3,6 +3,7 @@ package treerack
type results struct { type results struct {
noMatch []*idSet noMatch []*idSet
match [][]int match [][]int
isPending [][]int
} }
func (r *results) ensureOffset(offset int) { func (r *results) ensureOffset(offset int) {
@ -126,17 +127,17 @@ func (r *results) dropMatchTo(offset, id, to int) {
} }
} }
func (c *context) resetPending() { func (r *results) resetPending() {
c.isPending = nil r.isPending = nil
} }
func (c *context) pending(offset, id int) bool { func (r *results) pending(offset, id int) bool {
if len(c.isPending) <= id { if len(r.isPending) <= id {
return false return false
} }
for i := range c.isPending[id] { for i := range r.isPending[id] {
if c.isPending[id][i] == offset { if r.isPending[id][i] == offset {
return true return true
} }
} }
@ -144,32 +145,32 @@ func (c *context) pending(offset, id int) bool {
return false return false
} }
func (c *context) markPending(offset, id int) { func (r *results) markPending(offset, id int) {
if len(c.isPending) <= id { if len(r.isPending) <= id {
if cap(c.isPending) > id { if cap(r.isPending) > id {
c.isPending = c.isPending[:id+1] r.isPending = r.isPending[:id+1]
} else { } else {
c.isPending = c.isPending[:cap(c.isPending)] r.isPending = r.isPending[:cap(r.isPending)]
for i := cap(c.isPending); i <= id; i++ { for i := cap(r.isPending); i <= id; i++ {
c.isPending = append(c.isPending, nil) r.isPending = append(r.isPending, nil)
} }
} }
} }
for i := range c.isPending[id] { for i := range r.isPending[id] {
if c.isPending[id][i] == -1 { if r.isPending[id][i] == -1 {
c.isPending[id][i] = offset r.isPending[id][i] = offset
return return
} }
} }
c.isPending[id] = append(c.isPending[id], offset) r.isPending[id] = append(r.isPending[id], offset)
} }
func (c *context) unmarkPending(offset, id int) { func (r *results) unmarkPending(offset, id int) {
for i := range c.isPending[id] { for i := range r.isPending[id] {
if c.isPending[id][i] == offset { if r.isPending[id][i] == offset {
c.isPending[id][i] = -1 r.isPending[id][i] = -1
break break
} }
} }

View File

@ -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")
}
}
})
}

View File

@ -173,12 +173,12 @@ func (p *sequenceParser) nodeID() int { return p.id }
func (p *sequenceParser) parse(c *context) { func (p *sequenceParser) parse(c *context) {
if !p.allChars { if !p.allChars {
if c.pending(c.offset, p.id) { if c.results.pending(c.offset, p.id) {
c.fail(c.offset) c.fail(c.offset)
return return
} }
c.markPending(c.offset, p.id) c.results.markPending(c.offset, p.id)
} }
itemIndex := 0 itemIndex := 0
@ -192,9 +192,8 @@ func (p *sequenceParser) parse(c *context) {
if !c.matchLast { if !c.matchLast {
if currentCount < p.ranges[itemIndex][0] { if currentCount < p.ranges[itemIndex][0] {
c.fail(from) c.fail(from)
if !p.allChars { if !p.allChars {
c.unmarkPending(from, p.id) c.results.unmarkPending(from, p.id)
} }
return return
@ -219,7 +218,7 @@ func (p *sequenceParser) parse(c *context) {
} }
for _, g := range p.generalizations { for _, g := range p.generalizations {
if c.pending(from, g) { if c.results.pending(from, g) {
c.results.setMatch(from, g, to) c.results.setMatch(from, g, to)
} }
} }
@ -227,7 +226,7 @@ func (p *sequenceParser) parse(c *context) {
c.results.setMatch(from, p.id, to) c.results.setMatch(from, p.id, to)
c.success(to) c.success(to)
if !p.allChars { 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 { } else if parsed {
c.results.dropMatchTo(c.offset, b.id, to) c.results.dropMatchTo(c.offset, b.id, to)
} else { } else {
if c.pending(c.offset, b.id) { if c.results.pending(c.offset, b.id) {
return nil, false return nil, false
} }
c.markPending(c.offset, b.id) c.results.markPending(c.offset, b.id)
} }
var ( var (
@ -303,7 +302,7 @@ func (b *sequenceBuilder) build(c *context) ([]*Node, bool) {
} }
if !parsed { if !parsed {
c.unmarkPending(from, b.id) c.results.unmarkPending(from, b.id)
} }
if b.commit&Alias != 0 { if b.commit&Alias != 0 {

View File

@ -320,7 +320,7 @@ func (s *Syntax) Parse(r io.Reader) (*Node, error) {
} }
c.offset = 0 c.offset = 0
c.resetPending() c.results.resetPending()
n, _ := s.builder.build(c) n, _ := s.builder.build(c)
return n[0], nil return n[0], nil