Skip to content

Commit

Permalink
Prohibit ambiguous symbol in an #ast directive
Browse files Browse the repository at this point in the history
  • Loading branch information
nihei9 committed Apr 16, 2022
1 parent 533c454 commit 8bf4d23
Show file tree
Hide file tree
Showing 3 changed files with 49 additions and 1 deletion.
21 changes: 20 additions & 1 deletion grammar/grammar.go
Original file line number Diff line number Diff line change
Expand Up @@ -701,6 +701,7 @@ func (b *GrammarBuilder) genProductionsAndActions(root *spec.RootNode, symTabAnd
for _, alt := range prod.RHS {
altSyms := make([]symbol, len(alt.Elements))
offsets := map[string]int{}
ambiguousIDOffsets := map[string]struct{}{}
for i, elem := range alt.Elements {
var sym symbol
if elem.Pattern != "" {
Expand Down Expand Up @@ -756,7 +757,15 @@ func (b *GrammarBuilder) genProductionsAndActions(root *spec.RootNode, symTabAnd
// A symbol having a label can be specified by both the label and the symbol name.
// So record the symbol's position, whether or not it has a label.
if elem.ID != "" {
offsets[elem.ID] = i
if _, exist := offsets[elem.ID]; exist {
// When the same symbol appears multiple times in an alternative, the symbol is ambiguous. When we need
// to specify the symbol in a directive, we cannot use the name of the ambiguous symbol. Instead, specify
// a label to resolve the ambiguity.
delete(offsets, elem.ID)
ambiguousIDOffsets[elem.ID] = struct{}{}
} else {
offsets[elem.ID] = i
}
}
}

Expand Down Expand Up @@ -842,6 +851,16 @@ func (b *GrammarBuilder) genProductionsAndActions(root *spec.RootNode, symTabAnd
continue LOOP_RHS
}

if _, ambiguous := ambiguousIDOffsets[param.ID]; ambiguous {
b.errs = append(b.errs, &verr.SpecError{
Cause: semErrAmbiguousElem,
Detail: fmt.Sprintf("'%v' is ambiguous", param.ID),
Row: param.Pos.Row,
Col: param.Pos.Col,
})
continue LOOP_RHS
}

offset, ok := offsets[param.ID]
if !ok {
b.errs = append(b.errs, &verr.SpecError{
Expand Down
28 changes: 28 additions & 0 deletions grammar/grammar_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -1023,6 +1023,34 @@ foo
`,
errs: []*SemanticError{semErrDuplicateElem},
},
{
caption: "symbol `foo` is ambiguous because it appears in an alternative twice",
specSrc: `
%name test
s
: foo foo #ast foo
;
foo
: 'foo';
`,
errs: []*SemanticError{semErrAmbiguousElem},
},
{
caption: "symbol `foo` is ambiguous because it appears in an alternative twice, even if one of them has a label",
specSrc: `
%name test
s
: foo@x foo #ast foo
;
foo
: 'foo';
`,
errs: []*SemanticError{semErrAmbiguousElem},
},
{
caption: "the expansion operator cannot be applied to a terminal symbol",
specSrc: `
Expand Down
1 change: 1 addition & 0 deletions grammar/semantic_error.go
Original file line number Diff line number Diff line change
Expand Up @@ -35,6 +35,7 @@ var (
semErrDirInvalidParam = newSemanticError("invalid parameter")
semErrDuplicateDir = newSemanticError("a directive must not be duplicated")
semErrDuplicateElem = newSemanticError("duplicate element")
semErrAmbiguousElem = newSemanticError("ambiguous element")
semErrInvalidProdDir = newSemanticError("invalid production directive")
semErrInvalidAltDir = newSemanticError("invalid alternative directive")
)

0 comments on commit 8bf4d23

Please sign in to comment.