blob: faf49d9501db6d3ee0dbe3e11f1b85b0c8316931 [file] [log] [blame]
Zack Williamse940c7a2019-08-21 14:25:39 -07001%{
2package protoparse
3
4//lint:file-ignore SA4006 generated parser has unused values
5
6import (
7 "fmt"
8 "math"
9 "unicode"
10
11 "github.com/jhump/protoreflect/desc/internal"
12)
13
14%}
15
16// fields inside this union end up as the fields in a structure known
17// as ${PREFIX}SymType, of which a reference is passed to the lexer.
18%union{
19 file *fileNode
20 fileDecls []*fileElement
21 syn *syntaxNode
22 pkg *packageNode
23 imprt *importNode
24 msg *messageNode
25 msgDecls []*messageElement
26 fld *fieldNode
27 mapFld *mapFieldNode
28 grp *groupNode
29 oo *oneOfNode
30 ooDecls []*oneOfElement
31 ext *extensionRangeNode
32 resvd *reservedNode
33 en *enumNode
34 enDecls []*enumElement
35 env *enumValueNode
36 extend *extendNode
37 extDecls []*extendElement
38 svc *serviceNode
39 svcDecls []*serviceElement
40 mtd *methodNode
41 rpcType *rpcTypeNode
42 opts []*optionNode
43 optNm []*optionNamePartNode
44 rngs []*rangeNode
45 names []*stringLiteralNode
46 sl []valueNode
47 agg []*aggregateEntryNode
48 aggName *aggregateNameNode
49 v valueNode
50 str *stringLiteralNode
51 i *negativeIntLiteralNode
52 ui *intLiteralNode
53 f *floatLiteralNode
54 id *identNode
55 b *basicNode
56 err error
57}
58
59// any non-terminal which returns a value needs a type, which is
60// really a field name in the above union struct
61%type <file> file
62%type <syn> syntax
63%type <fileDecls> fileDecl fileDecls
64%type <imprt> import
65%type <pkg> package
66%type <opts> option fieldOption fieldOptions rpcOption rpcOptions
67%type <optNm> optionName optionNameRest optionNameComponent
68%type <v> constant scalarConstant aggregate
69%type <id> name ident typeIdent keyType
70%type <aggName> aggName
71%type <i> negIntLit
72%type <ui> intLit
73%type <f> floatLit
74%type <sl> constantList
75%type <agg> aggFields aggField aggFieldEntry
76%type <fld> field oneofField
77%type <oo> oneof
78%type <grp> group
79%type <mapFld> mapField
80%type <msg> message
81%type <msgDecls> messageItem messageBody
82%type <ooDecls> oneofItem oneofBody
83%type <names> fieldNames
84%type <resvd> msgReserved enumReserved reservedNames
85%type <rngs> tagRange tagRanges enumRange enumRanges
86%type <ext> extensions
87%type <en> enum
88%type <enDecls> enumItem enumBody
89%type <env> enumField
90%type <extend> extend
91%type <extDecls> extendItem extendBody
92%type <str> stringLit
93%type <svc> service
94%type <svcDecls> serviceItem serviceBody
95%type <mtd> rpc
96%type <rpcType> rpcType
97
98// same for terminals
99%token <str> _STRING_LIT
100%token <ui> _INT_LIT
101%token <f> _FLOAT_LIT
102%token <id> _NAME _FQNAME _TYPENAME
103%token <id> _SYNTAX _IMPORT _WEAK _PUBLIC _PACKAGE _OPTION _TRUE _FALSE _INF _NAN _REPEATED _OPTIONAL _REQUIRED
104%token <id> _DOUBLE _FLOAT _INT32 _INT64 _UINT32 _UINT64 _SINT32 _SINT64 _FIXED32 _FIXED64 _SFIXED32 _SFIXED64
105%token <id> _BOOL _STRING _BYTES _GROUP _ONEOF _MAP _EXTENSIONS _TO _MAX _RESERVED _ENUM _MESSAGE _EXTEND
106%token <id> _SERVICE _RPC _STREAM _RETURNS
107%token <err> _ERROR
108// we define all of these, even ones that aren't used, to improve error messages
109// so it shows the unexpected symbol instead of showing "$unk"
110%token <b> '=' ';' ':' '{' '}' '\\' '/' '?' '.' ',' '>' '<' '+' '-' '(' ')' '[' ']' '*' '&' '^' '%' '$' '#' '@' '!' '~' '`'
111
112%%
113
114file : syntax {
115 $$ = &fileNode{syntax: $1}
116 $$.setRange($1, $1)
117 protolex.(*protoLex).res = $$
118 }
119 | fileDecls {
120 $$ = &fileNode{decls: $1}
121 if len($1) > 0 {
122 $$.setRange($1[0], $1[len($1)-1])
123 }
124 protolex.(*protoLex).res = $$
125 }
126 | syntax fileDecls {
127 $$ = &fileNode{syntax: $1, decls: $2}
128 var end node
129 if len($2) > 0 {
130 end = $2[len($2)-1]
131 } else {
132 end = $1
133 }
134 $$.setRange($1, end)
135 protolex.(*protoLex).res = $$
136 }
137 | {
138 }
139
140fileDecls : fileDecls fileDecl {
141 $$ = append($1, $2...)
142 }
143 | fileDecl
144
145fileDecl : import {
146 $$ = []*fileElement{{imp: $1}}
147 }
148 | package {
149 $$ = []*fileElement{{pkg: $1}}
150 }
151 | option {
152 $$ = []*fileElement{{option: $1[0]}}
153 }
154 | message {
155 $$ = []*fileElement{{message: $1}}
156 }
157 | enum {
158 $$ = []*fileElement{{enum: $1}}
159 }
160 | extend {
161 $$ = []*fileElement{{extend: $1}}
162 }
163 | service {
164 $$ = []*fileElement{{service: $1}}
165 }
166 | ';' {
167 $$ = []*fileElement{{empty: $1}}
168 }
169
170syntax : _SYNTAX '=' stringLit ';' {
171 if $3.val != "proto2" && $3.val != "proto3" {
172 lexError(protolex, $3.start(), "syntax value must be 'proto2' or 'proto3'")
173 }
174 $$ = &syntaxNode{syntax: $3}
175 $$.setRange($1, $4)
176 }
177
178import : _IMPORT stringLit ';' {
179 $$ = &importNode{ name: $2 }
180 $$.setRange($1, $3)
181 }
182 | _IMPORT _WEAK stringLit ';' {
183 $$ = &importNode{ name: $3, weak: true }
184 $$.setRange($1, $4)
185 }
186 | _IMPORT _PUBLIC stringLit ';' {
187 $$ = &importNode{ name: $3, public: true }
188 $$.setRange($1, $4)
189 }
190
191package : _PACKAGE ident ';' {
192 $$ = &packageNode{name: $2}
193 $$.setRange($1, $3)
194 }
195
196ident : name
197 | _FQNAME
198
199option : _OPTION optionName '=' constant ';' {
200 n := &optionNameNode{parts: $2}
201 n.setRange($2[0], $2[len($2)-1])
202 o := &optionNode{name: n, val: $4}
203 o.setRange($1, $5)
204 $$ = []*optionNode{o}
205 }
206
207optionName : ident {
208 $$ = toNameParts($1, 0)
209 }
210 | '(' typeIdent ')' {
211 p := &optionNamePartNode{text: $2, isExtension: true}
212 p.setRange($1, $3)
213 $$ = []*optionNamePartNode{p}
214 }
215 | '(' typeIdent ')' optionNameRest {
216 p := &optionNamePartNode{text: $2, isExtension: true}
217 p.setRange($1, $3)
218 ps := make([]*optionNamePartNode, 1, len($4)+1)
219 ps[0] = p
220 $$ = append(ps, $4...)
221 }
222
223optionNameRest : optionNameComponent
224 | optionNameComponent optionNameRest {
225 $$ = append($1, $2...)
226 }
227
228optionNameComponent : _TYPENAME {
229 $$ = toNameParts($1, 1 /* exclude leading dot */)
230 }
231 | '.' '(' typeIdent ')' {
232 p := &optionNamePartNode{text: $3, isExtension: true}
233 p.setRange($2, $4)
234 $$ = []*optionNamePartNode{p}
235 }
236
237constant : scalarConstant
238 | aggregate
239
240scalarConstant : stringLit {
241 $$ = $1
242 }
243 | intLit {
244 $$ = $1
245 }
246 | negIntLit {
247 $$ = $1
248 }
249 | floatLit {
250 $$ = $1
251 }
252 | name {
253 if $1.val == "true" {
254 $$ = &boolLiteralNode{basicNode: $1.basicNode, val: true}
255 } else if $1.val == "false" {
256 $$ = &boolLiteralNode{basicNode: $1.basicNode, val: false}
257 } else if $1.val == "inf" {
258 f := &floatLiteralNode{val: math.Inf(1)}
259 f.setRange($1, $1)
260 $$ = f
261 } else if $1.val == "nan" {
262 f := &floatLiteralNode{val: math.NaN()}
263 f.setRange($1, $1)
264 $$ = f
265 } else {
266 $$ = $1
267 }
268 }
269
270intLit : _INT_LIT
271 | '+' _INT_LIT {
272 $$ = $2
273 }
274
275negIntLit : '-' _INT_LIT {
276 if $2.val > math.MaxInt64 + 1 {
277 lexError(protolex, $2.start(), fmt.Sprintf("numeric constant %d would underflow (allowed range is %d to %d)", $2.val, int64(math.MinInt64), int64(math.MaxInt64)))
278 }
279 $$ = &negativeIntLiteralNode{val: -int64($2.val)}
280 $$.setRange($1, $2)
281 }
282
283floatLit : _FLOAT_LIT
284 | '-' _FLOAT_LIT {
285 $$ = &floatLiteralNode{val: -$2.val}
286 $$.setRange($1, $2)
287 }
288 | '+' _FLOAT_LIT {
289 $$ = &floatLiteralNode{val: $2.val}
290 $$.setRange($1, $2)
291 }
292 | '+' _INF {
293 $$ = &floatLiteralNode{val: math.Inf(1)}
294 $$.setRange($1, $2)
295 }
296 | '-' _INF {
297 $$ = &floatLiteralNode{val: math.Inf(-1)}
298 $$.setRange($1, $2)
299 }
300
301stringLit : _STRING_LIT
302 | stringLit _STRING_LIT {
303 $$ = &stringLiteralNode{val: $1.val + $2.val}
304 $$.setRange($1, $2)
305 }
306
307aggregate : '{' aggFields '}' {
308 a := &aggregateLiteralNode{elements: $2}
309 a.setRange($1, $3)
310 $$ = a
311 }
312
313aggFields : aggField
314 | aggFields aggField {
315 $$ = append($1, $2...)
316 }
317 | {
318 $$ = nil
319 }
320
321aggField : aggFieldEntry
322 | aggFieldEntry ',' {
323 $$ = $1
324 }
325 | aggFieldEntry ';' {
326 $$ = $1
327 }
328
329aggFieldEntry : aggName ':' scalarConstant {
330 a := &aggregateEntryNode{name: $1, val: $3}
331 a.setRange($1, $3)
332 $$ = []*aggregateEntryNode{a}
333 }
334 | aggName ':' '[' ']' {
335 s := &sliceLiteralNode{}
336 s.setRange($3, $4)
337 a := &aggregateEntryNode{name: $1, val: s}
338 a.setRange($1, $4)
339 $$ = []*aggregateEntryNode{a}
340 }
341 | aggName ':' '[' constantList ']' {
342 s := &sliceLiteralNode{elements: $4}
343 s.setRange($3, $5)
344 a := &aggregateEntryNode{name: $1, val: s}
345 a.setRange($1, $5)
346 $$ = []*aggregateEntryNode{a}
347 }
348 | aggName ':' aggregate {
349 a := &aggregateEntryNode{name: $1, val: $3}
350 a.setRange($1, $3)
351 $$ = []*aggregateEntryNode{a}
352 }
353 | aggName aggregate {
354 a := &aggregateEntryNode{name: $1, val: $2}
355 a.setRange($1, $2)
356 $$ = []*aggregateEntryNode{a}
357 }
358 | aggName ':' '<' aggFields '>' {
359 s := &aggregateLiteralNode{elements: $4}
360 s.setRange($3, $5)
361 a := &aggregateEntryNode{name: $1, val: s}
362 a.setRange($1, $5)
363 $$ = []*aggregateEntryNode{a}
364 }
365 | aggName '<' aggFields '>' {
366 s := &aggregateLiteralNode{elements: $3}
367 s.setRange($2, $4)
368 a := &aggregateEntryNode{name: $1, val: s}
369 a.setRange($1, $4)
370 $$ = []*aggregateEntryNode{a}
371 }
372
373aggName : name {
374 $$ = &aggregateNameNode{name: $1}
375 $$.setRange($1, $1)
376 }
377 | '[' ident ']' {
378 $$ = &aggregateNameNode{name: $2, isExtension: true}
379 $$.setRange($1, $3)
380 }
381
382constantList : constant {
383 $$ = []valueNode{$1}
384 }
385 | constantList ',' constant {
386 $$ = append($1, $3)
387 }
388 | constantList ';' constant {
389 $$ = append($1, $3)
390 }
391 | '<' aggFields '>' {
392 s := &aggregateLiteralNode{elements: $2}
393 s.setRange($1, $3)
394 $$ = []valueNode{s}
395 }
396 | constantList ',' '<' aggFields '>' {
397 s := &aggregateLiteralNode{elements: $4}
398 s.setRange($3, $5)
399 $$ = append($1, s)
400 }
401 | constantList ';' '<' aggFields '>' {
402 s := &aggregateLiteralNode{elements: $4}
403 s.setRange($3, $5)
404 $$ = append($1, s)
405 }
406
407typeIdent : ident
408 | _TYPENAME
409
410field : _REQUIRED typeIdent name '=' _INT_LIT ';' {
411 checkTag(protolex, $5.start(), $5.val)
412 lbl := &labelNode{basicNode: $1.basicNode, required: true}
413 $$ = &fieldNode{label: lbl, fldType: $2, name: $3, tag: $5}
414 $$.setRange($1, $6)
415 }
416 | _OPTIONAL typeIdent name '=' _INT_LIT ';' {
417 checkTag(protolex, $5.start(), $5.val)
418 lbl := &labelNode{basicNode: $1.basicNode}
419 $$ = &fieldNode{label: lbl, fldType: $2, name: $3, tag: $5}
420 $$.setRange($1, $6)
421 }
422 | _REPEATED typeIdent name '=' _INT_LIT ';' {
423 checkTag(protolex, $5.start(), $5.val)
424 lbl := &labelNode{basicNode: $1.basicNode, repeated: true}
425 $$ = &fieldNode{label: lbl, fldType: $2, name: $3, tag: $5}
426 $$.setRange($1, $6)
427 }
428 | typeIdent name '=' _INT_LIT ';' {
429 checkTag(protolex, $4.start(), $4.val)
430 $$ = &fieldNode{fldType: $1, name: $2, tag: $4}
431 $$.setRange($1, $5)
432 }
433 | _REQUIRED typeIdent name '=' _INT_LIT '[' fieldOptions ']' ';' {
434 checkTag(protolex, $5.start(), $5.val)
435 lbl := &labelNode{basicNode: $1.basicNode, required: true}
436 $$ = &fieldNode{label: lbl, fldType: $2, name: $3, tag: $5, options: $7}
437 $$.setRange($1, $9)
438 }
439 | _OPTIONAL typeIdent name '=' _INT_LIT '[' fieldOptions ']' ';' {
440 checkTag(protolex, $5.start(), $5.val)
441 lbl := &labelNode{basicNode: $1.basicNode}
442 $$ = &fieldNode{label: lbl, fldType: $2, name: $3, tag: $5, options: $7}
443 $$.setRange($1, $9)
444 }
445 | _REPEATED typeIdent name '=' _INT_LIT '[' fieldOptions ']' ';' {
446 checkTag(protolex, $5.start(), $5.val)
447 lbl := &labelNode{basicNode: $1.basicNode, repeated: true}
448 $$ = &fieldNode{label: lbl, fldType: $2, name: $3, tag: $5, options: $7}
449 $$.setRange($1, $9)
450 }
451 | typeIdent name '=' _INT_LIT '[' fieldOptions ']' ';' {
452 checkTag(protolex, $4.start(), $4.val)
453 $$ = &fieldNode{fldType: $1, name: $2, tag: $4, options: $6}
454 $$.setRange($1, $8)
455 }
456
457fieldOptions : fieldOptions ',' fieldOption {
458 $$ = append($1, $3...)
459 }
460 | fieldOption
461
462fieldOption: optionName '=' constant {
463 n := &optionNameNode{parts: $1}
464 n.setRange($1[0], $1[len($1)-1])
465 o := &optionNode{name: n, val: $3}
466 o.setRange($1[0], $3)
467 $$ = []*optionNode{o}
468 }
469
470group : _REQUIRED _GROUP name '=' _INT_LIT '{' messageBody '}' {
471 checkTag(protolex, $5.start(), $5.val)
472 if !unicode.IsUpper(rune($3.val[0])) {
473 lexError(protolex, $3.start(), fmt.Sprintf("group %s should have a name that starts with a capital letter", $3.val))
474 }
475 lbl := &labelNode{basicNode: $1.basicNode, required: true}
476 $$ = &groupNode{groupKeyword: $2, label: lbl, name: $3, tag: $5, decls: $7}
477 $$.setRange($1, $8)
478 }
479 | _OPTIONAL _GROUP name '=' _INT_LIT '{' messageBody '}' {
480 checkTag(protolex, $5.start(), $5.val)
481 if !unicode.IsUpper(rune($3.val[0])) {
482 lexError(protolex, $3.start(), fmt.Sprintf("group %s should have a name that starts with a capital letter", $3.val))
483 }
484 lbl := &labelNode{basicNode: $1.basicNode}
485 $$ = &groupNode{groupKeyword: $2, label: lbl, name: $3, tag: $5, decls: $7}
486 $$.setRange($1, $8)
487 }
488 | _REPEATED _GROUP name '=' _INT_LIT '{' messageBody '}' {
489 checkTag(protolex, $5.start(), $5.val)
490 if !unicode.IsUpper(rune($3.val[0])) {
491 lexError(protolex, $3.start(), fmt.Sprintf("group %s should have a name that starts with a capital letter", $3.val))
492 }
493 lbl := &labelNode{basicNode: $1.basicNode, repeated: true}
494 $$ = &groupNode{groupKeyword: $2, label: lbl, name: $3, tag: $5, decls: $7}
495 $$.setRange($1, $8)
496 }
497
498oneof : _ONEOF name '{' oneofBody '}' {
499 c := 0
500 for _, el := range $4 {
501 if el.field != nil {
502 c++
503 }
504 }
505 if c == 0 {
506 lexError(protolex, $1.start(), "oneof must contain at least one field")
507 }
508 $$ = &oneOfNode{name: $2, decls: $4}
509 $$.setRange($1, $5)
510 }
511
512oneofBody : oneofBody oneofItem {
513 $$ = append($1, $2...)
514 }
515 | oneofItem
516 | {
517 $$ = nil
518 }
519
520oneofItem : option {
521 $$ = []*oneOfElement{{option: $1[0]}}
522 }
523 | oneofField {
524 $$ = []*oneOfElement{{field: $1}}
525 }
526 | ';' {
527 $$ = []*oneOfElement{{empty: $1}}
528 }
529
530oneofField : typeIdent name '=' _INT_LIT ';' {
531 checkTag(protolex, $4.start(), $4.val)
532 $$ = &fieldNode{fldType: $1, name: $2, tag: $4}
533 $$.setRange($1, $5)
534 }
535 | typeIdent name '=' _INT_LIT '[' fieldOptions ']' ';' {
536 checkTag(protolex, $4.start(), $4.val)
537 $$ = &fieldNode{fldType: $1, name: $2, tag: $4, options: $6}
538 $$.setRange($1, $8)
539 }
540
541mapField : _MAP '<' keyType ',' typeIdent '>' name '=' _INT_LIT ';' {
542 checkTag(protolex, $9.start(), $9.val)
543 $$ = &mapFieldNode{mapKeyword: $1, keyType: $3, valueType: $5, name: $7, tag: $9}
544 $$.setRange($1, $10)
545 }
546 | _MAP '<' keyType ',' typeIdent '>' name '=' _INT_LIT '[' fieldOptions ']' ';' {
547 checkTag(protolex, $9.start(), $9.val)
548 $$ = &mapFieldNode{mapKeyword: $1, keyType: $3, valueType: $5, name: $7, tag: $9, options: $11}
549 $$.setRange($1, $13)
550 }
551
552keyType : _INT32
553 | _INT64
554 | _UINT32
555 | _UINT64
556 | _SINT32
557 | _SINT64
558 | _FIXED32
559 | _FIXED64
560 | _SFIXED32
561 | _SFIXED64
562 | _BOOL
563 | _STRING
564
565extensions : _EXTENSIONS tagRanges ';' {
566 $$ = &extensionRangeNode{ranges: $2}
567 $$.setRange($1, $3)
568 }
569 | _EXTENSIONS tagRanges '[' fieldOptions ']' ';' {
570 $$ = &extensionRangeNode{ranges: $2, options: $4}
571 $$.setRange($1, $6)
572 }
573
574tagRanges : tagRanges ',' tagRange {
575 $$ = append($1, $3...)
576 }
577 | tagRange
578
579tagRange : _INT_LIT {
580 if $1.val > internal.MaxTag {
581 lexError(protolex, $1.start(), fmt.Sprintf("range includes out-of-range tag: %d (should be between 0 and %d)", $1.val, internal.MaxTag))
582 }
583 r := &rangeNode{stNode: $1, enNode: $1, st: int32($1.val), en: int32($1.val)}
584 r.setRange($1, $1)
585 $$ = []*rangeNode{r}
586 }
587 | _INT_LIT _TO _INT_LIT {
588 if $1.val > internal.MaxTag {
589 lexError(protolex, $1.start(), fmt.Sprintf("range start is out-of-range tag: %d (should be between 0 and %d)", $1.val, internal.MaxTag))
590 }
591 if $3.val > internal.MaxTag {
592 lexError(protolex, $3.start(), fmt.Sprintf("range end is out-of-range tag: %d (should be between 0 and %d)", $3.val, internal.MaxTag))
593 }
594 if $1.val > $3.val {
595 lexError(protolex, $1.start(), fmt.Sprintf("range, %d to %d, is invalid: start must be <= end", $1.val, $3.val))
596 }
597 r := &rangeNode{stNode: $1, enNode: $3, st: int32($1.val), en: int32($3.val)}
598 r.setRange($1, $3)
599 $$ = []*rangeNode{r}
600 }
601 | _INT_LIT _TO _MAX {
602 if $1.val > internal.MaxTag {
603 lexError(protolex, $1.start(), fmt.Sprintf("range start is out-of-range tag: %d (should be between 0 and %d)", $1.val, internal.MaxTag))
604 }
605 r := &rangeNode{stNode: $1, enNode: $3, st: int32($1.val), en: internal.MaxTag}
606 r.setRange($1, $3)
607 $$ = []*rangeNode{r}
608 }
609
610enumRanges : enumRanges ',' enumRange {
611 $$ = append($1, $3...)
612 }
613 | enumRange
614
615enumRange : _INT_LIT {
616 checkUint64InInt32Range(protolex, $1.start(), $1.val)
617 r := &rangeNode{stNode: $1, enNode: $1, st: int32($1.val), en: int32($1.val)}
618 r.setRange($1, $1)
619 $$ = []*rangeNode{r}
620 }
621 | negIntLit {
622 checkInt64InInt32Range(protolex, $1.start(), $1.val)
623 r := &rangeNode{stNode: $1, enNode: $1, st: int32($1.val), en: int32($1.val)}
624 r.setRange($1, $1)
625 $$ = []*rangeNode{r}
626 }
627 | _INT_LIT _TO _INT_LIT {
628 checkUint64InInt32Range(protolex, $1.start(), $1.val)
629 checkUint64InInt32Range(protolex, $3.start(), $3.val)
630 if $1.val > $3.val {
631 lexError(protolex, $1.start(), fmt.Sprintf("range, %d to %d, is invalid: start must be <= end", $1.val, $3.val))
632 }
633 r := &rangeNode{stNode: $1, enNode: $3, st: int32($1.val), en: int32($3.val)}
634 r.setRange($1, $3)
635 $$ = []*rangeNode{r}
636 }
637 | negIntLit _TO negIntLit {
638 checkInt64InInt32Range(protolex, $1.start(), $1.val)
639 checkInt64InInt32Range(protolex, $3.start(), $3.val)
640 if $1.val > $3.val {
641 lexError(protolex, $1.start(), fmt.Sprintf("range, %d to %d, is invalid: start must be <= end", $1.val, $3.val))
642 }
643 r := &rangeNode{stNode: $1, enNode: $3, st: int32($1.val), en: int32($3.val)}
644 r.setRange($1, $3)
645 $$ = []*rangeNode{r}
646 }
647 | negIntLit _TO _INT_LIT {
648 checkInt64InInt32Range(protolex, $1.start(), $1.val)
649 checkUint64InInt32Range(protolex, $3.start(), $3.val)
650 r := &rangeNode{stNode: $1, enNode: $3, st: int32($1.val), en: int32($3.val)}
651 r.setRange($1, $3)
652 $$ = []*rangeNode{r}
653 }
654 | _INT_LIT _TO _MAX {
655 checkUint64InInt32Range(protolex, $1.start(), $1.val)
656 r := &rangeNode{stNode: $1, enNode: $3, st: int32($1.val), en: math.MaxInt32}
657 r.setRange($1, $3)
658 $$ = []*rangeNode{r}
659 }
660 | negIntLit _TO _MAX {
661 checkInt64InInt32Range(protolex, $1.start(), $1.val)
662 r := &rangeNode{stNode: $1, enNode: $3, st: int32($1.val), en: math.MaxInt32}
663 r.setRange($1, $3)
664 $$ = []*rangeNode{r}
665 }
666
667msgReserved : _RESERVED tagRanges ';' {
668 $$ = &reservedNode{ranges: $2}
669 $$.setRange($1, $3)
670 }
671 | reservedNames
672
673enumReserved : _RESERVED enumRanges ';' {
674 $$ = &reservedNode{ranges: $2}
675 $$.setRange($1, $3)
676 }
677 | reservedNames
678
679reservedNames : _RESERVED fieldNames ';' {
680 rsvd := map[string]struct{}{}
681 for _, n := range $2 {
682 if _, ok := rsvd[n.val]; ok {
683 lexError(protolex, n.start(), fmt.Sprintf("name %q is reserved multiple times", n.val))
684 break
685 }
686 rsvd[n.val] = struct{}{}
687 }
688 $$ = &reservedNode{names: $2}
689 $$.setRange($1, $3)
690 }
691
692fieldNames : fieldNames ',' stringLit {
693 $$ = append($1, $3)
694 }
695 | stringLit {
696 $$ = []*stringLiteralNode{$1}
697 }
698
699enum : _ENUM name '{' enumBody '}' {
700 c := 0
701 for _, el := range $4 {
702 if el.value != nil {
703 c++
704 }
705 }
706 if c == 0 {
707 lexError(protolex, $1.start(), "enums must define at least one value")
708 }
709 $$ = &enumNode{name: $2, decls: $4}
710 $$.setRange($1, $5)
711 }
712
713enumBody : enumBody enumItem {
714 $$ = append($1, $2...)
715 }
716 | enumItem
717 | {
718 $$ = nil
719 }
720
721enumItem : option {
722 $$ = []*enumElement{{option: $1[0]}}
723 }
724 | enumField {
725 $$ = []*enumElement{{value: $1}}
726 }
727 | enumReserved {
728 $$ = []*enumElement{{reserved: $1}}
729 }
730 | ';' {
731 $$ = []*enumElement{{empty: $1}}
732 }
733
734enumField : name '=' _INT_LIT ';' {
735 checkUint64InInt32Range(protolex, $3.start(), $3.val)
736 $$ = &enumValueNode{name: $1, numberP: $3}
737 $$.setRange($1, $4)
738 }
739 | name '=' _INT_LIT '[' fieldOptions ']' ';' {
740 checkUint64InInt32Range(protolex, $3.start(), $3.val)
741 $$ = &enumValueNode{name: $1, numberP: $3, options: $5}
742 $$.setRange($1, $7)
743 }
744 | name '=' negIntLit ';' {
745 checkInt64InInt32Range(protolex, $3.start(), $3.val)
746 $$ = &enumValueNode{name: $1, numberN: $3}
747 $$.setRange($1, $4)
748 }
749 | name '=' negIntLit '[' fieldOptions ']' ';' {
750 checkInt64InInt32Range(protolex, $3.start(), $3.val)
751 $$ = &enumValueNode{name: $1, numberN: $3, options: $5}
752 $$.setRange($1, $7)
753 }
754
755message : _MESSAGE name '{' messageBody '}' {
756 $$ = &messageNode{name: $2, decls: $4}
757 $$.setRange($1, $5)
758 }
759
760messageBody : messageBody messageItem {
761 $$ = append($1, $2...)
762 }
763 | messageItem
764 | {
765 $$ = nil
766 }
767
768messageItem : field {
769 $$ = []*messageElement{{field: $1}}
770 }
771 | enum {
772 $$ = []*messageElement{{enum: $1}}
773 }
774 | message {
775 $$ = []*messageElement{{nested: $1}}
776 }
777 | extend {
778 $$ = []*messageElement{{extend: $1}}
779 }
780 | extensions {
781 $$ = []*messageElement{{extensionRange: $1}}
782 }
783 | group {
784 $$ = []*messageElement{{group: $1}}
785 }
786 | option {
787 $$ = []*messageElement{{option: $1[0]}}
788 }
789 | oneof {
790 $$ = []*messageElement{{oneOf: $1}}
791 }
792 | mapField {
793 $$ = []*messageElement{{mapField: $1}}
794 }
795 | msgReserved {
796 $$ = []*messageElement{{reserved: $1}}
797 }
798 | ';' {
799 $$ = []*messageElement{{empty: $1}}
800 }
801
802extend : _EXTEND typeIdent '{' extendBody '}' {
803 c := 0
804 for _, el := range $4 {
805 if el.field != nil || el.group != nil {
806 c++
807 }
808 }
809 if c == 0 {
810 lexError(protolex, $1.start(), "extend sections must define at least one extension")
811 }
812 $$ = &extendNode{extendee: $2, decls: $4}
813 $$.setRange($1, $5)
814 }
815
816extendBody : extendBody extendItem {
817 $$ = append($1, $2...)
818 }
819 | extendItem
820 | {
821 $$ = nil
822 }
823
824extendItem : field {
825 $$ = []*extendElement{{field: $1}}
826 }
827 | group {
828 $$ = []*extendElement{{group: $1}}
829 }
830 | ';' {
831 $$ = []*extendElement{{empty: $1}}
832 }
833
834service : _SERVICE name '{' serviceBody '}' {
835 $$ = &serviceNode{name: $2, decls: $4}
836 $$.setRange($1, $5)
837 }
838
839serviceBody : serviceBody serviceItem {
840 $$ = append($1, $2...)
841 }
842 | serviceItem
843 | {
844 $$ = nil
845 }
846
847// NB: doc suggests support for "stream" declaration, separate from "rpc", but
848// it does not appear to be supported in protoc (doc is likely from grammar for
849// Google-internal version of protoc, with support for streaming stubby)
850serviceItem : option {
851 $$ = []*serviceElement{{option: $1[0]}}
852 }
853 | rpc {
854 $$ = []*serviceElement{{rpc: $1}}
855 }
856 | ';' {
857 $$ = []*serviceElement{{empty: $1}}
858 }
859
860rpc : _RPC name '(' rpcType ')' _RETURNS '(' rpcType ')' ';' {
861 $$ = &methodNode{name: $2, input: $4, output: $8}
862 $$.setRange($1, $10)
863 }
864 | _RPC name '(' rpcType ')' _RETURNS '(' rpcType ')' '{' rpcOptions '}' {
865 $$ = &methodNode{name: $2, input: $4, output: $8, options: $11}
866 $$.setRange($1, $12)
867 }
868
869rpcType : _STREAM typeIdent {
870 $$ = &rpcTypeNode{msgType: $2, streamKeyword: $1}
871 $$.setRange($1, $2)
872 }
873 | typeIdent {
874 $$ = &rpcTypeNode{msgType: $1}
875 $$.setRange($1, $1)
876 }
877
878rpcOptions : rpcOptions rpcOption {
879 $$ = append($1, $2...)
880 }
881 | rpcOption
882 | {
883 $$ = []*optionNode{}
884 }
885
886rpcOption : option {
887 $$ = $1
888 }
889 | ';' {
890 $$ = []*optionNode{}
891 }
892
893name : _NAME
894 | _SYNTAX
895 | _IMPORT
896 | _WEAK
897 | _PUBLIC
898 | _PACKAGE
899 | _OPTION
900 | _TRUE
901 | _FALSE
902 | _INF
903 | _NAN
904 | _REPEATED
905 | _OPTIONAL
906 | _REQUIRED
907 | _DOUBLE
908 | _FLOAT
909 | _INT32
910 | _INT64
911 | _UINT32
912 | _UINT64
913 | _SINT32
914 | _SINT64
915 | _FIXED32
916 | _FIXED64
917 | _SFIXED32
918 | _SFIXED64
919 | _BOOL
920 | _STRING
921 | _BYTES
922 | _GROUP
923 | _ONEOF
924 | _MAP
925 | _EXTENSIONS
926 | _TO
927 | _MAX
928 | _RESERVED
929 | _ENUM
930 | _MESSAGE
931 | _EXTEND
932 | _SERVICE
933 | _RPC
934 | _STREAM
935 | _RETURNS
936
937%%