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

View File

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

View File

@ -1,11 +1,11 @@
package treerack package treerack
type store struct { type results struct {
noMatch []*idSet noMatch []*idSet
match [][]int 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) { if len(s.noMatch) > offset && s.noMatch[offset] != nil && s.noMatch[offset].has(id) {
return 0, false, true return 0, false, true
} }
@ -33,7 +33,7 @@ func (s *store) getMatch(offset, id int) (int, bool, bool) {
return to, found, found 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) { if len(s.noMatch) > offset && s.noMatch[offset] != nil && s.noMatch[offset].has(id) {
return false return false
} }
@ -55,7 +55,7 @@ func (s *store) hasMatchTo(offset, id, to int) bool {
return false 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 { if len(s.match) <= offset {
return 0, false return 0, false
} }
@ -91,7 +91,7 @@ func (s *store) takeMatch(offset, id int, includedBy *idSet) (int, bool) {
return to, found return to, found
} }
func (s *store) takeMatchLength(offset, id, to int) { func (s *results) takeMatchLength(offset, id, to int) {
if len(s.match) <= offset { if len(s.match) <= offset {
return 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 { if len(s.match) > offset {
return 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) s.ensureOffset(offset)
for i := 0; i < len(s.match[offset]); i += 2 { for i := 0; i < len(s.match[offset]); i += 2 {
if s.match[offset][i] != id || s.match[offset][i+1] != to { 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) 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 { if len(s.match) > offset {
for i := 0; i < len(s.match[offset]); i += 2 { for i := 0; i < len(s.match[offset]); i += 2 {
if s.match[offset][i] != id { 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) { func (p *sequenceParser) parse(c *context) {
if !p.allChars { if !p.allChars {
if c.excluded(c.offset, p.id) { if c.pending(c.offset, p.id) {
c.fail(c.offset) c.fail(c.offset)
return return
} }
c.exclude(c.offset, p.id) c.markPending(c.offset, p.id)
} }
itemIndex := 0 itemIndex := 0
@ -196,12 +196,12 @@ func (p *sequenceParser) parse(c *context) {
for itemIndex < len(p.items) { for itemIndex < len(p.items) {
// TODO: is it ok to parse before max range check? what if max=0 // TODO: is it ok to parse before max range check? what if max=0
p.items[itemIndex].parse(c) p.items[itemIndex].parse(c)
if !c.match { 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.include(from, p.id) c.unmarkPending(from, p.id)
} }
return return
@ -227,17 +227,17 @@ func (p *sequenceParser) parse(c *context) {
if !p.allChars { if !p.allChars {
for _, includedBy := range p.includedBy { for _, includedBy := range p.includedBy {
if c.excluded(from, includedBy) { if c.pending(from, includedBy) {
c.store.setMatch(from, includedBy, to) c.results.setMatch(from, includedBy, to)
} }
} }
} }
c.store.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.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) nodeID() int { return b.id }
func (b *sequenceBuilder) build(c *context) ([]*Node, bool) { 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 { if !ok {
return nil, false return nil, false
} }

View File

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