parser recognizes %return in a prefix op expression

also defer only valid at statement level now

see #110
This commit is contained in:
Andrew Kelley 2016-02-06 19:16:01 -07:00
parent 65a03c5859
commit 73727bd1c5
2 changed files with 72 additions and 14 deletions

View File

@ -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 {

View File

@ -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;
}