Skip to content

Commit ebf3519

Browse files
authored
Tolerate missing ';' in message body (#218)
While still producing an error, see: #200
1 parent 340bf80 commit ebf3519

File tree

7 files changed

+873
-823
lines changed

7 files changed

+873
-823
lines changed

ast/field.go

Lines changed: 7 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -543,19 +543,21 @@ func NewMapFieldNode(mapType *MapTypeNode, name *IdentNode, equals *RuneNode, ta
543543
if tag == nil {
544544
panic("tag is nil")
545545
}
546-
if semicolon == nil {
547-
panic("semicolon is nil")
548-
}
549-
numChildren := 5
546+
numChildren := 4
550547
if opts != nil {
551548
numChildren++
552549
}
550+
if semicolon != nil {
551+
numChildren++
552+
}
553553
children := make([]Node, 0, numChildren)
554554
children = append(children, mapType, name, equals, tag)
555555
if opts != nil {
556556
children = append(children, opts)
557557
}
558-
children = append(children, semicolon)
558+
if semicolon != nil {
559+
children = append(children, semicolon)
560+
}
559561

560562
return &MapFieldNode{
561563
compositeNode: compositeNode{

ast/ranges.go

Lines changed: 8 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -339,16 +339,17 @@ func NewReservedIdentifiersNode(keyword *KeywordNode, names []*IdentNode, commas
339339
if keyword == nil {
340340
panic("keyword is nil")
341341
}
342-
if semicolon == nil {
343-
panic("semicolon is nil")
344-
}
345342
if len(names) == 0 {
346343
panic("must have at least one name")
347344
}
348345
if len(commas) != len(names)-1 {
349346
panic(fmt.Sprintf("%d names requires %d commas, not %d", len(names), len(names)-1, len(commas)))
350347
}
351-
children := make([]Node, 0, len(names)*2+1)
348+
numChildren := len(names) * 2
349+
if semicolon != nil {
350+
numChildren++
351+
}
352+
children := make([]Node, 0, numChildren)
352353
children = append(children, keyword)
353354
for i, name := range names {
354355
if i > 0 {
@@ -362,7 +363,9 @@ func NewReservedIdentifiersNode(keyword *KeywordNode, names []*IdentNode, commas
362363
}
363364
children = append(children, name)
364365
}
365-
children = append(children, semicolon)
366+
if semicolon != nil {
367+
children = append(children, semicolon)
368+
}
366369
return &ReservedNode{
367370
compositeNode: compositeNode{
368371
children: children,

parser/ast.go

Lines changed: 18 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -135,6 +135,15 @@ func newEnumElements(semicolons []*ast.RuneNode, elements []ast.EnumElement) []a
135135
return elems
136136
}
137137

138+
func newMessageElements(semicolons []*ast.RuneNode, elements []ast.MessageElement) []ast.MessageElement {
139+
elems := make([]ast.MessageElement, 0, len(semicolons)+len(elements))
140+
for _, semicolon := range semicolons {
141+
elems = append(elems, ast.NewEmptyDeclNode(semicolon))
142+
}
143+
elems = append(elems, elements...)
144+
return elems
145+
}
146+
138147
type nodeWithEmptyDecls[T ast.Node] struct {
139148
Node T
140149
EmptyDecls []*ast.EmptyDeclNode
@@ -182,3 +191,12 @@ func toEnumElements[T ast.EnumElement](nodes nodeWithEmptyDecls[T]) []ast.EnumEl
182191
}
183192
return elements
184193
}
194+
195+
func toMessageElements[T ast.MessageElement](nodes nodeWithEmptyDecls[T]) []ast.MessageElement {
196+
elements := make([]ast.MessageElement, 1+len(nodes.EmptyDecls))
197+
elements[0] = nodes.Node
198+
for i, emptyDecl := range nodes.EmptyDecls {
199+
elements[i+1] = emptyDecl
200+
}
201+
return elements
202+
}

parser/parser_test.go

Lines changed: 86 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -266,6 +266,92 @@ func TestLenientParse_SemicolonLess(t *testing.T) {
266266
int32 bar = 1 [foo = 1];
267267
}`,
268268
},
269+
"message-field": {
270+
Error: `syntax = "proto3";
271+
message Foo {
272+
int32 bar = 1
273+
}`,
274+
NoError: `syntax = "proto3";
275+
message Foo {
276+
;
277+
int32 bar = 1;;
278+
}`,
279+
},
280+
"message-field-cardinality": {
281+
Error: `syntax = "proto3";
282+
message Foo {
283+
repeated int32 bar = 1
284+
}`,
285+
NoError: `syntax = "proto3";
286+
message Foo {
287+
repeated int32 bar = 1;
288+
}`,
289+
},
290+
"message-field-options": {
291+
Error: `syntax = "proto3";
292+
message Foo {
293+
int32 bar = 1 [foo = 1]
294+
}`,
295+
NoError: `syntax = "proto3";
296+
message Foo {
297+
int32 bar = 1 [foo = 1];
298+
}`,
299+
},
300+
"message-reserved": {
301+
Error: `syntax = "proto3";
302+
message Foo {
303+
reserved "FOO"
304+
}`,
305+
NoError: `syntax = "proto3";
306+
message Foo {
307+
;
308+
reserved "FOO";;
309+
}`,
310+
},
311+
"message-options": {
312+
Error: `syntax = "proto3";
313+
message Foo {
314+
option (foo) = 1
315+
}`,
316+
NoError: `syntax = "proto3";
317+
message Foo {
318+
;
319+
option (foo) = 1;;
320+
}`,
321+
},
322+
"message-map-field": {
323+
Error: `syntax = "proto3";
324+
message Foo {
325+
map<string, int32> bar = 1
326+
}`,
327+
NoError: `syntax = "proto3";
328+
message Foo {
329+
;
330+
map<string, int32> bar = 1;;
331+
}`,
332+
},
333+
"message-map-field-options": {
334+
Error: `syntax = "proto3";
335+
message Foo {
336+
map<string, int32> bar = 1 [foo = 1]
337+
}`,
338+
NoError: `syntax = "proto3";
339+
message Foo {
340+
;
341+
map<string, int32> bar = 1 [foo = 1];;
342+
}`,
343+
},
344+
"message-option": {
345+
Error: `syntax = "proto3";
346+
message Foo {
347+
option (foo) = 1
348+
}`,
349+
NoError: `syntax = "proto3";
350+
message Foo {
351+
;
352+
option (foo) = 1;;
353+
}`,
354+
},
269355
}
270356
for name, input := range inputs {
271357
name, input := name, input

0 commit comments

Comments
 (0)