diff --git a/char.go b/char.go index 9a74523..2f2728a 100644 --- a/char.go +++ b/char.go @@ -23,10 +23,11 @@ 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) 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) normalize(*registry, *idSet) error { return nil } func (p *charParser) init(r *registry) error { return nil } diff --git a/choice.go b/choice.go index 4cc37f6..57a41f1 100644 --- a/choice.go +++ b/choice.go @@ -38,6 +38,24 @@ 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) normalize(r *registry, path *idSet) error { + if path.has(d.id) { + return nil + } + + path.set(d.id) + for i := range d.elements { + element, ok := r.definition(d.elements[i]) + if !ok { + return parserNotFound(d.elements[i]) + } + + element.normalize(r, path) + } + + return nil +} + func (d *choiceDefinition) init(r *registry) error { if d.cbuilder == nil { d.cbuilder = &choiceBuilder{ diff --git a/parse.go b/parse.go index 958b505..cec0809 100644 --- a/parse.go +++ b/parse.go @@ -7,6 +7,7 @@ type definition interface { nodeID() int commitType() CommitType setID(int) + normalize(*registry, *idSet) error init(*registry) error setIncludedBy(*registry, int, *idSet) error parser(*registry, *idSet) (parser, error) diff --git a/sequence.go b/sequence.go index 03e4fcd..d133ca0 100644 --- a/sequence.go +++ b/sequence.go @@ -44,6 +44,24 @@ 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) normalize(r *registry, path *idSet) error { + if path.has(d.id) { + return nil + } + + path.set(d.id) + for i := range d.items { + element, ok := r.definition(d.items[i].Name) + if !ok { + return parserNotFound(d.items[i].Name) + } + + element.normalize(r, path) + } + + return nil +} + func (d *sequenceDefinition) includeItems() bool { return len(d.items) == 1 && d.items[0].Min == 1 && d.items[0].Max == 1 } diff --git a/syntax.go b/syntax.go index d6275a6..d81deac 100644 --- a/syntax.go +++ b/syntax.go @@ -144,6 +144,10 @@ func (s *Syntax) Init() error { return ErrRootAlias } + if err := s.root.normalize(s.registry, &idSet{}); err != nil { + return err + } + for _, p := range s.registry.definitions { p.init(s.registry) }