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 ":"
4545
4646TypeExpr = PrefixOpExpression | "var"
4747
48BlockOrExpression = Block | Expression
49
4850Expression = ReturnExpression | AssignmentExpression
4951
5052AsmExpression = "asm" option("volatile") "(" String option(AsmOutput) ")"
......@@ -143,7 +145,7 @@ StructLiteralField = "." Symbol "=" Expression
143145
144146PrefixOp = "!" | "-" | "~" | "*" | ("&" option("const") option("volatile")) | "?" | "%" | "%%" | "??" | "-%"
145147
146PrimaryExpression = Number | String | CharLiteral | KeywordLiteral | GroupedExpression | GotoExpression | BlockExpression(Expression) | Symbol | ("@" Symbol FnCallExpression) | ArrayType | (option("extern") FnProto) | AsmExpression | ("error" "." Symbol) | ContainerDecl
148PrimaryExpression = Number | String | CharLiteral | KeywordLiteral | GroupedExpression | GotoExpression | BlockExpression(BlockOrExpression) | Symbol | ("@" Symbol FnCallExpression) | ArrayType | (option("extern") FnProto) | AsmExpression | ("error" "." Symbol) | ContainerDecl
147149
148150ArrayType = "[" 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) {
211211 ast_error(pc, token, "invalid token: '%s'", buf_ptr(&token_value));
212212}
213213
214static AstNode *ast_parse_block_or_expression(ParseContext *pc, size_t *token_index, bool mandatory);
214215static AstNode *ast_parse_expression(ParseContext *pc, size_t *token_index, bool mandatory);
215216static AstNode *ast_parse_block(ParseContext *pc, size_t *token_index, bool mandatory);
216217static 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
632633 if (require_block_body)
633634 node->data.comptime_expr.expr = ast_parse_block(pc, token_index, true);
634635 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);
636637 return node;
637638}
638639
639640/*
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)
641642*/
642643static AstNode *ast_parse_try_expr(ParseContext *pc, size_t *token_index, bool mandatory) {
643644 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
685686
686687 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
690691 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) {
697693 *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);
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);
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);
703705 }
704706
705 node->data.try_expr.else_node = ast_parse_expression(pc, token_index, true);
706707 return node;
707708}
708709
709710/*
710PrimaryExpression = Number | String | CharLiteral | KeywordLiteral | GroupedExpression | GotoExpression | BlockExpression | Symbol | ("@" Symbol FnCallExpression) | ArrayType | (option("extern") FnProto) | AsmExpression | ("error" "." Symbol) | ContainerDecl
711PrimaryExpression = Number | String | CharLiteral | KeywordLiteral | GroupedExpression | GotoExpression | BlockExpression(BlockOrExpression) | Symbol | ("@" Symbol FnCallExpression) | ArrayType | (option("extern") FnProto) | AsmExpression | ("error" "." Symbol) | ContainerDecl
711712KeywordLiteral = "true" | "false" | "null" | "break" | "continue" | "undefined" | "error" | "type" | "this" | "unreachable"
712713*/
713714static 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
13811382}
13821383
13831384/*
1384Else : token(Else) Expression
1385*/
1386static 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/*
1402IfExpression : IfVarExpression | IfBoolExpression
1403IfBoolExpression = "if" "(" Expression ")" Expression option(Else)
1404IfVarExpression = "if" "(" ("const" | "var") option("*") Symbol option(":" TypeExpr) "?=" Expression ")" Expression Option(Else)
1385IfExpression(body) = IfVarExpression(body) | IfBoolExpression(body)
1386IfBoolExpression(body) = "if" "(" Expression ")" body option("else" body)
1387IfVarExpression(body) = "if" "(" ("const" | "var") option("*") Symbol option(":" TypeExpr) "?=" Expression ")" body Option("else" body)
14051388*/
14061389static AstNode *ast_parse_if_expr(ParseContext *pc, size_t *token_index, bool mandatory) {
14071390 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
14511434 ast_invalid_token_error(pc, eq_or_colon);
14521435 }
14531436 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 }
14561444
14571445 return node;
14581446 } else {
14591447 AstNode *node = ast_create_node(pc, NodeTypeIfBoolExpr, if_token);
14601448 node->data.if_bool_expr.condition = ast_parse_expression(pc, token_index, true);
14611449 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 }
14641457
14651458 return node;
14661459 }
......@@ -1509,7 +1502,7 @@ static AstNode *ast_parse_return_expr(ParseContext *pc, size_t *token_index) {
15091502}
15101503
15111504/*
1512Defer = option("%" | "?") "defer" Expression
1505Defer(body) = option("%" | "?") "defer" body
15131506*/
15141507static AstNode *ast_parse_defer_expr(ParseContext *pc, size_t *token_index) {
15151508 Token *token = &pc->tokens->at(*token_index);
......@@ -1545,7 +1538,7 @@ static AstNode *ast_parse_defer_expr(ParseContext *pc, size_t *token_index) {
15451538
15461539 AstNode *node = ast_create_node(pc, node_type, token);
15471540 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
15501543 return node;
15511544}
......@@ -1648,7 +1641,7 @@ static AstNode *ast_parse_bool_or_expr(ParseContext *pc, size_t *token_index, bo
16481641}
16491642
16501643/*
1651WhileExpression = option("inline") "while" "(" Expression option(";" Expression) ")" Expression
1644WhileExpression(body) = option("inline") "while" "(" Expression option(";" Expression) ")" body
16521645*/
16531646static AstNode *ast_parse_while_expr(ParseContext *pc, size_t *token_index, bool mandatory) {
16541647 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
16861679
16871680 if (semi_or_rparen->id == TokenIdRParen) {
16881681 *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);
16901683 } else if (semi_or_rparen->id == TokenIdSemicolon) {
16911684 *token_index += 1;
16921685 node->data.while_expr.continue_expr = ast_parse_expression(pc, token_index, true);
16931686 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);
16951688 } else {
16961689 ast_invalid_token_error(pc, semi_or_rparen);
16971690 }
......@@ -1708,7 +1701,7 @@ static AstNode *ast_parse_symbol(ParseContext *pc, size_t *token_index) {
17081701}
17091702
17101703/*
1711ForExpression = option("inline") "for" "(" Expression ")" option("|" option("*") Symbol option("," Symbol) "|") Expression
1704ForExpression(body) = option("inline") "for" "(" Expression ")" option("|" option("*") Symbol option("," Symbol) "|") body
17121705*/
17131706static AstNode *ast_parse_for_expr(ParseContext *pc, size_t *token_index, bool mandatory) {
17141707 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
17661759 ast_eat_token(pc, token_index, TokenIdBinOr);
17671760 }
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
17711764 return node;
17721765}
......@@ -1861,8 +1854,36 @@ static AstNode *ast_parse_switch_expr(ParseContext *pc, size_t *token_index, boo
18611854 }
18621855}
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
18641885/*
1865BlockExpression = IfExpression | Block | WhileExpression | ForExpression | SwitchExpression | CompTimeExpression | TryExpression
1886BlockExpression(body) = Block | IfExpression(body) | TryExpression(body) | WhileExpression(body) | ForExpression(body) | SwitchExpression | CompTimeExpression(body)
18661887*/
18671888static AstNode *ast_parse_block_expr(ParseContext *pc, size_t *token_index, bool mandatory) {
18681889 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
20062027}
20072028
20082029/*
2009NonBlockExpression : ReturnExpression | AssignmentExpression
2030BlockOrExpression = Block | Expression
20102031*/
2011static 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);
2032static 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;
20242036
2025 return nullptr;
2037 return ast_parse_expression(pc, token_index, mandatory);
20262038}
20272039
20282040/*
2029Expression : BlockExpression | NonBlockExpression
2041Expression = ReturnExpression | AssignmentExpression
20302042*/
20312043static AstNode *ast_parse_expression(ParseContext *pc, size_t *token_index, bool mandatory) {
20322044 Token *token = &pc->tokens->at(*token_index);
20332045
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;
20372049
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;
20412053
20422054 if (mandatory)
20432055 ast_invalid_token_error(pc, token);
......@@ -2080,8 +2092,8 @@ static AstNode *ast_create_void_expr(ParseContext *pc, Token *token) {
20802092}
20812093
20822094/*
2083Block : token(LBrace) list(option(Statement), token(Semicolon)) token(RBrace)
2084Statement = Label | VariableDeclaration ";" | Defer ";" | NonBlockExpression ";" | BlockExpression
2095Block = "{" many(Statement) option(Expression) "}"
2096Statement = Label | VariableDeclaration ";" | Defer(Block) | Defer(Expression) ";" | BlockExpression(Block) | Expression ";" | ";"
20852097*/
20862098static AstNode *ast_parse_block(ParseContext *pc, size_t *token_index, bool mandatory) {
20872099 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
21002112 for (;;) {
21012113 AstNode *statement_node = ast_parse_label(pc, token_index, false);
21022114 bool need_implicit_final_void_statement = false;
2103 bool semicolon_expected;
2115 bool semicolon_expected = true;
21042116 if (statement_node) {
21052117 semicolon_expected = false;
21062118 // 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
21092121 statement_node = ast_parse_variable_declaration_expr(pc, token_index, false, VisibModPrivate);
21102122 if (!statement_node) {
21112123 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;
21182124 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 }
21232136 }
21242137 }
21252138 }
......@@ -2301,7 +2314,7 @@ static AstNode *ast_parse_use(ParseContext *pc, size_t *token_index, VisibMod vi
23012314/*
23022315ContainerDecl = option("extern" | "packed") ("struct" | "enum" | "union") "{" many(ContainerMember) "}"
23032316ContainerMember = (ContainerField | FnDef | GlobalVarDecl)
2304ContainerField = Symbol option(":" Expression) ",")
2317ContainerField = Symbol option(":" Expression) ","
23052318*/
23062319static AstNode *ast_parse_container_decl(ParseContext *pc, size_t *token_index, bool mandatory) {
23072320 Token *first_token = &pc->tokens->at(*token_index);