refactor parse phase - context

This commit is contained in:
Arpad Ryszka 2017-11-02 20:49:49 +01:00
parent e0f61f9d28
commit 0efa15656d
6 changed files with 58 additions and 60 deletions

View File

@ -70,7 +70,7 @@ func (p *charParser) parse(c *context) {
}
for _, includedBy := range p.includedBy {
c.store.setMatch(c.offset, includedBy, c.offset+1)
c.results.setMatch(c.offset, includedBy, c.offset+1)
}
c.success(c.offset + 1)

View File

@ -141,16 +141,16 @@ func (p *choiceParser) nodeName() string { return p.name }
func (p *choiceParser) nodeID() int { return p.id }
func (p *choiceParser) parse(c *context) {
if c.fromStore(p.id) {
if c.fromResults(p.id) {
return
}
if c.excluded(c.offset, p.id) {
if c.pending(c.offset, p.id) {
c.fail(c.offset)
return
}
c.exclude(c.offset, p.id)
c.markPending(c.offset, p.id)
from := c.offset
to := c.offset
@ -171,7 +171,7 @@ func (p *choiceParser) parse(c *context) {
p.elements[elementIndex].parse(c)
elementIndex++
if !c.match || match && c.offset <= to {
if !c.matchLast || match && c.offset <= to {
c.offset = from
continue
}
@ -181,7 +181,7 @@ func (p *choiceParser) parse(c *context) {
to = c.offset
c.offset = from
c.store.setMatch(from, p.id, to)
c.results.setMatch(from, p.id, to)
}
if !foundMatch {
@ -191,27 +191,27 @@ func (p *choiceParser) parse(c *context) {
if match {
c.success(to)
c.include(from, p.id)
c.unmarkPending(from, p.id)
return
}
c.store.setNoMatch(from, p.id)
c.results.setNoMatch(from, p.id)
c.fail(from)
c.include(from, p.id)
c.unmarkPending(from, p.id)
}
func (b *choiceBuilder) nodeName() string { return b.name }
func (b *choiceBuilder) nodeID() int { return b.id }
func (b *choiceBuilder) build(c *context) ([]*Node, bool) {
to, ok := c.store.takeMatch(c.offset, b.id, b.includedBy)
to, ok := c.results.takeMatch(c.offset, b.id, b.includedBy)
if !ok {
return nil, false
}
var element builder
for _, e := range b.elements {
if c.store.hasMatchTo(c.offset, e.nodeID(), to) {
if c.results.hasMatchTo(c.offset, e.nodeID(), to) {
element = e
break
}

View File

@ -11,17 +11,16 @@ type context struct {
readOffset int
readErr error
eof bool
store *store
results *results
tokens []rune
match bool
node *Node
isExcluded [][]int
matchLast bool
isPending [][]int
}
func newContext(r io.RuneReader) *context {
return &context{
reader: r,
store: &store{},
results: &results{},
}
}
@ -64,13 +63,13 @@ func (c *context) token() (rune, bool) {
return c.tokens[c.offset], true
}
func (c *context) excluded(offset int, id int) bool {
if len(c.isExcluded) <= id {
func (c *context) pending(offset int, id int) bool {
if len(c.isPending) <= id {
return false
}
for i := range c.isExcluded[id] {
if c.isExcluded[id][i] == offset {
for i := range c.isPending[id] {
if c.isPending[id][i] == offset {
return true
}
}
@ -78,40 +77,39 @@ func (c *context) excluded(offset int, id int) bool {
return false
}
func (c *context) exclude(offset int, id int) {
if len(c.isExcluded) <= id {
if cap(c.isExcluded) > id {
c.isExcluded = c.isExcluded[:id+1]
func (c *context) markPending(offset int, id int) {
if len(c.isPending) <= id {
if cap(c.isPending) > id {
c.isPending = c.isPending[:id+1]
} else {
c.isExcluded = c.isExcluded[:cap(c.isExcluded)]
for i := cap(c.isExcluded); i <= id; i++ {
c.isExcluded = append(c.isExcluded, nil)
c.isPending = c.isPending[:cap(c.isPending)]
for i := cap(c.isPending); i <= id; i++ {
c.isPending = append(c.isPending, nil)
}
}
}
for i := range c.isExcluded[id] {
if c.isExcluded[id][i] == -1 {
c.isExcluded[id][i] = offset
for i := range c.isPending[id] {
if c.isPending[id][i] == -1 {
c.isPending[id][i] = offset
return
}
}
c.isExcluded[id] = append(c.isExcluded[id], offset)
c.isPending[id] = append(c.isPending[id], offset)
}
func (c *context) include(offset int, id int) {
for i := range c.isExcluded[id] {
if c.isExcluded[id][i] == offset {
// c.isExcluded[id] = append(c.isExcluded[id][:i], c.isExcluded[id][i+1:]...)
c.isExcluded[id][i] = -1
func (c *context) unmarkPending(offset int, id int) {
for i := range c.isPending[id] {
if c.isPending[id][i] == offset {
c.isPending[id][i] = -1
break
}
}
}
func (c *context) fromStore(id int) bool {
to, m, ok := c.store.getMatch(c.offset, id)
func (c *context) fromResults(id int) bool {
to, m, ok := c.results.getMatch(c.offset, id)
if !ok {
return false
}
@ -127,17 +125,17 @@ func (c *context) fromStore(id int) bool {
func (c *context) success(to int) {
c.offset = to
c.match = true
c.matchLast = true
}
func (c *context) fail(offset int) {
c.offset = offset
c.match = false
c.matchLast = false
}
func (c *context) finalize(root parser) error {
rootID := root.nodeID()
to, match, found := c.store.getMatch(0, rootID)
to, match, found := c.results.getMatch(0, rootID)
if !found || !match || to < c.readOffset {
return ErrUnexpectedCharacter
}

View File

@ -1,11 +1,11 @@
package treerack
type store struct {
type results struct {
noMatch []*idSet
match [][]int
}
func (s *store) getMatch(offset, id int) (int, bool, bool) {
func (s *results) getMatch(offset, id int) (int, bool, bool) {
if len(s.noMatch) > offset && s.noMatch[offset] != nil && s.noMatch[offset].has(id) {
return 0, false, true
}
@ -33,7 +33,7 @@ func (s *store) getMatch(offset, id int) (int, bool, bool) {
return to, found, found
}
func (s *store) hasMatchTo(offset, id, to int) bool {
func (s *results) hasMatchTo(offset, id, to int) bool {
if len(s.noMatch) > offset && s.noMatch[offset] != nil && s.noMatch[offset].has(id) {
return false
}
@ -55,7 +55,7 @@ func (s *store) hasMatchTo(offset, id, to int) bool {
return false
}
func (s *store) takeMatch(offset, id int, includedBy *idSet) (int, bool) {
func (s *results) takeMatch(offset, id int, includedBy *idSet) (int, bool) {
if len(s.match) <= offset {
return 0, false
}
@ -91,7 +91,7 @@ func (s *store) takeMatch(offset, id int, includedBy *idSet) (int, bool) {
return to, found
}
func (s *store) takeMatchLength(offset, id, to int) {
func (s *results) takeMatchLength(offset, id, to int) {
if len(s.match) <= offset {
return
}
@ -104,7 +104,7 @@ func (s *store) takeMatchLength(offset, id, to int) {
}
}
func (s *store) ensureOffset(offset int) {
func (s *results) ensureOffset(offset int) {
if len(s.match) > offset {
return
}
@ -120,7 +120,7 @@ func (s *store) ensureOffset(offset int) {
}
}
func (s *store) setMatch(offset, id, to int) {
func (s *results) setMatch(offset, id, to int) {
s.ensureOffset(offset)
for i := 0; i < len(s.match[offset]); i += 2 {
if s.match[offset][i] != id || s.match[offset][i+1] != to {
@ -133,7 +133,7 @@ func (s *store) setMatch(offset, id, to int) {
s.match[offset] = append(s.match[offset], id, to)
}
func (s *store) setNoMatch(offset, id int) {
func (s *results) setNoMatch(offset, id int) {
if len(s.match) > offset {
for i := 0; i < len(s.match[offset]); i += 2 {
if s.match[offset][i] != id {

View File

@ -179,12 +179,12 @@ func (p *sequenceParser) nodeID() int { return p.id }
func (p *sequenceParser) parse(c *context) {
if !p.allChars {
if c.excluded(c.offset, p.id) {
if c.pending(c.offset, p.id) {
c.fail(c.offset)
return
}
c.exclude(c.offset, p.id)
c.markPending(c.offset, p.id)
}
itemIndex := 0
@ -196,12 +196,12 @@ func (p *sequenceParser) parse(c *context) {
for itemIndex < len(p.items) {
// TODO: is it ok to parse before max range check? what if max=0
p.items[itemIndex].parse(c)
if !c.match {
if !c.matchLast {
if currentCount < p.ranges[itemIndex][0] {
c.fail(from)
if !p.allChars {
c.include(from, p.id)
c.unmarkPending(from, p.id)
}
return
@ -227,17 +227,17 @@ func (p *sequenceParser) parse(c *context) {
if !p.allChars {
for _, includedBy := range p.includedBy {
if c.excluded(from, includedBy) {
c.store.setMatch(from, includedBy, to)
if c.pending(from, includedBy) {
c.results.setMatch(from, includedBy, to)
}
}
}
c.store.setMatch(from, p.id, to)
c.results.setMatch(from, p.id, to)
c.success(to)
if !p.allChars {
c.include(from, p.id)
c.unmarkPending(from, p.id)
}
}
@ -245,7 +245,7 @@ func (b *sequenceBuilder) nodeName() string { return b.name }
func (b *sequenceBuilder) nodeID() int { return b.id }
func (b *sequenceBuilder) build(c *context) ([]*Node, bool) {
to, ok := c.store.takeMatch(c.offset, b.id, b.includedBy)
to, ok := c.results.takeMatch(c.offset, b.id, b.includedBy)
if !ok {
return nil, false
}

View File

@ -313,7 +313,7 @@ func (s *Syntax) Parse(r io.Reader) (*Node, error) {
return nil, c.readErr
}
if !c.match {
if !c.matchLast {
return nil, ErrInvalidInput
}