authorgravatar for andrew@ziglang.orgAndrew Kelley <andrew@ziglang.org> 2016-02-06 00:56:01-07:00
committergravatar for andrew@ziglang.orgAndrew Kelley <andrew@ziglang.org> 2016-02-06 01:00:29-07:00
logec33e5a638b816ab0ba1e4dd3f9433dbb71d7e53
tree72e6b01315b7902290ae6747ea39499fe0818890
parent6a2ede5a6eb17d6b86e6636457710a3583376fa3

simple unconditional defer support

See #110

8 files changed, 103 insertions(+), 75 deletions(-)

doc/langref.md+3-3
......@@ -43,7 +43,7 @@ ParamDecl = option("noalias") option("Symbol" ":") TypeExpr | "..."
4343
4444Block = "{" list(option(Statement), ";") "}"
4545
46Statement = Label | VariableDeclaration ";" | NonBlockExpression ";" | BlockExpression
46Statement = Label | VariableDeclaration ";" | Defer ";" | NonBlockExpression ";" | BlockExpression
4747
4848Label = "Symbol" ":"
4949
......@@ -51,7 +51,7 @@ Expression = BlockExpression | NonBlockExpression
5151
5252TypeExpr = PrefixOpExpression
5353
54NonBlockExpression = ReturnExpression | AssignmentExpression | DeferExpression
54NonBlockExpression = ReturnExpression | AssignmentExpression
5555
5656AsmExpression = "asm" option("volatile") "(" "String" option(AsmOutput) ")"
5757
......@@ -91,7 +91,7 @@ BoolOrExpression = BoolAndExpression "||" BoolOrExpression | BoolAndExpression
9191
9292ReturnExpression = option("%" | "?") "return" option(Expression)
9393
94DeferExpression = option("%" | "?") "defer" option(Expression)
94Defer = option("%" | "?") "defer" option(Expression)
9595
9696IfExpression = IfVarExpression | IfBoolExpression
9797
example/cat/main.zig-1
......@@ -4,7 +4,6 @@ import "std.zig";
44
55// Things to do to make this work:
66// * var args printing
7// * defer
87// * cast err type to string
98// * string equality
109
src/all_types.hpp+14-6
......@@ -117,7 +117,7 @@ enum NodeType {
117117 NodeTypeBlock,
118118 NodeTypeDirective,
119119 NodeTypeReturnExpr,
120 NodeTypeDeferExpr,
120 NodeTypeDefer,
121121 NodeTypeVariableDeclaration,
122122 NodeTypeTypeDecl,
123123 NodeTypeErrorValueDecl,
......@@ -216,7 +216,12 @@ struct AstNodeBlock {
216216 ZigList<AstNode *> statements;
217217
218218 // 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;
220225 Expr resolved_expr;
221226};
222227
......@@ -235,7 +240,7 @@ struct AstNodeReturnExpr {
235240 Expr resolved_expr;
236241};
237242
238struct AstNodeDeferExpr {
243struct AstNodeDefer {
239244 ReturnKind kind;
240245 AstNode *expr;
241246
......@@ -243,6 +248,7 @@ struct AstNodeDeferExpr {
243248 Expr resolved_expr;
244249 int index_in_block;
245250 LLVMBasicBlockRef basic_block;
251 BlockContext *child_block;
246252};
247253
248254struct AstNodeVariableDeclaration {
......@@ -739,7 +745,7 @@ struct AstNode {
739745 AstNodeParamDecl param_decl;
740746 AstNodeBlock block;
741747 AstNodeReturnExpr return_expr;
742 AstNodeDeferExpr defer_expr;
748 AstNodeDefer defer;
743749 AstNodeVariableDeclaration variable_declaration;
744750 AstNodeTypeDecl type_decl;
745751 AstNodeErrorValueDecl error_value_decl;
......@@ -1157,10 +1163,12 @@ enum BlockExitPath {
11571163 BlockExitPathFallthrough,
11581164 BlockExitPathReturn,
11591165 BlockExitPathGoto,
1166
1167 BlockExitPathCount,
11601168};
11611169
11621170struct BlockContext {
1163 // One of: NodeTypeFnDef, NodeTypeBlock, NodeTypeRoot, NodeTypeDeferExpr, NodeTypeVariableDeclaration
1171 // One of: NodeTypeFnDef, NodeTypeBlock, NodeTypeRoot, NodeTypeDefer, NodeTypeVariableDeclaration
11641172 AstNode *node;
11651173
11661174 // any variables that are introduced by this scope
......@@ -1178,7 +1186,7 @@ struct BlockContext {
11781186
11791187 LLVMZigDIScope *di_scope;
11801188 Buf *c_import_buf;
1181 bool block_exit_paths[3]; // one for each BlockExitPath
1189 bool block_exit_paths[BlockExitPathCount];
11821190};
11831191
11841192enum CIntType {
src/analyze.cpp+35-31
......@@ -57,7 +57,7 @@ static AstNode *first_executing_node(AstNode *node) {
5757 case NodeTypeBlock:
5858 case NodeTypeDirective:
5959 case NodeTypeReturnExpr:
60 case NodeTypeDeferExpr:
60 case NodeTypeDefer:
6161 case NodeTypeVariableDeclaration:
6262 case NodeTypeTypeDecl:
6363 case NodeTypeErrorValueDecl:
......@@ -1456,7 +1456,7 @@ static void resolve_top_level_decl(CodeGen *g, ImportTableEntry *import, AstNode
14561456 case NodeTypeParamDecl:
14571457 case NodeTypeFnDecl:
14581458 case NodeTypeReturnExpr:
1459 case NodeTypeDeferExpr:
1459 case NodeTypeDefer:
14601460 case NodeTypeRoot:
14611461 case NodeTypeBlock:
14621462 case NodeTypeBinOpExpr:
......@@ -4590,56 +4590,54 @@ static void validate_voided_expr(CodeGen *g, AstNode *source_node, TypeTableEntr
45904590 }
45914591}
45924592
4593static TypeTableEntry *analyze_defer_expr(CodeGen *g, ImportTableEntry *import, BlockContext *context,
4593static TypeTableEntry *analyze_defer(CodeGen *g, ImportTableEntry *import, BlockContext *parent_context,
45944594 TypeTableEntry *expected_type, AstNode *node)
45954595{
4596 if (!context->fn_entry) {
4596 if (!parent_context->fn_entry) {
45974597 add_node_error(g, node, buf_sprintf("defer expression outside function definition"));
45984598 return g->builtin_types.entry_invalid;
45994599 }
46004600
4601 if (!node->data.defer_expr.expr) {
4601 if (!node->data.defer.expr) {
46024602 add_node_error(g, node, buf_sprintf("defer expects an expression"));
46034603 return g->builtin_types.entry_void;
46044604 }
46054605
4606 node->data.defer.child_block = new_block_context(node, parent_context);
46064607
4607 switch (node->data.defer_expr.kind) {
4608 switch (node->data.defer.kind) {
46084609 case ReturnKindUnconditional:
46094610 {
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);
46144614
4615 //node->data.defer_expr.index_in_block = context->defer_list.length;
4616 //context->defer_list.append(node);
46174615 return g->builtin_types.entry_void;
46184616 }
46194617 case ReturnKindError:
46204618 {
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);
46234621 if (resolved_type->id == TypeTableEntryIdInvalid) {
46244622 // OK
46254623 } else if (resolved_type->id == TypeTableEntryIdErrorUnion) {
46264624 // OK
46274625 } else {
4628 add_node_error(g, node->data.defer_expr.expr,
4626 add_node_error(g, node->data.defer.expr,
46294627 buf_sprintf("expected error type, got '%s'", buf_ptr(&resolved_type->name)));
46304628 }
46314629 return g->builtin_types.entry_void;
46324630 }
46334631 case ReturnKindMaybe:
46344632 {
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);
46374635 if (resolved_type->id == TypeTableEntryIdInvalid) {
46384636 // OK
46394637 } else if (resolved_type->id == TypeTableEntryIdMaybe) {
46404638 // OK
46414639 } else {
4642 add_node_error(g, node->data.defer_expr.expr,
4640 add_node_error(g, node->data.defer.expr,
46434641 buf_sprintf("expected maybe type, got '%s'", buf_ptr(&resolved_type->name)));
46444642 }
46454643 return g->builtin_types.entry_void;
......@@ -4657,11 +4655,11 @@ static TypeTableEntry *analyze_string_literal_expr(CodeGen *g, ImportTableEntry
46574655 }
46584656}
46594657
4660static TypeTableEntry *analyze_block_expr(CodeGen *g, ImportTableEntry *import, BlockContext *context,
4658static TypeTableEntry *analyze_block_expr(CodeGen *g, ImportTableEntry *import, BlockContext *parent_context,
46614659 TypeTableEntry *expected_type, AstNode *node)
46624660{
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;
46654663 TypeTableEntry *return_type = g->builtin_types.entry_void;
46664664
46674665 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,
46764674 if (is_node_void_expr(child)) {
46774675 // {unreachable;void;void} is allowed.
46784676 // 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);
46804678 continue;
46814679 }
46824680 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,
46854683 bool is_last = (i == node->data.block.statements.length - 1);
46864684 TypeTableEntry *passed_expected_type = is_last ? expected_type : nullptr;
46874685 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 }
46884691 if (!is_last) {
46894692 validate_voided_expr(g, child, return_type);
46904693 }
46914694 }
4695 node->data.block.nested_block = child_context;
46924696 return return_type;
46934697}
46944698
......@@ -4750,8 +4754,8 @@ static TypeTableEntry *analyze_expression(CodeGen *g, ImportTableEntry *import,
47504754 case NodeTypeReturnExpr:
47514755 return_type = analyze_return_expr(g, import, context, expected_type, node);
47524756 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);
47554759 break;
47564760 case NodeTypeVariableDeclaration:
47574761 analyze_variable_declaration(g, import, context, expected_type, node);
......@@ -4956,7 +4960,7 @@ static void analyze_top_level_decl(CodeGen *g, ImportTableEntry *import, AstNode
49564960 case NodeTypeParamDecl:
49574961 case NodeTypeFnDecl:
49584962 case NodeTypeReturnExpr:
4959 case NodeTypeDeferExpr:
4963 case NodeTypeDefer:
49604964 case NodeTypeRoot:
49614965 case NodeTypeBlock:
49624966 case NodeTypeBinOpExpr:
......@@ -5039,8 +5043,8 @@ static void collect_expr_decl_deps(CodeGen *g, ImportTableEntry *import, AstNode
50395043 case NodeTypeReturnExpr:
50405044 collect_expr_decl_deps(g, import, node->data.return_expr.expr, decl_node);
50415045 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);
50445048 break;
50455049 case NodeTypePrefixOpExpr:
50465050 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
53615365 case NodeTypeParamDecl:
53625366 case NodeTypeFnDecl:
53635367 case NodeTypeReturnExpr:
5364 case NodeTypeDeferExpr:
5368 case NodeTypeDefer:
53655369 case NodeTypeBlock:
53665370 case NodeTypeBinOpExpr:
53675371 case NodeTypeUnwrapErrorExpr:
......@@ -5552,8 +5556,8 @@ Expr *get_resolved_expr(AstNode *node) {
55525556 switch (node->type) {
55535557 case NodeTypeReturnExpr:
55545558 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;
55575561 case NodeTypeBinOpExpr:
55585562 return &node->data.bin_op_expr.resolved_expr;
55595563 case NodeTypeUnwrapErrorExpr:
......@@ -5652,7 +5656,7 @@ TopLevelDecl *get_resolved_top_level_decl(AstNode *node) {
56525656 return &node->data.type_decl.top_level_decl;
56535657 case NodeTypeNumberLiteral:
56545658 case NodeTypeReturnExpr:
5655 case NodeTypeDeferExpr:
5659 case NodeTypeDefer:
56565660 case NodeTypeBinOpExpr:
56575661 case NodeTypeUnwrapErrorExpr:
56585662 case NodeTypePrefixOpExpr:
src/ast_render.cpp+7-7
......@@ -122,8 +122,8 @@ static const char *node_type_str(NodeType node_type) {
122122 return "Directive";
123123 case NodeTypeReturnExpr:
124124 return "ReturnExpr";
125 case NodeTypeDeferExpr:
126 return "DeferExpr";
125 case NodeTypeDefer:
126 return "Defer";
127127 case NodeTypeVariableDeclaration:
128128 return "VariableDeclaration";
129129 case NodeTypeTypeDecl:
......@@ -261,12 +261,12 @@ void ast_print(FILE *f, AstNode *node, int indent) {
261261 ast_print(f, node->data.return_expr.expr, indent + 2);
262262 break;
263263 }
264 case NodeTypeDeferExpr:
264 case NodeTypeDefer:
265265 {
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);
267267 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);
270270 break;
271271 }
272272 case NodeTypeVariableDeclaration:
......@@ -630,7 +630,7 @@ static void render_node(AstRender *ar, AstNode *node) {
630630 break;
631631 case NodeTypeReturnExpr:
632632 zig_panic("TODO");
633 case NodeTypeDeferExpr:
633 case NodeTypeDefer:
634634 zig_panic("TODO");
635635 case NodeTypeVariableDeclaration:
636636 {
src/codegen.cpp+26-22
......@@ -1669,11 +1669,9 @@ static LLVMValueRef gen_return_expr(CodeGen *g, AstNode *node) {
16691669 }
16701670}
16711671
1672static LLVMValueRef gen_defer_expr(CodeGen *g, AstNode *node) {
1673 assert(node->type == NodeTypeDeferExpr);
1672static LLVMValueRef gen_defer(CodeGen *g, AstNode *node) {
1673 assert(node->type == NodeTypeDefer);
16741674
1675 zig_panic("TODO");
1676 //node->block_context->cur_defer_index = node->data.defer_expr.index_in_block;
16771675
16781676 return nullptr;
16791677}
......@@ -1800,31 +1798,37 @@ static LLVMValueRef gen_if_var_expr(CodeGen *g, AstNode *node) {
18001798 return return_value;
18011799}
18021800
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
18031809static LLVMValueRef gen_block(CodeGen *g, AstNode *block_node, TypeTableEntry *implicit_return_type) {
18041810 assert(block_node->type == NodeTypeBlock);
18051811
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
18211812 LLVMValueRef return_value;
18221813 for (int i = 0; i < block_node->data.block.statements.length; i += 1) {
18231814 AstNode *statement_node = block_node->data.block.statements.at(i);
18241815 return_value = gen_expr(g, statement_node);
18251816 }
18261817
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) {
18281832 return gen_return(g, block_node, return_value);
18291833 } else {
18301834 return return_value;
......@@ -2475,8 +2479,8 @@ static LLVMValueRef gen_expr(CodeGen *g, AstNode *node) {
24752479 return gen_unwrap_err_expr(g, node);
24762480 case NodeTypeReturnExpr:
24772481 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);
24802484 case NodeTypeVariableDeclaration:
24812485 return gen_var_decl_expr(g, node);
24822486 case NodeTypePrefixOpExpr:
src/parser.cpp+5-5
......@@ -1651,7 +1651,7 @@ static AstNode *ast_parse_return_or_defer_expr(ParseContext *pc, int *token_inde
16511651 *token_index += 2;
16521652 } else if (next_token->id == TokenIdKeywordDefer) {
16531653 kind = ReturnKindError;
1654 node_type = NodeTypeDeferExpr;
1654 node_type = NodeTypeDefer;
16551655 *token_index += 2;
16561656 } else {
16571657 return nullptr;
......@@ -1664,7 +1664,7 @@ static AstNode *ast_parse_return_or_defer_expr(ParseContext *pc, int *token_inde
16641664 *token_index += 2;
16651665 } else if (next_token->id == TokenIdKeywordDefer) {
16661666 kind = ReturnKindMaybe;
1667 node_type = NodeTypeDeferExpr;
1667 node_type = NodeTypeDefer;
16681668 *token_index += 2;
16691669 } else {
16701670 return nullptr;
......@@ -1675,7 +1675,7 @@ static AstNode *ast_parse_return_or_defer_expr(ParseContext *pc, int *token_inde
16751675 *token_index += 1;
16761676 } else if (token->id == TokenIdKeywordDefer) {
16771677 kind = ReturnKindUnconditional;
1678 node_type = NodeTypeDeferExpr;
1678 node_type = NodeTypeDefer;
16791679 *token_index += 1;
16801680 } else {
16811681 return nullptr;
......@@ -2703,8 +2703,8 @@ void normalize_parent_ptrs(AstNode *node) {
27032703 case NodeTypeReturnExpr:
27042704 set_field(&node->data.return_expr.expr);
27052705 break;
2706 case NodeTypeDeferExpr:
2707 set_field(&node->data.defer_expr.expr);
2706 case NodeTypeDefer:
2707 set_field(&node->data.defer.expr);
27082708 break;
27092709 case NodeTypeVariableDeclaration:
27102710 set_list_fields(node->data.variable_declaration.directives);
test/run_tests.cpp+13
......@@ -1519,6 +1519,19 @@ pub fn main(args: [][]u8) -> %void {
15191519 %%stdout.printf("OK\n");
15201520}
15211521 )SOURCE", "OK\n");
1522
1523
1524 add_simple_case("defer with only fallthrough", R"SOURCE(
1525import "std.zig";
1526pub 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
15221535}
15231536
15241537