github.com/syumai/protoreflect@v1.7.1-0.20200810020253-2ac7e3b3a321/desc/protoparse/proto.y (about)

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