Commit 73727bd1c5
Changed files (2)
src
test
src/parser.cpp
@@ -498,6 +498,7 @@ static AstNode *ast_parse_unwrap_expr(ParseContext *pc, int *token_index, bool m
static AstNode *ast_parse_prefix_op_expr(ParseContext *pc, int *token_index, bool mandatory);
static AstNode *ast_parse_fn_proto(ParseContext *pc, int *token_index, bool mandatory,
ZigList<AstNode*> *directives, VisibMod visib_mod);
+static AstNode *ast_parse_return_expr(ParseContext *pc, int *token_index);
static void ast_expect_token(ParseContext *pc, Token *token, TokenId token_id) {
if (token->id == token_id) {
@@ -1215,8 +1216,17 @@ static AstNode *ast_parse_prefix_op_expr(ParseContext *pc, int *token_index, boo
if (prefix_op == PrefixOpInvalid) {
return ast_parse_suffix_op_expr(pc, token_index, mandatory);
}
+
+ if (prefix_op == PrefixOpError || prefix_op == PrefixOpMaybe) {
+ Token *maybe_return = &pc->tokens->at(*token_index + 1);
+ if (maybe_return->id == TokenIdKeywordReturn) {
+ return ast_parse_return_expr(pc, token_index);
+ }
+ }
+
*token_index += 1;
+
AstNode *node = ast_create_node(pc, NodeTypePrefixOpExpr, token);
AstNode *parent_node = node;
if (token->id == TokenIdBoolAnd) {
@@ -1635,9 +1645,8 @@ static AstNode *ast_parse_if_expr(ParseContext *pc, int *token_index, bool manda
/*
ReturnExpression : option("%" | "?") "return" option(Expression)
-DeferExpression = option("%" | "?") "defer" option(Expression)
*/
-static AstNode *ast_parse_return_or_defer_expr(ParseContext *pc, int *token_index) {
+static AstNode *ast_parse_return_expr(ParseContext *pc, int *token_index) {
Token *token = &pc->tokens->at(*token_index);
NodeType node_type;
@@ -1649,10 +1658,6 @@ static AstNode *ast_parse_return_or_defer_expr(ParseContext *pc, int *token_inde
kind = ReturnKindError;
node_type = NodeTypeReturnExpr;
*token_index += 2;
- } else if (next_token->id == TokenIdKeywordDefer) {
- kind = ReturnKindError;
- node_type = NodeTypeDefer;
- *token_index += 2;
} else {
return nullptr;
}
@@ -1662,10 +1667,6 @@ static AstNode *ast_parse_return_or_defer_expr(ParseContext *pc, int *token_inde
kind = ReturnKindMaybe;
node_type = NodeTypeReturnExpr;
*token_index += 2;
- } else if (next_token->id == TokenIdKeywordDefer) {
- kind = ReturnKindMaybe;
- node_type = NodeTypeDefer;
- *token_index += 2;
} else {
return nullptr;
}
@@ -1673,6 +1674,45 @@ static AstNode *ast_parse_return_or_defer_expr(ParseContext *pc, int *token_inde
kind = ReturnKindUnconditional;
node_type = NodeTypeReturnExpr;
*token_index += 1;
+ } else {
+ return nullptr;
+ }
+
+ AstNode *node = ast_create_node(pc, node_type, token);
+ node->data.return_expr.kind = kind;
+ node->data.return_expr.expr = ast_parse_expression(pc, token_index, false);
+
+ normalize_parent_ptrs(node);
+ return node;
+}
+
+/*
+Defer = option("%" | "?") "defer" option(Expression)
+*/
+static AstNode *ast_parse_defer_expr(ParseContext *pc, int *token_index) {
+ Token *token = &pc->tokens->at(*token_index);
+
+ NodeType node_type;
+ ReturnKind kind;
+
+ if (token->id == TokenIdPercent) {
+ Token *next_token = &pc->tokens->at(*token_index + 1);
+ if (next_token->id == TokenIdKeywordDefer) {
+ kind = ReturnKindError;
+ node_type = NodeTypeDefer;
+ *token_index += 2;
+ } else {
+ return nullptr;
+ }
+ } else if (token->id == TokenIdMaybe) {
+ Token *next_token = &pc->tokens->at(*token_index + 1);
+ if (next_token->id == TokenIdKeywordDefer) {
+ kind = ReturnKindMaybe;
+ node_type = NodeTypeDefer;
+ *token_index += 2;
+ } else {
+ return nullptr;
+ }
} else if (token->id == TokenIdKeywordDefer) {
kind = ReturnKindUnconditional;
node_type = NodeTypeDefer;
@@ -1682,8 +1722,8 @@ static AstNode *ast_parse_return_or_defer_expr(ParseContext *pc, int *token_inde
}
AstNode *node = ast_create_node(pc, node_type, token);
- node->data.return_expr.kind = kind;
- node->data.return_expr.expr = ast_parse_expression(pc, token_index, false);
+ node->data.defer.kind = kind;
+ node->data.defer.expr = ast_parse_expression(pc, token_index, false);
normalize_parent_ptrs(node);
return node;
@@ -2068,7 +2108,7 @@ NonBlockExpression : ReturnExpression | AssignmentExpression
static AstNode *ast_parse_non_block_expr(ParseContext *pc, int *token_index, bool mandatory) {
Token *token = &pc->tokens->at(*token_index);
- AstNode *return_expr = ast_parse_return_or_defer_expr(pc, token_index);
+ AstNode *return_expr = ast_parse_return_expr(pc, token_index);
if (return_expr)
return return_expr;
@@ -2142,7 +2182,7 @@ static AstNode *ast_create_void_expr(ParseContext *pc, Token *token) {
/*
Block : token(LBrace) list(option(Statement), token(Semicolon)) token(RBrace)
-Statement : Label | VariableDeclaration token(Semicolon) | NonBlockExpression token(Semicolon) | BlockExpression
+Statement = Label | VariableDeclaration ";" | Defer ";" | NonBlockExpression ";" | BlockExpression
*/
static AstNode *ast_parse_block(ParseContext *pc, int *token_index, bool mandatory) {
Token *last_token = &pc->tokens->at(*token_index);
@@ -2171,6 +2211,9 @@ static AstNode *ast_parse_block(ParseContext *pc, int *token_index, bool mandato
} else {
statement_node = ast_parse_variable_declaration_expr(pc, token_index, false,
nullptr, VisibModPrivate);
+ if (!statement_node) {
+ statement_node = ast_parse_defer_expr(pc, token_index);
+ }
if (statement_node) {
semicolon_expected = true;
} else {
test/self_hosted.zig
@@ -173,3 +173,18 @@ fn switch_prong_with_var_fn(a: SwitchProngWithVarEnum) {
},
}
}
+
+
+#attribute("test")
+fn err_return_in_assignment() {
+ %%do_err_return_in_assignment();
+}
+
+fn do_err_return_in_assignment() -> %void {
+ var x : i32 = undefined;
+ x = %return make_a_non_err();
+}
+
+fn make_a_non_err() -> %i32 {
+ return 1;
+}