aboutsummaryrefslogtreecommitdiff
path: root/grammar/grammar.go
diff options
context:
space:
mode:
authorRyo Nihei <nihei.dev@gmail.com>2022-03-30 00:44:17 +0900
committerRyo Nihei <nihei.dev@gmail.com>2022-03-30 00:50:06 +0900
commita1e4ae763cbf824f0d32a706cfe0d9603ce99b02 (patch)
treee32f48d6d5d3f56d495a8684653e913f14ca5ec8 /grammar/grammar.go
parentMove directives given to lexical productions (diff)
downloadurubu-a1e4ae763cbf824f0d32a706cfe0d9603ce99b02.tar.gz
urubu-a1e4ae763cbf824f0d32a706cfe0d9603ce99b02.tar.xz
Allow an alternative to have multiple directives
Diffstat (limited to 'grammar/grammar.go')
-rw-r--r--grammar/grammar.go30
1 files changed, 25 insertions, 5 deletions
diff --git a/grammar/grammar.go b/grammar/grammar.go
index c5726d7..2cdf2b3 100644
--- a/grammar/grammar.go
+++ b/grammar/grammar.go
@@ -571,12 +571,12 @@ func genLexEntry(prod *spec.ProductionNode) (*mlspec.LexEntry, bool, string, *ve
}
}
- if alt.Directive != nil {
+ if len(alt.Directives) > 0 {
return nil, false, "", &verr.SpecError{
Cause: semErrInvalidAltDir,
Detail: "a lexical production cannot have alternative directives",
- Row: alt.Directive.Pos.Row,
- Col: alt.Directive.Pos.Col,
+ Row: alt.Directives[0].Pos.Row,
+ Col: alt.Directives[0].Pos.Col,
}, nil
}
@@ -680,6 +680,16 @@ func (b *GrammarBuilder) genProductionsAndActions(root *spec.RootNode, symTabAnd
return nil, fmt.Errorf("symbol '%v' is undefined", prod.LHS)
}
+ if len(prod.Directives) > 0 {
+ b.errs = append(b.errs, &verr.SpecError{
+ Cause: semErrInvalidProdDir,
+ Detail: "a production cannot have production directives",
+ Row: prod.Directives[0].Pos.Row,
+ Col: prod.Directives[0].Pos.Col,
+ })
+ continue
+ }
+
LOOP_RHS:
for _, alt := range prod.RHS {
altSyms := make([]symbol, len(alt.Elements))
@@ -788,8 +798,18 @@ func (b *GrammarBuilder) genProductionsAndActions(root *spec.RootNode, symTabAnd
}
prods.append(p)
- if alt.Directive != nil {
- dir := alt.Directive
+ dirConsumed := map[string]struct{}{}
+ for _, dir := range alt.Directives {
+ if _, consumed := dirConsumed[dir.Name]; consumed {
+ b.errs = append(b.errs, &verr.SpecError{
+ Cause: semErrDuplicateDir,
+ Detail: dir.Name,
+ Row: dir.Pos.Row,
+ Col: dir.Pos.Col,
+ })
+ }
+ dirConsumed[dir.Name] = struct{}{}
+
switch dir.Name {
case "ast":
if len(dir.Parameters) == 0 {