aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--grammar/grammar.go46
-rw-r--r--grammar/grammar_test.go71
2 files changed, 103 insertions, 14 deletions
diff --git a/grammar/grammar.go b/grammar/grammar.go
index 82eff5d..410236b 100644
--- a/grammar/grammar.go
+++ b/grammar/grammar.go
@@ -155,7 +155,7 @@ func (b *GrammarBuilder) Build() (*Grammar, error) {
return nil, b.errs
}
- pa, err := b.genPrecAndAssoc(symTabAndLexSpec.symTab, prodsAndActs)
+ pa, err := b.genPrecAndAssoc(symTabAndLexSpec.symTab, symTabAndLexSpec.errSym, prodsAndActs)
if err != nil {
return nil, err
}
@@ -999,32 +999,41 @@ func (b *GrammarBuilder) genProductionsAndActions(root *spec.RootNode, symTabAnd
})
continue LOOP_RHS
}
+ param := dir.Parameters[0]
switch {
- case dir.Parameters[0].ID != "":
- sym, ok := symTab.toSymbol(dir.Parameters[0].ID)
+ case param.ID != "":
+ sym, ok := symTab.toSymbol(param.ID)
if !ok {
b.errs = append(b.errs, &verr.SpecError{
Cause: semErrDirInvalidParam,
- Detail: fmt.Sprintf("unknown terminal symbol: %v", dir.Parameters[0].ID),
- Row: dir.Pos.Row,
- Col: dir.Pos.Col,
+ Detail: fmt.Sprintf("unknown terminal symbol: %v", param.ID),
+ Row: param.Pos.Row,
+ Col: param.Pos.Col,
})
continue LOOP_RHS
}
+ if sym == errSym {
+ b.errs = append(b.errs, &verr.SpecError{
+ Cause: semErrDirInvalidParam,
+ Detail: fmt.Sprintf("'%v' directive cannot be applied to an error symbol", dir.Name),
+ Row: param.Pos.Row,
+ Col: param.Pos.Col,
+ })
+ }
if !sym.isTerminal() {
b.errs = append(b.errs, &verr.SpecError{
Cause: semErrDirInvalidParam,
- Detail: fmt.Sprintf("the symbol must be a terminal: %v", dir.Parameters[0].ID),
- Row: dir.Pos.Row,
- Col: dir.Pos.Col,
+ Detail: fmt.Sprintf("the symbol must be a terminal: %v", param.ID),
+ Row: param.Pos.Row,
+ Col: param.Pos.Col,
})
continue LOOP_RHS
}
prodPrecsTerm[p.id] = sym
- prodPrecPoss[p.id] = &dir.Parameters[0].Pos
- case dir.Parameters[0].OrderedSymbol != "":
- prodPrecsOrdSym[p.id] = dir.Parameters[0].OrderedSymbol
- prodPrecPoss[p.id] = &dir.Parameters[0].Pos
+ prodPrecPoss[p.id] = &param.Pos
+ case param.OrderedSymbol != "":
+ prodPrecsOrdSym[p.id] = param.OrderedSymbol
+ prodPrecPoss[p.id] = &param.Pos
}
case "recover":
if len(dir.Parameters) > 0 {
@@ -1061,7 +1070,7 @@ func (b *GrammarBuilder) genProductionsAndActions(root *spec.RootNode, symTabAnd
}, nil
}
-func (b *GrammarBuilder) genPrecAndAssoc(symTab *symbolTable, prodsAndActs *productionsAndActions) (*precAndAssoc, error) {
+func (b *GrammarBuilder) genPrecAndAssoc(symTab *symbolTable, errSym symbol, prodsAndActs *productionsAndActions) (*precAndAssoc, error) {
termPrec := map[symbolNum]int{}
termAssoc := map[symbolNum]assocType{}
ordSymPrec := map[string]int{}
@@ -1136,6 +1145,15 @@ func (b *GrammarBuilder) genPrecAndAssoc(symTab *symbolTable, prodsAndActs *prod
})
return nil, nil
}
+ if sym == errSym {
+ b.errs = append(b.errs, &verr.SpecError{
+ Cause: semErrDirInvalidParam,
+ Detail: fmt.Sprintf("'%v' directive cannot be applied to an error symbol", dir.Name),
+ Row: p.Pos.Row,
+ Col: p.Pos.Col,
+ })
+ return nil, nil
+ }
if !sym.isTerminal() {
b.errs = append(b.errs, &verr.SpecError{
Cause: semErrDirInvalidParam,
diff --git a/grammar/grammar_test.go b/grammar/grammar_test.go
index 5a8bb4a..aeeffac 100644
--- a/grammar/grammar_test.go
+++ b/grammar/grammar_test.go
@@ -1714,6 +1714,25 @@ foo
errs: []*SemanticError{semErrDirInvalidParam},
},
{
+ caption: "the `#left` directive cannot be applied to an error symbol",
+ specSrc: `
+#name test;
+
+#prec (
+ #left error
+);
+
+s
+ : foo ';'
+ | error ';'
+ ;
+
+foo
+ : 'foo';
+`,
+ errs: []*SemanticError{semErrDirInvalidParam},
+ },
+ {
caption: "the `#left` directive cannot take an undefined symbol",
specSrc: `
#name test;
@@ -1937,6 +1956,25 @@ foo
errs: []*SemanticError{semErrDirInvalidParam},
},
{
+ caption: "the `#right` directive cannot be applied to an error symbol",
+ specSrc: `
+#name test;
+
+#prec (
+ #right error
+);
+
+s
+ : foo ';'
+ | error ';'
+ ;
+
+foo
+ : 'foo';
+`,
+ errs: []*SemanticError{semErrDirInvalidParam},
+ },
+ {
caption: "the `#right` directive cannot take an undefined symbol",
specSrc: `
#name test;
@@ -2160,6 +2198,25 @@ foo
errs: []*SemanticError{semErrDirInvalidParam},
},
{
+ caption: "the `#assign` directive cannot be applied to an error symbol",
+ specSrc: `
+#name test;
+
+#prec (
+ #assign error
+);
+
+s
+ : foo ';'
+ | error ';'
+ ;
+
+foo
+ : 'foo';
+`,
+ errs: []*SemanticError{semErrDirInvalidParam},
+ },
+ {
caption: "the `#assign` directive cannot take an undefined symbol",
specSrc: `
#name test;
@@ -2669,6 +2726,20 @@ foo
errs: []*SemanticError{semErrDirInvalidParam},
},
{
+ caption: "the `#prec` directive cannot be applied to an error symbol",
+ specSrc: `
+#name test;
+
+s
+ : foo #prec error
+ ;
+
+foo
+ : 'foo';
+`,
+ errs: []*SemanticError{semErrDirInvalidParam},
+ },
+ {
caption: "the `#prec` directive cannot take an undefined symbol",
specSrc: `
#name test;