| author | |
| committer | |
| log | ec33e5a638b816ab0ba1e4dd3f9433dbb71d7e53 |
| tree | 72e6b01315b7902290ae6747ea39499fe0818890 |
| parent | 6a2ede5a6eb17d6b86e6636457710a3583376fa3 |
See #1108 files changed, 103 insertions(+), 75 deletions(-)
doc/langref.md+3-3| ... | ... | @@ -43,7 +43,7 @@ ParamDecl = option("noalias") option("Symbol" ":") TypeExpr | "..." |
| 43 | 43 | |
| 44 | 44 | Block = "{" list(option(Statement), ";") "}" |
| 45 | 45 | |
| 46 | Statement = Label | VariableDeclaration ";" | NonBlockExpression ";" | BlockExpression | |
| 46 | Statement = Label | VariableDeclaration ";" | Defer ";" | NonBlockExpression ";" | BlockExpression | |
| 47 | 47 | |
| 48 | 48 | Label = "Symbol" ":" |
| 49 | 49 | |
| ... | ... | @@ -51,7 +51,7 @@ Expression = BlockExpression | NonBlockExpression |
| 51 | 51 | |
| 52 | 52 | TypeExpr = PrefixOpExpression |
| 53 | 53 | |
| 54 | NonBlockExpression = ReturnExpression | AssignmentExpression | DeferExpression | |
| 54 | NonBlockExpression = ReturnExpression | AssignmentExpression | |
| 55 | 55 | |
| 56 | 56 | AsmExpression = "asm" option("volatile") "(" "String" option(AsmOutput) ")" |
| 57 | 57 | |
| ... | ... | @@ -91,7 +91,7 @@ BoolOrExpression = BoolAndExpression "||" BoolOrExpression | BoolAndExpression |
| 91 | 91 | |
| 92 | 92 | ReturnExpression = option("%" | "?") "return" option(Expression) |
| 93 | 93 | |
| 94 | DeferExpression = option("%" | "?") "defer" option(Expression) | |
| 94 | Defer = option("%" | "?") "defer" option(Expression) | |
| 95 | 95 | |
| 96 | 96 | IfExpression = IfVarExpression | IfBoolExpression |
| 97 | 97 |
example/cat/main.zig-1| ... | ... | @@ -4,7 +4,6 @@ import "std.zig"; |
| 4 | 4 | |
| 5 | 5 | // Things to do to make this work: |
| 6 | 6 | // * var args printing |
| 7 | // * defer | |
| 8 | 7 | // * cast err type to string |
| 9 | 8 | // * string equality |
| 10 | 9 |
src/all_types.hpp+14-6| ... | ... | @@ -117,7 +117,7 @@ enum NodeType { |
| 117 | 117 | NodeTypeBlock, |
| 118 | 118 | NodeTypeDirective, |
| 119 | 119 | NodeTypeReturnExpr, |
| 120 | NodeTypeDeferExpr, | |
| 120 | NodeTypeDefer, | |
| 121 | 121 | NodeTypeVariableDeclaration, |
| 122 | 122 | NodeTypeTypeDecl, |
| 123 | 123 | NodeTypeErrorValueDecl, |
| ... | ... | @@ -216,7 +216,12 @@ struct AstNodeBlock { |
| 216 | 216 | ZigList<AstNode *> statements; |
| 217 | 217 | |
| 218 | 218 | // populated by semantic analyzer |
| 219 | BlockContext *block_context; | |
| 219 | // this one is the scope that the block itself introduces | |
| 220 | BlockContext *child_block; | |
| 221 | // this is the innermost scope created by defers and var decls. | |
| 222 | // you can follow its parents up to child_block. it will equal | |
| 223 | // child_block if there are no defers or var decls in the block. | |
| 224 | BlockContext *nested_block; | |
| 220 | 225 | Expr resolved_expr; |
| 221 | 226 | }; |
| 222 | 227 | |
| ... | ... | @@ -235,7 +240,7 @@ struct AstNodeReturnExpr { |
| 235 | 240 | Expr resolved_expr; |
| 236 | 241 | }; |
| 237 | 242 | |
| 238 | struct AstNodeDeferExpr { | |
| 243 | struct AstNodeDefer { | |
| 239 | 244 | ReturnKind kind; |
| 240 | 245 | AstNode *expr; |
| 241 | 246 | |
| ... | ... | @@ -243,6 +248,7 @@ struct AstNodeDeferExpr { |
| 243 | 248 | Expr resolved_expr; |
| 244 | 249 | int index_in_block; |
| 245 | 250 | LLVMBasicBlockRef basic_block; |
| 251 | BlockContext *child_block; | |
| 246 | 252 | }; |
| 247 | 253 | |
| 248 | 254 | struct AstNodeVariableDeclaration { |
| ... | ... | @@ -739,7 +745,7 @@ struct AstNode { |
| 739 | 745 | AstNodeParamDecl param_decl; |
| 740 | 746 | AstNodeBlock block; |
| 741 | 747 | AstNodeReturnExpr return_expr; |
| 742 | AstNodeDeferExpr defer_expr; | |
| 748 | AstNodeDefer defer; | |
| 743 | 749 | AstNodeVariableDeclaration variable_declaration; |
| 744 | 750 | AstNodeTypeDecl type_decl; |
| 745 | 751 | AstNodeErrorValueDecl error_value_decl; |
| ... | ... | @@ -1157,10 +1163,12 @@ enum BlockExitPath { |
| 1157 | 1163 | BlockExitPathFallthrough, |
| 1158 | 1164 | BlockExitPathReturn, |
| 1159 | 1165 | BlockExitPathGoto, |
| 1166 | ||
| 1167 | BlockExitPathCount, | |
| 1160 | 1168 | }; |
| 1161 | 1169 | |
| 1162 | 1170 | struct BlockContext { |
| 1163 | // One of: NodeTypeFnDef, NodeTypeBlock, NodeTypeRoot, NodeTypeDeferExpr, NodeTypeVariableDeclaration | |
| 1171 | // One of: NodeTypeFnDef, NodeTypeBlock, NodeTypeRoot, NodeTypeDefer, NodeTypeVariableDeclaration | |
| 1164 | 1172 | AstNode *node; |
| 1165 | 1173 | |
| 1166 | 1174 | // any variables that are introduced by this scope |
| ... | ... | @@ -1178,7 +1186,7 @@ struct BlockContext { |
| 1178 | 1186 | |
| 1179 | 1187 | LLVMZigDIScope *di_scope; |
| 1180 | 1188 | Buf *c_import_buf; |
| 1181 | bool block_exit_paths[3]; // one for each BlockExitPath | |
| 1189 | bool block_exit_paths[BlockExitPathCount]; | |
| 1182 | 1190 | }; |
| 1183 | 1191 | |
| 1184 | 1192 | enum CIntType { |
src/analyze.cpp+35-31| ... | ... | @@ -57,7 +57,7 @@ static AstNode *first_executing_node(AstNode *node) { |
| 57 | 57 | case NodeTypeBlock: |
| 58 | 58 | case NodeTypeDirective: |
| 59 | 59 | case NodeTypeReturnExpr: |
| 60 | case NodeTypeDeferExpr: | |
| 60 | case NodeTypeDefer: | |
| 61 | 61 | case NodeTypeVariableDeclaration: |
| 62 | 62 | case NodeTypeTypeDecl: |
| 63 | 63 | case NodeTypeErrorValueDecl: |
| ... | ... | @@ -1456,7 +1456,7 @@ static void resolve_top_level_decl(CodeGen *g, ImportTableEntry *import, AstNode |
| 1456 | 1456 | case NodeTypeParamDecl: |
| 1457 | 1457 | case NodeTypeFnDecl: |
| 1458 | 1458 | case NodeTypeReturnExpr: |
| 1459 | case NodeTypeDeferExpr: | |
| 1459 | case NodeTypeDefer: | |
| 1460 | 1460 | case NodeTypeRoot: |
| 1461 | 1461 | case NodeTypeBlock: |
| 1462 | 1462 | case NodeTypeBinOpExpr: |
| ... | ... | @@ -4590,56 +4590,54 @@ static void validate_voided_expr(CodeGen *g, AstNode *source_node, TypeTableEntr |
| 4590 | 4590 | } |
| 4591 | 4591 | } |
| 4592 | 4592 | |
| 4593 | static TypeTableEntry *analyze_defer_expr(CodeGen *g, ImportTableEntry *import, BlockContext *context, | |
| 4593 | static TypeTableEntry *analyze_defer(CodeGen *g, ImportTableEntry *import, BlockContext *parent_context, | |
| 4594 | 4594 | TypeTableEntry *expected_type, AstNode *node) |
| 4595 | 4595 | { |
| 4596 | if (!context->fn_entry) { | |
| 4596 | if (!parent_context->fn_entry) { | |
| 4597 | 4597 | add_node_error(g, node, buf_sprintf("defer expression outside function definition")); |
| 4598 | 4598 | return g->builtin_types.entry_invalid; |
| 4599 | 4599 | } |
| 4600 | 4600 | |
| 4601 | if (!node->data.defer_expr.expr) { | |
| 4601 | if (!node->data.defer.expr) { | |
| 4602 | 4602 | add_node_error(g, node, buf_sprintf("defer expects an expression")); |
| 4603 | 4603 | return g->builtin_types.entry_void; |
| 4604 | 4604 | } |
| 4605 | 4605 | |
| 4606 | node->data.defer.child_block = new_block_context(node, parent_context); | |
| 4606 | 4607 | |
| 4607 | switch (node->data.defer_expr.kind) { | |
| 4608 | switch (node->data.defer.kind) { | |
| 4608 | 4609 | case ReturnKindUnconditional: |
| 4609 | 4610 | { |
| 4610 | TypeTableEntry *resolved_type = analyze_expression(g, import, context, nullptr, | |
| 4611 | node->data.defer_expr.expr); | |
| 4612 | validate_voided_expr(g, node->data.defer_expr.expr, resolved_type); | |
| 4613 | zig_panic("TODO"); | |
| 4611 | TypeTableEntry *resolved_type = analyze_expression(g, import, parent_context, nullptr, | |
| 4612 | node->data.defer.expr); | |
| 4613 | validate_voided_expr(g, node->data.defer.expr, resolved_type); | |
| 4614 | 4614 | |
| 4615 | //node->data.defer_expr.index_in_block = context->defer_list.length; | |
| 4616 | //context->defer_list.append(node); | |
| 4617 | 4615 | return g->builtin_types.entry_void; |
| 4618 | 4616 | } |
| 4619 | 4617 | case ReturnKindError: |
| 4620 | 4618 | { |
| 4621 | TypeTableEntry *resolved_type = analyze_expression(g, import, context, nullptr, | |
| 4622 | node->data.defer_expr.expr); | |
| 4619 | TypeTableEntry *resolved_type = analyze_expression(g, import, parent_context, nullptr, | |
| 4620 | node->data.defer.expr); | |
| 4623 | 4621 | if (resolved_type->id == TypeTableEntryIdInvalid) { |
| 4624 | 4622 | // OK |
| 4625 | 4623 | } else if (resolved_type->id == TypeTableEntryIdErrorUnion) { |
| 4626 | 4624 | // OK |
| 4627 | 4625 | } else { |
| 4628 | add_node_error(g, node->data.defer_expr.expr, | |
| 4626 | add_node_error(g, node->data.defer.expr, | |
| 4629 | 4627 | buf_sprintf("expected error type, got '%s'", buf_ptr(&resolved_type->name))); |
| 4630 | 4628 | } |
| 4631 | 4629 | return g->builtin_types.entry_void; |
| 4632 | 4630 | } |
| 4633 | 4631 | case ReturnKindMaybe: |
| 4634 | 4632 | { |
| 4635 | TypeTableEntry *resolved_type = analyze_expression(g, import, context, nullptr, | |
| 4636 | node->data.defer_expr.expr); | |
| 4633 | TypeTableEntry *resolved_type = analyze_expression(g, import, parent_context, nullptr, | |
| 4634 | node->data.defer.expr); | |
| 4637 | 4635 | if (resolved_type->id == TypeTableEntryIdInvalid) { |
| 4638 | 4636 | // OK |
| 4639 | 4637 | } else if (resolved_type->id == TypeTableEntryIdMaybe) { |
| 4640 | 4638 | // OK |
| 4641 | 4639 | } else { |
| 4642 | add_node_error(g, node->data.defer_expr.expr, | |
| 4640 | add_node_error(g, node->data.defer.expr, | |
| 4643 | 4641 | buf_sprintf("expected maybe type, got '%s'", buf_ptr(&resolved_type->name))); |
| 4644 | 4642 | } |
| 4645 | 4643 | return g->builtin_types.entry_void; |
| ... | ... | @@ -4657,11 +4655,11 @@ static TypeTableEntry *analyze_string_literal_expr(CodeGen *g, ImportTableEntry |
| 4657 | 4655 | } |
| 4658 | 4656 | } |
| 4659 | 4657 | |
| 4660 | static TypeTableEntry *analyze_block_expr(CodeGen *g, ImportTableEntry *import, BlockContext *context, | |
| 4658 | static TypeTableEntry *analyze_block_expr(CodeGen *g, ImportTableEntry *import, BlockContext *parent_context, | |
| 4661 | 4659 | TypeTableEntry *expected_type, AstNode *node) |
| 4662 | 4660 | { |
| 4663 | BlockContext *child_context = new_block_context(node, context); | |
| 4664 | node->data.block.block_context = child_context; | |
| 4661 | BlockContext *child_context = new_block_context(node, parent_context); | |
| 4662 | node->data.block.child_block = child_context; | |
| 4665 | 4663 | TypeTableEntry *return_type = g->builtin_types.entry_void; |
| 4666 | 4664 | |
| 4667 | 4665 | for (int i = 0; i < node->data.block.statements.length; i += 1) { |
| ... | ... | @@ -4676,7 +4674,7 @@ static TypeTableEntry *analyze_block_expr(CodeGen *g, ImportTableEntry *import, |
| 4676 | 4674 | if (is_node_void_expr(child)) { |
| 4677 | 4675 | // {unreachable;void;void} is allowed. |
| 4678 | 4676 | // ignore void statements once we enter unreachable land. |
| 4679 | analyze_expression(g, import, context, g->builtin_types.entry_void, child); | |
| 4677 | analyze_expression(g, import, child_context, g->builtin_types.entry_void, child); | |
| 4680 | 4678 | continue; |
| 4681 | 4679 | } |
| 4682 | 4680 | add_node_error(g, first_executing_node(child), buf_sprintf("unreachable code")); |
| ... | ... | @@ -4685,10 +4683,16 @@ static TypeTableEntry *analyze_block_expr(CodeGen *g, ImportTableEntry *import, |
| 4685 | 4683 | bool is_last = (i == node->data.block.statements.length - 1); |
| 4686 | 4684 | TypeTableEntry *passed_expected_type = is_last ? expected_type : nullptr; |
| 4687 | 4685 | return_type = analyze_expression(g, import, child_context, passed_expected_type, child); |
| 4686 | if (child->type == NodeTypeDefer && return_type->id != TypeTableEntryIdInvalid) { | |
| 4687 | // defer starts a new block context | |
| 4688 | child_context = child->data.defer.child_block; | |
| 4689 | assert(child_context); | |
| 4690 | } | |
| 4688 | 4691 | if (!is_last) { |
| 4689 | 4692 | validate_voided_expr(g, child, return_type); |
| 4690 | 4693 | } |
| 4691 | 4694 | } |
| 4695 | node->data.block.nested_block = child_context; | |
| 4692 | 4696 | return return_type; |
| 4693 | 4697 | } |
| 4694 | 4698 | |
| ... | ... | @@ -4750,8 +4754,8 @@ static TypeTableEntry *analyze_expression(CodeGen *g, ImportTableEntry *import, |
| 4750 | 4754 | case NodeTypeReturnExpr: |
| 4751 | 4755 | return_type = analyze_return_expr(g, import, context, expected_type, node); |
| 4752 | 4756 | break; |
| 4753 | case NodeTypeDeferExpr: | |
| 4754 | return_type = analyze_defer_expr(g, import, context, expected_type, node); | |
| 4757 | case NodeTypeDefer: | |
| 4758 | return_type = analyze_defer(g, import, context, expected_type, node); | |
| 4755 | 4759 | break; |
| 4756 | 4760 | case NodeTypeVariableDeclaration: |
| 4757 | 4761 | analyze_variable_declaration(g, import, context, expected_type, node); |
| ... | ... | @@ -4956,7 +4960,7 @@ static void analyze_top_level_decl(CodeGen *g, ImportTableEntry *import, AstNode |
| 4956 | 4960 | case NodeTypeParamDecl: |
| 4957 | 4961 | case NodeTypeFnDecl: |
| 4958 | 4962 | case NodeTypeReturnExpr: |
| 4959 | case NodeTypeDeferExpr: | |
| 4963 | case NodeTypeDefer: | |
| 4960 | 4964 | case NodeTypeRoot: |
| 4961 | 4965 | case NodeTypeBlock: |
| 4962 | 4966 | case NodeTypeBinOpExpr: |
| ... | ... | @@ -5039,8 +5043,8 @@ static void collect_expr_decl_deps(CodeGen *g, ImportTableEntry *import, AstNode |
| 5039 | 5043 | case NodeTypeReturnExpr: |
| 5040 | 5044 | collect_expr_decl_deps(g, import, node->data.return_expr.expr, decl_node); |
| 5041 | 5045 | break; |
| 5042 | case NodeTypeDeferExpr: | |
| 5043 | collect_expr_decl_deps(g, import, node->data.defer_expr.expr, decl_node); | |
| 5046 | case NodeTypeDefer: | |
| 5047 | collect_expr_decl_deps(g, import, node->data.defer.expr, decl_node); | |
| 5044 | 5048 | break; |
| 5045 | 5049 | case NodeTypePrefixOpExpr: |
| 5046 | 5050 | collect_expr_decl_deps(g, import, node->data.prefix_op_expr.primary_expr, decl_node); |
| ... | ... | @@ -5361,7 +5365,7 @@ static void detect_top_level_decl_deps(CodeGen *g, ImportTableEntry *import, Ast |
| 5361 | 5365 | case NodeTypeParamDecl: |
| 5362 | 5366 | case NodeTypeFnDecl: |
| 5363 | 5367 | case NodeTypeReturnExpr: |
| 5364 | case NodeTypeDeferExpr: | |
| 5368 | case NodeTypeDefer: | |
| 5365 | 5369 | case NodeTypeBlock: |
| 5366 | 5370 | case NodeTypeBinOpExpr: |
| 5367 | 5371 | case NodeTypeUnwrapErrorExpr: |
| ... | ... | @@ -5552,8 +5556,8 @@ Expr *get_resolved_expr(AstNode *node) { |
| 5552 | 5556 | switch (node->type) { |
| 5553 | 5557 | case NodeTypeReturnExpr: |
| 5554 | 5558 | return &node->data.return_expr.resolved_expr; |
| 5555 | case NodeTypeDeferExpr: | |
| 5556 | return &node->data.defer_expr.resolved_expr; | |
| 5559 | case NodeTypeDefer: | |
| 5560 | return &node->data.defer.resolved_expr; | |
| 5557 | 5561 | case NodeTypeBinOpExpr: |
| 5558 | 5562 | return &node->data.bin_op_expr.resolved_expr; |
| 5559 | 5563 | case NodeTypeUnwrapErrorExpr: |
| ... | ... | @@ -5652,7 +5656,7 @@ TopLevelDecl *get_resolved_top_level_decl(AstNode *node) { |
| 5652 | 5656 | return &node->data.type_decl.top_level_decl; |
| 5653 | 5657 | case NodeTypeNumberLiteral: |
| 5654 | 5658 | case NodeTypeReturnExpr: |
| 5655 | case NodeTypeDeferExpr: | |
| 5659 | case NodeTypeDefer: | |
| 5656 | 5660 | case NodeTypeBinOpExpr: |
| 5657 | 5661 | case NodeTypeUnwrapErrorExpr: |
| 5658 | 5662 | case NodeTypePrefixOpExpr: |
src/ast_render.cpp+7-7| ... | ... | @@ -122,8 +122,8 @@ static const char *node_type_str(NodeType node_type) { |
| 122 | 122 | return "Directive"; |
| 123 | 123 | case NodeTypeReturnExpr: |
| 124 | 124 | return "ReturnExpr"; |
| 125 | case NodeTypeDeferExpr: | |
| 126 | return "DeferExpr"; | |
| 125 | case NodeTypeDefer: | |
| 126 | return "Defer"; | |
| 127 | 127 | case NodeTypeVariableDeclaration: |
| 128 | 128 | return "VariableDeclaration"; |
| 129 | 129 | case NodeTypeTypeDecl: |
| ... | ... | @@ -261,12 +261,12 @@ void ast_print(FILE *f, AstNode *node, int indent) { |
| 261 | 261 | ast_print(f, node->data.return_expr.expr, indent + 2); |
| 262 | 262 | break; |
| 263 | 263 | } |
| 264 | case NodeTypeDeferExpr: | |
| 264 | case NodeTypeDefer: | |
| 265 | 265 | { |
| 266 | const char *prefix_str = return_prefix_str(node->data.defer_expr.kind); | |
| 266 | const char *prefix_str = return_prefix_str(node->data.defer.kind); | |
| 267 | 267 | fprintf(f, "%s%s\n", prefix_str, node_type_str(node->type)); |
| 268 | if (node->data.defer_expr.expr) | |
| 269 | ast_print(f, node->data.defer_expr.expr, indent + 2); | |
| 268 | if (node->data.defer.expr) | |
| 269 | ast_print(f, node->data.defer.expr, indent + 2); | |
| 270 | 270 | break; |
| 271 | 271 | } |
| 272 | 272 | case NodeTypeVariableDeclaration: |
| ... | ... | @@ -630,7 +630,7 @@ static void render_node(AstRender *ar, AstNode *node) { |
| 630 | 630 | break; |
| 631 | 631 | case NodeTypeReturnExpr: |
| 632 | 632 | zig_panic("TODO"); |
| 633 | case NodeTypeDeferExpr: | |
| 633 | case NodeTypeDefer: | |
| 634 | 634 | zig_panic("TODO"); |
| 635 | 635 | case NodeTypeVariableDeclaration: |
| 636 | 636 | { |
src/codegen.cpp+26-22| ... | ... | @@ -1669,11 +1669,9 @@ static LLVMValueRef gen_return_expr(CodeGen *g, AstNode *node) { |
| 1669 | 1669 | } |
| 1670 | 1670 | } |
| 1671 | 1671 | |
| 1672 | static LLVMValueRef gen_defer_expr(CodeGen *g, AstNode *node) { | |
| 1673 | assert(node->type == NodeTypeDeferExpr); | |
| 1672 | static LLVMValueRef gen_defer(CodeGen *g, AstNode *node) { | |
| 1673 | assert(node->type == NodeTypeDefer); | |
| 1674 | 1674 | |
| 1675 | zig_panic("TODO"); | |
| 1676 | //node->block_context->cur_defer_index = node->data.defer_expr.index_in_block; | |
| 1677 | 1675 | |
| 1678 | 1676 | return nullptr; |
| 1679 | 1677 | } |
| ... | ... | @@ -1800,31 +1798,37 @@ static LLVMValueRef gen_if_var_expr(CodeGen *g, AstNode *node) { |
| 1800 | 1798 | return return_value; |
| 1801 | 1799 | } |
| 1802 | 1800 | |
| 1801 | //static int block_exit_path_count(BlockContext *block_context) { | |
| 1802 | // int sum = 0; | |
| 1803 | // for (int i = 0; i < BlockExitPathCount; i += 1) { | |
| 1804 | // sum += block_context->block_exit_paths[i] ? 1 : 0; | |
| 1805 | // } | |
| 1806 | // return sum; | |
| 1807 | //} | |
| 1808 | ||
| 1803 | 1809 | static LLVMValueRef gen_block(CodeGen *g, AstNode *block_node, TypeTableEntry *implicit_return_type) { |
| 1804 | 1810 | assert(block_node->type == NodeTypeBlock); |
| 1805 | 1811 | |
| 1806 | /* TODO | |
| 1807 | BlockContext *block_context = block_node->data.block.block_context; | |
| 1808 | if (block_context->defer_list.length > 0) { | |
| 1809 | LLVMBasicBlockRef exit_scope_block = LLVMAppendBasicBlock(g->cur_fn->fn_value, "DeferExitScope"); | |
| 1810 | ||
| 1811 | for (int i = 0; i < block_context->defer_list.length; i += 1) { | |
| 1812 | AstNode *defer_node = block_context->defer_list.at(i); | |
| 1813 | defer_node->data.defer_expr.basic_block = LLVMAppendBasicBlock(g->cur_fn->fn_value, "DeferExpr"); | |
| 1814 | LLVMPositionBuilderAtEnd(g->builder, body_block); | |
| 1815 | } | |
| 1816 | ||
| 1817 | LLVMPositionBuilderAtEnd(g->builder, ?); | |
| 1818 | } | |
| 1819 | */ | |
| 1820 | ||
| 1821 | 1812 | LLVMValueRef return_value; |
| 1822 | 1813 | for (int i = 0; i < block_node->data.block.statements.length; i += 1) { |
| 1823 | 1814 | AstNode *statement_node = block_node->data.block.statements.at(i); |
| 1824 | 1815 | return_value = gen_expr(g, statement_node); |
| 1825 | 1816 | } |
| 1826 | 1817 | |
| 1827 | if (implicit_return_type && implicit_return_type->id != TypeTableEntryIdUnreachable) { | |
| 1818 | bool end_unreachable = implicit_return_type && implicit_return_type->id == TypeTableEntryIdUnreachable; | |
| 1819 | if (end_unreachable) { | |
| 1820 | return nullptr; | |
| 1821 | } | |
| 1822 | ||
| 1823 | BlockContext *block_context = block_node->data.block.nested_block; | |
| 1824 | while (block_context != block_node->data.block.child_block) { | |
| 1825 | if (block_context->node->type == NodeTypeDefer) { | |
| 1826 | gen_expr(g, block_context->node->data.defer.expr); | |
| 1827 | } | |
| 1828 | block_context = block_context->parent; | |
| 1829 | } | |
| 1830 | ||
| 1831 | if (implicit_return_type) { | |
| 1828 | 1832 | return gen_return(g, block_node, return_value); |
| 1829 | 1833 | } else { |
| 1830 | 1834 | return return_value; |
| ... | ... | @@ -2475,8 +2479,8 @@ static LLVMValueRef gen_expr(CodeGen *g, AstNode *node) { |
| 2475 | 2479 | return gen_unwrap_err_expr(g, node); |
| 2476 | 2480 | case NodeTypeReturnExpr: |
| 2477 | 2481 | return gen_return_expr(g, node); |
| 2478 | case NodeTypeDeferExpr: | |
| 2479 | return gen_defer_expr(g, node); | |
| 2482 | case NodeTypeDefer: | |
| 2483 | return gen_defer(g, node); | |
| 2480 | 2484 | case NodeTypeVariableDeclaration: |
| 2481 | 2485 | return gen_var_decl_expr(g, node); |
| 2482 | 2486 | case NodeTypePrefixOpExpr: |
src/parser.cpp+5-5| ... | ... | @@ -1651,7 +1651,7 @@ static AstNode *ast_parse_return_or_defer_expr(ParseContext *pc, int *token_inde |
| 1651 | 1651 | *token_index += 2; |
| 1652 | 1652 | } else if (next_token->id == TokenIdKeywordDefer) { |
| 1653 | 1653 | kind = ReturnKindError; |
| 1654 | node_type = NodeTypeDeferExpr; | |
| 1654 | node_type = NodeTypeDefer; | |
| 1655 | 1655 | *token_index += 2; |
| 1656 | 1656 | } else { |
| 1657 | 1657 | return nullptr; |
| ... | ... | @@ -1664,7 +1664,7 @@ static AstNode *ast_parse_return_or_defer_expr(ParseContext *pc, int *token_inde |
| 1664 | 1664 | *token_index += 2; |
| 1665 | 1665 | } else if (next_token->id == TokenIdKeywordDefer) { |
| 1666 | 1666 | kind = ReturnKindMaybe; |
| 1667 | node_type = NodeTypeDeferExpr; | |
| 1667 | node_type = NodeTypeDefer; | |
| 1668 | 1668 | *token_index += 2; |
| 1669 | 1669 | } else { |
| 1670 | 1670 | return nullptr; |
| ... | ... | @@ -1675,7 +1675,7 @@ static AstNode *ast_parse_return_or_defer_expr(ParseContext *pc, int *token_inde |
| 1675 | 1675 | *token_index += 1; |
| 1676 | 1676 | } else if (token->id == TokenIdKeywordDefer) { |
| 1677 | 1677 | kind = ReturnKindUnconditional; |
| 1678 | node_type = NodeTypeDeferExpr; | |
| 1678 | node_type = NodeTypeDefer; | |
| 1679 | 1679 | *token_index += 1; |
| 1680 | 1680 | } else { |
| 1681 | 1681 | return nullptr; |
| ... | ... | @@ -2703,8 +2703,8 @@ void normalize_parent_ptrs(AstNode *node) { |
| 2703 | 2703 | case NodeTypeReturnExpr: |
| 2704 | 2704 | set_field(&node->data.return_expr.expr); |
| 2705 | 2705 | break; |
| 2706 | case NodeTypeDeferExpr: | |
| 2707 | set_field(&node->data.defer_expr.expr); | |
| 2706 | case NodeTypeDefer: | |
| 2707 | set_field(&node->data.defer.expr); | |
| 2708 | 2708 | break; |
| 2709 | 2709 | case NodeTypeVariableDeclaration: |
| 2710 | 2710 | set_list_fields(node->data.variable_declaration.directives); |
test/run_tests.cpp+13| ... | ... | @@ -1519,6 +1519,19 @@ pub fn main(args: [][]u8) -> %void { |
| 1519 | 1519 | %%stdout.printf("OK\n"); |
| 1520 | 1520 | } |
| 1521 | 1521 | )SOURCE", "OK\n"); |
| 1522 | ||
| 1523 | ||
| 1524 | add_simple_case("defer with only fallthrough", R"SOURCE( | |
| 1525 | import "std.zig"; | |
| 1526 | pub fn main(args: [][]u8) -> %void { | |
| 1527 | %%stdout.printf("before\n"); | |
| 1528 | defer %%stdout.printf("defer1\n"); | |
| 1529 | defer %%stdout.printf("defer2\n"); | |
| 1530 | defer %%stdout.printf("defer3\n"); | |
| 1531 | %%stdout.printf("after\n"); | |
| 1532 | } | |
| 1533 | )SOURCE", "before\nafter\ndefer3\ndefer2\ndefer1\n"); | |
| 1534 | ||
| 1522 | 1535 | } |
| 1523 | 1536 | |
| 1524 | 1537 |