Zack Williams | e940c7a | 2019-08-21 14:25:39 -0700 | [diff] [blame] | 1 | %{ |
| 2 | package protoparse |
| 3 | |
| 4 | //lint:file-ignore SA4006 generated parser has unused values |
| 5 | |
| 6 | import ( |
| 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 | |
| 114 | file : 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 | |
| 140 | fileDecls : fileDecls fileDecl { |
| 141 | $$ = append($1, $2...) |
| 142 | } |
| 143 | | fileDecl |
| 144 | |
| 145 | fileDecl : 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 | |
| 170 | syntax : _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 | |
| 178 | import : _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 | |
| 191 | package : _PACKAGE ident ';' { |
| 192 | $$ = &packageNode{name: $2} |
| 193 | $$.setRange($1, $3) |
| 194 | } |
| 195 | |
| 196 | ident : name |
| 197 | | _FQNAME |
| 198 | |
| 199 | option : _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 | |
| 207 | optionName : 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 | |
| 223 | optionNameRest : optionNameComponent |
| 224 | | optionNameComponent optionNameRest { |
| 225 | $$ = append($1, $2...) |
| 226 | } |
| 227 | |
| 228 | optionNameComponent : _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 | |
| 237 | constant : scalarConstant |
| 238 | | aggregate |
| 239 | |
| 240 | scalarConstant : 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 | |
| 270 | intLit : _INT_LIT |
| 271 | | '+' _INT_LIT { |
| 272 | $$ = $2 |
| 273 | } |
| 274 | |
| 275 | negIntLit : '-' _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 | |
| 283 | floatLit : _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 | |
| 301 | stringLit : _STRING_LIT |
| 302 | | stringLit _STRING_LIT { |
| 303 | $$ = &stringLiteralNode{val: $1.val + $2.val} |
| 304 | $$.setRange($1, $2) |
| 305 | } |
| 306 | |
| 307 | aggregate : '{' aggFields '}' { |
| 308 | a := &aggregateLiteralNode{elements: $2} |
| 309 | a.setRange($1, $3) |
| 310 | $$ = a |
| 311 | } |
| 312 | |
| 313 | aggFields : aggField |
| 314 | | aggFields aggField { |
| 315 | $$ = append($1, $2...) |
| 316 | } |
| 317 | | { |
| 318 | $$ = nil |
| 319 | } |
| 320 | |
| 321 | aggField : aggFieldEntry |
| 322 | | aggFieldEntry ',' { |
| 323 | $$ = $1 |
| 324 | } |
| 325 | | aggFieldEntry ';' { |
| 326 | $$ = $1 |
| 327 | } |
| 328 | |
| 329 | aggFieldEntry : 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 | |
| 373 | aggName : name { |
| 374 | $$ = &aggregateNameNode{name: $1} |
| 375 | $$.setRange($1, $1) |
| 376 | } |
| 377 | | '[' ident ']' { |
| 378 | $$ = &aggregateNameNode{name: $2, isExtension: true} |
| 379 | $$.setRange($1, $3) |
| 380 | } |
| 381 | |
| 382 | constantList : 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 | |
| 407 | typeIdent : ident |
| 408 | | _TYPENAME |
| 409 | |
| 410 | field : _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 | |
| 457 | fieldOptions : fieldOptions ',' fieldOption { |
| 458 | $$ = append($1, $3...) |
| 459 | } |
| 460 | | fieldOption |
| 461 | |
| 462 | fieldOption: 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 | |
| 470 | group : _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 | |
| 498 | oneof : _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 | |
| 512 | oneofBody : oneofBody oneofItem { |
| 513 | $$ = append($1, $2...) |
| 514 | } |
| 515 | | oneofItem |
| 516 | | { |
| 517 | $$ = nil |
| 518 | } |
| 519 | |
| 520 | oneofItem : option { |
| 521 | $$ = []*oneOfElement{{option: $1[0]}} |
| 522 | } |
| 523 | | oneofField { |
| 524 | $$ = []*oneOfElement{{field: $1}} |
| 525 | } |
| 526 | | ';' { |
| 527 | $$ = []*oneOfElement{{empty: $1}} |
| 528 | } |
| 529 | |
| 530 | oneofField : 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 | |
| 541 | mapField : _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 | |
| 552 | keyType : _INT32 |
| 553 | | _INT64 |
| 554 | | _UINT32 |
| 555 | | _UINT64 |
| 556 | | _SINT32 |
| 557 | | _SINT64 |
| 558 | | _FIXED32 |
| 559 | | _FIXED64 |
| 560 | | _SFIXED32 |
| 561 | | _SFIXED64 |
| 562 | | _BOOL |
| 563 | | _STRING |
| 564 | |
| 565 | extensions : _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 | |
| 574 | tagRanges : tagRanges ',' tagRange { |
| 575 | $$ = append($1, $3...) |
| 576 | } |
| 577 | | tagRange |
| 578 | |
| 579 | tagRange : _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 | |
| 610 | enumRanges : enumRanges ',' enumRange { |
| 611 | $$ = append($1, $3...) |
| 612 | } |
| 613 | | enumRange |
| 614 | |
| 615 | enumRange : _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 | |
| 667 | msgReserved : _RESERVED tagRanges ';' { |
| 668 | $$ = &reservedNode{ranges: $2} |
| 669 | $$.setRange($1, $3) |
| 670 | } |
| 671 | | reservedNames |
| 672 | |
| 673 | enumReserved : _RESERVED enumRanges ';' { |
| 674 | $$ = &reservedNode{ranges: $2} |
| 675 | $$.setRange($1, $3) |
| 676 | } |
| 677 | | reservedNames |
| 678 | |
| 679 | reservedNames : _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 | |
| 692 | fieldNames : fieldNames ',' stringLit { |
| 693 | $$ = append($1, $3) |
| 694 | } |
| 695 | | stringLit { |
| 696 | $$ = []*stringLiteralNode{$1} |
| 697 | } |
| 698 | |
| 699 | enum : _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 | |
| 713 | enumBody : enumBody enumItem { |
| 714 | $$ = append($1, $2...) |
| 715 | } |
| 716 | | enumItem |
| 717 | | { |
| 718 | $$ = nil |
| 719 | } |
| 720 | |
| 721 | enumItem : 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 | |
| 734 | enumField : 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 | |
| 755 | message : _MESSAGE name '{' messageBody '}' { |
| 756 | $$ = &messageNode{name: $2, decls: $4} |
| 757 | $$.setRange($1, $5) |
| 758 | } |
| 759 | |
| 760 | messageBody : messageBody messageItem { |
| 761 | $$ = append($1, $2...) |
| 762 | } |
| 763 | | messageItem |
| 764 | | { |
| 765 | $$ = nil |
| 766 | } |
| 767 | |
| 768 | messageItem : 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 | |
| 802 | extend : _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 | |
| 816 | extendBody : extendBody extendItem { |
| 817 | $$ = append($1, $2...) |
| 818 | } |
| 819 | | extendItem |
| 820 | | { |
| 821 | $$ = nil |
| 822 | } |
| 823 | |
| 824 | extendItem : field { |
| 825 | $$ = []*extendElement{{field: $1}} |
| 826 | } |
| 827 | | group { |
| 828 | $$ = []*extendElement{{group: $1}} |
| 829 | } |
| 830 | | ';' { |
| 831 | $$ = []*extendElement{{empty: $1}} |
| 832 | } |
| 833 | |
| 834 | service : _SERVICE name '{' serviceBody '}' { |
| 835 | $$ = &serviceNode{name: $2, decls: $4} |
| 836 | $$.setRange($1, $5) |
| 837 | } |
| 838 | |
| 839 | serviceBody : 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) |
| 850 | serviceItem : option { |
| 851 | $$ = []*serviceElement{{option: $1[0]}} |
| 852 | } |
| 853 | | rpc { |
| 854 | $$ = []*serviceElement{{rpc: $1}} |
| 855 | } |
| 856 | | ';' { |
| 857 | $$ = []*serviceElement{{empty: $1}} |
| 858 | } |
| 859 | |
| 860 | rpc : _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 | |
| 869 | rpcType : _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 | |
| 878 | rpcOptions : rpcOptions rpcOption { |
| 879 | $$ = append($1, $2...) |
| 880 | } |
| 881 | | rpcOption |
| 882 | | { |
| 883 | $$ = []*optionNode{} |
| 884 | } |
| 885 | |
| 886 | rpcOption : option { |
| 887 | $$ = $1 |
| 888 | } |
| 889 | | ';' { |
| 890 | $$ = []*optionNode{} |
| 891 | } |
| 892 | |
| 893 | name : _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 | %% |