authorgravatar for thejoshwolfe@gmail.comJosh Wolfe <thejoshwolfe@gmail.com> 2017-04-02 11:50:34-07:00
committergravatar for thejoshwolfe@gmail.comJosh Wolfe <thejoshwolfe@gmail.com> 2017-04-02 11:50:34-07:00
log4b9e782d37a334740a04190e3b3dd375f41ef3fe
treebc554e18c98fb4c1376dd409f4457e7361bceabc
parent9968879261a8628600bfde4e438e8f8c0d2fa811

fix confusion in block expression parsing

closes #292 * if, try, while, for, comptime, defer are "greedy" with {} blocks, meaning if their bodies are blocks, then no suffix operator is allowed after the block. The {} block gets "built into" the containing statement, like the body of a switch statement. * the Expression syntactic element is no longer "greedy" with {} blocks, meaning it's possible to have suffix operators after {} blocks without needing the {} block to be an rhs operand first.

2 files changed, 99 insertions(+), 84 deletions(-)

doc/langref.md+3-1
...@@ -45,6 +45,8 @@ Label = Symbol ":"...@@ -45,6 +45,8 @@ Label = Symbol ":"
4545
46TypeExpr = PrefixOpExpression | "var"46TypeExpr = PrefixOpExpression | "var"
4747
48BlockOrExpression = Block | Expression
49
48Expression = ReturnExpression | AssignmentExpression50Expression = ReturnExpression | AssignmentExpression
4951
50AsmExpression = "asm" option("volatile") "(" String option(AsmOutput) ")"52AsmExpression = "asm" option("volatile") "(" String option(AsmOutput) ")"
...@@ -143,7 +145,7 @@ StructLiteralField = "." Symbol "=" Expression...@@ -143,7 +145,7 @@ StructLiteralField = "." Symbol "=" Expression
143145
144PrefixOp = "!" | "-" | "~" | "*" | ("&" option("const") option("volatile")) | "?" | "%" | "%%" | "??" | "-%"146PrefixOp = "!" | "-" | "~" | "*" | ("&" option("const") option("volatile")) | "?" | "%" | "%%" | "??" | "-%"
145147
146PrimaryExpression = Number | String | CharLiteral | KeywordLiteral | GroupedExpression | GotoExpression | BlockExpression(Expression) | Symbol | ("@" Symbol FnCallExpression) | ArrayType | (option("extern") FnProto) | AsmExpression | ("error" "." Symbol) | ContainerDecl148PrimaryExpression = Number | String | CharLiteral | KeywordLiteral | GroupedExpression | GotoExpression | BlockExpression(BlockOrExpression) | Symbol | ("@" Symbol FnCallExpression) | ArrayType | (option("extern") FnProto) | AsmExpression | ("error" "." Symbol) | ContainerDecl
147149
148ArrayType = "[" option(Expression) "]" option("const") TypeExpr150ArrayType = "[" option(Expression) "]" option("const") TypeExpr
149151
src/parser.cpp+96-83
...@@ -211,6 +211,7 @@ static void ast_invalid_token_error(ParseContext *pc, Token *token) {...@@ -211,6 +211,7 @@ static void ast_invalid_token_error(ParseContext *pc, Token *token) {
211 ast_error(pc, token, "invalid token: '%s'", buf_ptr(&token_value));211 ast_error(pc, token, "invalid token: '%s'", buf_ptr(&token_value));
212}212}
213213
214static AstNode *ast_parse_block_or_expression(ParseContext *pc, size_t *token_index, bool mandatory);
214static AstNode *ast_parse_expression(ParseContext *pc, size_t *token_index, bool mandatory);215static AstNode *ast_parse_expression(ParseContext *pc, size_t *token_index, bool mandatory);
215static AstNode *ast_parse_block(ParseContext *pc, size_t *token_index, bool mandatory);216static AstNode *ast_parse_block(ParseContext *pc, size_t *token_index, bool mandatory);
216static AstNode *ast_parse_if_expr(ParseContext *pc, size_t *token_index, bool mandatory);217static AstNode *ast_parse_if_expr(ParseContext *pc, size_t *token_index, bool mandatory);
...@@ -632,12 +633,12 @@ static AstNode *ast_parse_comptime_expr(ParseContext *pc, size_t *token_index, b...@@ -632,12 +633,12 @@ static AstNode *ast_parse_comptime_expr(ParseContext *pc, size_t *token_index, b
632 if (require_block_body)633 if (require_block_body)
633 node->data.comptime_expr.expr = ast_parse_block(pc, token_index, true);634 node->data.comptime_expr.expr = ast_parse_block(pc, token_index, true);
634 else635 else
635 node->data.comptime_expr.expr = ast_parse_expression(pc, token_index, true);636 node->data.comptime_expr.expr = ast_parse_block_or_expression(pc, token_index, true);
636 return node;637 return node;
637}638}
638639
639/*640/*
640TryExpression = "try" "(" option(("const" | "var") option("*") Symbol "=") Expression ")" Expression option("else" option("|" Symbol "|") Expression)641TryExpression(body) = "try" "(" option(("const" | "var") option("*") Symbol "=") Expression ")" body option("else" option("|" Symbol "|") body)
641*/642*/
642static AstNode *ast_parse_try_expr(ParseContext *pc, size_t *token_index, bool mandatory) {643static AstNode *ast_parse_try_expr(ParseContext *pc, size_t *token_index, bool mandatory) {
643 Token *try_token = &pc->tokens->at(*token_index);644 Token *try_token = &pc->tokens->at(*token_index);
...@@ -685,29 +686,29 @@ static AstNode *ast_parse_try_expr(ParseContext *pc, size_t *token_index, bool m...@@ -685,29 +686,29 @@ static AstNode *ast_parse_try_expr(ParseContext *pc, size_t *token_index, bool m
685686
686 ast_eat_token(pc, token_index, TokenIdRParen);687 ast_eat_token(pc, token_index, TokenIdRParen);
687688
688 node->data.try_expr.then_node = ast_parse_expression(pc, token_index, true);689 node->data.try_expr.then_node = ast_parse_block_or_expression(pc, token_index, true);
689690
690 Token *else_token = &pc->tokens->at(*token_index);691 Token *else_token = &pc->tokens->at(*token_index);
691 if (else_token->id != TokenIdKeywordElse)692 if (else_token->id == TokenIdKeywordElse) {
692 return node;
693
694 *token_index += 1;
695 Token *open_bar_tok = &pc->tokens->at(*token_index);
696 if (open_bar_tok->id == TokenIdBinOr) {
697 *token_index += 1;693 *token_index += 1;
694 Token *open_bar_tok = &pc->tokens->at(*token_index);
695 if (open_bar_tok->id == TokenIdBinOr) {
696 *token_index += 1;
698697
699 Token *err_name_tok = ast_eat_token(pc, token_index, TokenIdSymbol);698 Token *err_name_tok = ast_eat_token(pc, token_index, TokenIdSymbol);
700 node->data.try_expr.err_symbol = token_buf(err_name_tok);699 node->data.try_expr.err_symbol = token_buf(err_name_tok);
701700
702 ast_eat_token(pc, token_index, TokenIdBinOr);701 ast_eat_token(pc, token_index, TokenIdBinOr);
702 }
703
704 node->data.try_expr.else_node = ast_parse_block_or_expression(pc, token_index, true);
703 }705 }
704706
705 node->data.try_expr.else_node = ast_parse_expression(pc, token_index, true);
706 return node;707 return node;
707}708}
708709
709/*710/*
710PrimaryExpression = Number | String | CharLiteral | KeywordLiteral | GroupedExpression | GotoExpression | BlockExpression | Symbol | ("@" Symbol FnCallExpression) | ArrayType | (option("extern") FnProto) | AsmExpression | ("error" "." Symbol) | ContainerDecl711PrimaryExpression = Number | String | CharLiteral | KeywordLiteral | GroupedExpression | GotoExpression | BlockExpression(BlockOrExpression) | Symbol | ("@" Symbol FnCallExpression) | ArrayType | (option("extern") FnProto) | AsmExpression | ("error" "." Symbol) | ContainerDecl
711KeywordLiteral = "true" | "false" | "null" | "break" | "continue" | "undefined" | "error" | "type" | "this" | "unreachable"712KeywordLiteral = "true" | "false" | "null" | "break" | "continue" | "undefined" | "error" | "type" | "this" | "unreachable"
712*/713*/
713static AstNode *ast_parse_primary_expr(ParseContext *pc, size_t *token_index, bool mandatory) {714static AstNode *ast_parse_primary_expr(ParseContext *pc, size_t *token_index, bool mandatory) {
...@@ -1381,27 +1382,9 @@ static AstNode *ast_parse_bool_and_expr(ParseContext *pc, size_t *token_index, b...@@ -1381,27 +1382,9 @@ static AstNode *ast_parse_bool_and_expr(ParseContext *pc, size_t *token_index, b
1381}1382}
13821383
1383/*1384/*
1384Else : token(Else) Expression1385IfExpression(body) = IfVarExpression(body) | IfBoolExpression(body)
1385*/1386IfBoolExpression(body) = "if" "(" Expression ")" body option("else" body)
1386static AstNode *ast_parse_else(ParseContext *pc, size_t *token_index, bool mandatory) {1387IfVarExpression(body) = "if" "(" ("const" | "var") option("*") Symbol option(":" TypeExpr) "?=" Expression ")" body Option("else" body)
1387 Token *else_token = &pc->tokens->at(*token_index);
1388
1389 if (else_token->id != TokenIdKeywordElse) {
1390 if (mandatory) {
1391 ast_expect_token(pc, else_token, TokenIdKeywordElse);
1392 } else {
1393 return nullptr;
1394 }
1395 }
1396 *token_index += 1;
1397
1398 return ast_parse_expression(pc, token_index, true);
1399}
1400
1401/*
1402IfExpression : IfVarExpression | IfBoolExpression
1403IfBoolExpression = "if" "(" Expression ")" Expression option(Else)
1404IfVarExpression = "if" "(" ("const" | "var") option("*") Symbol option(":" TypeExpr) "?=" Expression ")" Expression Option(Else)
1405*/1388*/
1406static AstNode *ast_parse_if_expr(ParseContext *pc, size_t *token_index, bool mandatory) {1389static AstNode *ast_parse_if_expr(ParseContext *pc, size_t *token_index, bool mandatory) {
1407 Token *if_token = &pc->tokens->at(*token_index);1390 Token *if_token = &pc->tokens->at(*token_index);
...@@ -1451,16 +1434,26 @@ static AstNode *ast_parse_if_expr(ParseContext *pc, size_t *token_index, bool ma...@@ -1451,16 +1434,26 @@ static AstNode *ast_parse_if_expr(ParseContext *pc, size_t *token_index, bool ma
1451 ast_invalid_token_error(pc, eq_or_colon);1434 ast_invalid_token_error(pc, eq_or_colon);
1452 }1435 }
1453 ast_eat_token(pc, token_index, TokenIdRParen);1436 ast_eat_token(pc, token_index, TokenIdRParen);
1454 node->data.if_var_expr.then_block = ast_parse_expression(pc, token_index, true);1437 node->data.if_var_expr.then_block = ast_parse_block_or_expression(pc, token_index, true);
1455 node->data.if_var_expr.else_node = ast_parse_else(pc, token_index, false);1438
1439 Token *else_token = &pc->tokens->at(*token_index);
1440 if (else_token->id == TokenIdKeywordElse) {
1441 *token_index += 1;
1442 node->data.if_var_expr.else_node = ast_parse_block_or_expression(pc, token_index, true);
1443 }
14561444
1457 return node;1445 return node;
1458 } else {1446 } else {
1459 AstNode *node = ast_create_node(pc, NodeTypeIfBoolExpr, if_token);1447 AstNode *node = ast_create_node(pc, NodeTypeIfBoolExpr, if_token);
1460 node->data.if_bool_expr.condition = ast_parse_expression(pc, token_index, true);1448 node->data.if_bool_expr.condition = ast_parse_expression(pc, token_index, true);
1461 ast_eat_token(pc, token_index, TokenIdRParen);1449 ast_eat_token(pc, token_index, TokenIdRParen);
1462 node->data.if_bool_expr.then_block = ast_parse_expression(pc, token_index, true);1450 node->data.if_bool_expr.then_block = ast_parse_block_or_expression(pc, token_index, true);
1463 node->data.if_bool_expr.else_node = ast_parse_else(pc, token_index, false);1451
1452 Token *else_token = &pc->tokens->at(*token_index);
1453 if (else_token->id == TokenIdKeywordElse) {
1454 *token_index += 1;
1455 node->data.if_bool_expr.else_node = ast_parse_block_or_expression(pc, token_index, true);
1456 }
14641457
1465 return node;1458 return node;
1466 }1459 }
...@@ -1509,7 +1502,7 @@ static AstNode *ast_parse_return_expr(ParseContext *pc, size_t *token_index) {...@@ -1509,7 +1502,7 @@ static AstNode *ast_parse_return_expr(ParseContext *pc, size_t *token_index) {
1509}1502}
15101503
1511/*1504/*
1512Defer = option("%" | "?") "defer" Expression1505Defer(body) = option("%" | "?") "defer" body
1513*/1506*/
1514static AstNode *ast_parse_defer_expr(ParseContext *pc, size_t *token_index) {1507static AstNode *ast_parse_defer_expr(ParseContext *pc, size_t *token_index) {
1515 Token *token = &pc->tokens->at(*token_index);1508 Token *token = &pc->tokens->at(*token_index);
...@@ -1545,7 +1538,7 @@ static AstNode *ast_parse_defer_expr(ParseContext *pc, size_t *token_index) {...@@ -1545,7 +1538,7 @@ static AstNode *ast_parse_defer_expr(ParseContext *pc, size_t *token_index) {
15451538
1546 AstNode *node = ast_create_node(pc, node_type, token);1539 AstNode *node = ast_create_node(pc, node_type, token);
1547 node->data.defer.kind = kind;1540 node->data.defer.kind = kind;
1548 node->data.defer.expr = ast_parse_expression(pc, token_index, true);1541 node->data.defer.expr = ast_parse_block_or_expression(pc, token_index, true);
15491542
1550 return node;1543 return node;
1551}1544}
...@@ -1648,7 +1641,7 @@ static AstNode *ast_parse_bool_or_expr(ParseContext *pc, size_t *token_index, bo...@@ -1648,7 +1641,7 @@ static AstNode *ast_parse_bool_or_expr(ParseContext *pc, size_t *token_index, bo
1648}1641}
16491642
1650/*1643/*
1651WhileExpression = option("inline") "while" "(" Expression option(";" Expression) ")" Expression1644WhileExpression(body) = option("inline") "while" "(" Expression option(";" Expression) ")" body
1652*/1645*/
1653static AstNode *ast_parse_while_expr(ParseContext *pc, size_t *token_index, bool mandatory) {1646static AstNode *ast_parse_while_expr(ParseContext *pc, size_t *token_index, bool mandatory) {
1654 Token *first_token = &pc->tokens->at(*token_index);1647 Token *first_token = &pc->tokens->at(*token_index);
...@@ -1686,12 +1679,12 @@ static AstNode *ast_parse_while_expr(ParseContext *pc, size_t *token_index, bool...@@ -1686,12 +1679,12 @@ static AstNode *ast_parse_while_expr(ParseContext *pc, size_t *token_index, bool
16861679
1687 if (semi_or_rparen->id == TokenIdRParen) {1680 if (semi_or_rparen->id == TokenIdRParen) {
1688 *token_index += 1;1681 *token_index += 1;
1689 node->data.while_expr.body = ast_parse_expression(pc, token_index, true);1682 node->data.while_expr.body = ast_parse_block_or_expression(pc, token_index, true);
1690 } else if (semi_or_rparen->id == TokenIdSemicolon) {1683 } else if (semi_or_rparen->id == TokenIdSemicolon) {
1691 *token_index += 1;1684 *token_index += 1;
1692 node->data.while_expr.continue_expr = ast_parse_expression(pc, token_index, true);1685 node->data.while_expr.continue_expr = ast_parse_expression(pc, token_index, true);
1693 ast_eat_token(pc, token_index, TokenIdRParen);1686 ast_eat_token(pc, token_index, TokenIdRParen);
1694 node->data.while_expr.body = ast_parse_expression(pc, token_index, true);1687 node->data.while_expr.body = ast_parse_block_or_expression(pc, token_index, true);
1695 } else {1688 } else {
1696 ast_invalid_token_error(pc, semi_or_rparen);1689 ast_invalid_token_error(pc, semi_or_rparen);
1697 }1690 }
...@@ -1708,7 +1701,7 @@ static AstNode *ast_parse_symbol(ParseContext *pc, size_t *token_index) {...@@ -1708,7 +1701,7 @@ static AstNode *ast_parse_symbol(ParseContext *pc, size_t *token_index) {
1708}1701}
17091702
1710/*1703/*
1711ForExpression = option("inline") "for" "(" Expression ")" option("|" option("*") Symbol option("," Symbol) "|") Expression1704ForExpression(body) = option("inline") "for" "(" Expression ")" option("|" option("*") Symbol option("," Symbol) "|") body
1712*/1705*/
1713static AstNode *ast_parse_for_expr(ParseContext *pc, size_t *token_index, bool mandatory) {1706static AstNode *ast_parse_for_expr(ParseContext *pc, size_t *token_index, bool mandatory) {
1714 Token *first_token = &pc->tokens->at(*token_index);1707 Token *first_token = &pc->tokens->at(*token_index);
...@@ -1766,7 +1759,7 @@ static AstNode *ast_parse_for_expr(ParseContext *pc, size_t *token_index, bool m...@@ -1766,7 +1759,7 @@ static AstNode *ast_parse_for_expr(ParseContext *pc, size_t *token_index, bool m
1766 ast_eat_token(pc, token_index, TokenIdBinOr);1759 ast_eat_token(pc, token_index, TokenIdBinOr);
1767 }1760 }
17681761
1769 node->data.for_expr.body = ast_parse_expression(pc, token_index, true);1762 node->data.for_expr.body = ast_parse_block_or_expression(pc, token_index, true);
17701763
1771 return node;1764 return node;
1772}1765}
...@@ -1861,8 +1854,36 @@ static AstNode *ast_parse_switch_expr(ParseContext *pc, size_t *token_index, boo...@@ -1861,8 +1854,36 @@ static AstNode *ast_parse_switch_expr(ParseContext *pc, size_t *token_index, boo
1861 }1854 }
1862}1855}
18631856
1857static bool block_expr_has_block_body(AstNode *node) {
1858 switch (node->type) {
1859 case NodeTypeIfBoolExpr:
1860 if (node->data.if_bool_expr.else_node)
1861 return node->data.if_bool_expr.else_node->type == NodeTypeBlock;
1862 return node->data.if_bool_expr.then_block->type == NodeTypeBlock;
1863 case NodeTypeIfVarExpr:
1864 if (node->data.if_var_expr.else_node)
1865 return node->data.if_var_expr.else_node->type == NodeTypeBlock;
1866 return node->data.if_var_expr.then_block->type == NodeTypeBlock;
1867 case NodeTypeTryExpr:
1868 if (node->data.try_expr.else_node)
1869 return node->data.try_expr.else_node->type == NodeTypeBlock;
1870 return node->data.try_expr.then_node->type == NodeTypeBlock;
1871 case NodeTypeWhileExpr:
1872 return node->data.while_expr.body->type == NodeTypeBlock;
1873 case NodeTypeForExpr:
1874 return node->data.for_expr.body->type == NodeTypeBlock;
1875 case NodeTypeSwitchExpr:
1876 case NodeTypeBlock:
1877 return true;
1878 case NodeTypeCompTime:
1879 return node->data.comptime_expr.expr->type == NodeTypeBlock;
1880 default:
1881 zig_unreachable();
1882 }
1883}
1884
1864/*1885/*
1865BlockExpression = IfExpression | Block | WhileExpression | ForExpression | SwitchExpression | CompTimeExpression | TryExpression1886BlockExpression(body) = Block | IfExpression(body) | TryExpression(body) | WhileExpression(body) | ForExpression(body) | SwitchExpression | CompTimeExpression(body)
1866*/1887*/
1867static AstNode *ast_parse_block_expr(ParseContext *pc, size_t *token_index, bool mandatory) {1888static AstNode *ast_parse_block_expr(ParseContext *pc, size_t *token_index, bool mandatory) {
1868 Token *token = &pc->tokens->at(*token_index);1889 Token *token = &pc->tokens->at(*token_index);
...@@ -2006,38 +2027,29 @@ static AstNode *ast_parse_ass_expr(ParseContext *pc, size_t *token_index, bool m...@@ -2006,38 +2027,29 @@ static AstNode *ast_parse_ass_expr(ParseContext *pc, size_t *token_index, bool m
2006}2027}
20072028
2008/*2029/*
2009NonBlockExpression : ReturnExpression | AssignmentExpression2030BlockOrExpression = Block | Expression
2010*/2031*/
2011static AstNode *ast_parse_non_block_expr(ParseContext *pc, size_t *token_index, bool mandatory) {2032static AstNode *ast_parse_block_or_expression(ParseContext *pc, size_t *token_index, bool mandatory) {
2012 Token *token = &pc->tokens->at(*token_index);2033 AstNode *block_expr = ast_parse_block(pc, token_index, false);
20132034 if (block_expr)
2014 AstNode *return_expr = ast_parse_return_expr(pc, token_index);2035 return block_expr;
2015 if (return_expr)
2016 return return_expr;
2017
2018 AstNode *ass_expr = ast_parse_ass_expr(pc, token_index, false);
2019 if (ass_expr)
2020 return ass_expr;
2021
2022 if (mandatory)
2023 ast_invalid_token_error(pc, token);
20242036
2025 return nullptr;2037 return ast_parse_expression(pc, token_index, mandatory);
2026}2038}
20272039
2028/*2040/*
2029Expression : BlockExpression | NonBlockExpression2041Expression = ReturnExpression | AssignmentExpression
2030*/2042*/
2031static AstNode *ast_parse_expression(ParseContext *pc, size_t *token_index, bool mandatory) {2043static AstNode *ast_parse_expression(ParseContext *pc, size_t *token_index, bool mandatory) {
2032 Token *token = &pc->tokens->at(*token_index);2044 Token *token = &pc->tokens->at(*token_index);
20332045
2034 AstNode *block_expr = ast_parse_block_expr(pc, token_index, false);2046 AstNode *return_expr = ast_parse_return_expr(pc, token_index);
2035 if (block_expr)2047 if (return_expr)
2036 return block_expr;2048 return return_expr;
20372049
2038 AstNode *non_block_expr = ast_parse_non_block_expr(pc, token_index, false);2050 AstNode *ass_expr = ast_parse_ass_expr(pc, token_index, false);
2039 if (non_block_expr)2051 if (ass_expr)
2040 return non_block_expr;2052 return ass_expr;
20412053
2042 if (mandatory)2054 if (mandatory)
2043 ast_invalid_token_error(pc, token);2055 ast_invalid_token_error(pc, token);
...@@ -2080,8 +2092,8 @@ static AstNode *ast_create_void_expr(ParseContext *pc, Token *token) {...@@ -2080,8 +2092,8 @@ static AstNode *ast_create_void_expr(ParseContext *pc, Token *token) {
2080}2092}
20812093
2082/*2094/*
2083Block : token(LBrace) list(option(Statement), token(Semicolon)) token(RBrace)2095Block = "{" many(Statement) option(Expression) "}"
2084Statement = Label | VariableDeclaration ";" | Defer ";" | NonBlockExpression ";" | BlockExpression2096Statement = Label | VariableDeclaration ";" | Defer(Block) | Defer(Expression) ";" | BlockExpression(Block) | Expression ";" | ";"
2085*/2097*/
2086static AstNode *ast_parse_block(ParseContext *pc, size_t *token_index, bool mandatory) {2098static AstNode *ast_parse_block(ParseContext *pc, size_t *token_index, bool mandatory) {
2087 Token *last_token = &pc->tokens->at(*token_index);2099 Token *last_token = &pc->tokens->at(*token_index);
...@@ -2100,7 +2112,7 @@ static AstNode *ast_parse_block(ParseContext *pc, size_t *token_index, bool mand...@@ -2100,7 +2112,7 @@ static AstNode *ast_parse_block(ParseContext *pc, size_t *token_index, bool mand
2100 for (;;) {2112 for (;;) {
2101 AstNode *statement_node = ast_parse_label(pc, token_index, false);2113 AstNode *statement_node = ast_parse_label(pc, token_index, false);
2102 bool need_implicit_final_void_statement = false;2114 bool need_implicit_final_void_statement = false;
2103 bool semicolon_expected;2115 bool semicolon_expected = true;
2104 if (statement_node) {2116 if (statement_node) {
2105 semicolon_expected = false;2117 semicolon_expected = false;
2106 // if a label is the last thing in a block, add a void statement.2118 // if a label is the last thing in a block, add a void statement.
...@@ -2109,17 +2121,18 @@ static AstNode *ast_parse_block(ParseContext *pc, size_t *token_index, bool mand...@@ -2109,17 +2121,18 @@ static AstNode *ast_parse_block(ParseContext *pc, size_t *token_index, bool mand
2109 statement_node = ast_parse_variable_declaration_expr(pc, token_index, false, VisibModPrivate);2121 statement_node = ast_parse_variable_declaration_expr(pc, token_index, false, VisibModPrivate);
2110 if (!statement_node) {2122 if (!statement_node) {
2111 statement_node = ast_parse_defer_expr(pc, token_index);2123 statement_node = ast_parse_defer_expr(pc, token_index);
2112 }
2113 if (statement_node) {
2114 semicolon_expected = true;
2115 } else {
2116 statement_node = ast_parse_block_expr(pc, token_index, false);
2117 semicolon_expected = !statement_node;
2118 if (!statement_node) {2124 if (!statement_node) {
2119 statement_node = ast_parse_non_block_expr(pc, token_index, false);2125 statement_node = ast_parse_block_expr(pc, token_index, false);
2120 if (!statement_node) {2126 if (statement_node) {
2121 // final semicolon means add a void statement.2127 if (block_expr_has_block_body(statement_node)) {
2122 need_implicit_final_void_statement = true;2128 semicolon_expected = false;
2129 }
2130 } else {
2131 statement_node = ast_parse_expression(pc, token_index, false);
2132 if (!statement_node) {
2133 // final semicolon means add a void statement.
2134 need_implicit_final_void_statement = true;
2135 }
2123 }2136 }
2124 }2137 }
2125 }2138 }
...@@ -2301,7 +2314,7 @@ static AstNode *ast_parse_use(ParseContext *pc, size_t *token_index, VisibMod vi...@@ -2301,7 +2314,7 @@ static AstNode *ast_parse_use(ParseContext *pc, size_t *token_index, VisibMod vi
2301/*2314/*
2302ContainerDecl = option("extern" | "packed") ("struct" | "enum" | "union") "{" many(ContainerMember) "}"2315ContainerDecl = option("extern" | "packed") ("struct" | "enum" | "union") "{" many(ContainerMember) "}"
2303ContainerMember = (ContainerField | FnDef | GlobalVarDecl)2316ContainerMember = (ContainerField | FnDef | GlobalVarDecl)
2304ContainerField = Symbol option(":" Expression) ",")2317ContainerField = Symbol option(":" Expression) ","
2305*/2318*/
2306static AstNode *ast_parse_container_decl(ParseContext *pc, size_t *token_index, bool mandatory) {2319static AstNode *ast_parse_container_decl(ParseContext *pc, size_t *token_index, bool mandatory) {
2307 Token *first_token = &pc->tokens->at(*token_index);2320 Token *first_token = &pc->tokens->at(*token_index);