| 1 | # This grammar is intended to be LL(k) at the token level. |
| 2 | # In other words, whenever the parser is required to make a choice it must be |
| 3 | # able to choose "correctly" with constant token lookahead. This means that the |
| 4 | # handwritten recursive descent parser for this grammar can be implemented with |
| 5 | # worst-case linear run time rather than worst-case exponential runtime. |
| 6 | # |
| 7 | # To ensure this property is upheld, care must be taken to avoid requiring |
| 8 | # unbounded token lookahead in the grammar. To illustrate this, consider the |
| 9 | # following examples requiring unbounded lookahead: |
| 10 | # |
| 11 | # This is rather subtle as it looks fine at first glance: |
| 12 | # |
| 13 | # SingleAssignExpr <- Expr (AssignOp Expr)? |
| 14 | # |
| 15 | # Consider the case where the AssignOp token matches but Expr after it does |
| 16 | # not match. The parser would attempt to parse the Expr after the AssignOp, |
| 17 | # fail, then backtrack and succeed the SingleAssignExpr rule matching only |
| 18 | # the first Expr. This is an example of unbounded lookahead. The rule must |
| 19 | # be rewritten so that if the AssignOp token is not followed by an Expr the |
| 20 | # whole SingleAssignExpr rule fails to match: |
| 21 | # |
| 22 | # SingleAssignExpr <- Expr (AssignOp Expr / !AssignOp) |
| 23 | # |
| 24 | # The pattern is similar for e.g. the * operator. The following rule requires |
| 25 | # unbounded lookahead: |
| 26 | # |
| 27 | # BoolOrExpr <- BoolAndExpr (OrOp BoolAndExpr)* |
| 28 | # |
| 29 | # and can be fixed to require only bounded lookahead by adding a !OrOp: |
| 30 | # |
| 31 | # BoolOrExpr <- BoolAndExpr (OrOp BoolAndExpr)* !OrOp |
| 32 | # |
| 33 | # Note also that the negative lookahead added with the ! operator must always be |
| 34 | # for a constant maximum number of tokens. |
| 35 | # |
| 36 | # See this paper for analysis of how LL(k) grammars relate to PEGs: |
| 37 | # https://arxiv.org/abs/1304.3177 |
| 38 | |
| 39 | Root <- ContainerMembers skip eof |
| 40 | |
| 41 | # *** Top level *** |
| 42 | ContainerMembers <- container_doc_comment? ContainerDecl* ContainerMembersRest |
| 43 | ContainerMembersRest |
| 44 | <- !ContainerDeclPrefix ContainerField (COMMA ContainerMembersRest)? |
| 45 | / ContainerDecl* |
| 46 | |
| 47 | ContainerDecl <- TestDecl / ComptimeDecl / doc_comment? KEYWORD_pub? Decl |
| 48 | |
| 49 | ContainerDeclPrefix |
| 50 | <- KEYWORD_test |
| 51 | / KEYWORD_comptime LBRACE |
| 52 | / doc_comment? KEYWORD_pub? DeclPrefix |
| 53 | |
| 54 | TestDecl <- KEYWORD_test (STRINGLITERALSINGLE / IDENTIFIER)? Block |
| 55 | |
| 56 | ComptimeDecl <- KEYWORD_comptime Block |
| 57 | |
| 58 | Decl |
| 59 | <- (KEYWORD_export / KEYWORD_inline / KEYWORD_noinline)? FnProto (SEMICOLON / Block) |
| 60 | / KEYWORD_extern STRINGLITERALSINGLE? FnProto SEMICOLON |
| 61 | / (KEYWORD_export / KEYWORD_extern STRINGLITERALSINGLE?)? KEYWORD_threadlocal? GlobalVarDecl |
| 62 | |
| 63 | DeclPrefix |
| 64 | <- (KEYWORD_export / KEYWORD_inline / KEYWORD_noinline)? KEYWORD_fn |
| 65 | / KEYWORD_extern STRINGLITERALSINGLE? KEYWORD_fn |
| 66 | / (KEYWORD_export / KEYWORD_extern STRINGLITERALSINGLE?)? KEYWORD_threadlocal? (KEYWORD_const / KEYWORD_var) |
| 67 | |
| 68 | FnProto <- KEYWORD_fn IDENTIFIER? ParamDeclList ByteAlign? AddrSpace? LinkSection? CallConv? EXCLAMATIONMARK? TypeExpr |
| 69 | |
| 70 | VarDeclProto <- (KEYWORD_const / KEYWORD_var) IDENTIFIER (COLON TypeExpr)? ByteAlign? AddrSpace? LinkSection? |
| 71 | |
| 72 | GlobalVarDecl <- VarDeclProto (EQUAL Expr)? SEMICOLON |
| 73 | |
| 74 | ContainerField <- doc_comment? KEYWORD_comptime? (IDENTIFIER COLON)? TypeExpr ByteAlign? (EQUAL Expr)? |
| 75 | |
| 76 | # *** Block Level *** |
| 77 | BlockStatement |
| 78 | <- Statement |
| 79 | / KEYWORD_defer BlockExprStatement |
| 80 | / KEYWORD_errdefer BlockExprStatement |
| 81 | / !StatementPrefix KEYWORD_comptime? VarAssignStatement |
| 82 | |
| 83 | Statement |
| 84 | <- IfStatement |
| 85 | / LabeledStatement |
| 86 | / KEYWORD_nosuspend BlockExprStatement |
| 87 | / KEYWORD_comptime BlockExpr |
| 88 | / KEYWORD_suspend BlockExprStatement |
| 89 | / !StatementPrefix KEYWORD_comptime? AssignExpr SEMICOLON |
| 90 | |
| 91 | StatementPrefix |
| 92 | <- KEYWORD_if |
| 93 | / BlockLabel? (LBRACE / KEYWORD_inline? (KEYWORD_for / KEYWORD_while) / KEYWORD_switch) |
| 94 | / KEYWORD_nosuspend |
| 95 | / KEYWORD_comptime BlockExprPrefix |
| 96 | |
| 97 | IfStatement |
| 98 | <- IfPrefix BlockExpr (KEYWORD_else Payload? Statement / !KEYWORD_else) |
| 99 | / IfPrefix !BlockExprPrefix AssignExpr (SEMICOLON / KEYWORD_else Payload? Statement) |
| 100 | |
| 101 | LabeledStatement <- BlockLabel? (Block / LoopStatement / SwitchExpr) |
| 102 | |
| 103 | LoopStatement <- KEYWORD_inline? (ForStatement / WhileStatement) |
| 104 | |
| 105 | ForStatement |
| 106 | <- ForPrefix BlockExpr (KEYWORD_else Statement / !KEYWORD_else) |
| 107 | / ForPrefix !BlockExprPrefix AssignExpr (SEMICOLON / KEYWORD_else Statement) |
| 108 | |
| 109 | WhileStatement |
| 110 | <- WhilePrefix BlockExpr (KEYWORD_else Payload? Statement / !KEYWORD_else) |
| 111 | / WhilePrefix !BlockExprPrefix AssignExpr (SEMICOLON / KEYWORD_else Payload? Statement) |
| 112 | |
| 113 | BlockExprStatement |
| 114 | <- BlockExpr |
| 115 | / !BlockExprPrefix AssignExpr SEMICOLON |
| 116 | |
| 117 | BlockExprPrefix <- BlockLabel? LBRACE |
| 118 | BlockExpr <- BlockLabel? Block |
| 119 | |
| 120 | # An assignment or a destructure whose LHS are all lvalue expressions or variable declarations. |
| 121 | VarAssignStatement <- (VarDeclProto / Expr) (COMMA (VarDeclProto / Expr))* EQUAL Expr SEMICOLON |
| 122 | |
| 123 | # *** Expression Level *** |
| 124 | |
| 125 | # An assignment or a destructure whose LHS are all lvalue expressions. |
| 126 | AssignExpr <- Expr (AssignOp Expr / (COMMA Expr)+ EQUAL Expr / !AssignOp !COMMA) |
| 127 | |
| 128 | SingleAssignExpr <- Expr (AssignOp Expr / !AssignOp) |
| 129 | |
| 130 | Expr <- BoolOrExpr |
| 131 | |
| 132 | BoolOrExpr <- BoolAndExpr (OrOp BoolAndExpr)* !OrOp |
| 133 | |
| 134 | BoolAndExpr <- CompareExpr (AndOp CompareExpr)* !AndOp |
| 135 | |
| 136 | CompareExpr <- BitwiseExpr (CompareOp BitwiseExpr)? !CompareOp |
| 137 | |
| 138 | BitwiseExpr <- BitShiftExpr (BitwiseOp BitShiftExpr)* !BitwiseOp |
| 139 | |
| 140 | BitShiftExpr <- AdditionExpr (BitShiftOp AdditionExpr)* !BitShiftOp |
| 141 | |
| 142 | AdditionExpr <- MultiplyExpr (AdditionOp MultiplyExpr)* !AdditionOp |
| 143 | |
| 144 | MultiplyExpr <- PrefixExpr (MultiplyOp PrefixExpr)* !MultiplyOp |
| 145 | |
| 146 | PrefixExpr <- PrefixOp* !PrefixOp PrimaryExpr |
| 147 | |
| 148 | PrimaryExpr |
| 149 | <- AsmExpr |
| 150 | / IfExpr |
| 151 | / KEYWORD_break BreakLabel? (Expr / !ExprPrefix) |
| 152 | / KEYWORD_comptime Expr |
| 153 | / KEYWORD_nosuspend Expr |
| 154 | / KEYWORD_continue BreakLabel? (Expr / !ExprPrefix) |
| 155 | / KEYWORD_resume Expr |
| 156 | / KEYWORD_return (Expr / !ExprPrefix) |
| 157 | / BlockLabel? LoopExpr |
| 158 | / Block |
| 159 | / CurlySuffixExpr |
| 160 | |
| 161 | IfExpr <- IfPrefix Expr (KEYWORD_else Payload? Expr / !KEYWORD_else) |
| 162 | |
| 163 | Block <- LBRACE BlockStatement* RBRACE |
| 164 | |
| 165 | LoopExpr <- KEYWORD_inline? (ForExpr / WhileExpr) |
| 166 | |
| 167 | ForExpr <- ForPrefix Expr (KEYWORD_else Expr / !KEYWORD_else) |
| 168 | |
| 169 | WhileExpr <- WhilePrefix Expr (KEYWORD_else Payload? Expr)? |
| 170 | |
| 171 | CurlySuffixExpr <- TypeExpr (InitList / !LBRACE) |
| 172 | |
| 173 | InitList |
| 174 | <- LBRACE FieldInit (COMMA FieldInit)* COMMA? RBRACE |
| 175 | / LBRACE Expr (COMMA Expr)* COMMA? RBRACE |
| 176 | / LBRACE RBRACE |
| 177 | |
| 178 | TypeExpr <- PrefixTypeOp* !PrefixTypeOpPrefix ErrorUnionExpr |
| 179 | |
| 180 | ErrorUnionExpr <- SuffixExpr (EXCLAMATIONMARK TypeExpr / !EXCLAMATIONMARK) |
| 181 | |
| 182 | SuffixExpr <- PrimaryTypeExpr SuffixOp* !SuffixOpPrefix |
| 183 | |
| 184 | PrimaryTypeExpr |
| 185 | <- BUILTINIDENTIFIER FnCallArguments |
| 186 | / CHAR_LITERAL |
| 187 | / ContainerType |
| 188 | / DOT IDENTIFIER |
| 189 | / DOT InitList |
| 190 | / ErrorSetDecl |
| 191 | / FnProto |
| 192 | / GroupedExpr |
| 193 | / LabeledTypeExpr |
| 194 | / IDENTIFIER |
| 195 | / IfTypeExpr |
| 196 | / KEYWORD_comptime TypeExpr |
| 197 | / KEYWORD_error DOT IDENTIFIER |
| 198 | / KEYWORD_anyframe |
| 199 | / KEYWORD_unreachable |
| 200 | / NUMBERLITERAL |
| 201 | / STRINGLITERAL |
| 202 | |
| 203 | ContainerType <- (KEYWORD_extern / KEYWORD_packed)? ContainerTypeAuto |
| 204 | |
| 205 | ErrorSetDecl <- KEYWORD_error LBRACE IdentifierList RBRACE |
| 206 | |
| 207 | GroupedExpr <- LPAREN Expr RPAREN |
| 208 | |
| 209 | IfTypeExpr <- IfPrefix TypeExpr (KEYWORD_else Payload? TypeExpr / !KEYWORD_else) |
| 210 | |
| 211 | LabeledTypeExpr |
| 212 | <- BlockLabel Block |
| 213 | / BlockLabel? LoopTypeExpr |
| 214 | / BlockLabel? SwitchExpr |
| 215 | |
| 216 | LoopTypeExpr <- KEYWORD_inline? (ForTypeExpr / WhileTypeExpr) |
| 217 | |
| 218 | ForTypeExpr <- ForPrefix TypeExpr (KEYWORD_else TypeExpr / !KEYWORD_else) |
| 219 | |
| 220 | WhileTypeExpr <- WhilePrefix TypeExpr (KEYWORD_else Payload? TypeExpr / !KEYWORD_else) |
| 221 | |
| 222 | SwitchExpr <- KEYWORD_switch LPAREN Expr RPAREN LBRACE SwitchProngList RBRACE |
| 223 | |
| 224 | # *** Assembly *** |
| 225 | AsmExpr <- KEYWORD_asm KEYWORD_volatile? LPAREN Expr AsmOutput? RPAREN |
| 226 | |
| 227 | AsmOutput <- COLON AsmOutputList AsmInput? |
| 228 | |
| 229 | AsmOutputItem <- LBRACKET IDENTIFIER RBRACKET STRINGLITERALSINGLE LPAREN (MINUSRARROW TypeExpr / IDENTIFIER) RPAREN |
| 230 | |
| 231 | AsmInput <- COLON AsmInputList AsmClobbers? |
| 232 | |
| 233 | AsmInputItem <- LBRACKET IDENTIFIER RBRACKET STRINGLITERALSINGLE LPAREN Expr RPAREN |
| 234 | |
| 235 | AsmClobbers <- COLON Expr |
| 236 | |
| 237 | # *** Helper grammar *** |
| 238 | BreakLabel <- COLON IDENTIFIER |
| 239 | |
| 240 | BlockLabel <- IDENTIFIER COLON |
| 241 | |
| 242 | FieldInit <- DOT IDENTIFIER EQUAL Expr |
| 243 | |
| 244 | WhileContinueExpr <- COLON LPAREN AssignExpr RPAREN |
| 245 | |
| 246 | LinkSection <- KEYWORD_linksection LPAREN Expr RPAREN |
| 247 | |
| 248 | AddrSpace <- KEYWORD_addrspace LPAREN Expr RPAREN |
| 249 | |
| 250 | # Fn specific |
| 251 | CallConv <- KEYWORD_callconv LPAREN Expr RPAREN |
| 252 | |
| 253 | ParamDecl <- doc_comment? (KEYWORD_noalias / KEYWORD_comptime?) (IDENTIFIER COLON)? ParamType |
| 254 | |
| 255 | ParamType |
| 256 | <- KEYWORD_anytype |
| 257 | / TypeExpr |
| 258 | |
| 259 | # Control flow prefixes |
| 260 | IfPrefix <- KEYWORD_if LPAREN Expr RPAREN PtrPayload? |
| 261 | |
| 262 | WhilePrefix <- KEYWORD_while LPAREN Expr RPAREN PtrPayload? WhileContinueExpr? |
| 263 | |
| 264 | ForPrefix <- KEYWORD_for LPAREN ForArgumentsList RPAREN PtrListPayload |
| 265 | |
| 266 | # Payloads |
| 267 | Payload <- PIPE IDENTIFIER PIPE |
| 268 | |
| 269 | PtrPayload <- PIPE ASTERISK? IDENTIFIER PIPE |
| 270 | |
| 271 | PtrIndexPayload <- PIPE ASTERISK? IDENTIFIER (COMMA IDENTIFIER)? PIPE |
| 272 | |
| 273 | PtrListPayload <- PIPE ASTERISK? IDENTIFIER (COMMA ASTERISK? IDENTIFIER)* COMMA? PIPE |
| 274 | |
| 275 | # Switch specific |
| 276 | SwitchProng <- KEYWORD_inline? SwitchCase EQUALRARROW PtrIndexPayload? SingleAssignExpr |
| 277 | |
| 278 | SwitchCase |
| 279 | <- SwitchItem (COMMA SwitchItem)* COMMA? |
| 280 | / KEYWORD_else |
| 281 | |
| 282 | SwitchItem <- Expr (DOT3 Expr)? |
| 283 | |
| 284 | # For specific |
| 285 | ForArgumentsList <- ForItem (COMMA ForItem)* COMMA? |
| 286 | |
| 287 | ForItem <- Expr (DOT2 (Expr / !ExprPrefix) / !DOT2) |
| 288 | |
| 289 | # Operators |
| 290 | AssignOp |
| 291 | <- ASTERISKEQUAL |
| 292 | / ASTERISKPIPEEQUAL |
| 293 | / SLASHEQUAL |
| 294 | / PERCENTEQUAL |
| 295 | / PLUSEQUAL |
| 296 | / PLUSPIPEEQUAL |
| 297 | / MINUSEQUAL |
| 298 | / MINUSPIPEEQUAL |
| 299 | / LARROW2EQUAL |
| 300 | / LARROW2PIPEEQUAL |
| 301 | / RARROW2EQUAL |
| 302 | / AMPERSANDEQUAL |
| 303 | / CARETEQUAL |
| 304 | / PIPEEQUAL |
| 305 | / ASTERISKPERCENTEQUAL |
| 306 | / PLUSPERCENTEQUAL |
| 307 | / MINUSPERCENTEQUAL |
| 308 | / EQUAL |
| 309 | |
| 310 | OrOp <- pre_op_white KEYWORD_or post_op_white |
| 311 | / !pre_op_white KEYWORD_or !post_op_white |
| 312 | |
| 313 | AndOp <- pre_op_white KEYWORD_and post_op_white |
| 314 | / !pre_op_white KEYWORD_and !post_op_white |
| 315 | |
| 316 | CompareOp <- pre_op_white CompareOpTok post_op_white |
| 317 | / !pre_op_white CompareOpTok !post_op_white |
| 318 | CompareOpTok |
| 319 | <- EQUALEQUAL |
| 320 | / EXCLAMATIONMARKEQUAL |
| 321 | / LARROW |
| 322 | / RARROW |
| 323 | / LARROWEQUAL |
| 324 | / RARROWEQUAL |
| 325 | |
| 326 | BitwiseOp <- pre_op_white BitwiseOpTok post_op_white |
| 327 | / !pre_op_white BitwiseOpTok !post_op_white |
| 328 | / pre_op_white KEYWORD_catch post_op_white Payload? |
| 329 | / !pre_op_white KEYWORD_catch !post_op_white Payload? |
| 330 | BitwiseOpTok |
| 331 | <- AMPERSAND ![&] |
| 332 | / CARET |
| 333 | / PIPE |
| 334 | / KEYWORD_orelse |
| 335 | |
| 336 | BitShiftOp <- pre_op_white BitShiftOpTok post_op_white |
| 337 | / !pre_op_white BitShiftOpTok !post_op_white |
| 338 | BitShiftOpTok |
| 339 | <- LARROW2 |
| 340 | / RARROW2 |
| 341 | / LARROW2PIPE |
| 342 | |
| 343 | AdditionOp <- pre_op_white AdditionOpTok post_op_white |
| 344 | / !pre_op_white AdditionOpTok !post_op_white |
| 345 | AdditionOpTok |
| 346 | <- PLUS |
| 347 | / MINUS |
| 348 | / PLUS2 |
| 349 | / PLUSPERCENT |
| 350 | / MINUSPERCENT |
| 351 | / PLUSPIPE |
| 352 | / MINUSPIPE |
| 353 | |
| 354 | MultiplyOp <- pre_op_white MultiplyOpTok post_op_white |
| 355 | / !pre_op_white MultiplyOpTok !post_op_white |
| 356 | MultiplyOpTok |
| 357 | <- PIPE2 |
| 358 | / ASTERISK |
| 359 | / SLASH |
| 360 | / PERCENT |
| 361 | / ASTERISKPERCENT |
| 362 | / ASTERISKPIPE |
| 363 | |
| 364 | PrefixOp |
| 365 | <- EXCLAMATIONMARK |
| 366 | / MINUS |
| 367 | / TILDE |
| 368 | / MINUSPERCENT |
| 369 | / AMPERSAND |
| 370 | / KEYWORD_try |
| 371 | |
| 372 | PrefixTypeOp |
| 373 | <- QUESTIONMARK |
| 374 | / KEYWORD_anyframe MINUSRARROW |
| 375 | / (ManyPtrTypeStart / SliceTypeStart) PtrMods |
| 376 | / SinglePtrTypeStart SinglePtrMods |
| 377 | / ArrayTypeStart |
| 378 | |
| 379 | # Forbid more than one align or addrspace pointer modifier since these |
| 380 | # modifiers contain sub-expressions. This allows for a simpler AST data layout. |
| 381 | # Allow duplicate single-token modifiers (allowzero/const/volatile) in the grammar |
| 382 | # to avoid the combinatorial explosion of grammar rules necessary to forbid duplicates |
| 383 | # while permitting arbitrary order. A compile error for duplicates single-token modifiers |
| 384 | # is emitted during "AstGen" after parsing is complete. |
| 385 | PtrMods |
| 386 | <- PtrMod* !KEYWORD_addrspace ByteAlign? PtrMod* AddrSpace? PtrMod* |
| 387 | / PtrMod* !KEYWORD_align AddrSpace? PtrMod* ByteAlign? PtrMod* |
| 388 | |
| 389 | SinglePtrMods |
| 390 | <- PtrMod* !KEYWORD_addrspace BitAlign? PtrMod* AddrSpace? PtrMod* |
| 391 | / PtrMod* !KEYWORD_align AddrSpace? PtrMod* BitAlign? PtrMod* |
| 392 | |
| 393 | PtrMod |
| 394 | <- KEYWORD_allowzero |
| 395 | / KEYWORD_const |
| 396 | / KEYWORD_volatile |
| 397 | |
| 398 | PrefixTypeOpPrefix |
| 399 | <- QUESTIONMARK |
| 400 | / KEYWORD_anyframe MINUSRARROW |
| 401 | / LBRACKET |
| 402 | / ASTERISK |
| 403 | |
| 404 | SuffixOp |
| 405 | <- LBRACKET Expr (DOT2 (Expr / !ExprPrefix) (COLON Expr)?)? RBRACKET |
| 406 | / DOT IDENTIFIER |
| 407 | / DOTASTERISK |
| 408 | / DOT QUESTIONMARK |
| 409 | / FnCallArguments |
| 410 | |
| 411 | SuffixOpPrefix |
| 412 | <- LBRACKET |
| 413 | / DOT IDENTIFIER |
| 414 | / DOTASTERISK |
| 415 | / DOT QUESTIONMARK |
| 416 | / LPAREN |
| 417 | |
| 418 | FnCallArguments <- LPAREN ExprList RPAREN |
| 419 | |
| 420 | # Ptr specific |
| 421 | SliceTypeStart <- LBRACKET (COLON Expr)? RBRACKET |
| 422 | |
| 423 | SinglePtrTypeStart <- ASTERISK |
| 424 | |
| 425 | ManyPtrTypeStart <- LBRACKET ASTERISK (LETTERC / COLON Expr)? RBRACKET |
| 426 | |
| 427 | ArrayTypeStart <- LBRACKET !ASTERISK Expr (COLON Expr)? RBRACKET |
| 428 | |
| 429 | # ContainerType specific |
| 430 | ContainerTypeAuto <- ContainerTypeKind LBRACE ContainerMembers RBRACE |
| 431 | |
| 432 | ContainerTypeKind |
| 433 | <- KEYWORD_struct (LPAREN Expr RPAREN)? |
| 434 | / KEYWORD_opaque |
| 435 | / KEYWORD_enum (LPAREN Expr RPAREN)? |
| 436 | / KEYWORD_union (LPAREN (KEYWORD_enum (LPAREN Expr RPAREN)? / Expr) RPAREN)? |
| 437 | |
| 438 | # Alignment |
| 439 | ByteAlign <- KEYWORD_align LPAREN Expr RPAREN |
| 440 | |
| 441 | BitAlign <- KEYWORD_align LPAREN Expr (COLON Expr COLON Expr)? RPAREN |
| 442 | |
| 443 | # Lists |
| 444 | IdentifierList <- (doc_comment? IDENTIFIER (COMMA IdentifierList)?)? |
| 445 | |
| 446 | SwitchProngList <- (SwitchProng (COMMA SwitchProngList)?)? |
| 447 | |
| 448 | AsmOutputList <- (AsmOutputItem (COMMA AsmOutputList)?)? |
| 449 | |
| 450 | AsmInputList <- (AsmInputItem (COMMA AsmInputList)?)? |
| 451 | |
| 452 | ParamDeclList <- LPAREN ParamDeclListRest |
| 453 | ParamDeclListRest |
| 454 | <- RPAREN |
| 455 | / DOT3 COMMA? RPAREN |
| 456 | / ParamDecl (COMMA ParamDeclListRest / RPAREN) |
| 457 | |
| 458 | ExprList <- Expr (COMMA ExprList)? / !ExprPrefix |
| 459 | |
| 460 | ExprPrefix <- ASTERISK |
| 461 | |
| 462 | # *** Tokens *** |
| 463 | |
| 464 | # https://en.wikipedia.org/wiki/Byte_order_mark |
| 465 | byte_order_mark <- '\357\273\277' |
| 466 | |
| 467 | # Unfortunately, there is not a standard way to match the start of the file in PEG. |
| 468 | # This rule definition is compatible with the original peg(1) tool but is not |
| 469 | # portable. It is however trivial to implement an equivalent rule in hand written |
| 470 | # parsers and other PEG tooling should have similar mechanisms. |
| 471 | sof <- &{ (yy->__pos == 0) } byte_order_mark? |
| 472 | eof <- !. |
| 473 | |
| 474 | ox80_oxBF <- [\200-\277] |
| 475 | oxF4 <- '\364' |
| 476 | ox80_ox8F <- [\200-\217] |
| 477 | oxF1_oxF3 <- [\361-\363] |
| 478 | oxF0 <- '\360' |
| 479 | ox90_0xBF <- [\220-\277] |
| 480 | oxEE_oxEF <- [\356-\357] |
| 481 | oxED <- '\355' |
| 482 | ox80_ox9F <- [\200-\237] |
| 483 | oxE1_oxEC <- [\341-\354] |
| 484 | oxE0 <- '\340' |
| 485 | oxA0_oxBF <- [\240-\277] |
| 486 | oxC2_oxDF <- [\302-\337] |
| 487 | |
| 488 | # From https://lemire.me/blog/2018/05/09/how-quickly-can-you-check-that-a-string-is-valid-unicode-utf-8/ |
| 489 | # First Byte Second Byte Third Byte Fourth Byte |
| 490 | # [0x00,0x7F] |
| 491 | # [0xC2,0xDF] [0x80,0xBF] |
| 492 | # 0xE0 [0xA0,0xBF] [0x80,0xBF] |
| 493 | # [0xE1,0xEC] [0x80,0xBF] [0x80,0xBF] |
| 494 | # 0xED [0x80,0x9F] [0x80,0xBF] |
| 495 | # [0xEE,0xEF] [0x80,0xBF] [0x80,0xBF] |
| 496 | # 0xF0 [0x90,0xBF] [0x80,0xBF] [0x80,0xBF] |
| 497 | # [0xF1,0xF3] [0x80,0xBF] [0x80,0xBF] [0x80,0xBF] |
| 498 | # 0xF4 [0x80,0x8F] [0x80,0xBF] [0x80,0xBF] |
| 499 | |
| 500 | multibyte_utf8 <- |
| 501 | oxF4 ox80_ox8F ox80_oxBF ox80_oxBF |
| 502 | / oxF1_oxF3 ox80_oxBF ox80_oxBF ox80_oxBF |
| 503 | / oxF0 ox90_0xBF ox80_oxBF ox80_oxBF |
| 504 | / oxEE_oxEF ox80_oxBF ox80_oxBF |
| 505 | / oxED ox80_ox9F ox80_oxBF |
| 506 | / oxE1_oxEC ox80_oxBF ox80_oxBF |
| 507 | / oxE0 oxA0_oxBF ox80_oxBF |
| 508 | / oxC2_oxDF ox80_oxBF |
| 509 | |
| 510 | # Exclude \177 which is DEL |
| 511 | non_control_ascii <- [\040-\176] |
| 512 | non_control_utf8 <- [\040-\176\200-\377] |
| 513 | |
| 514 | # XXX: the Zig tokenizer doesn't yet perform UTF-8 validation |
| 515 | # When the tokenizer is fixed, switch back to these definitions |
| 516 | # that forbid invalid UTF-8: |
| 517 | # |
| 518 | # char_char |
| 519 | # <- multibyte_utf8 |
| 520 | # / "\\\\" |
| 521 | # / "\\'" |
| 522 | # / !['] non_control_ascii |
| 523 | # string_char |
| 524 | # <- multibyte_utf8 |
| 525 | # / '\\\\' |
| 526 | # / '\\"' |
| 527 | # / !["] non_control_ascii |
| 528 | |
| 529 | char_char |
| 530 | <- "\\\\" |
| 531 | / "\\'" |
| 532 | / !['] non_control_utf8 |
| 533 | |
| 534 | string_char |
| 535 | <- '\\\\' |
| 536 | / '\\"' |
| 537 | / !["] non_control_utf8 |
| 538 | |
| 539 | |
| 540 | container_doc_comment <- (skip '//!' non_control_utf8* newline)+ |
| 541 | # We forbid same-line doc comments to disambiguate the mapping to e.g. struct |
| 542 | # fields for documentation generation tooling. |
| 543 | doc_comment <- (sof / skip_require_newline) (skip '///' non_control_utf8* newline)+ |
| 544 | line_comment |
| 545 | <- '//' ![!/] non_control_utf8* newline |
| 546 | / '////' non_control_utf8* newline |
| 547 | line_string <- '\\\\' non_control_utf8* newline |
| 548 | |
| 549 | # This uses a positive lookahead rather than consuming input to make e.g. |
| 550 | # the newline terminating a multiline string literal or doc comment visible |
| 551 | # to the pre_op_white non-terminal. |
| 552 | newline <- &("\n" / "\r\n" / eof) |
| 553 | skip <- sof? ([ \n\t\r] / line_comment)* |
| 554 | skip_require_newline <- [ \t\r]* ([\n] / line_comment) skip |
| 555 | pre_op_white <- ([ \n\t\r] / line_comment)+ |
| 556 | post_op_white <- [ \n\t\r] skip |
| 557 | |
| 558 | CHAR_LITERAL <- skip ['] char_char* ['] |
| 559 | |
| 560 | digit <- [_0-9A-DF-OQ-Za-df-oq-z] |
| 561 | digit_int <- digit / [eEpP] |
| 562 | digit_float <- digit / [eEpP] [-+]? |
| 563 | NUMBERLITERAL |
| 564 | <- skip [0-9] digit_int* '.' digit_float+ |
| 565 | / skip [0-9] digit_float* |
| 566 | |
| 567 | |
| 568 | string <- ["] string_char* ["] |
| 569 | STRINGLITERALSINGLE <- skip string |
| 570 | STRINGLITERAL |
| 571 | <- skip string |
| 572 | / (skip line_string)+ |
| 573 | IDENTIFIER |
| 574 | <- skip !keyword [A-Za-z_] [A-Za-z0-9_]* |
| 575 | / skip '@' string |
| 576 | BUILTINIDENTIFIER <- skip '@'[A-Za-z_][A-Za-z0-9_]* |
| 577 | |
| 578 | |
| 579 | AMPERSAND <- skip '&' ![=] |
| 580 | AMPERSANDEQUAL <- skip '&=' |
| 581 | ASTERISK <- skip '*' ![%=|] |
| 582 | ASTERISKEQUAL <- skip '*=' |
| 583 | ASTERISKPERCENT <- skip '*%' ![=] |
| 584 | ASTERISKPERCENTEQUAL <- skip '*%=' |
| 585 | ASTERISKPIPE <- skip '*|' ![=] |
| 586 | ASTERISKPIPEEQUAL <- skip '*|=' |
| 587 | CARET <- skip '^' ![=] |
| 588 | CARETEQUAL <- skip '^=' |
| 589 | COLON <- skip ':' |
| 590 | COMMA <- skip ',' |
| 591 | DOT <- skip '.' ![*.] |
| 592 | DOT2 <- skip '..' ![.] |
| 593 | DOT3 <- skip '...' |
| 594 | DOTASTERISK <- skip '.*' |
| 595 | EQUAL <- skip '=' ![>=] |
| 596 | EQUALEQUAL <- skip '==' |
| 597 | EQUALRARROW <- skip '=>' |
| 598 | EXCLAMATIONMARK <- skip '!' ![=] |
| 599 | EXCLAMATIONMARKEQUAL <- skip '!=' |
| 600 | LARROW <- skip '<' ![<=] |
| 601 | LARROW2 <- skip '<<' ![=|] |
| 602 | LARROW2EQUAL <- skip '<<=' |
| 603 | LARROW2PIPE <- skip '<<|' ![=] |
| 604 | LARROW2PIPEEQUAL <- skip '<<|=' |
| 605 | LARROWEQUAL <- skip '<=' |
| 606 | LBRACE <- skip '{' |
| 607 | LBRACKET <- skip '[' |
| 608 | LPAREN <- skip '(' |
| 609 | MINUS <- skip '-' ![%=>|] |
| 610 | MINUSEQUAL <- skip '-=' |
| 611 | MINUSPERCENT <- skip '-%' ![=] |
| 612 | MINUSPERCENTEQUAL <- skip '-%=' |
| 613 | MINUSPIPE <- skip '-|' ![=] |
| 614 | MINUSPIPEEQUAL <- skip '-|=' |
| 615 | MINUSRARROW <- skip '->' |
| 616 | PERCENT <- skip '%' ![=] |
| 617 | PERCENTEQUAL <- skip '%=' |
| 618 | PIPE <- skip '|' ![|=] |
| 619 | PIPE2 <- skip '||' |
| 620 | PIPEEQUAL <- skip '|=' |
| 621 | PLUS <- skip '+' ![%+=|] |
| 622 | PLUS2 <- skip '++' |
| 623 | PLUSEQUAL <- skip '+=' |
| 624 | PLUSPERCENT <- skip '+%' ![=] |
| 625 | PLUSPERCENTEQUAL <- skip '+%=' |
| 626 | PLUSPIPE <- skip '+|' ![=] |
| 627 | PLUSPIPEEQUAL <- skip '+|=' |
| 628 | LETTERC <- skip 'c' |
| 629 | QUESTIONMARK <- skip '?' |
| 630 | RARROW <- skip '>' ![>=] |
| 631 | RARROW2 <- skip '>>' ![=] |
| 632 | RARROW2EQUAL <- skip '>>=' |
| 633 | RARROWEQUAL <- skip '>=' |
| 634 | RBRACE <- skip '}' |
| 635 | RBRACKET <- skip ']' |
| 636 | RPAREN <- skip ')' |
| 637 | SEMICOLON <- skip ';' |
| 638 | SLASH <- skip '/' ![=/] |
| 639 | SLASHEQUAL <- skip '/=' |
| 640 | TILDE <- skip '~' |
| 641 | |
| 642 | end_of_word <- ![a-zA-Z0-9_] |
| 643 | KEYWORD_addrspace <- skip 'addrspace' end_of_word |
| 644 | KEYWORD_align <- skip 'align' end_of_word |
| 645 | KEYWORD_allowzero <- skip 'allowzero' end_of_word |
| 646 | KEYWORD_and <- skip 'and' end_of_word |
| 647 | KEYWORD_anyframe <- skip 'anyframe' end_of_word |
| 648 | KEYWORD_anytype <- skip 'anytype' end_of_word |
| 649 | KEYWORD_asm <- skip 'asm' end_of_word |
| 650 | KEYWORD_break <- skip 'break' end_of_word |
| 651 | KEYWORD_callconv <- skip 'callconv' end_of_word |
| 652 | KEYWORD_catch <- skip 'catch' end_of_word |
| 653 | KEYWORD_comptime <- skip 'comptime' end_of_word |
| 654 | KEYWORD_const <- skip 'const' end_of_word |
| 655 | KEYWORD_continue <- skip 'continue' end_of_word |
| 656 | KEYWORD_defer <- skip 'defer' end_of_word |
| 657 | KEYWORD_else <- skip 'else' end_of_word |
| 658 | KEYWORD_enum <- skip 'enum' end_of_word |
| 659 | KEYWORD_errdefer <- skip 'errdefer' end_of_word |
| 660 | KEYWORD_error <- skip 'error' end_of_word |
| 661 | KEYWORD_export <- skip 'export' end_of_word |
| 662 | KEYWORD_extern <- skip 'extern' end_of_word |
| 663 | KEYWORD_fn <- skip 'fn' end_of_word |
| 664 | KEYWORD_for <- skip 'for' end_of_word |
| 665 | KEYWORD_if <- skip 'if' end_of_word |
| 666 | KEYWORD_inline <- skip 'inline' end_of_word |
| 667 | KEYWORD_noalias <- skip 'noalias' end_of_word |
| 668 | KEYWORD_nosuspend <- skip 'nosuspend' end_of_word |
| 669 | KEYWORD_noinline <- skip 'noinline' end_of_word |
| 670 | KEYWORD_opaque <- skip 'opaque' end_of_word |
| 671 | KEYWORD_or <- skip 'or' end_of_word |
| 672 | KEYWORD_orelse <- skip 'orelse' end_of_word |
| 673 | KEYWORD_packed <- skip 'packed' end_of_word |
| 674 | KEYWORD_pub <- skip 'pub' end_of_word |
| 675 | KEYWORD_resume <- skip 'resume' end_of_word |
| 676 | KEYWORD_return <- skip 'return' end_of_word |
| 677 | KEYWORD_linksection <- skip 'linksection' end_of_word |
| 678 | KEYWORD_struct <- skip 'struct' end_of_word |
| 679 | KEYWORD_suspend <- skip 'suspend' end_of_word |
| 680 | KEYWORD_switch <- skip 'switch' end_of_word |
| 681 | KEYWORD_test <- skip 'test' end_of_word |
| 682 | KEYWORD_threadlocal <- skip 'threadlocal' end_of_word |
| 683 | KEYWORD_try <- skip 'try' end_of_word |
| 684 | KEYWORD_union <- skip 'union' end_of_word |
| 685 | KEYWORD_unreachable <- skip 'unreachable' end_of_word |
| 686 | KEYWORD_var <- skip 'var' end_of_word |
| 687 | KEYWORD_volatile <- skip 'volatile' end_of_word |
| 688 | KEYWORD_while <- skip 'while' end_of_word |
| 689 | |
| 690 | keyword <- KEYWORD_addrspace / KEYWORD_align / KEYWORD_allowzero / KEYWORD_and |
| 691 | / KEYWORD_anyframe / KEYWORD_anytype / KEYWORD_asm |
| 692 | / KEYWORD_break / KEYWORD_callconv / KEYWORD_catch |
| 693 | / KEYWORD_comptime / KEYWORD_const / KEYWORD_continue / KEYWORD_defer |
| 694 | / KEYWORD_else / KEYWORD_enum / KEYWORD_errdefer / KEYWORD_error / KEYWORD_export |
| 695 | / KEYWORD_extern / KEYWORD_fn / KEYWORD_for / KEYWORD_if |
| 696 | / KEYWORD_inline / KEYWORD_noalias / KEYWORD_nosuspend / KEYWORD_noinline |
| 697 | / KEYWORD_opaque / KEYWORD_or / KEYWORD_orelse / KEYWORD_packed |
| 698 | / KEYWORD_pub / KEYWORD_resume / KEYWORD_return / KEYWORD_linksection |
| 699 | / KEYWORD_struct / KEYWORD_suspend / KEYWORD_switch / KEYWORD_test |
| 700 | / KEYWORD_threadlocal / KEYWORD_try / KEYWORD_union / KEYWORD_unreachable |
| 701 | / KEYWORD_var / KEYWORD_volatile / KEYWORD_while |