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