diff --git a/char.go b/char.go index 24dfd9a..4f588dd 100644 --- a/char.go +++ b/char.go @@ -3,7 +3,6 @@ package treerack type charParser struct { name string id int - commit CommitType not bool chars []rune ranges [][]rune @@ -12,14 +11,12 @@ type charParser struct { func newChar( name string, - ct CommitType, not bool, chars []rune, ranges [][]rune, ) *charParser { return &charParser{ name: name, - commit: ct, not: not, chars: chars, ranges: ranges, @@ -29,6 +26,7 @@ func newChar( func (p *charParser) nodeName() string { return p.name } func (p *charParser) nodeID() int { return p.id } func (p *charParser) setID(id int) { p.id = id } +func (p *charParser) commitType() CommitType { return Alias } func (p *charParser) init(r *registry) error { return nil } @@ -50,12 +48,8 @@ func (p *charParser) parser(r *registry, parsers *idSet) (parser, error) { return p, nil } -func (p *charParser) commitType() CommitType { - return p.commit -} - -func (p *charParser) storeIncluded(*context, int, int) { - panic(cannotIncludeParsers(p.name)) +func (p *charParser) builder() builder { + return p } func (p *charParser) match(t rune) bool { @@ -85,3 +79,18 @@ func (p *charParser) parse(t Trace, c *context) { c.store.setMatch(c.offset, includedBy, c.offset+1) } } + +func (p *charParser) build(c *context) ([]*Node, bool) { + t, ok := c.token() + if !ok { + panic("damaged parser context") + } + + if !p.match(t) { + return nil, false + } + + // always alias + c.offset++ + return nil, true +} diff --git a/choice.go b/choice.go index a0f9ce0..4377cf0 100644 --- a/choice.go +++ b/choice.go @@ -16,6 +16,12 @@ type choiceParser struct { includedBy []int } +type choiceBuilder struct { + name string + id int + commit CommitType +} + func newChoice(name string, ct CommitType, elements []string) *choiceDefinition { return &choiceDefinition{ name: name, @@ -27,6 +33,7 @@ func newChoice(name string, ct CommitType, elements []string) *choiceDefinition 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) commitType() CommitType { return d.commit } func (d *choiceDefinition) init(r *registry) error { parsers := &idSet{} @@ -44,6 +51,10 @@ func (d *choiceDefinition) setIncludedBy(r *registry, includedBy int, parsers *i return setItemsIncludedBy(r, d.elements, includedBy, parsers) } +// TODO: +// - it may be possible to initialize the parsers non-recursively +// - maybe the whole definition, parser and builder can be united + func (d *choiceDefinition) parser(r *registry, parsers *idSet) (parser, error) { p, ok := r.parser(d.name) if ok { @@ -86,8 +97,8 @@ func (d *choiceDefinition) parser(r *registry, parsers *idSet) (parser, error) { return cp, nil } -func (d *choiceDefinition) commitType() CommitType { - return d.commit +func (d *choiceDefinition) builder() builder { + return &choiceBuilder{} } func (p *choiceParser) nodeName() string { return p.name } @@ -155,3 +166,10 @@ func (p *choiceParser) parse(t Trace, c *context) { c.fail(from) c.include(from, p.id) } + +func (b *choiceBuilder) nodeName() string { return b.name } +func (b *choiceBuilder) nodeID() int { return b.id } + +func (b *choiceBuilder) build(*context) ([]*Node, bool) { + return nil, false +} diff --git a/context.go b/context.go index 150e7e7..10bdb3f 100644 --- a/context.go +++ b/context.go @@ -127,10 +127,10 @@ func (c *context) fail(offset int) { c.match = false } -func (c *context) finalize() error { - return ErrNotImplemented - - if c.node.To < c.readOffset { +func (c *context) finalize(root parser) error { + rootID := root.nodeID() + to, match, found := c.store.getMatch(0, rootID) + if !found || !match || to < c.readOffset { return ErrUnexpectedCharacter } @@ -145,6 +145,8 @@ func (c *context) finalize() error { } } + return ErrNotImplemented + c.node.commit(c.tokens) return nil } diff --git a/parse.go b/parse.go index d7d859d..e646a68 100644 --- a/parse.go +++ b/parse.go @@ -5,12 +5,12 @@ import "fmt" type definition interface { nodeName() string nodeID() int + commitType() CommitType setID(int) init(*registry) error setIncludedBy(*registry, int, *idSet) error parser(*registry, *idSet) (parser, error) - commitType() CommitType - // builder() builder + builder() builder } type parser interface { @@ -22,7 +22,7 @@ type parser interface { type builder interface { nodeName() string nodeID() int - build(*context) *Node + build(*context) ([]*Node, bool) } func parserNotFound(name string) error { @@ -83,7 +83,7 @@ func parse(t Trace, p parser, c *context) (*Node, error) { return nil, ErrInvalidInput } - if err := c.finalize(); err != nil { + if err := c.finalize(p); err != nil { return nil, err } diff --git a/sequence.go b/sequence.go index c30582a..4daf082 100644 --- a/sequence.go +++ b/sequence.go @@ -17,6 +17,12 @@ type sequenceParser struct { includedBy []int } +type sequenceBuilder struct { + name string + id int + commit CommitType +} + func newSequence(name string, ct CommitType, items []SequenceItem) *sequenceDefinition { return &sequenceDefinition{ name: name, @@ -28,6 +34,7 @@ func newSequence(name string, ct CommitType, items []SequenceItem) *sequenceDefi 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) commitType() CommitType { return d.commit } func (d *sequenceDefinition) includeItems() bool { return len(d.items) == 1 && d.items[0].Min == 1 && d.items[0].Max == 1 @@ -66,6 +73,7 @@ func (d *sequenceDefinition) setIncludedBy(r *registry, includedBy int, parsers } func (d *sequenceDefinition) parser(r *registry, parsers *idSet) (parser, error) { + // TODO: what is this for? test with sequence containing a sequence through a choice if parsers.has(d.id) { panic(cannotIncludeParsers(d.name)) } @@ -124,8 +132,8 @@ func (d *sequenceDefinition) parser(r *registry, parsers *idSet) (parser, error) return sp, nil } -func (d *sequenceDefinition) commitType() CommitType { - return d.commit +func (d *sequenceDefinition) builder() builder { + return &sequenceBuilder{} } func (p *sequenceParser) nodeName() string { return p.name } @@ -189,3 +197,10 @@ func (p *sequenceParser) parse(t Trace, c *context) { c.success(to) c.include(from, p.id) } + +func (b *sequenceBuilder) nodeName() string { return b.name } +func (b *sequenceBuilder) nodeID() int { return b.id } + +func (b *sequenceBuilder) build(*context) ([]*Node, bool) { + return nil, false +} diff --git a/store.go b/store.go index 515a324..dafeb67 100644 --- a/store.go +++ b/store.go @@ -58,6 +58,10 @@ 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 { + return + } + s.ensureOffset(offset) s.match[offset] = append(s.match[offset], id, to) } diff --git a/syntax.go b/syntax.go index 424b6b3..2e2d6d8 100644 --- a/syntax.go +++ b/syntax.go @@ -88,7 +88,7 @@ func childName(name string, childIndex int) string { func (s *Syntax) Class(name string, ct CommitType, not bool, chars []rune, ranges [][]rune) error { cname := childName(name, 0) - if err := s.register(newChar(cname, Alias, not, chars, ranges)); err != nil { + if err := s.register(newChar(cname, not, chars, ranges)); err != nil { return err } @@ -100,7 +100,7 @@ func (s *Syntax) CharSequence(name string, ct CommitType, chars []rune) error { for i, ci := range chars { ref := childName(name, i) refs = append(refs, ref) - if err := s.register(newChar(ref, Alias, false, []rune{ci}, nil)); err != nil { + if err := s.register(newChar(ref, false, []rune{ci}, nil)); err != nil { return err } }