diff --git a/core_ast.cpp b/core_ast.cpp index 5bff871..1af02d5 100644 --- a/core_ast.cpp +++ b/core_ast.cpp @@ -177,6 +177,13 @@ ast_return(Token *pos, Ast_Expr *expr) { 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 * ast_goto(Token *pos, Intern_String label) { Ast_Goto *result = ast_new(Ast_Goto, AST_GOTO, pos, AST_STMT); diff --git a/core_compiler.cpp b/core_compiler.cpp index 4366d84..368b3b8 100644 --- a/core_compiler.cpp +++ b/core_compiler.cpp @@ -67,8 +67,9 @@ for i in meta.token_simple_expr: pctx->keyword_for = pctx->intern("for"_s); pctx->keyword_enum = pctx->intern("enum"_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.last_keyword = pctx->keyword_goto.str; + pctx->interns.last_keyword = pctx->keyword_defer.str; pctx->intern_typeof = pctx->intern("typeof"_s); pctx->intern_sizeof = pctx->intern("sizeof"_s); pctx->intern_len = pctx->intern("Len"_s); diff --git a/core_compiler.h b/core_compiler.h index 0244bc2..2a69a3a 100644 --- a/core_compiler.h +++ b/core_compiler.h @@ -108,6 +108,7 @@ for i in meta.interns: print(f'Intern_String intern_{i.lower()};') Intern_String keyword_for; Intern_String keyword_enum; Intern_String keyword_goto; + Intern_String keyword_defer; Intern_String intern_typeof; Intern_String intern_sizeof; Intern_String intern_len; diff --git a/core_compiler_interface.hpp b/core_compiler_interface.hpp index 7d6840f..7eec953 100644 --- a/core_compiler_interface.hpp +++ b/core_compiler_interface.hpp @@ -334,6 +334,7 @@ enum Ast_Kind : uint32_t { AST_TYPE_OF, AST_VARGS_LAMBDA_PARAM, + AST_DEFER, AST_LABEL, AST_GOTO, AST_SWITCH, @@ -535,6 +536,10 @@ struct Ast_Goto : Ast { Intern_String label; }; +struct Ast_Defer : Ast { + Ast_Scope *scope; +}; + struct Ast_For : Ast { Ast_Expr *init; Ast_Expr *cond; @@ -636,7 +641,7 @@ struct Ast_Decl : Ast { Array polymorph_resolved_parameter_types; Array polymorph_parameters; Array polymorphs; // instantiated polymorphs - + Ast_Scope *scope; Ast_Expr *typespec; union { diff --git a/core_parsing.cpp b/core_parsing.cpp index 1f48036..a0aa4c2 100644 --- a/core_parsing.cpp +++ b/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 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 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 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 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; } diff --git a/meta.py b/meta.py index 0e105e2..5b878a9 100644 --- a/meta.py +++ b/meta.py @@ -116,6 +116,7 @@ keywords = [ "for", "enum", "goto", + "defer", ] interns = [