| ... | @@ -526,6 +526,15 @@ static void ast_parse_container_doc_comments(ParseContext *pc, Buf *buf) { | ... | @@ -526,6 +526,15 @@ static void ast_parse_container_doc_comments(ParseContext *pc, Buf *buf) { |
| 526 | } | 526 | } |
| 527 | } | 527 | } |
| 528 | | 528 | |
| | 529 | enum ContainerFieldState { |
| | 530 | // no fields have been seen |
| | 531 | ContainerFieldStateNone, |
| | 532 | // currently parsing fields |
| | 533 | ContainerFieldStateSeen, |
| | 534 | // saw fields and then a declaration after them |
| | 535 | ContainerFieldStateEnd, |
| | 536 | }; |
| | 537 | |
| 529 | // ContainerMembers | 538 | // ContainerMembers |
| 530 | // <- TestDecl ContainerMembers | 539 | // <- TestDecl ContainerMembers |
| 531 | // / TopLevelComptime ContainerMembers | 540 | // / TopLevelComptime ContainerMembers |
| ... | @@ -537,17 +546,29 @@ static AstNodeContainerDecl ast_parse_container_members(ParseContext *pc) { | ... | @@ -537,17 +546,29 @@ static AstNodeContainerDecl ast_parse_container_members(ParseContext *pc) { |
| 537 | AstNodeContainerDecl res = {}; | 546 | AstNodeContainerDecl res = {}; |
| 538 | Buf tld_doc_comment_buf = BUF_INIT; | 547 | Buf tld_doc_comment_buf = BUF_INIT; |
| 539 | buf_resize(&tld_doc_comment_buf, 0); | 548 | buf_resize(&tld_doc_comment_buf, 0); |
| | 549 | ContainerFieldState field_state = ContainerFieldStateNone; |
| | 550 | Token *first_token = nullptr; |
| 540 | for (;;) { | 551 | for (;;) { |
| 541 | ast_parse_container_doc_comments(pc, &tld_doc_comment_buf); | 552 | ast_parse_container_doc_comments(pc, &tld_doc_comment_buf); |
| 542 | | 553 | |
| | 554 | Token *peeked_token = peek_token(pc); |
| | 555 | |
| 543 | AstNode *test_decl = ast_parse_test_decl(pc); | 556 | AstNode *test_decl = ast_parse_test_decl(pc); |
| 544 | if (test_decl != nullptr) { | 557 | if (test_decl != nullptr) { |
| | 558 | if (field_state == ContainerFieldStateSeen) { |
| | 559 | field_state = ContainerFieldStateEnd; |
| | 560 | first_token = peeked_token; |
| | 561 | } |
| 545 | res.decls.append(test_decl); | 562 | res.decls.append(test_decl); |
| 546 | continue; | 563 | continue; |
| 547 | } | 564 | } |
| 548 | | 565 | |
| 549 | AstNode *top_level_comptime = ast_parse_top_level_comptime(pc); | 566 | AstNode *top_level_comptime = ast_parse_top_level_comptime(pc); |
| 550 | if (top_level_comptime != nullptr) { | 567 | if (top_level_comptime != nullptr) { |
| | 568 | if (field_state == ContainerFieldStateSeen) { |
| | 569 | field_state = ContainerFieldStateEnd; |
| | 570 | first_token = peeked_token; |
| | 571 | } |
| 551 | res.decls.append(top_level_comptime); | 572 | res.decls.append(top_level_comptime); |
| 552 | continue; | 573 | continue; |
| 553 | } | 574 | } |
| ... | @@ -555,11 +576,17 @@ static AstNodeContainerDecl ast_parse_container_members(ParseContext *pc) { | ... | @@ -555,11 +576,17 @@ static AstNodeContainerDecl ast_parse_container_members(ParseContext *pc) { |
| 555 | Buf doc_comment_buf = BUF_INIT; | 576 | Buf doc_comment_buf = BUF_INIT; |
| 556 | ast_parse_doc_comments(pc, &doc_comment_buf); | 577 | ast_parse_doc_comments(pc, &doc_comment_buf); |
| 557 | | 578 | |
| | 579 | peeked_token = peek_token(pc); |
| | 580 | |
| 558 | Token *visib_token = eat_token_if(pc, TokenIdKeywordPub); | 581 | Token *visib_token = eat_token_if(pc, TokenIdKeywordPub); |
| 559 | VisibMod visib_mod = visib_token != nullptr ? VisibModPub : VisibModPrivate; | 582 | VisibMod visib_mod = visib_token != nullptr ? VisibModPub : VisibModPrivate; |
| 560 | | 583 | |
| 561 | AstNode *top_level_decl = ast_parse_top_level_decl(pc, visib_mod, &doc_comment_buf); | 584 | AstNode *top_level_decl = ast_parse_top_level_decl(pc, visib_mod, &doc_comment_buf); |
| 562 | if (top_level_decl != nullptr) { | 585 | if (top_level_decl != nullptr) { |
| | 586 | if (field_state == ContainerFieldStateSeen) { |
| | 587 | field_state = ContainerFieldStateEnd; |
| | 588 | first_token = peeked_token; |
| | 589 | } |
| 563 | res.decls.append(top_level_decl); | 590 | res.decls.append(top_level_decl); |
| 564 | continue; | 591 | continue; |
| 565 | } | 592 | } |
| ... | @@ -572,6 +599,16 @@ static AstNodeContainerDecl ast_parse_container_members(ParseContext *pc) { | ... | @@ -572,6 +599,16 @@ static AstNodeContainerDecl ast_parse_container_members(ParseContext *pc) { |
| 572 | | 599 | |
| 573 | AstNode *container_field = ast_parse_container_field(pc); | 600 | AstNode *container_field = ast_parse_container_field(pc); |
| 574 | if (container_field != nullptr) { | 601 | if (container_field != nullptr) { |
| | 602 | switch (field_state) { |
| | 603 | case ContainerFieldStateNone: |
| | 604 | field_state = ContainerFieldStateSeen; |
| | 605 | break; |
| | 606 | case ContainerFieldStateSeen: |
| | 607 | break; |
| | 608 | case ContainerFieldStateEnd: |
| | 609 | ast_error(pc, first_token, "declarations are not allowed between container fields"); |
| | 610 | } |
| | 611 | |
| 575 | assert(container_field->type == NodeTypeStructField); | 612 | assert(container_field->type == NodeTypeStructField); |
| 576 | container_field->data.struct_field.doc_comments = doc_comment_buf; | 613 | container_field->data.struct_field.doc_comments = doc_comment_buf; |
| 577 | container_field->data.struct_field.comptime_token = comptime_token; | 614 | container_field->data.struct_field.comptime_token = comptime_token; |