Skip to content

Commit

Permalink
Tolerate missing ';' in oneof options/fields and extension fields (bu…
Browse files Browse the repository at this point in the history
…fbuild#216)

While still reporting an error, see:
bufbuild#200
A little different from the others, as oneof and extensions don't
support empty decls.
  • Loading branch information
Alfus authored and kralicky committed Feb 7, 2024
1 parent 885d1ff commit 1892c66
Show file tree
Hide file tree
Showing 4 changed files with 718 additions and 613 deletions.
10 changes: 6 additions & 4 deletions ast/field.go
Original file line number Diff line number Diff line change
Expand Up @@ -90,10 +90,10 @@ func NewFieldNode(label *KeywordNode, fieldType IdentValueNode, name *IdentNode,
if tag == nil {
panic("tag is nil")
}
if semicolon == nil {
panic("semicolon is nil")
numChildren := 4
if semicolon != nil {
numChildren++
}
numChildren := 5
if label != nil {
numChildren++
}
Expand All @@ -108,7 +108,9 @@ func NewFieldNode(label *KeywordNode, fieldType IdentValueNode, name *IdentNode,
if opts != nil {
children = append(children, opts)
}
children = append(children, semicolon)
if semicolon != nil {
children = append(children, semicolon)
}

return &FieldNode{
compositeNode: compositeNode{
Expand Down
72 changes: 72 additions & 0 deletions parser/parser_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -194,6 +194,78 @@ func TestLenientParse_SemicolonLess(t *testing.T) {
reserved "FOO";;
}`,
},
"oneof-options": {
Error: `syntax = "proto3";
message Foo {
oneof bar {
option (foo) = 1
}
}`,
NoError: `syntax = "proto3";
message Foo {
oneof bar {
option (foo) = 1;
};
}`,
},
"oneof-field": {
Error: `syntax = "proto3";
message Foo {
oneof bar {
int32 baz = 1
}
}`,
NoError: `syntax = "proto3";
message Foo {
oneof bar {
int32 baz = 1;
};
}`,
},
"oneof-field-options": {
Error: `syntax = "proto3";
message Foo {
oneof bar {
int32 baz = 1 [foo = 1]
}
}`,
NoError: `syntax = "proto3";
message Foo {
oneof bar {
int32 baz = 1 [foo = 1];
};
}`,
},
"extension-field": {
Error: `syntax = "proto3";
extend Foo {
int32 bar = 1
}`,
NoError: `syntax = "proto3";
extend Foo {
int32 bar = 1;
}`,
},
"extension-field-cardinality": {
Error: `syntax = "proto3";
extend Foo {
repeated int32 bar = 1
}`,
NoError: `syntax = "proto3";
extend Foo {
repeated int32 bar = 1;
}`,
},
"extension-field-options": {
Error: `syntax = "proto3";
extend Foo {
int32 bar = 1 [foo = 1]
}`,
NoError: `syntax = "proto3";
extend Foo {
int32 bar = 1 [foo = 1];
}`,
},
}
for name, input := range inputs {
name, input := name, input
Expand Down
30 changes: 22 additions & 8 deletions parser/proto.y
Original file line number Diff line number Diff line change
Expand Up @@ -84,7 +84,7 @@ import (
%type <fileElements> fileBody fileElement fileElements
%type <imprt> importDecl
%type <pkg> packageDecl
%type <opt> optionDecl compactOption
%type <opt> optionDecl compactOption oneofOptionDecl
%type <optN> optionDeclWithEmptyDecls
%type <opts> compactOptionDecls
%type <ref> extensionName messageLiteralFieldName
Expand Down Expand Up @@ -129,6 +129,7 @@ import (
%type <mtd> methodDecl
%type <mtdElements> methodElement methodElements methodBody
%type <mtdMsgType> methodMessageType
%type <b> semicolon
%type <bs> semicolons semicolonList

// same for terminals
Expand Down Expand Up @@ -228,6 +229,14 @@ semicolons : semicolonList {
$$ = nil
}

semicolon : ';' {
$$ = $1
} |
{
protolex.(*protoLex).Error("expected ';'")
$$ = nil
}

syntaxDecl : _SYNTAX '=' stringLit ';' {
$$ = ast.NewSyntaxNode($1.ToKeyword(), $2, toStringValueNode($3), $4)
}
Expand Down Expand Up @@ -317,6 +326,11 @@ optionDecl : _OPTION optionName '=' optionValue ';' {
$$ = ast.NewOptionNode($1.ToKeyword(), optName, $3, $4, $5)
}

oneofOptionDecl : _OPTION optionName '=' optionValue semicolon {
optName := ast.NewOptionNameNode($2.refs, $2.dots)
$$ = ast.NewOptionNode($1.ToKeyword(), optName, $3, $4, $5)
}

optionDeclWithEmptyDecls : _OPTION optionName '=' optionValue semicolons {
optName := ast.NewOptionNameNode($2.refs, $2.dots)
semi, extra := protolex.(*protoLex).requireSemicolon($5)
Expand Down Expand Up @@ -649,7 +663,7 @@ oneofElements : oneofElements oneofElement {
}
}

oneofElement : optionDecl {
oneofElement : oneofOptionDecl {
$$ = $1
}
| oneofFieldDecl {
Expand All @@ -665,10 +679,10 @@ oneofElement : optionDecl {
$$ = nil
}

oneofFieldDecl : oneofElementTypeIdent identifier '=' _INT_LIT ';' {
oneofFieldDecl : oneofElementTypeIdent identifier '=' _INT_LIT semicolon {
$$ = ast.NewFieldNode(nil, $1, $2, $3, $4, nil, $5)
}
| oneofElementTypeIdent identifier '=' _INT_LIT compactOptions ';' {
| oneofElementTypeIdent identifier '=' _INT_LIT compactOptions semicolon {
$$ = ast.NewFieldNode(nil, $1, $2, $3, $4, $5, $6)
}

Expand Down Expand Up @@ -964,16 +978,16 @@ extensionElement : extensionFieldDecl {
$$ = nil
}

extensionFieldDecl : fieldCardinality notGroupElementTypeIdent identifier '=' _INT_LIT ';' {
extensionFieldDecl : fieldCardinality notGroupElementTypeIdent identifier '=' _INT_LIT semicolon {
$$ = ast.NewFieldNode($1.ToKeyword(), $2, $3, $4, $5, nil, $6)
}
| fieldCardinality notGroupElementTypeIdent identifier '=' _INT_LIT compactOptions ';' {
| fieldCardinality notGroupElementTypeIdent identifier '=' _INT_LIT compactOptions semicolon {
$$ = ast.NewFieldNode($1.ToKeyword(), $2, $3, $4, $5, $6, $7)
}
| extElementTypeIdent identifier '=' _INT_LIT ';' {
| extElementTypeIdent identifier '=' _INT_LIT semicolon {
$$ = ast.NewFieldNode(nil, $1, $2, $3, $4, nil, $5)
}
| extElementTypeIdent identifier '=' _INT_LIT compactOptions ';' {
| extElementTypeIdent identifier '=' _INT_LIT compactOptions semicolon {
$$ = ast.NewFieldNode(nil, $1, $2, $3, $4, $5, $6)
}

Expand Down
Loading

0 comments on commit 1892c66

Please sign in to comment.