Core: Factor + start defer
This commit is contained in:
412
core_parsing.cpp
412
core_parsing.cpp
@@ -271,218 +271,228 @@ parse_optional_type() {
|
||||
return result;
|
||||
}
|
||||
|
||||
CORE_Static Ast_Scope *
|
||||
parse_stmt_scope(Ast_Scope *scope_defined_outside = 0) {
|
||||
Ast_Scope *scope = scope_defined_outside;
|
||||
CORE_Static Ast_Scope *parse_stmt_scope(Ast_Scope *scope_defined_outside = 0, bool empty_scope_is_error = true);
|
||||
|
||||
if (token_expect(OPEN_SCOPE)) { // @todo: Fix error message here, it doesn't show proper token context
|
||||
Token *token_block = token_get();
|
||||
CORE_Static Ast *
|
||||
parse_stmt() {
|
||||
Token *token = token_get();
|
||||
Scoped_Arena scratch(pctx->scratch);
|
||||
|
||||
Scoped_Arena scratch(pctx->scratch);
|
||||
if (!scope_defined_outside) scope = begin_stmt_scope(scratch.arena, token_block);
|
||||
if (token_match_keyword(pctx->keyword_return)) {
|
||||
Ast_Expr *expr = 0;
|
||||
if (!token_is_scope()) expr = parse_expr();
|
||||
return ast_return(token, expr);
|
||||
}
|
||||
|
||||
else if (token_match_keyword(pctx->keyword_continue)) {
|
||||
return ast_continue(token);
|
||||
}
|
||||
|
||||
else if (token_match_keyword(pctx->intern_compiler_breakpoint)) {
|
||||
return ast_compiler_breakpoint(token);
|
||||
}
|
||||
|
||||
else if (token_match_keyword(pctx->keyword_break)) {
|
||||
return ast_break(token);
|
||||
}
|
||||
|
||||
else if (token_match_keyword(pctx->keyword_pass)) {
|
||||
return ast_pass(token);
|
||||
}
|
||||
|
||||
else if (token_match_keyword(pctx->keyword_switch)) {
|
||||
Ast_Switch *result = ast_new(Ast_Switch, AST_SWITCH, token, AST_STMT);
|
||||
result->value = parse_expr();
|
||||
result->cases = {scratch.arena};
|
||||
|
||||
token_expect(OPEN_SCOPE);
|
||||
do {
|
||||
Token *token = token_get();
|
||||
|
||||
if (token_match_keyword(pctx->keyword_return)) {
|
||||
Ast_Expr *expr = 0;
|
||||
if (!token_is_scope()) expr = parse_expr();
|
||||
scope->stmts.add(ast_return(token, expr));
|
||||
if (token_match_keyword(pctx->keyword_default)) {
|
||||
result->default_scope = parse_stmt_scope();
|
||||
continue;
|
||||
}
|
||||
|
||||
else if (token_match_keyword(pctx->keyword_continue)) {
|
||||
scope->stmts.add(ast_continue(token));
|
||||
}
|
||||
Ast_Switch_Case *switch_case = ast_new(Ast_Switch_Case, AST_SWITCH_CASE, token_get(), AST_STMT);
|
||||
if (token_match_pound(pctx->intern("fallthrough"_s)))
|
||||
switch_case->fallthrough = true;
|
||||
|
||||
else if (token_match_keyword(pctx->intern_compiler_breakpoint)) {
|
||||
scope->stmts.add(ast_compiler_breakpoint(token));
|
||||
}
|
||||
switch_case->labels = {scratch.arena};
|
||||
do {
|
||||
switch_case->labels.add(parse_expr());
|
||||
} while (token_match(TK_Comma));
|
||||
switch_case->labels = switch_case->labels.tight_copy(pctx->perm);
|
||||
|
||||
else if (token_match_keyword(pctx->keyword_break)) {
|
||||
scope->stmts.add(ast_break(token));
|
||||
}
|
||||
|
||||
else if (token_match_keyword(pctx->keyword_pass)) {
|
||||
scope->stmts.add(ast_pass(token));
|
||||
}
|
||||
|
||||
else if (token_match_keyword(pctx->keyword_switch)) {
|
||||
Ast_Switch *result = ast_new(Ast_Switch, AST_SWITCH, token, AST_STMT);
|
||||
result->value = parse_expr();
|
||||
result->cases = {scratch.arena};
|
||||
|
||||
token_expect(OPEN_SCOPE);
|
||||
do {
|
||||
if (token_match_keyword(pctx->keyword_default)) {
|
||||
result->default_scope = parse_stmt_scope();
|
||||
continue;
|
||||
}
|
||||
|
||||
Ast_Switch_Case *switch_case = ast_new(Ast_Switch_Case, AST_SWITCH_CASE, token_get(), AST_STMT);
|
||||
if (token_match_pound(pctx->intern("fallthrough"_s)))
|
||||
switch_case->fallthrough = true;
|
||||
|
||||
switch_case->labels = {scratch.arena};
|
||||
do {
|
||||
switch_case->labels.add(parse_expr());
|
||||
} while (token_match(TK_Comma));
|
||||
switch_case->labels = switch_case->labels.tight_copy(pctx->perm);
|
||||
|
||||
switch_case->scope = parse_stmt_scope();
|
||||
result->cases.add(switch_case);
|
||||
} while (token_match(SAME_SCOPE));
|
||||
token_expect(CLOSE_SCOPE);
|
||||
result->cases = result->cases.tight_copy(pctx->perm);
|
||||
|
||||
scope->stmts.add(result);
|
||||
}
|
||||
|
||||
else if (token_match_keyword(pctx->keyword_assert)) {
|
||||
token_expect(TK_OpenParen);
|
||||
Ast_Expr *expr = parse_expr();
|
||||
Intern_String message = {};
|
||||
if (token_match(TK_Comma)) {
|
||||
Token *t = token_expect(TK_StringLit);
|
||||
message = t->intern_val;
|
||||
}
|
||||
token_expect(TK_CloseParen);
|
||||
scope->stmts.add(ast_runtime_assert(token, expr, message));
|
||||
}
|
||||
|
||||
else if (token_match_pound(pctx->keyword_assert)) {
|
||||
token_expect(TK_OpenParen);
|
||||
Ast_Expr *expr = parse_expr();
|
||||
Intern_String message = {};
|
||||
if (token_match(TK_Comma)) {
|
||||
Token *t = token_expect(TK_StringLit);
|
||||
message = t->intern_val;
|
||||
}
|
||||
token_expect(TK_CloseParen);
|
||||
scope->stmts.add(ast_constant_assert(token, expr, message));
|
||||
}
|
||||
|
||||
else if (token_match_keyword(pctx->keyword_for)) {
|
||||
Ast_Scope *for_scope = begin_stmt_scope(scratch.arena, token_get());
|
||||
Ast_Expr *init = 0;
|
||||
Ast_Expr *cond = 0;
|
||||
Ast_Expr *iter = 0;
|
||||
|
||||
if (!token_is(OPEN_SCOPE)) {
|
||||
if (!token_is(TK_Comma)) {
|
||||
Ast_Expr *expr_first = parse_expr();
|
||||
init = parse_init_stmt(expr_first);
|
||||
}
|
||||
|
||||
if (token_match(TK_Comma)) {
|
||||
if (!token_is(TK_Comma)) cond = parse_expr();
|
||||
if (token_match(TK_Comma)) {
|
||||
iter = parse_expr();
|
||||
iter = parse_init_stmt(iter);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
parse_stmt_scope(for_scope);
|
||||
finalize_stmt_scope(for_scope);
|
||||
scope->stmts.add(ast_for(token, init, cond, iter, for_scope));
|
||||
}
|
||||
|
||||
else if (token_match_keyword(pctx->keyword_if)) {
|
||||
Array<Ast_If_Node *> if_nodes = {scratch.arena};
|
||||
Ast_Expr *expr = parse_expr();
|
||||
Ast_Expr *init_val = parse_init_stmt(expr);
|
||||
if (init_val != expr) {
|
||||
if (token_match(TK_Comma)) expr = parse_expr();
|
||||
else expr = 0;
|
||||
}
|
||||
if (init_val == expr) init_val = 0;
|
||||
|
||||
Ast_Scope *if_block = parse_stmt_scope();
|
||||
Ast_If_Node *if_node = ast_if_node(token, init_val, expr, if_block);
|
||||
if_nodes.add(if_node);
|
||||
|
||||
while (token_is(SAME_SCOPE) && (token_is_keyword(pctx->keyword_elif, 1) || (token_is_keyword(pctx->keyword_else, 1)))) {
|
||||
token_next();
|
||||
token = token_get();
|
||||
if (token_match_keyword(pctx->keyword_elif)) {
|
||||
assert(token->intern_val == pctx->keyword_elif);
|
||||
Ast_Expr *expr = parse_expr();
|
||||
Ast_Scope *else_if_block = parse_stmt_scope();
|
||||
Ast_If_Node *if_node = ast_if_node(token, 0, expr, else_if_block);
|
||||
if_nodes.add(if_node);
|
||||
}
|
||||
else {
|
||||
token_match_keyword(pctx->keyword_else);
|
||||
assert(token->intern_val == pctx->keyword_else);
|
||||
Ast_Scope *else_block = parse_stmt_scope();
|
||||
Ast_If_Node *if_node = ast_if_node(token, 0, 0, else_block);
|
||||
if_nodes.add(if_node);
|
||||
break;
|
||||
}
|
||||
}
|
||||
Ast_If *result_if = ast_if(token, if_nodes);
|
||||
scope->stmts.add(result_if);
|
||||
}
|
||||
|
||||
else if (token_match_keyword(pctx->keyword_goto)) {
|
||||
Token *ident = token_expect(TK_Identifier);
|
||||
Ast_Goto *result = ast_goto(token, ident->intern_val);
|
||||
scope->stmts.add(result);
|
||||
}
|
||||
|
||||
// Label
|
||||
else if (token_match(TK_Colon)) {
|
||||
Token *ident = token_expect(TK_Identifier);
|
||||
Token *enable_goto_token = token_match(TK_Colon);
|
||||
bool enable_goto = enable_goto_token ? 1 : 0;
|
||||
Token *breakpoint = token_match_pound(pctx->intern_compiler_breakpoint);
|
||||
|
||||
Ast_Scope *s = 0;
|
||||
if (token_is(OPEN_SCOPE)) s = parse_stmt_scope();
|
||||
|
||||
Ast_Label *result = ast_label(token, ident->intern_val, s, enable_goto);
|
||||
if (breakpoint) set_flag(result->flags, AST_COMPILER_BREAKPOINT);
|
||||
scope->stmts.add(result);
|
||||
}
|
||||
|
||||
// Var unpack
|
||||
else if (token_is(TK_Identifier) && token_is(TK_Comma, 1)) {
|
||||
Array<Ast_Decl *> decls = {scratch.arena};
|
||||
do {
|
||||
Token *name = token_match(TK_Identifier);
|
||||
Ast_Decl *decl = ast_var(name, 0, name->intern_val, 0);
|
||||
decls.add(decl);
|
||||
} while (token_match(TK_Comma));
|
||||
|
||||
token_expect(TK_ColonAssign);
|
||||
Ast_Expr *expr = parse_expr();
|
||||
Ast_Var_Unpack *vars = ast_var_unpack(token, decls, expr);
|
||||
scope->stmts.add(vars);
|
||||
}
|
||||
|
||||
// Declaration or init stmt
|
||||
else {
|
||||
Ast *result = parse_decl(false);
|
||||
if (result && result->kind != AST_VAR && result->kind != AST_CONST) {
|
||||
compiler_error(token, "Invalid statement construct");
|
||||
}
|
||||
if (!result) {
|
||||
result = parse_expr();
|
||||
result = parse_init_stmt((Ast_Expr *)result);
|
||||
}
|
||||
|
||||
if (result) {
|
||||
result->flags = set_flag(result->flags, AST_STMT);
|
||||
scope->stmts.add(result);
|
||||
}
|
||||
else {
|
||||
compiler_error(token, "Unexpected token [%s] while parsing statement", name(token->kind));
|
||||
}
|
||||
}
|
||||
switch_case->scope = parse_stmt_scope();
|
||||
result->cases.add(switch_case);
|
||||
} while (token_match(SAME_SCOPE));
|
||||
token_expect(CLOSE_SCOPE);
|
||||
result->cases = result->cases.tight_copy(pctx->perm);
|
||||
|
||||
if (!scope_defined_outside) finalize_stmt_scope(scope);
|
||||
return result;
|
||||
}
|
||||
|
||||
else if (token_match_keyword(pctx->keyword_assert)) {
|
||||
token_expect(TK_OpenParen);
|
||||
Ast_Expr *expr = parse_expr();
|
||||
Intern_String message = {};
|
||||
if (token_match(TK_Comma)) {
|
||||
Token *t = token_expect(TK_StringLit);
|
||||
message = t->intern_val;
|
||||
}
|
||||
token_expect(TK_CloseParen);
|
||||
return ast_runtime_assert(token, expr, message);
|
||||
}
|
||||
|
||||
else if (token_match_pound(pctx->keyword_assert)) {
|
||||
token_expect(TK_OpenParen);
|
||||
Ast_Expr *expr = parse_expr();
|
||||
Intern_String message = {};
|
||||
if (token_match(TK_Comma)) {
|
||||
Token *t = token_expect(TK_StringLit);
|
||||
message = t->intern_val;
|
||||
}
|
||||
token_expect(TK_CloseParen);
|
||||
return ast_constant_assert(token, expr, message);
|
||||
}
|
||||
|
||||
else if (token_match_keyword(pctx->keyword_for)) {
|
||||
Ast_Scope *for_scope = begin_stmt_scope(scratch.arena, token_get());
|
||||
Ast_Expr *init = 0;
|
||||
Ast_Expr *cond = 0;
|
||||
Ast_Expr *iter = 0;
|
||||
|
||||
if (!token_is(OPEN_SCOPE)) {
|
||||
if (!token_is(TK_Comma)) {
|
||||
Ast_Expr *expr_first = parse_expr();
|
||||
init = parse_init_stmt(expr_first);
|
||||
}
|
||||
|
||||
if (token_match(TK_Comma)) {
|
||||
if (!token_is(TK_Comma)) cond = parse_expr();
|
||||
if (token_match(TK_Comma)) {
|
||||
iter = parse_expr();
|
||||
iter = parse_init_stmt(iter);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
parse_stmt_scope(for_scope);
|
||||
finalize_stmt_scope(for_scope);
|
||||
return ast_for(token, init, cond, iter, for_scope);
|
||||
}
|
||||
|
||||
else if (token_match_keyword(pctx->keyword_if)) {
|
||||
Array<Ast_If_Node *> if_nodes = {scratch.arena};
|
||||
Ast_Expr *expr = parse_expr();
|
||||
Ast_Expr *init_val = parse_init_stmt(expr);
|
||||
if (init_val != expr) {
|
||||
if (token_match(TK_Comma)) expr = parse_expr();
|
||||
else expr = 0;
|
||||
}
|
||||
if (init_val == expr) init_val = 0;
|
||||
|
||||
Ast_Scope *if_block = parse_stmt_scope();
|
||||
Ast_If_Node *if_node = ast_if_node(token, init_val, expr, if_block);
|
||||
if_nodes.add(if_node);
|
||||
|
||||
while (token_is(SAME_SCOPE) && (token_is_keyword(pctx->keyword_elif, 1) || (token_is_keyword(pctx->keyword_else, 1)))) {
|
||||
token_next();
|
||||
token = token_get();
|
||||
if (token_match_keyword(pctx->keyword_elif)) {
|
||||
assert(token->intern_val == pctx->keyword_elif);
|
||||
Ast_Expr *expr = parse_expr();
|
||||
Ast_Scope *else_if_block = parse_stmt_scope();
|
||||
Ast_If_Node *if_node = ast_if_node(token, 0, expr, else_if_block);
|
||||
if_nodes.add(if_node);
|
||||
}
|
||||
else {
|
||||
token_match_keyword(pctx->keyword_else);
|
||||
assert(token->intern_val == pctx->keyword_else);
|
||||
Ast_Scope *else_block = parse_stmt_scope();
|
||||
Ast_If_Node *if_node = ast_if_node(token, 0, 0, else_block);
|
||||
if_nodes.add(if_node);
|
||||
break;
|
||||
}
|
||||
}
|
||||
return ast_if(token, if_nodes);
|
||||
}
|
||||
|
||||
else if (token_match_keyword(pctx->keyword_defer)) {
|
||||
Ast_Scope *s = parse_stmt_scope();
|
||||
return ast_defer(token, s);
|
||||
}
|
||||
|
||||
else if (token_match_keyword(pctx->keyword_goto)) {
|
||||
Token *ident = token_expect(TK_Identifier);
|
||||
return ast_goto(token, ident->intern_val);
|
||||
}
|
||||
|
||||
// Label
|
||||
else if (token_match(TK_Colon)) {
|
||||
Token *ident = token_expect(TK_Identifier);
|
||||
Token *enable_goto_token = token_match(TK_Colon);
|
||||
bool enable_goto = enable_goto_token ? 1 : 0;
|
||||
Token *breakpoint = token_match_pound(pctx->intern_compiler_breakpoint);
|
||||
|
||||
Ast_Scope *s = 0;
|
||||
if (token_is(OPEN_SCOPE)) s = parse_stmt_scope();
|
||||
|
||||
Ast_Label *result = ast_label(token, ident->intern_val, s, enable_goto);
|
||||
if (breakpoint) set_flag(result->flags, AST_COMPILER_BREAKPOINT);
|
||||
return result;
|
||||
}
|
||||
|
||||
// Var unpack
|
||||
else if (token_is(TK_Identifier) && token_is(TK_Comma, 1)) {
|
||||
Array<Ast_Decl *> decls = {scratch.arena};
|
||||
do {
|
||||
Token *name = token_match(TK_Identifier);
|
||||
Ast_Decl *decl = ast_var(name, 0, name->intern_val, 0);
|
||||
decls.add(decl);
|
||||
} while (token_match(TK_Comma));
|
||||
|
||||
token_expect(TK_ColonAssign);
|
||||
Ast_Expr *expr = parse_expr();
|
||||
Ast_Var_Unpack *vars = ast_var_unpack(token, decls, expr);
|
||||
return vars;
|
||||
}
|
||||
|
||||
// Declaration or init stmt
|
||||
else {
|
||||
Ast *result = parse_decl(false);
|
||||
if (result && result->kind != AST_VAR && result->kind != AST_CONST) {
|
||||
compiler_error(token, "Invalid statement construct");
|
||||
}
|
||||
if (!result) {
|
||||
result = parse_expr();
|
||||
result = parse_init_stmt((Ast_Expr *)result);
|
||||
}
|
||||
if (result) {
|
||||
result->flags = set_flag(result->flags, AST_STMT);
|
||||
return result;
|
||||
}
|
||||
else {
|
||||
compiler_error(token, "Unexpected token [%s] while parsing statement", name(token->kind));
|
||||
return 0;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
CORE_Static Ast_Scope *
|
||||
parse_stmt_scope(Ast_Scope *scope_defined_outside, bool empty_scope_is_error) {
|
||||
Scoped_Arena scratch(pctx->scratch);
|
||||
Ast_Scope *scope = scope_defined_outside;
|
||||
if (!scope_defined_outside) scope = begin_stmt_scope(scratch.arena, token_get());
|
||||
|
||||
if (token_expect(OPEN_SCOPE)) { // @todo: Fix error message here, it doesn't show proper token context
|
||||
do {
|
||||
Ast *stmt = parse_stmt();
|
||||
scope->stmts.add(stmt);
|
||||
} while (token_match(SAME_SCOPE));
|
||||
token_expect(CLOSE_SCOPE);
|
||||
}
|
||||
|
||||
if (!scope_defined_outside) finalize_stmt_scope(scope);
|
||||
return scope;
|
||||
}
|
||||
|
||||
|
||||
Reference in New Issue
Block a user