Core: Factor + start defer

This commit is contained in:
Krzosa Karol
2023-04-22 13:46:21 +02:00
parent b51a2080d2
commit d9a7882f8c
6 changed files with 228 additions and 203 deletions

View File

@@ -177,6 +177,13 @@ ast_return(Token *pos, Ast_Expr *expr) {
return result; return result;
} }
CORE_Static Ast_Defer *
ast_defer(Token *pos, Ast_Scope *scope) {
Ast_Defer *result = ast_new(Ast_Defer, AST_DEFER, pos, AST_STMT);
result->scope = scope;
return result;
}
CORE_Static Ast_Goto * CORE_Static Ast_Goto *
ast_goto(Token *pos, Intern_String label) { ast_goto(Token *pos, Intern_String label) {
Ast_Goto *result = ast_new(Ast_Goto, AST_GOTO, pos, AST_STMT); Ast_Goto *result = ast_new(Ast_Goto, AST_GOTO, pos, AST_STMT);

View File

@@ -67,8 +67,9 @@ for i in meta.token_simple_expr:
pctx->keyword_for = pctx->intern("for"_s); pctx->keyword_for = pctx->intern("for"_s);
pctx->keyword_enum = pctx->intern("enum"_s); pctx->keyword_enum = pctx->intern("enum"_s);
pctx->keyword_goto = pctx->intern("goto"_s); pctx->keyword_goto = pctx->intern("goto"_s);
pctx->keyword_defer = pctx->intern("defer"_s);
pctx->interns.first_keyword = pctx->keyword_struct.str; pctx->interns.first_keyword = pctx->keyword_struct.str;
pctx->interns.last_keyword = pctx->keyword_goto.str; pctx->interns.last_keyword = pctx->keyword_defer.str;
pctx->intern_typeof = pctx->intern("typeof"_s); pctx->intern_typeof = pctx->intern("typeof"_s);
pctx->intern_sizeof = pctx->intern("sizeof"_s); pctx->intern_sizeof = pctx->intern("sizeof"_s);
pctx->intern_len = pctx->intern("Len"_s); pctx->intern_len = pctx->intern("Len"_s);

View File

@@ -108,6 +108,7 @@ for i in meta.interns: print(f'Intern_String intern_{i.lower()};')
Intern_String keyword_for; Intern_String keyword_for;
Intern_String keyword_enum; Intern_String keyword_enum;
Intern_String keyword_goto; Intern_String keyword_goto;
Intern_String keyword_defer;
Intern_String intern_typeof; Intern_String intern_typeof;
Intern_String intern_sizeof; Intern_String intern_sizeof;
Intern_String intern_len; Intern_String intern_len;

View File

@@ -334,6 +334,7 @@ enum Ast_Kind : uint32_t {
AST_TYPE_OF, AST_TYPE_OF,
AST_VARGS_LAMBDA_PARAM, AST_VARGS_LAMBDA_PARAM,
AST_DEFER,
AST_LABEL, AST_LABEL,
AST_GOTO, AST_GOTO,
AST_SWITCH, AST_SWITCH,
@@ -535,6 +536,10 @@ struct Ast_Goto : Ast {
Intern_String label; Intern_String label;
}; };
struct Ast_Defer : Ast {
Ast_Scope *scope;
};
struct Ast_For : Ast { struct Ast_For : Ast {
Ast_Expr *init; Ast_Expr *init;
Ast_Expr *cond; Ast_Expr *cond;
@@ -636,7 +641,7 @@ struct Ast_Decl : Ast {
Array<Ast_Type *> polymorph_resolved_parameter_types; Array<Ast_Type *> polymorph_resolved_parameter_types;
Array<Ast_Decl *> polymorph_parameters; Array<Ast_Decl *> polymorph_parameters;
Array<Ast_Decl *> polymorphs; // instantiated polymorphs Array<Ast_Decl *> polymorphs; // instantiated polymorphs
Ast_Scope *scope; Ast_Scope *scope;
Ast_Expr *typespec; Ast_Expr *typespec;
union { union {

View File

@@ -271,218 +271,228 @@ parse_optional_type() {
return result; return result;
} }
CORE_Static Ast_Scope * CORE_Static Ast_Scope *parse_stmt_scope(Ast_Scope *scope_defined_outside = 0, bool empty_scope_is_error = true);
parse_stmt_scope(Ast_Scope *scope_defined_outside = 0) {
Ast_Scope *scope = scope_defined_outside;
if (token_expect(OPEN_SCOPE)) { // @todo: Fix error message here, it doesn't show proper token context CORE_Static Ast *
Token *token_block = token_get(); parse_stmt() {
Token *token = token_get();
Scoped_Arena scratch(pctx->scratch);
Scoped_Arena scratch(pctx->scratch); if (token_match_keyword(pctx->keyword_return)) {
if (!scope_defined_outside) scope = begin_stmt_scope(scratch.arena, token_block); 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 { do {
Token *token = token_get(); if (token_match_keyword(pctx->keyword_default)) {
result->default_scope = parse_stmt_scope();
if (token_match_keyword(pctx->keyword_return)) { continue;
Ast_Expr *expr = 0;
if (!token_is_scope()) expr = parse_expr();
scope->stmts.add(ast_return(token, expr));
} }
else if (token_match_keyword(pctx->keyword_continue)) { Ast_Switch_Case *switch_case = ast_new(Ast_Switch_Case, AST_SWITCH_CASE, token_get(), AST_STMT);
scope->stmts.add(ast_continue(token)); if (token_match_pound(pctx->intern("fallthrough"_s)))
} switch_case->fallthrough = true;
else if (token_match_keyword(pctx->intern_compiler_breakpoint)) { switch_case->labels = {scratch.arena};
scope->stmts.add(ast_compiler_breakpoint(token)); 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)) { switch_case->scope = parse_stmt_scope();
scope->stmts.add(ast_break(token)); result->cases.add(switch_case);
}
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));
}
}
} while (token_match(SAME_SCOPE)); } while (token_match(SAME_SCOPE));
token_expect(CLOSE_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; return scope;
} }

View File

@@ -116,6 +116,7 @@ keywords = [
"for", "for",
"enum", "enum",
"goto", "goto",
"defer",
] ]
interns = [ interns = [