authorgravatar for thejoshwolfe@gmail.comJosh Wolfe <thejoshwolfe@gmail.com> 2017-04-12 22:18:56-07:00
committergravatar for thejoshwolfe@gmail.comJosh Wolfe <thejoshwolfe@gmail.com> 2017-04-12 23:22:32-07:00
log356424916ced599852e2c38265eebe7a1fc1637d
tree2bec2154f1e4bbb93b0f9d5e959aaf491240ccd0
parent919910312d7d25fe8f894adbc9ff8a449ac26281

block statement lists never get fake expressions

instead blocks have a field that encodes whether the last statement ended with a semicolon.

4 files changed, 64 insertions(+), 81 deletions(-)

src/all_types.hpp+1-3
...@@ -410,10 +410,8 @@ struct AstNodeParamDecl {...@@ -410,10 +410,8 @@ struct AstNodeParamDecl {
410};410};
411411
412struct AstNodeBlock {412struct AstNodeBlock {
413 // the final statement is the returned expression.
414 // if there are no statements, the returned expression is void.
415 // the final statement is never a label.
416 ZigList<AstNode *> statements;413 ZigList<AstNode *> statements;
414 bool last_statement_is_result_expression;
417};415};
418416
419enum ReturnKind {417enum ReturnKind {
src/ast_render.cpp+3-1
...@@ -464,8 +464,10 @@ static void render_node_extra(AstRender *ar, AstNode *node, bool grouped) {...@@ -464,8 +464,10 @@ static void render_node_extra(AstRender *ar, AstNode *node, bool grouped) {
464 }464 }
465 print_indent(ar);465 print_indent(ar);
466 render_node_grouped(ar, statement);466 render_node_grouped(ar, statement);
467 if (i != node->data.block.statements.length - 1)467 if (!(i == node->data.block.statements.length - 1 &&
468 node->data.block.last_statement_is_result_expression)) {
468 fprintf(ar->f, ";");469 fprintf(ar->f, ";");
470 }
469 fprintf(ar->f, "\n");471 fprintf(ar->f, "\n");
470 }472 }
471 ar->indent -= ar->indent_size;473 ar->indent -= ar->indent_size;
src/ir.cpp+10-3
...@@ -3378,6 +3378,7 @@ static IrInstruction *ir_gen_block(IrBuilder *irb, Scope *parent_scope, AstNode...@@ -3378,6 +3378,7 @@ static IrInstruction *ir_gen_block(IrBuilder *irb, Scope *parent_scope, AstNode
33783378
3379 // a label is an entry point3379 // a label is an entry point
3380 is_continuation_unreachable = false;3380 is_continuation_unreachable = false;
3381 return_value = nullptr;
3381 continue;3382 continue;
3382 }3383 }
33833384
...@@ -3406,7 +3407,8 @@ static IrInstruction *ir_gen_block(IrBuilder *irb, Scope *parent_scope, AstNode...@@ -3406,7 +3407,8 @@ static IrInstruction *ir_gen_block(IrBuilder *irb, Scope *parent_scope, AstNode
3406 child_scope = decl_var_instruction->var->child_scope;3407 child_scope = decl_var_instruction->var->child_scope;
3407 } else {3408 } else {
3408 // label, defer, variable declaration will never be the last statement3409 // label, defer, variable declaration will never be the last statement
3409 if (i == block_node->data.block.statements.length - 1) {3410 if (block_node->data.block.last_statement_is_result_expression &&
3411 i == block_node->data.block.statements.length - 1) {
3410 // this is the result value statement3412 // this is the result value statement
3411 return_value = statement_value;3413 return_value = statement_value;
3412 } else {3414 } else {
...@@ -3422,13 +3424,18 @@ static IrInstruction *ir_gen_block(IrBuilder *irb, Scope *parent_scope, AstNode...@@ -3422,13 +3424,18 @@ static IrInstruction *ir_gen_block(IrBuilder *irb, Scope *parent_scope, AstNode
3422 }3424 }
3423 }3425 }
34243426
3425 assert(return_value != nullptr);
3426
3427 if (!is_continuation_unreachable) {3427 if (!is_continuation_unreachable) {
3428 // control flow falls out of block3428 // control flow falls out of block
3429
3430 if (!block_node->data.block.last_statement_is_result_expression) {
3431 assert(return_value == nullptr);
3432 return_value = ir_mark_gen(ir_build_const_void(irb, child_scope, block_node));
3433 }
3434
3429 ir_gen_defers_for_block(irb, child_scope, outer_block_scope, false, false);3435 ir_gen_defers_for_block(irb, child_scope, outer_block_scope, false, false);
3430 }3436 }
34313437
3438 assert(return_value != nullptr);
3432 return return_value;3439 return return_value;
3433}3440}
34343441
src/parser.cpp+50-74
...@@ -1882,36 +1882,6 @@ static AstNode *ast_parse_switch_expr(ParseContext *pc, size_t *token_index, boo...@@ -1882,36 +1882,6 @@ static AstNode *ast_parse_switch_expr(ParseContext *pc, size_t *token_index, boo
1882 }1882 }
1883}1883}
18841884
1885static bool statement_has_block_body(AstNode *node) {
1886 switch (node->type) {
1887 case NodeTypeIfBoolExpr:
1888 if (node->data.if_bool_expr.else_node)
1889 return statement_has_block_body(node->data.if_bool_expr.else_node);
1890 return node->data.if_bool_expr.then_block->type == NodeTypeBlock;
1891 case NodeTypeIfVarExpr:
1892 if (node->data.if_var_expr.else_node)
1893 return statement_has_block_body(node->data.if_var_expr.else_node);
1894 return node->data.if_var_expr.then_block->type == NodeTypeBlock;
1895 case NodeTypeTryExpr:
1896 if (node->data.try_expr.else_node)
1897 return statement_has_block_body(node->data.try_expr.else_node);
1898 return node->data.try_expr.then_node->type == NodeTypeBlock;
1899 case NodeTypeWhileExpr:
1900 return node->data.while_expr.body->type == NodeTypeBlock;
1901 case NodeTypeForExpr:
1902 return node->data.for_expr.body->type == NodeTypeBlock;
1903 case NodeTypeSwitchExpr:
1904 case NodeTypeBlock:
1905 return true;
1906 case NodeTypeCompTime:
1907 return node->data.comptime_expr.expr->type == NodeTypeBlock;
1908 case NodeTypeDefer:
1909 return node->data.defer.expr->type == NodeTypeBlock;
1910 default:
1911 return false;
1912 }
1913}
1914
1915/*1885/*
1916BlockExpression(body) = Block | IfExpression(body) | TryExpression(body) | WhileExpression(body) | ForExpression(body) | SwitchExpression | CompTimeExpression(body)1886BlockExpression(body) = Block | IfExpression(body) | TryExpression(body) | WhileExpression(body) | ForExpression(body) | SwitchExpression | CompTimeExpression(body)
1917*/1887*/
...@@ -2124,9 +2094,35 @@ static AstNode *ast_parse_label(ParseContext *pc, size_t *token_index, bool mand...@@ -2124,9 +2094,35 @@ static AstNode *ast_parse_label(ParseContext *pc, size_t *token_index, bool mand
2124 return node;2094 return node;
2125}2095}
21262096
2127static AstNode *ast_create_void_expr(ParseContext *pc, Token *token) {2097static bool statement_terminates_without_semicolon(AstNode *node) {
2128 AstNode *node = ast_create_node(pc, NodeTypeBlock, token);2098 switch (node->type) {
2129 return node;2099 case NodeTypeIfBoolExpr:
2100 if (node->data.if_bool_expr.else_node)
2101 return statement_terminates_without_semicolon(node->data.if_bool_expr.else_node);
2102 return node->data.if_bool_expr.then_block->type == NodeTypeBlock;
2103 case NodeTypeIfVarExpr:
2104 if (node->data.if_var_expr.else_node)
2105 return statement_terminates_without_semicolon(node->data.if_var_expr.else_node);
2106 return node->data.if_var_expr.then_block->type == NodeTypeBlock;
2107 case NodeTypeTryExpr:
2108 if (node->data.try_expr.else_node)
2109 return statement_terminates_without_semicolon(node->data.try_expr.else_node);
2110 return node->data.try_expr.then_node->type == NodeTypeBlock;
2111 case NodeTypeWhileExpr:
2112 return node->data.while_expr.body->type == NodeTypeBlock;
2113 case NodeTypeForExpr:
2114 return node->data.for_expr.body->type == NodeTypeBlock;
2115 case NodeTypeCompTime:
2116 return node->data.comptime_expr.expr->type == NodeTypeBlock;
2117 case NodeTypeDefer:
2118 return node->data.defer.expr->type == NodeTypeBlock;
2119 case NodeTypeSwitchExpr:
2120 case NodeTypeBlock:
2121 case NodeTypeLabel:
2122 return true;
2123 default:
2124 return false;
2125 }
2130}2126}
21312127
2132/*2128/*
...@@ -2149,56 +2145,36 @@ static AstNode *ast_parse_block(ParseContext *pc, size_t *token_index, bool mand...@@ -2149,56 +2145,36 @@ static AstNode *ast_parse_block(ParseContext *pc, size_t *token_index, bool mand
21492145
2150 for (;;) {2146 for (;;) {
2151 AstNode *statement_node = ast_parse_label(pc, token_index, false);2147 AstNode *statement_node = ast_parse_label(pc, token_index, false);
2152 bool need_implicit_final_void_statement = false;2148 if (!statement_node)
2149 statement_node = ast_parse_variable_declaration_expr(pc, token_index, false, VisibModPrivate);
2150 if (!statement_node)
2151 statement_node = ast_parse_defer_expr(pc, token_index);
2152 if (!statement_node)
2153 statement_node = ast_parse_block_expr(pc, token_index, false);
2154 if (!statement_node)
2155 statement_node = ast_parse_expression(pc, token_index, false);
2156
2153 bool semicolon_expected = true;2157 bool semicolon_expected = true;
2154 if (statement_node) {2158 if (statement_node) {
2155 // label2159 node->data.block.statements.append(statement_node);
2156 semicolon_expected = false;2160 if (statement_terminates_without_semicolon(statement_node)) {
2157 // if a label is the last thing in a block, add a void statement.2161 semicolon_expected = false;
2158 need_implicit_final_void_statement = true;2162 } else {
2159 } else {2163 if (statement_node->type == NodeTypeDefer) {
2160 statement_node = ast_parse_variable_declaration_expr(pc, token_index, false, VisibModPrivate);2164 // defer without a block body requires a semicolon
2161 if (!statement_node) {2165 Token *token = &pc->tokens->at(*token_index);
2162 statement_node = ast_parse_defer_expr(pc, token_index);2166 ast_expect_token(pc, token, TokenIdSemicolon);
2163 if (statement_node) {
2164 // defer
2165 if (statement_has_block_body(statement_node)) {
2166 // don't let defer be the last statement in a block
2167 need_implicit_final_void_statement = true;
2168 semicolon_expected = false;
2169 } else {
2170 // defer without a block body requires a semicolon
2171 Token *token = &pc->tokens->at(*token_index);
2172 ast_expect_token(pc, token, TokenIdSemicolon);
2173 }
2174 } else {
2175 statement_node = ast_parse_block_expr(pc, token_index, false);
2176 if (statement_node) {
2177 // block expr
2178 if (statement_has_block_body(statement_node))
2179 semicolon_expected = false;
2180 } else {
2181 statement_node = ast_parse_expression(pc, token_index, false);
2182 if (!statement_node) {
2183 // no statement.
2184 // final semicolon means add a void statement.
2185 need_implicit_final_void_statement = true;
2186 }
2187 }
2188 }2167 }
2189 }2168 }
2190 }2169 }
2191 if (statement_node)2170
2192 node->data.block.statements.append(statement_node);2171 node->data.block.last_statement_is_result_expression = statement_node && !(
2172 statement_node->type == NodeTypeLabel ||
2173 statement_node->type == NodeTypeDefer);
21932174
2194 last_token = &pc->tokens->at(*token_index);2175 last_token = &pc->tokens->at(*token_index);
2195 if (last_token->id == TokenIdRBrace) {2176 if (last_token->id == TokenIdRBrace) {
2196 *token_index += 1;2177 *token_index += 1;
2197
2198 if (node->data.block.statements.length > 0 && need_implicit_final_void_statement) {
2199 node->data.block.statements.append(ast_create_void_expr(pc, last_token));
2200 }
2201
2202 return node;2178 return node;
2203 } else if (!semicolon_expected) {2179 } else if (!semicolon_expected) {
2204 continue;2180 continue;