track parsers by numeric id

This commit is contained in:
Arpad Ryszka 2017-07-15 21:49:08 +02:00
parent 9e30f1512f
commit 94a21ae755
22 changed files with 155 additions and 80 deletions

View File

@ -1,4 +1,4 @@
package parse package treerack
import ( import (
"errors" "errors"

View File

@ -1,4 +1,4 @@
package parse package treerack
import ( import (
"os" "os"

View File

@ -1,4 +1,4 @@
package parse package treerack
var bootSyntaxDefs = [][]string{{ var bootSyntaxDefs = [][]string{{
"chars", "space", "alias", " ", "chars", "space", "alias", " ",

15
char.go
View File

@ -1,7 +1,8 @@
package parse package treerack
type charParser struct { type charParser struct {
name string name string
id int
commit CommitType commit CommitType
not bool not bool
chars []rune chars []rune
@ -26,9 +27,11 @@ func newChar(
} }
func (p *charParser) nodeName() string { return p.name } func (p *charParser) nodeName() string { return p.name }
func (p *charParser) nodeID() int { return p.id }
func (p *charParser) setID(id int) { p.id = p.id }
func (p *charParser) parser(r *registry, path []string) (parser, error) { func (p *charParser) parser(r *registry, parsers []string) (parser, error) {
if stringsContain(path, p.name) { if stringsContainDeprecated(parsers, p.name) {
panic(cannotIncludeParsers(p.name)) panic(cannotIncludeParsers(p.name))
} }
@ -44,8 +47,8 @@ func (p *charParser) commitType() CommitType {
return p.commit return p.commit
} }
func (p *charParser) setIncludedBy(includedBy parser, path []string) { func (p *charParser) setIncludedBy(includedBy parser, parsers []string) {
if stringsContain(path, p.name) { if stringsContainDeprecated(parsers, p.name) {
panic(cannotIncludeParsers(p.name)) panic(cannotIncludeParsers(p.name))
} }
@ -89,7 +92,7 @@ func (p *charParser) parse(t Trace, c *context) {
if tok, ok := c.token(); ok && p.match(tok) { if tok, ok := c.token(); ok && p.match(tok) {
// t.Out1("success", string(tok)) // t.Out1("success", string(tok))
n := newNode(p.name, c.offset, c.offset+1, p.commit) n := newNode(p.name, p.id, c.offset, c.offset+1, p.commit)
c.store.set(c.offset, p.name, n) c.store.set(c.offset, p.name, n)
for _, includedBy := range p.includedBy { for _, includedBy := range p.includedBy {
includedBy.storeIncluded(c, n) includedBy.storeIncluded(c, n)

View File

@ -1,13 +1,15 @@
package parse package treerack
type choiceDefinition struct { type choiceDefinition struct {
name string name string
id int
commit CommitType commit CommitType
elements []string elements []string
} }
type choiceParser struct { type choiceParser struct {
name string name string
id int
commit CommitType commit CommitType
elements []parser elements []parser
includedBy []parser includedBy []parser
@ -22,8 +24,10 @@ func newChoice(name string, ct CommitType, elements []string) *choiceDefinition
} }
func (d *choiceDefinition) nodeName() string { return d.name } func (d *choiceDefinition) nodeName() string { return d.name }
func (d *choiceDefinition) nodeID() int { return d.id }
func (d *choiceDefinition) setID(id int) { d.id = id }
func (d *choiceDefinition) parser(r *registry, path []string) (parser, error) { func (d *choiceDefinition) parser(r *registry, parsers []string) (parser, error) {
p, ok := r.parser(d.name) p, ok := r.parser(d.name)
if ok { if ok {
return p, nil return p, nil
@ -31,18 +35,19 @@ func (d *choiceDefinition) parser(r *registry, path []string) (parser, error) {
cp := &choiceParser{ cp := &choiceParser{
name: d.name, name: d.name,
id: d.id,
commit: d.commit, commit: d.commit,
} }
r.setParser(cp) r.setParser(cp)
var elements []parser var elements []parser
path = append(path, d.name) parsers = append(parsers, d.name)
for _, e := range d.elements { for _, e := range d.elements {
element, ok := r.parser(e) element, ok := r.parser(e)
if ok { if ok {
elements = append(elements, element) elements = append(elements, element)
element.setIncludedBy(cp, path) element.setIncludedBy(cp, parsers)
continue continue
} }
@ -51,12 +56,12 @@ func (d *choiceDefinition) parser(r *registry, path []string) (parser, error) {
return nil, parserNotFound(e) return nil, parserNotFound(e)
} }
element, err := elementDefinition.parser(r, path) element, err := elementDefinition.parser(r, parsers)
if err != nil { if err != nil {
return nil, err return nil, err
} }
element.setIncludedBy(cp, path) element.setIncludedBy(cp, parsers)
elements = append(elements, element) elements = append(elements, element)
} }
@ -69,9 +74,10 @@ func (d *choiceDefinition) commitType() CommitType {
} }
func (p *choiceParser) nodeName() string { return p.name } func (p *choiceParser) nodeName() string { return p.name }
func (p *choiceParser) nodeID() int { return p.id }
func (p *choiceParser) setIncludedBy(includedBy parser, path []string) { func (p *choiceParser) setIncludedBy(includedBy parser, parsers []string) {
if stringsContain(path, p.name) { if stringsContainDeprecated(parsers, p.name) {
return return
} }
@ -79,11 +85,11 @@ func (p *choiceParser) setIncludedBy(includedBy parser, path []string) {
} }
func (p *choiceParser) storeIncluded(c *context, n *Node) { func (p *choiceParser) storeIncluded(c *context, n *Node) {
if !c.excluded(n.From, p.name) { if !c.excluded(n.From, p.id) {
return return
} }
nc := newNode(p.name, n.From, n.To, p.commit) nc := newNode(p.name, p.id, n.From, n.To, p.commit)
nc.append(n) nc.append(n)
c.store.set(nc.From, p.name, nc) c.store.set(nc.From, p.name, nc)
@ -107,16 +113,16 @@ func (p *choiceParser) parse(t Trace, c *context) {
return return
} }
if c.excluded(c.offset, p.name) { if c.excluded(c.offset, p.id) {
// t.Out1("excluded") // t.Out1("excluded")
c.fail(c.offset) c.fail(c.offset)
return return
} }
c.exclude(c.offset, p.name) c.exclude(c.offset, p.id)
defer c.include(c.offset, p.name) defer c.include(c.offset, p.id) // TODO: test if can be optimized
node := newNode(p.name, c.offset, c.offset, p.commit) node := newNode(p.name, p.id, c.offset, c.offset, p.commit)
var match bool var match bool
for { for {
@ -134,7 +140,7 @@ func (p *choiceParser) parse(t Trace, c *context) {
match = true match = true
foundMatch = true foundMatch = true
node = newNode(p.name, c.offset, c.offset, p.commit) node = newNode(p.name, p.id, c.offset, c.offset, p.commit)
node.append(c.node) node.append(c.node)
c.store.set(node.From, p.name, node) c.store.set(node.From, p.name, node)

View File

@ -1,4 +1,4 @@
package parse package treerack
import ( import (
"io" "io"
@ -15,7 +15,7 @@ type context struct {
tokens []rune tokens []rune
match bool match bool
node *Node node *Node
isExcluded [][]string isExcluded []*idSet
} }
func newContext(r io.RuneReader) *context { func newContext(r io.RuneReader) *context {
@ -64,16 +64,16 @@ func (c *context) token() (rune, bool) {
return c.tokens[c.offset], true return c.tokens[c.offset], true
} }
func (c *context) excluded(offset int, name string) bool { func (c *context) excluded(offset int, id int) bool {
if len(c.isExcluded) <= offset { if len(c.isExcluded) <= offset || c.isExcluded[offset] == nil {
return false return false
} }
return stringsContain(c.isExcluded[offset], name) return c.isExcluded[offset].has(id)
} }
func (c *context) exclude(offset int, name string) { func (c *context) exclude(offset int, id int) {
if c.excluded(offset, name) { if c.excluded(offset, id) {
return return
} }
@ -84,25 +84,24 @@ func (c *context) exclude(offset int, name string) {
} else { } else {
c.isExcluded = append( c.isExcluded = append(
c.isExcluded[:cap(c.isExcluded)], c.isExcluded[:cap(c.isExcluded)],
make([][]string, offset+1-cap(c.isExcluded))..., make([]*idSet, offset+1-cap(c.isExcluded))...,
) )
} }
} }
c.isExcluded[offset] = append(c.isExcluded[offset], name) if c.isExcluded[offset] == nil {
c.isExcluded[offset] = &idSet{}
}
c.isExcluded[offset].set(id)
} }
func (c *context) include(offset int, name string) { func (c *context) include(offset int, id int) {
if len(c.isExcluded) <= offset { if len(c.isExcluded) <= offset || c.isExcluded[offset] == nil {
return return
} }
for i := len(c.isExcluded[offset]) - 1; i >= 0; i-- { c.isExcluded[offset].unset(id)
if c.isExcluded[offset][i] == name {
c.isExcluded[offset] = append(c.isExcluded[offset][:i], c.isExcluded[offset][i+1:]...)
return
}
}
} }
func (c *context) fromStore(name string) (bool, bool) { func (c *context) fromStore(name string) (bool, bool) {

View File

@ -1,4 +1,4 @@
package parse package treerack
import "strconv" import "strconv"

View File

@ -1,4 +1,4 @@
package parse package treerack
import ( import (
"bytes" "bytes"

45
idset.go Normal file
View File

@ -0,0 +1,45 @@
package treerack
import "strconv"
type idSet struct {
ids []uint
}
func divModBits(id int) (int, int) {
return id / strconv.IntSize, id % strconv.IntSize
}
func (s *idSet) set(id int) {
d, m := divModBits(id)
if d >= len(s.ids) {
if d < cap(s.ids) {
s.ids = s.ids[:d+1]
} else {
s.ids = s.ids[:cap(s.ids)]
for i := cap(s.ids); i <= d; i++ {
s.ids = append(s.ids, 0)
}
}
}
s.ids[d] |= 1 << uint(m)
}
func (s *idSet) unset(id int) {
d, m := divModBits(id)
if d >= len(s.ids) {
return
}
s.ids[d] &^= 1 << uint(m)
}
func (s *idSet) has(id int) bool {
d, m := divModBits(id)
if d >= len(s.ids) {
return false
}
return s.ids[d]&(1<<uint(m)) != 0
}

View File

@ -1,4 +1,4 @@
package parse package treerack
import ( import (
"bytes" "bytes"

View File

@ -1,4 +1,4 @@
package parse package treerack
import "testing" import "testing"

View File

@ -1,4 +1,4 @@
package parse package treerack
import "testing" import "testing"

View File

@ -1,18 +1,20 @@
package parse package treerack
import "fmt" import "fmt"
type Node struct { type Node struct {
Name string Name string
id int
Nodes []*Node Nodes []*Node
From, To int From, To int
commitType CommitType commitType CommitType
tokens []rune tokens []rune
} }
func newNode(name string, from, to int, ct CommitType) *Node { func newNode(name string, id int, from, to int, ct CommitType) *Node {
return &Node{ return &Node{
Name: name, Name: name,
id: id,
From: from, From: from,
To: to, To: to,
commitType: ct, commitType: ct,

View File

@ -1,15 +1,18 @@
package parse package treerack
import "fmt" import "fmt"
type definition interface { type definition interface {
nodeName() string nodeName() string
nodeID() int
setID(int)
parser(*registry, []string) (parser, error) parser(*registry, []string) (parser, error)
commitType() CommitType commitType() CommitType
} }
type parser interface { type parser interface {
nodeName() string nodeName() string
nodeID() int
setIncludedBy(parser, []string) setIncludedBy(parser, []string)
storeIncluded(*context, *Node) storeIncluded(*context, *Node)
parse(Trace, *context) parse(Trace, *context)
@ -23,7 +26,7 @@ func cannotIncludeParsers(name string) error {
return fmt.Errorf("parser: %s cannot include other parsers", name) return fmt.Errorf("parser: %s cannot include other parsers", name)
} }
func stringsContain(ss []string, s string) bool { func stringsContainDeprecated(ss []string, s string) bool {
for _, si := range ss { for _, si := range ss {
if si == s { if si == s {
return true return true

View File

@ -1,4 +1,4 @@
package parse package treerack
import ( import (
"bytes" "bytes"

View File

@ -1,12 +1,17 @@
package parse package treerack
type registry struct { type registry struct {
idSeed int
ids map[string]int
names map[int]string
definitions map[string]definition definitions map[string]definition
parsers map[string]parser parsers map[string]parser
} }
func newRegistry() *registry { func newRegistry() *registry {
return &registry{ return &registry{
ids: make(map[string]int),
names: make(map[int]string),
definitions: make(map[string]definition), definitions: make(map[string]definition),
parsers: make(map[string]parser), parsers: make(map[string]parser),
} }
@ -27,6 +32,12 @@ func (r *registry) setDefinition(d definition) error {
return duplicateDefinition(d.nodeName()) return duplicateDefinition(d.nodeName())
} }
r.idSeed++
id := r.idSeed
d.setID(id)
r.ids[d.nodeName()] = id
r.names[id] = d.nodeName()
r.definitions[d.nodeName()] = d r.definitions[d.nodeName()] = d
return nil return nil
} }

View File

@ -1,4 +1,4 @@
package parse package treerack
import "testing" import "testing"

View File

@ -1,13 +1,15 @@
package parse package treerack
type sequenceDefinition struct { type sequenceDefinition struct {
name string name string
id int
commit CommitType commit CommitType
items []SequenceItem items []SequenceItem
} }
type sequenceParser struct { type sequenceParser struct {
name string name string
id int
commit CommitType commit CommitType
items []parser items []parser
ranges [][]int ranges [][]int
@ -23,9 +25,11 @@ func newSequence(name string, ct CommitType, items []SequenceItem) *sequenceDefi
} }
func (d *sequenceDefinition) nodeName() string { return d.name } func (d *sequenceDefinition) nodeName() string { return d.name }
func (d *sequenceDefinition) nodeID() int { return d.id }
func (d *sequenceDefinition) setID(id int) { d.id = id }
func (d *sequenceDefinition) parser(r *registry, path []string) (parser, error) { func (d *sequenceDefinition) parser(r *registry, parsers []string) (parser, error) {
if stringsContain(path, d.name) { if stringsContainDeprecated(parsers, d.name) {
panic(cannotIncludeParsers(d.name)) panic(cannotIncludeParsers(d.name))
} }
@ -36,6 +40,7 @@ func (d *sequenceDefinition) parser(r *registry, path []string) (parser, error)
sp := &sequenceParser{ sp := &sequenceParser{
name: d.name, name: d.name,
id: d.id,
commit: d.commit, commit: d.commit,
} }
@ -46,7 +51,7 @@ func (d *sequenceDefinition) parser(r *registry, path []string) (parser, error)
ranges [][]int ranges [][]int
) )
path = append(path, d.name) parsers = append(parsers, d.name)
for _, item := range d.items { for _, item := range d.items {
if item.Min == 0 && item.Max == 0 { if item.Min == 0 && item.Max == 0 {
item.Min, item.Max = 1, 1 item.Min, item.Max = 1, 1
@ -66,7 +71,7 @@ func (d *sequenceDefinition) parser(r *registry, path []string) (parser, error)
return nil, parserNotFound(item.Name) return nil, parserNotFound(item.Name)
} }
pi, err := itemDefinition.parser(r, path) pi, err := itemDefinition.parser(r, parsers)
if err != nil { if err != nil {
return nil, err return nil, err
} }
@ -77,7 +82,7 @@ func (d *sequenceDefinition) parser(r *registry, path []string) (parser, error)
// for single items, acts like a choice // for single items, acts like a choice
if len(items) == 1 && ranges[0][0] == 1 && ranges[0][1] == 1 { if len(items) == 1 && ranges[0][0] == 1 && ranges[0][1] == 1 {
items[0].setIncludedBy(sp, path) items[0].setIncludedBy(sp, parsers)
} }
sp.items = items sp.items = items
@ -90,9 +95,10 @@ func (d *sequenceDefinition) commitType() CommitType {
} }
func (p *sequenceParser) nodeName() string { return p.name } func (p *sequenceParser) nodeName() string { return p.name }
func (p *sequenceParser) nodeID() int { return p.id }
func (p *sequenceParser) setIncludedBy(includedBy parser, path []string) { func (p *sequenceParser) setIncludedBy(includedBy parser, parsers []string) {
if stringsContain(path, p.name) { if stringsContainDeprecated(parsers, p.name) {
return return
} }
@ -100,11 +106,11 @@ func (p *sequenceParser) setIncludedBy(includedBy parser, path []string) {
} }
func (p *sequenceParser) storeIncluded(c *context, n *Node) { func (p *sequenceParser) storeIncluded(c *context, n *Node) {
if !c.excluded(n.From, p.name) { if !c.excluded(n.From, p.id) {
return return
} }
nc := newNode(p.name, n.From, n.To, p.commit) nc := newNode(p.name, p.id, n.From, n.To, p.commit)
nc.append(n) nc.append(n)
c.store.set(nc.From, p.name, nc) c.store.set(nc.From, p.name, nc)
@ -123,19 +129,19 @@ func (p *sequenceParser) parse(t Trace, c *context) {
return return
} }
if c.excluded(c.offset, p.name) { if c.excluded(c.offset, p.id) {
// t.Out1("excluded") // t.Out1("excluded")
c.fail(c.offset) c.fail(c.offset)
return return
} }
c.exclude(c.offset, p.name) c.exclude(c.offset, p.id)
defer c.include(c.offset, p.name) defer c.include(c.offset, p.id)
items := p.items items := p.items
ranges := p.ranges ranges := p.ranges
var currentCount int var currentCount int
node := newNode(p.name, c.offset, c.offset, p.commit) node := newNode(p.name, p.id, c.offset, c.offset, p.commit)
for len(items) > 0 { for len(items) > 0 {
m, ok := c.fromStore(items[0].nodeName()) m, ok := c.fromStore(items[0].nodeName())

View File

@ -1,4 +1,4 @@
package parse package treerack
import "testing" import "testing"

View File

@ -1,4 +1,4 @@
package parse package treerack
type storedItem struct { type storedItem struct {
name string name string

View File

@ -1,4 +1,4 @@
package parse package treerack
import ( import (
"bufio" "bufio"
@ -26,7 +26,7 @@ type Syntax struct {
registry *registry registry *registry
initialized bool initialized bool
initFailed bool initFailed bool
rootSet bool explicitRoot bool
root definition root definition
parser parser parser parser
} }
@ -70,8 +70,8 @@ func (s *Syntax) register(d definition) error {
if d.commitType()&Root != 0 { if d.commitType()&Root != 0 {
s.root = d s.root = d
s.rootSet = true s.explicitRoot = true
} else if !s.rootSet { } else if !s.explicitRoot {
s.root = d s.root = d
} }

View File

@ -1,4 +1,4 @@
package parse package treerack
import ( import (
"fmt" "fmt"