From 0efa15656d881c214ed230991c1b0770650b1d6d Mon Sep 17 00:00:00 2001 From: Arpad Ryszka Date: Thu, 2 Nov 2017 20:49:49 +0100 Subject: [PATCH] refactor parse phase - context --- char.go | 2 +- choice.go | 20 +++++++------- context.go | 60 ++++++++++++++++++++---------------------- store.go => results.go | 16 +++++------ sequence.go | 18 ++++++------- syntax.go | 2 +- 6 files changed, 58 insertions(+), 60 deletions(-) rename store.go => results.go (85%) diff --git a/char.go b/char.go index 2b030fb..95942d3 100644 --- a/char.go +++ b/char.go @@ -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) diff --git a/choice.go b/choice.go index 05ba775..3af9157 100644 --- a/choice.go +++ b/choice.go @@ -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 } diff --git a/context.go b/context.go index 852927c..93172c0 100644 --- a/context.go +++ b/context.go @@ -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{}, + reader: r, + 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 } diff --git a/store.go b/results.go similarity index 85% rename from store.go rename to results.go index 8bd273d..ca21875 100644 --- a/store.go +++ b/results.go @@ -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 { diff --git a/sequence.go b/sequence.go index a1d49f3..4b4f585 100644 --- a/sequence.go +++ b/sequence.go @@ -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 } diff --git a/syntax.go b/syntax.go index f7e92e4..4c41834 100644 --- a/syntax.go +++ b/syntax.go @@ -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 }