From 005da7cd1fd26198d104f6cffa44ec2b4834f256 Mon Sep 17 00:00:00 2001 From: Arpad Ryszka Date: Sat, 6 Jun 2026 05:54:48 +0200 Subject: [PATCH] check if all parsers are referenced --- chardefine.go | 6 +++++- choicedefine.go | 1 + doc/example/mml-exp.treerack | 8 ++++++-- doc/example/mml-exp2.treerack | 1 - doc/example/mml-exp3.treerack | 2 -- doc/example/scheme.treerack | 2 +- registry.go | 25 +++++++++++++++++++++++++ sequencedefine.go | 1 + syntax.go | 14 ++++++++++++++ syntax_test.go | 6 ++++++ 10 files changed, 59 insertions(+), 7 deletions(-) diff --git a/chardefine.go b/chardefine.go index 6a7df8c..f1a3c58 100644 --- a/chardefine.go +++ b/chardefine.go @@ -29,11 +29,15 @@ func (p *charParser) setName(n string) { p.name = n } func (p *charParser) setID(id int) { p.id = id } func (p *charParser) setCommitType(ct CommitType) {} func (p *charParser) preinit() {} -func (p *charParser) validate(*registry) error { return nil } func (p *charParser) init(*registry) {} func (p *charParser) addGeneralization(int) {} func (p *charParser) parser() parser { return p } +func (p *charParser) validate(r *registry) error { + r.setRef(p) + return nil +} + func (p *charParser) builder() builder { return &charBuilder{ id: p.id, diff --git a/choicedefine.go b/choicedefine.go index ddea381..8837db5 100644 --- a/choicedefine.go +++ b/choicedefine.go @@ -40,6 +40,7 @@ func (d *choiceDefinition) validate(r *registry) error { } d.validated = true + r.setRef(d) for i := range d.options { o, ok := r.definition[d.options[i]] if !ok { diff --git a/doc/example/mml-exp.treerack b/doc/example/mml-exp.treerack index fc53335..61c914f 100644 --- a/doc/example/mml-exp.treerack +++ b/doc/example/mml-exp.treerack @@ -281,7 +281,10 @@ receive-assignment-equal = assignable nl* "=" nl* receive-expression; receive-capture:alias = symbol-expression nl* ("=" nl*)? receive-expression; receive-definition = "let" nl* receive-capture; receive-mutable-definition = "let" nl* "~" nl* receive-capture; -receive-statement:alias = receive-assignment | receive-definition; +receive-statement:alias = receive-assignment + | receive-assignment-equal + | receive-definition + | receive-mutable-definition; send-call:alias = "send" "(" (nl | ",")* expression list-sep expression (nl | ",")* ")"; send-op:alias = primary-expression "<-" expression; send-call-group:alias = "(" nl* send nl* ")"; @@ -496,7 +499,8 @@ statement:alias = send | expression | type-alias | type-constraint - | statement-group; + | statement-group + | type-expression; shebang-command = [^\n]*; shebang = "#!" shebang-command "\n"; sep:alias = (";" | "\n") (nl | ";")*; diff --git a/doc/example/mml-exp2.treerack b/doc/example/mml-exp2.treerack index 1aa8596..0699a94 100644 --- a/doc/example/mml-exp2.treerack +++ b/doc/example/mml-exp2.treerack @@ -110,7 +110,6 @@ operand1:alias = operand0 | binary0; operand2:alias = operand1 | binary1; operand3:alias = operand2 | binary2; operand4:alias = operand3 | binary3; -operand5:alias = operand4 | binary4; binary0 = operand0 (nl* binary-op0 nl* operand0)+; binary1 = operand1 (nl* binary-op1 nl* operand1)+; binary2 = operand2 (nl* binary-op2 nl* operand2)+; diff --git a/doc/example/mml-exp3.treerack b/doc/example/mml-exp3.treerack index 513e65d..3341127 100644 --- a/doc/example/mml-exp3.treerack +++ b/doc/example/mml-exp3.treerack @@ -1,7 +1,6 @@ ws:ws = " " | "\b" | "\f" | "\r" | "\t" | "\v"; wsc:ws = comment; nl:alias = "\n"; -wsep:alias = ws | nl; line-comment-content:nows = [^\n]*; line-comment:alias:nows = "//" line-comment-content; block-comment-content:nows = ([^*] | "*" [^/])*; @@ -112,7 +111,6 @@ operand1:alias = operand0 | binary0; operand2:alias = operand1 | binary1; operand3:alias = operand2 | binary2; operand4:alias = operand3 | binary3; -operand5:alias = operand4 | binary4; binary0 = operand0 (nl* binary-op0 nl* operand0)+; binary1 = operand1 (nl* binary-op1 nl* operand1)+; binary2 = operand2 (nl* binary-op2 nl* operand2)+; diff --git a/doc/example/scheme.treerack b/doc/example/scheme.treerack index e2ac7b6..05ee327 100644 --- a/doc/example/scheme.treerack +++ b/doc/example/scheme.treerack @@ -6,5 +6,5 @@ symbol:nows = ([^\\ \n\t\b\f\r\v\"()\[\]#] | "\\" .)+; list-form:alias = "(" expression* ")" | "[" expression* "]"; list = list-form; vector = "#" list-form; -expression:alias = number | string | symbol | list; +expression:alias = number | string | symbol | list | vector; scheme = expression*; diff --git a/registry.go b/registry.go index ac859df..795bc9a 100644 --- a/registry.go +++ b/registry.go @@ -4,11 +4,13 @@ type registry struct { idSeed int definition map[string]definition definitions []definition + referenced map[string]bool } func newRegistry(defs ...definition) *registry { r := ®istry{ definition: make(map[string]definition), + referenced: make(map[string]bool), } for _, def := range defs { @@ -31,3 +33,26 @@ func (r *registry) setDefinition(d definition) error { r.definitions = append(r.definitions, d) return nil } + +func (r *registry) setRef(d definition) { + if d.commitType()&userDefined == 0 { + return + } + + r.referenced[d.nodeName()] = true +} + +func (r *registry) unreferenced() []string { + var u []string + for _, def := range r.definitions { + if def.commitType()&userDefined == 0 { + continue + } + + if !r.referenced[def.nodeName()] { + u = append(u, def.nodeName()) + } + } + + return u +} diff --git a/sequencedefine.go b/sequencedefine.go index 99a126d..425ac41 100644 --- a/sequencedefine.go +++ b/sequencedefine.go @@ -79,6 +79,7 @@ func (d *sequenceDefinition) validate(r *registry) error { } d.validated = true + r.setRef(d) for i := range d.items { ii, ok := r.definition[d.items[i].Name] if !ok { diff --git a/syntax.go b/syntax.go index c2b045e..8a07578 100644 --- a/syntax.go +++ b/syntax.go @@ -430,6 +430,20 @@ func (s *Syntax) Init() error { return err } + u := s.registry.unreferenced() + if len(u) > 0 { + var err error + us := strings.Join(u, ", ") + if len(us) > 108 { + err = fmt.Errorf("unrefenced parsers (%d)", len(u)) + } else { + err = fmt.Errorf("unrefenced parsers (%d): %s", len(u), us) + } + + s.errInitFailed = err + return err + } + for i := range s.keywords { s.keywords[i].init(s.registry) } diff --git a/syntax_test.go b/syntax_test.go index 92b8f11..f873520 100644 --- a/syntax_test.go +++ b/syntax_test.go @@ -79,6 +79,12 @@ func TestValidation(t *testing.T) { t.Error("failed to fail") } }) + + t.Run("unreferenced parser", func(t *testing.T) { + if _, err := openSyntaxString(`foo = "foo"; bar:root = "bar"`); err == nil { + t.Error("failed to fail") + } + }) } func TestInit(t *testing.T) {