blob c118700a (86765B) - Raw
1 #include "common.h" 2 3 #include <assert.h> 4 #include <stdio.h> 5 #include <stdlib.h> 6 #include <string.h> 7 8 #include "ast.h" 9 #include "parser.h" 10 11 const AstNodeIndex null_node = 0; 12 const AstTokenIndex null_token = ~(AstTokenIndex)(0); 13 14 // OPT encodes a node index as OptionalIndex: 0 → ~0 (none) 15 #define OPT(x) ((x) == 0 ? ~(AstNodeIndex)0 : (x)) 16 17 typedef struct { 18 uint32_t len; 19 AstNodeIndex lhs; 20 AstNodeIndex rhs; 21 bool trailing; 22 } Members; 23 24 static AstNodeIndex parsePrefixExpr(Parser*); 25 static AstNodeIndex parseTypeExpr(Parser*); 26 static AstNodeIndex parseBlock(Parser* p); 27 static AstNodeIndex parseLabeledStatement(Parser*); 28 static AstNodeIndex parseExpr(Parser*); 29 static AstNodeIndex expectExpr(Parser*); 30 static AstNodeIndex expectSemicolon(Parser*); 31 static AstTokenIndex expectToken(Parser*, TokenizerTag); 32 static AstNodeIndex parseFnProto(Parser*); 33 static Members parseContainerMembers(Parser*); 34 static AstNodeIndex parseInitList(Parser*, AstNodeIndex, AstTokenIndex); 35 static AstNodeIndex expectBlockExprStatement(Parser*); 36 37 typedef struct { 38 enum { FIELD_STATE_NONE, FIELD_STATE_SEEN, FIELD_STATE_END } tag; 39 union { 40 uint32_t end; 41 } payload; 42 } FieldState; 43 44 typedef struct { 45 enum { SMALL_SPAN_ZERO_OR_ONE, SMALL_SPAN_MULTI } tag; 46 union { 47 AstNodeIndex zero_or_one; 48 AstSubRange multi; 49 } payload; 50 } SmallSpan; 51 52 typedef struct { 53 AstNodeIndexSlice* scratch; 54 uint32_t old_len; 55 } CleanupScratch; 56 57 static CleanupScratch initCleanupScratch(Parser* p) { 58 return (CleanupScratch) { 59 .scratch = &p->scratch, 60 .old_len = p->scratch.len, 61 }; 62 } 63 64 static void cleanupScratch(CleanupScratch* c) { c->scratch->len = c->old_len; } 65 66 static AstSubRange listToSpan( 67 Parser* p, const AstNodeIndex* list, uint32_t count) { 68 SLICE_ENSURE_CAPACITY(AstNodeIndex, &p->extra_data, count); 69 memcpy(p->extra_data.arr + p->extra_data.len, list, 70 count * sizeof(AstNodeIndex)); 71 p->extra_data.len += count; 72 return (AstSubRange) { 73 .start = p->extra_data.len - count, 74 .end = p->extra_data.len, 75 }; 76 } 77 78 static AstSubRange membersToSpan(const Members self, Parser* p) { 79 if (self.len <= 2) { 80 const AstNodeIndex nodes[] = { self.lhs, self.rhs }; 81 return listToSpan(p, nodes, self.len); 82 } else { 83 return (AstSubRange) { .start = self.lhs, .end = self.rhs }; 84 } 85 } 86 87 static AstTokenIndex nextToken(Parser* p) { return p->tok_i++; } 88 89 static AstTokenIndex eatToken(Parser* p, TokenizerTag tag) { 90 if (p->token_tags[p->tok_i] == tag) { 91 return nextToken(p); 92 } else { 93 return null_token; 94 } 95 } 96 97 static AstTokenIndex assertToken(Parser* p, TokenizerTag tag) { 98 const AstTokenIndex token = nextToken(p); 99 assert(p->token_tags[token] == tag); 100 return token; 101 } 102 103 static void eatDocComments(Parser* p) { 104 while (eatToken(p, TOKEN_DOC_COMMENT) != null_token) { } 105 } 106 107 static AstNodeIndex setNode(Parser* p, uint32_t i, AstNodeItem item) { 108 p->nodes.tags[i] = item.tag; 109 p->nodes.main_tokens[i] = item.main_token; 110 p->nodes.datas[i] = item.data; 111 return i; 112 } 113 114 static void astNodeListEnsureCapacity(AstNodeList* list, uint32_t additional) { 115 const uint32_t new_len = list->len + additional; 116 if (new_len <= list->cap) { 117 return; 118 } 119 120 const uint32_t new_cap = new_len > list->cap * 2 ? new_len : list->cap * 2; 121 list->tags = realloc(list->tags, new_cap * sizeof(AstNodeTag)); 122 list->main_tokens 123 = realloc(list->main_tokens, new_cap * sizeof(AstTokenIndex)); 124 list->datas = realloc(list->datas, new_cap * sizeof(AstData)); 125 if (!list->tags || !list->main_tokens || !list->datas) 126 exit(1); 127 list->cap = new_cap; 128 } 129 130 static AstNodeIndex addNode(AstNodeList* nodes, AstNodeItem item) { 131 astNodeListEnsureCapacity(nodes, 1); 132 nodes->tags[nodes->len] = item.tag; 133 nodes->main_tokens[nodes->len] = item.main_token; 134 nodes->datas[nodes->len] = item.data; 135 return nodes->len++; 136 } 137 138 static AstNodeIndex addExtra( 139 Parser* p, const AstNodeIndex* extra, uint32_t count) { 140 const AstNodeIndex result = p->extra_data.len; 141 SLICE_ENSURE_CAPACITY(AstNodeIndex, &p->extra_data, count); 142 memcpy(p->extra_data.arr + p->extra_data.len, extra, 143 count * sizeof(AstNodeIndex)); 144 p->extra_data.len += count; 145 return result; 146 } 147 148 static AstNodeIndex parseByteAlign(Parser* p) { 149 if (eatToken(p, TOKEN_KEYWORD_ALIGN) == null_token) 150 return null_node; 151 expectToken(p, TOKEN_L_PAREN); 152 const AstNodeIndex expr = expectExpr(p); 153 expectToken(p, TOKEN_R_PAREN); 154 return expr; 155 } 156 157 static AstNodeIndex parseAddrSpace(Parser* p) { 158 if (eatToken(p, TOKEN_KEYWORD_ADDRSPACE) == null_token) 159 return null_node; 160 expectToken(p, TOKEN_L_PAREN); 161 const AstNodeIndex expr = expectExpr(p); 162 expectToken(p, TOKEN_R_PAREN); 163 return expr; 164 } 165 166 static AstNodeIndex parseLinkSection(Parser* p) { 167 if (eatToken(p, TOKEN_KEYWORD_LINKSECTION) == null_token) 168 return null_node; 169 expectToken(p, TOKEN_L_PAREN); 170 const AstNodeIndex expr = expectExpr(p); 171 expectToken(p, TOKEN_R_PAREN); 172 return expr; 173 } 174 175 static AstNodeIndex parseCallconv(Parser* p) { 176 if (eatToken(p, TOKEN_KEYWORD_CALLCONV) == null_token) 177 return null_node; 178 expectToken(p, TOKEN_L_PAREN); 179 const AstNodeIndex expr = expectExpr(p); 180 expectToken(p, TOKEN_R_PAREN); 181 return expr; 182 } 183 184 typedef struct { 185 AstNodeIndex align_expr, value_expr; 186 } NodeContainerField; 187 188 static AstNodeIndex expectContainerField(Parser* p) { 189 eatToken(p, TOKEN_KEYWORD_COMPTIME); 190 const AstTokenIndex main_token = p->tok_i; 191 if (p->token_tags[p->tok_i] == TOKEN_IDENTIFIER 192 && p->token_tags[p->tok_i + 1] == TOKEN_COLON) 193 p->tok_i += 2; 194 195 const AstNodeIndex type_expr = parseTypeExpr(p); 196 const AstNodeIndex align_expr = parseByteAlign(p); 197 const AstNodeIndex value_expr 198 = eatToken(p, TOKEN_EQUAL) != null_token ? expectExpr(p) : 0; 199 200 if (align_expr == 0) { 201 return addNode( 202 &p->nodes, 203 (AstNodeItem) { 204 .tag = AST_NODE_CONTAINER_FIELD_INIT, 205 .main_token = main_token, 206 .data = { 207 .lhs = type_expr, 208 .rhs = value_expr, 209 }, 210 }); 211 } else if (value_expr == 0) { 212 return addNode( 213 &p->nodes, 214 (AstNodeItem) { 215 .tag = AST_NODE_CONTAINER_FIELD_ALIGN, 216 .main_token = main_token, 217 .data = { 218 .lhs = type_expr, 219 .rhs = align_expr, 220 }, 221 }); 222 } else { 223 return addNode( 224 &p->nodes, 225 (AstNodeItem) { 226 .tag = AST_NODE_CONTAINER_FIELD, 227 .main_token = main_token, 228 .data = { 229 .lhs = type_expr, 230 .rhs = addExtra(p, (AstNodeIndex[]) { align_expr, value_expr }, 2), 231 }, 232 }); 233 } 234 } 235 236 static AstNodeIndex parseBuiltinCall(Parser* p) { 237 const AstTokenIndex builtin_token = assertToken(p, TOKEN_BUILTIN); 238 assertToken(p, TOKEN_L_PAREN); 239 240 CleanupScratch scratch_top __attribute__((__cleanup__(cleanupScratch))) 241 = initCleanupScratch(p); 242 243 while (true) { 244 if (eatToken(p, TOKEN_R_PAREN) != null_token) 245 break; 246 247 const AstNodeIndex param = expectExpr(p); 248 SLICE_APPEND(AstNodeIndex, &p->scratch, param); 249 switch (p->token_tags[p->tok_i]) { 250 case TOKEN_COMMA: 251 p->tok_i++; 252 break; 253 case TOKEN_R_PAREN: 254 p->tok_i++; 255 goto end_loop; 256 default: 257 fprintf(stderr, "expected comma after arg\n"); 258 exit(1); 259 } 260 } 261 end_loop:; 262 263 const bool comma = (p->token_tags[p->tok_i - 2] == TOKEN_COMMA); 264 const uint32_t params_len = p->scratch.len - scratch_top.old_len; 265 switch (params_len) { 266 case 0: 267 return addNode(&p->nodes, 268 (AstNodeItem) { 269 .tag = AST_NODE_BUILTIN_CALL_TWO, 270 .main_token = builtin_token, 271 .data = { 272 .lhs = 0, 273 .rhs = 0, 274 }, 275 }); 276 case 1: 277 return addNode(&p->nodes, 278 (AstNodeItem) { 279 .tag = comma ? 280 AST_NODE_BUILTIN_CALL_TWO_COMMA : 281 AST_NODE_BUILTIN_CALL_TWO, 282 .main_token = builtin_token, 283 .data = { 284 .lhs = p->scratch.arr[scratch_top.old_len], 285 .rhs = 0, 286 }, 287 }); 288 case 2: 289 return addNode(&p->nodes, 290 (AstNodeItem) { 291 .tag = comma ? 292 AST_NODE_BUILTIN_CALL_TWO_COMMA : 293 AST_NODE_BUILTIN_CALL_TWO, 294 .main_token = builtin_token, 295 .data = { 296 .lhs = p->scratch.arr[scratch_top.old_len], 297 .rhs = p->scratch.arr[scratch_top.old_len+1], 298 }, 299 }); 300 default:; 301 const AstSubRange span 302 = listToSpan(p, &p->scratch.arr[scratch_top.old_len], params_len); 303 return addNode( 304 &p->nodes, 305 (AstNodeItem) { 306 .tag = comma ? 307 AST_NODE_BUILTIN_CALL_COMMA : 308 AST_NODE_BUILTIN_CALL, 309 .main_token = builtin_token, 310 .data = { 311 .lhs = span.start, 312 .rhs = span.end, 313 }, 314 }); 315 } 316 } 317 318 static AstNodeIndex parseContainerDeclAuto(Parser* p) { 319 const AstTokenIndex main_token = nextToken(p); 320 AstNodeIndex arg_expr = null_node; 321 switch (p->token_tags[main_token]) { 322 case TOKEN_KEYWORD_OPAQUE: 323 break; 324 case TOKEN_KEYWORD_STRUCT: 325 case TOKEN_KEYWORD_ENUM: 326 if (eatToken(p, TOKEN_L_PAREN) != null_token) { 327 arg_expr = expectExpr(p); 328 expectToken(p, TOKEN_R_PAREN); 329 } 330 break; 331 case TOKEN_KEYWORD_UNION: 332 if (eatToken(p, TOKEN_L_PAREN) != null_token) { 333 if (eatToken(p, TOKEN_KEYWORD_ENUM) != null_token) { 334 if (eatToken(p, TOKEN_L_PAREN) != null_token) { 335 const AstNodeIndex enum_tag_expr = expectExpr(p); 336 expectToken(p, TOKEN_R_PAREN); 337 expectToken(p, TOKEN_R_PAREN); 338 expectToken(p, TOKEN_L_BRACE); 339 const Members members = parseContainerMembers(p); 340 const AstSubRange members_span = membersToSpan(members, p); 341 expectToken(p, TOKEN_R_BRACE); 342 return addNode( 343 &p->nodes, 344 (AstNodeItem) { 345 .tag = members.trailing 346 ? AST_NODE_TAGGED_UNION_ENUM_TAG_TRAILING 347 : AST_NODE_TAGGED_UNION_ENUM_TAG, 348 .main_token = main_token, 349 .data = { 350 .lhs = enum_tag_expr, 351 .rhs = addExtra(p, 352 (AstNodeIndex[]) { 353 members_span.start, 354 members_span.end }, 355 2), 356 }, 357 }); 358 } 359 expectToken(p, TOKEN_R_PAREN); 360 expectToken(p, TOKEN_L_BRACE); 361 const Members members = parseContainerMembers(p); 362 expectToken(p, TOKEN_R_BRACE); 363 if (members.len <= 2) { 364 return addNode(&p->nodes, 365 (AstNodeItem) { 366 .tag = members.trailing 367 ? AST_NODE_TAGGED_UNION_TWO_TRAILING 368 : AST_NODE_TAGGED_UNION_TWO, 369 .main_token = main_token, 370 .data = { .lhs = members.lhs, .rhs = members.rhs }, 371 }); 372 } 373 const AstSubRange span = membersToSpan(members, p); 374 return addNode(&p->nodes, 375 (AstNodeItem) { 376 .tag = members.trailing 377 ? AST_NODE_TAGGED_UNION_TRAILING 378 : AST_NODE_TAGGED_UNION, 379 .main_token = main_token, 380 .data = { .lhs = span.start, .rhs = span.end }, 381 }); 382 } 383 arg_expr = expectExpr(p); 384 expectToken(p, TOKEN_R_PAREN); 385 } 386 break; 387 default: 388 fprintf(stderr, "parseContainerDeclAuto: unexpected token\n"); 389 exit(1); 390 } 391 392 expectToken(p, TOKEN_L_BRACE); 393 const Members members = parseContainerMembers(p); 394 expectToken(p, TOKEN_R_BRACE); 395 396 if (arg_expr == null_node) { 397 if (members.len <= 2) { 398 return addNode(&p->nodes, 399 (AstNodeItem) { 400 .tag = members.trailing 401 ? AST_NODE_CONTAINER_DECL_TWO_TRAILING 402 : AST_NODE_CONTAINER_DECL_TWO, 403 .main_token = main_token, 404 .data = { .lhs = members.lhs, .rhs = members.rhs }, 405 }); 406 } 407 const AstSubRange span = membersToSpan(members, p); 408 return addNode(&p->nodes, 409 (AstNodeItem) { 410 .tag = members.trailing ? AST_NODE_CONTAINER_DECL_TRAILING 411 : AST_NODE_CONTAINER_DECL, 412 .main_token = main_token, 413 .data = { .lhs = span.start, .rhs = span.end }, 414 }); 415 } 416 417 const AstSubRange span = membersToSpan(members, p); 418 return addNode( 419 &p->nodes, 420 (AstNodeItem) { 421 .tag = members.trailing 422 ? AST_NODE_CONTAINER_DECL_ARG_TRAILING 423 : AST_NODE_CONTAINER_DECL_ARG, 424 .main_token = main_token, 425 .data = { 426 .lhs = arg_expr, 427 .rhs = addExtra(p, 428 (AstNodeIndex[]) { span.start, span.end }, 2), 429 }, 430 }); 431 } 432 433 static AstNodeIndex parsePrimaryTypeExpr(Parser* p) { 434 const TokenizerTag tok = p->token_tags[p->tok_i]; 435 switch (tok) { 436 case TOKEN_CHAR_LITERAL: 437 return addNode(&p->nodes, 438 (AstNodeItem) { 439 .tag = AST_NODE_CHAR_LITERAL, 440 .main_token = nextToken(p), 441 .data = {}, 442 }); 443 case TOKEN_NUMBER_LITERAL: 444 return addNode(&p->nodes, 445 (AstNodeItem) { 446 .tag = AST_NODE_NUMBER_LITERAL, 447 .main_token = nextToken(p), 448 .data = {}, 449 }); 450 case TOKEN_KEYWORD_UNREACHABLE: 451 return addNode(&p->nodes, 452 (AstNodeItem) { 453 .tag = AST_NODE_UNREACHABLE_LITERAL, 454 .main_token = nextToken(p), 455 .data = {}, 456 }); 457 case TOKEN_KEYWORD_ANYFRAME: 458 fprintf(stderr, "parsePrimaryTypeExpr does not support %s\n", 459 tokenizerGetTagString(tok)); 460 exit(1); 461 case TOKEN_STRING_LITERAL: 462 return addNode(&p->nodes, 463 (AstNodeItem) { 464 .tag = AST_NODE_STRING_LITERAL, 465 .main_token = nextToken(p), 466 .data = {}, 467 }); 468 case TOKEN_BUILTIN: 469 return parseBuiltinCall(p); 470 case TOKEN_KEYWORD_FN: 471 return parseFnProto(p); 472 case TOKEN_KEYWORD_IF: 473 case TOKEN_KEYWORD_SWITCH: 474 fprintf(stderr, "parsePrimaryTypeExpr does not support %s\n", 475 tokenizerGetTagString(tok)); 476 exit(1); 477 case TOKEN_KEYWORD_EXTERN: 478 case TOKEN_KEYWORD_PACKED: 479 // extern/packed can precede struct/union/enum 480 switch (p->token_tags[p->tok_i + 1]) { 481 case TOKEN_KEYWORD_STRUCT: 482 case TOKEN_KEYWORD_UNION: 483 case TOKEN_KEYWORD_ENUM: 484 p->tok_i++; // consume extern/packed 485 return parseContainerDeclAuto(p); 486 default: 487 fprintf(stderr, "parsePrimaryTypeExpr does not support %s\n", 488 tokenizerGetTagString(tok)); 489 exit(1); 490 } 491 case TOKEN_KEYWORD_STRUCT: 492 case TOKEN_KEYWORD_OPAQUE: 493 case TOKEN_KEYWORD_ENUM: 494 case TOKEN_KEYWORD_UNION: 495 return parseContainerDeclAuto(p); 496 case TOKEN_KEYWORD_COMPTIME: 497 return addNode(&p->nodes, 498 (AstNodeItem) { 499 .tag = AST_NODE_COMPTIME, 500 .main_token = nextToken(p), 501 .data = { .lhs = parseTypeExpr(p), .rhs = 0 }, 502 }); 503 case TOKEN_MULTILINE_STRING_LITERAL_LINE: { 504 const AstTokenIndex first = nextToken(p); 505 AstTokenIndex last = first; 506 while (p->token_tags[p->tok_i] == TOKEN_MULTILINE_STRING_LITERAL_LINE) 507 last = nextToken(p); 508 return addNode(&p->nodes, 509 (AstNodeItem) { 510 .tag = AST_NODE_MULTILINE_STRING_LITERAL, 511 .main_token = first, 512 .data = { .lhs = first, .rhs = last }, 513 }); 514 } 515 case TOKEN_IDENTIFIER: 516 return addNode(&p->nodes, 517 (AstNodeItem) { 518 .tag = AST_NODE_IDENTIFIER, 519 .main_token = nextToken(p), 520 .data = {}, 521 }); 522 case TOKEN_KEYWORD_INLINE: 523 case TOKEN_KEYWORD_FOR: 524 case TOKEN_KEYWORD_WHILE: 525 case TOKEN_PERIOD: 526 switch (p->token_tags[p->tok_i + 1]) { 527 case TOKEN_IDENTIFIER: { 528 const AstTokenIndex dot = nextToken(p); 529 return addNode(&p->nodes, 530 (AstNodeItem) { 531 .tag = AST_NODE_ENUM_LITERAL, 532 .main_token = nextToken(p), 533 .data = { .lhs = dot, .rhs = 0 }, 534 }); 535 } 536 case TOKEN_L_BRACE: { 537 // Anonymous struct/array init: .{ ... } 538 const AstTokenIndex lbrace = p->tok_i + 1; 539 p->tok_i = lbrace + 1; 540 return parseInitList(p, null_node, lbrace); 541 } 542 default: 543 fprintf(stderr, 544 "parsePrimaryTypeExpr: unsupported period suffix %s\n", 545 tokenizerGetTagString(p->token_tags[p->tok_i + 1])); 546 exit(1); 547 } 548 return 0; // tcc 549 case TOKEN_KEYWORD_ERROR: 550 fprintf(stderr, "parsePrimaryTypeExpr does not support %s\n", 551 tokenizerGetTagString(tok)); 552 exit(1); 553 case TOKEN_L_PAREN: { 554 const AstTokenIndex lparen = nextToken(p); 555 const AstNodeIndex inner = expectExpr(p); 556 const AstTokenIndex rparen = expectToken(p, TOKEN_R_PAREN); 557 return addNode(&p->nodes, 558 (AstNodeItem) { 559 .tag = AST_NODE_GROUPED_EXPRESSION, 560 .main_token = lparen, 561 .data = { .lhs = inner, .rhs = rparen }, 562 }); 563 } 564 default: 565 return null_node; 566 } 567 } 568 569 static AstNodeIndex parseSuffixOp(Parser* p, AstNodeIndex lhs) { 570 const TokenizerTag tok = p->token_tags[p->tok_i]; 571 switch (tok) { 572 case TOKEN_L_BRACKET: { 573 const AstTokenIndex lbracket = nextToken(p); 574 const AstNodeIndex index_expr = expectExpr(p); 575 switch (p->token_tags[p->tok_i]) { 576 case TOKEN_R_BRACKET: 577 p->tok_i++; 578 return addNode(&p->nodes, 579 (AstNodeItem) { 580 .tag = AST_NODE_ARRAY_ACCESS, 581 .main_token = lbracket, 582 .data = { .lhs = lhs, .rhs = index_expr }, 583 }); 584 case TOKEN_ELLIPSIS2: { 585 p->tok_i++; // consume .. 586 const AstNodeIndex end_expr = parseExpr(p); 587 if (eatToken(p, TOKEN_COLON) != null_token) { 588 const AstNodeIndex sentinel = expectExpr(p); 589 expectToken(p, TOKEN_R_BRACKET); 590 // end_expr 0 means "no end" — encode as ~0 for 591 // OptionalIndex.none 592 const AstNodeIndex opt_end 593 = end_expr == 0 ? ~(AstNodeIndex)0 : end_expr; 594 return addNode(&p->nodes, 595 (AstNodeItem) { 596 .tag = AST_NODE_SLICE_SENTINEL, 597 .main_token = lbracket, 598 .data = { 599 .lhs = lhs, 600 .rhs = addExtra(p, 601 (AstNodeIndex[]) { 602 index_expr, opt_end, sentinel }, 603 3), 604 }, 605 }); 606 } 607 expectToken(p, TOKEN_R_BRACKET); 608 if (end_expr == 0) { 609 return addNode(&p->nodes, 610 (AstNodeItem) { 611 .tag = AST_NODE_SLICE_OPEN, 612 .main_token = lbracket, 613 .data = { .lhs = lhs, .rhs = index_expr }, 614 }); 615 } 616 return addNode(&p->nodes, 617 (AstNodeItem) { 618 .tag = AST_NODE_SLICE, 619 .main_token = lbracket, 620 .data = { 621 .lhs = lhs, 622 .rhs = addExtra(p, 623 (AstNodeIndex[]) { index_expr, end_expr }, 2), 624 }, 625 }); 626 } 627 default: 628 fprintf( 629 stderr, "parseSuffixOp: expected ] or .. after index expr\n"); 630 exit(1); 631 } 632 return 0; // tcc 633 } 634 case TOKEN_PERIOD_ASTERISK: 635 case TOKEN_INVALID_PERIODASTERISKS: 636 fprintf(stderr, "parseSuffixOp does not support %s\n", 637 tokenizerGetTagString(tok)); 638 exit(1); 639 case TOKEN_PERIOD: 640 if (p->token_tags[p->tok_i + 1] == TOKEN_IDENTIFIER) { 641 const AstTokenIndex dot = nextToken(p); 642 return addNode(&p->nodes, 643 (AstNodeItem) { 644 .tag = AST_NODE_FIELD_ACCESS, 645 .main_token = dot, 646 .data = { .lhs = lhs, .rhs = nextToken(p) }, 647 }); 648 } 649 if (p->token_tags[p->tok_i + 1] == TOKEN_ASTERISK) { 650 const AstTokenIndex dot = nextToken(p); 651 nextToken(p); // consume the * 652 return addNode(&p->nodes, 653 (AstNodeItem) { 654 .tag = AST_NODE_DEREF, 655 .main_token = dot, 656 .data = { .lhs = lhs, .rhs = 0 }, 657 }); 658 } 659 if (p->token_tags[p->tok_i + 1] == TOKEN_QUESTION_MARK) { 660 const AstTokenIndex dot = nextToken(p); 661 return addNode(&p->nodes, 662 (AstNodeItem) { 663 .tag = AST_NODE_UNWRAP_OPTIONAL, 664 .main_token = dot, 665 .data = { .lhs = lhs, .rhs = nextToken(p) }, 666 }); 667 } 668 fprintf(stderr, "parseSuffixOp: unsupported period suffix\n"); 669 exit(1); 670 return 0; // tcc 671 default: 672 return null_node; 673 } 674 } 675 676 static AstNodeIndex parseSuffixExpr(Parser* p) { 677 if (eatToken(p, TOKEN_KEYWORD_ASYNC) != null_token) { 678 fprintf(stderr, "async not supported\n"); 679 exit(1); 680 } 681 682 AstNodeIndex res = parsePrimaryTypeExpr(p); 683 if (res == 0) 684 return res; 685 686 while (true) { 687 const AstNodeIndex suffix_op = parseSuffixOp(p, res); 688 if (suffix_op != 0) { 689 res = suffix_op; 690 continue; 691 } 692 const AstTokenIndex lparen = eatToken(p, TOKEN_L_PAREN); 693 if (lparen == null_token) 694 return res; 695 696 CleanupScratch scratch_top __attribute__((__cleanup__(cleanupScratch))) 697 = initCleanupScratch(p); 698 while (true) { 699 if (eatToken(p, TOKEN_R_PAREN) != null_token) 700 break; 701 const AstNodeIndex arg = expectExpr(p); 702 SLICE_APPEND(AstNodeIndex, &p->scratch, arg); 703 if (p->token_tags[p->tok_i] == TOKEN_COMMA) { 704 p->tok_i++; 705 continue; 706 } 707 expectToken(p, TOKEN_R_PAREN); 708 break; 709 } 710 711 const bool comma = p->token_tags[p->tok_i - 2] == TOKEN_COMMA; 712 const uint32_t params_len = p->scratch.len - scratch_top.old_len; 713 switch (params_len) { 714 case 0: 715 res = addNode( 716 &p->nodes, 717 (AstNodeItem) { 718 .tag = comma ? AST_NODE_CALL_ONE_COMMA : AST_NODE_CALL_ONE, 719 .main_token = lparen, 720 .data = { 721 .lhs = res, 722 .rhs = 0, 723 }, 724 }); 725 break; 726 case 1: 727 res = addNode( 728 &p->nodes, 729 (AstNodeItem) { 730 .tag = comma ? AST_NODE_CALL_ONE_COMMA : AST_NODE_CALL_ONE, 731 .main_token = lparen, 732 .data = { 733 .lhs = res, 734 .rhs = p->scratch.arr[scratch_top.old_len], 735 }, 736 }); 737 break; 738 default:; 739 const AstSubRange span = listToSpan( 740 p, &p->scratch.arr[scratch_top.old_len], params_len); 741 res = addNode( 742 &p->nodes, 743 (AstNodeItem) { 744 .tag = comma ? AST_NODE_CALL_COMMA : AST_NODE_CALL, 745 .main_token = lparen, 746 .data = { 747 .lhs = res, 748 .rhs = addExtra(p, (AstNodeIndex[]) { 749 span.start, 750 span.end, 751 }, 2), 752 }, 753 }); 754 break; 755 } 756 } 757 } 758 759 static AstTokenIndex expectToken(Parser* p, TokenizerTag tag) { 760 if (p->token_tags[p->tok_i] == tag) { 761 return nextToken(p); 762 } else { 763 fprintf(stderr, "expected token %s, got %s\n", 764 tokenizerGetTagString(tag), 765 tokenizerGetTagString(p->token_tags[p->tok_i])); 766 exit(1); 767 } 768 return 0; // tcc 769 } 770 771 static AstNodeIndex expectSemicolon(Parser* p) { 772 return expectToken(p, TOKEN_SEMICOLON); 773 } 774 775 static AstNodeIndex parseErrorUnionExpr(Parser* p) { 776 const AstNodeIndex suffix_expr = parseSuffixExpr(p); 777 if (suffix_expr == 0) 778 return null_node; 779 780 const AstNodeIndex bang = eatToken(p, TOKEN_BANG); 781 if (bang == null_token) 782 return suffix_expr; 783 784 return addNode( 785 &p->nodes, 786 (AstNodeItem) { 787 .tag = AST_NODE_ERROR_UNION, 788 .main_token = bang, 789 .data = { 790 .lhs = suffix_expr, 791 .rhs = parseTypeExpr(p), 792 }, 793 }); 794 } 795 796 // parsePtrModifiersAndType parses pointer modifiers (allowzero, align, 797 // addrspace, const, volatile, sentinel) and the child type for a pointer 798 // started at main_token. 799 static AstNodeIndex parsePtrModifiersAndType( 800 Parser* p, AstTokenIndex main_token) { 801 AstNodeIndex sentinel = 0; 802 AstNodeIndex align_expr = 0; 803 AstNodeIndex bit_range_start = 0; 804 AstNodeIndex bit_range_end = 0; 805 AstNodeIndex addrspace_expr = 0; 806 807 // sentinel: *:0 808 if (eatToken(p, TOKEN_COLON) != null_token) 809 sentinel = expectExpr(p); 810 811 // allowzero, const, volatile (before align) 812 while (p->token_tags[p->tok_i] == TOKEN_KEYWORD_CONST 813 || p->token_tags[p->tok_i] == TOKEN_KEYWORD_VOLATILE 814 || p->token_tags[p->tok_i] == TOKEN_KEYWORD_ALLOWZERO) 815 p->tok_i++; 816 817 // align(expr) or align(expr:expr:expr) 818 if (eatToken(p, TOKEN_KEYWORD_ALIGN) != null_token) { 819 expectToken(p, TOKEN_L_PAREN); 820 align_expr = expectExpr(p); 821 if (eatToken(p, TOKEN_COLON) != null_token) { 822 bit_range_start = expectExpr(p); 823 expectToken(p, TOKEN_COLON); 824 bit_range_end = expectExpr(p); 825 } 826 expectToken(p, TOKEN_R_PAREN); 827 } 828 829 // addrspace 830 addrspace_expr = parseAddrSpace(p); 831 832 // const, volatile, allowzero (after align/addrspace) 833 while (p->token_tags[p->tok_i] == TOKEN_KEYWORD_CONST 834 || p->token_tags[p->tok_i] == TOKEN_KEYWORD_VOLATILE 835 || p->token_tags[p->tok_i] == TOKEN_KEYWORD_ALLOWZERO) 836 p->tok_i++; 837 838 const AstNodeIndex child_type = parseTypeExpr(p); 839 840 if (bit_range_start != 0) { 841 return addNode(&p->nodes, 842 (AstNodeItem) { 843 .tag = AST_NODE_PTR_TYPE_BIT_RANGE, 844 .main_token = main_token, 845 .data = { 846 .lhs = addExtra(p, 847 (AstNodeIndex[]) { OPT(sentinel), align_expr, 848 OPT(addrspace_expr), bit_range_start, 849 bit_range_end }, 850 5), 851 .rhs = child_type, 852 }, 853 }); 854 } 855 if (addrspace_expr != 0) { 856 return addNode(&p->nodes, 857 (AstNodeItem) { 858 .tag = AST_NODE_PTR_TYPE, 859 .main_token = main_token, 860 .data = { 861 .lhs = addExtra(p, 862 (AstNodeIndex[]) { OPT(sentinel), OPT(align_expr), 863 addrspace_expr }, 864 3), 865 .rhs = child_type, 866 }, 867 }); 868 } 869 if (sentinel != 0) { 870 return addNode(&p->nodes, 871 (AstNodeItem) { 872 .tag = AST_NODE_PTR_TYPE_SENTINEL, 873 .main_token = main_token, 874 .data = { .lhs = sentinel, .rhs = child_type }, 875 }); 876 } 877 return addNode(&p->nodes, 878 (AstNodeItem) { 879 .tag = AST_NODE_PTR_TYPE_ALIGNED, 880 .main_token = main_token, 881 .data = { .lhs = align_expr, .rhs = child_type }, 882 }); 883 } 884 885 static AstNodeIndex parseTypeExpr(Parser* p) { 886 const TokenizerTag tok = p->token_tags[p->tok_i]; 887 switch (tok) { 888 case TOKEN_QUESTION_MARK: 889 return addNode(&p->nodes, 890 (AstNodeItem) { 891 .tag = AST_NODE_OPTIONAL_TYPE, 892 .main_token = nextToken(p), 893 .data = { .lhs = parseTypeExpr(p), .rhs = 0 }, 894 }); 895 case TOKEN_KEYWORD_ANYFRAME: 896 fprintf(stderr, "parseTypeExpr not supported for %s\n", 897 tokenizerGetTagString(tok)); 898 exit(1); 899 case TOKEN_ASTERISK: { 900 const AstTokenIndex asterisk = nextToken(p); 901 return parsePtrModifiersAndType(p, asterisk); 902 } 903 case TOKEN_ASTERISK_ASTERISK: { 904 // ** is two nested pointer types sharing the same token 905 const AstTokenIndex asterisk = nextToken(p); 906 // Inner pointer: parse modifiers and child type 907 const AstNodeIndex inner_child = parseTypeExpr(p); 908 const AstNodeIndex inner = addNode(&p->nodes, 909 (AstNodeItem) { 910 .tag = AST_NODE_PTR_TYPE_ALIGNED, 911 .main_token = asterisk, 912 .data = { .lhs = 0, .rhs = inner_child }, 913 }); 914 // Outer pointer wraps the inner 915 return addNode(&p->nodes, 916 (AstNodeItem) { 917 .tag = AST_NODE_PTR_TYPE_ALIGNED, 918 .main_token = asterisk, 919 .data = { .lhs = 0, .rhs = inner }, 920 }); 921 } 922 case TOKEN_L_BRACKET: { 923 const AstTokenIndex lbracket = nextToken(p); 924 if (p->token_tags[p->tok_i] == TOKEN_ASTERISK) { 925 // [*] many-item pointer, [*c] C pointer, [*:s] sentinel 926 p->tok_i++; // consume * 927 AstNodeIndex sentinel = 0; 928 if (p->token_tags[p->tok_i] == TOKEN_IDENTIFIER) { 929 // Check for 'c' modifier: [*c] 930 // The 'c' is a regular identifier token 931 const char c = p->source[p->token_starts[p->tok_i]]; 932 if (c == 'c' 933 && p->token_starts[p->tok_i + 1] 934 - p->token_starts[p->tok_i] 935 <= 2) { 936 p->tok_i++; // consume 'c' 937 } 938 } else if (eatToken(p, TOKEN_COLON) != null_token) { 939 sentinel = expectExpr(p); 940 } 941 expectToken(p, TOKEN_R_BRACKET); 942 // Reuse shared pointer modifier + type parsing 943 // If we captured a sentinel from [*:s], temporarily store it 944 // and let parsePtrModifiersAndType handle the rest. 945 // But parsePtrModifiersAndType expects sentinel after main 946 // token via `:`. Since we already consumed it, we need to 947 // handle this inline. 948 949 // allowzero, const, volatile (before align) 950 while (p->token_tags[p->tok_i] == TOKEN_KEYWORD_CONST 951 || p->token_tags[p->tok_i] == TOKEN_KEYWORD_VOLATILE 952 || p->token_tags[p->tok_i] == TOKEN_KEYWORD_ALLOWZERO) 953 p->tok_i++; 954 955 AstNodeIndex align_expr = 0; 956 AstNodeIndex bit_range_start = 0; 957 AstNodeIndex bit_range_end = 0; 958 if (eatToken(p, TOKEN_KEYWORD_ALIGN) != null_token) { 959 expectToken(p, TOKEN_L_PAREN); 960 align_expr = expectExpr(p); 961 if (eatToken(p, TOKEN_COLON) != null_token) { 962 bit_range_start = expectExpr(p); 963 expectToken(p, TOKEN_COLON); 964 bit_range_end = expectExpr(p); 965 } 966 expectToken(p, TOKEN_R_PAREN); 967 } 968 const AstNodeIndex addrspace_expr = parseAddrSpace(p); 969 970 while (p->token_tags[p->tok_i] == TOKEN_KEYWORD_CONST 971 || p->token_tags[p->tok_i] == TOKEN_KEYWORD_VOLATILE 972 || p->token_tags[p->tok_i] == TOKEN_KEYWORD_ALLOWZERO) 973 p->tok_i++; 974 975 const AstNodeIndex elem_type = parseTypeExpr(p); 976 977 if (bit_range_start != 0) { 978 return addNode(&p->nodes, 979 (AstNodeItem) { 980 .tag = AST_NODE_PTR_TYPE_BIT_RANGE, 981 .main_token = lbracket, 982 .data = { 983 .lhs = addExtra(p, 984 (AstNodeIndex[]) { OPT(sentinel), 985 align_expr, OPT(addrspace_expr), 986 bit_range_start, bit_range_end }, 987 5), 988 .rhs = elem_type, 989 }, 990 }); 991 } 992 if (addrspace_expr != 0) { 993 return addNode(&p->nodes, 994 (AstNodeItem) { 995 .tag = AST_NODE_PTR_TYPE, 996 .main_token = lbracket, 997 .data = { 998 .lhs = addExtra(p, 999 (AstNodeIndex[]) { OPT(sentinel), 1000 OPT(align_expr), addrspace_expr }, 1001 3), 1002 .rhs = elem_type, 1003 }, 1004 }); 1005 } 1006 if (sentinel != 0) { 1007 return addNode(&p->nodes, 1008 (AstNodeItem) { 1009 .tag = AST_NODE_PTR_TYPE_SENTINEL, 1010 .main_token = lbracket, 1011 .data = { .lhs = sentinel, .rhs = elem_type }, 1012 }); 1013 } 1014 return addNode(&p->nodes, 1015 (AstNodeItem) { 1016 .tag = AST_NODE_PTR_TYPE_ALIGNED, 1017 .main_token = lbracket, 1018 .data = { .lhs = align_expr, .rhs = elem_type }, 1019 }); 1020 } 1021 const AstNodeIndex len_expr = parseExpr(p); 1022 const AstNodeIndex sentinel 1023 = eatToken(p, TOKEN_COLON) != null_token ? expectExpr(p) : 0; 1024 expectToken(p, TOKEN_R_BRACKET); 1025 if (len_expr == 0) { 1026 // Slice type: []T or [:s]T — reuse shared modifier parsing 1027 // allowzero, const, volatile 1028 while (p->token_tags[p->tok_i] == TOKEN_KEYWORD_CONST 1029 || p->token_tags[p->tok_i] == TOKEN_KEYWORD_VOLATILE 1030 || p->token_tags[p->tok_i] == TOKEN_KEYWORD_ALLOWZERO) 1031 p->tok_i++; 1032 const AstNodeIndex align_expr = parseByteAlign(p); 1033 const AstNodeIndex addrspace_expr = parseAddrSpace(p); 1034 while (p->token_tags[p->tok_i] == TOKEN_KEYWORD_CONST 1035 || p->token_tags[p->tok_i] == TOKEN_KEYWORD_VOLATILE 1036 || p->token_tags[p->tok_i] == TOKEN_KEYWORD_ALLOWZERO) 1037 p->tok_i++; 1038 const AstNodeIndex elem_type = parseTypeExpr(p); 1039 if (addrspace_expr != 0) { 1040 return addNode(&p->nodes, 1041 (AstNodeItem) { 1042 .tag = AST_NODE_PTR_TYPE, 1043 .main_token = lbracket, 1044 .data = { 1045 .lhs = addExtra(p, 1046 (AstNodeIndex[]) { OPT(sentinel), 1047 OPT(align_expr), addrspace_expr }, 1048 3), 1049 .rhs = elem_type, 1050 }, 1051 }); 1052 } 1053 if (sentinel != 0 && align_expr == 0) { 1054 return addNode(&p->nodes, 1055 (AstNodeItem) { 1056 .tag = AST_NODE_PTR_TYPE_SENTINEL, 1057 .main_token = lbracket, 1058 .data = { .lhs = sentinel, .rhs = elem_type }, 1059 }); 1060 } 1061 return addNode(&p->nodes, 1062 (AstNodeItem) { 1063 .tag = AST_NODE_PTR_TYPE_ALIGNED, 1064 .main_token = lbracket, 1065 .data = { .lhs = align_expr, .rhs = elem_type }, 1066 }); 1067 } 1068 // Array type: [N]T or [N:s]T 1069 const AstNodeIndex elem_type = parseTypeExpr(p); 1070 if (sentinel == 0) { 1071 return addNode(&p->nodes, 1072 (AstNodeItem) { 1073 .tag = AST_NODE_ARRAY_TYPE, 1074 .main_token = lbracket, 1075 .data = { .lhs = len_expr, .rhs = elem_type }, 1076 }); 1077 } 1078 return addNode(&p->nodes, 1079 (AstNodeItem) { 1080 .tag = AST_NODE_ARRAY_TYPE_SENTINEL, 1081 .main_token = lbracket, 1082 .data = { 1083 .lhs = len_expr, 1084 .rhs = addExtra(p, 1085 (AstNodeIndex[]) { sentinel, elem_type }, 2), 1086 }, 1087 }); 1088 } 1089 default: 1090 return parseErrorUnionExpr(p); 1091 } 1092 return 0; // tcc 1093 } 1094 1095 static SmallSpan parseParamDeclList(Parser* p) { 1096 expectToken(p, TOKEN_L_PAREN); 1097 1098 CleanupScratch scratch_top __attribute__((__cleanup__(cleanupScratch))) 1099 = initCleanupScratch(p); 1100 1101 while (true) { 1102 if (eatToken(p, TOKEN_R_PAREN) != null_token) 1103 break; 1104 1105 eatDocComments(p); 1106 1107 // Check for comptime or noalias 1108 eatToken(p, TOKEN_KEYWORD_COMPTIME); 1109 eatToken(p, TOKEN_KEYWORD_NOALIAS); 1110 1111 // Check for name: type or just type 1112 if (p->token_tags[p->tok_i] == TOKEN_IDENTIFIER 1113 && p->token_tags[p->tok_i + 1] == TOKEN_COLON) { 1114 p->tok_i += 2; // consume name and colon 1115 } else if (p->token_tags[p->tok_i] == TOKEN_ELLIPSIS3) { 1116 // varargs (...) 1117 p->tok_i++; 1118 if (eatToken(p, TOKEN_R_PAREN) != null_token) 1119 break; 1120 expectToken(p, TOKEN_COMMA); 1121 continue; 1122 } 1123 1124 // anytype params are omitted from the AST 1125 if (eatToken(p, TOKEN_KEYWORD_ANYTYPE) != null_token) { 1126 if (p->token_tags[p->tok_i] == TOKEN_COMMA) { 1127 p->tok_i++; 1128 continue; 1129 } 1130 expectToken(p, TOKEN_R_PAREN); 1131 break; 1132 } 1133 1134 const AstNodeIndex type_expr = parseTypeExpr(p); 1135 if (type_expr != 0) 1136 SLICE_APPEND(AstNodeIndex, &p->scratch, type_expr); 1137 1138 if (p->token_tags[p->tok_i] == TOKEN_COMMA) { 1139 p->tok_i++; 1140 continue; 1141 } 1142 expectToken(p, TOKEN_R_PAREN); 1143 break; 1144 } 1145 1146 const uint32_t params_len = p->scratch.len - scratch_top.old_len; 1147 switch (params_len) { 1148 case 0: 1149 return (SmallSpan) { 1150 .tag = SMALL_SPAN_ZERO_OR_ONE, 1151 .payload = { .zero_or_one = 0 }, 1152 }; 1153 case 1: 1154 return (SmallSpan) { 1155 .tag = SMALL_SPAN_ZERO_OR_ONE, 1156 .payload = { .zero_or_one = p->scratch.arr[scratch_top.old_len] }, 1157 }; 1158 default:; 1159 const AstSubRange span 1160 = listToSpan(p, &p->scratch.arr[scratch_top.old_len], params_len); 1161 return (SmallSpan) { 1162 .tag = SMALL_SPAN_MULTI, 1163 .payload = { .multi = span }, 1164 }; 1165 } 1166 } 1167 1168 static uint32_t reserveNode(Parser* p, AstNodeTag tag) { 1169 astNodeListEnsureCapacity(&p->nodes, 1); 1170 p->nodes.len++; 1171 p->nodes.tags[p->nodes.len - 1] = tag; 1172 return p->nodes.len - 1; 1173 } 1174 1175 static AstNodeIndex parseFnProto(Parser* p) { 1176 AstTokenIndex fn_token = eatToken(p, TOKEN_KEYWORD_FN); 1177 if (fn_token == null_token) 1178 return null_node; 1179 1180 AstNodeIndex fn_proto_index = reserveNode(p, AST_NODE_FN_PROTO); 1181 1182 eatToken(p, TOKEN_IDENTIFIER); 1183 1184 SmallSpan params = parseParamDeclList(p); 1185 const AstNodeIndex align_expr = parseByteAlign(p); 1186 const AstNodeIndex addrspace_expr = parseAddrSpace(p); 1187 const AstNodeIndex section_expr = parseLinkSection(p); 1188 const AstNodeIndex callconv_expr = parseCallconv(p); 1189 eatToken(p, TOKEN_BANG); 1190 1191 const AstNodeIndex return_type_expr = parseTypeExpr(p); 1192 1193 if (align_expr == 0 && section_expr == 0 && callconv_expr == 0 1194 && addrspace_expr == 0) { 1195 switch (params.tag) { 1196 case SMALL_SPAN_ZERO_OR_ONE: 1197 return setNode(p, fn_proto_index, 1198 (AstNodeItem) { 1199 .tag = AST_NODE_FN_PROTO_SIMPLE, 1200 .main_token = fn_token, 1201 .data = { 1202 .lhs = params.payload.zero_or_one, 1203 .rhs = return_type_expr, 1204 }, 1205 }); 1206 case SMALL_SPAN_MULTI: 1207 return setNode(p, fn_proto_index, 1208 (AstNodeItem) { 1209 .tag = AST_NODE_FN_PROTO_MULTI, 1210 .main_token = fn_token, 1211 .data = { 1212 .lhs = addExtra(p, 1213 (AstNodeIndex[]) { 1214 params.payload.multi.start, 1215 params.payload.multi.end }, 1216 2), 1217 .rhs = return_type_expr, 1218 }, 1219 }); 1220 } 1221 } 1222 1223 // Complex fn proto with align/section/callconv/addrspace 1224 switch (params.tag) { 1225 case SMALL_SPAN_ZERO_OR_ONE: 1226 return setNode(p, fn_proto_index, 1227 (AstNodeItem) { 1228 .tag = AST_NODE_FN_PROTO_ONE, 1229 .main_token = fn_token, 1230 .data = { 1231 .lhs = addExtra(p, 1232 (AstNodeIndex[]) { 1233 OPT(params.payload.zero_or_one), 1234 OPT(align_expr), OPT(addrspace_expr), 1235 OPT(section_expr), OPT(callconv_expr) }, 1236 5), 1237 .rhs = return_type_expr, 1238 }, 1239 }); 1240 case SMALL_SPAN_MULTI: 1241 return setNode(p, fn_proto_index, 1242 (AstNodeItem) { 1243 .tag = AST_NODE_FN_PROTO, 1244 .main_token = fn_token, 1245 .data = { 1246 .lhs = addExtra(p, 1247 (AstNodeIndex[]) { 1248 params.payload.multi.start, 1249 params.payload.multi.end, 1250 OPT(align_expr), OPT(addrspace_expr), 1251 OPT(section_expr), OPT(callconv_expr) }, 1252 6), 1253 .rhs = return_type_expr, 1254 }, 1255 }); 1256 } 1257 return 0; // tcc 1258 } 1259 1260 static AstTokenIndex parseBlockLabel(Parser* p) { 1261 if (p->token_tags[p->tok_i] == TOKEN_IDENTIFIER 1262 && p->token_tags[p->tok_i + 1] == TOKEN_COLON) { 1263 const AstTokenIndex identifier = p->tok_i; 1264 p->tok_i += 2; 1265 return identifier; 1266 } 1267 return null_node; 1268 } 1269 1270 static AstNodeIndex parseForStatement(Parser* p) { 1271 const AstNodeIndex for_token = eatToken(p, TOKEN_KEYWORD_FOR); 1272 if (for_token == null_token) 1273 return null_node; 1274 1275 (void)for_token; 1276 fprintf(stderr, "parseForStatement cannot parse for statements\n"); 1277 return 0; // tcc 1278 } 1279 1280 static AstNodeIndex parseWhileStatement(Parser* p) { 1281 const AstNodeIndex while_token = eatToken(p, TOKEN_KEYWORD_WHILE); 1282 if (while_token == null_token) 1283 return null_node; 1284 1285 (void)while_token; 1286 fprintf(stderr, "parseWhileStatement cannot parse while statements\n"); 1287 return 0; // tcc 1288 } 1289 1290 static AstNodeIndex parseLoopStatement(Parser* p) { 1291 const AstTokenIndex inline_token = eatToken(p, TOKEN_KEYWORD_INLINE); 1292 1293 const AstNodeIndex for_statement = parseForStatement(p); 1294 if (for_statement != 0) 1295 return for_statement; 1296 1297 const AstNodeIndex while_statement = parseWhileStatement(p); 1298 if (while_statement != 0) 1299 return while_statement; 1300 1301 if (inline_token == null_token) 1302 return null_node; 1303 1304 fprintf( 1305 stderr, "seen 'inline', there should have been a 'for' or 'while'\n"); 1306 exit(1); 1307 return 0; // tcc 1308 } 1309 1310 static AstNodeIndex parseVarDeclProto(Parser* p) { 1311 AstTokenIndex mut_token; 1312 if ((mut_token = eatToken(p, TOKEN_KEYWORD_CONST)) == null_token) 1313 if ((mut_token = eatToken(p, TOKEN_KEYWORD_VAR)) == null_token) 1314 return null_node; 1315 1316 expectToken(p, TOKEN_IDENTIFIER); 1317 const AstNodeIndex type_node 1318 = eatToken(p, TOKEN_COLON) == null_token ? 0 : parseTypeExpr(p); 1319 const AstNodeIndex align_node = parseByteAlign(p); 1320 const AstNodeIndex addrspace_node = parseAddrSpace(p); 1321 const AstNodeIndex section_node = parseLinkSection(p); 1322 1323 if (section_node == 0 && addrspace_node == 0) { 1324 if (align_node == 0) { 1325 return addNode(&p->nodes, 1326 (AstNodeItem) { 1327 .tag = AST_NODE_SIMPLE_VAR_DECL, 1328 .main_token = mut_token, 1329 .data = { .lhs = type_node, .rhs = 0 }, 1330 }); 1331 } 1332 if (type_node == 0) { 1333 return addNode(&p->nodes, 1334 (AstNodeItem) { 1335 .tag = AST_NODE_ALIGNED_VAR_DECL, 1336 .main_token = mut_token, 1337 .data = { .lhs = align_node, .rhs = 0 }, 1338 }); 1339 } 1340 return addNode(&p->nodes, 1341 (AstNodeItem) { 1342 .tag = AST_NODE_LOCAL_VAR_DECL, 1343 .main_token = mut_token, 1344 .data = { 1345 .lhs = addExtra(p, 1346 (AstNodeIndex[]) { type_node, align_node }, 2), 1347 .rhs = 0, 1348 }, 1349 }); 1350 } 1351 return addNode(&p->nodes, 1352 (AstNodeItem) { 1353 .tag = AST_NODE_GLOBAL_VAR_DECL, 1354 .main_token = mut_token, 1355 .data = { 1356 .lhs = addExtra(p, 1357 (AstNodeIndex[]) { OPT(type_node), OPT(align_node), 1358 OPT(addrspace_node), OPT(section_node) }, 1359 4), 1360 .rhs = 0, 1361 }, 1362 }); 1363 } 1364 1365 static AstTokenIndex parseBreakLabel(Parser* p) { 1366 if (eatToken(p, TOKEN_COLON) == null_token) 1367 return null_token; 1368 return expectToken(p, TOKEN_IDENTIFIER); 1369 } 1370 1371 // parseFieldInit tries to parse .field_name = expr; returns 0 if not a 1372 // field init 1373 static AstNodeIndex parseFieldInit(Parser* p) { 1374 if (p->token_tags[p->tok_i] == TOKEN_PERIOD 1375 && p->token_tags[p->tok_i + 1] == TOKEN_IDENTIFIER 1376 && p->token_tags[p->tok_i + 2] == TOKEN_EQUAL) { 1377 p->tok_i += 3; 1378 return expectExpr(p); 1379 } 1380 return null_node; 1381 } 1382 1383 // parseInitList parses the contents of { ... } for struct/array init. 1384 // lhs is the type expression (0 for anonymous .{...}). 1385 // lbrace is the lbrace token index. 1386 static AstNodeIndex parseInitList( 1387 Parser* p, AstNodeIndex lhs, AstTokenIndex lbrace) { 1388 CleanupScratch scratch_top __attribute__((__cleanup__(cleanupScratch))) 1389 = initCleanupScratch(p); 1390 1391 const AstNodeIndex field_init = parseFieldInit(p); 1392 if (field_init != 0) { 1393 // Struct init 1394 SLICE_APPEND(AstNodeIndex, &p->scratch, field_init); 1395 while (true) { 1396 if (p->token_tags[p->tok_i] == TOKEN_COMMA) 1397 p->tok_i++; 1398 else if (p->token_tags[p->tok_i] == TOKEN_R_BRACE) { 1399 p->tok_i++; 1400 break; 1401 } else { 1402 fprintf( 1403 stderr, "parseInitList: expected , or } in struct init\n"); 1404 exit(1); 1405 } 1406 if (eatToken(p, TOKEN_R_BRACE) != null_token) 1407 break; 1408 const AstNodeIndex next = parseFieldInit(p); 1409 assert(next != 0); 1410 SLICE_APPEND(AstNodeIndex, &p->scratch, next); 1411 } 1412 const bool comma = p->token_tags[p->tok_i - 2] == TOKEN_COMMA; 1413 const uint32_t inits_len = p->scratch.len - scratch_top.old_len; 1414 if (lhs == 0) { 1415 // Anonymous struct init: .{...} 1416 switch (inits_len) { 1417 case 0: 1418 case 1: 1419 case 2: 1420 return addNode(&p->nodes, 1421 (AstNodeItem) { 1422 .tag = comma 1423 ? AST_NODE_STRUCT_INIT_DOT_TWO_COMMA 1424 : AST_NODE_STRUCT_INIT_DOT_TWO, 1425 .main_token = lbrace, 1426 .data = { 1427 .lhs = inits_len >= 1 1428 ? p->scratch.arr[scratch_top.old_len] 1429 : 0, 1430 .rhs = inits_len >= 2 1431 ? p->scratch.arr[scratch_top.old_len + 1] 1432 : 0, 1433 }, 1434 }); 1435 default:; 1436 const AstSubRange span = listToSpan( 1437 p, &p->scratch.arr[scratch_top.old_len], inits_len); 1438 return addNode(&p->nodes, 1439 (AstNodeItem) { 1440 .tag = comma ? AST_NODE_STRUCT_INIT_DOT_COMMA 1441 : AST_NODE_STRUCT_INIT_DOT, 1442 .main_token = lbrace, 1443 .data = { .lhs = span.start, .rhs = span.end }, 1444 }); 1445 } 1446 } 1447 // Named struct init: X{...} 1448 switch (inits_len) { 1449 case 0: 1450 case 1: 1451 return addNode(&p->nodes, 1452 (AstNodeItem) { 1453 .tag = comma ? AST_NODE_STRUCT_INIT_ONE_COMMA 1454 : AST_NODE_STRUCT_INIT_ONE, 1455 .main_token = lbrace, 1456 .data = { 1457 .lhs = lhs, 1458 .rhs = inits_len >= 1 1459 ? p->scratch.arr[scratch_top.old_len] 1460 : 0, 1461 }, 1462 }); 1463 default:; 1464 const AstSubRange span = listToSpan( 1465 p, &p->scratch.arr[scratch_top.old_len], inits_len); 1466 return addNode(&p->nodes, 1467 (AstNodeItem) { 1468 .tag = comma ? AST_NODE_STRUCT_INIT_COMMA 1469 : AST_NODE_STRUCT_INIT, 1470 .main_token = lbrace, 1471 .data = { 1472 .lhs = lhs, 1473 .rhs = addExtra(p, 1474 (AstNodeIndex[]) { span.start, span.end }, 2), 1475 }, 1476 }); 1477 } 1478 } 1479 1480 // Array init or empty init 1481 while (true) { 1482 if (eatToken(p, TOKEN_R_BRACE) != null_token) 1483 break; 1484 const AstNodeIndex elem = expectExpr(p); 1485 SLICE_APPEND(AstNodeIndex, &p->scratch, elem); 1486 if (p->token_tags[p->tok_i] == TOKEN_COMMA) 1487 p->tok_i++; 1488 else if (p->token_tags[p->tok_i] == TOKEN_R_BRACE) { 1489 p->tok_i++; 1490 break; 1491 } else { 1492 fprintf(stderr, "parseInitList: expected , or } in array init\n"); 1493 exit(1); 1494 } 1495 } 1496 1497 const bool comma = p->token_tags[p->tok_i - 2] == TOKEN_COMMA; 1498 const uint32_t elems_len = p->scratch.len - scratch_top.old_len; 1499 if (lhs == 0) { 1500 // Anonymous array init: .{a, b, ...} 1501 switch (elems_len) { 1502 case 0: 1503 case 1: 1504 case 2: 1505 return addNode(&p->nodes, 1506 (AstNodeItem) { 1507 .tag = comma ? AST_NODE_ARRAY_INIT_DOT_TWO_COMMA 1508 : AST_NODE_ARRAY_INIT_DOT_TWO, 1509 .main_token = lbrace, 1510 .data = { 1511 .lhs = elems_len >= 1 1512 ? p->scratch.arr[scratch_top.old_len] 1513 : 0, 1514 .rhs = elems_len >= 2 1515 ? p->scratch.arr[scratch_top.old_len + 1] 1516 : 0, 1517 }, 1518 }); 1519 default:; 1520 const AstSubRange span = listToSpan( 1521 p, &p->scratch.arr[scratch_top.old_len], elems_len); 1522 return addNode(&p->nodes, 1523 (AstNodeItem) { 1524 .tag = comma ? AST_NODE_ARRAY_INIT_DOT_COMMA 1525 : AST_NODE_ARRAY_INIT_DOT, 1526 .main_token = lbrace, 1527 .data = { .lhs = span.start, .rhs = span.end }, 1528 }); 1529 } 1530 } 1531 // Named init: X{a, b, ...} 1532 switch (elems_len) { 1533 case 0: 1534 // Empty init X{} — treat as struct init 1535 return addNode(&p->nodes, 1536 (AstNodeItem) { 1537 .tag = AST_NODE_STRUCT_INIT_ONE, 1538 .main_token = lbrace, 1539 .data = { .lhs = lhs, .rhs = 0 }, 1540 }); 1541 case 1: 1542 return addNode(&p->nodes, 1543 (AstNodeItem) { 1544 .tag = comma ? AST_NODE_ARRAY_INIT_ONE_COMMA 1545 : AST_NODE_ARRAY_INIT_ONE, 1546 .main_token = lbrace, 1547 .data = { 1548 .lhs = lhs, 1549 .rhs = p->scratch.arr[scratch_top.old_len], 1550 }, 1551 }); 1552 default:; 1553 const AstSubRange span 1554 = listToSpan(p, &p->scratch.arr[scratch_top.old_len], elems_len); 1555 return addNode(&p->nodes, 1556 (AstNodeItem) { 1557 .tag = comma ? AST_NODE_ARRAY_INIT_COMMA 1558 : AST_NODE_ARRAY_INIT, 1559 .main_token = lbrace, 1560 .data = { 1561 .lhs = lhs, 1562 .rhs = addExtra(p, 1563 (AstNodeIndex[]) { span.start, span.end }, 2), 1564 }, 1565 }); 1566 } 1567 } 1568 1569 static AstNodeIndex parseCurlySuffixExpr(Parser* p) { 1570 const AstNodeIndex lhs = parseTypeExpr(p); 1571 if (lhs == 0) 1572 return null_node; 1573 1574 const AstTokenIndex lbrace = eatToken(p, TOKEN_L_BRACE); 1575 if (lbrace == null_token) 1576 return lhs; 1577 1578 return parseInitList(p, lhs, lbrace); 1579 } 1580 1581 typedef struct { 1582 int8_t prec; 1583 AstNodeTag tag; 1584 enum { 1585 ASSOC_LEFT, 1586 ASSOC_NONE, 1587 } assoc; 1588 } OperInfo; 1589 1590 static OperInfo operTable(TokenizerTag tok_tag) { 1591 switch (tok_tag) { 1592 case TOKEN_KEYWORD_OR: 1593 return (OperInfo) { .prec = 10, .tag = AST_NODE_BOOL_OR }; 1594 case TOKEN_KEYWORD_AND: 1595 return (OperInfo) { .prec = 20, .tag = AST_NODE_BOOL_AND }; 1596 1597 case TOKEN_EQUAL_EQUAL: 1598 return (OperInfo) { 1599 .prec = 30, .tag = AST_NODE_EQUAL_EQUAL, .assoc = ASSOC_NONE 1600 }; 1601 case TOKEN_BANG_EQUAL: 1602 return (OperInfo) { 1603 .prec = 30, .tag = AST_NODE_BANG_EQUAL, .assoc = ASSOC_NONE 1604 }; 1605 case TOKEN_ANGLE_BRACKET_LEFT: 1606 return (OperInfo) { 1607 .prec = 30, .tag = AST_NODE_LESS_THAN, .assoc = ASSOC_NONE 1608 }; 1609 case TOKEN_ANGLE_BRACKET_RIGHT: 1610 return (OperInfo) { 1611 .prec = 30, .tag = AST_NODE_GREATER_THAN, .assoc = ASSOC_NONE 1612 }; 1613 case TOKEN_ANGLE_BRACKET_LEFT_EQUAL: 1614 return (OperInfo) { 1615 .prec = 30, .tag = AST_NODE_LESS_OR_EQUAL, .assoc = ASSOC_NONE 1616 }; 1617 case TOKEN_ANGLE_BRACKET_RIGHT_EQUAL: 1618 return (OperInfo) { 1619 .prec = 30, .tag = AST_NODE_GREATER_OR_EQUAL, .assoc = ASSOC_NONE 1620 }; 1621 1622 case TOKEN_AMPERSAND: 1623 return (OperInfo) { .prec = 40, .tag = AST_NODE_BIT_AND }; 1624 case TOKEN_CARET: 1625 return (OperInfo) { .prec = 40, .tag = AST_NODE_BIT_XOR }; 1626 case TOKEN_PIPE: 1627 return (OperInfo) { .prec = 40, .tag = AST_NODE_BIT_OR }; 1628 case TOKEN_KEYWORD_ORELSE: 1629 return (OperInfo) { .prec = 40, .tag = AST_NODE_ORELSE }; 1630 case TOKEN_KEYWORD_CATCH: 1631 return (OperInfo) { .prec = 40, .tag = AST_NODE_CATCH }; 1632 1633 case TOKEN_ANGLE_BRACKET_ANGLE_BRACKET_LEFT: 1634 return (OperInfo) { .prec = 50, .tag = AST_NODE_SHL }; 1635 case TOKEN_ANGLE_BRACKET_ANGLE_BRACKET_LEFT_PIPE: 1636 return (OperInfo) { .prec = 50, .tag = AST_NODE_SHL_SAT }; 1637 case TOKEN_ANGLE_BRACKET_ANGLE_BRACKET_RIGHT: 1638 return (OperInfo) { .prec = 50, .tag = AST_NODE_SHR }; 1639 1640 case TOKEN_PLUS: 1641 return (OperInfo) { .prec = 60, .tag = AST_NODE_ADD }; 1642 case TOKEN_MINUS: 1643 return (OperInfo) { .prec = 60, .tag = AST_NODE_SUB }; 1644 case TOKEN_PLUS_PLUS: 1645 return (OperInfo) { .prec = 60, .tag = AST_NODE_ARRAY_CAT }; 1646 case TOKEN_PLUS_PERCENT: 1647 return (OperInfo) { .prec = 60, .tag = AST_NODE_ADD_WRAP }; 1648 case TOKEN_MINUS_PERCENT: 1649 return (OperInfo) { .prec = 60, .tag = AST_NODE_SUB_WRAP }; 1650 case TOKEN_PLUS_PIPE: 1651 return (OperInfo) { .prec = 60, .tag = AST_NODE_ADD_SAT }; 1652 case TOKEN_MINUS_PIPE: 1653 return (OperInfo) { .prec = 60, .tag = AST_NODE_SUB_SAT }; 1654 1655 case TOKEN_PIPE_PIPE: 1656 return (OperInfo) { .prec = 70, .tag = AST_NODE_MERGE_ERROR_SETS }; 1657 case TOKEN_ASTERISK: 1658 return (OperInfo) { .prec = 70, .tag = AST_NODE_MUL }; 1659 case TOKEN_SLASH: 1660 return (OperInfo) { .prec = 70, .tag = AST_NODE_DIV }; 1661 case TOKEN_PERCENT: 1662 return (OperInfo) { .prec = 70, .tag = AST_NODE_MOD }; 1663 case TOKEN_ASTERISK_ASTERISK: 1664 return (OperInfo) { .prec = 70, .tag = AST_NODE_ARRAY_MULT }; 1665 case TOKEN_ASTERISK_PERCENT: 1666 return (OperInfo) { .prec = 70, .tag = AST_NODE_MUL_WRAP }; 1667 case TOKEN_ASTERISK_PIPE: 1668 return (OperInfo) { .prec = 70, .tag = AST_NODE_MUL_SAT }; 1669 1670 default: 1671 return (OperInfo) { .prec = -1, .tag = AST_NODE_ROOT }; 1672 } 1673 } 1674 1675 static AstNodeIndex parseExprPrecedence(Parser* p, int32_t min_prec) { 1676 assert(min_prec >= 0); 1677 1678 AstNodeIndex node = parsePrefixExpr(p); 1679 if (node == 0) 1680 return null_node; 1681 1682 int8_t banned_prec = -1; 1683 1684 while (true) { 1685 const TokenizerTag tok_tag = p->token_tags[p->tok_i]; 1686 const OperInfo info = operTable(tok_tag); 1687 if (info.prec < min_prec) 1688 break; 1689 1690 assert(info.prec != banned_prec); 1691 1692 const AstTokenIndex oper_token = nextToken(p); 1693 if (tok_tag == TOKEN_KEYWORD_CATCH) { 1694 fprintf(stderr, "parsePayload not supported\n"); 1695 exit(1); 1696 return 0; // tcc 1697 } 1698 const AstNodeIndex rhs = parseExprPrecedence(p, info.prec + 1); 1699 assert(rhs != 0); 1700 1701 node = addNode( 1702 &p->nodes, 1703 (AstNodeItem) { 1704 .tag = info.tag, 1705 .main_token = oper_token, 1706 .data = { 1707 .lhs = node, 1708 .rhs = rhs, 1709 }, 1710 }); 1711 1712 if (info.assoc == ASSOC_NONE) 1713 banned_prec = info.prec; 1714 } 1715 1716 return node; 1717 } 1718 1719 static AstNodeIndex parseExpr(Parser* p) { return parseExprPrecedence(p, 0); } 1720 1721 static AstNodeIndex expectExpr(Parser* p) { 1722 const AstNodeIndex node = parseExpr(p); 1723 assert(node != 0); 1724 return node; 1725 } 1726 1727 static void parsePtrPayload(Parser* p) { 1728 if (eatToken(p, TOKEN_PIPE) == null_token) 1729 return; 1730 eatToken(p, TOKEN_ASTERISK); 1731 expectToken(p, TOKEN_IDENTIFIER); 1732 expectToken(p, TOKEN_PIPE); 1733 } 1734 1735 static void parsePayload(Parser* p) { 1736 if (eatToken(p, TOKEN_PIPE) == null_token) 1737 return; 1738 expectToken(p, TOKEN_IDENTIFIER); 1739 expectToken(p, TOKEN_PIPE); 1740 } 1741 1742 static AstNodeIndex parseIfExpr(Parser* p) { 1743 const AstTokenIndex if_token = eatToken(p, TOKEN_KEYWORD_IF); 1744 if (if_token == null_token) 1745 return null_node; 1746 1747 expectToken(p, TOKEN_L_PAREN); 1748 const AstNodeIndex condition = expectExpr(p); 1749 expectToken(p, TOKEN_R_PAREN); 1750 parsePtrPayload(p); 1751 1752 const AstNodeIndex then_expr = expectExpr(p); 1753 1754 if (eatToken(p, TOKEN_KEYWORD_ELSE) == null_token) { 1755 return addNode(&p->nodes, 1756 (AstNodeItem) { 1757 .tag = AST_NODE_IF_SIMPLE, 1758 .main_token = if_token, 1759 .data = { .lhs = condition, .rhs = then_expr }, 1760 }); 1761 } 1762 1763 parsePayload(p); 1764 const AstNodeIndex else_expr = expectExpr(p); 1765 return addNode(&p->nodes, 1766 (AstNodeItem) { 1767 .tag = AST_NODE_IF, 1768 .main_token = if_token, 1769 .data = { 1770 .lhs = condition, 1771 .rhs = addExtra(p, 1772 (AstNodeIndex[]) { then_expr, else_expr }, 2), 1773 }, 1774 }); 1775 } 1776 1777 static AstNodeIndex parsePrimaryExpr(Parser* p) { 1778 const char* tok = tokenizerGetTagString(p->token_tags[p->tok_i]); 1779 switch (p->token_tags[p->tok_i]) { 1780 case TOKEN_KEYWORD_ASM: 1781 fprintf(stderr, "parsePrimaryExpr does not implement %s\n", tok); 1782 exit(1); 1783 break; 1784 case TOKEN_KEYWORD_IF: 1785 return parseIfExpr(p); 1786 case TOKEN_KEYWORD_BREAK: 1787 return addNode( 1788 &p->nodes, 1789 (AstNodeItem) { 1790 .tag = AST_NODE_BREAK, 1791 .main_token = nextToken(p), 1792 .data = { 1793 .lhs = parseBreakLabel(p), 1794 .rhs = parseExpr(p), 1795 }, 1796 }); 1797 case TOKEN_KEYWORD_CONTINUE: 1798 return addNode( 1799 &p->nodes, 1800 (AstNodeItem) { 1801 .tag = AST_NODE_CONTINUE, 1802 .main_token = nextToken(p), 1803 .data = { 1804 .lhs = parseBreakLabel(p), 1805 .rhs = parseExpr(p), 1806 }, 1807 }); 1808 case TOKEN_KEYWORD_COMPTIME: 1809 return addNode(&p->nodes, 1810 (AstNodeItem) { 1811 .tag = AST_NODE_COMPTIME, 1812 .main_token = nextToken(p), 1813 .data = { .lhs = expectExpr(p), .rhs = 0 }, 1814 }); 1815 case TOKEN_KEYWORD_NOSUSPEND: 1816 return addNode(&p->nodes, 1817 (AstNodeItem) { 1818 .tag = AST_NODE_NOSUSPEND, 1819 .main_token = nextToken(p), 1820 .data = { .lhs = expectExpr(p), .rhs = 0 }, 1821 }); 1822 case TOKEN_KEYWORD_RESUME: 1823 return addNode(&p->nodes, 1824 (AstNodeItem) { 1825 .tag = AST_NODE_RESUME, 1826 .main_token = nextToken(p), 1827 .data = { .lhs = expectExpr(p), .rhs = 0 }, 1828 }); 1829 case TOKEN_KEYWORD_RETURN: 1830 return addNode(&p->nodes, 1831 (AstNodeItem) { 1832 .tag = AST_NODE_RETURN, 1833 .main_token = nextToken(p), 1834 .data = { .lhs = parseExpr(p), .rhs = 0 }, 1835 }); 1836 case TOKEN_IDENTIFIER: 1837 if (p->token_tags[p->tok_i + 1] == TOKEN_COLON) { 1838 switch (p->token_tags[p->tok_i + 2]) { 1839 case TOKEN_KEYWORD_INLINE: 1840 case TOKEN_KEYWORD_FOR: 1841 case TOKEN_KEYWORD_WHILE: 1842 fprintf(stderr, "parsePrimaryExpr NotImplemented\n"); 1843 exit(1); 1844 return 0; // tcc 1845 case TOKEN_L_BRACE: 1846 p->tok_i += 2; 1847 return parseBlock(p); 1848 default: 1849 return parseCurlySuffixExpr(p); 1850 } 1851 } else { 1852 return parseCurlySuffixExpr(p); 1853 } 1854 case TOKEN_KEYWORD_INLINE: 1855 case TOKEN_KEYWORD_FOR: 1856 case TOKEN_KEYWORD_WHILE: 1857 fprintf(stderr, "parsePrimaryExpr does not implement %s\n", tok); 1858 exit(1); 1859 return 0; // tcc 1860 case TOKEN_L_BRACE: 1861 return parseBlock(p); 1862 default: 1863 return parseCurlySuffixExpr(p); 1864 } 1865 1866 return 0; // tcc 1867 } 1868 1869 static AstNodeIndex parsePrefixExpr(Parser* p) { 1870 AstNodeTag tag; 1871 switch (p->token_tags[p->tok_i]) { 1872 case TOKEN_BANG: 1873 tag = AST_NODE_BOOL_NOT; 1874 break; 1875 case TOKEN_MINUS: 1876 tag = AST_NODE_NEGATION; 1877 break; 1878 case TOKEN_TILDE: 1879 tag = AST_NODE_BIT_NOT; 1880 break; 1881 case TOKEN_MINUS_PERCENT: 1882 tag = AST_NODE_NEGATION_WRAP; 1883 break; 1884 case TOKEN_AMPERSAND: 1885 tag = AST_NODE_ADDRESS_OF; 1886 break; 1887 case TOKEN_KEYWORD_TRY: 1888 tag = AST_NODE_TRY; 1889 break; 1890 case TOKEN_KEYWORD_AWAIT: 1891 tag = AST_NODE_AWAIT; 1892 break; 1893 default: 1894 return parsePrimaryExpr(p); 1895 } 1896 return addNode( 1897 &p->nodes, 1898 (AstNodeItem) { 1899 .tag = tag, 1900 .main_token = nextToken(p), 1901 .data = { 1902 .lhs = parsePrefixExpr(p), 1903 .rhs = 0, 1904 }, 1905 }); 1906 } 1907 1908 static AstNodeTag assignOpTag(TokenizerTag tok) { 1909 switch (tok) { 1910 case TOKEN_EQUAL: 1911 return AST_NODE_ASSIGN; 1912 case TOKEN_PLUS_EQUAL: 1913 return AST_NODE_ASSIGN_ADD; 1914 case TOKEN_MINUS_EQUAL: 1915 return AST_NODE_ASSIGN_SUB; 1916 case TOKEN_ASTERISK_EQUAL: 1917 return AST_NODE_ASSIGN_MUL; 1918 case TOKEN_SLASH_EQUAL: 1919 return AST_NODE_ASSIGN_DIV; 1920 case TOKEN_PERCENT_EQUAL: 1921 return AST_NODE_ASSIGN_MOD; 1922 case TOKEN_AMPERSAND_EQUAL: 1923 return AST_NODE_ASSIGN_BIT_AND; 1924 case TOKEN_PIPE_EQUAL: 1925 return AST_NODE_ASSIGN_BIT_OR; 1926 case TOKEN_CARET_EQUAL: 1927 return AST_NODE_ASSIGN_BIT_XOR; 1928 case TOKEN_ANGLE_BRACKET_ANGLE_BRACKET_LEFT_EQUAL: 1929 return AST_NODE_ASSIGN_SHL; 1930 case TOKEN_ANGLE_BRACKET_ANGLE_BRACKET_RIGHT_EQUAL: 1931 return AST_NODE_ASSIGN_SHR; 1932 case TOKEN_PLUS_PERCENT_EQUAL: 1933 return AST_NODE_ASSIGN_ADD_WRAP; 1934 case TOKEN_MINUS_PERCENT_EQUAL: 1935 return AST_NODE_ASSIGN_SUB_WRAP; 1936 case TOKEN_ASTERISK_PERCENT_EQUAL: 1937 return AST_NODE_ASSIGN_MUL_WRAP; 1938 case TOKEN_PLUS_PIPE_EQUAL: 1939 return AST_NODE_ASSIGN_ADD_SAT; 1940 case TOKEN_MINUS_PIPE_EQUAL: 1941 return AST_NODE_ASSIGN_SUB_SAT; 1942 case TOKEN_ASTERISK_PIPE_EQUAL: 1943 return AST_NODE_ASSIGN_MUL_SAT; 1944 case TOKEN_ANGLE_BRACKET_ANGLE_BRACKET_LEFT_PIPE_EQUAL: 1945 return AST_NODE_ASSIGN_SHL_SAT; 1946 default: 1947 return AST_NODE_ROOT; // not an assignment op 1948 } 1949 } 1950 1951 static AstNodeIndex parseAssignExpr(Parser* p) { 1952 const AstNodeIndex expr = parseExpr(p); 1953 if (expr == 0) 1954 return null_node; 1955 1956 const AstNodeTag assign_tag = assignOpTag(p->token_tags[p->tok_i]); 1957 if (assign_tag == AST_NODE_ROOT) 1958 return expr; 1959 1960 const AstTokenIndex op_token = nextToken(p); 1961 const AstNodeIndex rhs = expectExpr(p); 1962 return addNode(&p->nodes, 1963 (AstNodeItem) { 1964 .tag = assign_tag, 1965 .main_token = op_token, 1966 .data = { .lhs = expr, .rhs = rhs }, 1967 }); 1968 } 1969 1970 static AstNodeIndex expectBlockExprStatement(Parser* p) { 1971 // Try block first (labeled or unlabeled) 1972 if (p->token_tags[p->tok_i] == TOKEN_L_BRACE) 1973 return parseBlock(p); 1974 if (p->token_tags[p->tok_i] == TOKEN_IDENTIFIER 1975 && p->token_tags[p->tok_i + 1] == TOKEN_COLON 1976 && p->token_tags[p->tok_i + 2] == TOKEN_L_BRACE) { 1977 p->tok_i += 2; 1978 return parseBlock(p); 1979 } 1980 // Assign expr + semicolon 1981 const AstNodeIndex expr = parseAssignExpr(p); 1982 if (expr != 0) { 1983 expectSemicolon(p); 1984 return expr; 1985 } 1986 fprintf(stderr, "expectBlockExprStatement: expected block or expr\n"); 1987 exit(1); 1988 return 0; // tcc 1989 } 1990 1991 static AstNodeIndex expectVarDeclExprStatement(Parser* p) { 1992 CleanupScratch scratch_top __attribute__((__cleanup__(cleanupScratch))) 1993 = initCleanupScratch(p); 1994 1995 while (true) { 1996 const AstNodeIndex var_decl_proto = parseVarDeclProto(p); 1997 if (var_decl_proto != 0) { 1998 SLICE_APPEND(AstNodeIndex, &p->scratch, var_decl_proto); 1999 } else { 2000 const AstNodeIndex expr = parseExpr(p); 2001 SLICE_APPEND(AstNodeIndex, &p->scratch, expr); 2002 } 2003 if (eatToken(p, TOKEN_COMMA) == null_token) 2004 break; 2005 } 2006 2007 const uint32_t lhs_count = p->scratch.len - scratch_top.old_len; 2008 assert(lhs_count > 0); 2009 2010 if (lhs_count == 1) { 2011 const AstNodeIndex lhs = p->scratch.arr[scratch_top.old_len]; 2012 switch (p->token_tags[p->tok_i]) { 2013 case TOKEN_SEMICOLON: 2014 p->tok_i++; 2015 return lhs; 2016 case TOKEN_R_BRACE: 2017 // Expression that doesn't need semicolon (block-terminated) 2018 return lhs; 2019 default: { 2020 const AstNodeTag assign_tag = assignOpTag(p->token_tags[p->tok_i]); 2021 if (assign_tag == AST_NODE_ROOT) { 2022 fprintf(stderr, 2023 "expectVarDeclExprStatement: unexpected token %s\n", 2024 tokenizerGetTagString(p->token_tags[p->tok_i])); 2025 exit(1); 2026 } 2027 if (assign_tag == AST_NODE_ASSIGN) { 2028 // Check if lhs is a var decl that needs initialization 2029 const AstNodeTag lhs_tag = p->nodes.tags[lhs]; 2030 if (lhs_tag == AST_NODE_SIMPLE_VAR_DECL 2031 || lhs_tag == AST_NODE_ALIGNED_VAR_DECL 2032 || lhs_tag == AST_NODE_LOCAL_VAR_DECL 2033 || lhs_tag == AST_NODE_GLOBAL_VAR_DECL) { 2034 p->tok_i++; 2035 p->nodes.datas[lhs].rhs = expectExpr(p); 2036 expectSemicolon(p); 2037 return lhs; 2038 } 2039 } 2040 const AstTokenIndex op_token = nextToken(p); 2041 const AstNodeIndex rhs = expectExpr(p); 2042 expectSemicolon(p); 2043 return addNode(&p->nodes, 2044 (AstNodeItem) { 2045 .tag = assign_tag, 2046 .main_token = op_token, 2047 .data = { .lhs = lhs, .rhs = rhs }, 2048 }); 2049 } 2050 } 2051 } 2052 2053 fprintf( 2054 stderr, "expectVarDeclExprStatement: destructuring not implemented\n"); 2055 exit(1); 2056 return 0; // tcc 2057 } 2058 2059 static AstNodeIndex expectStatement(Parser* p, bool allow_defer_var) { 2060 const AstTokenIndex comptime_token = eatToken(p, TOKEN_KEYWORD_COMPTIME); 2061 if (comptime_token != null_token) { 2062 // comptime followed by block => comptime block statement 2063 const AstNodeIndex block = parseBlock(p); 2064 if (block != 0) { 2065 return addNode(&p->nodes, 2066 (AstNodeItem) { 2067 .tag = AST_NODE_COMPTIME, 2068 .main_token = comptime_token, 2069 .data = { .lhs = block, .rhs = 0 }, 2070 }); 2071 } 2072 // comptime var decl or expression 2073 if (allow_defer_var) { 2074 return expectVarDeclExprStatement(p); 2075 } 2076 fprintf( 2077 stderr, "expectStatement: comptime keyword not supported here\n"); 2078 exit(1); 2079 } 2080 2081 const AstNodeIndex tok = p->token_tags[p->tok_i]; 2082 switch (tok) { 2083 case TOKEN_KEYWORD_DEFER: 2084 return addNode(&p->nodes, 2085 (AstNodeItem) { 2086 .tag = AST_NODE_DEFER, 2087 .main_token = nextToken(p), 2088 .data = { 2089 .lhs = expectBlockExprStatement(p), 2090 .rhs = 0, 2091 }, 2092 }); 2093 case TOKEN_KEYWORD_ERRDEFER: { 2094 const AstTokenIndex errdefer_token = nextToken(p); 2095 AstTokenIndex payload = null_token; 2096 if (p->token_tags[p->tok_i] == TOKEN_PIPE) { 2097 p->tok_i++; 2098 payload = expectToken(p, TOKEN_IDENTIFIER); 2099 expectToken(p, TOKEN_PIPE); 2100 } 2101 return addNode(&p->nodes, 2102 (AstNodeItem) { 2103 .tag = AST_NODE_ERRDEFER, 2104 .main_token = errdefer_token, 2105 .data = { 2106 .lhs = payload, 2107 .rhs = expectBlockExprStatement(p), 2108 }, 2109 }); 2110 } 2111 case TOKEN_KEYWORD_NOSUSPEND: 2112 return addNode(&p->nodes, 2113 (AstNodeItem) { 2114 .tag = AST_NODE_NOSUSPEND, 2115 .main_token = nextToken(p), 2116 .data = { 2117 .lhs = expectBlockExprStatement(p), 2118 .rhs = 0, 2119 }, 2120 }); 2121 case TOKEN_KEYWORD_SUSPEND: 2122 case TOKEN_KEYWORD_ENUM: 2123 case TOKEN_KEYWORD_STRUCT: 2124 case TOKEN_KEYWORD_UNION:; 2125 const char* tok_str = tokenizerGetTagString(tok); 2126 fprintf( 2127 stderr, "expectStatement does not support keyword %s\n", tok_str); 2128 exit(1); 2129 default:; 2130 } 2131 2132 const AstNodeIndex labeled_statement = parseLabeledStatement(p); 2133 if (labeled_statement != 0) 2134 return labeled_statement; 2135 2136 if (allow_defer_var) { 2137 return expectVarDeclExprStatement(p); 2138 } else { 2139 const AstNodeIndex assign_expr = parseAssignExpr(p); 2140 expectSemicolon(p); 2141 return assign_expr; 2142 } 2143 } 2144 2145 static AstNodeIndex parseBlock(Parser* p) { 2146 const AstNodeIndex lbrace = eatToken(p, TOKEN_L_BRACE); 2147 if (lbrace == null_token) 2148 return null_node; 2149 2150 CleanupScratch scratch_top __attribute__((__cleanup__(cleanupScratch))) 2151 = initCleanupScratch(p); 2152 2153 while (1) { 2154 if (p->token_tags[p->tok_i] == TOKEN_R_BRACE) 2155 break; 2156 2157 // "const AstNodeIndex statement" once tinycc supports typeof_unqual 2158 // (C23) 2159 AstNodeIndex statement = expectStatement(p, true); 2160 if (statement == 0) 2161 break; 2162 SLICE_APPEND(AstNodeIndex, &p->scratch, statement); 2163 } 2164 expectToken(p, TOKEN_R_BRACE); 2165 const bool semicolon = (p->token_tags[p->tok_i - 2] == TOKEN_SEMICOLON); 2166 2167 const uint32_t statements_len = p->scratch.len - scratch_top.old_len; 2168 switch (statements_len) { 2169 case 0: 2170 return addNode( 2171 &p->nodes, 2172 (AstNodeItem) { 2173 .tag = AST_NODE_BLOCK_TWO, 2174 .main_token = lbrace, 2175 .data = { 2176 .lhs = 0, 2177 .rhs = 0, 2178 }, 2179 }); 2180 case 1: 2181 return addNode( 2182 &p->nodes, 2183 (AstNodeItem) { 2184 .tag = semicolon ? AST_NODE_BLOCK_TWO_SEMICOLON : AST_NODE_BLOCK_TWO, 2185 .main_token = lbrace, 2186 .data = { 2187 .lhs = p->scratch.arr[scratch_top.old_len], 2188 .rhs = 0, 2189 }, 2190 }); 2191 case 2: 2192 return addNode( 2193 &p->nodes, 2194 (AstNodeItem) { 2195 .tag = semicolon ? AST_NODE_BLOCK_TWO_SEMICOLON : AST_NODE_BLOCK_TWO, 2196 .main_token = lbrace, 2197 .data = { 2198 .lhs = p->scratch.arr[scratch_top.old_len], 2199 .rhs = p->scratch.arr[scratch_top.old_len + 1], 2200 }, 2201 }); 2202 default:; 2203 const AstSubRange span = listToSpan( 2204 p, &p->scratch.arr[scratch_top.old_len], statements_len); 2205 return addNode( 2206 &p->nodes, 2207 (AstNodeItem) { 2208 .tag = semicolon ? AST_NODE_BLOCK_SEMICOLON : AST_NODE_BLOCK, 2209 .main_token = lbrace, 2210 .data = { 2211 .lhs = span.start, 2212 .rhs = span.end, 2213 }, 2214 }); 2215 } 2216 2217 return 0; 2218 } 2219 2220 static AstNodeIndex parseLabeledStatement(Parser* p) { 2221 const AstNodeIndex label_token = parseBlockLabel(p); 2222 const AstNodeIndex block = parseBlock(p); 2223 if (block != 0) 2224 return block; 2225 2226 const AstNodeIndex loop_stmt = parseLoopStatement(p); 2227 if (loop_stmt != 0) 2228 return loop_stmt; 2229 2230 if (label_token != 0) { 2231 fprintf(stderr, "parseLabeledStatement does not support labels\n"); 2232 exit(1); 2233 } 2234 2235 return null_node; 2236 } 2237 2238 static AstNodeIndex parseGlobalVarDecl(Parser* p) { 2239 const AstNodeIndex var_decl = parseVarDeclProto(p); 2240 if (var_decl == 0) { 2241 return null_node; 2242 } 2243 2244 if (eatToken(p, TOKEN_EQUAL) != null_token) { 2245 const AstNodeIndex init_expr = expectExpr(p); 2246 p->nodes.datas[var_decl].rhs = init_expr; 2247 } 2248 expectToken(p, TOKEN_SEMICOLON); 2249 return var_decl; 2250 } 2251 2252 static AstNodeIndex expectTopLevelDecl(Parser* p) { 2253 AstTokenIndex extern_export_inline_token = nextToken(p); 2254 2255 switch (p->token_tags[extern_export_inline_token]) { 2256 case TOKEN_KEYWORD_EXTERN: 2257 eatToken(p, TOKEN_STRING_LITERAL); 2258 break; 2259 case TOKEN_KEYWORD_EXPORT: 2260 case TOKEN_KEYWORD_INLINE: 2261 case TOKEN_KEYWORD_NOINLINE: 2262 break; 2263 default: 2264 p->tok_i--; 2265 } 2266 2267 AstNodeIndex fn_proto = parseFnProto(p); 2268 if (fn_proto != 0) { 2269 switch (p->token_tags[p->tok_i]) { 2270 case TOKEN_SEMICOLON: 2271 p->tok_i++; 2272 return fn_proto; 2273 case TOKEN_L_BRACE:; 2274 AstNodeIndex fn_decl_index = reserveNode(p, AST_NODE_FN_DECL); 2275 AstNodeIndex body_block = parseBlock(p); 2276 return setNode(p, fn_decl_index, 2277 (AstNodeItem) { 2278 .tag = AST_NODE_FN_DECL, 2279 .main_token = p->nodes.main_tokens[fn_proto], 2280 .data = { .lhs = fn_proto, .rhs = body_block }, 2281 }); 2282 default: 2283 exit(1); // Expected semicolon or left brace 2284 } 2285 } 2286 2287 eatToken(p, TOKEN_KEYWORD_THREADLOCAL); 2288 AstNodeIndex var_decl = parseGlobalVarDecl(p); 2289 if (var_decl != 0) { 2290 return var_decl; 2291 } 2292 2293 // assuming the program is correct... 2294 fprintf(stderr, 2295 "the next token should be usingnamespace, which is not supported\n"); 2296 exit(1); 2297 return 0; // make tcc happy 2298 } 2299 2300 static void findNextContainerMember(Parser* p) { 2301 uint32_t level = 0; 2302 2303 while (true) { 2304 AstTokenIndex tok = nextToken(p); 2305 2306 switch (p->token_tags[tok]) { 2307 // Any of these can start a new top level declaration 2308 case TOKEN_KEYWORD_TEST: 2309 case TOKEN_KEYWORD_COMPTIME: 2310 case TOKEN_KEYWORD_PUB: 2311 case TOKEN_KEYWORD_EXPORT: 2312 case TOKEN_KEYWORD_EXTERN: 2313 case TOKEN_KEYWORD_INLINE: 2314 case TOKEN_KEYWORD_NOINLINE: 2315 case TOKEN_KEYWORD_USINGNAMESPACE: 2316 case TOKEN_KEYWORD_THREADLOCAL: 2317 case TOKEN_KEYWORD_CONST: 2318 case TOKEN_KEYWORD_VAR: 2319 case TOKEN_KEYWORD_FN: 2320 if (level == 0) { 2321 p->tok_i--; 2322 return; 2323 } 2324 break; 2325 case TOKEN_IDENTIFIER: 2326 if (p->token_tags[tok + 1] == TOKEN_COMMA && level == 0) { 2327 p->tok_i--; 2328 return; 2329 } 2330 break; 2331 case TOKEN_COMMA: 2332 case TOKEN_SEMICOLON: 2333 // This decl was likely meant to end here 2334 if (level == 0) 2335 return; 2336 break; 2337 case TOKEN_L_PAREN: 2338 case TOKEN_L_BRACKET: 2339 case TOKEN_L_BRACE: 2340 level++; 2341 break; 2342 case TOKEN_R_PAREN: 2343 case TOKEN_R_BRACKET: 2344 if (level != 0) 2345 level--; 2346 break; 2347 case TOKEN_R_BRACE: 2348 if (level == 0) { 2349 // end of container, exit 2350 p->tok_i--; 2351 return; 2352 } 2353 level--; 2354 break; 2355 case TOKEN_EOF: 2356 p->tok_i--; 2357 return; 2358 default: 2359 break; 2360 } 2361 } 2362 } 2363 2364 static Members parseContainerMembers(Parser* p) { 2365 CleanupScratch scratch_top __attribute__((__cleanup__(cleanupScratch))) 2366 = initCleanupScratch(p); 2367 while (eatToken(p, TOKEN_CONTAINER_DOC_COMMENT) != null_token) 2368 ; 2369 2370 FieldState field_state = { .tag = FIELD_STATE_NONE }; 2371 2372 bool trailing = false; 2373 while (1) { 2374 eatDocComments(p); 2375 switch (p->token_tags[p->tok_i]) { 2376 case TOKEN_KEYWORD_TEST: { 2377 const AstTokenIndex test_token = nextToken(p); 2378 // test name can be a string literal or identifier, or omitted 2379 const AstTokenIndex test_name 2380 = (p->token_tags[p->tok_i] == TOKEN_STRING_LITERAL 2381 || p->token_tags[p->tok_i] == TOKEN_IDENTIFIER) 2382 ? nextToken(p) 2383 : null_token; 2384 const AstNodeIndex body = parseBlock(p); 2385 assert(body != 0); 2386 const AstNodeIndex test_decl = addNode(&p->nodes, 2387 (AstNodeItem) { 2388 .tag = AST_NODE_TEST_DECL, 2389 .main_token = test_token, 2390 .data = { .lhs = test_name, .rhs = body }, 2391 }); 2392 SLICE_APPEND(AstNodeIndex, &p->scratch, test_decl); 2393 trailing = p->token_tags[p->tok_i - 1] == TOKEN_R_BRACE; 2394 break; 2395 } 2396 case TOKEN_KEYWORD_USINGNAMESPACE:; 2397 const char* str = tokenizerGetTagString(p->token_tags[p->tok_i]); 2398 fprintf( 2399 stderr, "%s not implemented in parseContainerMembers\n", str); 2400 exit(1); 2401 case TOKEN_KEYWORD_COMPTIME: 2402 // comptime can be a container field modifier or a comptime 2403 // block/decl. Check if it's followed by a block (comptime { ... 2404 // }). 2405 if (p->token_tags[p->tok_i + 1] == TOKEN_L_BRACE) { 2406 const AstTokenIndex comptime_token = nextToken(p); 2407 const AstNodeIndex block_node = parseBlock(p); 2408 SLICE_APPEND(AstNodeIndex, &p->scratch, 2409 addNode(&p->nodes, 2410 (AstNodeItem) { 2411 .tag = AST_NODE_COMPTIME, 2412 .main_token = comptime_token, 2413 .data = { .lhs = block_node, .rhs = 0 }, 2414 })); 2415 trailing = false; 2416 break; 2417 } 2418 // Otherwise it's a container field with comptime modifier 2419 goto container_field; 2420 case TOKEN_KEYWORD_PUB: { 2421 p->tok_i++; 2422 AstNodeIndex top_level_decl = expectTopLevelDecl(p); 2423 if (top_level_decl != 0) { 2424 if (field_state.tag == FIELD_STATE_SEEN) { 2425 field_state.tag = FIELD_STATE_END; 2426 field_state.payload.end = top_level_decl; 2427 } 2428 SLICE_APPEND(AstNodeIndex, &p->scratch, top_level_decl); 2429 } 2430 trailing = p->token_tags[p->tok_i - 1] == TOKEN_SEMICOLON; 2431 break; 2432 } 2433 case TOKEN_KEYWORD_CONST: 2434 case TOKEN_KEYWORD_VAR: 2435 case TOKEN_KEYWORD_THREADLOCAL: 2436 case TOKEN_KEYWORD_EXPORT: 2437 case TOKEN_KEYWORD_EXTERN: 2438 case TOKEN_KEYWORD_INLINE: 2439 case TOKEN_KEYWORD_NOINLINE: 2440 case TOKEN_KEYWORD_FN: { 2441 const AstNodeIndex top_level_decl = expectTopLevelDecl(p); 2442 if (top_level_decl != 0) { 2443 if (field_state.tag == FIELD_STATE_SEEN) { 2444 field_state.tag = FIELD_STATE_END; 2445 field_state.payload.end = top_level_decl; 2446 } 2447 SLICE_APPEND(AstNodeIndex, &p->scratch, top_level_decl); 2448 } 2449 trailing = (p->token_tags[p->tok_i - 1] == TOKEN_SEMICOLON); 2450 break; 2451 } 2452 case TOKEN_EOF: 2453 case TOKEN_R_BRACE: 2454 goto break_loop; 2455 container_field: 2456 default:; 2457 // skip parseCStyleContainer 2458 const AstNodeIndex field_node = expectContainerField(p); 2459 switch (field_state.tag) { 2460 case FIELD_STATE_NONE: 2461 field_state.tag = FIELD_STATE_SEEN; 2462 break; 2463 case FIELD_STATE_SEEN: 2464 break; 2465 case FIELD_STATE_END: 2466 fprintf(stderr, "parseContainerMembers error condition\n"); 2467 exit(1); 2468 } 2469 SLICE_APPEND(AstNodeIndex, &p->scratch, field_node); 2470 switch (p->token_tags[p->tok_i]) { 2471 case TOKEN_COMMA: 2472 p->tok_i++; 2473 trailing = true; 2474 continue; 2475 case TOKEN_R_BRACE: 2476 case TOKEN_EOF: 2477 trailing = false; 2478 goto break_loop; 2479 default:; 2480 } 2481 2482 findNextContainerMember(p); 2483 continue; 2484 } 2485 } 2486 2487 break_loop:; 2488 2489 const uint32_t items_len = p->scratch.len - scratch_top.old_len; 2490 switch (items_len) { 2491 case 0: 2492 return (Members) { 2493 .len = 0, 2494 .lhs = 0, 2495 .rhs = 0, 2496 .trailing = trailing, 2497 }; 2498 case 1: 2499 return (Members) { 2500 .len = 1, 2501 .lhs = p->scratch.arr[scratch_top.old_len], 2502 .rhs = 0, 2503 .trailing = trailing, 2504 }; 2505 case 2: 2506 return (Members) { 2507 .len = 2, 2508 .lhs = p->scratch.arr[scratch_top.old_len], 2509 .rhs = p->scratch.arr[scratch_top.old_len + 1], 2510 .trailing = trailing, 2511 }; 2512 default:; 2513 const AstSubRange span 2514 = listToSpan(p, &p->scratch.arr[scratch_top.old_len], items_len); 2515 return (Members) { 2516 .len = items_len, 2517 .lhs = span.start, 2518 .rhs = span.end, 2519 .trailing = trailing, 2520 }; 2521 } 2522 } 2523 2524 void parseRoot(Parser* p) { 2525 addNode( 2526 &p->nodes, (AstNodeItem) { .tag = AST_NODE_ROOT, .main_token = 0 }); 2527 2528 Members root_members = parseContainerMembers(p); 2529 AstSubRange root_decls = membersToSpan(root_members, p); 2530 2531 p->nodes.datas[0].lhs = root_decls.start; 2532 p->nodes.datas[0].rhs = root_decls.end; 2533 }