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
}
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 {

View File

@ -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

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()
f, err := os.Open("test.mml")
f, err := os.Open("examples/test.mml")
if err != nil {
t.Error(err)
return

View File

@ -3,6 +3,7 @@ package treerack
type results struct {
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
}
}

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) {
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 {

View File

@ -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