| author | |
| committer | |
| log | c60496a297a0d4c53ad0e22850ad62b0b4a2d841 |
| tree | 821fd1f0399d8d013acba645a9f54df6914adad7 |
| parent | 6fef7406c80d6db26513a6ae53f9c44444bef1f2 |
See #7276 files changed, 139 insertions(+), 6 deletions(-)
doc/langref.html.in+7-3| ... | ... | @@ -5687,7 +5687,7 @@ AssignmentExpression = UnwrapExpression AssignmentOperator UnwrapExpression | Un |
| 5687 | 5687 | |
| 5688 | 5688 | AssignmentOperator = "=" | "*=" | "/=" | "%=" | "+=" | "-=" | "<<=" | ">>=" | "&=" | "^=" | "|=" | "*%=" | "+%=" | "-%=" |
| 5689 | 5689 | |
| 5690 | BlockExpression(body) = Block | IfExpression(body) | IfErrorExpression(body) | TestExpression(body) | WhileExpression(body) | ForExpression(body) | SwitchExpression | CompTimeExpression(body) | |
| 5690 | BlockExpression(body) = Block | IfExpression(body) | IfErrorExpression(body) | TestExpression(body) | WhileExpression(body) | ForExpression(body) | SwitchExpression | CompTimeExpression(body) | SuspendExpression(body) | |
| 5691 | 5691 | |
| 5692 | 5692 | CompTimeExpression(body) = "comptime" body |
| 5693 | 5693 | |
| ... | ... | @@ -5705,6 +5705,8 @@ ReturnExpression = "return" option(Expression) |
| 5705 | 5705 | |
| 5706 | 5706 | TryExpression = "try" Expression |
| 5707 | 5707 | |
| 5708 | AwaitExpression = "await" Expression | |
| 5709 | ||
| 5708 | 5710 | BreakExpression = "break" option(":" Symbol) option(Expression) |
| 5709 | 5711 | |
| 5710 | 5712 | CancelExpression = "cancel" Expression; |
| ... | ... | @@ -5713,6 +5715,8 @@ Defer(body) = ("defer" | "deferror") body |
| 5713 | 5715 | |
| 5714 | 5716 | IfExpression(body) = "if" "(" Expression ")" body option("else" BlockExpression(body)) |
| 5715 | 5717 | |
| 5718 | SuspendExpression(body) = "suspend" option(("|" Symbol "|" body)) | |
| 5719 | ||
| 5716 | 5720 | IfErrorExpression(body) = "if" "(" Expression ")" option("|" option("*") Symbol "|") body "else" "|" Symbol "|" BlockExpression(body) |
| 5717 | 5721 | |
| 5718 | 5722 | TestExpression(body) = "if" "(" Expression ")" option("|" option("*") Symbol "|") body option("else" BlockExpression(body)) |
| ... | ... | @@ -5763,7 +5767,7 @@ ContainerInitBody = list(StructLiteralField, ",") | list(Expression, ",") |
| 5763 | 5767 | |
| 5764 | 5768 | StructLiteralField = "." Symbol "=" Expression |
| 5765 | 5769 | |
| 5766 | PrefixOp = "!" | "-" | "~" | "*" | ("&" option("align" "(" Expression option(":" Integer ":" Integer) ")" ) option("const") option("volatile")) | "?" | "??" | "-%" | "try" | |
| 5770 | PrefixOp = "!" | "-" | "~" | "*" | ("&" option("align" "(" Expression option(":" Integer ":" Integer) ")" ) option("const") option("volatile")) | "?" | "??" | "-%" | "try" | "await" | |
| 5767 | 5771 | |
| 5768 | 5772 | PrimaryExpression = Integer | Float | String | CharLiteral | KeywordLiteral | GroupedExpression | BlockExpression(BlockOrExpression) | Symbol | ("@" Symbol FnCallExpression) | ArrayType | FnProto | AsmExpression | ContainerDecl | ("continue" option(":" Symbol)) | ErrorSetDecl |
| 5769 | 5773 | |
| ... | ... | @@ -5771,7 +5775,7 @@ ArrayType : "[" option(Expression) "]" option("align" "(" Expression option(":" |
| 5771 | 5775 | |
| 5772 | 5776 | GroupedExpression = "(" Expression ")" |
| 5773 | 5777 | |
| 5774 | KeywordLiteral = "true" | "false" | "null" | "undefined" | "error" | "this" | "unreachable" | |
| 5778 | KeywordLiteral = "true" | "false" | "null" | "undefined" | "error" | "this" | "unreachable" | "suspend" | |
| 5775 | 5779 | |
| 5776 | 5780 | ErrorSetDecl = "error" "{" list(Symbol, ",") "}" |
| 5777 | 5781 |
src/all_types.hpp+13| ... | ... | @@ -401,6 +401,8 @@ enum NodeType { |
| 401 | 401 | NodeTypeTestExpr, |
| 402 | 402 | NodeTypeErrorSetDecl, |
| 403 | 403 | NodeTypeCancel, |
| 404 | NodeTypeAwaitExpr, | |
| 405 | NodeTypeSuspend, | |
| 404 | 406 | }; |
| 405 | 407 | |
| 406 | 408 | struct AstNodeRoot { |
| ... | ... | @@ -859,6 +861,15 @@ struct AstNodeErrorType { |
| 859 | 861 | struct AstNodeVarLiteral { |
| 860 | 862 | }; |
| 861 | 863 | |
| 864 | struct AstNodeAwaitExpr { | |
| 865 | AstNode *expr; | |
| 866 | }; | |
| 867 | ||
| 868 | struct AstNodeSuspend { | |
| 869 | AstNode *block; | |
| 870 | AstNode *promise_symbol; | |
| 871 | }; | |
| 872 | ||
| 862 | 873 | struct AstNode { |
| 863 | 874 | enum NodeType type; |
| 864 | 875 | size_t line; |
| ... | ... | @@ -917,6 +928,8 @@ struct AstNode { |
| 917 | 928 | AstNodeVarLiteral var_literal; |
| 918 | 929 | AstNodeErrorSetDecl err_set_decl; |
| 919 | 930 | AstNodeCancelExpr cancel_expr; |
| 931 | AstNodeAwaitExpr await_expr; | |
| 932 | AstNodeSuspend suspend; | |
| 920 | 933 | } data; |
| 921 | 934 | }; |
| 922 | 935 |
src/analyze.cpp+2| ... | ... | @@ -3214,6 +3214,8 @@ void scan_decls(CodeGen *g, ScopeDecls *decls_scope, AstNode *node) { |
| 3214 | 3214 | case NodeTypeTestExpr: |
| 3215 | 3215 | case NodeTypeErrorSetDecl: |
| 3216 | 3216 | case NodeTypeCancel: |
| 3217 | case NodeTypeAwaitExpr: | |
| 3218 | case NodeTypeSuspend: | |
| 3217 | 3219 | zig_unreachable(); |
| 3218 | 3220 | } |
| 3219 | 3221 | } |
src/ast_render.cpp+21| ... | ... | @@ -246,6 +246,10 @@ static const char *node_type_str(NodeType node_type) { |
| 246 | 246 | return "ErrorSetDecl"; |
| 247 | 247 | case NodeTypeCancel: |
| 248 | 248 | return "Cancel"; |
| 249 | case NodeTypeAwaitExpr: | |
| 250 | return "AwaitExpr"; | |
| 251 | case NodeTypeSuspend: | |
| 252 | return "Suspend"; | |
| 249 | 253 | } |
| 250 | 254 | zig_unreachable(); |
| 251 | 255 | } |
| ... | ... | @@ -1045,6 +1049,23 @@ static void render_node_extra(AstRender *ar, AstNode *node, bool grouped) { |
| 1045 | 1049 | render_node_grouped(ar, node->data.cancel_expr.expr); |
| 1046 | 1050 | break; |
| 1047 | 1051 | } |
| 1052 | case NodeTypeAwaitExpr: | |
| 1053 | { | |
| 1054 | fprintf(ar->f, "await "); | |
| 1055 | render_node_grouped(ar, node->data.await_expr.expr); | |
| 1056 | break; | |
| 1057 | } | |
| 1058 | case NodeTypeSuspend: | |
| 1059 | { | |
| 1060 | fprintf(ar->f, "suspend"); | |
| 1061 | if (node->data.suspend.block != nullptr) { | |
| 1062 | fprintf(ar->f, " |"); | |
| 1063 | render_node_grouped(ar, node->data.suspend.promise_symbol); | |
| 1064 | fprintf(ar->f, "| "); | |
| 1065 | render_node_grouped(ar, node->data.suspend.block); | |
| 1066 | } | |
| 1067 | break; | |
| 1068 | } | |
| 1048 | 1069 | case NodeTypeFnDecl: |
| 1049 | 1070 | case NodeTypeParamDecl: |
| 1050 | 1071 | case NodeTypeTestDecl: |
src/ir.cpp+20| ... | ... | @@ -5834,6 +5834,22 @@ static IrInstruction *ir_gen_cancel(IrBuilder *irb, Scope *parent_scope, AstNode |
| 5834 | 5834 | return ir_build_cancel(irb, parent_scope, node, target_inst); |
| 5835 | 5835 | } |
| 5836 | 5836 | |
| 5837 | static IrInstruction *ir_gen_await_expr(IrBuilder *irb, Scope *parent_scope, AstNode *node) { | |
| 5838 | assert(node->type == NodeTypeAwaitExpr); | |
| 5839 | ||
| 5840 | IrInstruction *target_inst = ir_gen_node(irb, node->data.await_expr.expr, parent_scope); | |
| 5841 | if (target_inst == irb->codegen->invalid_instruction) | |
| 5842 | return irb->codegen->invalid_instruction; | |
| 5843 | ||
| 5844 | zig_panic("TODO: generate await expr"); | |
| 5845 | } | |
| 5846 | ||
| 5847 | static IrInstruction *ir_gen_suspend(IrBuilder *irb, Scope *parent_scope, AstNode *node) { | |
| 5848 | assert(node->type == NodeTypeSuspend); | |
| 5849 | ||
| 5850 | zig_panic("TODO: generate suspend"); | |
| 5851 | } | |
| 5852 | ||
| 5837 | 5853 | static IrInstruction *ir_gen_node_raw(IrBuilder *irb, AstNode *node, Scope *scope, |
| 5838 | 5854 | LVal lval) |
| 5839 | 5855 | { |
| ... | ... | @@ -5932,6 +5948,10 @@ static IrInstruction *ir_gen_node_raw(IrBuilder *irb, AstNode *node, Scope *scop |
| 5932 | 5948 | return ir_lval_wrap(irb, scope, ir_gen_err_set_decl(irb, scope, node), lval); |
| 5933 | 5949 | case NodeTypeCancel: |
| 5934 | 5950 | return ir_lval_wrap(irb, scope, ir_gen_cancel(irb, scope, node), lval); |
| 5951 | case NodeTypeAwaitExpr: | |
| 5952 | return ir_lval_wrap(irb, scope, ir_gen_await_expr(irb, scope, node), lval); | |
| 5953 | case NodeTypeSuspend: | |
| 5954 | return ir_lval_wrap(irb, scope, ir_gen_suspend(irb, scope, node), lval); | |
| 5935 | 5955 | } |
| 5936 | 5956 | zig_unreachable(); |
| 5937 | 5957 | } |
src/parser.cpp+76-3| ... | ... | @@ -221,6 +221,7 @@ static AstNode *ast_parse_grouped_expr(ParseContext *pc, size_t *token_index, bo |
| 221 | 221 | static AstNode *ast_parse_container_decl(ParseContext *pc, size_t *token_index, bool mandatory); |
| 222 | 222 | static AstNode *ast_parse_primary_expr(ParseContext *pc, size_t *token_index, bool mandatory); |
| 223 | 223 | static AstNode *ast_parse_try_expr(ParseContext *pc, size_t *token_index); |
| 224 | static AstNode *ast_parse_await_expr(ParseContext *pc, size_t *token_index); | |
| 224 | 225 | static AstNode *ast_parse_symbol(ParseContext *pc, size_t *token_index); |
| 225 | 226 | |
| 226 | 227 | static void ast_expect_token(ParseContext *pc, Token *token, TokenId token_id) { |
| ... | ... | @@ -650,6 +651,41 @@ static AstNode *ast_parse_asm_expr(ParseContext *pc, size_t *token_index, bool m |
| 650 | 651 | return node; |
| 651 | 652 | } |
| 652 | 653 | |
| 654 | /* | |
| 655 | SuspendExpression(body) = "suspend" "|" Symbol "|" body | |
| 656 | */ | |
| 657 | static AstNode *ast_parse_suspend_block(ParseContext *pc, size_t *token_index, bool mandatory) { | |
| 658 | size_t orig_token_index = *token_index; | |
| 659 | ||
| 660 | Token *suspend_token = &pc->tokens->at(*token_index); | |
| 661 | if (suspend_token->id == TokenIdKeywordSuspend) { | |
| 662 | *token_index += 1; | |
| 663 | } else if (mandatory) { | |
| 664 | ast_expect_token(pc, suspend_token, TokenIdKeywordSuspend); | |
| 665 | zig_unreachable(); | |
| 666 | } else { | |
| 667 | return nullptr; | |
| 668 | } | |
| 669 | ||
| 670 | Token *bar_token = &pc->tokens->at(*token_index); | |
| 671 | if (bar_token->id == TokenIdBinOr) { | |
| 672 | *token_index += 1; | |
| 673 | } else if (mandatory) { | |
| 674 | ast_expect_token(pc, suspend_token, TokenIdBinOr); | |
| 675 | zig_unreachable(); | |
| 676 | } else { | |
| 677 | *token_index = orig_token_index; | |
| 678 | return nullptr; | |
| 679 | } | |
| 680 | ||
| 681 | AstNode *node = ast_create_node(pc, NodeTypeSuspend, suspend_token); | |
| 682 | node->data.suspend.promise_symbol = ast_parse_symbol(pc, token_index); | |
| 683 | ast_eat_token(pc, token_index, TokenIdBinOr); | |
| 684 | node->data.suspend.block = ast_parse_block(pc, token_index, true); | |
| 685 | ||
| 686 | return node; | |
| 687 | } | |
| 688 | ||
| 653 | 689 | /* |
| 654 | 690 | CompTimeExpression(body) = "comptime" body |
| 655 | 691 | */ |
| ... | ... | @@ -674,7 +710,7 @@ static AstNode *ast_parse_comptime_expr(ParseContext *pc, size_t *token_index, b |
| 674 | 710 | |
| 675 | 711 | /* |
| 676 | 712 | PrimaryExpression = Integer | Float | String | CharLiteral | KeywordLiteral | GroupedExpression | BlockExpression(BlockOrExpression) | Symbol | ("@" Symbol FnCallExpression) | ArrayType | FnProto | AsmExpression | ContainerDecl | ("continue" option(":" Symbol)) | ErrorSetDecl |
| 677 | KeywordLiteral = "true" | "false" | "null" | "undefined" | "error" | "this" | "unreachable" | |
| 713 | KeywordLiteral = "true" | "false" | "null" | "undefined" | "error" | "this" | "unreachable" | "suspend" | |
| 678 | 714 | ErrorSetDecl = "error" "{" list(Symbol, ",") "}" |
| 679 | 715 | */ |
| 680 | 716 | static AstNode *ast_parse_primary_expr(ParseContext *pc, size_t *token_index, bool mandatory) { |
| ... | ... | @@ -738,6 +774,10 @@ static AstNode *ast_parse_primary_expr(ParseContext *pc, size_t *token_index, bo |
| 738 | 774 | AstNode *node = ast_create_node(pc, NodeTypeUnreachable, token); |
| 739 | 775 | *token_index += 1; |
| 740 | 776 | return node; |
| 777 | } else if (token->id == TokenIdKeywordSuspend) { | |
| 778 | AstNode *node = ast_create_node(pc, NodeTypeSuspend, token); | |
| 779 | *token_index += 1; | |
| 780 | return node; | |
| 741 | 781 | } else if (token->id == TokenIdKeywordError) { |
| 742 | 782 | Token *next_token = &pc->tokens->at(*token_index + 1); |
| 743 | 783 | if (next_token->id == TokenIdLBrace) { |
| ... | ... | @@ -1067,7 +1107,7 @@ static AstNode *ast_parse_addr_of(ParseContext *pc, size_t *token_index) { |
| 1067 | 1107 | |
| 1068 | 1108 | /* |
| 1069 | 1109 | PrefixOpExpression = PrefixOp ErrorSetExpr | SuffixOpExpression |
| 1070 | PrefixOp = "!" | "-" | "~" | "*" | ("&" option("align" "(" Expression option(":" Integer ":" Integer) ")" ) option("const") option("volatile")) | "?" | "??" | "-%" | "try" | |
| 1110 | PrefixOp = "!" | "-" | "~" | "*" | ("&" option("align" "(" Expression option(":" Integer ":" Integer) ")" ) option("const") option("volatile")) | "?" | "??" | "-%" | "try" | "await" | |
| 1071 | 1111 | */ |
| 1072 | 1112 | static AstNode *ast_parse_prefix_op_expr(ParseContext *pc, size_t *token_index, bool mandatory) { |
| 1073 | 1113 | Token *token = &pc->tokens->at(*token_index); |
| ... | ... | @@ -1077,6 +1117,9 @@ static AstNode *ast_parse_prefix_op_expr(ParseContext *pc, size_t *token_index, |
| 1077 | 1117 | if (token->id == TokenIdKeywordTry) { |
| 1078 | 1118 | return ast_parse_try_expr(pc, token_index); |
| 1079 | 1119 | } |
| 1120 | if (token->id == TokenIdKeywordAwait) { | |
| 1121 | return ast_parse_await_expr(pc, token_index); | |
| 1122 | } | |
| 1080 | 1123 | PrefixOp prefix_op = tok_to_prefix_op(token); |
| 1081 | 1124 | if (prefix_op == PrefixOpInvalid) { |
| 1082 | 1125 | return ast_parse_suffix_op_expr(pc, token_index, mandatory); |
| ... | ... | @@ -1535,6 +1578,23 @@ static AstNode *ast_parse_try_expr(ParseContext *pc, size_t *token_index) { |
| 1535 | 1578 | return node; |
| 1536 | 1579 | } |
| 1537 | 1580 | |
| 1581 | /* | |
| 1582 | AwaitExpression : "await" Expression | |
| 1583 | */ | |
| 1584 | static AstNode *ast_parse_await_expr(ParseContext *pc, size_t *token_index) { | |
| 1585 | Token *token = &pc->tokens->at(*token_index); | |
| 1586 | ||
| 1587 | if (token->id != TokenIdKeywordAwait) { | |
| 1588 | return nullptr; | |
| 1589 | } | |
| 1590 | *token_index += 1; | |
| 1591 | ||
| 1592 | AstNode *node = ast_create_node(pc, NodeTypeAwaitExpr, token); | |
| 1593 | node->data.await_expr.expr = ast_parse_expression(pc, token_index, true); | |
| 1594 | ||
| 1595 | return node; | |
| 1596 | } | |
| 1597 | ||
| 1538 | 1598 | /* |
| 1539 | 1599 | BreakExpression = "break" option(":" Symbol) option(Expression) |
| 1540 | 1600 | */ |
| ... | ... | @@ -2044,7 +2104,7 @@ static AstNode *ast_parse_switch_expr(ParseContext *pc, size_t *token_index, boo |
| 2044 | 2104 | } |
| 2045 | 2105 | |
| 2046 | 2106 | /* |
| 2047 | BlockExpression(body) = Block | IfExpression(body) | TryExpression(body) | TestExpression(body) | WhileExpression(body) | ForExpression(body) | SwitchExpression | CompTimeExpression(body) | |
| 2107 | BlockExpression(body) = Block | IfExpression(body) | IfErrorExpression(body) | TestExpression(body) | WhileExpression(body) | ForExpression(body) | SwitchExpression | CompTimeExpression(body) | SuspendExpression(body) | |
| 2048 | 2108 | */ |
| 2049 | 2109 | static AstNode *ast_parse_block_expr(ParseContext *pc, size_t *token_index, bool mandatory) { |
| 2050 | 2110 | Token *token = &pc->tokens->at(*token_index); |
| ... | ... | @@ -2073,6 +2133,10 @@ static AstNode *ast_parse_block_expr(ParseContext *pc, size_t *token_index, bool |
| 2073 | 2133 | if (comptime_node) |
| 2074 | 2134 | return comptime_node; |
| 2075 | 2135 | |
| 2136 | AstNode *suspend_node = ast_parse_suspend_block(pc, token_index, false); | |
| 2137 | if (suspend_node) | |
| 2138 | return suspend_node; | |
| 2139 | ||
| 2076 | 2140 | if (mandatory) |
| 2077 | 2141 | ast_invalid_token_error(pc, token); |
| 2078 | 2142 | |
| ... | ... | @@ -2255,6 +2319,8 @@ static bool statement_terminates_without_semicolon(AstNode *node) { |
| 2255 | 2319 | return node->data.comptime_expr.expr->type == NodeTypeBlock; |
| 2256 | 2320 | case NodeTypeDefer: |
| 2257 | 2321 | return node->data.defer.expr->type == NodeTypeBlock; |
| 2322 | case NodeTypeSuspend: | |
| 2323 | return node->data.suspend.block != nullptr && node->data.suspend.block->type == NodeTypeBlock; | |
| 2258 | 2324 | case NodeTypeSwitchExpr: |
| 2259 | 2325 | case NodeTypeBlock: |
| 2260 | 2326 | return true; |
| ... | ... | @@ -2994,5 +3060,12 @@ void ast_visit_node_children(AstNode *node, void (*visit)(AstNode **, void *cont |
| 2994 | 3060 | case NodeTypeCancel: |
| 2995 | 3061 | visit_field(&node->data.cancel_expr.expr, visit, context); |
| 2996 | 3062 | break; |
| 3063 | case NodeTypeAwaitExpr: | |
| 3064 | visit_field(&node->data.await_expr.expr, visit, context); | |
| 3065 | break; | |
| 3066 | case NodeTypeSuspend: | |
| 3067 | visit_field(&node->data.suspend.promise_symbol, visit, context); | |
| 3068 | visit_field(&node->data.suspend.block, visit, context); | |
| 3069 | break; | |
| 2997 | 3070 | } |
| 2998 | 3071 | } |