| ... | @@ -577,7 +577,7 @@ static AstNode *ast_parse_top_level_comptime(ParseContext *pc) { | ... | @@ -577,7 +577,7 @@ static AstNode *ast_parse_top_level_comptime(ParseContext *pc) { |
| 577 | | 577 | |
| 578 | // TopLevelDecl | 578 | // TopLevelDecl |
| 579 | // <- (KEYWORD_export / KEYWORD_extern STRINGLITERAL? / KEYWORD_inline)? FnProto (SEMICOLON / Block) | 579 | // <- (KEYWORD_export / KEYWORD_extern STRINGLITERAL? / KEYWORD_inline)? FnProto (SEMICOLON / Block) |
| 580 | // / (KEYWORD_export / KEYWORD_extern STRINGLITERAL?)? VarDecl | 580 | // / (KEYWORD_export / KEYWORD_extern STRINGLITERAL?)? KEYWORD_threadlocal? VarDecl |
| 581 | // / KEYWORD_use Expr SEMICOLON | 581 | // / KEYWORD_use Expr SEMICOLON |
| 582 | static AstNode *ast_parse_top_level_decl(ParseContext *pc, VisibMod visib_mod) { | 582 | static AstNode *ast_parse_top_level_decl(ParseContext *pc, VisibMod visib_mod) { |
| 583 | Token *first = eat_token_if(pc, TokenIdKeywordExport); | 583 | Token *first = eat_token_if(pc, TokenIdKeywordExport); |
| ... | @@ -632,13 +632,18 @@ static AstNode *ast_parse_top_level_decl(ParseContext *pc, VisibMod visib_mod) { | ... | @@ -632,13 +632,18 @@ static AstNode *ast_parse_top_level_decl(ParseContext *pc, VisibMod visib_mod) { |
| 632 | ast_invalid_token_error(pc, peek_token(pc)); | 632 | ast_invalid_token_error(pc, peek_token(pc)); |
| 633 | } | 633 | } |
| 634 | | 634 | |
| | 635 | Token *thread_local_kw = eat_token_if(pc, TokenIdKeywordThreadLocal); |
| 635 | AstNode *var_decl = ast_parse_var_decl(pc); | 636 | AstNode *var_decl = ast_parse_var_decl(pc); |
| 636 | if (var_decl != nullptr) { | 637 | if (var_decl != nullptr) { |
| 637 | assert(var_decl->type == NodeTypeVariableDeclaration); | 638 | assert(var_decl->type == NodeTypeVariableDeclaration); |
| 638 | var_decl->data.variable_declaration.visib_mod = visib_mod; | 639 | var_decl->data.variable_declaration.visib_mod = visib_mod; |
| | 640 | var_decl->data.variable_declaration.threadlocal_tok = thread_local_kw; |
| 639 | return var_decl; | 641 | return var_decl; |
| 640 | } | 642 | } |
| 641 | | 643 | |
| | 644 | if (thread_local_kw != nullptr) |
| | 645 | put_back_token(pc); |
| | 646 | |
| 642 | AstNode *fn_proto = ast_parse_fn_proto(pc); | 647 | AstNode *fn_proto = ast_parse_fn_proto(pc); |
| 643 | if (fn_proto != nullptr) { | 648 | if (fn_proto != nullptr) { |
| 644 | AstNode *body = ast_parse_block(pc); | 649 | AstNode *body = ast_parse_block(pc); |
| ... | @@ -741,17 +746,12 @@ static AstNode *ast_parse_fn_proto(ParseContext *pc) { | ... | @@ -741,17 +746,12 @@ static AstNode *ast_parse_fn_proto(ParseContext *pc) { |
| 741 | | 746 | |
| 742 | // VarDecl <- (KEYWORD_const / KEYWORD_var) IDENTIFIER (COLON TypeExpr)? ByteAlign? LinkSection? (EQUAL Expr)? SEMICOLON | 747 | // VarDecl <- (KEYWORD_const / KEYWORD_var) IDENTIFIER (COLON TypeExpr)? ByteAlign? LinkSection? (EQUAL Expr)? SEMICOLON |
| 743 | static AstNode *ast_parse_var_decl(ParseContext *pc) { | 748 | static AstNode *ast_parse_var_decl(ParseContext *pc) { |
| 744 | Token *thread_local_kw = eat_token_if(pc, TokenIdKeywordThreadLocal); | | |
| 745 | Token *mut_kw = eat_token_if(pc, TokenIdKeywordConst); | 749 | Token *mut_kw = eat_token_if(pc, TokenIdKeywordConst); |
| 746 | if (mut_kw == nullptr) | 750 | if (mut_kw == nullptr) |
| 747 | mut_kw = eat_token_if(pc, TokenIdKeywordVar); | 751 | mut_kw = eat_token_if(pc, TokenIdKeywordVar); |
| 748 | if (mut_kw == nullptr) { | 752 | if (mut_kw == nullptr) |
| 749 | if (thread_local_kw == nullptr) { | 753 | return nullptr; |
| 750 | return nullptr; | 754 | |
| 751 | } else { | | |
| 752 | ast_invalid_token_error(pc, peek_token(pc)); | | |
| 753 | } | | |
| 754 | } | | |
| 755 | Token *identifier = expect_token(pc, TokenIdSymbol); | 755 | Token *identifier = expect_token(pc, TokenIdSymbol); |
| 756 | AstNode *type_expr = nullptr; | 756 | AstNode *type_expr = nullptr; |
| 757 | if (eat_token_if(pc, TokenIdColon) != nullptr) | 757 | if (eat_token_if(pc, TokenIdColon) != nullptr) |
| ... | @@ -766,7 +766,6 @@ static AstNode *ast_parse_var_decl(ParseContext *pc) { | ... | @@ -766,7 +766,6 @@ static AstNode *ast_parse_var_decl(ParseContext *pc) { |
| 766 | expect_token(pc, TokenIdSemicolon); | 766 | expect_token(pc, TokenIdSemicolon); |
| 767 | | 767 | |
| 768 | AstNode *res = ast_create_node(pc, NodeTypeVariableDeclaration, mut_kw); | 768 | AstNode *res = ast_create_node(pc, NodeTypeVariableDeclaration, mut_kw); |
| 769 | res->data.variable_declaration.threadlocal_tok = thread_local_kw; | | |
| 770 | res->data.variable_declaration.is_const = mut_kw->id == TokenIdKeywordConst; | 769 | res->data.variable_declaration.is_const = mut_kw->id == TokenIdKeywordConst; |
| 771 | res->data.variable_declaration.symbol = token_buf(identifier); | 770 | res->data.variable_declaration.symbol = token_buf(identifier); |
| 772 | res->data.variable_declaration.type = type_expr; | 771 | res->data.variable_declaration.type = type_expr; |
| ... | @@ -952,17 +951,10 @@ static AstNode *ast_parse_labeled_statement(ParseContext *pc) { | ... | @@ -952,17 +951,10 @@ static AstNode *ast_parse_labeled_statement(ParseContext *pc) { |
| 952 | | 951 | |
| 953 | // LoopStatement <- KEYWORD_inline? (ForStatement / WhileStatement) | 952 | // LoopStatement <- KEYWORD_inline? (ForStatement / WhileStatement) |
| 954 | static AstNode *ast_parse_loop_statement(ParseContext *pc) { | 953 | static AstNode *ast_parse_loop_statement(ParseContext *pc) { |
| 955 | Token *label = ast_parse_block_label(pc); | | |
| 956 | Token *first = label; | | |
| 957 | | | |
| 958 | Token *inline_token = eat_token_if(pc, TokenIdKeywordInline); | 954 | Token *inline_token = eat_token_if(pc, TokenIdKeywordInline); |
| 959 | if (first == nullptr) | | |
| 960 | first = inline_token; | | |
| 961 | | | |
| 962 | AstNode *for_statement = ast_parse_for_statement(pc); | 955 | AstNode *for_statement = ast_parse_for_statement(pc); |
| 963 | if (for_statement != nullptr) { | 956 | if (for_statement != nullptr) { |
| 964 | assert(for_statement->type == NodeTypeForExpr); | 957 | assert(for_statement->type == NodeTypeForExpr); |
| 965 | for_statement->data.for_expr.name = token_buf(label); | | |
| 966 | for_statement->data.for_expr.is_inline = inline_token != nullptr; | 958 | for_statement->data.for_expr.is_inline = inline_token != nullptr; |
| 967 | return for_statement; | 959 | return for_statement; |
| 968 | } | 960 | } |
| ... | @@ -970,12 +962,11 @@ static AstNode *ast_parse_loop_statement(ParseContext *pc) { | ... | @@ -970,12 +962,11 @@ static AstNode *ast_parse_loop_statement(ParseContext *pc) { |
| 970 | AstNode *while_statement = ast_parse_while_statement(pc); | 962 | AstNode *while_statement = ast_parse_while_statement(pc); |
| 971 | if (while_statement != nullptr) { | 963 | if (while_statement != nullptr) { |
| 972 | assert(while_statement->type == NodeTypeWhileExpr); | 964 | assert(while_statement->type == NodeTypeWhileExpr); |
| 973 | while_statement->data.while_expr.name = token_buf(label); | | |
| 974 | while_statement->data.while_expr.is_inline = inline_token != nullptr; | 965 | while_statement->data.while_expr.is_inline = inline_token != nullptr; |
| 975 | return while_statement; | 966 | return while_statement; |
| 976 | } | 967 | } |
| 977 | | 968 | |
| 978 | if (first != nullptr) | 969 | if (inline_token != nullptr) |
| 979 | ast_invalid_token_error(pc, peek_token(pc)); | 970 | ast_invalid_token_error(pc, peek_token(pc)); |
| 980 | return nullptr; | 971 | return nullptr; |
| 981 | } | 972 | } |
| ... | @@ -1117,7 +1108,7 @@ static AstNode *ast_parse_bool_and_expr(ParseContext *pc) { | ... | @@ -1117,7 +1108,7 @@ static AstNode *ast_parse_bool_and_expr(ParseContext *pc) { |
| 1117 | | 1108 | |
| 1118 | // CompareExpr <- BitwiseExpr (CompareOp BitwiseExpr)? | 1109 | // CompareExpr <- BitwiseExpr (CompareOp BitwiseExpr)? |
| 1119 | static AstNode *ast_parse_compare_expr(ParseContext *pc) { | 1110 | static AstNode *ast_parse_compare_expr(ParseContext *pc) { |
| 1120 | return ast_parse_bin_op_expr(pc, BinOpChainInf, ast_parse_compare_op, ast_parse_bitwise_expr); | 1111 | return ast_parse_bin_op_expr(pc, BinOpChainOnce, ast_parse_compare_op, ast_parse_bitwise_expr); |
| 1121 | } | 1112 | } |
| 1122 | | 1113 | |
| 1123 | // BitwiseExpr <- BitShiftExpr (BitwiseOp BitShiftExpr)* | 1114 | // BitwiseExpr <- BitShiftExpr (BitwiseOp BitShiftExpr)* |
| ... | @@ -1246,11 +1237,8 @@ static AstNode *ast_parse_primary_expr(ParseContext *pc) { | ... | @@ -1246,11 +1237,8 @@ static AstNode *ast_parse_primary_expr(ParseContext *pc) { |
| 1246 | } | 1237 | } |
| 1247 | | 1238 | |
| 1248 | AstNode *block = ast_parse_block(pc); | 1239 | AstNode *block = ast_parse_block(pc); |
| 1249 | if (block != nullptr) { | 1240 | if (block != nullptr) |
| 1250 | assert(block->type == NodeTypeBlock); | | |
| 1251 | block->data.block.name = token_buf(label); | | |
| 1252 | return block; | 1241 | return block; |
| 1253 | } | | |
| 1254 | | 1242 | |
| 1255 | AstNode *curly_suffix = ast_parse_curly_suffix_expr(pc); | 1243 | AstNode *curly_suffix = ast_parse_curly_suffix_expr(pc); |
| 1256 | if (curly_suffix != nullptr) | 1244 | if (curly_suffix != nullptr) |
| ... | @@ -1672,32 +1660,26 @@ static AstNode *ast_parse_primary_type_expr(ParseContext *pc) { | ... | @@ -1672,32 +1660,26 @@ static AstNode *ast_parse_primary_type_expr(ParseContext *pc) { |
| 1672 | | 1660 | |
| 1673 | // ContainerDecl <- (KEYWORD_extern / KEYWORD_packed)? ContainerDeclAuto | 1661 | // ContainerDecl <- (KEYWORD_extern / KEYWORD_packed)? ContainerDeclAuto |
| 1674 | static AstNode *ast_parse_container_decl(ParseContext *pc) { | 1662 | static AstNode *ast_parse_container_decl(ParseContext *pc) { |
| 1675 | Token *extern_token = eat_token_if(pc, TokenIdKeywordExtern); | 1663 | Token *layout_token = eat_token_if(pc, TokenIdKeywordExtern); |
| 1676 | if (extern_token != nullptr) { | 1664 | if (layout_token == nullptr) |
| 1677 | AstNode *res = ast_parse_container_decl_auto(pc); | 1665 | layout_token = eat_token_if(pc, TokenIdKeywordPacked); |
| 1678 | if (res == nullptr) { | | |
| 1679 | put_back_token(pc); | | |
| 1680 | return nullptr; | | |
| 1681 | } | | |
| 1682 | | 1666 | |
| 1683 | assert(res->type == NodeTypeContainerDecl); | 1667 | AstNode *res = ast_parse_container_decl_auto(pc); |
| 1684 | res->line = extern_token->start_line; | 1668 | if (res == nullptr) { |
| 1685 | res->column = extern_token->start_column; | 1669 | if (layout_token != nullptr) |
| 1686 | res->data.container_decl.layout = ContainerLayoutExtern; | 1670 | put_back_token(pc); |
| 1687 | return res; | 1671 | return nullptr; |
| 1688 | } | 1672 | } |
| 1689 | | 1673 | |
| 1690 | Token *packed_token = eat_token_if(pc, TokenIdKeywordPacked); | 1674 | assert(res->type == NodeTypeContainerDecl); |
| 1691 | if (packed_token != nullptr) { | 1675 | if (layout_token != nullptr) { |
| 1692 | AstNode *res = ast_expect(pc, ast_parse_container_decl_auto); | 1676 | res->line = layout_token->start_line; |
| 1693 | assert(res->type == NodeTypeContainerDecl); | 1677 | res->column = layout_token->start_column; |
| 1694 | res->line = packed_token->start_line; | 1678 | res->data.container_decl.layout = layout_token->id == TokenIdKeywordExtern |
| 1695 | res->column = packed_token->start_column; | 1679 | ? ContainerLayoutExtern |
| 1696 | res->data.container_decl.layout = ContainerLayoutPacked; | 1680 | : ContainerLayoutPacked; |
| 1697 | return res; | | |
| 1698 | } | 1681 | } |
| 1699 | | 1682 | return res; |
| 1700 | return ast_parse_container_decl_auto(pc); | | |
| 1701 | } | 1683 | } |
| 1702 | | 1684 | |
| 1703 | // ErrorSetDecl <- KEYWORD_error LBRACE IdentifierList RBRACE | 1685 | // ErrorSetDecl <- KEYWORD_error LBRACE IdentifierList RBRACE |