Commit 0594487a2e

Josh Wolfe <thejoshwolfe@gmail.com>
2017-04-03 00:14:35
fix else-if parsing
implicit semicolon rules apply recursively to the "else" clause of if and try if (a) {} else {} // implicit semicolon if (a) {} else if (a) {} // implicit semicolon if (a) {} else while (a) {} // implicit semicolon
1 parent a33be6f
Changed files (2)
doc/langref.md
@@ -93,11 +93,11 @@ Defer(body) = option("%" | "?") "defer" body
 
 IfExpression(body) = IfVarExpression(body) | IfBoolExpression(body)
 
-IfBoolExpression(body) = "if" "(" Expression ")" body option("else" body)
+IfBoolExpression(body) = "if" "(" Expression ")" body option("else" BlockExpression(body))
 
-TryExpression(body) = "try" "(" option(("const" | "var") option("*") Symbol "=") Expression  ")" body option("else" option("|" Symbol "|") body)
+TryExpression(body) = "try" "(" option(("const" | "var") option("*") Symbol "=") Expression  ")" body option("else" option("|" Symbol "|") BlockExpression(body))
 
-IfVarExpression(body) = "if" "(" ("const" | "var") option("*") Symbol option(":" TypeExpr) "?=" Expression ")" body Option("else" body)
+IfVarExpression(body) = "if" "(" ("const" | "var") option("*") Symbol option(":" TypeExpr) "?=" Expression ")" body Option("else" BlockExpression(body))
 
 BoolAndExpression = ComparisonExpression "and" BoolAndExpression | ComparisonExpression
 
src/parser.cpp
@@ -212,6 +212,7 @@ static void ast_invalid_token_error(ParseContext *pc, Token *token) {
 }
 
 static AstNode *ast_parse_block_or_expression(ParseContext *pc, size_t *token_index, bool mandatory);
+static AstNode *ast_parse_block_expr_or_expression(ParseContext *pc, size_t *token_index, bool mandatory);
 static AstNode *ast_parse_expression(ParseContext *pc, size_t *token_index, bool mandatory);
 static AstNode *ast_parse_block(ParseContext *pc, size_t *token_index, bool mandatory);
 static AstNode *ast_parse_if_expr(ParseContext *pc, size_t *token_index, bool mandatory);
@@ -701,7 +702,7 @@ static AstNode *ast_parse_try_expr(ParseContext *pc, size_t *token_index, bool m
             ast_eat_token(pc, token_index, TokenIdBinOr);
         }
 
-        node->data.try_expr.else_node = ast_parse_block_or_expression(pc, token_index, true);
+        node->data.try_expr.else_node = ast_parse_block_expr_or_expression(pc, token_index, true);
     }
 
     return node;
@@ -1439,7 +1440,7 @@ static AstNode *ast_parse_if_expr(ParseContext *pc, size_t *token_index, bool ma
         Token *else_token = &pc->tokens->at(*token_index);
         if (else_token->id == TokenIdKeywordElse) {
             *token_index += 1;
-            node->data.if_var_expr.else_node = ast_parse_block_or_expression(pc, token_index, true);
+            node->data.if_var_expr.else_node = ast_parse_block_expr_or_expression(pc, token_index, true);
         }
 
         return node;
@@ -1452,7 +1453,7 @@ static AstNode *ast_parse_if_expr(ParseContext *pc, size_t *token_index, bool ma
         Token *else_token = &pc->tokens->at(*token_index);
         if (else_token->id == TokenIdKeywordElse) {
             *token_index += 1;
-            node->data.if_bool_expr.else_node = ast_parse_block_or_expression(pc, token_index, true);
+            node->data.if_bool_expr.else_node = ast_parse_block_expr_or_expression(pc, token_index, true);
         }
 
         return node;
@@ -1860,15 +1861,15 @@ static bool statement_has_block_body(AstNode *node) {
     switch (node->type) {
         case NodeTypeIfBoolExpr:
             if (node->data.if_bool_expr.else_node)
-                return node->data.if_bool_expr.else_node->type == NodeTypeBlock;
+                return statement_has_block_body(node->data.if_bool_expr.else_node);
             return node->data.if_bool_expr.then_block->type == NodeTypeBlock;
         case NodeTypeIfVarExpr:
             if (node->data.if_var_expr.else_node)
-                return node->data.if_var_expr.else_node->type == NodeTypeBlock;
+                return statement_has_block_body(node->data.if_var_expr.else_node);
             return node->data.if_var_expr.then_block->type == NodeTypeBlock;
         case NodeTypeTryExpr:
             if (node->data.try_expr.else_node)
-                return node->data.try_expr.else_node->type == NodeTypeBlock;
+                return statement_has_block_body(node->data.try_expr.else_node);
             return node->data.try_expr.then_node->type == NodeTypeBlock;
         case NodeTypeWhileExpr:
             return node->data.while_expr.body->type == NodeTypeBlock;
@@ -1882,7 +1883,7 @@ static bool statement_has_block_body(AstNode *node) {
         case NodeTypeDefer:
             return node->data.defer.expr->type == NodeTypeBlock;
         default:
-            zig_unreachable();
+            return false;
     }
 }
 
@@ -2030,6 +2031,14 @@ static AstNode *ast_parse_ass_expr(ParseContext *pc, size_t *token_index, bool m
     return node;
 }
 
+static AstNode *ast_parse_block_expr_or_expression(ParseContext *pc, size_t *token_index, bool mandatory) {
+    AstNode *block_expr = ast_parse_block_expr(pc, token_index, false);
+    if (block_expr)
+        return block_expr;
+
+    return ast_parse_expression(pc, token_index, mandatory);
+}
+
 /*
 BlockOrExpression = Block | Expression
 */