diff --git a/.gitignore b/.gitignore index a1338d6..e104a7d 100644 --- a/.gitignore +++ b/.gitignore @@ -1,14 +1,2 @@ -# Binaries for programs and plugins -*.exe -*.dll -*.so -*.dylib - -# Test binary, build with `go test -c` *.test - -# Output of the go coverage tool, specifically when used with LiteIDE *.out - -# Project-local glide cache, RE: https://github.com/Masterminds/glide/issues/736 -.glide/ diff --git a/Makefile b/Makefile index e2fa897..4e2a6db 100644 --- a/Makefile +++ b/Makefile @@ -14,4 +14,15 @@ check: build fmt: $(SOURCES) @gofmt -w -s $(SOURCES) +cpu.out: $(SOURCES) + go test -v -run TestMMLFile -cpuprofile cpu.out + +cpu: cpu.out + go tool pprof -top cpu.out + precommit: fmt build check + +clean: + @rm -f *.test + @rm -f cpu.out + @go clean -i ./... diff --git a/char.go b/char.go index d09a066..1514e0c 100644 --- a/char.go +++ b/char.go @@ -68,6 +68,22 @@ func (p *charParser) match(t rune) bool { return p.not } +func (p *charParser) matchBuild(t rune) bool { + for _, ci := range p.chars { + if ci == t { + return !p.not + } + } + + for _, ri := range p.ranges { + if t >= ri[0] && t <= ri[1] { + return !p.not + } + } + + return p.not +} + func (p *charParser) parse(t Trace, c *context) { // t = t.Extend(p.name) // t.Out1("parsing", c.offset) @@ -86,12 +102,13 @@ func (p *charParser) parse(t Trace, c *context) { } func (p *charParser) build(c *context) ([]*Node, bool) { + // TODO: how to remove this check t, ok := c.token() if !ok { panic("damaged parser context") } - if !p.match(t) { + if !p.matchBuild(t) { return nil, false } diff --git a/choice.go b/choice.go index 4b7193f..5db1676 100644 --- a/choice.go +++ b/choice.go @@ -22,7 +22,7 @@ type choiceBuilder struct { id int commit CommitType elements []builder - includedBy []int + includedBy *idSet } func newChoice(name string, ct CommitType, elements []string) *choiceDefinition { @@ -41,9 +41,10 @@ func (d *choiceDefinition) commitType() CommitType { return d.commit } func (d *choiceDefinition) init(r *registry) error { if d.cbuilder == nil { d.cbuilder = &choiceBuilder{ - name: d.name, - id: d.id, - commit: d.commit, + name: d.name, + id: d.id, + commit: d.commit, + includedBy: &idSet{}, } } @@ -70,13 +71,14 @@ func (d *choiceDefinition) setIncludedBy(r *registry, includedBy int, parsers *i if d.cbuilder == nil { d.cbuilder = &choiceBuilder{ - name: d.name, - id: d.id, - commit: d.commit, + name: d.name, + id: d.id, + commit: d.commit, + includedBy: &idSet{}, } } - d.cbuilder.includedBy = appendIfMissing(d.cbuilder.includedBy, includedBy) + d.cbuilder.includedBy.set(includedBy) parsers.set(d.id) return setItemsIncludedBy(r, d.elements, includedBy, parsers) @@ -131,9 +133,10 @@ func (d *choiceDefinition) parser(r *registry, parsers *idSet) (parser, error) { func (d *choiceDefinition) builder() builder { if d.cbuilder == nil { d.cbuilder = &choiceBuilder{ - name: d.name, - id: d.id, - commit: d.commit, + name: d.name, + id: d.id, + commit: d.commit, + includedBy: &idSet{}, } } @@ -172,9 +175,10 @@ func (p *choiceParser) parse(t Trace, c *context) { var match bool var nextTo int var elementIndex int + var foundMatch bool for { - var foundMatch bool + foundMatch = false elementIndex = 0 for elementIndex < len(p.elements) { @@ -222,19 +226,14 @@ 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) + to, ok := c.store.takeMatch(c.offset, b.id, b.includedBy) if !ok { return nil, false } - for _, ib := range b.includedBy { - c.store.takeMatchLength(c.offset, ib, to) - } - var element builder for _, e := range b.elements { - elementTo, match, _ := c.store.getMatch(c.offset, e.nodeID()) - if match && elementTo == to { + if c.store.hasMatchTo(c.offset, e.nodeID(), to) { element = e break } diff --git a/context.go b/context.go index b9ea63e..eaec093 100644 --- a/context.go +++ b/context.go @@ -90,13 +90,21 @@ func (c *context) exclude(offset int, id int) { } } + for i := range c.isExcluded[id] { + if c.isExcluded[id][i] == -1 { + c.isExcluded[id][i] = offset + return + } + } + c.isExcluded[id] = append(c.isExcluded[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] = append(c.isExcluded[id][:i], c.isExcluded[id][i+1:]...) + c.isExcluded[id][i] = -1 break } } diff --git a/sequence.go b/sequence.go index 93309b9..deefa83 100644 --- a/sequence.go +++ b/sequence.go @@ -25,7 +25,8 @@ type sequenceBuilder struct { commit CommitType items []builder ranges [][]int - includedBy []int + includedBy *idSet + allChars bool } func newSequence(name string, ct CommitType, items []SequenceItem) *sequenceDefinition { @@ -48,12 +49,14 @@ func (d *sequenceDefinition) includeItems() bool { func (d *sequenceDefinition) init(r *registry) error { if d.sbuilder == nil { d.sbuilder = &sequenceBuilder{ - name: d.name, - id: d.id, - commit: d.commit, + name: d.name, + id: d.id, + commit: d.commit, + includedBy: &idSet{}, } } + allChars := true for _, item := range d.items { if item.Min == 0 && item.Max == 0 { item.Min, item.Max = 1, 1 @@ -69,9 +72,16 @@ func (d *sequenceDefinition) init(r *registry) error { } d.sbuilder.items = append(d.sbuilder.items, def.builder()) + + if allChars { + if _, isChar := def.(*charParser); !isChar { + allChars = false + } + } } d.sbuilder.ranges = d.ranges + d.sbuilder.allChars = allChars if !d.includeItems() { return nil @@ -91,13 +101,14 @@ func (d *sequenceDefinition) setIncludedBy(r *registry, includedBy int, parsers if d.sbuilder == nil { d.sbuilder = &sequenceBuilder{ - name: d.name, - id: d.id, - commit: d.commit, + name: d.name, + id: d.id, + commit: d.commit, + includedBy: &idSet{}, } } - d.sbuilder.includedBy = appendIfMissing(d.sbuilder.includedBy, includedBy) + d.sbuilder.includedBy.set(includedBy) if !d.includeItems() { return nil @@ -158,9 +169,10 @@ func (d *sequenceDefinition) parser(r *registry, parsers *idSet) (parser, error) func (d *sequenceDefinition) builder() builder { if d.sbuilder == nil { d.sbuilder = &sequenceBuilder{ - name: d.name, - id: d.id, - commit: d.commit, + name: d.name, + id: d.id, + commit: d.commit, + includedBy: &idSet{}, } } @@ -186,16 +198,13 @@ func (p *sequenceParser) parse(t Trace, c *context) { return } - // if c.store.hasNoMatch(c.offset, p.id) { - // c.fail(c.offset) - // } - c.exclude(c.offset, p.id) itemIndex := 0 var currentCount int from := c.offset to := c.offset + var parsed bool for itemIndex < len(p.items) { // TODO: is it ok to parse before max range check? what if max=0 @@ -214,7 +223,7 @@ func (p *sequenceParser) parse(t Trace, c *context) { continue } - parsed := c.offset > to + parsed = c.offset > to if parsed { currentCount++ } @@ -244,13 +253,24 @@ 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) + to, ok := c.store.takeMatch(c.offset, b.id, b.includedBy) if !ok { return nil, false } - for _, ib := range b.includedBy { - c.store.takeMatchLength(c.offset, ib, to) + if b.allChars { + from := c.offset + c.offset = to + if b.commit&Alias != 0 { + return nil, true + } + + return []*Node{{ + Name: b.name, + From: from, + To: to, + tokens: c.tokens, + }}, true } from := c.offset diff --git a/store.go b/store.go index 6b3ffd9..3bc5660 100644 --- a/store.go +++ b/store.go @@ -10,16 +10,8 @@ type store struct { match [][]int } -func (s *store) hasNoMatch(offset, id int) bool { - if len(s.noMatch) <= offset || s.noMatch[offset] == nil { - return false - } - - return s.noMatch[offset].has(id) -} - func (s *store) getMatch(offset, id int) (int, bool, bool) { - if s.hasNoMatch(offset, id) { + if len(s.noMatch) > offset && s.noMatch[offset] != nil && s.noMatch[offset].has(id) { return 0, false, true } @@ -46,11 +38,29 @@ func (s *store) getMatch(offset, id int) (int, bool, bool) { return to, found, found } -func (s *store) takeMatch(offset, id int) (int, bool) { - if s.hasNoMatch(offset, id) { - return 0, false +func (s *store) hasMatchTo(offset, id, to int) bool { + if len(s.noMatch) > offset && s.noMatch[offset] != nil && s.noMatch[offset].has(id) { + return false } + if len(s.match) <= offset { + return false + } + + for i := 0; i < len(s.match[offset]); i += 2 { + if s.match[offset][i] != id { + continue + } + + if s.match[offset][i+1] == to { + return true + } + } + + return false +} + +func (s *store) takeMatch(offset, id int, includedBy *idSet) (int, bool) { if len(s.match) <= offset { return 0, false } @@ -75,43 +85,27 @@ func (s *store) takeMatch(offset, id int) (int, bool) { if found { s.match[offset][index] = -1 + for i := 0; i < len(s.match[offset]); i += 2 { + if includedBy.has(s.match[offset][i]) && s.match[offset][i+1] == to { + s.match[offset][i] = -1 + } + } } return to, found } -func (s *store) takeMatchLength(offset, id, to int) (int, bool) { - if s.hasNoMatch(offset, id) { - return 0, false - } - +func (s *store) takeMatchLength(offset, id, to int) { if len(s.match) <= offset { - return 0, false + return } - var ( - found bool - // index int - ) - for i := 0; i < len(s.match[offset]); i += 2 { - if s.match[offset][i] != id { - continue - } - - found = true - if s.match[offset][i+1] == to { + if s.match[offset][i] == id && s.match[offset][i+1] == to { s.match[offset][i] = -1 - return to, true - //eindex = i + return } } - - if found { - // s.match[offset][index] = -1 - } - - return to, found } func (s *store) ensureOffset(offset int) { @@ -131,15 +125,29 @@ func (s *store) ensureOffset(offset int) { } func (s *store) setMatch(offset, id, to int) { - if toe, match, ok := s.getMatch(offset, id); ok && match && toe == to { + 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 { + continue + } + return } - s.ensureOffset(offset) s.match[offset] = append(s.match[offset], id, to) } func (s *store) 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 { + continue + } + + return + } + } + if len(s.noMatch) <= offset { if cap(s.noMatch) > offset { s.noMatch = s.noMatch[:offset+1]