1
0

check if all parsers are referenced

This commit is contained in:
Arpad Ryszka 2026-06-06 05:54:48 +02:00
parent b20ed19b4e
commit 005da7cd1f
10 changed files with 59 additions and 7 deletions

View File

@ -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,

View File

@ -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 {

View File

@ -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 | ";")*;

View File

@ -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)+;

View File

@ -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)+;

View File

@ -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*;

View File

@ -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 := &registry{
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
}

View File

@ -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 {

View File

@ -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)
}

View File

@ -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) {