| ... | ... | @@ -211,6 +211,7 @@ static void ast_invalid_token_error(ParseContext *pc, Token *token) { |
| 211 | 211 | ast_error(pc, token, "invalid token: '%s'", buf_ptr(&token_value)); |
| 212 | 212 | } |
| 213 | 213 | |
| 214 | static AstNode *ast_parse_block_or_expression(ParseContext *pc, size_t *token_index, bool mandatory); |
| 214 | 215 | static AstNode *ast_parse_expression(ParseContext *pc, size_t *token_index, bool mandatory); |
| 215 | 216 | static AstNode *ast_parse_block(ParseContext *pc, size_t *token_index, bool mandatory); |
| 216 | 217 | static 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 | 633 | if (require_block_body) |
| 633 | 634 | node->data.comptime_expr.expr = ast_parse_block(pc, token_index, true); |
| 634 | 635 | 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 | 637 | return node; |
| 637 | 638 | } |
| 638 | 639 | |
| 639 | 640 | /* |
| 640 | | TryExpression = "try" "(" option(("const" | "var") option("*") Symbol "=") Expression ")" Expression option("else" option("|" Symbol "|") Expression) |
| 641 | TryExpression(body) = "try" "(" option(("const" | "var") option("*") Symbol "=") Expression ")" body option("else" option("|" Symbol "|") body) |
| 641 | 642 | */ |
| 642 | 643 | static AstNode *ast_parse_try_expr(ParseContext *pc, size_t *token_index, bool mandatory) { |
| 643 | 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 | 686 | |
| 686 | 687 | ast_eat_token(pc, token_index, TokenIdRParen); |
| 687 | 688 | |
| 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); |
| 689 | 690 | |
| 690 | 691 | Token *else_token = &pc->tokens->at(*token_index); |
| 691 | | 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) { |
| 692 | if (else_token->id == TokenIdKeywordElse) { |
| 697 | 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; |
| 698 | 697 | |
| 699 | | Token *err_name_tok = ast_eat_token(pc, token_index, TokenIdSymbol); |
| 700 | | node->data.try_expr.err_symbol = token_buf(err_name_tok); |
| 698 | Token *err_name_tok = ast_eat_token(pc, token_index, TokenIdSymbol); |
| 699 | node->data.try_expr.err_symbol = token_buf(err_name_tok); |
| 701 | 700 | |
| 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 | } |
| 704 | 706 | |
| 705 | | node->data.try_expr.else_node = ast_parse_expression(pc, token_index, true); |
| 706 | 707 | return node; |
| 707 | 708 | } |
| 708 | 709 | |
| 709 | 710 | /* |
| 710 | | PrimaryExpression = Number | String | CharLiteral | KeywordLiteral | GroupedExpression | GotoExpression | BlockExpression | Symbol | ("@" Symbol FnCallExpression) | ArrayType | (option("extern") FnProto) | AsmExpression | ("error" "." Symbol) | ContainerDecl |
| 711 | PrimaryExpression = Number | String | CharLiteral | KeywordLiteral | GroupedExpression | GotoExpression | BlockExpression(BlockOrExpression) | Symbol | ("@" Symbol FnCallExpression) | ArrayType | (option("extern") FnProto) | AsmExpression | ("error" "." Symbol) | ContainerDecl |
| 711 | 712 | KeywordLiteral = "true" | "false" | "null" | "break" | "continue" | "undefined" | "error" | "type" | "this" | "unreachable" |
| 712 | 713 | */ |
| 713 | 714 | static 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 | 1382 | } |
| 1382 | 1383 | |
| 1383 | 1384 | /* |
| 1384 | | Else : token(Else) Expression |
| 1385 | | */ |
| 1386 | | static AstNode *ast_parse_else(ParseContext *pc, size_t *token_index, bool mandatory) { |
| 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 | | /* |
| 1402 | | IfExpression : IfVarExpression | IfBoolExpression |
| 1403 | | IfBoolExpression = "if" "(" Expression ")" Expression option(Else) |
| 1404 | | IfVarExpression = "if" "(" ("const" | "var") option("*") Symbol option(":" TypeExpr) "?=" Expression ")" Expression Option(Else) |
| 1385 | IfExpression(body) = IfVarExpression(body) | IfBoolExpression(body) |
| 1386 | IfBoolExpression(body) = "if" "(" Expression ")" body option("else" body) |
| 1387 | IfVarExpression(body) = "if" "(" ("const" | "var") option("*") Symbol option(":" TypeExpr) "?=" Expression ")" body Option("else" body) |
| 1405 | 1388 | */ |
| 1406 | 1389 | static AstNode *ast_parse_if_expr(ParseContext *pc, size_t *token_index, bool mandatory) { |
| 1407 | 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 | 1434 | ast_invalid_token_error(pc, eq_or_colon); |
| 1452 | 1435 | } |
| 1453 | 1436 | ast_eat_token(pc, token_index, TokenIdRParen); |
| 1454 | | node->data.if_var_expr.then_block = ast_parse_expression(pc, token_index, true); |
| 1455 | | node->data.if_var_expr.else_node = ast_parse_else(pc, token_index, false); |
| 1437 | node->data.if_var_expr.then_block = ast_parse_block_or_expression(pc, token_index, true); |
| 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 | } |
| 1456 | 1444 | |
| 1457 | 1445 | return node; |
| 1458 | 1446 | } else { |
| 1459 | 1447 | AstNode *node = ast_create_node(pc, NodeTypeIfBoolExpr, if_token); |
| 1460 | 1448 | node->data.if_bool_expr.condition = ast_parse_expression(pc, token_index, true); |
| 1461 | 1449 | ast_eat_token(pc, token_index, TokenIdRParen); |
| 1462 | | node->data.if_bool_expr.then_block = ast_parse_expression(pc, token_index, true); |
| 1463 | | node->data.if_bool_expr.else_node = ast_parse_else(pc, token_index, false); |
| 1450 | node->data.if_bool_expr.then_block = ast_parse_block_or_expression(pc, token_index, true); |
| 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 | } |
| 1464 | 1457 | |
| 1465 | 1458 | return node; |
| 1466 | 1459 | } |
| ... | ... | @@ -1509,7 +1502,7 @@ static AstNode *ast_parse_return_expr(ParseContext *pc, size_t *token_index) { |
| 1509 | 1502 | } |
| 1510 | 1503 | |
| 1511 | 1504 | /* |
| 1512 | | Defer = option("%" | "?") "defer" Expression |
| 1505 | Defer(body) = option("%" | "?") "defer" body |
| 1513 | 1506 | */ |
| 1514 | 1507 | static AstNode *ast_parse_defer_expr(ParseContext *pc, size_t *token_index) { |
| 1515 | 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 | 1538 | |
| 1546 | 1539 | AstNode *node = ast_create_node(pc, node_type, token); |
| 1547 | 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); |
| 1549 | 1542 | |
| 1550 | 1543 | return node; |
| 1551 | 1544 | } |
| ... | ... | @@ -1648,7 +1641,7 @@ static AstNode *ast_parse_bool_or_expr(ParseContext *pc, size_t *token_index, bo |
| 1648 | 1641 | } |
| 1649 | 1642 | |
| 1650 | 1643 | /* |
| 1651 | | WhileExpression = option("inline") "while" "(" Expression option(";" Expression) ")" Expression |
| 1644 | WhileExpression(body) = option("inline") "while" "(" Expression option(";" Expression) ")" body |
| 1652 | 1645 | */ |
| 1653 | 1646 | static AstNode *ast_parse_while_expr(ParseContext *pc, size_t *token_index, bool mandatory) { |
| 1654 | 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 | 1679 | |
| 1687 | 1680 | if (semi_or_rparen->id == TokenIdRParen) { |
| 1688 | 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 | 1683 | } else if (semi_or_rparen->id == TokenIdSemicolon) { |
| 1691 | 1684 | *token_index += 1; |
| 1692 | 1685 | node->data.while_expr.continue_expr = ast_parse_expression(pc, token_index, true); |
| 1693 | 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 | 1688 | } else { |
| 1696 | 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 | 1701 | } |
| 1709 | 1702 | |
| 1710 | 1703 | /* |
| 1711 | | ForExpression = option("inline") "for" "(" Expression ")" option("|" option("*") Symbol option("," Symbol) "|") Expression |
| 1704 | ForExpression(body) = option("inline") "for" "(" Expression ")" option("|" option("*") Symbol option("," Symbol) "|") body |
| 1712 | 1705 | */ |
| 1713 | 1706 | static AstNode *ast_parse_for_expr(ParseContext *pc, size_t *token_index, bool mandatory) { |
| 1714 | 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 | 1759 | ast_eat_token(pc, token_index, TokenIdBinOr); |
| 1767 | 1760 | } |
| 1768 | 1761 | |
| 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); |
| 1770 | 1763 | |
| 1771 | 1764 | return node; |
| 1772 | 1765 | } |
| ... | ... | @@ -1861,8 +1854,36 @@ static AstNode *ast_parse_switch_expr(ParseContext *pc, size_t *token_index, boo |
| 1861 | 1854 | } |
| 1862 | 1855 | } |
| 1863 | 1856 | |
| 1857 | static 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 | /* |
| 1865 | | BlockExpression = IfExpression | Block | WhileExpression | ForExpression | SwitchExpression | CompTimeExpression | TryExpression |
| 1886 | BlockExpression(body) = Block | IfExpression(body) | TryExpression(body) | WhileExpression(body) | ForExpression(body) | SwitchExpression | CompTimeExpression(body) |
| 1866 | 1887 | */ |
| 1867 | 1888 | static AstNode *ast_parse_block_expr(ParseContext *pc, size_t *token_index, bool mandatory) { |
| 1868 | 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 | 2027 | } |
| 2007 | 2028 | |
| 2008 | 2029 | /* |
| 2009 | | NonBlockExpression : ReturnExpression | AssignmentExpression |
| 2030 | BlockOrExpression = Block | Expression |
| 2010 | 2031 | */ |
| 2011 | | static AstNode *ast_parse_non_block_expr(ParseContext *pc, size_t *token_index, bool mandatory) { |
| 2012 | | Token *token = &pc->tokens->at(*token_index); |
| 2013 | | |
| 2014 | | AstNode *return_expr = ast_parse_return_expr(pc, token_index); |
| 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); |
| 2032 | static AstNode *ast_parse_block_or_expression(ParseContext *pc, size_t *token_index, bool mandatory) { |
| 2033 | AstNode *block_expr = ast_parse_block(pc, token_index, false); |
| 2034 | if (block_expr) |
| 2035 | return block_expr; |
| 2024 | 2036 | |
| 2025 | | return nullptr; |
| 2037 | return ast_parse_expression(pc, token_index, mandatory); |
| 2026 | 2038 | } |
| 2027 | 2039 | |
| 2028 | 2040 | /* |
| 2029 | | Expression : BlockExpression | NonBlockExpression |
| 2041 | Expression = ReturnExpression | AssignmentExpression |
| 2030 | 2042 | */ |
| 2031 | 2043 | static AstNode *ast_parse_expression(ParseContext *pc, size_t *token_index, bool mandatory) { |
| 2032 | 2044 | Token *token = &pc->tokens->at(*token_index); |
| 2033 | 2045 | |
| 2034 | | AstNode *block_expr = ast_parse_block_expr(pc, token_index, false); |
| 2035 | | if (block_expr) |
| 2036 | | return block_expr; |
| 2046 | AstNode *return_expr = ast_parse_return_expr(pc, token_index); |
| 2047 | if (return_expr) |
| 2048 | return return_expr; |
| 2037 | 2049 | |
| 2038 | | AstNode *non_block_expr = ast_parse_non_block_expr(pc, token_index, false); |
| 2039 | | if (non_block_expr) |
| 2040 | | return non_block_expr; |
| 2050 | AstNode *ass_expr = ast_parse_ass_expr(pc, token_index, false); |
| 2051 | if (ass_expr) |
| 2052 | return ass_expr; |
| 2041 | 2053 | |
| 2042 | 2054 | if (mandatory) |
| 2043 | 2055 | ast_invalid_token_error(pc, token); |
| ... | ... | @@ -2080,8 +2092,8 @@ static AstNode *ast_create_void_expr(ParseContext *pc, Token *token) { |
| 2080 | 2092 | } |
| 2081 | 2093 | |
| 2082 | 2094 | /* |
| 2083 | | Block : token(LBrace) list(option(Statement), token(Semicolon)) token(RBrace) |
| 2084 | | Statement = Label | VariableDeclaration ";" | Defer ";" | NonBlockExpression ";" | BlockExpression |
| 2095 | Block = "{" many(Statement) option(Expression) "}" |
| 2096 | Statement = Label | VariableDeclaration ";" | Defer(Block) | Defer(Expression) ";" | BlockExpression(Block) | Expression ";" | ";" |
| 2085 | 2097 | */ |
| 2086 | 2098 | static AstNode *ast_parse_block(ParseContext *pc, size_t *token_index, bool mandatory) { |
| 2087 | 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 | 2112 | for (;;) { |
| 2101 | 2113 | AstNode *statement_node = ast_parse_label(pc, token_index, false); |
| 2102 | 2114 | bool need_implicit_final_void_statement = false; |
| 2103 | | bool semicolon_expected; |
| 2115 | bool semicolon_expected = true; |
| 2104 | 2116 | if (statement_node) { |
| 2105 | 2117 | semicolon_expected = false; |
| 2106 | 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 | 2121 | statement_node = ast_parse_variable_declaration_expr(pc, token_index, false, VisibModPrivate); |
| 2110 | 2122 | if (!statement_node) { |
| 2111 | 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 | 2124 | if (!statement_node) { |
| 2119 | | statement_node = ast_parse_non_block_expr(pc, token_index, false); |
| 2120 | | if (!statement_node) { |
| 2121 | | // final semicolon means add a void statement. |
| 2122 | | need_implicit_final_void_statement = true; |
| 2125 | statement_node = ast_parse_block_expr(pc, token_index, false); |
| 2126 | if (statement_node) { |
| 2127 | if (block_expr_has_block_body(statement_node)) { |
| 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 | 2314 | /* |
| 2302 | 2315 | ContainerDecl = option("extern" | "packed") ("struct" | "enum" | "union") "{" many(ContainerMember) "}" |
| 2303 | 2316 | ContainerMember = (ContainerField | FnDef | GlobalVarDecl) |
| 2304 | | ContainerField = Symbol option(":" Expression) ",") |
| 2317 | ContainerField = Symbol option(":" Expression) "," |
| 2305 | 2318 | */ |
| 2306 | 2319 | static AstNode *ast_parse_container_decl(ParseContext *pc, size_t *token_index, bool mandatory) { |
| 2307 | 2320 | Token *first_token = &pc->tokens->at(*token_index); |