parser.c (117904B) - Raw
1 2 #include "common.h" 3 4 #include <assert.h> 5 #include <ctype.h> 6 #include <stdlib.h> 7 #include <string.h> 8 9 #include "ast.h" 10 #include "parser.h" 11 12 const AstNodeIndex null_node = 0; 13 const AstTokenIndex null_token = ~(AstTokenIndex)(0); 14 15 // OPT encodes a node index as OptionalIndex: 0 → ~0 (none) 16 #define OPT(x) ((x) == 0 ? ~(AstNodeIndex)0 : (x)) 17 18 typedef struct { 19 uint32_t len; 20 AstNodeIndex lhs; 21 AstNodeIndex rhs; 22 bool trailing; 23 } Members; 24 25 typedef struct { 26 enum { FIELD_STATE_NONE, FIELD_STATE_SEEN, FIELD_STATE_END } tag; 27 union { 28 uint32_t end; 29 } payload; 30 } FieldState; 31 32 typedef struct { 33 enum { SMALL_SPAN_ZERO_OR_ONE, SMALL_SPAN_MULTI } tag; 34 union { 35 AstNodeIndex zero_or_one; 36 AstSubRange multi; 37 } payload; 38 } SmallSpan; 39 40 typedef struct { 41 AstNodeIndex align_node; 42 AstNodeIndex addrspace_node; 43 AstNodeIndex bit_range_start; 44 AstNodeIndex bit_range_end; 45 } PtrModifiers; 46 47 typedef struct { 48 int8_t prec; 49 AstNodeTag tag; 50 enum { 51 ASSOC_LEFT, 52 ASSOC_NONE, 53 } assoc; 54 } OperInfo; 55 56 typedef struct { 57 AstNodeIndex align_expr, value_expr; 58 } NodeContainerField; 59 60 static AstNodeIndex addExtra(Parser*, const AstNodeIndex*, uint32_t); 61 static AstNodeIndex addNode(AstNodeList*, AstNodeItem); 62 static AstNodeTag assignOpNode(TokenizerTag); 63 static AstTokenIndex assertToken(Parser*, TokenizerTag); 64 static void astNodeListEnsureCapacity(AstNodeList*, uint32_t); 65 static AstTokenIndex eatDocComments(Parser*); 66 static AstTokenIndex eatToken(Parser*, TokenizerTag); 67 static AstNodeIndex expectBlockExprStatement(Parser*); 68 static AstNodeIndex expectContainerField(Parser*); 69 static AstNodeIndex expectExpr(Parser*); 70 static AstNodeIndex expectIfStatement(Parser*); 71 static AstNodeIndex expectParamDecl(Parser*); 72 static AstNodeIndex expectSemicolon(Parser*); 73 static AstNodeIndex expectStatement(Parser*, bool); 74 static AstNodeIndex expectTestDecl(Parser*); 75 static AstTokenIndex expectToken(Parser*, TokenizerTag); 76 static AstNodeIndex expectTopLevelDecl(Parser*); 77 static AstNodeIndex expectVarDeclExprStatement(Parser*, AstTokenIndex); 78 static void findNextContainerMember(Parser*); 79 static AstNodeIndex finishAssignExpr(Parser*, AstNodeIndex); 80 static uint32_t forPrefix(Parser*); 81 static AstSubRange listToSpan(Parser*, const AstNodeIndex*, uint32_t); 82 static AstNodeIndex makePtrTypeNode( 83 Parser*, AstTokenIndex, AstNodeIndex, PtrModifiers, AstNodeIndex); 84 static AstSubRange membersToSpan(const Members, Parser*); 85 static AstTokenIndex nextToken(Parser*); 86 static OperInfo operTable(TokenizerTag); 87 static AstNodeIndex parseAddrSpace(Parser*); 88 static AstNodeIndex parseAsmExpr(Parser*); 89 static AstNodeIndex parseAsmInputItem(Parser*); 90 static AstNodeIndex parseAsmOutputItem(Parser*); 91 static AstNodeIndex parseAssignExpr(Parser*); 92 static AstNodeIndex parseBlock(Parser*); 93 static AstNodeIndex parseBlockExpr(Parser*); 94 static AstTokenIndex parseBlockLabel(Parser*); 95 static AstTokenIndex parseBreakLabel(Parser*); 96 static AstNodeIndex parseBuiltinCall(Parser*); 97 static AstNodeIndex parseByteAlign(Parser*); 98 static AstNodeIndex parseCallconv(Parser*); 99 static AstNodeIndex parseContainerDeclAuto(Parser*); 100 static Members parseContainerMembers(Parser*); 101 static AstNodeIndex parseCurlySuffixExpr(Parser*); 102 static AstNodeIndex parseErrorUnionExpr(Parser*); 103 static AstNodeIndex parseExpr(Parser*); 104 static AstNodeIndex parseExprPrecedence(Parser*, int32_t); 105 static AstNodeIndex parseFieldInit(Parser*); 106 static AstNodeIndex parseFnProto(Parser*); 107 static AstNodeIndex parseForExpr(Parser*); 108 static AstNodeIndex parseForStatement(Parser*); 109 static AstNodeIndex parseGlobalVarDecl(Parser*); 110 static AstNodeIndex parseIfExpr(Parser*); 111 static AstNodeIndex parseInitList(Parser*, AstNodeIndex, AstTokenIndex); 112 static AstNodeIndex parseLabeledStatement(Parser*); 113 static AstNodeIndex parseLinkSection(Parser*); 114 static AstNodeIndex parseLoopStatement(Parser*); 115 static SmallSpan parseParamDeclList(Parser*); 116 static void parsePayload(Parser*); 117 static AstNodeIndex parsePrefixExpr(Parser*); 118 static AstNodeIndex parsePrimaryExpr(Parser*); 119 static AstNodeIndex parsePrimaryTypeExpr(Parser*); 120 static PtrModifiers parsePtrModifiers(Parser*); 121 static void parsePtrPayload(Parser*); 122 static AstNodeIndex parseSingleAssignExpr(Parser*); 123 static AstNodeIndex parseSuffixExpr(Parser*); 124 static AstNodeIndex parseSuffixOp(Parser*, AstNodeIndex); 125 static AstNodeIndex parseSwitchExpr(Parser*); 126 static AstNodeIndex parseSwitchItem(Parser*); 127 static AstNodeIndex parseSwitchProng(Parser*); 128 static AstSubRange parseSwitchProngList(Parser*); 129 static AstNodeIndex parseTypeExpr(Parser*); 130 static AstNodeIndex parseVarDeclProto(Parser*); 131 static AstNodeIndex parseWhileContinueExpr(Parser*); 132 static AstNodeIndex parseWhileExpr(Parser*); 133 static AstNodeIndex parseWhileStatement(Parser*); 134 static uint32_t reserveNode(Parser*, AstNodeTag); 135 static AstNodeIndex setNode(Parser*, uint32_t, AstNodeItem); 136 static uint32_t tokenTagLexemeLen(TokenizerTag); 137 static bool tokensOnSameLine(Parser*, AstTokenIndex, AstTokenIndex); 138 139 static AstSubRange membersToSpan(const Members self, Parser* p) { 140 if (self.len <= 2) { 141 const AstNodeIndex nodes[] = { self.lhs, self.rhs }; 142 return listToSpan(p, nodes, self.len); 143 } else { 144 return (AstSubRange) { .start = self.lhs, .end = self.rhs }; 145 } 146 } 147 148 static AstSubRange listToSpan( 149 Parser* p, const AstNodeIndex* list, uint32_t count) { 150 SLICE_ENSURE_CAPACITY(AstNodeIndex, &p->extra_data, count); 151 memcpy(p->extra_data.arr + p->extra_data.len, list, 152 count * sizeof(AstNodeIndex)); 153 p->extra_data.len += count; 154 return (AstSubRange) { 155 .start = p->extra_data.len - count, 156 .end = p->extra_data.len, 157 }; 158 } 159 160 static AstNodeIndex addNode(AstNodeList* nodes, AstNodeItem item) { 161 astNodeListEnsureCapacity(nodes, 1); 162 nodes->tags[nodes->len] = item.tag; 163 nodes->main_tokens[nodes->len] = item.main_token; 164 nodes->datas[nodes->len] = item.data; 165 return nodes->len++; 166 } 167 168 static AstNodeIndex setNode(Parser* p, uint32_t i, AstNodeItem item) { 169 p->nodes.tags[i] = item.tag; 170 p->nodes.main_tokens[i] = item.main_token; 171 p->nodes.datas[i] = item.data; 172 return i; 173 } 174 175 static uint32_t reserveNode(Parser* p, AstNodeTag tag) { 176 astNodeListEnsureCapacity(&p->nodes, 1); 177 p->nodes.len++; 178 p->nodes.tags[p->nodes.len - 1] = tag; 179 return p->nodes.len - 1; 180 } 181 182 static AstNodeIndex addExtra( 183 Parser* p, const AstNodeIndex* extra, uint32_t count) { 184 const AstNodeIndex result = p->extra_data.len; 185 SLICE_ENSURE_CAPACITY(AstNodeIndex, &p->extra_data, count); 186 memcpy(p->extra_data.arr + p->extra_data.len, extra, 187 count * sizeof(AstNodeIndex)); 188 p->extra_data.len += count; 189 return result; 190 } 191 192 static void astNodeListEnsureCapacity(AstNodeList* list, uint32_t additional) { 193 const uint32_t new_len = list->len + additional; 194 if (new_len <= list->cap) { 195 return; 196 } 197 198 const uint32_t new_cap = new_len > list->cap * 2 ? new_len : list->cap * 2; 199 list->tags = realloc(list->tags, new_cap * sizeof(AstNodeTag)); 200 list->main_tokens 201 = realloc(list->main_tokens, new_cap * sizeof(AstTokenIndex)); 202 list->datas = realloc(list->datas, new_cap * sizeof(AstData)); 203 if (!list->tags || !list->main_tokens || !list->datas) 204 exit(1); 205 list->cap = new_cap; 206 } 207 208 void parseRoot(Parser* p) { 209 addNode( 210 &p->nodes, (AstNodeItem) { .tag = AST_NODE_ROOT, .main_token = 0 }); 211 212 Members root_members = parseContainerMembers(p); 213 AstSubRange root_decls = membersToSpan(root_members, p); 214 215 if (p->token_tags[p->tok_i] != TOKEN_EOF) { 216 fail(p, "expected EOF"); 217 } 218 219 p->nodes.datas[0].lhs = root_decls.start; 220 p->nodes.datas[0].rhs = root_decls.end; 221 } 222 223 static Members parseContainerMembers(Parser* p) { 224 const uint32_t scratch_top = p->scratch.len; 225 while (eatToken(p, TOKEN_CONTAINER_DOC_COMMENT) != null_token) 226 ; 227 228 FieldState field_state = { .tag = FIELD_STATE_NONE }; 229 230 bool trailing = false; 231 while (1) { 232 const AstTokenIndex doc_comment = eatDocComments(p); 233 switch (p->token_tags[p->tok_i]) { 234 case TOKEN_KEYWORD_TEST: { 235 if (doc_comment != null_token) 236 fail(p, "test_doc_comment"); 237 const AstNodeIndex test_decl = expectTestDecl(p); 238 if (field_state.tag == FIELD_STATE_SEEN) { 239 field_state.tag = FIELD_STATE_END; 240 field_state.payload.end = test_decl; 241 } 242 SLICE_APPEND(AstNodeIndex, &p->scratch, test_decl); 243 trailing = false; 244 break; 245 } 246 case TOKEN_KEYWORD_COMPTIME: 247 // comptime can be a container field modifier or a comptime 248 // block/decl. Check if it's followed by a block (comptime { ... 249 // }). 250 if (p->token_tags[p->tok_i + 1] == TOKEN_L_BRACE) { 251 if (doc_comment != null_token) { 252 fail(p, "comptime_doc_comment"); 253 } 254 const AstTokenIndex comptime_token = nextToken(p); 255 const AstNodeIndex block_node = parseBlock(p); 256 SLICE_APPEND(AstNodeIndex, &p->scratch, 257 addNode(&p->nodes, 258 (AstNodeItem) { 259 .tag = AST_NODE_COMPTIME, 260 .main_token = comptime_token, 261 .data = { .lhs = block_node, .rhs = 0 }, 262 })); 263 trailing = false; 264 break; 265 } 266 // Otherwise it's a container field with comptime modifier 267 goto container_field; 268 case TOKEN_KEYWORD_PUB: { 269 p->tok_i++; 270 AstNodeIndex top_level_decl = expectTopLevelDecl(p); 271 if (top_level_decl != 0) { 272 if (field_state.tag == FIELD_STATE_SEEN) { 273 field_state.tag = FIELD_STATE_END; 274 field_state.payload.end = top_level_decl; 275 } 276 SLICE_APPEND(AstNodeIndex, &p->scratch, top_level_decl); 277 } 278 trailing = p->token_tags[p->tok_i - 1] == TOKEN_SEMICOLON; 279 break; 280 } 281 case TOKEN_KEYWORD_CONST: 282 case TOKEN_KEYWORD_VAR: 283 case TOKEN_KEYWORD_THREADLOCAL: 284 case TOKEN_KEYWORD_EXPORT: 285 case TOKEN_KEYWORD_EXTERN: 286 case TOKEN_KEYWORD_INLINE: 287 case TOKEN_KEYWORD_NOINLINE: 288 case TOKEN_KEYWORD_FN: { 289 const AstNodeIndex top_level_decl = expectTopLevelDecl(p); 290 if (top_level_decl != 0) { 291 if (field_state.tag == FIELD_STATE_SEEN) { 292 field_state.tag = FIELD_STATE_END; 293 field_state.payload.end = top_level_decl; 294 } 295 SLICE_APPEND(AstNodeIndex, &p->scratch, top_level_decl); 296 } 297 trailing = (p->token_tags[p->tok_i - 1] == TOKEN_SEMICOLON); 298 break; 299 } 300 case TOKEN_EOF: 301 case TOKEN_R_BRACE: 302 goto break_loop; 303 container_field: 304 default:; 305 // skip parseCStyleContainer 306 const AstNodeIndex field_node = expectContainerField(p); 307 switch (field_state.tag) { 308 case FIELD_STATE_NONE: 309 field_state.tag = FIELD_STATE_SEEN; 310 break; 311 case FIELD_STATE_SEEN: 312 break; 313 case FIELD_STATE_END: 314 fail(p, "parseContainerMembers error condition"); 315 } 316 SLICE_APPEND(AstNodeIndex, &p->scratch, field_node); 317 switch (p->token_tags[p->tok_i]) { 318 case TOKEN_COMMA: 319 p->tok_i++; 320 trailing = true; 321 continue; 322 case TOKEN_R_BRACE: 323 case TOKEN_EOF: 324 trailing = false; 325 goto break_loop; 326 default: 327 fail(p, "expected comma after field"); 328 } 329 } 330 } 331 332 break_loop:; 333 334 const uint32_t items_len = p->scratch.len - scratch_top; 335 p->scratch.len = scratch_top; 336 switch (items_len) { 337 case 0: 338 return (Members) { 339 .len = 0, 340 .lhs = 0, 341 .rhs = 0, 342 .trailing = trailing, 343 }; 344 case 1: 345 return (Members) { 346 .len = 1, 347 .lhs = p->scratch.arr[scratch_top], 348 .rhs = 0, 349 .trailing = trailing, 350 }; 351 case 2: 352 return (Members) { 353 .len = 2, 354 .lhs = p->scratch.arr[scratch_top], 355 .rhs = p->scratch.arr[scratch_top + 1], 356 .trailing = trailing, 357 }; 358 default:; 359 const AstSubRange span 360 = listToSpan(p, &p->scratch.arr[scratch_top], items_len); 361 return (Members) { 362 .len = items_len, 363 .lhs = span.start, 364 .rhs = span.end, 365 .trailing = trailing, 366 }; 367 } 368 } 369 370 static void findNextContainerMember(Parser* p) { 371 uint32_t level = 0; 372 373 while (true) { 374 AstTokenIndex tok = nextToken(p); 375 376 switch (p->token_tags[tok]) { 377 // Any of these can start a new top level declaration 378 case TOKEN_KEYWORD_TEST: 379 case TOKEN_KEYWORD_COMPTIME: 380 case TOKEN_KEYWORD_PUB: 381 case TOKEN_KEYWORD_EXPORT: 382 case TOKEN_KEYWORD_EXTERN: 383 case TOKEN_KEYWORD_INLINE: 384 case TOKEN_KEYWORD_NOINLINE: 385 case TOKEN_KEYWORD_THREADLOCAL: 386 case TOKEN_KEYWORD_CONST: 387 case TOKEN_KEYWORD_VAR: 388 case TOKEN_KEYWORD_FN: 389 if (level == 0) { 390 p->tok_i--; 391 return; 392 } 393 break; 394 case TOKEN_IDENTIFIER: 395 if (p->token_tags[tok + 1] == TOKEN_COMMA && level == 0) { 396 p->tok_i--; 397 return; 398 } 399 break; 400 case TOKEN_COMMA: 401 case TOKEN_SEMICOLON: 402 // This decl was likely meant to end here 403 if (level == 0) 404 return; 405 break; 406 case TOKEN_L_PAREN: 407 case TOKEN_L_BRACKET: 408 case TOKEN_L_BRACE: 409 level++; 410 break; 411 case TOKEN_R_PAREN: 412 case TOKEN_R_BRACKET: 413 if (level != 0) 414 level--; 415 break; 416 case TOKEN_R_BRACE: 417 if (level == 0) { 418 // end of container, exit 419 p->tok_i--; 420 return; 421 } 422 level--; 423 break; 424 case TOKEN_EOF: 425 p->tok_i--; 426 return; 427 default: 428 break; 429 } 430 } 431 } 432 433 static AstNodeIndex expectTestDecl(Parser* p) { 434 const AstTokenIndex test_token = assertToken(p, TOKEN_KEYWORD_TEST); 435 const AstTokenIndex test_name 436 = (p->token_tags[p->tok_i] == TOKEN_STRING_LITERAL 437 || p->token_tags[p->tok_i] == TOKEN_IDENTIFIER) 438 ? nextToken(p) 439 : null_token; 440 const AstNodeIndex body = parseBlock(p); 441 if (body == 0) 442 fail(p, "expected block after test"); 443 return addNode(&p->nodes, 444 (AstNodeItem) { 445 .tag = AST_NODE_TEST_DECL, 446 .main_token = test_token, 447 .data = { .lhs = test_name, .rhs = body }, 448 }); 449 } 450 451 static AstNodeIndex expectTopLevelDecl(Parser* p) { 452 AstTokenIndex extern_export_inline_token = nextToken(p); 453 bool is_extern = false; 454 455 switch (p->token_tags[extern_export_inline_token]) { 456 case TOKEN_KEYWORD_EXTERN: 457 eatToken(p, TOKEN_STRING_LITERAL); 458 is_extern = true; 459 break; 460 case TOKEN_KEYWORD_EXPORT: 461 case TOKEN_KEYWORD_INLINE: 462 case TOKEN_KEYWORD_NOINLINE: 463 break; 464 default: 465 p->tok_i--; 466 } 467 468 AstNodeIndex fn_proto = parseFnProto(p); 469 if (fn_proto != 0) { 470 switch (p->token_tags[p->tok_i]) { 471 case TOKEN_SEMICOLON: 472 p->tok_i++; 473 return fn_proto; 474 case TOKEN_L_BRACE:; 475 if (is_extern) { 476 fail(p, "extern_fn_body"); 477 } 478 AstNodeIndex fn_decl_index = reserveNode(p, AST_NODE_FN_DECL); 479 AstNodeIndex body_block = parseBlock(p); 480 return setNode(p, fn_decl_index, 481 (AstNodeItem) { 482 .tag = AST_NODE_FN_DECL, 483 .main_token = p->nodes.main_tokens[fn_proto], 484 .data = { .lhs = fn_proto, .rhs = body_block }, 485 }); 486 default: 487 fail(p, "expected semicolon or lbrace"); 488 } 489 } 490 491 eatToken(p, TOKEN_KEYWORD_THREADLOCAL); 492 AstNodeIndex var_decl = parseGlobalVarDecl(p); 493 if (var_decl != 0) { 494 return var_decl; 495 } 496 497 // assuming the program is correct... 498 fail(p, "the next token should be usingnamespace, which is not supported"); 499 return 0; // make tcc happy 500 } 501 502 static AstNodeIndex parseFnProto(Parser* p) { 503 AstTokenIndex fn_token = eatToken(p, TOKEN_KEYWORD_FN); 504 if (fn_token == null_token) 505 return null_node; 506 507 AstNodeIndex fn_proto_index = reserveNode(p, AST_NODE_FN_PROTO); 508 509 eatToken(p, TOKEN_IDENTIFIER); 510 511 SmallSpan params = parseParamDeclList(p); 512 const AstNodeIndex align_expr = parseByteAlign(p); 513 const AstNodeIndex addrspace_expr = parseAddrSpace(p); 514 const AstNodeIndex section_expr = parseLinkSection(p); 515 const AstNodeIndex callconv_expr = parseCallconv(p); 516 eatToken(p, TOKEN_BANG); 517 518 const AstNodeIndex return_type_expr = parseTypeExpr(p); 519 if (return_type_expr == 0) { 520 fail(p, "expected_return_type"); 521 } 522 523 if (align_expr == 0 && section_expr == 0 && callconv_expr == 0 524 && addrspace_expr == 0) { 525 switch (params.tag) { 526 case SMALL_SPAN_ZERO_OR_ONE: 527 return setNode(p, fn_proto_index, 528 (AstNodeItem) { 529 .tag = AST_NODE_FN_PROTO_SIMPLE, 530 .main_token = fn_token, 531 .data = { 532 .lhs = params.payload.zero_or_one, 533 .rhs = return_type_expr, 534 }, 535 }); 536 case SMALL_SPAN_MULTI: 537 return setNode(p, fn_proto_index, 538 (AstNodeItem) { 539 .tag = AST_NODE_FN_PROTO_MULTI, 540 .main_token = fn_token, 541 .data = { 542 .lhs = addExtra(p, 543 (AstNodeIndex[]) { 544 params.payload.multi.start, 545 params.payload.multi.end }, 546 2), 547 .rhs = return_type_expr, 548 }, 549 }); 550 } 551 } 552 553 // Complex fn proto with align/section/callconv/addrspace 554 switch (params.tag) { 555 case SMALL_SPAN_ZERO_OR_ONE: 556 return setNode(p, fn_proto_index, 557 (AstNodeItem) { 558 .tag = AST_NODE_FN_PROTO_ONE, 559 .main_token = fn_token, 560 .data = { 561 .lhs = addExtra(p, 562 (AstNodeIndex[]) { 563 OPT(params.payload.zero_or_one), 564 OPT(align_expr), OPT(addrspace_expr), 565 OPT(section_expr), OPT(callconv_expr) }, 566 5), 567 .rhs = return_type_expr, 568 }, 569 }); 570 case SMALL_SPAN_MULTI: 571 return setNode(p, fn_proto_index, 572 (AstNodeItem) { 573 .tag = AST_NODE_FN_PROTO, 574 .main_token = fn_token, 575 .data = { 576 .lhs = addExtra(p, 577 (AstNodeIndex[]) { 578 params.payload.multi.start, 579 params.payload.multi.end, 580 OPT(align_expr), OPT(addrspace_expr), 581 OPT(section_expr), OPT(callconv_expr) }, 582 6), 583 .rhs = return_type_expr, 584 }, 585 }); 586 } 587 return 0; // tcc 588 } 589 590 static AstNodeIndex parseVarDeclProto(Parser* p) { 591 AstTokenIndex mut_token; 592 if ((mut_token = eatToken(p, TOKEN_KEYWORD_CONST)) == null_token) 593 if ((mut_token = eatToken(p, TOKEN_KEYWORD_VAR)) == null_token) 594 return null_node; 595 596 expectToken(p, TOKEN_IDENTIFIER); 597 const AstNodeIndex type_node 598 = eatToken(p, TOKEN_COLON) == null_token ? 0 : parseTypeExpr(p); 599 const AstNodeIndex align_node = parseByteAlign(p); 600 const AstNodeIndex addrspace_node = parseAddrSpace(p); 601 const AstNodeIndex section_node = parseLinkSection(p); 602 603 if (section_node == 0 && addrspace_node == 0) { 604 if (align_node == 0) { 605 return addNode(&p->nodes, 606 (AstNodeItem) { 607 .tag = AST_NODE_SIMPLE_VAR_DECL, 608 .main_token = mut_token, 609 .data = { .lhs = type_node, .rhs = 0 }, 610 }); 611 } 612 if (type_node == 0) { 613 return addNode(&p->nodes, 614 (AstNodeItem) { 615 .tag = AST_NODE_ALIGNED_VAR_DECL, 616 .main_token = mut_token, 617 .data = { .lhs = align_node, .rhs = 0 }, 618 }); 619 } 620 return addNode(&p->nodes, 621 (AstNodeItem) { 622 .tag = AST_NODE_LOCAL_VAR_DECL, 623 .main_token = mut_token, 624 .data = { 625 .lhs = addExtra(p, 626 (AstNodeIndex[]) { type_node, align_node }, 2), 627 .rhs = 0, 628 }, 629 }); 630 } 631 return addNode(&p->nodes, 632 (AstNodeItem) { 633 .tag = AST_NODE_GLOBAL_VAR_DECL, 634 .main_token = mut_token, 635 .data = { 636 .lhs = addExtra(p, 637 (AstNodeIndex[]) { OPT(type_node), OPT(align_node), 638 OPT(addrspace_node), OPT(section_node) }, 639 4), 640 .rhs = 0, 641 }, 642 }); 643 } 644 645 static AstNodeIndex parseGlobalVarDecl(Parser* p) { 646 const AstNodeIndex var_decl = parseVarDeclProto(p); 647 if (var_decl == 0) { 648 return null_node; 649 } 650 651 if (eatToken(p, TOKEN_EQUAL) != null_token) { 652 const AstNodeIndex init_expr = expectExpr(p); 653 p->nodes.datas[var_decl].rhs = init_expr; 654 } 655 expectToken(p, TOKEN_SEMICOLON); 656 return var_decl; 657 } 658 659 static AstNodeIndex expectContainerField(Parser* p) { 660 eatToken(p, TOKEN_KEYWORD_COMPTIME); 661 const AstTokenIndex main_token = p->tok_i; 662 if (p->token_tags[p->tok_i] == TOKEN_IDENTIFIER 663 && p->token_tags[p->tok_i + 1] == TOKEN_COLON) 664 p->tok_i += 2; 665 666 const AstNodeIndex type_expr = parseTypeExpr(p); 667 if (type_expr == 0) { 668 fail(p, "expected type expression"); 669 } 670 const AstNodeIndex align_expr = parseByteAlign(p); 671 const AstNodeIndex value_expr 672 = eatToken(p, TOKEN_EQUAL) != null_token ? expectExpr(p) : 0; 673 674 if (align_expr == 0) { 675 return addNode( 676 &p->nodes, 677 (AstNodeItem) { 678 .tag = AST_NODE_CONTAINER_FIELD_INIT, 679 .main_token = main_token, 680 .data = { 681 .lhs = type_expr, 682 .rhs = value_expr, 683 }, 684 }); 685 } else if (value_expr == 0) { 686 return addNode( 687 &p->nodes, 688 (AstNodeItem) { 689 .tag = AST_NODE_CONTAINER_FIELD_ALIGN, 690 .main_token = main_token, 691 .data = { 692 .lhs = type_expr, 693 .rhs = align_expr, 694 }, 695 }); 696 } else { 697 return addNode( 698 &p->nodes, 699 (AstNodeItem) { 700 .tag = AST_NODE_CONTAINER_FIELD, 701 .main_token = main_token, 702 .data = { 703 .lhs = type_expr, 704 .rhs = addExtra(p, (AstNodeIndex[]) { align_expr, value_expr }, 2), 705 }, 706 }); 707 } 708 } 709 710 static AstNodeIndex expectStatement(Parser* p, bool allow_defer_var) { 711 const AstTokenIndex comptime_token = eatToken(p, TOKEN_KEYWORD_COMPTIME); 712 if (comptime_token != null_token) { 713 // comptime followed by block => comptime block statement 714 const AstNodeIndex block = parseBlockExpr(p); 715 if (block != 0) { 716 return addNode(&p->nodes, 717 (AstNodeItem) { 718 .tag = AST_NODE_COMPTIME, 719 .main_token = comptime_token, 720 .data = { .lhs = block, .rhs = 0 }, 721 }); 722 } 723 // comptime var decl or expression 724 if (allow_defer_var) 725 return expectVarDeclExprStatement(p, comptime_token); 726 { 727 const AstNodeIndex assign = parseAssignExpr(p); 728 if (assign == 0) { 729 fail(p, "expected expression"); 730 } 731 expectSemicolon(p); 732 return addNode(&p->nodes, 733 (AstNodeItem) { 734 .tag = AST_NODE_COMPTIME, 735 .main_token = comptime_token, 736 .data = { .lhs = assign, .rhs = 0 }, 737 }); 738 } 739 } 740 741 const AstNodeIndex tok = p->token_tags[p->tok_i]; 742 switch (tok) { 743 case TOKEN_KEYWORD_DEFER: 744 if (allow_defer_var) 745 return addNode(&p->nodes, 746 (AstNodeItem) { 747 .tag = AST_NODE_DEFER, 748 .main_token = nextToken(p), 749 .data = { 750 .lhs = expectBlockExprStatement(p), 751 .rhs = 0, 752 }, 753 }); 754 break; 755 case TOKEN_KEYWORD_ERRDEFER: 756 if (allow_defer_var) { 757 const AstTokenIndex errdefer_token = nextToken(p); 758 AstTokenIndex payload = null_token; 759 if (p->token_tags[p->tok_i] == TOKEN_PIPE) { 760 p->tok_i++; 761 payload = expectToken(p, TOKEN_IDENTIFIER); 762 expectToken(p, TOKEN_PIPE); 763 } 764 return addNode(&p->nodes, 765 (AstNodeItem) { 766 .tag = AST_NODE_ERRDEFER, 767 .main_token = errdefer_token, 768 .data = { 769 .lhs = payload, 770 .rhs = expectBlockExprStatement(p), 771 }, 772 }); 773 } 774 break; 775 case TOKEN_KEYWORD_NOSUSPEND: 776 return addNode(&p->nodes, 777 (AstNodeItem) { 778 .tag = AST_NODE_NOSUSPEND, 779 .main_token = nextToken(p), 780 .data = { 781 .lhs = expectBlockExprStatement(p), 782 .rhs = 0, 783 }, 784 }); 785 case TOKEN_KEYWORD_SUSPEND: 786 return addNode(&p->nodes, 787 (AstNodeItem) { 788 .tag = AST_NODE_SUSPEND, 789 .main_token = nextToken(p), 790 .data = { 791 .lhs = expectBlockExprStatement(p), 792 .rhs = 0, 793 }, 794 }); 795 case TOKEN_KEYWORD_IF: 796 return expectIfStatement(p); 797 case TOKEN_KEYWORD_ENUM: 798 case TOKEN_KEYWORD_STRUCT: 799 case TOKEN_KEYWORD_UNION:; 800 fail(p, "unsupported statement keyword"); 801 default:; 802 } 803 804 const AstNodeIndex labeled_statement = parseLabeledStatement(p); 805 if (labeled_statement != 0) 806 return labeled_statement; 807 808 if (allow_defer_var) { 809 return expectVarDeclExprStatement(p, null_token); 810 } else { 811 const AstNodeIndex assign_expr = parseAssignExpr(p); 812 expectSemicolon(p); 813 return assign_expr; 814 } 815 } 816 817 static AstNodeIndex expectVarDeclExprStatement( 818 Parser* p, AstTokenIndex comptime_token) { 819 const uint32_t scratch_top = p->scratch.len; 820 821 while (true) { 822 const AstNodeIndex var_decl_proto = parseVarDeclProto(p); 823 if (var_decl_proto != 0) { 824 SLICE_APPEND(AstNodeIndex, &p->scratch, var_decl_proto); 825 } else { 826 const AstNodeIndex expr = parseExpr(p); 827 SLICE_APPEND(AstNodeIndex, &p->scratch, expr); 828 } 829 if (eatToken(p, TOKEN_COMMA) == null_token) 830 break; 831 } 832 833 const uint32_t lhs_count = p->scratch.len - scratch_top; 834 assert(lhs_count > 0); 835 836 // Try to eat '=' for assignment/initialization 837 // (matches upstream: `const equal_token = p.eatToken(.equal) orelse eql:`) 838 AstTokenIndex equal_token = eatToken(p, TOKEN_EQUAL); 839 if (equal_token == null_token) { 840 if (lhs_count > 1) { 841 // Destructure requires '=' 842 fail(p, "expected '='"); 843 } 844 const AstNodeIndex lhs = p->scratch.arr[scratch_top]; 845 p->scratch.len = scratch_top; 846 const AstNodeTag lhs_tag = p->nodes.tags[lhs]; 847 if (lhs_tag == AST_NODE_SIMPLE_VAR_DECL 848 || lhs_tag == AST_NODE_ALIGNED_VAR_DECL 849 || lhs_tag == AST_NODE_LOCAL_VAR_DECL 850 || lhs_tag == AST_NODE_GLOBAL_VAR_DECL) { 851 // var decl without init requires '=' 852 fail(p, "expected '='"); 853 } 854 // Expression statement: finish with assignment operators or semicolon 855 const AstNodeIndex expr = finishAssignExpr(p, lhs); 856 // Semicolon is optional for block-terminated expressions 857 eatToken(p, TOKEN_SEMICOLON); 858 if (comptime_token != null_token) { 859 return addNode(&p->nodes, 860 (AstNodeItem) { 861 .tag = AST_NODE_COMPTIME, 862 .main_token = comptime_token, 863 .data = { .lhs = expr, .rhs = 0 }, 864 }); 865 } 866 return expr; 867 } 868 869 // Have '=', parse RHS and semicolon 870 const AstNodeIndex rhs = expectExpr(p); 871 expectSemicolon(p); 872 873 if (lhs_count == 1) { 874 const AstNodeIndex lhs = p->scratch.arr[scratch_top]; 875 p->scratch.len = scratch_top; 876 const AstNodeTag lhs_tag = p->nodes.tags[lhs]; 877 if (lhs_tag == AST_NODE_SIMPLE_VAR_DECL 878 || lhs_tag == AST_NODE_ALIGNED_VAR_DECL 879 || lhs_tag == AST_NODE_LOCAL_VAR_DECL 880 || lhs_tag == AST_NODE_GLOBAL_VAR_DECL) { 881 // var decl initialization: const x = val; 882 p->nodes.datas[lhs].rhs = rhs; 883 return lhs; 884 } 885 // Simple assignment: x = val; 886 const AstNodeIndex assign = addNode(&p->nodes, 887 (AstNodeItem) { 888 .tag = AST_NODE_ASSIGN, 889 .main_token = equal_token, 890 .data = { .lhs = lhs, .rhs = rhs }, 891 }); 892 if (comptime_token != null_token) { 893 return addNode(&p->nodes, 894 (AstNodeItem) { 895 .tag = AST_NODE_COMPTIME, 896 .main_token = comptime_token, 897 .data = { .lhs = assign, .rhs = 0 }, 898 }); 899 } 900 return assign; 901 } 902 903 // Destructure: a, b, c = rhs 904 // rhs and semicolon already parsed above 905 906 // Store count + lhs nodes in extra_data 907 const AstNodeIndex extra_start = p->extra_data.len; 908 SLICE_ENSURE_CAPACITY(AstNodeIndex, &p->extra_data, lhs_count + 1); 909 p->extra_data.arr[p->extra_data.len++] = lhs_count; 910 memcpy(p->extra_data.arr + p->extra_data.len, &p->scratch.arr[scratch_top], 911 lhs_count * sizeof(AstNodeIndex)); 912 p->extra_data.len += lhs_count; 913 p->scratch.len = scratch_top; 914 915 return addNode(&p->nodes, 916 (AstNodeItem) { 917 .tag = AST_NODE_ASSIGN_DESTRUCTURE, 918 .main_token = equal_token, 919 .data = { .lhs = extra_start, .rhs = rhs }, 920 }); 921 } 922 923 static AstNodeIndex expectIfStatement(Parser* p) { 924 const AstTokenIndex if_token = assertToken(p, TOKEN_KEYWORD_IF); 925 expectToken(p, TOKEN_L_PAREN); 926 const AstNodeIndex condition = expectExpr(p); 927 expectToken(p, TOKEN_R_PAREN); 928 parsePtrPayload(p); 929 bool else_required = false; 930 AstNodeIndex then_body; 931 const AstNodeIndex block2 = parseBlockExpr(p); 932 if (block2 != 0) { 933 then_body = block2; 934 } else { 935 then_body = parseAssignExpr(p); 936 if (then_body == 0) 937 fail(p, "expected block or assignment"); 938 if (eatToken(p, TOKEN_SEMICOLON) != null_token) 939 return addNode(&p->nodes, 940 (AstNodeItem) { 941 .tag = AST_NODE_IF_SIMPLE, 942 .main_token = if_token, 943 .data = { .lhs = condition, .rhs = then_body }, 944 }); 945 else_required = true; 946 } 947 if (eatToken(p, TOKEN_KEYWORD_ELSE) == null_token) { 948 if (else_required) 949 fail(p, "expected_semi_or_else"); 950 return addNode(&p->nodes, 951 (AstNodeItem) { 952 .tag = AST_NODE_IF_SIMPLE, 953 .main_token = if_token, 954 .data = { .lhs = condition, .rhs = then_body }, 955 }); 956 } 957 parsePayload(p); 958 const AstNodeIndex else_body = expectStatement(p, false); 959 return addNode(&p->nodes, 960 (AstNodeItem) { 961 .tag = AST_NODE_IF, 962 .main_token = if_token, 963 .data = { 964 .lhs = condition, 965 .rhs = addExtra(p, 966 (AstNodeIndex[]) { then_body, else_body }, 2), 967 }, 968 }); 969 } 970 971 static AstNodeIndex parseLabeledStatement(Parser* p) { 972 const AstNodeIndex label_token = parseBlockLabel(p); 973 const AstNodeIndex block = parseBlock(p); 974 if (block != 0) 975 return block; 976 977 const AstNodeIndex loop_stmt = parseLoopStatement(p); 978 if (loop_stmt != 0) 979 return loop_stmt; 980 981 const AstNodeIndex switch_expr = parseSwitchExpr(p); 982 if (switch_expr != 0) 983 return switch_expr; 984 985 if (label_token != 0) { 986 fail(p, "expected_labelable"); 987 } 988 989 return null_node; 990 } 991 992 static AstNodeIndex parseLoopStatement(Parser* p) { 993 const AstTokenIndex inline_token = eatToken(p, TOKEN_KEYWORD_INLINE); 994 995 const AstNodeIndex for_statement = parseForStatement(p); 996 if (for_statement != 0) 997 return for_statement; 998 999 const AstNodeIndex while_statement = parseWhileStatement(p); 1000 if (while_statement != 0) 1001 return while_statement; 1002 1003 if (inline_token == null_token) 1004 return null_node; 1005 1006 fail(p, "seen 'inline', there should have been a 'for' or 'while'"); 1007 return 0; // tcc 1008 } 1009 1010 static AstNodeIndex parseForStatement(Parser* p) { 1011 const AstTokenIndex for_token = eatToken(p, TOKEN_KEYWORD_FOR); 1012 if (for_token == null_token) 1013 return null_node; 1014 1015 const uint32_t scratch_top = p->scratch.len; 1016 const uint32_t inputs = forPrefix(p); 1017 1018 // Statement body: block or assign expr 1019 bool else_required = false; 1020 bool seen_semicolon = false; 1021 AstNodeIndex then_body; 1022 const AstNodeIndex block = parseBlock(p); 1023 if (block != 0) { 1024 then_body = block; 1025 } else { 1026 then_body = parseAssignExpr(p); 1027 if (then_body == 0) { 1028 fail(p, "expected_block_or_assignment"); 1029 } 1030 if (eatToken(p, TOKEN_SEMICOLON) != null_token) { 1031 seen_semicolon = true; 1032 } else { 1033 else_required = true; 1034 } 1035 } 1036 1037 bool has_else = false; 1038 if (!seen_semicolon && eatToken(p, TOKEN_KEYWORD_ELSE) != null_token) { 1039 parsePayload(p); 1040 SLICE_APPEND(AstNodeIndex, &p->scratch, then_body); 1041 const AstNodeIndex else_body = expectStatement(p, false); 1042 SLICE_APPEND(AstNodeIndex, &p->scratch, else_body); 1043 has_else = true; 1044 } else if (inputs == 1) { 1045 if (else_required) 1046 fail(p, "expected_semi_or_else"); 1047 p->scratch.len = scratch_top; 1048 return addNode(&p->nodes, 1049 (AstNodeItem) { 1050 .tag = AST_NODE_FOR_SIMPLE, 1051 .main_token = for_token, 1052 .data = { 1053 .lhs = p->scratch.arr[scratch_top], 1054 .rhs = then_body, 1055 }, 1056 }); 1057 } else { 1058 if (else_required) 1059 fail(p, "expected_semi_or_else"); 1060 SLICE_APPEND(AstNodeIndex, &p->scratch, then_body); 1061 } 1062 1063 const uint32_t total = p->scratch.len - scratch_top; 1064 const AstSubRange span 1065 = listToSpan(p, &p->scratch.arr[scratch_top], total); 1066 p->scratch.len = scratch_top; 1067 return addNode(&p->nodes, 1068 (AstNodeItem) { 1069 .tag = AST_NODE_FOR, 1070 .main_token = for_token, 1071 .data = { 1072 .lhs = span.start, 1073 .rhs = ((uint32_t)inputs & 0x7FFFFFFF) 1074 | (has_else ? (1u << 31) : 0), 1075 }, 1076 }); 1077 } 1078 1079 static AstNodeIndex parseForExpr(Parser* p) { 1080 const AstTokenIndex for_token = eatToken(p, TOKEN_KEYWORD_FOR); 1081 if (for_token == null_token) 1082 return null_node; 1083 1084 const uint32_t scratch_top = p->scratch.len; 1085 const uint32_t inputs = forPrefix(p); 1086 1087 const AstNodeIndex then_expr = expectExpr(p); 1088 1089 if (eatToken(p, TOKEN_KEYWORD_ELSE) != null_token) { 1090 parsePayload(p); 1091 SLICE_APPEND(AstNodeIndex, &p->scratch, then_expr); 1092 const AstNodeIndex else_expr = expectExpr(p); 1093 SLICE_APPEND(AstNodeIndex, &p->scratch, else_expr); 1094 const uint32_t total = p->scratch.len - scratch_top; 1095 const AstSubRange span 1096 = listToSpan(p, &p->scratch.arr[scratch_top], total); 1097 p->scratch.len = scratch_top; 1098 return addNode(&p->nodes, 1099 (AstNodeItem) { 1100 .tag = AST_NODE_FOR, 1101 .main_token = for_token, 1102 .data = { 1103 .lhs = span.start, 1104 .rhs = ((uint32_t)inputs & 0x7FFFFFFF) | (1u << 31), 1105 }, 1106 }); 1107 } 1108 1109 if (inputs == 1) { 1110 const AstNodeIndex input = p->scratch.arr[scratch_top]; 1111 p->scratch.len = scratch_top; 1112 return addNode(&p->nodes, 1113 (AstNodeItem) { 1114 .tag = AST_NODE_FOR_SIMPLE, 1115 .main_token = for_token, 1116 .data = { .lhs = input, .rhs = then_expr }, 1117 }); 1118 } 1119 1120 SLICE_APPEND(AstNodeIndex, &p->scratch, then_expr); 1121 const uint32_t total = p->scratch.len - scratch_top; 1122 const AstSubRange span 1123 = listToSpan(p, &p->scratch.arr[scratch_top], total); 1124 p->scratch.len = scratch_top; 1125 return addNode(&p->nodes, 1126 (AstNodeItem) { 1127 .tag = AST_NODE_FOR, 1128 .main_token = for_token, 1129 .data = { 1130 .lhs = span.start, 1131 .rhs = (uint32_t)inputs & 0x7FFFFFFF, 1132 }, 1133 }); 1134 } 1135 1136 static AstNodeIndex parseWhileStatement(Parser* p) { 1137 const AstTokenIndex while_token = eatToken(p, TOKEN_KEYWORD_WHILE); 1138 if (while_token == null_token) 1139 return null_node; 1140 1141 expectToken(p, TOKEN_L_PAREN); 1142 const AstNodeIndex condition = expectExpr(p); 1143 expectToken(p, TOKEN_R_PAREN); 1144 parsePtrPayload(p); 1145 1146 const AstNodeIndex cont_expr = parseWhileContinueExpr(p); 1147 1148 // Statement body: block, or assign expr 1149 bool else_required = false; 1150 AstNodeIndex body; 1151 const AstNodeIndex block = parseBlock(p); 1152 if (block != 0) { 1153 body = block; 1154 } else { 1155 body = parseAssignExpr(p); 1156 if (body == 0) { 1157 fail(p, "expected_block_or_assignment"); 1158 } 1159 if (eatToken(p, TOKEN_SEMICOLON) != null_token) { 1160 if (cont_expr != 0) { 1161 return addNode(&p->nodes, 1162 (AstNodeItem) { 1163 .tag = AST_NODE_WHILE_CONT, 1164 .main_token = while_token, 1165 .data = { 1166 .lhs = condition, 1167 .rhs = addExtra(p, 1168 (AstNodeIndex[]) { cont_expr, body }, 2), 1169 }, 1170 }); 1171 } 1172 return addNode(&p->nodes, 1173 (AstNodeItem) { 1174 .tag = AST_NODE_WHILE_SIMPLE, 1175 .main_token = while_token, 1176 .data = { .lhs = condition, .rhs = body }, 1177 }); 1178 } 1179 else_required = true; 1180 } 1181 1182 if (eatToken(p, TOKEN_KEYWORD_ELSE) == null_token) { 1183 if (else_required) 1184 fail(p, "expected_semi_or_else"); 1185 if (cont_expr != 0) { 1186 return addNode(&p->nodes, 1187 (AstNodeItem) { 1188 .tag = AST_NODE_WHILE_CONT, 1189 .main_token = while_token, 1190 .data = { 1191 .lhs = condition, 1192 .rhs = addExtra(p, 1193 (AstNodeIndex[]) { cont_expr, body }, 2), 1194 }, 1195 }); 1196 } 1197 return addNode(&p->nodes, 1198 (AstNodeItem) { 1199 .tag = AST_NODE_WHILE_SIMPLE, 1200 .main_token = while_token, 1201 .data = { .lhs = condition, .rhs = body }, 1202 }); 1203 } 1204 1205 parsePayload(p); 1206 const AstNodeIndex else_body = expectStatement(p, false); 1207 return addNode(&p->nodes, 1208 (AstNodeItem) { 1209 .tag = AST_NODE_WHILE, 1210 .main_token = while_token, 1211 .data = { 1212 .lhs = condition, 1213 .rhs = addExtra(p, 1214 (AstNodeIndex[]) { OPT(cont_expr), body, else_body }, 1215 3), 1216 }, 1217 }); 1218 } 1219 1220 static AstNodeIndex expectBlockExprStatement(Parser* p) { 1221 const AstNodeIndex block_expr = parseBlockExpr(p); 1222 if (block_expr != 0) 1223 return block_expr; 1224 // Assign expr + semicolon 1225 const AstNodeIndex expr = parseAssignExpr(p); 1226 if (expr != 0) { 1227 expectSemicolon(p); 1228 return expr; 1229 } 1230 fail(p, "expectBlockExprStatement: expected block or expr"); 1231 return 0; // tcc 1232 } 1233 1234 static AstNodeIndex parseBlockExpr(Parser* p) { 1235 if (p->token_tags[p->tok_i] == TOKEN_L_BRACE) 1236 return parseBlock(p); 1237 if (p->token_tags[p->tok_i] == TOKEN_IDENTIFIER 1238 && p->token_tags[p->tok_i + 1] == TOKEN_COLON 1239 && p->token_tags[p->tok_i + 2] == TOKEN_L_BRACE) { 1240 p->tok_i += 2; 1241 return parseBlock(p); 1242 } 1243 return null_node; 1244 } 1245 1246 static AstNodeIndex parseAssignExpr(Parser* p) { 1247 const AstNodeIndex expr = parseExpr(p); 1248 if (expr == 0) 1249 return null_node; 1250 return finishAssignExpr(p, expr); 1251 } 1252 1253 static AstNodeIndex parseSingleAssignExpr(Parser* p) { 1254 const AstNodeIndex expr = parseExpr(p); 1255 if (expr == 0) 1256 return null_node; 1257 const AstNodeTag tag = assignOpNode(p->token_tags[p->tok_i]); 1258 if (tag == AST_NODE_ROOT) 1259 return expr; 1260 const AstTokenIndex op_token = nextToken(p); 1261 const AstNodeIndex rhs = expectExpr(p); 1262 return addNode(&p->nodes, 1263 (AstNodeItem) { 1264 .tag = tag, 1265 .main_token = op_token, 1266 .data = { .lhs = expr, .rhs = rhs }, 1267 }); 1268 } 1269 1270 static AstNodeIndex finishAssignExpr(Parser* p, AstNodeIndex lhs) { 1271 const AstNodeTag assign_tag = assignOpNode(p->token_tags[p->tok_i]); 1272 if (assign_tag == AST_NODE_ROOT) 1273 return lhs; 1274 1275 const AstTokenIndex op_token = nextToken(p); 1276 const AstNodeIndex rhs = expectExpr(p); 1277 return addNode(&p->nodes, 1278 (AstNodeItem) { 1279 .tag = assign_tag, 1280 .main_token = op_token, 1281 .data = { .lhs = lhs, .rhs = rhs }, 1282 }); 1283 } 1284 1285 static AstNodeTag assignOpNode(TokenizerTag tok) { 1286 switch (tok) { 1287 case TOKEN_EQUAL: 1288 return AST_NODE_ASSIGN; 1289 case TOKEN_PLUS_EQUAL: 1290 return AST_NODE_ASSIGN_ADD; 1291 case TOKEN_MINUS_EQUAL: 1292 return AST_NODE_ASSIGN_SUB; 1293 case TOKEN_ASTERISK_EQUAL: 1294 return AST_NODE_ASSIGN_MUL; 1295 case TOKEN_SLASH_EQUAL: 1296 return AST_NODE_ASSIGN_DIV; 1297 case TOKEN_PERCENT_EQUAL: 1298 return AST_NODE_ASSIGN_MOD; 1299 case TOKEN_AMPERSAND_EQUAL: 1300 return AST_NODE_ASSIGN_BIT_AND; 1301 case TOKEN_PIPE_EQUAL: 1302 return AST_NODE_ASSIGN_BIT_OR; 1303 case TOKEN_CARET_EQUAL: 1304 return AST_NODE_ASSIGN_BIT_XOR; 1305 case TOKEN_ANGLE_BRACKET_ANGLE_BRACKET_LEFT_EQUAL: 1306 return AST_NODE_ASSIGN_SHL; 1307 case TOKEN_ANGLE_BRACKET_ANGLE_BRACKET_RIGHT_EQUAL: 1308 return AST_NODE_ASSIGN_SHR; 1309 case TOKEN_PLUS_PERCENT_EQUAL: 1310 return AST_NODE_ASSIGN_ADD_WRAP; 1311 case TOKEN_MINUS_PERCENT_EQUAL: 1312 return AST_NODE_ASSIGN_SUB_WRAP; 1313 case TOKEN_ASTERISK_PERCENT_EQUAL: 1314 return AST_NODE_ASSIGN_MUL_WRAP; 1315 case TOKEN_PLUS_PIPE_EQUAL: 1316 return AST_NODE_ASSIGN_ADD_SAT; 1317 case TOKEN_MINUS_PIPE_EQUAL: 1318 return AST_NODE_ASSIGN_SUB_SAT; 1319 case TOKEN_ASTERISK_PIPE_EQUAL: 1320 return AST_NODE_ASSIGN_MUL_SAT; 1321 case TOKEN_ANGLE_BRACKET_ANGLE_BRACKET_LEFT_PIPE_EQUAL: 1322 return AST_NODE_ASSIGN_SHL_SAT; 1323 default: 1324 return AST_NODE_ROOT; // not an assignment op 1325 } 1326 } 1327 1328 static AstNodeIndex parseExpr(Parser* p) { return parseExprPrecedence(p, 0); } 1329 1330 static AstNodeIndex expectExpr(Parser* p) { 1331 const AstNodeIndex node = parseExpr(p); 1332 if (node == 0) { 1333 fail(p, "expected expression"); 1334 } 1335 return node; 1336 } 1337 1338 static AstNodeIndex parseExprPrecedence(Parser* p, int32_t min_prec) { 1339 assert(min_prec >= 0); 1340 1341 AstNodeIndex node = parsePrefixExpr(p); 1342 if (node == 0) 1343 return null_node; 1344 1345 int8_t banned_prec = -1; 1346 1347 while (true) { 1348 const TokenizerTag tok_tag = p->token_tags[p->tok_i]; 1349 const OperInfo info = operTable(tok_tag); 1350 if (info.prec < min_prec) 1351 break; 1352 1353 if (info.prec == banned_prec) { 1354 fail(p, "chained comparison operators"); 1355 } 1356 1357 const AstTokenIndex oper_token = nextToken(p); 1358 if (tok_tag == TOKEN_KEYWORD_CATCH) 1359 parsePayload(p); 1360 const AstNodeIndex rhs = parseExprPrecedence(p, info.prec + 1); 1361 if (rhs == 0) { 1362 fail(p, "expected expression"); 1363 } 1364 1365 { 1366 const uint32_t tok_len = tokenTagLexemeLen(tok_tag); 1367 if (tok_len > 0) { 1368 const uint32_t tok_start = p->token_starts[oper_token]; 1369 const char char_before = p->source[tok_start - 1]; 1370 const char char_after = p->source[tok_start + tok_len]; 1371 if (tok_tag == TOKEN_AMPERSAND && char_after == '&') { 1372 fail(p, "invalid ampersand ampersand"); 1373 } else if (isspace((unsigned char)char_before) 1374 != isspace((unsigned char)char_after)) { 1375 fail(p, "mismatched binary op whitespace"); 1376 } 1377 } 1378 } 1379 1380 node = addNode( 1381 &p->nodes, 1382 (AstNodeItem) { 1383 .tag = info.tag, 1384 .main_token = oper_token, 1385 .data = { 1386 .lhs = node, 1387 .rhs = rhs, 1388 }, 1389 }); 1390 1391 if (info.assoc == ASSOC_NONE) 1392 banned_prec = info.prec; 1393 } 1394 1395 return node; 1396 } 1397 1398 static uint32_t tokenTagLexemeLen(TokenizerTag tag) { 1399 switch (tag) { 1400 case TOKEN_PLUS: 1401 case TOKEN_MINUS: 1402 case TOKEN_ASTERISK: 1403 case TOKEN_SLASH: 1404 case TOKEN_PERCENT: 1405 case TOKEN_AMPERSAND: 1406 case TOKEN_CARET: 1407 case TOKEN_PIPE: 1408 case TOKEN_ANGLE_BRACKET_LEFT: 1409 case TOKEN_ANGLE_BRACKET_RIGHT: 1410 return 1; 1411 case TOKEN_PLUS_PLUS: 1412 case TOKEN_MINUS_PERCENT: 1413 case TOKEN_PLUS_PERCENT: 1414 case TOKEN_MINUS_PIPE: 1415 case TOKEN_PLUS_PIPE: 1416 case TOKEN_ASTERISK_ASTERISK: 1417 case TOKEN_ASTERISK_PERCENT: 1418 case TOKEN_ASTERISK_PIPE: 1419 case TOKEN_PIPE_PIPE: 1420 case TOKEN_EQUAL_EQUAL: 1421 case TOKEN_BANG_EQUAL: 1422 case TOKEN_ANGLE_BRACKET_LEFT_EQUAL: 1423 case TOKEN_ANGLE_BRACKET_RIGHT_EQUAL: 1424 case TOKEN_ANGLE_BRACKET_ANGLE_BRACKET_LEFT: 1425 case TOKEN_ANGLE_BRACKET_ANGLE_BRACKET_RIGHT: 1426 return 2; 1427 case TOKEN_ANGLE_BRACKET_ANGLE_BRACKET_LEFT_PIPE: 1428 return 3; 1429 case TOKEN_KEYWORD_OR: 1430 return 2; 1431 case TOKEN_KEYWORD_AND: 1432 return 3; 1433 case TOKEN_KEYWORD_ORELSE: 1434 return 6; 1435 case TOKEN_KEYWORD_CATCH: 1436 return 5; 1437 default: 1438 return 0; 1439 } 1440 } 1441 1442 static OperInfo operTable(TokenizerTag tok_tag) { 1443 switch (tok_tag) { 1444 case TOKEN_KEYWORD_OR: 1445 return (OperInfo) { .prec = 10, .tag = AST_NODE_BOOL_OR }; 1446 case TOKEN_KEYWORD_AND: 1447 return (OperInfo) { .prec = 20, .tag = AST_NODE_BOOL_AND }; 1448 1449 case TOKEN_EQUAL_EQUAL: 1450 return (OperInfo) { 1451 .prec = 30, .tag = AST_NODE_EQUAL_EQUAL, .assoc = ASSOC_NONE 1452 }; 1453 case TOKEN_BANG_EQUAL: 1454 return (OperInfo) { 1455 .prec = 30, .tag = AST_NODE_BANG_EQUAL, .assoc = ASSOC_NONE 1456 }; 1457 case TOKEN_ANGLE_BRACKET_LEFT: 1458 return (OperInfo) { 1459 .prec = 30, .tag = AST_NODE_LESS_THAN, .assoc = ASSOC_NONE 1460 }; 1461 case TOKEN_ANGLE_BRACKET_RIGHT: 1462 return (OperInfo) { 1463 .prec = 30, .tag = AST_NODE_GREATER_THAN, .assoc = ASSOC_NONE 1464 }; 1465 case TOKEN_ANGLE_BRACKET_LEFT_EQUAL: 1466 return (OperInfo) { 1467 .prec = 30, .tag = AST_NODE_LESS_OR_EQUAL, .assoc = ASSOC_NONE 1468 }; 1469 case TOKEN_ANGLE_BRACKET_RIGHT_EQUAL: 1470 return (OperInfo) { 1471 .prec = 30, .tag = AST_NODE_GREATER_OR_EQUAL, .assoc = ASSOC_NONE 1472 }; 1473 1474 case TOKEN_AMPERSAND: 1475 return (OperInfo) { .prec = 40, .tag = AST_NODE_BIT_AND }; 1476 case TOKEN_CARET: 1477 return (OperInfo) { .prec = 40, .tag = AST_NODE_BIT_XOR }; 1478 case TOKEN_PIPE: 1479 return (OperInfo) { .prec = 40, .tag = AST_NODE_BIT_OR }; 1480 case TOKEN_KEYWORD_ORELSE: 1481 return (OperInfo) { .prec = 40, .tag = AST_NODE_ORELSE }; 1482 case TOKEN_KEYWORD_CATCH: 1483 return (OperInfo) { .prec = 40, .tag = AST_NODE_CATCH }; 1484 1485 case TOKEN_ANGLE_BRACKET_ANGLE_BRACKET_LEFT: 1486 return (OperInfo) { .prec = 50, .tag = AST_NODE_SHL }; 1487 case TOKEN_ANGLE_BRACKET_ANGLE_BRACKET_LEFT_PIPE: 1488 return (OperInfo) { .prec = 50, .tag = AST_NODE_SHL_SAT }; 1489 case TOKEN_ANGLE_BRACKET_ANGLE_BRACKET_RIGHT: 1490 return (OperInfo) { .prec = 50, .tag = AST_NODE_SHR }; 1491 1492 case TOKEN_PLUS: 1493 return (OperInfo) { .prec = 60, .tag = AST_NODE_ADD }; 1494 case TOKEN_MINUS: 1495 return (OperInfo) { .prec = 60, .tag = AST_NODE_SUB }; 1496 case TOKEN_PLUS_PLUS: 1497 return (OperInfo) { .prec = 60, .tag = AST_NODE_ARRAY_CAT }; 1498 case TOKEN_PLUS_PERCENT: 1499 return (OperInfo) { .prec = 60, .tag = AST_NODE_ADD_WRAP }; 1500 case TOKEN_MINUS_PERCENT: 1501 return (OperInfo) { .prec = 60, .tag = AST_NODE_SUB_WRAP }; 1502 case TOKEN_PLUS_PIPE: 1503 return (OperInfo) { .prec = 60, .tag = AST_NODE_ADD_SAT }; 1504 case TOKEN_MINUS_PIPE: 1505 return (OperInfo) { .prec = 60, .tag = AST_NODE_SUB_SAT }; 1506 1507 case TOKEN_PIPE_PIPE: 1508 return (OperInfo) { .prec = 70, .tag = AST_NODE_MERGE_ERROR_SETS }; 1509 case TOKEN_ASTERISK: 1510 return (OperInfo) { .prec = 70, .tag = AST_NODE_MUL }; 1511 case TOKEN_SLASH: 1512 return (OperInfo) { .prec = 70, .tag = AST_NODE_DIV }; 1513 case TOKEN_PERCENT: 1514 return (OperInfo) { .prec = 70, .tag = AST_NODE_MOD }; 1515 case TOKEN_ASTERISK_ASTERISK: 1516 return (OperInfo) { .prec = 70, .tag = AST_NODE_ARRAY_MULT }; 1517 case TOKEN_ASTERISK_PERCENT: 1518 return (OperInfo) { .prec = 70, .tag = AST_NODE_MUL_WRAP }; 1519 case TOKEN_ASTERISK_PIPE: 1520 return (OperInfo) { .prec = 70, .tag = AST_NODE_MUL_SAT }; 1521 1522 default: 1523 return (OperInfo) { .prec = -1, .tag = AST_NODE_ROOT }; 1524 } 1525 } 1526 1527 static AstNodeIndex parsePrefixExpr(Parser* p) { 1528 AstNodeTag tag; 1529 switch (p->token_tags[p->tok_i]) { 1530 case TOKEN_BANG: 1531 tag = AST_NODE_BOOL_NOT; 1532 break; 1533 case TOKEN_MINUS: 1534 tag = AST_NODE_NEGATION; 1535 break; 1536 case TOKEN_TILDE: 1537 tag = AST_NODE_BIT_NOT; 1538 break; 1539 case TOKEN_MINUS_PERCENT: 1540 tag = AST_NODE_NEGATION_WRAP; 1541 break; 1542 case TOKEN_AMPERSAND: 1543 tag = AST_NODE_ADDRESS_OF; 1544 break; 1545 case TOKEN_KEYWORD_TRY: 1546 tag = AST_NODE_TRY; 1547 break; 1548 default: 1549 return parsePrimaryExpr(p); 1550 } 1551 return addNode( 1552 &p->nodes, 1553 (AstNodeItem) { 1554 .tag = tag, 1555 .main_token = nextToken(p), 1556 .data = { 1557 .lhs = parsePrefixExpr(p), 1558 .rhs = 0, 1559 }, 1560 }); 1561 } 1562 1563 static AstNodeIndex parseTypeExpr(Parser* p) { 1564 const TokenizerTag tok = p->token_tags[p->tok_i]; 1565 switch (tok) { 1566 case TOKEN_QUESTION_MARK: 1567 return addNode(&p->nodes, 1568 (AstNodeItem) { 1569 .tag = AST_NODE_OPTIONAL_TYPE, 1570 .main_token = nextToken(p), 1571 .data = { .lhs = parseTypeExpr(p), .rhs = 0 }, 1572 }); 1573 case TOKEN_KEYWORD_ANYFRAME: 1574 fail(p, "unsupported type expression"); 1575 case TOKEN_ASTERISK: { 1576 const AstTokenIndex asterisk = nextToken(p); 1577 const PtrModifiers mods = parsePtrModifiers(p); 1578 const AstNodeIndex elem_type = parseTypeExpr(p); 1579 return makePtrTypeNode(p, asterisk, 0, mods, elem_type); 1580 } 1581 case TOKEN_ASTERISK_ASTERISK: { 1582 const AstTokenIndex asterisk = nextToken(p); 1583 const PtrModifiers mods = parsePtrModifiers(p); 1584 const AstNodeIndex elem_type = parseTypeExpr(p); 1585 if (elem_type == 0) { 1586 fail(p, "expected type expression"); 1587 } 1588 const AstNodeIndex inner 1589 = makePtrTypeNode(p, asterisk, 0, mods, elem_type); 1590 return addNode(&p->nodes, 1591 (AstNodeItem) { 1592 .tag = AST_NODE_PTR_TYPE_ALIGNED, 1593 .main_token = asterisk, 1594 .data = { .lhs = 0, .rhs = inner }, 1595 }); 1596 } 1597 case TOKEN_L_BRACKET: { 1598 const AstTokenIndex lbracket = nextToken(p); 1599 if (p->token_tags[p->tok_i] == TOKEN_ASTERISK) { 1600 // [*] many-item pointer, [*c] C pointer, [*:s] sentinel 1601 p->tok_i++; // consume * 1602 AstNodeIndex sentinel = 0; 1603 if (p->token_tags[p->tok_i] == TOKEN_IDENTIFIER) { 1604 // Check for 'c' modifier: [*c] 1605 const char c = p->source[p->token_starts[p->tok_i]]; 1606 if (c == 'c' 1607 && p->token_starts[p->tok_i + 1] 1608 - p->token_starts[p->tok_i] 1609 <= 2) { 1610 p->tok_i++; // consume 'c' 1611 } 1612 } else if (eatToken(p, TOKEN_COLON) != null_token) { 1613 sentinel = expectExpr(p); 1614 } 1615 expectToken(p, TOKEN_R_BRACKET); 1616 const PtrModifiers mods = parsePtrModifiers(p); 1617 const AstNodeIndex elem_type = parseTypeExpr(p); 1618 return makePtrTypeNode(p, lbracket, sentinel, mods, elem_type); 1619 } 1620 const AstNodeIndex len_expr = parseExpr(p); 1621 const AstNodeIndex sentinel 1622 = eatToken(p, TOKEN_COLON) != null_token ? expectExpr(p) : 0; 1623 expectToken(p, TOKEN_R_BRACKET); 1624 if (len_expr == 0) { 1625 // Slice type: []T or [:s]T 1626 const PtrModifiers mods = parsePtrModifiers(p); 1627 const AstNodeIndex elem_type = parseTypeExpr(p); 1628 if (mods.bit_range_start != 0) { 1629 fail(p, "invalid_bit_range"); 1630 } 1631 return makePtrTypeNode(p, lbracket, sentinel, mods, elem_type); 1632 } 1633 // Array type: [N]T or [N:s]T 1634 const AstNodeIndex elem_type = parseTypeExpr(p); 1635 if (sentinel == 0) { 1636 return addNode(&p->nodes, 1637 (AstNodeItem) { 1638 .tag = AST_NODE_ARRAY_TYPE, 1639 .main_token = lbracket, 1640 .data = { .lhs = len_expr, .rhs = elem_type }, 1641 }); 1642 } 1643 return addNode(&p->nodes, 1644 (AstNodeItem) { 1645 .tag = AST_NODE_ARRAY_TYPE_SENTINEL, 1646 .main_token = lbracket, 1647 .data = { 1648 .lhs = len_expr, 1649 .rhs = addExtra(p, 1650 (AstNodeIndex[]) { sentinel, elem_type }, 2), 1651 }, 1652 }); 1653 } 1654 case TOKEN_KEYWORD_IF: { 1655 // if-type-expr: uses parseTypeExpr for branches instead of parseExpr 1656 const AstTokenIndex if_token = nextToken(p); 1657 expectToken(p, TOKEN_L_PAREN); 1658 const AstNodeIndex condition = expectExpr(p); 1659 expectToken(p, TOKEN_R_PAREN); 1660 parsePtrPayload(p); 1661 const AstNodeIndex then_expr = parseTypeExpr(p); 1662 if (eatToken(p, TOKEN_KEYWORD_ELSE) == null_token) 1663 return addNode(&p->nodes, 1664 (AstNodeItem) { 1665 .tag = AST_NODE_IF_SIMPLE, 1666 .main_token = if_token, 1667 .data = { .lhs = condition, .rhs = then_expr }, 1668 }); 1669 parsePayload(p); 1670 const AstNodeIndex else_expr = parseTypeExpr(p); 1671 return addNode(&p->nodes, 1672 (AstNodeItem) { 1673 .tag = AST_NODE_IF, 1674 .main_token = if_token, 1675 .data = { 1676 .lhs = condition, 1677 .rhs = addExtra(p, 1678 (AstNodeIndex[]) { then_expr, else_expr }, 2), 1679 }, 1680 }); 1681 } 1682 case TOKEN_KEYWORD_FOR: { 1683 // for-type-expr: uses parseTypeExpr for body instead of parseExpr 1684 const AstTokenIndex for_token = nextToken(p); 1685 const uint32_t scratch_top2 = p->scratch.len; 1686 const uint32_t inputs = forPrefix(p); 1687 const AstNodeIndex body = parseTypeExpr(p); 1688 bool has_else = false; 1689 if (eatToken(p, TOKEN_KEYWORD_ELSE) != null_token) { 1690 parsePayload(p); 1691 SLICE_APPEND(AstNodeIndex, &p->scratch, body); 1692 const AstNodeIndex else_expr = parseTypeExpr(p); 1693 SLICE_APPEND(AstNodeIndex, &p->scratch, else_expr); 1694 has_else = true; 1695 } else if (inputs == 1) { 1696 p->scratch.len = scratch_top2; 1697 return addNode(&p->nodes, 1698 (AstNodeItem) { 1699 .tag = AST_NODE_FOR_SIMPLE, 1700 .main_token = for_token, 1701 .data = { 1702 .lhs = p->scratch.arr[scratch_top2], 1703 .rhs = body, 1704 }, 1705 }); 1706 } else { 1707 SLICE_APPEND(AstNodeIndex, &p->scratch, body); 1708 } 1709 const uint32_t total = p->scratch.len - scratch_top2; 1710 const AstSubRange span 1711 = listToSpan(p, &p->scratch.arr[scratch_top2], total); 1712 p->scratch.len = scratch_top2; 1713 return addNode(&p->nodes, 1714 (AstNodeItem) { 1715 .tag = AST_NODE_FOR, 1716 .main_token = for_token, 1717 .data = { 1718 .lhs = span.start, 1719 .rhs = ((uint32_t)inputs & 0x7FFFFFFF) 1720 | (has_else ? (1u << 31) : 0), 1721 }, 1722 }); 1723 } 1724 case TOKEN_KEYWORD_WHILE: { 1725 // while-type-expr: uses parseTypeExpr for body instead of parseExpr 1726 const AstTokenIndex while_token = nextToken(p); 1727 expectToken(p, TOKEN_L_PAREN); 1728 const AstNodeIndex condition = expectExpr(p); 1729 expectToken(p, TOKEN_R_PAREN); 1730 parsePtrPayload(p); 1731 const AstNodeIndex cont_expr = parseWhileContinueExpr(p); 1732 const AstNodeIndex body = parseTypeExpr(p); 1733 if (eatToken(p, TOKEN_KEYWORD_ELSE) != null_token) { 1734 parsePayload(p); 1735 const AstNodeIndex else_expr = parseTypeExpr(p); 1736 return addNode(&p->nodes, 1737 (AstNodeItem) { 1738 .tag = AST_NODE_WHILE, 1739 .main_token = while_token, 1740 .data = { 1741 .lhs = condition, 1742 .rhs = addExtra(p, 1743 (AstNodeIndex[]) { cont_expr, body, else_expr }, 3), 1744 }, 1745 }); 1746 } 1747 if (cont_expr != 0) 1748 return addNode(&p->nodes, 1749 (AstNodeItem) { 1750 .tag = AST_NODE_WHILE_CONT, 1751 .main_token = while_token, 1752 .data = { 1753 .lhs = condition, 1754 .rhs = addExtra(p, 1755 (AstNodeIndex[]) { cont_expr, body }, 2), 1756 }, 1757 }); 1758 return addNode(&p->nodes, 1759 (AstNodeItem) { 1760 .tag = AST_NODE_WHILE_SIMPLE, 1761 .main_token = while_token, 1762 .data = { .lhs = condition, .rhs = body }, 1763 }); 1764 } 1765 default: 1766 return parseErrorUnionExpr(p); 1767 } 1768 return 0; // tcc 1769 } 1770 1771 static AstNodeIndex makePtrTypeNode(Parser* p, AstTokenIndex main_token, 1772 AstNodeIndex sentinel, PtrModifiers mods, AstNodeIndex elem_type) { 1773 if (mods.bit_range_start != 0) { 1774 return addNode(&p->nodes, 1775 (AstNodeItem) { 1776 .tag = AST_NODE_PTR_TYPE_BIT_RANGE, 1777 .main_token = main_token, 1778 .data = { 1779 .lhs = addExtra(p, 1780 (AstNodeIndex[]) { OPT(sentinel), mods.align_node, 1781 OPT(mods.addrspace_node), mods.bit_range_start, 1782 mods.bit_range_end }, 1783 5), 1784 .rhs = elem_type, 1785 }, 1786 }); 1787 } 1788 if (mods.addrspace_node != 0 || (sentinel != 0 && mods.align_node != 0)) { 1789 return addNode(&p->nodes, 1790 (AstNodeItem) { 1791 .tag = AST_NODE_PTR_TYPE, 1792 .main_token = main_token, 1793 .data = { 1794 .lhs = addExtra(p, 1795 (AstNodeIndex[]) { OPT(sentinel), 1796 OPT(mods.align_node), 1797 OPT(mods.addrspace_node) }, 1798 3), 1799 .rhs = elem_type, 1800 }, 1801 }); 1802 } 1803 if (sentinel != 0) { 1804 return addNode(&p->nodes, 1805 (AstNodeItem) { 1806 .tag = AST_NODE_PTR_TYPE_SENTINEL, 1807 .main_token = main_token, 1808 .data = { .lhs = sentinel, .rhs = elem_type }, 1809 }); 1810 } 1811 return addNode(&p->nodes, 1812 (AstNodeItem) { 1813 .tag = AST_NODE_PTR_TYPE_ALIGNED, 1814 .main_token = main_token, 1815 .data = { .lhs = mods.align_node, .rhs = elem_type }, 1816 }); 1817 } 1818 1819 static AstNodeIndex parsePrimaryExpr(Parser* p) { 1820 switch (p->token_tags[p->tok_i]) { 1821 case TOKEN_KEYWORD_ASM: 1822 return parseAsmExpr(p); 1823 case TOKEN_KEYWORD_IF: 1824 return parseIfExpr(p); 1825 case TOKEN_KEYWORD_BREAK: 1826 return addNode( 1827 &p->nodes, 1828 (AstNodeItem) { 1829 .tag = AST_NODE_BREAK, 1830 .main_token = nextToken(p), 1831 .data = { 1832 .lhs = parseBreakLabel(p), 1833 .rhs = parseExpr(p), 1834 }, 1835 }); 1836 case TOKEN_KEYWORD_CONTINUE: 1837 return addNode( 1838 &p->nodes, 1839 (AstNodeItem) { 1840 .tag = AST_NODE_CONTINUE, 1841 .main_token = nextToken(p), 1842 .data = { 1843 .lhs = parseBreakLabel(p), 1844 .rhs = parseExpr(p), 1845 }, 1846 }); 1847 case TOKEN_KEYWORD_COMPTIME: 1848 return addNode(&p->nodes, 1849 (AstNodeItem) { 1850 .tag = AST_NODE_COMPTIME, 1851 .main_token = nextToken(p), 1852 .data = { .lhs = expectExpr(p), .rhs = 0 }, 1853 }); 1854 case TOKEN_KEYWORD_NOSUSPEND: 1855 return addNode(&p->nodes, 1856 (AstNodeItem) { 1857 .tag = AST_NODE_NOSUSPEND, 1858 .main_token = nextToken(p), 1859 .data = { .lhs = expectExpr(p), .rhs = 0 }, 1860 }); 1861 case TOKEN_KEYWORD_RESUME: 1862 return addNode(&p->nodes, 1863 (AstNodeItem) { 1864 .tag = AST_NODE_RESUME, 1865 .main_token = nextToken(p), 1866 .data = { .lhs = expectExpr(p), .rhs = 0 }, 1867 }); 1868 case TOKEN_KEYWORD_RETURN: 1869 return addNode(&p->nodes, 1870 (AstNodeItem) { 1871 .tag = AST_NODE_RETURN, 1872 .main_token = nextToken(p), 1873 .data = { .lhs = parseExpr(p), .rhs = 0 }, 1874 }); 1875 case TOKEN_IDENTIFIER: 1876 if (p->token_tags[p->tok_i + 1] == TOKEN_COLON) { 1877 switch (p->token_tags[p->tok_i + 2]) { 1878 case TOKEN_KEYWORD_INLINE: 1879 p->tok_i += 3; 1880 if (p->token_tags[p->tok_i] == TOKEN_KEYWORD_FOR) 1881 return parseForExpr(p); 1882 if (p->token_tags[p->tok_i] == TOKEN_KEYWORD_WHILE) 1883 return parseWhileExpr(p); 1884 fail(p, "expected for or while after inline"); 1885 return 0; // tcc 1886 case TOKEN_KEYWORD_FOR: 1887 p->tok_i += 2; 1888 return parseForExpr(p); 1889 case TOKEN_KEYWORD_WHILE: 1890 p->tok_i += 2; 1891 return parseWhileExpr(p); 1892 case TOKEN_L_BRACE: 1893 p->tok_i += 2; 1894 return parseBlock(p); 1895 default: 1896 return parseCurlySuffixExpr(p); 1897 } 1898 } else { 1899 return parseCurlySuffixExpr(p); 1900 } 1901 case TOKEN_KEYWORD_WHILE: 1902 return parseWhileExpr(p); 1903 case TOKEN_KEYWORD_FOR: 1904 return parseForExpr(p); 1905 case TOKEN_KEYWORD_INLINE: 1906 p->tok_i++; 1907 if (p->token_tags[p->tok_i] == TOKEN_KEYWORD_FOR) 1908 return parseForExpr(p); 1909 if (p->token_tags[p->tok_i] == TOKEN_KEYWORD_WHILE) 1910 return parseWhileExpr(p); 1911 fail(p, "parsePrimaryExpr: inline without for/while"); 1912 return 0; // tcc 1913 case TOKEN_L_BRACE: 1914 return parseBlock(p); 1915 default: 1916 return parseCurlySuffixExpr(p); 1917 } 1918 1919 return 0; // tcc 1920 } 1921 1922 static AstNodeIndex parseIfExpr(Parser* p) { 1923 const AstTokenIndex if_token = eatToken(p, TOKEN_KEYWORD_IF); 1924 if (if_token == null_token) 1925 return null_node; 1926 1927 expectToken(p, TOKEN_L_PAREN); 1928 const AstNodeIndex condition = expectExpr(p); 1929 expectToken(p, TOKEN_R_PAREN); 1930 parsePtrPayload(p); 1931 1932 const AstNodeIndex then_expr = expectExpr(p); 1933 1934 if (eatToken(p, TOKEN_KEYWORD_ELSE) == null_token) { 1935 return addNode(&p->nodes, 1936 (AstNodeItem) { 1937 .tag = AST_NODE_IF_SIMPLE, 1938 .main_token = if_token, 1939 .data = { .lhs = condition, .rhs = then_expr }, 1940 }); 1941 } 1942 1943 parsePayload(p); 1944 const AstNodeIndex else_expr = expectExpr(p); 1945 return addNode(&p->nodes, 1946 (AstNodeItem) { 1947 .tag = AST_NODE_IF, 1948 .main_token = if_token, 1949 .data = { 1950 .lhs = condition, 1951 .rhs = addExtra(p, 1952 (AstNodeIndex[]) { then_expr, else_expr }, 2), 1953 }, 1954 }); 1955 } 1956 1957 static AstNodeIndex parseBlock(Parser* p) { 1958 const AstNodeIndex lbrace = eatToken(p, TOKEN_L_BRACE); 1959 if (lbrace == null_token) 1960 return null_node; 1961 1962 const uint32_t scratch_top = p->scratch.len; 1963 1964 while (1) { 1965 if (p->token_tags[p->tok_i] == TOKEN_R_BRACE) 1966 break; 1967 1968 // "const AstNodeIndex statement" once tinycc supports typeof_unqual 1969 // (C23) 1970 AstNodeIndex statement = expectStatement(p, true); 1971 if (statement == 0) 1972 break; 1973 SLICE_APPEND(AstNodeIndex, &p->scratch, statement); 1974 } 1975 expectToken(p, TOKEN_R_BRACE); 1976 const uint32_t statements_len = p->scratch.len - scratch_top; 1977 p->scratch.len = scratch_top; 1978 const bool semicolon = statements_len != 0 1979 && (p->token_tags[p->tok_i - 2] == TOKEN_SEMICOLON); 1980 switch (statements_len) { 1981 case 0: 1982 return addNode( 1983 &p->nodes, 1984 (AstNodeItem) { 1985 .tag = AST_NODE_BLOCK_TWO, 1986 .main_token = lbrace, 1987 .data = { 1988 .lhs = 0, 1989 .rhs = 0, 1990 }, 1991 }); 1992 case 1: 1993 return addNode( 1994 &p->nodes, 1995 (AstNodeItem) { 1996 .tag = semicolon ? AST_NODE_BLOCK_TWO_SEMICOLON : AST_NODE_BLOCK_TWO, 1997 .main_token = lbrace, 1998 .data = { 1999 .lhs = p->scratch.arr[scratch_top], 2000 .rhs = 0, 2001 }, 2002 }); 2003 case 2: 2004 return addNode( 2005 &p->nodes, 2006 (AstNodeItem) { 2007 .tag = semicolon ? AST_NODE_BLOCK_TWO_SEMICOLON : AST_NODE_BLOCK_TWO, 2008 .main_token = lbrace, 2009 .data = { 2010 .lhs = p->scratch.arr[scratch_top], 2011 .rhs = p->scratch.arr[scratch_top + 1], 2012 }, 2013 }); 2014 default:; 2015 const AstSubRange span 2016 = listToSpan(p, &p->scratch.arr[scratch_top], statements_len); 2017 return addNode( 2018 &p->nodes, 2019 (AstNodeItem) { 2020 .tag = semicolon ? AST_NODE_BLOCK_SEMICOLON : AST_NODE_BLOCK, 2021 .main_token = lbrace, 2022 .data = { 2023 .lhs = span.start, 2024 .rhs = span.end, 2025 }, 2026 }); 2027 } 2028 2029 return 0; 2030 } 2031 2032 // forPrefix parses the for prefix: (expr, expr, ...) |captures|. 2033 // Returns the number of input expressions. The inputs are appended 2034 // to the scratch buffer. 2035 static uint32_t forPrefix(Parser* p) { 2036 const uint32_t start = p->scratch.len; 2037 expectToken(p, TOKEN_L_PAREN); 2038 2039 while (true) { 2040 AstNodeIndex input = expectExpr(p); 2041 if (eatToken(p, TOKEN_ELLIPSIS2) != null_token) { 2042 const AstTokenIndex ellipsis = p->tok_i - 1; 2043 const AstNodeIndex end = parseExpr(p); 2044 input = addNode(&p->nodes, 2045 (AstNodeItem) { 2046 .tag = AST_NODE_FOR_RANGE, 2047 .main_token = ellipsis, 2048 .data = { .lhs = input, .rhs = end }, 2049 }); 2050 } 2051 SLICE_APPEND(AstNodeIndex, &p->scratch, input); 2052 if (p->token_tags[p->tok_i] == TOKEN_COMMA) { 2053 p->tok_i++; 2054 if (eatToken(p, TOKEN_R_PAREN) != null_token) 2055 break; 2056 continue; 2057 } 2058 expectToken(p, TOKEN_R_PAREN); 2059 break; 2060 } 2061 const uint32_t inputs = p->scratch.len - start; 2062 2063 // Parse payload |a, *b, c| 2064 if (eatToken(p, TOKEN_PIPE) == null_token) { 2065 fail(p, "expected loop payload"); 2066 } 2067 { 2068 while (true) { 2069 eatToken(p, TOKEN_ASTERISK); 2070 expectToken(p, TOKEN_IDENTIFIER); 2071 if (p->token_tags[p->tok_i] == TOKEN_COMMA) { 2072 p->tok_i++; 2073 if (eatToken(p, TOKEN_PIPE) != null_token) 2074 break; 2075 continue; 2076 } 2077 expectToken(p, TOKEN_PIPE); 2078 break; 2079 } 2080 } 2081 return inputs; 2082 } 2083 2084 static AstNodeIndex parseWhileExpr(Parser* p) { 2085 const AstTokenIndex while_token = eatToken(p, TOKEN_KEYWORD_WHILE); 2086 if (while_token == null_token) 2087 return null_node; 2088 2089 expectToken(p, TOKEN_L_PAREN); 2090 const AstNodeIndex condition = expectExpr(p); 2091 expectToken(p, TOKEN_R_PAREN); 2092 parsePtrPayload(p); 2093 2094 const AstNodeIndex cont_expr = parseWhileContinueExpr(p); 2095 2096 const AstNodeIndex body = expectExpr(p); 2097 2098 if (eatToken(p, TOKEN_KEYWORD_ELSE) == null_token) { 2099 if (cont_expr != 0) { 2100 return addNode(&p->nodes, 2101 (AstNodeItem) { 2102 .tag = AST_NODE_WHILE_CONT, 2103 .main_token = while_token, 2104 .data = { 2105 .lhs = condition, 2106 .rhs = addExtra(p, 2107 (AstNodeIndex[]) { cont_expr, body }, 2), 2108 }, 2109 }); 2110 } 2111 return addNode(&p->nodes, 2112 (AstNodeItem) { 2113 .tag = AST_NODE_WHILE_SIMPLE, 2114 .main_token = while_token, 2115 .data = { .lhs = condition, .rhs = body }, 2116 }); 2117 } 2118 2119 parsePayload(p); 2120 const AstNodeIndex else_expr = expectExpr(p); 2121 return addNode(&p->nodes, 2122 (AstNodeItem) { 2123 .tag = AST_NODE_WHILE, 2124 .main_token = while_token, 2125 .data = { 2126 .lhs = condition, 2127 .rhs = addExtra(p, 2128 (AstNodeIndex[]) { OPT(cont_expr), body, else_expr }, 2129 3), 2130 }, 2131 }); 2132 } 2133 2134 static AstNodeIndex parseWhileContinueExpr(Parser* p) { 2135 if (eatToken(p, TOKEN_COLON) == null_token) 2136 return null_node; 2137 expectToken(p, TOKEN_L_PAREN); 2138 const AstNodeIndex expr = parseAssignExpr(p); 2139 expectToken(p, TOKEN_R_PAREN); 2140 return expr; 2141 } 2142 2143 static AstNodeIndex parseCurlySuffixExpr(Parser* p) { 2144 const AstNodeIndex lhs = parseTypeExpr(p); 2145 if (lhs == 0) 2146 return null_node; 2147 2148 const AstTokenIndex lbrace = eatToken(p, TOKEN_L_BRACE); 2149 if (lbrace == null_token) 2150 return lhs; 2151 2152 return parseInitList(p, lhs, lbrace); 2153 } 2154 2155 // parseInitList parses the contents of { ... } for struct/array init. 2156 // lhs is the type expression (0 for anonymous .{...}). 2157 // lbrace is the lbrace token index. 2158 static AstNodeIndex parseInitList( 2159 Parser* p, AstNodeIndex lhs, AstTokenIndex lbrace) { 2160 const uint32_t scratch_top = p->scratch.len; 2161 2162 const AstNodeIndex field_init = parseFieldInit(p); 2163 if (field_init != 0) { 2164 // Struct init 2165 SLICE_APPEND(AstNodeIndex, &p->scratch, field_init); 2166 while (true) { 2167 if (p->token_tags[p->tok_i] == TOKEN_COMMA) 2168 p->tok_i++; 2169 else if (p->token_tags[p->tok_i] == TOKEN_R_BRACE) { 2170 p->tok_i++; 2171 break; 2172 } else { 2173 fail(p, "parseInitList: expected , or } in struct init"); 2174 } 2175 if (eatToken(p, TOKEN_R_BRACE) != null_token) 2176 break; 2177 const AstNodeIndex next = parseFieldInit(p); 2178 assert(next != 0); 2179 SLICE_APPEND(AstNodeIndex, &p->scratch, next); 2180 } 2181 const bool comma = p->token_tags[p->tok_i - 2] == TOKEN_COMMA; 2182 const uint32_t inits_len = p->scratch.len - scratch_top; 2183 p->scratch.len = scratch_top; 2184 if (lhs == 0) { 2185 // Anonymous struct init: .{...} 2186 switch (inits_len) { 2187 case 0: 2188 case 1: 2189 case 2: 2190 return addNode(&p->nodes, 2191 (AstNodeItem) { 2192 .tag = comma 2193 ? AST_NODE_STRUCT_INIT_DOT_TWO_COMMA 2194 : AST_NODE_STRUCT_INIT_DOT_TWO, 2195 .main_token = lbrace, 2196 .data = { 2197 .lhs = inits_len >= 1 2198 ? p->scratch.arr[scratch_top] 2199 : 0, 2200 .rhs = inits_len >= 2 2201 ? p->scratch.arr[scratch_top + 1] 2202 : 0, 2203 }, 2204 }); 2205 default:; 2206 const AstSubRange span 2207 = listToSpan(p, &p->scratch.arr[scratch_top], inits_len); 2208 return addNode(&p->nodes, 2209 (AstNodeItem) { 2210 .tag = comma ? AST_NODE_STRUCT_INIT_DOT_COMMA 2211 : AST_NODE_STRUCT_INIT_DOT, 2212 .main_token = lbrace, 2213 .data = { .lhs = span.start, .rhs = span.end }, 2214 }); 2215 } 2216 } 2217 // Named struct init: X{...} 2218 switch (inits_len) { 2219 case 0: 2220 case 1: 2221 return addNode(&p->nodes, 2222 (AstNodeItem) { 2223 .tag = comma ? AST_NODE_STRUCT_INIT_ONE_COMMA 2224 : AST_NODE_STRUCT_INIT_ONE, 2225 .main_token = lbrace, 2226 .data = { 2227 .lhs = lhs, 2228 .rhs = inits_len >= 1 2229 ? p->scratch.arr[scratch_top] 2230 : 0, 2231 }, 2232 }); 2233 default:; 2234 const AstSubRange span 2235 = listToSpan(p, &p->scratch.arr[scratch_top], inits_len); 2236 return addNode(&p->nodes, 2237 (AstNodeItem) { 2238 .tag = comma ? AST_NODE_STRUCT_INIT_COMMA 2239 : AST_NODE_STRUCT_INIT, 2240 .main_token = lbrace, 2241 .data = { 2242 .lhs = lhs, 2243 .rhs = addExtra(p, 2244 (AstNodeIndex[]) { span.start, span.end }, 2), 2245 }, 2246 }); 2247 } 2248 } 2249 2250 // Array init or empty init 2251 while (true) { 2252 if (eatToken(p, TOKEN_R_BRACE) != null_token) 2253 break; 2254 const AstNodeIndex elem = expectExpr(p); 2255 SLICE_APPEND(AstNodeIndex, &p->scratch, elem); 2256 if (p->token_tags[p->tok_i] == TOKEN_COMMA) 2257 p->tok_i++; 2258 else if (p->token_tags[p->tok_i] == TOKEN_R_BRACE) { 2259 p->tok_i++; 2260 break; 2261 } else { 2262 fail(p, "parseInitList: expected , or } in array init"); 2263 } 2264 } 2265 2266 const bool comma = p->token_tags[p->tok_i - 2] == TOKEN_COMMA; 2267 const uint32_t elems_len = p->scratch.len - scratch_top; 2268 p->scratch.len = scratch_top; 2269 if (lhs == 0) { 2270 // Anonymous array init: .{a, b, ...} 2271 switch (elems_len) { 2272 case 0: 2273 case 1: 2274 case 2: 2275 return addNode(&p->nodes, 2276 (AstNodeItem) { 2277 .tag = (elems_len == 0) 2278 ? AST_NODE_STRUCT_INIT_DOT_TWO 2279 : (comma ? AST_NODE_ARRAY_INIT_DOT_TWO_COMMA 2280 : AST_NODE_ARRAY_INIT_DOT_TWO), 2281 .main_token = lbrace, 2282 .data = { 2283 .lhs = elems_len >= 1 2284 ? p->scratch.arr[scratch_top] 2285 : 0, 2286 .rhs = elems_len >= 2 2287 ? p->scratch.arr[scratch_top + 1] 2288 : 0, 2289 }, 2290 }); 2291 default:; 2292 const AstSubRange span 2293 = listToSpan(p, &p->scratch.arr[scratch_top], elems_len); 2294 return addNode(&p->nodes, 2295 (AstNodeItem) { 2296 .tag = comma ? AST_NODE_ARRAY_INIT_DOT_COMMA 2297 : AST_NODE_ARRAY_INIT_DOT, 2298 .main_token = lbrace, 2299 .data = { .lhs = span.start, .rhs = span.end }, 2300 }); 2301 } 2302 } 2303 // Named init: X{a, b, ...} 2304 switch (elems_len) { 2305 case 0: 2306 // Empty init X{} — treat as struct init 2307 return addNode(&p->nodes, 2308 (AstNodeItem) { 2309 .tag = AST_NODE_STRUCT_INIT_ONE, 2310 .main_token = lbrace, 2311 .data = { .lhs = lhs, .rhs = 0 }, 2312 }); 2313 case 1: 2314 return addNode(&p->nodes, 2315 (AstNodeItem) { 2316 .tag = comma ? AST_NODE_ARRAY_INIT_ONE_COMMA 2317 : AST_NODE_ARRAY_INIT_ONE, 2318 .main_token = lbrace, 2319 .data = { 2320 .lhs = lhs, 2321 .rhs = p->scratch.arr[scratch_top], 2322 }, 2323 }); 2324 default:; 2325 const AstSubRange span 2326 = listToSpan(p, &p->scratch.arr[scratch_top], elems_len); 2327 return addNode(&p->nodes, 2328 (AstNodeItem) { 2329 .tag = comma ? AST_NODE_ARRAY_INIT_COMMA 2330 : AST_NODE_ARRAY_INIT, 2331 .main_token = lbrace, 2332 .data = { 2333 .lhs = lhs, 2334 .rhs = addExtra(p, 2335 (AstNodeIndex[]) { span.start, span.end }, 2), 2336 }, 2337 }); 2338 } 2339 } 2340 2341 static AstNodeIndex parseErrorUnionExpr(Parser* p) { 2342 const AstNodeIndex suffix_expr = parseSuffixExpr(p); 2343 if (suffix_expr == 0) 2344 return null_node; 2345 2346 const AstNodeIndex bang = eatToken(p, TOKEN_BANG); 2347 if (bang == null_token) 2348 return suffix_expr; 2349 2350 return addNode( 2351 &p->nodes, 2352 (AstNodeItem) { 2353 .tag = AST_NODE_ERROR_UNION, 2354 .main_token = bang, 2355 .data = { 2356 .lhs = suffix_expr, 2357 .rhs = parseTypeExpr(p), 2358 }, 2359 }); 2360 } 2361 2362 static AstNodeIndex parseSuffixExpr(Parser* p) { 2363 AstNodeIndex res = parsePrimaryTypeExpr(p); 2364 if (res == 0) 2365 return res; 2366 2367 while (true) { 2368 const AstNodeIndex suffix_op = parseSuffixOp(p, res); 2369 if (suffix_op != 0) { 2370 res = suffix_op; 2371 continue; 2372 } 2373 const AstTokenIndex lparen = eatToken(p, TOKEN_L_PAREN); 2374 if (lparen == null_token) 2375 return res; 2376 2377 const uint32_t scratch_top = p->scratch.len; 2378 while (true) { 2379 if (eatToken(p, TOKEN_R_PAREN) != null_token) 2380 break; 2381 const AstNodeIndex arg = expectExpr(p); 2382 SLICE_APPEND(AstNodeIndex, &p->scratch, arg); 2383 if (p->token_tags[p->tok_i] == TOKEN_COMMA) { 2384 p->tok_i++; 2385 continue; 2386 } 2387 expectToken(p, TOKEN_R_PAREN); 2388 break; 2389 } 2390 2391 const bool comma = p->token_tags[p->tok_i - 2] == TOKEN_COMMA; 2392 const uint32_t params_len = p->scratch.len - scratch_top; 2393 p->scratch.len = scratch_top; 2394 switch (params_len) { 2395 case 0: 2396 res = addNode( 2397 &p->nodes, 2398 (AstNodeItem) { 2399 .tag = comma ? AST_NODE_CALL_ONE_COMMA : AST_NODE_CALL_ONE, 2400 .main_token = lparen, 2401 .data = { 2402 .lhs = res, 2403 .rhs = 0, 2404 }, 2405 }); 2406 break; 2407 case 1: 2408 res = addNode( 2409 &p->nodes, 2410 (AstNodeItem) { 2411 .tag = comma ? AST_NODE_CALL_ONE_COMMA : AST_NODE_CALL_ONE, 2412 .main_token = lparen, 2413 .data = { 2414 .lhs = res, 2415 .rhs = p->scratch.arr[scratch_top], 2416 }, 2417 }); 2418 break; 2419 default:; 2420 const AstSubRange span 2421 = listToSpan(p, &p->scratch.arr[scratch_top], params_len); 2422 res = addNode( 2423 &p->nodes, 2424 (AstNodeItem) { 2425 .tag = comma ? AST_NODE_CALL_COMMA : AST_NODE_CALL, 2426 .main_token = lparen, 2427 .data = { 2428 .lhs = res, 2429 .rhs = addExtra(p, (AstNodeIndex[]) { 2430 span.start, 2431 span.end, 2432 }, 2), 2433 }, 2434 }); 2435 break; 2436 } 2437 } 2438 } 2439 2440 static AstNodeIndex parsePrimaryTypeExpr(Parser* p) { 2441 const TokenizerTag tok = p->token_tags[p->tok_i]; 2442 switch (tok) { 2443 case TOKEN_CHAR_LITERAL: 2444 return addNode(&p->nodes, 2445 (AstNodeItem) { 2446 .tag = AST_NODE_CHAR_LITERAL, 2447 .main_token = nextToken(p), 2448 .data = {}, 2449 }); 2450 case TOKEN_NUMBER_LITERAL: 2451 return addNode(&p->nodes, 2452 (AstNodeItem) { 2453 .tag = AST_NODE_NUMBER_LITERAL, 2454 .main_token = nextToken(p), 2455 .data = {}, 2456 }); 2457 case TOKEN_KEYWORD_UNREACHABLE: 2458 return addNode(&p->nodes, 2459 (AstNodeItem) { 2460 .tag = AST_NODE_UNREACHABLE_LITERAL, 2461 .main_token = nextToken(p), 2462 .data = {}, 2463 }); 2464 case TOKEN_KEYWORD_ANYFRAME: 2465 fail(p, "unsupported primary type expression"); 2466 case TOKEN_STRING_LITERAL: 2467 return addNode(&p->nodes, 2468 (AstNodeItem) { 2469 .tag = AST_NODE_STRING_LITERAL, 2470 .main_token = nextToken(p), 2471 .data = {}, 2472 }); 2473 case TOKEN_BUILTIN: 2474 return parseBuiltinCall(p); 2475 case TOKEN_KEYWORD_FN: 2476 return parseFnProto(p); 2477 case TOKEN_KEYWORD_IF: 2478 return parseIfExpr(p); 2479 case TOKEN_KEYWORD_SWITCH: 2480 return parseSwitchExpr(p); 2481 case TOKEN_KEYWORD_EXTERN: 2482 case TOKEN_KEYWORD_PACKED: 2483 // extern/packed can precede struct/union/enum 2484 switch (p->token_tags[p->tok_i + 1]) { 2485 case TOKEN_KEYWORD_STRUCT: 2486 case TOKEN_KEYWORD_UNION: 2487 case TOKEN_KEYWORD_ENUM: 2488 p->tok_i++; // consume extern/packed 2489 return parseContainerDeclAuto(p); 2490 default: 2491 fail(p, "unsupported primary type expression"); 2492 } 2493 case TOKEN_KEYWORD_STRUCT: 2494 case TOKEN_KEYWORD_OPAQUE: 2495 case TOKEN_KEYWORD_ENUM: 2496 case TOKEN_KEYWORD_UNION: 2497 return parseContainerDeclAuto(p); 2498 case TOKEN_KEYWORD_COMPTIME: 2499 return addNode(&p->nodes, 2500 (AstNodeItem) { 2501 .tag = AST_NODE_COMPTIME, 2502 .main_token = nextToken(p), 2503 .data = { .lhs = parseTypeExpr(p), .rhs = 0 }, 2504 }); 2505 case TOKEN_MULTILINE_STRING_LITERAL_LINE: { 2506 const AstTokenIndex first = nextToken(p); 2507 AstTokenIndex last = first; 2508 while (p->token_tags[p->tok_i] == TOKEN_MULTILINE_STRING_LITERAL_LINE) 2509 last = nextToken(p); 2510 return addNode(&p->nodes, 2511 (AstNodeItem) { 2512 .tag = AST_NODE_MULTILINE_STRING_LITERAL, 2513 .main_token = first, 2514 .data = { .lhs = first, .rhs = last }, 2515 }); 2516 } 2517 case TOKEN_IDENTIFIER: 2518 if (p->token_tags[p->tok_i + 1] == TOKEN_COLON) { 2519 switch (p->token_tags[p->tok_i + 2]) { 2520 case TOKEN_L_BRACE: { 2521 // Labeled block: label: { ... } 2522 nextToken(p); // consume label 2523 nextToken(p); // consume ':' 2524 return parseBlock(p); 2525 } 2526 case TOKEN_KEYWORD_WHILE: 2527 return parseLabeledStatement(p); 2528 case TOKEN_KEYWORD_FOR: 2529 return parseLabeledStatement(p); 2530 default: 2531 break; 2532 } 2533 } 2534 return addNode(&p->nodes, 2535 (AstNodeItem) { 2536 .tag = AST_NODE_IDENTIFIER, 2537 .main_token = nextToken(p), 2538 .data = {}, 2539 }); 2540 case TOKEN_KEYWORD_FOR: 2541 return parseForExpr(p); 2542 case TOKEN_KEYWORD_WHILE: 2543 return parseWhileExpr(p); 2544 case TOKEN_KEYWORD_INLINE: 2545 case TOKEN_PERIOD: 2546 switch (p->token_tags[p->tok_i + 1]) { 2547 case TOKEN_IDENTIFIER: { 2548 const AstTokenIndex dot = nextToken(p); 2549 return addNode(&p->nodes, 2550 (AstNodeItem) { 2551 .tag = AST_NODE_ENUM_LITERAL, 2552 .main_token = nextToken(p), 2553 .data = { .lhs = dot, .rhs = 0 }, 2554 }); 2555 } 2556 case TOKEN_L_BRACE: { 2557 // Anonymous struct/array init: .{ ... } 2558 const AstTokenIndex lbrace = p->tok_i + 1; 2559 p->tok_i = lbrace + 1; 2560 return parseInitList(p, null_node, lbrace); 2561 } 2562 default: 2563 fail(p, "unsupported period suffix"); 2564 } 2565 return 0; // tcc 2566 case TOKEN_KEYWORD_ERROR: 2567 switch (p->token_tags[p->tok_i + 1]) { 2568 case TOKEN_PERIOD: { 2569 const AstTokenIndex error_token = nextToken(p); 2570 const AstTokenIndex dot = nextToken(p); 2571 const AstTokenIndex value = expectToken(p, TOKEN_IDENTIFIER); 2572 return addNode(&p->nodes, 2573 (AstNodeItem) { 2574 .tag = AST_NODE_ERROR_VALUE, 2575 .main_token = error_token, 2576 .data = { .lhs = dot, .rhs = value }, 2577 }); 2578 } 2579 case TOKEN_L_BRACE: { 2580 const AstTokenIndex error_token = nextToken(p); 2581 const AstTokenIndex lbrace = nextToken(p); 2582 while (p->token_tags[p->tok_i] != TOKEN_R_BRACE) 2583 p->tok_i++; 2584 const AstTokenIndex rbrace = nextToken(p); 2585 return addNode(&p->nodes, 2586 (AstNodeItem) { 2587 .tag = AST_NODE_ERROR_SET_DECL, 2588 .main_token = error_token, 2589 .data = { .lhs = lbrace, .rhs = rbrace }, 2590 }); 2591 } 2592 default: { 2593 const AstTokenIndex main_token = nextToken(p); 2594 const AstTokenIndex period = eatToken(p, TOKEN_PERIOD); 2595 if (period == null_token) { 2596 fail(p, "expected '.'"); 2597 } 2598 const AstTokenIndex identifier = eatToken(p, TOKEN_IDENTIFIER); 2599 if (identifier == null_token) { 2600 fail(p, "expected identifier"); 2601 } 2602 return addNode(&p->nodes, 2603 (AstNodeItem) { 2604 .tag = AST_NODE_ERROR_VALUE, 2605 .main_token = main_token, 2606 .data = { .lhs = period, .rhs = identifier }, 2607 }); 2608 } 2609 } 2610 case TOKEN_L_PAREN: { 2611 const AstTokenIndex lparen = nextToken(p); 2612 const AstNodeIndex inner = expectExpr(p); 2613 const AstTokenIndex rparen = expectToken(p, TOKEN_R_PAREN); 2614 return addNode(&p->nodes, 2615 (AstNodeItem) { 2616 .tag = AST_NODE_GROUPED_EXPRESSION, 2617 .main_token = lparen, 2618 .data = { .lhs = inner, .rhs = rparen }, 2619 }); 2620 } 2621 default: 2622 return null_node; 2623 } 2624 } 2625 2626 static AstNodeIndex parseSwitchExpr(Parser* p) { 2627 const AstTokenIndex switch_token = eatToken(p, TOKEN_KEYWORD_SWITCH); 2628 if (switch_token == null_token) 2629 return null_node; 2630 2631 expectToken(p, TOKEN_L_PAREN); 2632 const AstNodeIndex operand = expectExpr(p); 2633 expectToken(p, TOKEN_R_PAREN); 2634 expectToken(p, TOKEN_L_BRACE); 2635 2636 const AstSubRange span = parseSwitchProngList(p); 2637 const bool comma = p->token_tags[p->tok_i - 2] == TOKEN_COMMA; 2638 return addNode(&p->nodes, 2639 (AstNodeItem) { 2640 .tag = comma ? AST_NODE_SWITCH_COMMA : AST_NODE_SWITCH, 2641 .main_token = switch_token, 2642 .data = { 2643 .lhs = operand, 2644 .rhs = addExtra(p, 2645 (AstNodeIndex[]) { span.start, span.end }, 2), 2646 }, 2647 }); 2648 } 2649 2650 static AstNodeIndex parseAsmExpr(Parser* p) { 2651 const AstTokenIndex asm_token = nextToken(p); 2652 assert(p->token_tags[asm_token] == TOKEN_KEYWORD_ASM); 2653 eatToken(p, TOKEN_KEYWORD_VOLATILE); 2654 expectToken(p, TOKEN_L_PAREN); 2655 const AstNodeIndex template = expectExpr(p); 2656 2657 // Simple asm: asm("...") 2658 if (eatToken(p, TOKEN_R_PAREN) != null_token) { 2659 return addNode(&p->nodes, 2660 (AstNodeItem) { 2661 .tag = AST_NODE_ASM_SIMPLE, 2662 .main_token = asm_token, 2663 .data = { .lhs = template, .rhs = p->tok_i - 1 }, 2664 }); 2665 } 2666 2667 // Complex asm with outputs, inputs, clobbers 2668 expectToken(p, TOKEN_COLON); 2669 2670 const uint32_t scratch_top = p->scratch.len; 2671 2672 // Parse outputs 2673 while (true) { 2674 const AstNodeIndex output = parseAsmOutputItem(p); 2675 if (output == 0) 2676 break; 2677 SLICE_APPEND(AstNodeIndex, &p->scratch, output); 2678 if (eatToken(p, TOKEN_COMMA) == null_token) 2679 break; 2680 } 2681 2682 // Parse inputs (after second colon) 2683 if (eatToken(p, TOKEN_COLON) != null_token) { 2684 while (true) { 2685 const AstNodeIndex input = parseAsmInputItem(p); 2686 if (input == 0) 2687 break; 2688 SLICE_APPEND(AstNodeIndex, &p->scratch, input); 2689 if (eatToken(p, TOKEN_COMMA) == null_token) 2690 break; 2691 } 2692 } 2693 2694 // Parse clobbers (after third colon) 2695 if (eatToken(p, TOKEN_COLON) != null_token) { 2696 if (p->token_tags[p->tok_i] == TOKEN_STRING_LITERAL) { 2697 // Legacy clobber format: "str1", "str2", ... 2698 // Produces asm_legacy node 2699 while (p->token_tags[p->tok_i] == TOKEN_STRING_LITERAL) { 2700 p->tok_i++; 2701 if (eatToken(p, TOKEN_COMMA) == null_token) 2702 break; 2703 } 2704 const AstTokenIndex rparen = expectToken(p, TOKEN_R_PAREN); 2705 const uint32_t items_len = p->scratch.len - scratch_top; 2706 const AstSubRange items_span 2707 = listToSpan(p, &p->scratch.arr[scratch_top], items_len); 2708 p->scratch.len = scratch_top; 2709 return addNode(&p->nodes, 2710 (AstNodeItem) { 2711 .tag = AST_NODE_ASM_LEGACY, 2712 .main_token = asm_token, 2713 .data = { 2714 .lhs = template, 2715 .rhs = addExtra(p, 2716 (AstNodeIndex[]) { items_span.start, 2717 items_span.end, rparen }, 2718 3), 2719 }, 2720 }); 2721 } 2722 // New clobber format: expression (e.g. .{ .clobber = true }) 2723 AstNodeIndex clobbers = 0; 2724 if (p->token_tags[p->tok_i] != TOKEN_R_PAREN) 2725 clobbers = expectExpr(p); 2726 2727 const AstTokenIndex rparen = expectToken(p, TOKEN_R_PAREN); 2728 const uint32_t items_len = p->scratch.len - scratch_top; 2729 const AstSubRange items_span 2730 = listToSpan(p, &p->scratch.arr[scratch_top], items_len); 2731 p->scratch.len = scratch_top; 2732 return addNode(&p->nodes, 2733 (AstNodeItem) { 2734 .tag = AST_NODE_ASM, 2735 .main_token = asm_token, 2736 .data = { 2737 .lhs = template, 2738 .rhs = addExtra(p, 2739 (AstNodeIndex[]) { items_span.start, 2740 items_span.end, OPT(clobbers), rparen }, 2741 4), 2742 }, 2743 }); 2744 } 2745 2746 // No clobbers 2747 const AstTokenIndex rparen = expectToken(p, TOKEN_R_PAREN); 2748 const uint32_t items_len = p->scratch.len - scratch_top; 2749 const AstSubRange items_span 2750 = listToSpan(p, &p->scratch.arr[scratch_top], items_len); 2751 p->scratch.len = scratch_top; 2752 return addNode(&p->nodes, 2753 (AstNodeItem) { 2754 .tag = AST_NODE_ASM, 2755 .main_token = asm_token, 2756 .data = { 2757 .lhs = template, 2758 .rhs = addExtra(p, 2759 (AstNodeIndex[]) { items_span.start, items_span.end, 2760 OPT((AstNodeIndex)0), rparen }, 2761 4), 2762 }, 2763 }); 2764 } 2765 2766 static AstNodeIndex parseAsmOutputItem(Parser* p) { 2767 if (p->token_tags[p->tok_i] == TOKEN_L_BRACKET) { 2768 p->tok_i++; // [ 2769 const AstTokenIndex ident = expectToken(p, TOKEN_IDENTIFIER); 2770 expectToken(p, TOKEN_R_BRACKET); 2771 expectToken(p, TOKEN_STRING_LITERAL); 2772 expectToken(p, TOKEN_L_PAREN); 2773 AstNodeIndex type_expr = 0; 2774 if (eatToken(p, TOKEN_ARROW) != null_token) { 2775 type_expr = parseTypeExpr(p); 2776 } else { 2777 expectToken(p, TOKEN_IDENTIFIER); 2778 } 2779 const AstTokenIndex rparen = expectToken(p, TOKEN_R_PAREN); 2780 return addNode(&p->nodes, 2781 (AstNodeItem) { 2782 .tag = AST_NODE_ASM_OUTPUT, 2783 .main_token = ident, 2784 .data = { .lhs = type_expr, .rhs = rparen }, 2785 }); 2786 } 2787 return null_node; 2788 } 2789 2790 static AstNodeIndex parseAsmInputItem(Parser* p) { 2791 if (p->token_tags[p->tok_i] == TOKEN_L_BRACKET) { 2792 p->tok_i++; // [ 2793 const AstTokenIndex ident = expectToken(p, TOKEN_IDENTIFIER); 2794 expectToken(p, TOKEN_R_BRACKET); 2795 expectToken(p, TOKEN_STRING_LITERAL); 2796 expectToken(p, TOKEN_L_PAREN); 2797 const AstNodeIndex operand = expectExpr(p); 2798 const AstTokenIndex rparen = expectToken(p, TOKEN_R_PAREN); 2799 return addNode(&p->nodes, 2800 (AstNodeItem) { 2801 .tag = AST_NODE_ASM_INPUT, 2802 .main_token = ident, 2803 .data = { .lhs = operand, .rhs = rparen }, 2804 }); 2805 } 2806 return null_node; 2807 } 2808 2809 static AstTokenIndex parseBreakLabel(Parser* p) { 2810 if (eatToken(p, TOKEN_COLON) == null_token) 2811 return null_token; 2812 return expectToken(p, TOKEN_IDENTIFIER); 2813 } 2814 2815 static AstTokenIndex parseBlockLabel(Parser* p) { 2816 if (p->token_tags[p->tok_i] == TOKEN_IDENTIFIER 2817 && p->token_tags[p->tok_i + 1] == TOKEN_COLON) { 2818 const AstTokenIndex identifier = p->tok_i; 2819 p->tok_i += 2; 2820 return identifier; 2821 } 2822 return null_node; 2823 } 2824 2825 // parseFieldInit tries to parse .field_name = expr; returns 0 if not a 2826 // field init 2827 static AstNodeIndex parseFieldInit(Parser* p) { 2828 if (p->token_tags[p->tok_i] == TOKEN_PERIOD 2829 && p->token_tags[p->tok_i + 1] == TOKEN_IDENTIFIER 2830 && p->token_tags[p->tok_i + 2] == TOKEN_EQUAL) { 2831 p->tok_i += 3; 2832 return expectExpr(p); 2833 } 2834 return null_node; 2835 } 2836 2837 static AstNodeIndex parseLinkSection(Parser* p) { 2838 if (eatToken(p, TOKEN_KEYWORD_LINKSECTION) == null_token) 2839 return null_node; 2840 expectToken(p, TOKEN_L_PAREN); 2841 const AstNodeIndex expr = expectExpr(p); 2842 expectToken(p, TOKEN_R_PAREN); 2843 return expr; 2844 } 2845 2846 static AstNodeIndex parseCallconv(Parser* p) { 2847 if (eatToken(p, TOKEN_KEYWORD_CALLCONV) == null_token) 2848 return null_node; 2849 expectToken(p, TOKEN_L_PAREN); 2850 const AstNodeIndex expr = expectExpr(p); 2851 expectToken(p, TOKEN_R_PAREN); 2852 return expr; 2853 } 2854 2855 static AstNodeIndex parseAddrSpace(Parser* p) { 2856 if (eatToken(p, TOKEN_KEYWORD_ADDRSPACE) == null_token) 2857 return null_node; 2858 expectToken(p, TOKEN_L_PAREN); 2859 const AstNodeIndex expr = expectExpr(p); 2860 expectToken(p, TOKEN_R_PAREN); 2861 return expr; 2862 } 2863 2864 static AstNodeIndex expectParamDecl(Parser* p) { 2865 eatDocComments(p); 2866 eatToken(p, TOKEN_KEYWORD_COMPTIME); 2867 eatToken(p, TOKEN_KEYWORD_NOALIAS); 2868 if (p->token_tags[p->tok_i] == TOKEN_IDENTIFIER 2869 && p->token_tags[p->tok_i + 1] == TOKEN_COLON) 2870 p->tok_i += 2; 2871 if (eatToken(p, TOKEN_KEYWORD_ANYTYPE) != null_token) 2872 return 0; 2873 return parseTypeExpr(p); 2874 } 2875 2876 static void parsePayload(Parser* p) { 2877 if (eatToken(p, TOKEN_PIPE) == null_token) 2878 return; 2879 expectToken(p, TOKEN_IDENTIFIER); 2880 expectToken(p, TOKEN_PIPE); 2881 } 2882 2883 static void parsePtrPayload(Parser* p) { 2884 if (eatToken(p, TOKEN_PIPE) == null_token) 2885 return; 2886 while (true) { 2887 eatToken(p, TOKEN_ASTERISK); 2888 expectToken(p, TOKEN_IDENTIFIER); 2889 if (p->token_tags[p->tok_i] == TOKEN_COMMA) { 2890 p->tok_i++; 2891 continue; 2892 } 2893 break; 2894 } 2895 expectToken(p, TOKEN_PIPE); 2896 } 2897 2898 static AstNodeIndex parseSwitchProng(Parser* p) { 2899 const uint32_t items_old_len = p->scratch.len; 2900 2901 if (eatToken(p, TOKEN_KEYWORD_ELSE) == null_token) { 2902 while (true) { 2903 const AstNodeIndex item = parseSwitchItem(p); 2904 if (item == 0) 2905 break; 2906 SLICE_APPEND(AstNodeIndex, &p->scratch, item); 2907 if (eatToken(p, TOKEN_COMMA) == null_token) 2908 break; 2909 } 2910 if (p->scratch.len == items_old_len) 2911 return null_node; 2912 } 2913 2914 const AstTokenIndex arrow 2915 = expectToken(p, TOKEN_EQUAL_ANGLE_BRACKET_RIGHT); 2916 parsePtrPayload(p); 2917 const AstNodeIndex case_body = parseAssignExpr(p); 2918 if (case_body == 0) { 2919 fail(p, "expected expression"); 2920 } 2921 2922 const uint32_t items_len = p->scratch.len - items_old_len; 2923 AstNodeIndex case_node; 2924 switch (items_len) { 2925 case 0: 2926 case 1: 2927 case_node = addNode(&p->nodes, 2928 (AstNodeItem) { 2929 .tag = AST_NODE_SWITCH_CASE_ONE, 2930 .main_token = arrow, 2931 .data = { 2932 .lhs 2933 = items_len >= 1 ? p->scratch.arr[items_old_len] : 0, 2934 .rhs = case_body, 2935 }, 2936 }); 2937 break; 2938 default: { 2939 const AstSubRange span 2940 = listToSpan(p, &p->scratch.arr[items_old_len], items_len); 2941 case_node = addNode(&p->nodes, 2942 (AstNodeItem) { 2943 .tag = AST_NODE_SWITCH_CASE, 2944 .main_token = arrow, 2945 .data = { 2946 .lhs = addExtra(p, 2947 (AstNodeIndex[]) { span.start, span.end }, 2), 2948 .rhs = case_body, 2949 }, 2950 }); 2951 } break; 2952 } 2953 2954 p->scratch.len = items_old_len; 2955 return case_node; 2956 } 2957 2958 static AstNodeIndex parseSwitchItem(Parser* p) { 2959 const AstNodeIndex expr = parseExpr(p); 2960 if (expr == 0) 2961 return null_node; 2962 if (p->token_tags[p->tok_i] == TOKEN_ELLIPSIS3) { 2963 const AstTokenIndex range_tok = nextToken(p); 2964 const AstNodeIndex range_end = expectExpr(p); 2965 return addNode(&p->nodes, 2966 (AstNodeItem) { 2967 .tag = AST_NODE_SWITCH_RANGE, 2968 .main_token = range_tok, 2969 .data = { .lhs = expr, .rhs = range_end }, 2970 }); 2971 } 2972 return expr; 2973 } 2974 2975 static PtrModifiers parsePtrModifiers(Parser* p) { 2976 PtrModifiers mods = {}; 2977 2978 while (true) { 2979 switch (p->token_tags[p->tok_i]) { 2980 case TOKEN_KEYWORD_CONST: 2981 case TOKEN_KEYWORD_VOLATILE: 2982 case TOKEN_KEYWORD_ALLOWZERO: 2983 p->tok_i++; 2984 continue; 2985 case TOKEN_KEYWORD_ALIGN: 2986 p->tok_i++; 2987 expectToken(p, TOKEN_L_PAREN); 2988 mods.align_node = expectExpr(p); 2989 if (eatToken(p, TOKEN_COLON) != null_token) { 2990 mods.bit_range_start = expectExpr(p); 2991 expectToken(p, TOKEN_COLON); 2992 mods.bit_range_end = expectExpr(p); 2993 } 2994 expectToken(p, TOKEN_R_PAREN); 2995 continue; 2996 case TOKEN_KEYWORD_ADDRSPACE: 2997 p->tok_i++; 2998 expectToken(p, TOKEN_L_PAREN); 2999 mods.addrspace_node = expectExpr(p); 3000 expectToken(p, TOKEN_R_PAREN); 3001 continue; 3002 default: 3003 return mods; 3004 } 3005 } 3006 } 3007 3008 static AstNodeIndex parseSuffixOp(Parser* p, AstNodeIndex lhs) { 3009 const TokenizerTag tok = p->token_tags[p->tok_i]; 3010 switch (tok) { 3011 case TOKEN_L_BRACKET: { 3012 const AstTokenIndex lbracket = nextToken(p); 3013 const AstNodeIndex index_expr = expectExpr(p); 3014 switch (p->token_tags[p->tok_i]) { 3015 case TOKEN_R_BRACKET: 3016 p->tok_i++; 3017 return addNode(&p->nodes, 3018 (AstNodeItem) { 3019 .tag = AST_NODE_ARRAY_ACCESS, 3020 .main_token = lbracket, 3021 .data = { .lhs = lhs, .rhs = index_expr }, 3022 }); 3023 case TOKEN_ELLIPSIS2: { 3024 p->tok_i++; // consume .. 3025 const AstNodeIndex end_expr = parseExpr(p); 3026 if (eatToken(p, TOKEN_COLON) != null_token) { 3027 const AstNodeIndex sentinel = expectExpr(p); 3028 expectToken(p, TOKEN_R_BRACKET); 3029 // end_expr 0 means "no end" — encode as ~0 for 3030 // OptionalIndex.none 3031 const AstNodeIndex opt_end 3032 = end_expr == 0 ? ~(AstNodeIndex)0 : end_expr; 3033 return addNode(&p->nodes, 3034 (AstNodeItem) { 3035 .tag = AST_NODE_SLICE_SENTINEL, 3036 .main_token = lbracket, 3037 .data = { 3038 .lhs = lhs, 3039 .rhs = addExtra(p, 3040 (AstNodeIndex[]) { 3041 index_expr, opt_end, sentinel }, 3042 3), 3043 }, 3044 }); 3045 } 3046 expectToken(p, TOKEN_R_BRACKET); 3047 if (end_expr == 0) { 3048 return addNode(&p->nodes, 3049 (AstNodeItem) { 3050 .tag = AST_NODE_SLICE_OPEN, 3051 .main_token = lbracket, 3052 .data = { .lhs = lhs, .rhs = index_expr }, 3053 }); 3054 } 3055 return addNode(&p->nodes, 3056 (AstNodeItem) { 3057 .tag = AST_NODE_SLICE, 3058 .main_token = lbracket, 3059 .data = { 3060 .lhs = lhs, 3061 .rhs = addExtra(p, 3062 (AstNodeIndex[]) { index_expr, end_expr }, 2), 3063 }, 3064 }); 3065 } 3066 default: 3067 fail(p, "parseSuffixOp: expected ] or .. after index expr"); 3068 } 3069 return 0; // tcc 3070 } 3071 case TOKEN_PERIOD_ASTERISK: 3072 return addNode(&p->nodes, 3073 (AstNodeItem) { 3074 .tag = AST_NODE_DEREF, 3075 .main_token = nextToken(p), 3076 .data = { .lhs = lhs, .rhs = 0 }, 3077 }); 3078 case TOKEN_INVALID_PERIODASTERISKS: 3079 fail(p, "unsupported suffix op"); 3080 case TOKEN_PERIOD: 3081 if (p->token_tags[p->tok_i + 1] == TOKEN_IDENTIFIER) { 3082 const AstTokenIndex dot = nextToken(p); 3083 return addNode(&p->nodes, 3084 (AstNodeItem) { 3085 .tag = AST_NODE_FIELD_ACCESS, 3086 .main_token = dot, 3087 .data = { .lhs = lhs, .rhs = nextToken(p) }, 3088 }); 3089 } 3090 if (p->token_tags[p->tok_i + 1] == TOKEN_ASTERISK) { 3091 const AstTokenIndex dot = nextToken(p); 3092 nextToken(p); // consume the * 3093 return addNode(&p->nodes, 3094 (AstNodeItem) { 3095 .tag = AST_NODE_DEREF, 3096 .main_token = dot, 3097 .data = { .lhs = lhs, .rhs = 0 }, 3098 }); 3099 } 3100 if (p->token_tags[p->tok_i + 1] == TOKEN_QUESTION_MARK) { 3101 const AstTokenIndex dot = nextToken(p); 3102 return addNode(&p->nodes, 3103 (AstNodeItem) { 3104 .tag = AST_NODE_UNWRAP_OPTIONAL, 3105 .main_token = dot, 3106 .data = { .lhs = lhs, .rhs = nextToken(p) }, 3107 }); 3108 } 3109 fail(p, "parseSuffixOp: unsupported period suffix"); 3110 return 0; // tcc 3111 default: 3112 return null_node; 3113 } 3114 } 3115 3116 static AstNodeIndex parseContainerDeclAuto(Parser* p) { 3117 const AstTokenIndex main_token = nextToken(p); 3118 AstNodeIndex arg_expr = null_node; 3119 switch (p->token_tags[main_token]) { 3120 case TOKEN_KEYWORD_OPAQUE: 3121 break; 3122 case TOKEN_KEYWORD_STRUCT: 3123 case TOKEN_KEYWORD_ENUM: 3124 if (eatToken(p, TOKEN_L_PAREN) != null_token) { 3125 arg_expr = expectExpr(p); 3126 expectToken(p, TOKEN_R_PAREN); 3127 } 3128 break; 3129 case TOKEN_KEYWORD_UNION: 3130 if (eatToken(p, TOKEN_L_PAREN) != null_token) { 3131 if (eatToken(p, TOKEN_KEYWORD_ENUM) != null_token) { 3132 if (eatToken(p, TOKEN_L_PAREN) != null_token) { 3133 const AstNodeIndex enum_tag_expr = expectExpr(p); 3134 expectToken(p, TOKEN_R_PAREN); 3135 expectToken(p, TOKEN_R_PAREN); 3136 expectToken(p, TOKEN_L_BRACE); 3137 const Members members = parseContainerMembers(p); 3138 const AstSubRange members_span = membersToSpan(members, p); 3139 expectToken(p, TOKEN_R_BRACE); 3140 return addNode( 3141 &p->nodes, 3142 (AstNodeItem) { 3143 .tag = members.trailing 3144 ? AST_NODE_TAGGED_UNION_ENUM_TAG_TRAILING 3145 : AST_NODE_TAGGED_UNION_ENUM_TAG, 3146 .main_token = main_token, 3147 .data = { 3148 .lhs = enum_tag_expr, 3149 .rhs = addExtra(p, 3150 (AstNodeIndex[]) { 3151 members_span.start, 3152 members_span.end }, 3153 2), 3154 }, 3155 }); 3156 } 3157 expectToken(p, TOKEN_R_PAREN); 3158 expectToken(p, TOKEN_L_BRACE); 3159 const Members members = parseContainerMembers(p); 3160 expectToken(p, TOKEN_R_BRACE); 3161 if (members.len <= 2) { 3162 return addNode(&p->nodes, 3163 (AstNodeItem) { 3164 .tag = members.trailing 3165 ? AST_NODE_TAGGED_UNION_TWO_TRAILING 3166 : AST_NODE_TAGGED_UNION_TWO, 3167 .main_token = main_token, 3168 .data = { .lhs = members.lhs, .rhs = members.rhs }, 3169 }); 3170 } 3171 const AstSubRange span = membersToSpan(members, p); 3172 return addNode(&p->nodes, 3173 (AstNodeItem) { 3174 .tag = members.trailing 3175 ? AST_NODE_TAGGED_UNION_TRAILING 3176 : AST_NODE_TAGGED_UNION, 3177 .main_token = main_token, 3178 .data = { .lhs = span.start, .rhs = span.end }, 3179 }); 3180 } 3181 arg_expr = expectExpr(p); 3182 expectToken(p, TOKEN_R_PAREN); 3183 } 3184 break; 3185 default: 3186 fail(p, "parseContainerDeclAuto: unexpected token"); 3187 } 3188 3189 expectToken(p, TOKEN_L_BRACE); 3190 const Members members = parseContainerMembers(p); 3191 expectToken(p, TOKEN_R_BRACE); 3192 3193 if (arg_expr == null_node) { 3194 if (members.len <= 2) { 3195 return addNode(&p->nodes, 3196 (AstNodeItem) { 3197 .tag = members.trailing 3198 ? AST_NODE_CONTAINER_DECL_TWO_TRAILING 3199 : AST_NODE_CONTAINER_DECL_TWO, 3200 .main_token = main_token, 3201 .data = { .lhs = members.lhs, .rhs = members.rhs }, 3202 }); 3203 } 3204 const AstSubRange span = membersToSpan(members, p); 3205 return addNode(&p->nodes, 3206 (AstNodeItem) { 3207 .tag = members.trailing ? AST_NODE_CONTAINER_DECL_TRAILING 3208 : AST_NODE_CONTAINER_DECL, 3209 .main_token = main_token, 3210 .data = { .lhs = span.start, .rhs = span.end }, 3211 }); 3212 } 3213 3214 const AstSubRange span = membersToSpan(members, p); 3215 return addNode( 3216 &p->nodes, 3217 (AstNodeItem) { 3218 .tag = members.trailing 3219 ? AST_NODE_CONTAINER_DECL_ARG_TRAILING 3220 : AST_NODE_CONTAINER_DECL_ARG, 3221 .main_token = main_token, 3222 .data = { 3223 .lhs = arg_expr, 3224 .rhs = addExtra(p, 3225 (AstNodeIndex[]) { span.start, span.end }, 2), 3226 }, 3227 }); 3228 } 3229 3230 static AstNodeIndex parseByteAlign(Parser* p) { 3231 if (eatToken(p, TOKEN_KEYWORD_ALIGN) == null_token) 3232 return null_node; 3233 expectToken(p, TOKEN_L_PAREN); 3234 const AstNodeIndex expr = expectExpr(p); 3235 expectToken(p, TOKEN_R_PAREN); 3236 return expr; 3237 } 3238 3239 static AstSubRange parseSwitchProngList(Parser* p) { 3240 const uint32_t scratch_top = p->scratch.len; 3241 while (true) { 3242 if (eatToken(p, TOKEN_R_BRACE) != null_token) 3243 break; 3244 eatDocComments(p); 3245 const AstNodeIndex case_node = parseSwitchProng(p); 3246 if (case_node == 0) 3247 break; 3248 SLICE_APPEND(AstNodeIndex, &p->scratch, case_node); 3249 if (p->token_tags[p->tok_i] == TOKEN_COMMA) 3250 p->tok_i++; 3251 } 3252 const uint32_t cases_len = p->scratch.len - scratch_top; 3253 const AstSubRange span 3254 = listToSpan(p, &p->scratch.arr[scratch_top], cases_len); 3255 p->scratch.len = scratch_top; 3256 return span; 3257 } 3258 3259 static SmallSpan parseParamDeclList(Parser* p) { 3260 expectToken(p, TOKEN_L_PAREN); 3261 3262 const uint32_t scratch_top = p->scratch.len; 3263 3264 // 0 = none, 1 = seen, 2 = nonfinal 3265 int varargs = 0; 3266 3267 while (true) { 3268 if (eatToken(p, TOKEN_R_PAREN) != null_token) 3269 break; 3270 if (varargs == 1) 3271 varargs = 2; 3272 3273 if (p->token_tags[p->tok_i] == TOKEN_ELLIPSIS3) { 3274 p->tok_i++; 3275 if (varargs == 0) 3276 varargs = 1; 3277 if (eatToken(p, TOKEN_R_PAREN) != null_token) 3278 break; 3279 expectToken(p, TOKEN_COMMA); 3280 continue; 3281 } 3282 3283 const AstNodeIndex type_expr = expectParamDecl(p); 3284 if (type_expr != 0) 3285 SLICE_APPEND(AstNodeIndex, &p->scratch, type_expr); 3286 3287 if (p->token_tags[p->tok_i] == TOKEN_COMMA) { 3288 p->tok_i++; 3289 continue; 3290 } 3291 expectToken(p, TOKEN_R_PAREN); 3292 break; 3293 } 3294 3295 if (varargs == 2) { 3296 fail(p, "varargs_nonfinal"); 3297 } 3298 3299 const uint32_t params_len = p->scratch.len - scratch_top; 3300 p->scratch.len = scratch_top; 3301 switch (params_len) { 3302 case 0: 3303 return (SmallSpan) { 3304 .tag = SMALL_SPAN_ZERO_OR_ONE, 3305 .payload = { .zero_or_one = 0 }, 3306 }; 3307 case 1: 3308 return (SmallSpan) { 3309 .tag = SMALL_SPAN_ZERO_OR_ONE, 3310 .payload = { .zero_or_one = p->scratch.arr[scratch_top] }, 3311 }; 3312 default:; 3313 const AstSubRange span 3314 = listToSpan(p, &p->scratch.arr[scratch_top], params_len); 3315 return (SmallSpan) { 3316 .tag = SMALL_SPAN_MULTI, 3317 .payload = { .multi = span }, 3318 }; 3319 } 3320 } 3321 3322 static AstNodeIndex parseBuiltinCall(Parser* p) { 3323 const AstTokenIndex builtin_token = assertToken(p, TOKEN_BUILTIN); 3324 assertToken(p, TOKEN_L_PAREN); 3325 3326 const uint32_t scratch_top = p->scratch.len; 3327 3328 while (true) { 3329 if (eatToken(p, TOKEN_R_PAREN) != null_token) 3330 break; 3331 3332 const AstNodeIndex param = expectExpr(p); 3333 SLICE_APPEND(AstNodeIndex, &p->scratch, param); 3334 switch (p->token_tags[p->tok_i]) { 3335 case TOKEN_COMMA: 3336 p->tok_i++; 3337 break; 3338 case TOKEN_R_PAREN: 3339 p->tok_i++; 3340 goto end_loop; 3341 default: 3342 fail(p, "expected comma after arg"); 3343 } 3344 } 3345 end_loop:; 3346 3347 const bool comma = (p->token_tags[p->tok_i - 2] == TOKEN_COMMA); 3348 const uint32_t params_len = p->scratch.len - scratch_top; 3349 p->scratch.len = scratch_top; 3350 switch (params_len) { 3351 case 0: 3352 return addNode(&p->nodes, 3353 (AstNodeItem) { 3354 .tag = AST_NODE_BUILTIN_CALL_TWO, 3355 .main_token = builtin_token, 3356 .data = { 3357 .lhs = 0, 3358 .rhs = 0, 3359 }, 3360 }); 3361 case 1: 3362 return addNode(&p->nodes, 3363 (AstNodeItem) { 3364 .tag = comma ? 3365 AST_NODE_BUILTIN_CALL_TWO_COMMA : 3366 AST_NODE_BUILTIN_CALL_TWO, 3367 .main_token = builtin_token, 3368 .data = { 3369 .lhs = p->scratch.arr[scratch_top], 3370 .rhs = 0, 3371 }, 3372 }); 3373 case 2: 3374 return addNode(&p->nodes, 3375 (AstNodeItem) { 3376 .tag = comma ? 3377 AST_NODE_BUILTIN_CALL_TWO_COMMA : 3378 AST_NODE_BUILTIN_CALL_TWO, 3379 .main_token = builtin_token, 3380 .data = { 3381 .lhs = p->scratch.arr[scratch_top], 3382 .rhs = p->scratch.arr[scratch_top+1], 3383 }, 3384 }); 3385 default:; 3386 const AstSubRange span 3387 = listToSpan(p, &p->scratch.arr[scratch_top], params_len); 3388 return addNode( 3389 &p->nodes, 3390 (AstNodeItem) { 3391 .tag = comma ? 3392 AST_NODE_BUILTIN_CALL_COMMA : 3393 AST_NODE_BUILTIN_CALL, 3394 .main_token = builtin_token, 3395 .data = { 3396 .lhs = span.start, 3397 .rhs = span.end, 3398 }, 3399 }); 3400 } 3401 } 3402 3403 static AstTokenIndex eatDocComments(Parser* p) { 3404 AstTokenIndex first = null_token; 3405 AstTokenIndex tok; 3406 while ((tok = eatToken(p, TOKEN_DOC_COMMENT)) != null_token) { 3407 if (first == null_token) { 3408 if (tok > 0 && tokensOnSameLine(p, tok - 1, tok)) { 3409 fail(p, "same_line_doc_comment"); 3410 } 3411 first = tok; 3412 } 3413 } 3414 return first; 3415 } 3416 3417 static bool tokensOnSameLine( 3418 Parser* p, AstTokenIndex tok1, AstTokenIndex tok2) { 3419 const uint32_t start1 = p->token_starts[tok1]; 3420 const uint32_t start2 = p->token_starts[tok2]; 3421 for (uint32_t i = start1; i < start2; i++) { 3422 if (p->source[i] == '\n') 3423 return false; 3424 } 3425 return true; 3426 } 3427 3428 static AstTokenIndex eatToken(Parser* p, TokenizerTag tag) { 3429 if (p->token_tags[p->tok_i] == tag) { 3430 return nextToken(p); 3431 } else { 3432 return null_token; 3433 } 3434 } 3435 3436 static AstTokenIndex assertToken(Parser* p, TokenizerTag tag) { 3437 const AstTokenIndex token = nextToken(p); 3438 if (p->token_tags[token] != tag) { 3439 fail(p, "unexpected token"); 3440 } 3441 return token; 3442 } 3443 3444 static AstTokenIndex expectToken(Parser* p, TokenizerTag tag) { 3445 if (p->token_tags[p->tok_i] == tag) { 3446 return nextToken(p); 3447 } else { 3448 fail(p, "unexpected token"); 3449 } 3450 return 0; // tcc 3451 } 3452 3453 static AstNodeIndex expectSemicolon(Parser* p) { 3454 return expectToken(p, TOKEN_SEMICOLON); 3455 } 3456 3457 static AstTokenIndex nextToken(Parser* p) { return p->tok_i++; }