blob: a795fe78233f0cadd9b1019280ae59266ad24ec7 [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
Scott Baker4a35a702019-11-26 08:17:33 -080028 mapType *mapTypeNode
Zack Williamse940c7a2019-08-21 14:25:39 -070029 grp *groupNode
30 oo *oneOfNode
31 ooDecls []*oneOfElement
32 ext *extensionRangeNode
33 resvd *reservedNode
34 en *enumNode
35 enDecls []*enumElement
36 env *enumValueNode
37 extend *extendNode
38 extDecls []*extendElement
39 svc *serviceNode
40 svcDecls []*serviceElement
41 mtd *methodNode
42 rpcType *rpcTypeNode
43 opts []*optionNode
44 optNm []*optionNamePartNode
Scott Baker4a35a702019-11-26 08:17:33 -080045 cmpctOpts *compactOptionsNode
Zack Williamse940c7a2019-08-21 14:25:39 -070046 rngs []*rangeNode
Scott Baker4a35a702019-11-26 08:17:33 -080047 names []*compoundStringNode
48 cid *compoundIdentNode
Zack Williamse940c7a2019-08-21 14:25:39 -070049 sl []valueNode
50 agg []*aggregateEntryNode
51 aggName *aggregateNameNode
52 v valueNode
Scott Baker4a35a702019-11-26 08:17:33 -080053 il *compoundIntNode
54 str *compoundStringNode
55 s *stringLiteralNode
56 i *intLiteralNode
Zack Williamse940c7a2019-08-21 14:25:39 -070057 f *floatLiteralNode
58 id *identNode
59 b *basicNode
60 err error
61}
62
63// any non-terminal which returns a value needs a type, which is
64// really a field name in the above union struct
65%type <file> file
66%type <syn> syntax
67%type <fileDecls> fileDecl fileDecls
68%type <imprt> import
69%type <pkg> package
Scott Baker4a35a702019-11-26 08:17:33 -080070%type <opts> option compactOption compactOptionDecls rpcOption rpcOptions
Zack Williamse940c7a2019-08-21 14:25:39 -070071%type <optNm> optionName optionNameRest optionNameComponent
Scott Baker4a35a702019-11-26 08:17:33 -080072%type <cmpctOpts> compactOptions
73%type <v> constant scalarConstant aggregate uintLit floatLit
74%type <il> intLit negIntLit
75%type <id> name keyType
76%type <cid> ident typeIdent
Zack Williamse940c7a2019-08-21 14:25:39 -070077%type <aggName> aggName
Zack Williamse940c7a2019-08-21 14:25:39 -070078%type <sl> constantList
79%type <agg> aggFields aggField aggFieldEntry
80%type <fld> field oneofField
81%type <oo> oneof
Scott Baker4a35a702019-11-26 08:17:33 -080082%type <grp> group oneofGroup
Zack Williamse940c7a2019-08-21 14:25:39 -070083%type <mapFld> mapField
Scott Baker4a35a702019-11-26 08:17:33 -080084%type <mapType> mapType
Zack Williamse940c7a2019-08-21 14:25:39 -070085%type <msg> message
86%type <msgDecls> messageItem messageBody
87%type <ooDecls> oneofItem oneofBody
88%type <names> fieldNames
89%type <resvd> msgReserved enumReserved reservedNames
90%type <rngs> tagRange tagRanges enumRange enumRanges
91%type <ext> extensions
92%type <en> enum
93%type <enDecls> enumItem enumBody
94%type <env> enumField
95%type <extend> extend
96%type <extDecls> extendItem extendBody
97%type <str> stringLit
98%type <svc> service
99%type <svcDecls> serviceItem serviceBody
100%type <mtd> rpc
101%type <rpcType> rpcType
102
103// same for terminals
Scott Baker4a35a702019-11-26 08:17:33 -0800104%token <s> _STRING_LIT
105%token <i> _INT_LIT
Zack Williamse940c7a2019-08-21 14:25:39 -0700106%token <f> _FLOAT_LIT
Scott Baker4a35a702019-11-26 08:17:33 -0800107%token <id> _NAME
Zack Williamse940c7a2019-08-21 14:25:39 -0700108%token <id> _SYNTAX _IMPORT _WEAK _PUBLIC _PACKAGE _OPTION _TRUE _FALSE _INF _NAN _REPEATED _OPTIONAL _REQUIRED
109%token <id> _DOUBLE _FLOAT _INT32 _INT64 _UINT32 _UINT64 _SINT32 _SINT64 _FIXED32 _FIXED64 _SFIXED32 _SFIXED64
110%token <id> _BOOL _STRING _BYTES _GROUP _ONEOF _MAP _EXTENSIONS _TO _MAX _RESERVED _ENUM _MESSAGE _EXTEND
111%token <id> _SERVICE _RPC _STREAM _RETURNS
112%token <err> _ERROR
113// we define all of these, even ones that aren't used, to improve error messages
114// so it shows the unexpected symbol instead of showing "$unk"
115%token <b> '=' ';' ':' '{' '}' '\\' '/' '?' '.' ',' '>' '<' '+' '-' '(' ')' '[' ']' '*' '&' '^' '%' '$' '#' '@' '!' '~' '`'
116
117%%
118
119file : syntax {
120 $$ = &fileNode{syntax: $1}
121 $$.setRange($1, $1)
122 protolex.(*protoLex).res = $$
123 }
124 | fileDecls {
125 $$ = &fileNode{decls: $1}
126 if len($1) > 0 {
127 $$.setRange($1[0], $1[len($1)-1])
128 }
129 protolex.(*protoLex).res = $$
130 }
131 | syntax fileDecls {
132 $$ = &fileNode{syntax: $1, decls: $2}
133 var end node
134 if len($2) > 0 {
135 end = $2[len($2)-1]
136 } else {
137 end = $1
138 }
139 $$.setRange($1, end)
140 protolex.(*protoLex).res = $$
141 }
142 | {
143 }
144
145fileDecls : fileDecls fileDecl {
146 $$ = append($1, $2...)
147 }
148 | fileDecl
149
150fileDecl : import {
151 $$ = []*fileElement{{imp: $1}}
152 }
153 | package {
154 $$ = []*fileElement{{pkg: $1}}
155 }
156 | option {
157 $$ = []*fileElement{{option: $1[0]}}
158 }
159 | message {
160 $$ = []*fileElement{{message: $1}}
161 }
162 | enum {
163 $$ = []*fileElement{{enum: $1}}
164 }
165 | extend {
166 $$ = []*fileElement{{extend: $1}}
167 }
168 | service {
169 $$ = []*fileElement{{service: $1}}
170 }
171 | ';' {
172 $$ = []*fileElement{{empty: $1}}
173 }
Scott Baker4a35a702019-11-26 08:17:33 -0800174 | error ';' {
175 }
176 | error {
177 }
Zack Williamse940c7a2019-08-21 14:25:39 -0700178
179syntax : _SYNTAX '=' stringLit ';' {
180 if $3.val != "proto2" && $3.val != "proto3" {
181 lexError(protolex, $3.start(), "syntax value must be 'proto2' or 'proto3'")
182 }
183 $$ = &syntaxNode{syntax: $3}
184 $$.setRange($1, $4)
185 }
186
187import : _IMPORT stringLit ';' {
188 $$ = &importNode{ name: $2 }
189 $$.setRange($1, $3)
190 }
191 | _IMPORT _WEAK stringLit ';' {
192 $$ = &importNode{ name: $3, weak: true }
193 $$.setRange($1, $4)
194 }
195 | _IMPORT _PUBLIC stringLit ';' {
196 $$ = &importNode{ name: $3, public: true }
197 $$.setRange($1, $4)
198 }
199
200package : _PACKAGE ident ';' {
201 $$ = &packageNode{name: $2}
202 $$.setRange($1, $3)
203 }
204
Scott Baker4a35a702019-11-26 08:17:33 -0800205ident : name {
206 $$ = &compoundIdentNode{val: $1.val}
207 $$.setRange($1, $1)
208 }
209 | ident '.' name {
210 $$ = &compoundIdentNode{val: $1.val + "." + $3.val}
211 $$.setRange($1, $3)
212 }
Zack Williamse940c7a2019-08-21 14:25:39 -0700213
214option : _OPTION optionName '=' constant ';' {
215 n := &optionNameNode{parts: $2}
216 n.setRange($2[0], $2[len($2)-1])
217 o := &optionNode{name: n, val: $4}
218 o.setRange($1, $5)
219 $$ = []*optionNode{o}
220 }
221
222optionName : ident {
223 $$ = toNameParts($1, 0)
224 }
225 | '(' typeIdent ')' {
226 p := &optionNamePartNode{text: $2, isExtension: true}
227 p.setRange($1, $3)
228 $$ = []*optionNamePartNode{p}
229 }
230 | '(' typeIdent ')' optionNameRest {
231 p := &optionNamePartNode{text: $2, isExtension: true}
232 p.setRange($1, $3)
233 ps := make([]*optionNamePartNode, 1, len($4)+1)
234 ps[0] = p
235 $$ = append(ps, $4...)
236 }
237
238optionNameRest : optionNameComponent
239 | optionNameComponent optionNameRest {
240 $$ = append($1, $2...)
241 }
242
Scott Baker4a35a702019-11-26 08:17:33 -0800243optionNameComponent : typeIdent {
Zack Williamse940c7a2019-08-21 14:25:39 -0700244 $$ = toNameParts($1, 1 /* exclude leading dot */)
245 }
246 | '.' '(' typeIdent ')' {
247 p := &optionNamePartNode{text: $3, isExtension: true}
248 p.setRange($2, $4)
249 $$ = []*optionNamePartNode{p}
250 }
251
252constant : scalarConstant
253 | aggregate
254
255scalarConstant : stringLit {
256 $$ = $1
257 }
Scott Baker4a35a702019-11-26 08:17:33 -0800258 | uintLit
Zack Williamse940c7a2019-08-21 14:25:39 -0700259 | negIntLit {
Scott Baker4a35a702019-11-26 08:17:33 -0800260 $$ = $1
Zack Williamse940c7a2019-08-21 14:25:39 -0700261 }
Scott Baker4a35a702019-11-26 08:17:33 -0800262 | floatLit
Zack Williamse940c7a2019-08-21 14:25:39 -0700263 | name {
264 if $1.val == "true" {
Scott Baker4a35a702019-11-26 08:17:33 -0800265 $$ = &boolLiteralNode{identNode: $1, val: true}
Zack Williamse940c7a2019-08-21 14:25:39 -0700266 } else if $1.val == "false" {
Scott Baker4a35a702019-11-26 08:17:33 -0800267 $$ = &boolLiteralNode{identNode: $1, val: false}
Zack Williamse940c7a2019-08-21 14:25:39 -0700268 } else if $1.val == "inf" {
Scott Baker4a35a702019-11-26 08:17:33 -0800269 f := &compoundFloatNode{val: math.Inf(1)}
Zack Williamse940c7a2019-08-21 14:25:39 -0700270 f.setRange($1, $1)
271 $$ = f
272 } else if $1.val == "nan" {
Scott Baker4a35a702019-11-26 08:17:33 -0800273 f := &compoundFloatNode{val: math.NaN()}
Zack Williamse940c7a2019-08-21 14:25:39 -0700274 f.setRange($1, $1)
275 $$ = f
276 } else {
277 $$ = $1
278 }
279 }
280
Scott Baker4a35a702019-11-26 08:17:33 -0800281uintLit : _INT_LIT {
282 i := &compoundUintNode{val: $1.val}
283 i.setRange($1, $1)
284 $$ = i
285 }
Zack Williamse940c7a2019-08-21 14:25:39 -0700286 | '+' _INT_LIT {
Scott Baker4a35a702019-11-26 08:17:33 -0800287 i := &compoundUintNode{val: $2.val}
288 i.setRange($1, $2)
289 $$ = i
Zack Williamse940c7a2019-08-21 14:25:39 -0700290 }
291
292negIntLit : '-' _INT_LIT {
293 if $2.val > math.MaxInt64 + 1 {
294 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)))
295 }
Scott Baker4a35a702019-11-26 08:17:33 -0800296 i := &compoundIntNode{val: -int64($2.val)}
297 i.setRange($1, $2)
298 $$ = i
Zack Williamse940c7a2019-08-21 14:25:39 -0700299 }
300
Scott Baker4a35a702019-11-26 08:17:33 -0800301intLit : negIntLit
302 | _INT_LIT {
303 // we don't allow uintLit because this is for enum numeric vals, which don't allow '+'
304 checkUint64InInt32Range(protolex, $1.start(), $1.val)
305 i := &compoundIntNode{val: int64($1.val)}
306 i.setRange($1, $1)
307 $$ = i
308 }
309
310floatLit : _FLOAT_LIT {
311 $$ = $1
312 }
Zack Williamse940c7a2019-08-21 14:25:39 -0700313 | '-' _FLOAT_LIT {
Scott Baker4a35a702019-11-26 08:17:33 -0800314 f := &compoundFloatNode{val: -$2.val}
315 f.setRange($1, $2)
316 $$ = f
Zack Williamse940c7a2019-08-21 14:25:39 -0700317 }
318 | '+' _FLOAT_LIT {
Scott Baker4a35a702019-11-26 08:17:33 -0800319 f := &compoundFloatNode{val: $2.val}
320 f.setRange($1, $2)
321 $$ = f
Zack Williamse940c7a2019-08-21 14:25:39 -0700322 }
323 | '+' _INF {
Scott Baker4a35a702019-11-26 08:17:33 -0800324 f := &compoundFloatNode{val: math.Inf(1)}
325 f.setRange($1, $2)
326 $$ = f
Zack Williamse940c7a2019-08-21 14:25:39 -0700327 }
328 | '-' _INF {
Scott Baker4a35a702019-11-26 08:17:33 -0800329 f := &compoundFloatNode{val: math.Inf(-1)}
330 f.setRange($1, $2)
331 $$ = f
Zack Williamse940c7a2019-08-21 14:25:39 -0700332 }
333
Scott Baker4a35a702019-11-26 08:17:33 -0800334stringLit : _STRING_LIT {
335 $$ = &compoundStringNode{val: $1.val}
336 $$.setRange($1, $1)
337 }
Zack Williamse940c7a2019-08-21 14:25:39 -0700338 | stringLit _STRING_LIT {
Scott Baker4a35a702019-11-26 08:17:33 -0800339 $$ = &compoundStringNode{val: $1.val + $2.val}
Zack Williamse940c7a2019-08-21 14:25:39 -0700340 $$.setRange($1, $2)
341 }
342
343aggregate : '{' aggFields '}' {
344 a := &aggregateLiteralNode{elements: $2}
345 a.setRange($1, $3)
346 $$ = a
347 }
348
349aggFields : aggField
350 | aggFields aggField {
351 $$ = append($1, $2...)
352 }
353 | {
354 $$ = nil
355 }
356
357aggField : aggFieldEntry
358 | aggFieldEntry ',' {
359 $$ = $1
360 }
361 | aggFieldEntry ';' {
362 $$ = $1
363 }
Scott Baker4a35a702019-11-26 08:17:33 -0800364 | error ',' {
365 }
366 | error ';' {
367 }
368 | error {
369 }
Zack Williamse940c7a2019-08-21 14:25:39 -0700370
371aggFieldEntry : aggName ':' scalarConstant {
372 a := &aggregateEntryNode{name: $1, val: $3}
373 a.setRange($1, $3)
374 $$ = []*aggregateEntryNode{a}
375 }
376 | aggName ':' '[' ']' {
377 s := &sliceLiteralNode{}
378 s.setRange($3, $4)
379 a := &aggregateEntryNode{name: $1, val: s}
380 a.setRange($1, $4)
381 $$ = []*aggregateEntryNode{a}
382 }
383 | aggName ':' '[' constantList ']' {
384 s := &sliceLiteralNode{elements: $4}
385 s.setRange($3, $5)
386 a := &aggregateEntryNode{name: $1, val: s}
387 a.setRange($1, $5)
388 $$ = []*aggregateEntryNode{a}
389 }
Scott Baker4a35a702019-11-26 08:17:33 -0800390 | aggName ':' '[' error ']' {
391 }
Zack Williamse940c7a2019-08-21 14:25:39 -0700392 | aggName ':' aggregate {
393 a := &aggregateEntryNode{name: $1, val: $3}
394 a.setRange($1, $3)
395 $$ = []*aggregateEntryNode{a}
396 }
397 | aggName aggregate {
398 a := &aggregateEntryNode{name: $1, val: $2}
399 a.setRange($1, $2)
400 $$ = []*aggregateEntryNode{a}
401 }
402 | aggName ':' '<' aggFields '>' {
403 s := &aggregateLiteralNode{elements: $4}
404 s.setRange($3, $5)
405 a := &aggregateEntryNode{name: $1, val: s}
406 a.setRange($1, $5)
407 $$ = []*aggregateEntryNode{a}
408 }
409 | aggName '<' aggFields '>' {
410 s := &aggregateLiteralNode{elements: $3}
411 s.setRange($2, $4)
412 a := &aggregateEntryNode{name: $1, val: s}
413 a.setRange($1, $4)
414 $$ = []*aggregateEntryNode{a}
415 }
Scott Baker4a35a702019-11-26 08:17:33 -0800416 | aggName ':' '<' error '>' {
417 }
418 | aggName '<' error '>' {
419 }
Zack Williamse940c7a2019-08-21 14:25:39 -0700420
421aggName : name {
Scott Baker4a35a702019-11-26 08:17:33 -0800422 n := &compoundIdentNode{val: $1.val}
423 n.setRange($1, $1)
424 $$ = &aggregateNameNode{name: n}
Zack Williamse940c7a2019-08-21 14:25:39 -0700425 $$.setRange($1, $1)
426 }
Scott Baker4a35a702019-11-26 08:17:33 -0800427 | '[' typeIdent ']' {
Zack Williamse940c7a2019-08-21 14:25:39 -0700428 $$ = &aggregateNameNode{name: $2, isExtension: true}
429 $$.setRange($1, $3)
430 }
Scott Baker4a35a702019-11-26 08:17:33 -0800431 | '[' error ']' {
432 }
Zack Williamse940c7a2019-08-21 14:25:39 -0700433
434constantList : constant {
435 $$ = []valueNode{$1}
436 }
437 | constantList ',' constant {
438 $$ = append($1, $3)
439 }
440 | constantList ';' constant {
441 $$ = append($1, $3)
442 }
443 | '<' aggFields '>' {
444 s := &aggregateLiteralNode{elements: $2}
445 s.setRange($1, $3)
446 $$ = []valueNode{s}
447 }
448 | constantList ',' '<' aggFields '>' {
449 s := &aggregateLiteralNode{elements: $4}
450 s.setRange($3, $5)
451 $$ = append($1, s)
452 }
453 | constantList ';' '<' aggFields '>' {
454 s := &aggregateLiteralNode{elements: $4}
455 s.setRange($3, $5)
456 $$ = append($1, s)
457 }
Scott Baker4a35a702019-11-26 08:17:33 -0800458 | '<' error '>' {
459 }
460 | constantList ',' '<' error '>' {
461 }
462 | constantList ';' '<' error '>' {
463 }
Zack Williamse940c7a2019-08-21 14:25:39 -0700464
465typeIdent : ident
Scott Baker4a35a702019-11-26 08:17:33 -0800466 | '.' ident {
467 $$ = &compoundIdentNode{val: "." + $2.val}
468 $$.setRange($1, $2)
469 }
Zack Williamse940c7a2019-08-21 14:25:39 -0700470
471field : _REQUIRED typeIdent name '=' _INT_LIT ';' {
472 checkTag(protolex, $5.start(), $5.val)
Scott Baker4a35a702019-11-26 08:17:33 -0800473 lbl := fieldLabel{identNode: $1, required: true}
Zack Williamse940c7a2019-08-21 14:25:39 -0700474 $$ = &fieldNode{label: lbl, fldType: $2, name: $3, tag: $5}
475 $$.setRange($1, $6)
476 }
477 | _OPTIONAL typeIdent name '=' _INT_LIT ';' {
478 checkTag(protolex, $5.start(), $5.val)
Scott Baker4a35a702019-11-26 08:17:33 -0800479 lbl := fieldLabel{identNode: $1}
Zack Williamse940c7a2019-08-21 14:25:39 -0700480 $$ = &fieldNode{label: lbl, fldType: $2, name: $3, tag: $5}
481 $$.setRange($1, $6)
482 }
483 | _REPEATED typeIdent name '=' _INT_LIT ';' {
484 checkTag(protolex, $5.start(), $5.val)
Scott Baker4a35a702019-11-26 08:17:33 -0800485 lbl := fieldLabel{identNode: $1, repeated: true}
Zack Williamse940c7a2019-08-21 14:25:39 -0700486 $$ = &fieldNode{label: lbl, fldType: $2, name: $3, tag: $5}
487 $$.setRange($1, $6)
488 }
489 | typeIdent name '=' _INT_LIT ';' {
490 checkTag(protolex, $4.start(), $4.val)
491 $$ = &fieldNode{fldType: $1, name: $2, tag: $4}
492 $$.setRange($1, $5)
493 }
Scott Baker4a35a702019-11-26 08:17:33 -0800494 | _REQUIRED typeIdent name '=' _INT_LIT compactOptions ';' {
Zack Williamse940c7a2019-08-21 14:25:39 -0700495 checkTag(protolex, $5.start(), $5.val)
Scott Baker4a35a702019-11-26 08:17:33 -0800496 lbl := fieldLabel{identNode: $1, required: true}
497 $$ = &fieldNode{label: lbl, fldType: $2, name: $3, tag: $5, options: $6}
498 $$.setRange($1, $7)
Zack Williamse940c7a2019-08-21 14:25:39 -0700499 }
Scott Baker4a35a702019-11-26 08:17:33 -0800500 | _OPTIONAL typeIdent name '=' _INT_LIT compactOptions ';' {
Zack Williamse940c7a2019-08-21 14:25:39 -0700501 checkTag(protolex, $5.start(), $5.val)
Scott Baker4a35a702019-11-26 08:17:33 -0800502 lbl := fieldLabel{identNode: $1}
503 $$ = &fieldNode{label: lbl, fldType: $2, name: $3, tag: $5, options: $6}
504 $$.setRange($1, $7)
Zack Williamse940c7a2019-08-21 14:25:39 -0700505 }
Scott Baker4a35a702019-11-26 08:17:33 -0800506 | _REPEATED typeIdent name '=' _INT_LIT compactOptions ';' {
Zack Williamse940c7a2019-08-21 14:25:39 -0700507 checkTag(protolex, $5.start(), $5.val)
Scott Baker4a35a702019-11-26 08:17:33 -0800508 lbl := fieldLabel{identNode: $1, repeated: true}
509 $$ = &fieldNode{label: lbl, fldType: $2, name: $3, tag: $5, options: $6}
510 $$.setRange($1, $7)
Zack Williamse940c7a2019-08-21 14:25:39 -0700511 }
Scott Baker4a35a702019-11-26 08:17:33 -0800512 | typeIdent name '=' _INT_LIT compactOptions ';' {
Zack Williamse940c7a2019-08-21 14:25:39 -0700513 checkTag(protolex, $4.start(), $4.val)
Scott Baker4a35a702019-11-26 08:17:33 -0800514 $$ = &fieldNode{fldType: $1, name: $2, tag: $4, options: $5}
515 $$.setRange($1, $6)
Zack Williamse940c7a2019-08-21 14:25:39 -0700516 }
517
Scott Baker4a35a702019-11-26 08:17:33 -0800518compactOptions: '[' compactOptionDecls ']' {
519 $$ = &compactOptionsNode{decls: $2}
520 $$.setRange($1, $3)
521 }
522
523compactOptionDecls : compactOptionDecls ',' compactOption {
Zack Williamse940c7a2019-08-21 14:25:39 -0700524 $$ = append($1, $3...)
525 }
Scott Baker4a35a702019-11-26 08:17:33 -0800526 | compactOption
Zack Williamse940c7a2019-08-21 14:25:39 -0700527
Scott Baker4a35a702019-11-26 08:17:33 -0800528compactOption: optionName '=' constant {
Zack Williamse940c7a2019-08-21 14:25:39 -0700529 n := &optionNameNode{parts: $1}
530 n.setRange($1[0], $1[len($1)-1])
531 o := &optionNode{name: n, val: $3}
532 o.setRange($1[0], $3)
533 $$ = []*optionNode{o}
534 }
535
536group : _REQUIRED _GROUP name '=' _INT_LIT '{' messageBody '}' {
537 checkTag(protolex, $5.start(), $5.val)
538 if !unicode.IsUpper(rune($3.val[0])) {
539 lexError(protolex, $3.start(), fmt.Sprintf("group %s should have a name that starts with a capital letter", $3.val))
540 }
Scott Baker4a35a702019-11-26 08:17:33 -0800541 lbl := fieldLabel{identNode: $1, required: true}
Zack Williamse940c7a2019-08-21 14:25:39 -0700542 $$ = &groupNode{groupKeyword: $2, label: lbl, name: $3, tag: $5, decls: $7}
543 $$.setRange($1, $8)
544 }
545 | _OPTIONAL _GROUP name '=' _INT_LIT '{' messageBody '}' {
546 checkTag(protolex, $5.start(), $5.val)
547 if !unicode.IsUpper(rune($3.val[0])) {
548 lexError(protolex, $3.start(), fmt.Sprintf("group %s should have a name that starts with a capital letter", $3.val))
549 }
Scott Baker4a35a702019-11-26 08:17:33 -0800550 lbl := fieldLabel{identNode: $1}
Zack Williamse940c7a2019-08-21 14:25:39 -0700551 $$ = &groupNode{groupKeyword: $2, label: lbl, name: $3, tag: $5, decls: $7}
552 $$.setRange($1, $8)
553 }
554 | _REPEATED _GROUP name '=' _INT_LIT '{' messageBody '}' {
555 checkTag(protolex, $5.start(), $5.val)
556 if !unicode.IsUpper(rune($3.val[0])) {
557 lexError(protolex, $3.start(), fmt.Sprintf("group %s should have a name that starts with a capital letter", $3.val))
558 }
Scott Baker4a35a702019-11-26 08:17:33 -0800559 lbl := fieldLabel{identNode: $1, repeated: true}
Zack Williamse940c7a2019-08-21 14:25:39 -0700560 $$ = &groupNode{groupKeyword: $2, label: lbl, name: $3, tag: $5, decls: $7}
561 $$.setRange($1, $8)
562 }
563
564oneof : _ONEOF name '{' oneofBody '}' {
565 c := 0
566 for _, el := range $4 {
567 if el.field != nil {
568 c++
569 }
570 }
571 if c == 0 {
572 lexError(protolex, $1.start(), "oneof must contain at least one field")
573 }
574 $$ = &oneOfNode{name: $2, decls: $4}
575 $$.setRange($1, $5)
576 }
577
578oneofBody : oneofBody oneofItem {
579 $$ = append($1, $2...)
580 }
581 | oneofItem
582 | {
583 $$ = nil
584 }
585
586oneofItem : option {
587 $$ = []*oneOfElement{{option: $1[0]}}
588 }
589 | oneofField {
590 $$ = []*oneOfElement{{field: $1}}
591 }
Scott Baker4a35a702019-11-26 08:17:33 -0800592 | oneofGroup {
593 $$ = []*oneOfElement{{group: $1}}
594 }
Zack Williamse940c7a2019-08-21 14:25:39 -0700595 | ';' {
596 $$ = []*oneOfElement{{empty: $1}}
597 }
Scott Baker4a35a702019-11-26 08:17:33 -0800598 | error ';' {
599 }
600 | error {
601 }
Zack Williamse940c7a2019-08-21 14:25:39 -0700602
603oneofField : typeIdent name '=' _INT_LIT ';' {
604 checkTag(protolex, $4.start(), $4.val)
605 $$ = &fieldNode{fldType: $1, name: $2, tag: $4}
606 $$.setRange($1, $5)
607 }
Scott Baker4a35a702019-11-26 08:17:33 -0800608 | typeIdent name '=' _INT_LIT compactOptions ';' {
Zack Williamse940c7a2019-08-21 14:25:39 -0700609 checkTag(protolex, $4.start(), $4.val)
Scott Baker4a35a702019-11-26 08:17:33 -0800610 $$ = &fieldNode{fldType: $1, name: $2, tag: $4, options: $5}
611 $$.setRange($1, $6)
Zack Williamse940c7a2019-08-21 14:25:39 -0700612 }
613
Scott Baker4a35a702019-11-26 08:17:33 -0800614oneofGroup : _GROUP name '=' _INT_LIT '{' messageBody '}' {
615 checkTag(protolex, $4.start(), $4.val)
616 if !unicode.IsUpper(rune($2.val[0])) {
617 lexError(protolex, $2.start(), fmt.Sprintf("group %s should have a name that starts with a capital letter", $2.val))
618 }
619 $$ = &groupNode{groupKeyword: $1, name: $2, tag: $4, decls: $6}
620 $$.setRange($1, $7)
Zack Williamse940c7a2019-08-21 14:25:39 -0700621 }
Scott Baker4a35a702019-11-26 08:17:33 -0800622
623mapField : mapType name '=' _INT_LIT ';' {
624 checkTag(protolex, $4.start(), $4.val)
625 $$ = &mapFieldNode{mapType: $1, name: $2, tag: $4}
626 $$.setRange($1, $5)
Zack Williamse940c7a2019-08-21 14:25:39 -0700627 }
Scott Baker4a35a702019-11-26 08:17:33 -0800628 | mapType name '=' _INT_LIT compactOptions ';' {
629 checkTag(protolex, $4.start(), $4.val)
630 $$ = &mapFieldNode{mapType: $1, name: $2, tag: $4, options: $5}
631 $$.setRange($1, $6)
632 }
633
634mapType : _MAP '<' keyType ',' typeIdent '>' {
635 $$ = &mapTypeNode{mapKeyword: $1, keyType: $3, valueType: $5}
636 $$.setRange($1, $6)
637}
Zack Williamse940c7a2019-08-21 14:25:39 -0700638
639keyType : _INT32
640 | _INT64
641 | _UINT32
642 | _UINT64
643 | _SINT32
644 | _SINT64
645 | _FIXED32
646 | _FIXED64
647 | _SFIXED32
648 | _SFIXED64
649 | _BOOL
650 | _STRING
651
652extensions : _EXTENSIONS tagRanges ';' {
653 $$ = &extensionRangeNode{ranges: $2}
654 $$.setRange($1, $3)
655 }
Scott Baker4a35a702019-11-26 08:17:33 -0800656 | _EXTENSIONS tagRanges compactOptions ';' {
657 $$ = &extensionRangeNode{ranges: $2, options: $3}
658 $$.setRange($1, $4)
Zack Williamse940c7a2019-08-21 14:25:39 -0700659 }
660
661tagRanges : tagRanges ',' tagRange {
662 $$ = append($1, $3...)
663 }
664 | tagRange
665
666tagRange : _INT_LIT {
667 if $1.val > internal.MaxTag {
668 lexError(protolex, $1.start(), fmt.Sprintf("range includes out-of-range tag: %d (should be between 0 and %d)", $1.val, internal.MaxTag))
669 }
670 r := &rangeNode{stNode: $1, enNode: $1, st: int32($1.val), en: int32($1.val)}
671 r.setRange($1, $1)
672 $$ = []*rangeNode{r}
673 }
674 | _INT_LIT _TO _INT_LIT {
675 if $1.val > internal.MaxTag {
676 lexError(protolex, $1.start(), fmt.Sprintf("range start is out-of-range tag: %d (should be between 0 and %d)", $1.val, internal.MaxTag))
677 }
678 if $3.val > internal.MaxTag {
679 lexError(protolex, $3.start(), fmt.Sprintf("range end is out-of-range tag: %d (should be between 0 and %d)", $3.val, internal.MaxTag))
680 }
681 if $1.val > $3.val {
682 lexError(protolex, $1.start(), fmt.Sprintf("range, %d to %d, is invalid: start must be <= end", $1.val, $3.val))
683 }
684 r := &rangeNode{stNode: $1, enNode: $3, st: int32($1.val), en: int32($3.val)}
685 r.setRange($1, $3)
686 $$ = []*rangeNode{r}
687 }
688 | _INT_LIT _TO _MAX {
689 if $1.val > internal.MaxTag {
690 lexError(protolex, $1.start(), fmt.Sprintf("range start is out-of-range tag: %d (should be between 0 and %d)", $1.val, internal.MaxTag))
691 }
692 r := &rangeNode{stNode: $1, enNode: $3, st: int32($1.val), en: internal.MaxTag}
693 r.setRange($1, $3)
694 $$ = []*rangeNode{r}
695 }
696
697enumRanges : enumRanges ',' enumRange {
698 $$ = append($1, $3...)
699 }
700 | enumRange
701
Scott Baker4a35a702019-11-26 08:17:33 -0800702enumRange : intLit {
Zack Williamse940c7a2019-08-21 14:25:39 -0700703 checkInt64InInt32Range(protolex, $1.start(), $1.val)
704 r := &rangeNode{stNode: $1, enNode: $1, st: int32($1.val), en: int32($1.val)}
705 r.setRange($1, $1)
706 $$ = []*rangeNode{r}
707 }
Scott Baker4a35a702019-11-26 08:17:33 -0800708 | intLit _TO intLit {
Zack Williamse940c7a2019-08-21 14:25:39 -0700709 checkInt64InInt32Range(protolex, $1.start(), $1.val)
710 checkInt64InInt32Range(protolex, $3.start(), $3.val)
711 if $1.val > $3.val {
712 lexError(protolex, $1.start(), fmt.Sprintf("range, %d to %d, is invalid: start must be <= end", $1.val, $3.val))
713 }
714 r := &rangeNode{stNode: $1, enNode: $3, st: int32($1.val), en: int32($3.val)}
715 r.setRange($1, $3)
716 $$ = []*rangeNode{r}
717 }
Scott Baker4a35a702019-11-26 08:17:33 -0800718 | intLit _TO _MAX {
Zack Williamse940c7a2019-08-21 14:25:39 -0700719 checkInt64InInt32Range(protolex, $1.start(), $1.val)
720 r := &rangeNode{stNode: $1, enNode: $3, st: int32($1.val), en: math.MaxInt32}
721 r.setRange($1, $3)
722 $$ = []*rangeNode{r}
723 }
724
725msgReserved : _RESERVED tagRanges ';' {
726 $$ = &reservedNode{ranges: $2}
727 $$.setRange($1, $3)
728 }
729 | reservedNames
730
731enumReserved : _RESERVED enumRanges ';' {
732 $$ = &reservedNode{ranges: $2}
733 $$.setRange($1, $3)
734 }
735 | reservedNames
736
737reservedNames : _RESERVED fieldNames ';' {
738 rsvd := map[string]struct{}{}
739 for _, n := range $2 {
740 if _, ok := rsvd[n.val]; ok {
741 lexError(protolex, n.start(), fmt.Sprintf("name %q is reserved multiple times", n.val))
742 break
743 }
744 rsvd[n.val] = struct{}{}
745 }
746 $$ = &reservedNode{names: $2}
747 $$.setRange($1, $3)
748 }
749
750fieldNames : fieldNames ',' stringLit {
751 $$ = append($1, $3)
752 }
753 | stringLit {
Scott Baker4a35a702019-11-26 08:17:33 -0800754 $$ = []*compoundStringNode{$1}
Zack Williamse940c7a2019-08-21 14:25:39 -0700755 }
756
757enum : _ENUM name '{' enumBody '}' {
758 c := 0
759 for _, el := range $4 {
760 if el.value != nil {
761 c++
762 }
763 }
764 if c == 0 {
765 lexError(protolex, $1.start(), "enums must define at least one value")
766 }
767 $$ = &enumNode{name: $2, decls: $4}
768 $$.setRange($1, $5)
769 }
770
771enumBody : enumBody enumItem {
772 $$ = append($1, $2...)
773 }
774 | enumItem
775 | {
776 $$ = nil
777 }
778
779enumItem : option {
780 $$ = []*enumElement{{option: $1[0]}}
781 }
782 | enumField {
783 $$ = []*enumElement{{value: $1}}
784 }
785 | enumReserved {
786 $$ = []*enumElement{{reserved: $1}}
787 }
788 | ';' {
789 $$ = []*enumElement{{empty: $1}}
790 }
Scott Baker4a35a702019-11-26 08:17:33 -0800791 | error ';' {
792 }
793 | error {
794 }
Zack Williamse940c7a2019-08-21 14:25:39 -0700795
Scott Baker4a35a702019-11-26 08:17:33 -0800796enumField : name '=' intLit ';' {
797 checkInt64InInt32Range(protolex, $3.start(), $3.val)
798 $$ = &enumValueNode{name: $1, number: $3}
Zack Williamse940c7a2019-08-21 14:25:39 -0700799 $$.setRange($1, $4)
800 }
Scott Baker4a35a702019-11-26 08:17:33 -0800801 | name '=' intLit compactOptions ';' {
Zack Williamse940c7a2019-08-21 14:25:39 -0700802 checkInt64InInt32Range(protolex, $3.start(), $3.val)
Scott Baker4a35a702019-11-26 08:17:33 -0800803 $$ = &enumValueNode{name: $1, number: $3, options: $4}
804 $$.setRange($1, $5)
Zack Williamse940c7a2019-08-21 14:25:39 -0700805 }
806
807message : _MESSAGE name '{' messageBody '}' {
808 $$ = &messageNode{name: $2, decls: $4}
809 $$.setRange($1, $5)
810 }
811
812messageBody : messageBody messageItem {
813 $$ = append($1, $2...)
814 }
815 | messageItem
816 | {
817 $$ = nil
818 }
819
820messageItem : field {
821 $$ = []*messageElement{{field: $1}}
822 }
823 | enum {
824 $$ = []*messageElement{{enum: $1}}
825 }
826 | message {
827 $$ = []*messageElement{{nested: $1}}
828 }
829 | extend {
830 $$ = []*messageElement{{extend: $1}}
831 }
832 | extensions {
833 $$ = []*messageElement{{extensionRange: $1}}
834 }
835 | group {
836 $$ = []*messageElement{{group: $1}}
837 }
838 | option {
839 $$ = []*messageElement{{option: $1[0]}}
840 }
841 | oneof {
842 $$ = []*messageElement{{oneOf: $1}}
843 }
844 | mapField {
845 $$ = []*messageElement{{mapField: $1}}
846 }
847 | msgReserved {
848 $$ = []*messageElement{{reserved: $1}}
849 }
850 | ';' {
851 $$ = []*messageElement{{empty: $1}}
852 }
Scott Baker4a35a702019-11-26 08:17:33 -0800853 | error ';' {
854 }
855 | error {
856 }
Zack Williamse940c7a2019-08-21 14:25:39 -0700857
858extend : _EXTEND typeIdent '{' extendBody '}' {
859 c := 0
860 for _, el := range $4 {
861 if el.field != nil || el.group != nil {
862 c++
863 }
864 }
865 if c == 0 {
866 lexError(protolex, $1.start(), "extend sections must define at least one extension")
867 }
868 $$ = &extendNode{extendee: $2, decls: $4}
869 $$.setRange($1, $5)
870 }
871
872extendBody : extendBody extendItem {
873 $$ = append($1, $2...)
874 }
875 | extendItem
876 | {
877 $$ = nil
878 }
879
880extendItem : field {
881 $$ = []*extendElement{{field: $1}}
882 }
883 | group {
884 $$ = []*extendElement{{group: $1}}
885 }
886 | ';' {
887 $$ = []*extendElement{{empty: $1}}
888 }
Scott Baker4a35a702019-11-26 08:17:33 -0800889 | error ';' {
890 }
891 | error {
892 }
Zack Williamse940c7a2019-08-21 14:25:39 -0700893
894service : _SERVICE name '{' serviceBody '}' {
895 $$ = &serviceNode{name: $2, decls: $4}
896 $$.setRange($1, $5)
897 }
898
899serviceBody : serviceBody serviceItem {
900 $$ = append($1, $2...)
901 }
902 | serviceItem
903 | {
904 $$ = nil
905 }
906
907// NB: doc suggests support for "stream" declaration, separate from "rpc", but
908// it does not appear to be supported in protoc (doc is likely from grammar for
909// Google-internal version of protoc, with support for streaming stubby)
910serviceItem : option {
911 $$ = []*serviceElement{{option: $1[0]}}
912 }
913 | rpc {
914 $$ = []*serviceElement{{rpc: $1}}
915 }
916 | ';' {
917 $$ = []*serviceElement{{empty: $1}}
918 }
Scott Baker4a35a702019-11-26 08:17:33 -0800919 | error ';' {
920 }
921 | error {
922 }
Zack Williamse940c7a2019-08-21 14:25:39 -0700923
924rpc : _RPC name '(' rpcType ')' _RETURNS '(' rpcType ')' ';' {
925 $$ = &methodNode{name: $2, input: $4, output: $8}
926 $$.setRange($1, $10)
927 }
928 | _RPC name '(' rpcType ')' _RETURNS '(' rpcType ')' '{' rpcOptions '}' {
929 $$ = &methodNode{name: $2, input: $4, output: $8, options: $11}
930 $$.setRange($1, $12)
931 }
932
933rpcType : _STREAM typeIdent {
934 $$ = &rpcTypeNode{msgType: $2, streamKeyword: $1}
935 $$.setRange($1, $2)
936 }
937 | typeIdent {
938 $$ = &rpcTypeNode{msgType: $1}
939 $$.setRange($1, $1)
940 }
941
942rpcOptions : rpcOptions rpcOption {
943 $$ = append($1, $2...)
944 }
945 | rpcOption
946 | {
947 $$ = []*optionNode{}
948 }
949
950rpcOption : option {
951 $$ = $1
952 }
953 | ';' {
954 $$ = []*optionNode{}
955 }
Scott Baker4a35a702019-11-26 08:17:33 -0800956 | error ';' {
957 }
958 | error {
959 }
Zack Williamse940c7a2019-08-21 14:25:39 -0700960
961name : _NAME
962 | _SYNTAX
963 | _IMPORT
964 | _WEAK
965 | _PUBLIC
966 | _PACKAGE
967 | _OPTION
968 | _TRUE
969 | _FALSE
970 | _INF
971 | _NAN
972 | _REPEATED
973 | _OPTIONAL
974 | _REQUIRED
975 | _DOUBLE
976 | _FLOAT
977 | _INT32
978 | _INT64
979 | _UINT32
980 | _UINT64
981 | _SINT32
982 | _SINT64
983 | _FIXED32
984 | _FIXED64
985 | _SFIXED32
986 | _SFIXED64
987 | _BOOL
988 | _STRING
989 | _BYTES
990 | _GROUP
991 | _ONEOF
992 | _MAP
993 | _EXTENSIONS
994 | _TO
995 | _MAX
996 | _RESERVED
997 | _ENUM
998 | _MESSAGE
999 | _EXTEND
1000 | _SERVICE
1001 | _RPC
1002 | _STREAM
1003 | _RETURNS
1004
1005%%