diff options
-rw-r--r-- | grammar/grammar.go | 46 | ||||
-rw-r--r-- | grammar/grammar_test.go | 71 |
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] = ¶m.Pos + case param.OrderedSymbol != "": + prodPrecsOrdSym[p.id] = param.OrderedSymbol + prodPrecPoss[p.id] = ¶m.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; |