From b4c661eaad3c30e476a9ab93ffca998867ffcd0b Mon Sep 17 00:00:00 2001 From: Christoffer Lerno Date: Sat, 11 Jul 2020 12:38:25 +0200 Subject: [PATCH] Pre lexing and mmap allocation together with exact exits. --- CMakeLists.txt | 2 +- resources/testfragments/super_simple.c3 | 99 ++++--- src/compiler/ast.c | 98 +++---- src/compiler/compiler.c | 38 ++- src/compiler/compiler_internal.h | 334 ++++++++++++++---------- src/compiler/context.c | 40 +-- src/compiler/diagnostics.c | 156 +++++------ src/compiler/enums.h | 10 +- src/compiler/lexer.c | 334 ++++++++++++++---------- src/compiler/llvm_codegen.c | 2 +- src/compiler/llvm_codegen_debug_info.c | 36 +-- src/compiler/llvm_codegen_expr.c | 102 +++++++- src/compiler/llvm_codegen_function.c | 5 +- src/compiler/llvm_codegen_internal.h | 26 +- src/compiler/llvm_codegen_stmt.c | 33 +-- src/compiler/module.c | 8 +- src/compiler/parse_expr.c | 71 +++-- src/compiler/parse_stmt.c | 107 ++++---- src/compiler/parser.c | 292 ++++++++++----------- src/compiler/parser_internal.h | 8 +- src/compiler/sema_casts.c | 230 ++++++++-------- src/compiler/sema_decls.c | 24 +- src/compiler/sema_expr.c | 248 +++++++++--------- src/compiler/sema_internal.h | 9 +- src/compiler/sema_name_resolution.c | 2 +- src/compiler/sema_stmts.c | 265 ++++++++++--------- src/compiler/sema_types.c | 16 +- src/compiler/semantic_analyser.c | 1 - src/compiler/source_file.c | 46 ---- src/compiler/symtab.c | 1 + src/compiler/types.c | 40 --- src/compiler_tests/tests.c | 15 +- src/utils/common.h | 8 + src/utils/malloc.c | 90 +------ src/utils/malloc.h | 12 +- src/utils/vmem.c | 86 ++++++ src/utils/vmem.h | 21 ++ 37 files changed, 1557 insertions(+), 1358 deletions(-) create mode 100644 src/utils/vmem.c create mode 100644 src/utils/vmem.h diff --git a/CMakeLists.txt b/CMakeLists.txt index 2e56880d9..a1fc8e95e 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -86,7 +86,7 @@ add_executable(c3c src/compiler/llvm_codegen_function.c src/build/builder.c src/utils/toml.c src/build/project.c - src/compiler/sema_name_resolution.c src/target_info/target_info.c src/compiler/parse_expr.c src/compiler/parser_internal.h src/compiler/parse_stmt.c src/compiler/sema_passes.c src/compiler/sema_internal.h src/compiler/sema_decls.c src/compiler/sema_types.c src/compiler/sema_stmts.c src/compiler/number.c) + src/compiler/sema_name_resolution.c src/target_info/target_info.c src/compiler/parse_expr.c src/compiler/parser_internal.h src/compiler/parse_stmt.c src/compiler/sema_passes.c src/compiler/sema_internal.h src/compiler/sema_decls.c src/compiler/sema_types.c src/compiler/sema_stmts.c src/compiler/number.c src/utils/vmem.c src/utils/vmem.h) target_compile_options(c3c PRIVATE -Wimplicit-int -Werror -Wall -Wno-unknown-pragmas -Wextra -Wno-unused-function -Wno-unused-variable -Wno-unused-parameter) diff --git a/resources/testfragments/super_simple.c3 b/resources/testfragments/super_simple.c3 index 1cb0a1e29..3669f1269 100644 --- a/resources/testfragments/super_simple.c3 +++ b/resources/testfragments/super_simple.c3 @@ -3,6 +3,11 @@ module bar; typedef int as Bob; +func int! testThrow4(int x) +{ + return x > 4 ? TestErr1! : TestErr2!; +} + struct Test { int a; @@ -152,11 +157,11 @@ func void testIf() printf("No: %d/%d\n", x, y); } int! z = 67; - /* + try (int j = z, int k = z + 1) { printf("Check: %d %d\n", j, k); - }*/ + } try (z) { printf("Show :%d", z); @@ -237,7 +242,7 @@ func void enumInferenceTest() func void switchTest() { -/* + switch FOO: (cast(1, int)) { case 1: @@ -251,7 +256,7 @@ func void switchTest() next 2; case 4: printf("4\n"); - }*/ + } } func int jumptest() @@ -300,13 +305,6 @@ func int testReturnWithOtherAtEnd() if (i == 10) i++; i = i + 2; } -/* -func int testReturnWithError() throws Error -{ - int i = 0; - throw Error.NO_SUCH_FILE; - i = i + 1; -}*/ func int testReturnWithConditional() { @@ -780,7 +778,7 @@ func void show() } func void testAllErrors() { -/* + printf("Try test all\n"); int! i = 7; int*! iptr = &i; @@ -789,7 +787,7 @@ func void testAllErrors() { printf("Unexpected error!\n"); } - catch (int i = **iptrptr) + catch (i = **iptrptr) { printf("Unexpected error!\n"); } @@ -847,15 +845,23 @@ func void testAllErrors() printf("No error!\n"); int! flow = 1; catch (flow) return; - int xy = flow;*/ + int xy = flow; + + catch (err = i) return; + if (i > 0) + { + printf("Ok!\n"); + } + i = TestErr1!; +/* Error if (i > 0) + { + printf("Not ok!\n"); + }*/ + } -/* -func int! testThrow4(int x) -{ - return x > 4 ? TestErr1! : TestErr2!; -} + func int! testThrow6(int x) @@ -871,31 +877,23 @@ func int! testThrow(int x) if (x < 0) return TestErr1!; return x * x; } -*/ - -/* func int! oekt() { - int z = testThrow(-1) else goto NEXT; + int z = testThrow(-1) else return 1; printf("Skipped.\n"); - NEXT: int! x = testThrow(-3); catch (err = x) { - printf("An error %p\n", cast(err, usize)); +// printf("An error %p\n", cast(err, usize)); return err!; } return x; } -*/ -/* func int! testThrowAny(int x) { if (x < 0) return TestErr1!; return x * x; } -*/ -/* func void testErrorBug() { printf("Test error multi\n"); @@ -905,8 +903,8 @@ func void testErrorBug() case TestErr1: printf("Expected particular error.\n"); default: - error foo = Err.TEST_ERR1; - printf("Not expected %p != %p\n", cast(e, usize), cast(foo, usize)); + error foo = TestErr2{}; + //printf("Not expected %p != %p\n", cast(e, usize), cast(foo, usize)); printf("Unexpected any error error.\n"); } printf("End\n"); @@ -922,21 +920,18 @@ func void testErrorMulti() z = oekt(); printf("Got here\n"); } - switch (e = z) + catch (e = z) { case TestErr1: printf("Expected particular error.\n"); default: - error foo = Err.TEST_ERR1; - printf("Not expected %p != %p\n", usize(e), usize(foo)); + error foo = TestErr1{}; +// printf("Not expected %p != %p\n", cast(e, usize), cast(foo, usize)); printf("Unexpected any error error.\n"); } printf("End\n"); } -*/ - -/* func void! throwAOrB(int i) { printf("AB\n"); @@ -947,7 +942,7 @@ func void! throwAOrB(int i) if (i == 2) return TestErr2!; printf("None\n"); } -*/ + struct ThrowsDone { long x; @@ -957,7 +952,6 @@ struct ThrowsDone } ThrowsDone throwsDone; -/* func void testErrors() { @@ -976,17 +970,14 @@ func void testErrors() printf("Begin\n"); int! y = testThrow(-1); - if (y) + try (y) { printf("Value was %d, expected 9.\n", y); printf("Didn't expect this one.\n"); } - else + catch(y) { - catch(y) - { - printf("Expected this catch.\n"); - } + printf("Expected this catch.\n"); } y = testThrow(-1); @@ -994,26 +985,26 @@ func void testErrors() { printf("Particular error.\n"); } - // testErrorMulti(); + testErrorMulti(); catch (throwAOrB(1)) { - case Err: + case TestErr1: printf("A1\n"); - case Err2: + case TestErr2: printf("A2\n"); } catch (throwAOrB(2)) { - case Err: + case TestErr1: printf("B1\n"); - case Err2: + case TestErr2: printf("B2\n"); } printf("Throws: %d\n", throwsDone.times); printf("End of errors\n"); } -*/ + macro void arrayCallMacro($x) { printf("Array call: %d, %d\n", $x[0], $x[1]); @@ -1075,7 +1066,7 @@ func void testArray() } } -func void testBreak() +func void testBreak1() { for FOO: (int i = 0; i < 10; i++) { @@ -1398,6 +1389,7 @@ func int main(int x) testMethodFunctions(); testTypeValues(); int efd = 9; + uint fefoek = 1; testIf(); printf("Helo: %d\n", efd + cast(fefoek, int)); @@ -1567,9 +1559,9 @@ func void test2(int* x, int y, int z) j1 = *x; } - func void testBreak() { + defer printf("ALL TESTS DONE\n"); int i = 0; int j = 0; @@ -1816,5 +1808,4 @@ func void testBreak() default: printf("WAAAIT\n"); } - } \ No newline at end of file diff --git a/src/compiler/ast.c b/src/compiler/ast.c index 11b12abd3..1a13a0670 100644 --- a/src/compiler/ast.c +++ b/src/compiler/ast.c @@ -4,9 +4,9 @@ #include "compiler_internal.h" -static void fprint_asts_recursive(FILE *file, Ast **asts, int indent); -static void fprint_decl_list(FILE *file, Decl **decls, int indent); -static void fprint_ast_recursive(FILE *file, Ast *ast, int indent); +static void fprint_asts_recursive(Context *context, FILE *file, Ast **asts, int indent); +static void fprint_decl_list(Context *context, FILE *file, Decl **decls, int indent); +static void fprint_ast_recursive(Context *context, FILE *file, Ast *ast, int indent); #define DUMP(text) do { fprintf_indented(file, indent, text); fprintf(file, "\n"); } while(0) #define DUMPF(text, ...) do { fprintf_indented(file, indent, text, __VA_ARGS__); fprintf(file, "\n"); } while(0) @@ -14,21 +14,22 @@ static void fprint_ast_recursive(FILE *file, Ast *ast, int indent); #define DUMPFI(text, ...) do { fprintf_indented(file, indent + 1, text, __VA_ARGS__); fprintf(file, "\n"); } while(0) #define DUMPE() fprint_endparen(file, indent) #define DUMPEND() fprint_endparen(file, indent); return -#define DUMPEXPR(_expr) fprint_expr_recursive(file, _expr, indent + 1) -#define DUMPAST(_ast) fprint_ast_recursive(file, _ast, indent + 1) -#define DUMPASTS(_asts) fprint_asts_recursive(file, _asts, indent + 1) -#define DUMPTI(_type_info) fprint_type_info_recursive(file, _type_info, indent + 1) -#define DUMPTYPE(_type) fprint_type_recursive(file, _type, indent + 1) -#define DUMPDECLS(_decls) fprint_decl_list(file, _decls, indent + 1) -#define DUMPDECL(_decl) fprint_decl_recursive(file, _decl, indent + 1) +#define DUMPEXPR(_expr) fprint_expr_recursive(context, file, _expr, indent + 1) +#define DUMPAST(_ast) fprint_ast_recursive(context, file, _ast, indent + 1) +#define DUMPASTS(_asts) fprint_asts_recursive(context, file, _asts, indent + 1) +#define DUMPTI(_type_info) fprint_type_info_recursive(context, file, _type_info, indent + 1) +#define DUMPTYPE(_type) fprint_type_recursive(context, file, _type, indent + 1) +#define DUMPDECLS(_decls) fprint_decl_list(context, file, _decls, indent + 1) +#define DUMPDECL(_decl) fprint_decl_recursive(context, file, _decl, indent + 1) -Decl *decl_new(DeclKind decl_kind, Token name, Visibility visibility) +Decl *decl_new(DeclKind decl_kind, TokenId name, Visibility visibility) { - Decl *decl = CALLOCS(Decl); + Decl *decl = decl_calloc(); decl->decl_kind = decl_kind; - decl->name_span = name.span; - decl->span = name.span; - decl->name = name.string; + decl->name_token = name; + decl->span = source_span_from_token_id(name); + decl->name = name.index ? TOKSTR(name) : "anon"; + decl->member_decl.anonymous = name.index == 0; decl->visibility = visibility; return decl; } @@ -53,7 +54,7 @@ void decl_set_external_name(Decl *decl) decl->external_name = symtab_add(buffer, len, fnv1a(buffer, len), &type); } -Decl *decl_new_with_type(Token name, DeclKind decl_type, Visibility visibility) +Decl *decl_new_with_type(TokenId name, DeclKind decl_type, Visibility visibility) { Decl *decl = decl_new(decl_type, name, visibility); TypeKind kind = TYPE_POISONED; @@ -92,7 +93,7 @@ Decl *decl_new_with_type(Token name, DeclKind decl_type, Visibility visibility) case DECL_LABEL: UNREACHABLE } - Type *type = type_new(kind, name.string); + Type *type = type_new(kind, TOKSTR(name)); type->canonical = type; type->decl = decl; decl->type = type; @@ -124,7 +125,7 @@ const char *decl_var_to_string(VarDeclKind kind) static Decl poison_decl = { .decl_kind = DECL_POISONED, .resolve_status = RESOLVE_DONE }; Decl *poisoned_decl = &poison_decl; -Decl *decl_new_var(Token name, TypeInfo *type, VarDeclKind kind, Visibility visibility) +Decl *decl_new_var(TokenId name, TypeInfo *type, VarDeclKind kind, Visibility visibility) { Decl *decl = decl_new(DECL_VAR, name, visibility); decl->var.kind = kind; @@ -144,7 +145,8 @@ Decl *struct_find_name(Decl *decl, const char* name) Decl *member = compare_members[i]; if (member->member_decl.anonymous) { - Decl *found = struct_find_name(member, name); + assert(member->decl_kind == DECL_MEMBER); + Decl *found = struct_find_name(member->member_decl.type_info->type->decl, name); if (found) return found; } else if (member->name == name) return member; @@ -152,9 +154,9 @@ Decl *struct_find_name(Decl *decl, const char* name) return NULL; } -Expr *expr_new(ExprKind kind, SourceRange start) +Expr *expr_new(ExprKind kind, SourceSpan start) { - Expr *expr = CALLOCS(Expr); + Expr *expr = expr_calloc(); expr->expr_kind = kind; expr->span = start; expr->type = NULL; @@ -308,9 +310,9 @@ void fprint_endparen(FILE *file, int indent) fprintf(file, ")\n"); } -void fprint_decl_recursive(FILE *file, Decl *decl, int indent); +void fprint_decl_recursive(Context *context, FILE *file, Decl *decl, int indent); -void fprint_type_recursive(FILE *file, Type *type, int indent) +void fprint_type_recursive(Context *context, FILE *file, Type *type, int indent) { if (!type) { @@ -409,7 +411,7 @@ const char *resolve_status_to_string(ResolveStatus status) } -void fprint_type_info_recursive(FILE *file, TypeInfo *type_info, int indent) +void fprint_type_info_recursive(Context *context, FILE *file, TypeInfo *type_info, int indent) { if (!type_info) { @@ -432,10 +434,10 @@ void fprint_type_info_recursive(FILE *file, TypeInfo *type_info, int indent) case TYPE_INFO_IDENTIFIER: if (type_info->unresolved.path) { - DUMPF("(unresolved %s::%s)\n", type_info->unresolved.path->module, type_info->unresolved.name_loc.string); + DUMPF("(unresolved %s::%s)\n", type_info->unresolved.path->module, TOKSTR(type_info->unresolved.name_loc)); break; } - DUMPF("(unresolved %s)", type_info->unresolved.name_loc.string); + DUMPF("(unresolved %s)", TOKSTR(type_info->unresolved.name_loc)); break; case TYPE_INFO_VARARRAY: DUMP("(vararray"); @@ -473,7 +475,7 @@ void fprint_type_info_recursive(FILE *file, TypeInfo *type_info, int indent) DUMPEND(); } -void fprint_expr_common(FILE *file, Expr *expr, int indent) +void fprint_expr_common(Context *context, FILE *file, Expr *expr, int indent) { switch (expr->resolve_status) { @@ -490,9 +492,9 @@ void fprint_expr_common(FILE *file, Expr *expr, int indent) UNREACHABLE } -#define DUMPEXPC(_expr) fprint_expr_common(file, _expr, indent + 1) +#define DUMPEXPC(_expr) fprint_expr_common(context, file, _expr, indent + 1) -void fprint_expr_recursive(FILE *file, Expr *expr, int indent) +void fprint_expr_recursive(Context *context, FILE *file, Expr *expr, int indent) { if (!expr) return; switch (expr->expr_kind) @@ -569,12 +571,12 @@ void fprint_expr_recursive(FILE *file, Expr *expr, int indent) DUMPEXPR(expr->trycatch_expr); DUMPEND(); case EXPR_TYPE_ACCESS: - DUMPF("(typeaccess .%s", expr->type_access.name.string); + DUMPF("(typeaccess .%s", TOKSTR(expr->type_access.name)); DUMPEXPC(expr); DUMPTI(expr->type_access.type); DUMPEND(); case EXPR_ACCESS: - DUMPF("(access .%s", expr->access_expr.sub_element.string); + DUMPF("(access .%s", TOKSTR(expr->access_expr.sub_element)); DUMPEXPC(expr); DUMPEXPR(expr->access_expr.parent); DUMPEND(); @@ -679,7 +681,7 @@ void fprint_expr_recursive(FILE *file, Expr *expr, int indent) DUMPTI(expr->struct_value_expr.type); VECEACH(expr->expression_list, i) { - fprint_expr_recursive(file, expr->expression_list[i], indent + 1); + fprint_expr_recursive(context, file, expr->expression_list[i], indent + 1); } DUMPEND(); case EXPR_POISONED: @@ -714,7 +716,7 @@ void fprint_expr_recursive(FILE *file, Expr *expr, int indent) } -void fprint_func_signature(FILE *file, FunctionSignature *signature, int indent) +void fprint_func_signature(Context *context, FILE *file, FunctionSignature *signature, int indent) { DUMP("(func-sig"); DUMPTI(signature->rtype); @@ -734,7 +736,7 @@ void fprint_func_signature(FILE *file, FunctionSignature *signature, int indent) DUMPEND(); } -void fprint_decl_recursive(FILE *file, Decl *decl, int indent) +void fprint_decl_recursive(Context *context, FILE *file, Decl *decl, int indent) { if (!decl) return; switch (decl->decl_kind) @@ -782,7 +784,7 @@ void fprint_decl_recursive(FILE *file, Decl *decl, int indent) DUMPE(); indent--; } - fprint_func_signature(file, &decl->func.function_signature, indent + 1); + fprint_func_signature(context, file, &decl->func.function_signature, indent + 1); if (decl->func.body) DUMPAST(decl->func.body); DUMPEND(); case DECL_STRUCT: @@ -817,7 +819,7 @@ void fprint_decl_recursive(FILE *file, Decl *decl, int indent) DUMP("(params"); VECEACH(decl->generic_decl.parameters, i) { - DUMPFI("%s", decl->generic_decl.parameters[i].string); + DUMPFI("%s", TOKSTR(decl->generic_decl.parameters[i])); } DUMPE(); DUMP("(cases"); @@ -829,7 +831,7 @@ void fprint_decl_recursive(FILE *file, Decl *decl, int indent) DUMPF("(typedef %s", decl->name); if (decl->typedef_decl.is_func) { - fprint_func_signature(file, &decl->typedef_decl.function_signature, indent + 1); + fprint_func_signature(context, file, &decl->typedef_decl.function_signature, indent + 1); } else { @@ -910,23 +912,23 @@ void fprint_decl_recursive(FILE *file, Decl *decl, int indent) UNREACHABLE } -static void fprint_decl_list(FILE *file, Decl **decls, int indent) +static void fprint_decl_list(Context *context, FILE *file, Decl **decls, int indent) { VECEACH(decls, i) { - fprint_decl_recursive(file, decls[i], indent); + fprint_decl_recursive(context, file, decls[i], indent); } } -static void fprint_asts_recursive(FILE *file, Ast **asts, int indent) +static void fprint_asts_recursive(Context *context, FILE *file, Ast **asts, int indent) { VECEACH(asts, i) { - fprint_ast_recursive(file, asts[i], indent); + fprint_ast_recursive(context, file, asts[i], indent); } } -static void fprint_ast_recursive(FILE *file, Ast *ast, int indent) +static void fprint_ast_recursive(Context *context, FILE *file, Ast *ast, int indent) { if (!ast) return; switch (ast->ast_kind) @@ -943,7 +945,7 @@ static void fprint_ast_recursive(FILE *file, Ast *ast, int indent) return; } DUMP("(compound\n"); - fprint_asts_recursive(file, ast->compound_stmt.stmts, indent + 1); + fprint_asts_recursive(context, file, ast->compound_stmt.stmts, indent + 1); DUMPEND(); case AST_DEFINE_STMT: DUMP("(define"); @@ -967,13 +969,13 @@ static void fprint_ast_recursive(FILE *file, Ast *ast, int indent) DUMPAST(ast->scoped_stmt.stmt); DUMPEND(); case AST_CT_FOR_STMT: - if (ast->ct_for_stmt.index.string) + if (ast->ct_for_stmt.index.index) { - DUMPF("($for %s, %s\n", ast->ct_for_stmt.index.string, ast->ct_for_stmt.value.string); + DUMPF("($for %s, %s\n", TOKSTR(ast->ct_for_stmt.index), TOKSTR(ast->ct_for_stmt.value)); } else { - DUMPF("($for %s\n", ast->ct_for_stmt.value.string); + DUMPF("($for %s\n", TOKSTR(ast->ct_for_stmt.value)); } DUMPEXPR(ast->ct_for_stmt.expr); DUMPAST(ast->ct_for_stmt.body); @@ -1088,8 +1090,8 @@ static void fprint_ast_recursive(FILE *file, Ast *ast, int indent) } UNREACHABLE } -void fprint_decl(FILE *file, Decl *dec) +void fprint_decl(Context *context, FILE *file, Decl *dec) { - fprint_decl_recursive(file, dec, 0); + fprint_decl_recursive(context, file, dec, 0); } diff --git a/src/compiler/compiler.c b/src/compiler/compiler.c index ae1e3ac48..73cb297a9 100644 --- a/src/compiler/compiler.c +++ b/src/compiler/compiler.c @@ -7,10 +7,29 @@ Compiler compiler; +Vmem ast_arena; +Vmem expr_arena; +Vmem sourceloc_arena; +Vmem toktype_arena; +Vmem tokdata_arena; +Vmem decl_arena; +Vmem type_info_arena; + void compiler_init(void) { stable_init(&compiler.modules, 64); stable_init(&compiler.global_symbols, 0x1000); + vmem_init(&ast_arena, 4 * 1024); + vmem_init(&expr_arena, 4 * 1024); + vmem_init(&decl_arena, 1024); + vmem_init(&sourceloc_arena, 4 * 1024); + vmem_init(&toktype_arena, 4 * 1024); + vmem_init(&tokdata_arena, 4 * 1024); + vmem_init(&type_info_arena, 1024); + // Create zero index value. + SourceLocation *loc = sourceloc_calloc(); + char *token_type = toktype_calloc(); + TokenData *data = tokdata_calloc(); } static void compiler_lex(BuildTarget *target) @@ -25,7 +44,7 @@ static void compiler_lex(BuildTarget *target) printf("# %s\n", file->full_path); while (1) { - Token token = lexer_scan_token(&lexer); + Token token = lexer_advance(&lexer); printf("%s ", token_type_to_string(token.type)); if (token.type == TOKEN_EOF) break; } @@ -101,6 +120,15 @@ void compiler_compile(BuildTarget *target) Context *context = contexts[i]; llvm_codegen(context); } + + printf("-- AST/EXPR INFO -- \n"); + printf(" * Ast memory use: %llukb\n", (unsigned long long)ast_arena.allocated / 1024); + printf(" * Decl memory use: %llukb\n", (unsigned long long)decl_arena.allocated / 1024); + printf(" * Expr memory use: %llukb\n", (unsigned long long)expr_arena.allocated / 1024); + printf(" * TypeInfo memory use: %llukb\n", (unsigned long long)type_info_arena.allocated / 1024); + printf(" * Token memory use: %llukb\n", (unsigned long long)(toktype_arena.allocated) / 1024); + printf(" * Sourceloc memory use: %llukb\n", (unsigned long long)(sourceloc_arena.allocated) / 1024); + printf(" * Token data memory use: %llukb\n", (unsigned long long)(tokdata_arena.allocated) / 1024); print_arena_status(); exit(EXIT_SUCCESS); } @@ -173,9 +201,9 @@ void compile_files(BuildTarget *target) } -Decl *compiler_find_symbol(Token token) +Decl *compiler_find_symbol(const char *string) { - return stable_get(&compiler.global_symbols, token.string); + return stable_get(&compiler.global_symbols, string); } void compiler_add_type(Type *type) @@ -192,7 +220,7 @@ Module *compiler_find_or_create_module(Path *module_name) { // We might have gotten an auto-generated module, if so // update the path here. - if (module->name->span.loc == INVALID_LOC && module_name->span.loc != INVALID_LOC) + if (module->name->span.loc.index == INVALID_TOKEN_ID.index && module_name->span.loc.index != INVALID_TOKEN_ID.index) { module->name = module_name; } @@ -206,7 +234,7 @@ Module *compiler_find_or_create_module(Path *module_name) stable_init(&module->symbols, 0x10000); stable_set(&compiler.modules, module_name->module, module); // Now find the possible parent array: - Path *parent_path = path_find_parent_path(module_name); + Path *parent_path = path_find_parent_path(NULL, module_name); if (parent_path) { // Get the parent diff --git a/src/compiler/compiler_internal.h b/src/compiler/compiler_internal.h index 1f3880e29..dfe3a1641 100644 --- a/src/compiler/compiler_internal.h +++ b/src/compiler/compiler_internal.h @@ -13,11 +13,19 @@ #include "compiler.h" #include "enums.h" #include "target.h" +#include "utils/malloc.h" typedef uint32_t SourceLoc; +typedef struct +{ + unsigned index; +} TokenId; + #define INVALID_LOC UINT32_MAX -#define INVALID_RANGE ((SourceRange){ .loc = UINT32_MAX }) -#define EMPTY_TOKEN ((Token) { .string = NULL }) +#define NO_TOKEN_ID ((TokenId) { 0 }) +#define NO_TOKEN ((Token) { .type = TOKEN_INVALID_TOKEN }) +#define INVALID_TOKEN_ID ((TokenId) { UINT32_MAX }) +#define INVALID_RANGE ((SourceSpan){ INVALID_TOKEN_ID, INVALID_TOKEN_ID }) #define MAX_LOCALS 0xFFFF #define MAX_FLAGS 0xFFFF #define MAX_SCOPE_DEPTH 0xFF @@ -28,6 +36,7 @@ typedef uint32_t SourceLoc; #define MAX_PARAMS 512 #define MAX_ERRORS 0xFFFF #define MAX_ALIGNMENT (1U << 29U) +#define LEXER_VM_SIZE_MB 2048 typedef struct _Ast Ast; typedef struct _Decl Decl; @@ -36,6 +45,8 @@ typedef struct _Expr Expr; typedef struct _Module Module; typedef struct _Type Type; +typedef unsigned AstId; + typedef struct _BigInt { unsigned digit_count; @@ -68,25 +79,44 @@ typedef struct typedef struct { - SourceLoc loc; - SourceLoc end_loc; -} SourceRange; + TokenId loc; + TokenId end_loc; +} SourceSpan; typedef struct { - Ast *start; - Ast *end; + AstId start; + AstId end; } DeferList; + typedef struct { - SourceRange span; + const char *contents; + char *name; + char *dir_path; + const char *full_path; + SourceLoc start_id; + SourceLoc end_id; + SourceLoc *lines; + SourceLoc current_line_start; + unsigned token_start_id; +} File; + +typedef struct +{ + File *file; + uint32_t line; + uint32_t col; + uint32_t start; + uint32_t length; +} SourceLocation; + + +typedef struct +{ + TokenId id; TokenType type : 8; - union - { - const char *string; - const char* start; - }; } Token; typedef struct _Diagnostics @@ -110,18 +140,6 @@ typedef struct } STable; -typedef struct -{ - const char *contents; - char *name; - char *dir_path; - const char *full_path; - SourceLoc start_id; - SourceLoc end_id; - SourceLoc *lines; - SourceLoc current_line_start; -} File; - typedef struct { File *file; @@ -131,9 +149,11 @@ typedef struct const char *start; } SourcePosition; + + typedef struct _Path { - SourceRange span; + SourceSpan span; const char *module; uint32_t len; } Path; @@ -166,7 +186,7 @@ typedef struct typedef struct { - Token name_loc; + TokenId name_loc; Path *path; } TypeUnresolved; @@ -210,7 +230,7 @@ struct _TypeInfo ResolveStatus resolve_status : 2; Type *type; TypeInfoKind kind; - SourceRange span; + SourceSpan span; union { TypeUnresolved unresolved; @@ -227,7 +247,7 @@ struct _TypeInfo typedef struct { Path *path; - Token name; + TokenId name; union { Expr *expr; @@ -238,7 +258,7 @@ typedef struct typedef struct { Path *path; - Token symbol; + TokenId symbol; bool aliased; } ImportDecl; @@ -364,19 +384,19 @@ typedef struct typedef struct { struct _Ast **cases; - Token *parameters; + TokenId *parameters; TypeInfo *rtype; // May be null! Path *path; // For redefinition } GenericDecl; typedef struct { - Ast *defer; + AstId defer; + bool next_target : 1; void *break_target; void *continue_target; unsigned scope_id; - bool next_target : 1; - Ast *parent; + AstId parent; } LabelDecl; @@ -392,8 +412,8 @@ typedef struct typedef struct _Decl { const char *name; - SourceRange name_span; - SourceRange span; + TokenId name_token; + SourceSpan span; const char *external_name; DeclKind decl_kind : 6; Visibility visibility : 2; @@ -460,7 +480,6 @@ typedef struct Expr *else_expr; Ast *else_stmt; }; - void *jump_target; } ExprElse; typedef struct @@ -468,7 +487,7 @@ typedef struct TypeInfo *type; union { - Token name; + TokenId name; Decl *decl; }; } ExprTypeAccess; @@ -530,7 +549,7 @@ typedef struct Expr *parent; union { - Token sub_element; + TokenId sub_element; Decl *ref; }; } ExprAccess; @@ -609,7 +628,7 @@ typedef struct typedef struct { const char *name; - SourceRange span; + TokenId span; } Label; struct _Expr @@ -617,7 +636,7 @@ struct _Expr ExprKind expr_kind : 8; ResolveStatus resolve_status : 3; bool failable : 1; - SourceRange span; + SourceSpan span; Type *type; union { ExprDesignatedInit designated_init_expr; @@ -663,12 +682,19 @@ typedef struct typedef struct { Expr *expr; // May be NULL - Ast *defer; + AstId defer; } AstReturnStmt; typedef struct { + bool has_break : 1; + bool no_exit : 1; Decl *label; +} FlowCommon; + +typedef struct +{ + FlowCommon flow; Expr *cond; Ast *body; void *break_block; @@ -677,6 +703,7 @@ typedef struct typedef struct { + FlowCommon flow; DeferList expr_defer; DeferList body_defer; union @@ -688,7 +715,6 @@ typedef struct }; struct { - Decl *label; Expr *expr; Ast *body; }; @@ -697,7 +723,7 @@ typedef struct typedef struct { - Decl *label; + FlowCommon flow; Expr *cond; Ast *then_body; Ast *else_body; @@ -720,18 +746,28 @@ typedef struct typedef struct { - Decl *label; + FlowCommon flow; + AstId defer; Expr *cond; Ast **cases; - void *retry_block; - void *exit_block; - void *retry_var; - Ast *defer; + union + { + struct + { + unsigned scope_id; + }; + struct + { + void *retry_block; + void *exit_block; + void *retry_var; + } codegen; + }; } AstSwitchStmt; typedef struct { - Decl *label; + FlowCommon flow; Expr *init; Expr *cond; Expr *incr; @@ -742,15 +778,17 @@ typedef struct typedef struct { + AstId prev_defer; Ast *body; // Compound statement - Ast *prev_defer; } AstDeferStmt; typedef struct { + FlowCommon flow; bool is_switch : 1; bool has_err_var : 1; - Decl *label; + unsigned scope_id; + AstId defer; union { Expr *catchable; @@ -762,7 +800,6 @@ typedef struct Ast **cases; }; void *block; - Ast *defer; } AstCatchStmt; @@ -789,8 +826,8 @@ typedef struct typedef struct { - Token index; - Token value; + TokenId index; + TokenId value; Expr *expr; Ast *body; } AstCtForStmt; @@ -801,7 +838,7 @@ typedef struct union { Label label; - Ast *ast; + AstId ast; }; DeferList defers; } AstContinueBreakStmt; @@ -823,7 +860,7 @@ typedef struct }; struct { - Ast *case_switch_stmt; + AstId case_switch_stmt; Expr *switch_expr; }; }; @@ -833,8 +870,8 @@ typedef struct typedef struct { Expr *expr; - Token alias; - Token constraints; + TokenId alias; + TokenId constraints; } AsmOperand; typedef struct @@ -847,8 +884,8 @@ typedef struct { AsmOperand *inputs; AsmOperand *outputs; - Token *clobbers; - Token *labels; + TokenId **clobbers; + TokenId **labels; } AsmParams; typedef struct @@ -857,15 +894,17 @@ typedef struct bool is_inline : 1; bool is_goto : 1; AsmParams *params; - Token *instructions; + TokenId **instructions; } AstAsmStmt; + typedef struct _Ast { - SourceRange span; + SourceSpan span; AstKind ast_kind : 8; union { + FlowCommon flow; // Shared struct AstAsmStmt asm_stmt; // 24 AstCompoundStmt compound_stmt; // 16 Decl *declare_stmt; // 8 @@ -917,22 +956,30 @@ typedef struct _Module typedef struct _DynamicScope { unsigned scope_id; + bool allow_dead_code : 1; + bool jump_end : 1; ScopeFlags flags; - ScopeFlags flags_created; Decl **local_decl_start; DeferList defers; Ast *current_defer; - ExitType exit; - const char* label; } DynamicScope; +typedef union +{ + const char *string; + long double value; +} TokenData; + typedef struct { + unsigned lexer_index; const char *file_begin; const char *lexing_start; const char *current; uint16_t source_file; + unsigned current_line; + const char *line_start; File *current_file; SourceLoc last_in_range; } Lexer; @@ -940,11 +987,10 @@ typedef struct typedef struct _Context { - unsigned numbering; unsigned current_block; BuildTarget *target; Path *module_name; - Token* module_parameters; + TokenId* module_parameters; File* file; Decl** imports; Module *module; @@ -962,13 +1008,13 @@ typedef struct _Context Token *trailing_comment; Token *next_lead_comment; unsigned scope_id; - Ast *break_target; - Ast *break_defer; - Ast *continue_target; - Ast *continue_defer; - Ast *next_target; + AstId break_target; + AstId break_defer; + AstId continue_target; + AstId continue_defer; + AstId next_target; Ast *next_switch; - Ast *next_defer; + AstId next_defer; DynamicScope *current_scope; struct { @@ -1000,7 +1046,6 @@ typedef struct _Context }; STable scratch_table; Lexer lexer; - SourceLoc prev_tok_end; Token tok; Token next_tok; struct @@ -1013,6 +1058,7 @@ typedef struct _Context Token *lead_comment; Token *trailing_comment; Token *next_lead_comment; + unsigned lexer_index; } stored; } Context; @@ -1055,30 +1101,33 @@ extern const char *kw_main; extern const char *kw_sizeof; extern const char *kw_offsetof; -#define AST_NEW_TOKEN(_kind, _token) new_ast(_kind, _token.span) +#define AST_NEW_TOKEN(_kind, _token) new_ast(_kind, source_span_from_token_id(_token.id)) #define AST_NEW(_kind, _loc) new_ast(_kind, _loc) +ARENA_DEF(ast, Ast); +ARENA_DEF(expr, Expr); +ARENA_DEF(sourceloc, SourceLocation); +ARENA_DEF(toktype, char); +ARENA_DEF(tokdata, TokenData); +ARENA_DEF(decl, Decl); +ARENA_DEF(type_info, TypeInfo); + static inline bool ast_ok(Ast *ast) { return ast == NULL || ast->ast_kind != AST_POISONED; } static inline bool ast_poison(Ast *ast) { ast->ast_kind = AST_POISONED; return false; } -static inline Ast *new_ast(AstKind kind, SourceRange range) +static inline Ast *new_ast(AstKind kind, SourceSpan range) { - Ast *ast = CALLOCS(Ast); + Ast *ast = ast_calloc(); ast->span = range; ast->ast_kind = kind; return ast; } -static inline Ast *extend_ast(Ast *ast, Token token) -{ - ast->span.end_loc = token.span.end_loc; - return ast; -} static inline Ast *extend_ast_with_prev_token(Context *context, Ast *ast) { - ast->span.end_loc = context->prev_tok_end; + ast->span.end_loc.index = context->tok.id.index - 1; return ast; } @@ -1127,12 +1176,11 @@ static inline bool builtin_may_bit_negate(Type *canonical) } -bool cast_implicit(Expr *expr, Type *to_type); -bool cast(Expr *expr, Type *to_type, CastType cast_type); -bool cast_binary_arithmetic(Expr *left, Expr *right, const char *action); +bool cast_implicit(Context *context, Expr *expr, Type *to_type); +bool cast(Context *context, Expr *expr, Type *to_type, CastType cast_type); CastKind cast_to_bool_kind(Type *type); -bool cast_implicitly_to_runtime(Expr *expr); +bool cast_implicitly_to_runtime(Context *context, Expr *expr); void llvm_codegen(Context *context); void llvm_codegen_setup(); @@ -1144,7 +1192,7 @@ bool sema_analyse_expr(Context *context, Type *to, Expr *expr); bool sema_analyse_decl(Context *context, Decl *decl); void compiler_add_type(Type *type); -Decl *compiler_find_symbol(Token token); +Decl *compiler_find_symbol(const char *name); Module *compiler_find_or_create_module(Path *module_name); void compiler_register_public_symbol(Decl *decl); @@ -1153,14 +1201,17 @@ void context_register_global_decl(Context *context, Decl *decl); void context_register_external_symbol(Context *context, Decl *decl); bool context_add_import(Context *context, Path *path, Token symbol, Token alias); bool context_set_module_from_filename(Context *context); -bool context_set_module(Context *context, Path *path, Token *generic_parameters); +bool context_set_module(Context *context, Path *path, TokenId *generic_parameters); void context_print_ast(Context *context, FILE *file); #pragma mark --- Decl functions -Decl *decl_new(DeclKind decl_kind, Token name, Visibility visibility); -Decl *decl_new_with_type(Token name, DeclKind decl_type, Visibility visibility); -Decl *decl_new_var(Token name, TypeInfo *type, VarDeclKind kind, Visibility visibility); +Decl *decl_new(DeclKind decl_kind, TokenId name, Visibility visibility); +Decl *decl_new_with_type(TokenId name, DeclKind decl_type, Visibility visibility); +Decl *decl_new_var(TokenId name, TypeInfo *type, VarDeclKind kind, Visibility visibility); +#define DECL_NEW(_kind, _vis) decl_new(_kind, context->tok.id, _vis) +#define DECL_NEW_WITH_TYPE(_kind, _vis) decl_new_with_type(context->tok.id, _kind, _vis) +#define DECL_NEW_VAR(_type, _kind, _vis) decl_new_var(context->tok.id, _type, _kind, _vis) void decl_set_external_name(Decl *decl); const char *decl_var_to_string(VarDeclKind kind); static inline Decl *decl_raw(Decl *decl) @@ -1188,18 +1239,17 @@ static inline DeclKind decl_from_token(TokenType type) #pragma mark --- Diag functions void diag_reset(void); -void diag_error_range(SourceRange span, const char *message, ...); -void diag_verror_range(SourceRange span, const char *message, va_list args); +void diag_verror_range(SourceLocation *location, const char *message, va_list args); #define EXPR_NEW_EXPR(_kind, _expr) expr_new(_kind, _expr->span) -#define EXPR_NEW_TOKEN(_kind, _tok) expr_new(_kind, _tok.span) -Expr *expr_new(ExprKind kind, SourceRange start); +#define EXPR_NEW_TOKEN(_kind, _tok) expr_new(_kind, source_span_from_token_id(_tok.id)) +Expr *expr_new(ExprKind kind, SourceSpan start); static inline bool expr_ok(Expr *expr) { return expr == NULL || expr->expr_kind != EXPR_POISONED; } static inline bool expr_poison(Expr *expr) { expr->expr_kind = EXPR_POISONED; expr->resolve_status = RESOLVE_DONE; return false; } static inline void expr_replace(Expr *expr, Expr *replacement) { - SourceRange loc = expr->span; + SourceSpan loc = expr->span; *expr = *replacement; expr->span = loc; } @@ -1212,34 +1262,56 @@ bool expr_const_int_overflowed(const ExprConst *expr); bool expr_const_compare(const ExprConst *left, const ExprConst *right, BinaryOp op); const char *expr_const_to_error_string(const ExprConst *expr); -void fprint_decl(FILE *file, Decl *dec); -void fprint_type_info_recursive(FILE *file, TypeInfo *type_info, int indent); -void fprint_expr_recursive(FILE *file, Expr *expr, int indent); +void fprint_decl(Context *context, FILE *file, Decl *dec); +void fprint_type_info_recursive(Context *context, FILE *file, TypeInfo *type_info, int indent); +void fprint_expr_recursive(Context *context, FILE *file, Expr *expr, int indent); #pragma mark --- Lexer functions -Token lexer_scan_asm(Lexer *lexer); -Token lexer_scan_asm_constraint(Lexer *lexer); -Token lexer_scan_token(Lexer *lexer); -Token lexer_scan_ident_test(Lexer *lexer, const char *scan); + +Token lexer_advance(Lexer *lexer); +bool lexer_scan_ident_test(Lexer *lexer, const char *scan); void lexer_init_for_test(Lexer *lexer, const char *text, size_t len); void lexer_init_with_file(Lexer *lexer, File *file); File* lexer_current_file(Lexer *lexer); +static inline SourceLocation *TOKILOC(TokenId token) { return sourcelocptr(token.index); } +static inline SourceLocation *TOKKLOC(Token token) { return sourcelocptr(token.id.index); } +static inline TokenData *tokendata_from_id(TokenId token) { return tokdataptr(token.index); } +#define TOKLOC(T) _Generic((T), TokenId: TOKILOC, Token: TOKKLOC)(T) +static inline const char *TOKISTR(TokenId token) { return tokendata_from_id(token)->string; } +static inline const char *TOKKSTR(Token token) { return tokendata_from_id(token.id)->string; } +#define TOKSTR(T) _Generic((T), TokenId: TOKISTR, Token: TOKKSTR)(T) + +static inline double TOKIREAL(TokenId token) { return tokendata_from_id(token)->value; } +static inline double TOKKREAL(Token token) { return tokendata_from_id(token.id)->value; } +#define TOKREAL(T) _Generic((T), TokenId: TOKIREAL, Token: TOKKREAL)(T) + +static inline TokenType TOKITYPE(TokenId token) { return toktypeptr(token.index)[0]; } +static inline TokenType TOKKTYPE(Token token) { return toktypeptr(token.id.index)[0]; } +#define TOKTYPE(T) _Generic((T), TokenId: TOKITYPE, Token: TOKKTYPE)(T) + +static inline uint32_t TOKILEN(TokenId token) { return TOKILOC(token)->length; } +static inline uint32_t TOKKLEN(Token token) { return TOKKLOC(token)->length; } +#define TOKLEN(T) _Generic((T), TokenId: TOKILEN, Token:TOKKLEN)(T) + +#define TOKVALID(_tok) (_tok.index != 0) Decl *module_find_symbol(Module *module, const char *symbol, ModuleSymbolSearch search); void parse_file(Context *context); -Path *path_create_from_string(const char *string, size_t len, SourceRange span); -Path *path_find_parent_path(Path *path); +Path *path_create_from_string(Context *context, const char *string, size_t len, SourceSpan span); +Path *path_find_parent_path(Context *context, Path *path); const char *resolve_status_to_string(ResolveStatus status); -#define SEMA_TOKEN_ERROR(_tok, ...) sema_error_range((_tok).span, __VA_ARGS__) -#define SEMA_ERROR(_node, ...) sema_error_range((_node)->span, __VA_ARGS__) -#define SEMA_PREV(_node, ...) sema_prev_at_range((_node)->span, __VA_ARGS__) +#define SEMA_TOKEN_ERROR(_tok, ...) sema_error_range3(source_span_from_token_id(_tok.id), __VA_ARGS__) +#define SEMA_TOKID_ERROR(_tok_id, ...) sema_error_range3(source_span_from_token_id(_tok_id), __VA_ARGS__) +#define SEMA_ERROR(_node, ...) sema_error_range3((_node)->span, __VA_ARGS__) +#define SEMA_PREV(_node, ...) sema_prev_at_range3((_node)->span, __VA_ARGS__) + void sema_analysis_pass_process_imports(Context *context); void sema_analysis_pass_conditional_compilation(Context *context); void sema_analysis_pass_decls(Context *context); @@ -1252,24 +1324,28 @@ bool sema_analyse_statement(Context *context, Ast *statement); Decl *sema_resolve_symbol(Context *context, const char *symbol, Path *path, Decl **ambiguous_other_decl); bool sema_resolve_type_info(Context *context, TypeInfo *type_info); bool sema_resolve_type_shallow(Context *context, TypeInfo *type_info); -void sema_error_at(SourceLoc loc, const char *message, ...); -void sema_error_range(SourceRange range, const char *message, ...); -void sema_verror_at(SourceLoc loc, const char *message, va_list args); -void sema_verror_range(SourceRange range, const char *message, va_list args); + +void sema_error_at_prev_end(Token token, const char *message, ...); + +void sema_error_range2(SourceLocation *location, const char *message, ...); +void sema_error_range3(SourceSpan location, const char *message, ...); + +void sema_verror_range(SourceLocation *location, const char *message, va_list args); void sema_error(Context *context, const char *message, ...); -void sema_prev_at_range(SourceRange span, const char *message, ...); -void sema_prev_at(SourceLoc loc, const char *message, ...); +void sema_prev_at_range3(SourceSpan span, const char *message, ...); void sema_shadow_error(Decl *decl, Decl *old); File *source_file_load(const char *filename, bool *already_loaded); -File *source_file_from_position(SourceLoc loc); void source_file_append_line_end(File *file, SourceLoc loc); SourcePosition source_file_find_position_in_file(File *file, SourceLoc loc); -SourcePosition source_file_find_position(SourceLoc loc); -SourceRange source_range_from_ranges(SourceRange first, SourceRange last); -#define RANGE_EXTEND_PREV(x) (x)->span.end_loc = context->prev_tok_end -static inline unsigned source_range_len(SourceRange range) { return range.end_loc - range.loc; } +static inline SourceSpan source_span_from_token_id(TokenId id) +{ + return (SourceSpan) { id, id }; +} + + +#define RANGE_EXTEND_PREV(x) ((x)->span.end_loc.index = context->tok.id.index - 1) void stable_init(STable *table, uint32_t initial_size); void *stable_set(STable *table, const char *key, void *value); @@ -1291,10 +1367,6 @@ bool token_is_type(TokenType type); bool token_is_any_type(TokenType type); bool token_is_symbol(TokenType type); const char *token_type_to_string(TokenType type); -static inline Token wrap(const char *string) -{ - return (Token) { .span = INVALID_RANGE, .type = TOKEN_IDENT, .string = string }; -} Type *type_get_ptr(Type *ptr_type); Type *type_get_subarray(Type *arr_type); @@ -1403,22 +1475,22 @@ static inline bool type_is_float(Type *type) return type->type_kind >= TYPE_F32 && type->type_kind <= TYPE_FXX; } -static inline TypeInfo *type_info_new(TypeInfoKind kind, SourceRange range) +static inline TypeInfo *type_info_new(TypeInfoKind kind, SourceSpan span) { - TypeInfo *type_info = CALLOCS(TypeInfo); + TypeInfo *type_info = type_info_calloc(); type_info->kind = kind; - type_info->span = range; + type_info->span = span; type_info->resolve_status = RESOLVE_NOT_DONE; return type_info; } -static inline TypeInfo *type_info_new_base(Type *type, SourceRange range) +static inline TypeInfo *type_info_new_base(Type *type, SourceSpan span) { - TypeInfo *type_info = CALLOCS(TypeInfo); + TypeInfo *type_info = type_info_calloc(); type_info->kind = TYPE_INFO_IDENTIFIER; type_info->resolve_status = RESOLVE_DONE; type_info->type = type; - type_info->span = range; + type_info->span = span; return type_info; } diff --git a/src/compiler/context.c b/src/compiler/context.c index 46ce69273..fa1ce1a6e 100644 --- a/src/compiler/context.c +++ b/src/compiler/context.c @@ -7,8 +7,7 @@ Context *context_create(File *file, BuildTarget *target) { - Context *context = malloc_arena(sizeof(Context)); - memset(context, 0, sizeof(Context)); + Context *context = CALLOCS(Context); context->file = file; context->target = target; stable_init(&context->local_symbols, 256); @@ -28,7 +27,7 @@ static inline bool create_module_or_check_name(Context *context, Path *module_na } else if (context->module->name->module != module_name->module) { - sema_error_range(module_name->span, "Module name here '%s' did not match actual module '%s'.", module_name->module, context->module->name->module); + SEMA_ERROR(module_name, "Module name here '%s' did not match actual module '%s'.", module_name->module, context->module->name->module); return false; } return true; @@ -48,8 +47,8 @@ bool context_set_module_from_filename(Context *context) const char *module_name = symtab_add(buffer, (uint32_t) len, fnv1a(buffer, (uint32_t) len), &type); if (type != TOKEN_IDENT) { - sema_error(context, "Generating a filename from the file '%s' resulted in a name that is a reserved keyword, " - "try using an explicit module name."); + sema_error(context, "Generating a filename from the file '%s' resulted in a name that is a reserved keyword, " + "try using an explicit module name."); return false; } Path *path = CALLOCS(Path); @@ -59,14 +58,14 @@ bool context_set_module_from_filename(Context *context) return create_module_or_check_name(context, path); } -bool context_set_module(Context *context, Path *path, Token *generic_parameters) +bool context_set_module(Context *context, Path *path, TokenId *generic_parameters) { DEBUG_LOG("CONTEXT: Setting module to '%s'.", path->module); // Note that we allow the illegal name for now, to be able to parse further. context->module_name = path; if (!is_all_lower(path->module)) { - sema_error_range(path->span, "A module name may not have any upper case characters."); + SEMA_ERROR(path, "A module name may not have any upper case characters."); return false; } context->module_parameters = generic_parameters; @@ -161,29 +160,30 @@ bool context_add_import(Context *context, Path *path, Token token, Token alias) if (!is_all_lower(path->module)) { - sema_error_range(path->span, "A module is not expected to have any upper case characters, please change it."); + SEMA_ERROR(path, "A module is not expected to have any upper case characters, please change it."); return false; } - Decl *import = CALLOCS(Decl); + Decl *import = decl_calloc(); import->decl_kind = DECL_IMPORT; import->visibility = VISIBLE_LOCAL; import->import.path = path; - import->import.symbol = token; + import->import.symbol = token.id; if (alias.type != TOKEN_INVALID_TOKEN) { - if (alias.string == token.string) + const char *alias_name = TOKKSTR(alias); + if (alias_name == TOKKSTR(token)) { - sema_error_range(alias.span, "If an alias would be the same as the symbol aliased, it wouldn't have any effect."); + SEMA_TOKEN_ERROR(alias, "If an alias would be the same as the symbol aliased, it wouldn't have any effect."); return false; } - if (alias.string == context->module_name->module) + if (alias_name == context->module_name->module) { - sema_error_range(alias.span, "An alias cannot have not have the same as the name of the current module."); + SEMA_TOKEN_ERROR(alias, "An alias cannot have not have the same as the name of the current module."); return false; } import->import.aliased = true; - TODO + TODO } vec_add(context->imports, import); @@ -195,22 +195,22 @@ void context_print_ast(Context *context, FILE *file) { VECEACH(context->enums, i) { - fprint_decl(file, context->enums[i]); + fprint_decl(context, file, context->enums[i]); } VECEACH(context->vars, i) { - fprint_decl(file, context->vars[i]); + fprint_decl(context, file, context->vars[i]); } VECEACH(context->types, i) { - fprint_decl(file, context->types[i]); + fprint_decl(context, file, context->types[i]); } VECEACH(context->functions, i) { - fprint_decl(file, context->functions[i]); + fprint_decl(context, file, context->functions[i]); } VECEACH(context->ct_ifs, i) { - fprint_decl(file, context->ct_ifs[i]); + fprint_decl(context, file, context->ct_ifs[i]); } } diff --git a/src/compiler/diagnostics.c b/src/compiler/diagnostics.c index cf07f1aa0..63c0a4aad 100644 --- a/src/compiler/diagnostics.c +++ b/src/compiler/diagnostics.c @@ -21,46 +21,44 @@ typedef enum PRINT_TYPE_WARN } PrintType; -static void print_error(SourceRange source_range, const char *message, PrintType print_type) +static void print_error2(SourceLocation *location, const char *message, PrintType print_type) { - SourcePosition position = source_file_find_position(source_range.loc); - static const int LINES_SHOWN = 4; - unsigned max_line_length = (int)round(log10(position.line)) + 1; + unsigned max_line_length = (int)round(log10(location->line)) + 1; char number_buffer[20]; snprintf(number_buffer, 20, "%%%dd: %%.*s\n", max_line_length); // Insert end in case it's not yet there. - for (SourceLoc s = position.loc; s < position.file->end_id; s++) + for (SourceLoc s = location->start; s < location->file->end_id; s++) { - if ((position.file->contents + s - position.file->start_id)[0] == '\n') + if ((location->file->contents + s - location->file->start_id)[0] == '\n') { - source_file_append_line_end(position.file, s); + source_file_append_line_end(location->file, s); break; } } - size_t lines_in_file = vec_size(position.file->lines); + size_t lines_in_file = vec_size(location->file->lines); const char *start = NULL; for (unsigned i = LINES_SHOWN; i > 0; i--) { - if (position.line < i) continue; - uint32_t line_number = position.line + 1 - i; - SourceLoc line_start = position.file->lines[line_number - 1]; + if (location->line < i) continue; + uint32_t line_number = location->line + 1 - i; + SourceLoc line_start = location->file->lines[line_number - 1]; - SourceLoc line_end = line_number == lines_in_file ? position.file->end_id : - position.file->lines[line_number]; + SourceLoc line_end = line_number == lines_in_file ? location->file->end_id : + location->file->lines[line_number]; uint32_t line_len = line_end - line_start - 1; - start = position.file->contents + line_start - position.file->start_id; - eprintf(number_buffer, line_number, line_len, start); + start = location->file->contents + line_start - location->file->start_id; + eprintf(number_buffer, line_number, line_len, start); } eprintf(" "); for (unsigned i = 0; i < max_line_length; i++) { eprintf(" "); } - for (unsigned i = 0; i < position.col - 1; i++) + for (unsigned i = 0; i < location->col - 1; i++) { if (start[i] == '\t') { @@ -71,7 +69,7 @@ static void print_error(SourceRange source_range, const char *message, PrintType eprintf(" "); } } - for (uint32_t i = 0; i < source_range_len(source_range); i++) + for (uint32_t i = 0; i < location->length; i++) { eprintf("^"); } @@ -80,13 +78,13 @@ static void print_error(SourceRange source_range, const char *message, PrintType switch (print_type) { case PRINT_TYPE_ERROR: - eprintf("(%s:%d) Error: %s\n\n", position.file->name, position.line, message); + eprintf("(%s:%d) Error: %s\n\n", location->file->name, location->line, message); break; case PRINT_TYPE_PREV: - eprintf("(%s:%d) %s\n\n", position.file->name, position.line, message); + eprintf("(%s:%d) %s\n\n", location->file->name, location->line, message); break; case PRINT_TYPE_WARN: - eprintf("(%s:%d) Warning: %s\n\n", position.file->name, position.line, message); + eprintf("(%s:%d) Warning: %s\n\n", location->file->name, location->line, message); break; default: UNREACHABLE @@ -94,60 +92,77 @@ static void print_error(SourceRange source_range, const char *message, PrintType } - -static void vprint_error(SourceRange span, const char *message, va_list args) +static void vprint_error(SourceLocation *location, const char *message, va_list args) { char buffer[256]; vsnprintf(buffer, 256, message, args); - print_error(span, buffer, PRINT_TYPE_ERROR); + print_error2(location, buffer, PRINT_TYPE_ERROR); } -void diag_error_range(SourceRange span, const char *message, ...) + +void diag_verror_range(SourceLocation *location, const char *message, va_list args) { if (diagnostics.panic_mode) return; diagnostics.panic_mode = true; - va_list args; - va_start(args, message); - vprint_error(span, message, args); - va_end(args); + vprint_error(location, message, args); diagnostics.errors++; } -void diag_verror_range(SourceRange span, const char *message, va_list args) + +void sema_verror_range(SourceLocation *location, const char *message, va_list args) { - if (diagnostics.panic_mode) return; - diagnostics.panic_mode = true; - vprint_error(span, message, args); + vprint_error(location, message, args); diagnostics.errors++; } -void sema_error_at(SourceLoc loc, const char *message, ...) +void sema_error_range2(SourceLocation *location, const char *message, ...) { va_list list; va_start(list, message); - sema_verror_at(loc, message, list); + sema_verror_range(location, message, list); va_end(list); } -void sema_error_range(SourceRange range, const char *message, ...) +void sema_error_range3(SourceSpan location, const char *message, ...) { + SourceLocation *start = TOKLOC(location.loc); + SourceLocation *end = TOKLOC(location.end_loc); + + SourceLocation loc = *start; + loc.length = end->start - start->start + end->length; va_list list; va_start(list, message); - sema_verror_range(range, message, list); + sema_verror_range(&loc, message, list); va_end(list); } -void sema_verror_at(SourceLoc loc, const char *message, va_list args) +void sema_error_at_prev_end(Token token, const char *message, ...) { - vprint_error((SourceRange) { loc, loc + 1 }, message, args); - diagnostics.errors++; + SourceLocation *curr = TOKLOC(token); + SourceLocation *prev = TOKLOC((TokenId) { token.id.index - 1 }); + SourceLocation location; + if (curr->file != prev->file) + { + // Ok, this is the first location, so then we create a "start" location: + location = *curr; + location.start = 0; + location.line = 1; + location.col = 1; + } + else + { + // TODO handle multiline + location = *prev; + location.col += location.length; + location.start += location.length; + } + location.length = 1; + va_list list; + va_start(list, message); + sema_verror_range(&location, message, list); + va_end(list); } -void sema_verror_range(SourceRange range, const char *message, va_list args) -{ - vprint_error(range, message, args); - diagnostics.errors++; -} void sema_error(Context *context, const char *message, ...) { @@ -160,25 +175,20 @@ void sema_error(Context *context, const char *message, ...) va_end(list); } -void sema_prev_at_range(SourceRange span, const char *message, ...) +void sema_prev_at_range3(SourceSpan span, const char *message, ...) { + SourceLocation *start = TOKLOC(span.loc); + SourceLocation *end = TOKLOC(span.end_loc); va_list args; va_start(args, message); char buffer[256]; vsnprintf(buffer, 256, message, args); - print_error(span, buffer, PRINT_TYPE_PREV); + SourceLocation loc = *start; + loc.length = end->start - start->start + end->length; + print_error2(&loc, buffer, PRINT_TYPE_PREV); va_end(args); } -void sema_prev_at(SourceLoc loc, const char *message, ...) -{ - va_list args; - va_start(args, message); - char buffer[256]; - vsnprintf(buffer, 256, message, args); - print_error((SourceRange){ loc, loc + 1 }, buffer, PRINT_TYPE_PREV); - va_end(args); -} /* @@ -241,43 +251,7 @@ bool diagnostics_silence_warnings(Array *warnings) -void prev_at_range(SourceRange span, const char *message, ...) -{ - va_list args; - va_start(args, message); - char buffer[256]; - vsnprintf(buffer, 256, message, args); - print_error(span, buffer, PRINT_TYPE_PREV); - va_end(args); -} -void prev_at(SourceLoc loc, const char *message, ...) -{ - va_list args; - va_start(args, message); - char buffer[256]; - vsnprintf(buffer, 256, message, args); - print_error((SourceRange){ loc, 1 }, buffer, PRINT_TYPE_PREV); - va_end(args); -} - -void sema_error_range(SourceRange token, const char *message, ...) -{ - va_list args; - va_start(args, message); - vprint_error(token, message, args); - va_end(args); - diagnostics.errors++; -} - -void sema_error_at(SourceLoc loc, const char *message, ...) -{ - va_list args; - va_start(args, message); - vprint_error((SourceRange) { loc, 1 }, message, args); - va_end(args); - diagnostics.errors++; -} void sema_warn_at(DiagnosticsType type, SourceLoc loc, const char *message, ...) { diff --git a/src/compiler/enums.h b/src/compiler/enums.h index 670046ffd..1f8e0c5e6 100644 --- a/src/compiler/enums.h +++ b/src/compiler/enums.h @@ -154,10 +154,10 @@ typedef enum typedef enum { EXIT_NONE = 0, - EXIT_BREAK = 1 << 1, - EXIT_NEXT = 1 << 2, - EXIT_CONTINUE = 1 << 5, - EXIT_RETURN = 1 << 6, + EXIT_CONTINUE, + EXIT_RETURN, + EXIT_NEXT, + EXIT_BREAK, } ExitType; typedef enum @@ -247,7 +247,7 @@ typedef enum TYPE_INFO_POINTER, } TypeInfoKind; -typedef enum +typedef enum { TOKEN_INVALID_TOKEN = 0, diff --git a/src/compiler/lexer.c b/src/compiler/lexer.c index 598330b4c..4eebc5d2c 100644 --- a/src/compiler/lexer.c +++ b/src/compiler/lexer.c @@ -4,8 +4,11 @@ #include "compiler_internal.h" + #pragma mark --- Lexing general methods. +static bool lexer_scan_token_inner(Lexer *lexer); + static inline char peek(Lexer *lexer) { return *lexer->current; @@ -23,6 +26,8 @@ static inline void backtrack(Lexer *lexer) void lexer_store_line_end(Lexer *lexer) { + lexer->current_line++; + lexer->line_start = lexer->current; source_file_append_line_end(lexer->current_file, lexer->current_file->start_id + lexer->current - lexer->file_begin); } @@ -54,58 +59,50 @@ static inline bool match(Lexer *lexer, char expected) return true; } -static inline SourceRange range_from_ptr(Lexer *lexer, const char *start, const char *end) -{ - return (SourceRange) { - (lexer->current_file->start_id + (start - lexer->file_begin)), - (lexer->current_file->start_id + (end - lexer->file_begin)), - }; -} - #pragma mark --- Token creation -static Token error_token(Lexer *lexer, const char *message, ...) +static inline void add_generic_token(Lexer *lexer, TokenType type, SourceLocation **ret_loc, TokenData **ret_data) { - Token token = { - .type = TOKEN_INVALID_TOKEN, - .span = range_from_ptr(lexer, lexer->lexing_start, lexer->current), - .start = lexer->lexing_start - }; + SourceLocation *location = sourceloc_alloc(); + char *token_type = toktype_alloc(); + TokenData *data = tokdata_alloc(); + *token_type = type; + location->file = lexer->current_file; + location->line = lexer->current_line; + location->col = (unsigned)(lexer->lexing_start - lexer->line_start); + location->start = lexer->lexing_start - lexer->file_begin; + location->length = lexer->current - lexer->lexing_start; + *ret_data = data; + *ret_loc = location; +} +static bool add_error_token(Lexer *lexer, const char *message, ...) +{ + TokenData *data; + SourceLocation *loc; + add_generic_token(lexer, TOKEN_INVALID_TOKEN, &loc, &data); va_list list; va_start(list, message); - diag_verror_range(token.span, message, list); + diag_verror_range(loc, message, list); va_end(list); - return token; + return false; } -static Token make_token(Lexer *lexer, TokenType type, const char *string) +static bool add_token(Lexer *lexer, TokenType type, const char *string) { size_t token_size = lexer->current - lexer->lexing_start; - if (token_size > TOKEN_MAX_LENGTH) return error_token(lexer, "Token exceeding max length"); - return (Token) - { - .type = type, - .span = range_from_ptr(lexer, lexer->lexing_start, lexer->current), - .start = string - }; + if (token_size > TOKEN_MAX_LENGTH) return add_error_token(lexer, "Token exceeding max length"); + TokenData *data; + SourceLocation *loc; + add_generic_token(lexer, type, &loc, &data); + data->string = string; + return true; } -static Token make_string_token(Lexer *lexer, TokenType type, const char* string) -{ - size_t token_size = lexer->current - lexer->lexing_start; - if (token_size > TOKEN_MAX_LENGTH) return error_token(lexer, "Token exceeding max length"); - return (Token) - { - .type = type, - .span = range_from_ptr(lexer, lexer->lexing_start, lexer->current), - .string = string, - }; -} #pragma mark --- Comment parsing -static inline Token parse_line_comment(Lexer *lexer) +static inline bool parse_line_comment(Lexer *lexer) { // // style comment // Skip forward to the end. @@ -118,7 +115,7 @@ static inline Token parse_line_comment(Lexer *lexer) next(lexer); } - Token token = make_token(lexer, comment_type, lexer->lexing_start); + bool success = add_token(lexer, comment_type, lexer->lexing_start); // If we found EOL, then walk past '\n' if (!reached_end(lexer)) @@ -126,11 +123,10 @@ static inline Token parse_line_comment(Lexer *lexer) lexer_store_line_end(lexer); next(lexer); } - - return token; + return success; } -static inline Token parse_nested_comment(Lexer *lexer) +static inline bool parse_nested_comment(Lexer *lexer) { next(lexer); int nesting = 0; @@ -163,12 +159,12 @@ static inline Token parse_nested_comment(Lexer *lexer) } if (nesting > 0) { - return error_token(lexer, "Missing '+/' to end the nested comment."); + return add_error_token(lexer, "Missing '+/' to end the nested comment."); } - return make_token(lexer, TOKEN_COMMENT, lexer->lexing_start); + return add_token(lexer, TOKEN_COMMENT, lexer->lexing_start); } -static inline Token parse_multiline_comment(Lexer *lexer) +static inline bool parse_multiline_comment(Lexer *lexer) { TokenType type = peek(lexer) == '*' && peek_next(lexer) != '/' ? TOKEN_DOC_COMMENT : TOKEN_COMMENT; while (1) @@ -179,14 +175,14 @@ static inline Token parse_multiline_comment(Lexer *lexer) if (peek_next(lexer) == '/') { skip(lexer, 2); - return make_token(lexer, type, lexer->lexing_start); + return add_token(lexer, type, lexer->lexing_start); } break; case '\n': lexer_store_line_end(lexer); break; case '\0': - return error_token(lexer, "Missing '*/' to end the multiline comment."); + return add_error_token(lexer, "Missing '*/' to end the multiline comment."); } next(lexer); } @@ -220,7 +216,7 @@ static void skip_whitespace(Lexer *lexer) #pragma mark --- Identifier scanning -static inline Token scan_prefixed_ident(Lexer *lexer, TokenType type, TokenType no_ident_type, bool ends_with_bang, const char *start) +static inline bool scan_prefixed_ident(Lexer *lexer, TokenType type, TokenType no_ident_type, bool ends_with_bang, const char *start) { uint32_t hash = FNV1a(prev(lexer), FNV1_SEED); while (is_alphanum_(peek(lexer))) @@ -232,15 +228,18 @@ static inline Token scan_prefixed_ident(Lexer *lexer, TokenType type, TokenType hash = FNV1a(next(lexer), hash); } uint32_t len = (uint32_t)(lexer->current - lexer->lexing_start); - if (len == 1) return make_token(lexer, no_ident_type, start); + if (len == 1) + { + return add_token(lexer, no_ident_type, start); + } const char* interned = symtab_add(lexer->lexing_start, len, hash, &type); - return make_string_token(lexer, type, interned); + return add_token(lexer, type, interned); } // Parses identifiers. Note that this is a bit complicated here since // we split identifiers into 2 types + find keywords. -static inline Token scan_ident(Lexer *lexer, TokenType normal, TokenType const_token, TokenType type_token, char prefix) +static inline bool scan_ident(Lexer *lexer, TokenType normal, TokenType const_token, TokenType type_token, char prefix) { TokenType type = 0; uint32_t hash = FNV1_SEED; @@ -281,7 +280,7 @@ static inline Token scan_ident(Lexer *lexer, TokenType normal, TokenType const_t break; case '0': case '1': case '2': case '3': case '4': case '5': case '6': case '7': case '8': case '9': - if (!type) return error_token(lexer, "A letter must preceed any digit"); + if (!type) return add_error_token(lexer, "A letter must preceed any digit"); case '_': break; default: @@ -297,38 +296,37 @@ static inline Token scan_ident(Lexer *lexer, TokenType normal, TokenType const_t EXIT:; uint32_t len = lexer->current - lexer->lexing_start; const char* interned_string = symtab_add(lexer->lexing_start, len, hash, &type); - return make_string_token(lexer, type, interned_string); + return add_token(lexer, type, interned_string); } #pragma mark --- Number scanning -static Token scan_oct(Lexer *lexer) +static bool scan_oct(Lexer *lexer) { char o = next(lexer); // Skip the o - if (!is_oct(next(lexer))) return error_token(lexer, "An expression starting with '0%c' would expect to be followed by octal numbers (0-7).", o); + if (!is_oct(next(lexer))) return add_error_token(lexer, "An expression starting with '0%c' would expect to be followed by octal numbers (0-7).", o); while (is_oct_or_(peek(lexer))) next(lexer); - return make_token(lexer, TOKEN_INTEGER, lexer->lexing_start); + return add_token(lexer, TOKEN_INTEGER, lexer->lexing_start); } -static Token scan_binary(Lexer *lexer) +static bool scan_binary(Lexer *lexer) { next(lexer); // Skip the b if (!is_binary(next(lexer))) { - return error_token(lexer, "An expression starting with '0b' would expect a sequence of zeroes and ones, " + return add_error_token(lexer, "An expression starting with '0b' would expect a sequence of zeroes and ones, " "did you try to write a hex value but forgot the '0x'?"); } while (is_binary_or_(peek(lexer))) next(lexer); - return make_token(lexer, TOKEN_INTEGER, lexer->lexing_start); + return add_token(lexer, TOKEN_INTEGER, lexer->lexing_start); } - -static inline Token scan_hex(Lexer *lexer) +static inline bool scan_hex(Lexer *lexer) { if (!is_hex(next(lexer))) { - return error_token(lexer, "'0x' starts a hexadecimal number, " + return add_error_token(lexer, "'0x' starts a hexadecimal number, " "but it was followed by '%c' which is not part of a hexadecimal number.", prev(lexer)); } while (is_hex_or_(peek(lexer))) next(lexer); @@ -338,7 +336,7 @@ static inline Token scan_hex(Lexer *lexer) is_float = true; next(lexer); char c = peek(lexer); - if (c == '_') return error_token(lexer, "Can't parse this as a floating point value due to the '_' directly after decimal point."); + if (c == '_') return add_error_token(lexer, "Can't parse this as a floating point value due to the '_' directly after decimal point."); if (is_hex(c)) next(lexer); while (is_hex_or_(peek(lexer))) next(lexer); } @@ -349,14 +347,14 @@ static inline Token scan_hex(Lexer *lexer) next(lexer); char c2 = next(lexer); if (c2 == '+' || c2 == '-') c2 = next(lexer); - if (!is_hex(c2)) return error_token(lexer, "Parsing the floating point exponent failed, because '%c' is not a number.", c2); + if (!is_hex(c2)) return add_error_token(lexer, "Parsing the floating point exponent failed, because '%c' is not a number.", c2); while (is_hex(peek(lexer))) next(lexer); } - if (prev(lexer) == '_') return error_token(lexer, "The number ended with '_', but that character needs to be between, not after, digits."); - return make_token(lexer, is_float ? TOKEN_REAL : TOKEN_INTEGER, lexer->lexing_start); + if (prev(lexer) == '_') return add_error_token(lexer, "The number ended with '_', but that character needs to be between, not after, digits."); + return add_token(lexer, is_float ? TOKEN_REAL : TOKEN_INTEGER, lexer->lexing_start); } -static inline Token scan_dec(Lexer *lexer) +static inline bool scan_dec(Lexer *lexer) { while (is_digit_or_(peek(lexer))) next(lexer); bool is_float = false; @@ -365,7 +363,7 @@ static inline Token scan_dec(Lexer *lexer) is_float = true; next(lexer); char c = peek(lexer); - if (c == '_') return error_token(lexer, "Can't parse this as a floating point value due to the '_' directly after decimal point."); + if (c == '_') return add_error_token(lexer, "Can't parse this as a floating point value due to the '_' directly after decimal point."); if (is_digit(c)) next(lexer); while (is_digit_or_(peek(lexer))) next(lexer); } @@ -376,15 +374,31 @@ static inline Token scan_dec(Lexer *lexer) next(lexer); char c2 = next(lexer); if (c2 == '+' || c2 == '-') c2 = next(lexer); - if (!is_digit(c2)) return error_token(lexer, "Parsing the floating point exponent failed, because '%c' is not a number.", c2); + if (!is_digit(c2)) return add_error_token(lexer, "Parsing the floating point exponent failed, because '%c' is not a number.", c2); while (is_digit(peek(lexer))) next(lexer); } - if (prev(lexer) == '_') return error_token(lexer, "The number ended with '_', but that character needs to be between, not after, digits."); - return make_token(lexer, is_float ? TOKEN_REAL : TOKEN_INTEGER, lexer->lexing_start); + if (prev(lexer) == '_') return add_error_token(lexer, "The number ended with '_', but that character needs to be between, not after, digits."); + + if (is_float) + { + // IMPROVE + char *end = NULL; + long double fval = strtold(lexer->lexing_start, &end); + if (end != lexer->current) + { + return add_error_token(lexer, "Invalid float value."); + } + SourceLocation *token; + TokenData *data; + add_generic_token(lexer, TOKEN_REAL, &token, &data); + data->value = fval; + return true; + } + return add_token(lexer, TOKEN_INTEGER, lexer->lexing_start); } -static inline Token scan_digit(Lexer *lexer) +static inline bool scan_digit(Lexer *lexer) { if (peek(lexer) == '0') { @@ -411,13 +425,13 @@ static inline Token scan_digit(Lexer *lexer) #pragma mark --- Character & string scan -static inline Token scan_char(Lexer *lexer) +static inline bool scan_char(Lexer *lexer) { int width = 0; char c; while ((c = next(lexer)) != '\'') { - if (c == '\0' || c == '\n') return error_token(lexer, "Character literal did not terminate."); + if (c == '\0' || c == '\n') return add_error_token(lexer, "Character literal did not terminate."); width++; // Was this an escape? if (c == '\\') @@ -430,7 +444,7 @@ static inline Token scan_char(Lexer *lexer) { if (!is_hex(next(lexer))) { - return error_token(lexer, + return add_error_token(lexer, "An escape sequence starting with " "'\\x' needs to be followed by " "a two digit hexadecimal number."); @@ -441,16 +455,16 @@ static inline Token scan_char(Lexer *lexer) } if (width == 0) { - return error_token(lexer, "The character literal was empty."); + return add_error_token(lexer, "The character literal was empty."); } if (width > 2 && width != 4 && width != 8) { - error_token(lexer, "Character literals may only be 1, 2 or 8 characters wide."); + add_error_token(lexer, "Character literals may only be 1, 2 or 8 characters wide."); } - return make_token(lexer, TOKEN_INTEGER, lexer->lexing_start); + return add_token(lexer, TOKEN_INTEGER, lexer->lexing_start); } -static inline Token scan_string(Lexer *lexer) +static inline bool scan_string(Lexer *lexer) { char c; while ((c = next(lexer)) != '"') @@ -462,15 +476,15 @@ static inline Token scan_string(Lexer *lexer) } if (reached_end(lexer)) { - return error_token(lexer, "Reached the end looking for '\"'. Did you forget it?"); + return add_error_token(lexer, "Reached the end looking for '\"'. Did you forget it?"); } } - return make_token(lexer, TOKEN_STRING, lexer->lexing_start); + return add_token(lexer, TOKEN_STRING, lexer->lexing_start); } #pragma mark --- Lexer public functions -Token lexer_scan_asm_constraint(Lexer *lexer) +SourceLocation *lexer_scan_asm_constraint(Lexer *lexer) { // Skip the whitespace. skip_whitespace(lexer); @@ -480,7 +494,8 @@ Token lexer_scan_asm_constraint(Lexer *lexer) if (reached_end(lexer)) { - return make_token(lexer, TOKEN_EOF, "\n"); + TODO +// return add_token(lexer, TOKEN_EOF, "\n"); } // Move past '+=&' @@ -501,16 +516,23 @@ Token lexer_scan_asm_constraint(Lexer *lexer) } if (c != ' ') { - return error_token(lexer, "Invalid asm constraint"); + TODO + //return error_token(lexer, "Invalid asm constraint"); } break; } - return make_token(lexer, TOKEN_ASM_CONSTRAINT, strcopy(lexer->lexing_start, lexer->current - lexer->lexing_start + 1)); + TODO + /* + return add_token(lexer, + TOKEN_ASM_CONSTRAINT, + strcopy(lexer->lexing_start, lexer->current - lexer->lexing_start + 1));*/ } -Token lexer_scan_asm(Lexer *lexer) +SourceLocation *lexer_scan_asm(Lexer *lexer) { + TODO + /* // Skip the whitespace. skip_whitespace(lexer); @@ -519,7 +541,7 @@ Token lexer_scan_asm(Lexer *lexer) if (reached_end(lexer)) { - return make_token(lexer, TOKEN_EOF, "\n"); + return add_token(lexer, TOKEN_EOF, "\n"); } int bracket = 0; @@ -554,7 +576,7 @@ Token lexer_scan_asm(Lexer *lexer) // If this is the first non whitespace this is an end of asm. if (lexer->lexing_start == lexer->current - 1) { - return make_token(lexer, TOKEN_RBRACE, "}"); + return add_token(lexer, TOKEN_RBRACE, "}"); } // Otherwise we need to return the previous as a token. break; @@ -562,11 +584,23 @@ Token lexer_scan_asm(Lexer *lexer) last_non_whitespace = lexer->current - 1; continue; } - return make_token(lexer, TOKEN_ASM_STRING, strcopy(lexer->lexing_start, last_non_whitespace - lexer->lexing_start + 1)); + return add_token(lexer, + TOKEN_ASM_STRING, + strcopy(lexer->lexing_start, last_non_whitespace - lexer->lexing_start + 1)); } + */ } -Token lexer_scan_token(Lexer *lexer) + + +Token lexer_advance(Lexer *lexer) +{ + Token token = { .id.index = lexer->lexer_index, .type = (TokenType)*toktypeptr(lexer->lexer_index) }; + lexer->lexer_index++; + return token; +} + +static bool lexer_scan_token_inner(Lexer *lexer) { // Now skip the whitespace. skip_whitespace(lexer); @@ -576,87 +610,108 @@ Token lexer_scan_token(Lexer *lexer) if (reached_end(lexer)) { - return make_token(lexer, TOKEN_EOF, "\n"); + return add_token(lexer, TOKEN_EOF, "\n") && false; } char c = next(lexer); switch (c) { case '@': - return make_token(lexer, TOKEN_AT, "@"); + return add_token(lexer, TOKEN_AT, "@"); case '\'': return scan_char(lexer); case '"': return scan_string(lexer); case '#': - return make_token(lexer, TOKEN_HASH, "#"); + return add_token(lexer, TOKEN_HASH, "#"); case '$': return scan_ident(lexer, TOKEN_CT_IDENT, TOKEN_CT_CONST_IDENT, TOKEN_CT_TYPE_IDENT, '$'); case ',': - return make_token(lexer, TOKEN_COMMA, ","); + return add_token(lexer, TOKEN_COMMA, ","); case ';': - return make_token(lexer, TOKEN_EOS, ";"); + return add_token(lexer, TOKEN_EOS, ";"); case '{': - return make_token(lexer, TOKEN_LBRACE, "{"); + return add_token(lexer, TOKEN_LBRACE, "{"); case '}': - return match(lexer, ')') ? make_token(lexer, TOKEN_RPARBRA, "})") : make_token(lexer, TOKEN_RBRACE, "}"); + return match(lexer, ')') ? add_token(lexer, TOKEN_RPARBRA, "})") : add_token(lexer, TOKEN_RBRACE, "}"); case '(': - return match(lexer, '{') ? make_token(lexer, TOKEN_LPARBRA, "({") : make_token(lexer, TOKEN_LPAREN, "("); + return match(lexer, '{') ? add_token(lexer, TOKEN_LPARBRA, "({") : add_token(lexer, TOKEN_LPAREN, "("); case ')': - return make_token(lexer, TOKEN_RPAREN, ")"); + return add_token(lexer, TOKEN_RPAREN, ")"); case '[': - return make_token(lexer, TOKEN_LBRACKET, "["); + return add_token(lexer, TOKEN_LBRACKET, "["); case ']': - return make_token(lexer, TOKEN_RBRACKET, "]"); + return add_token(lexer, TOKEN_RBRACKET, "]"); case '.': - if (match(lexer, '.')) return match(lexer, '.') ? make_token(lexer, TOKEN_ELLIPSIS, "...") : make_token(lexer, TOKEN_DOTDOT, ".."); - return make_token(lexer, TOKEN_DOT, "."); + if (match(lexer, '.')) return match(lexer, '.') ? add_token(lexer, TOKEN_ELLIPSIS, "...") : add_token(lexer, + TOKEN_DOTDOT, + ".."); + return add_token(lexer, TOKEN_DOT, "."); case '~': - return make_token(lexer, TOKEN_BIT_NOT, "~"); + return add_token(lexer, TOKEN_BIT_NOT, "~"); case ':': - return match(lexer, ':') ? make_token(lexer, TOKEN_SCOPE, "::") : make_token(lexer, TOKEN_COLON, ":"); + return match(lexer, ':') ? add_token(lexer, TOKEN_SCOPE, "::") : add_token(lexer, TOKEN_COLON, ":"); case '!': - if (match(lexer, '!')) return make_token(lexer, TOKEN_BANGBANG, "!!"); - return match(lexer, '=') ? make_token(lexer, TOKEN_NOT_EQUAL, "!=") : make_token(lexer, TOKEN_BANG, "!"); + if (match(lexer, '!')) return add_token(lexer, TOKEN_BANGBANG, "!!"); + return match(lexer, '=') ? add_token(lexer, TOKEN_NOT_EQUAL, "!=") : add_token(lexer, TOKEN_BANG, "!"); case '/': if (match(lexer, '/')) return parse_line_comment(lexer); if (match(lexer, '*')) return parse_multiline_comment(lexer); if (match(lexer, '+')) return parse_nested_comment(lexer); - return match(lexer, '=') ? make_token(lexer, TOKEN_DIV_ASSIGN, "/=") : make_token(lexer, TOKEN_DIV, "/"); + return match(lexer, '=') ? add_token(lexer, TOKEN_DIV_ASSIGN, "/=") : add_token(lexer, TOKEN_DIV, "/"); case '*': - if (match(lexer, '%')) return match(lexer, '=') ? make_token(lexer, TOKEN_MULT_MOD_ASSIGN, "*%=") : make_token(lexer, TOKEN_MULT_MOD, "*%"); - return match(lexer, '=') ? make_token(lexer, TOKEN_MULT_ASSIGN, "*=") : make_token(lexer, TOKEN_STAR, "*"); + if (match(lexer, '%')) return match(lexer, '=') ? add_token(lexer, TOKEN_MULT_MOD_ASSIGN, "*%=") : add_token( + lexer, + TOKEN_MULT_MOD, + "*%"); + return match(lexer, '=') ? add_token(lexer, TOKEN_MULT_ASSIGN, "*=") : add_token(lexer, TOKEN_STAR, "*"); case '=': - return match(lexer, '=') ? make_token(lexer, TOKEN_EQEQ, "==") : make_token(lexer, TOKEN_EQ, "="); + return match(lexer, '=') ? add_token(lexer, TOKEN_EQEQ, "==") : add_token(lexer, TOKEN_EQ, "="); case '^': - return match(lexer, '=') ? make_token(lexer, TOKEN_BIT_XOR_ASSIGN, "^=") : make_token(lexer, TOKEN_BIT_XOR, "^"); + return match(lexer, '=') ? add_token(lexer, TOKEN_BIT_XOR_ASSIGN, "^=") : add_token(lexer, + TOKEN_BIT_XOR, + "^"); case '?': - return match(lexer, ':') ? make_token(lexer, TOKEN_ELVIS, "?:") : make_token(lexer, TOKEN_QUESTION, "?"); + return match(lexer, ':') ? add_token(lexer, TOKEN_ELVIS, "?:") : add_token(lexer, TOKEN_QUESTION, "?"); case '<': - if (match(lexer, '<')) return match(lexer, '=') ? make_token(lexer, TOKEN_SHL_ASSIGN, "<<=") : make_token(lexer, TOKEN_SHL, "<<"); - return match(lexer, '=') ? make_token(lexer, TOKEN_LESS_EQ, "<=") : make_token(lexer, TOKEN_LESS, "<"); + if (match(lexer, '<')) return match(lexer, '=') ? add_token(lexer, TOKEN_SHL_ASSIGN, "<<=") : add_token( + lexer, + TOKEN_SHL, + "<<"); + return match(lexer, '=') ? add_token(lexer, TOKEN_LESS_EQ, "<=") : add_token(lexer, TOKEN_LESS, "<"); case '>': - if (match(lexer, '>')) return match(lexer, '=') ? make_token(lexer, TOKEN_SHR_ASSIGN, ">>=") : make_token(lexer, TOKEN_SHR, ">>"); - return match(lexer, '=') ? make_token(lexer, TOKEN_GREATER_EQ, ">=") : make_token(lexer, TOKEN_GREATER, ">"); + if (match(lexer, '>')) return match(lexer, '=') ? add_token(lexer, TOKEN_SHR_ASSIGN, ">>=") : add_token( + lexer, + TOKEN_SHR, + ">>"); + return match(lexer, '=') ? add_token(lexer, TOKEN_GREATER_EQ, ">=") : add_token(lexer, TOKEN_GREATER, ">"); case '%': - return match(lexer, '=') ? make_token(lexer, TOKEN_MOD_ASSIGN, "%=") : make_token(lexer, TOKEN_MOD, "%"); + return match(lexer, '=') ? add_token(lexer, TOKEN_MOD_ASSIGN, "%=") : add_token(lexer, TOKEN_MOD, "%"); case '&': - if (match(lexer, '&')) return make_token(lexer, TOKEN_AND, "&&"); - return match(lexer, '=') ? make_token(lexer, TOKEN_BIT_AND_ASSIGN, "&=") : make_token(lexer, TOKEN_AMP, "&"); + if (match(lexer, '&')) return add_token(lexer, TOKEN_AND, "&&"); + return match(lexer, '=') ? add_token(lexer, TOKEN_BIT_AND_ASSIGN, "&=") : add_token(lexer, TOKEN_AMP, "&"); case '|': - if (match(lexer, '|')) return make_token(lexer, TOKEN_OR, "||"); - return match(lexer, '=') ? make_token(lexer, TOKEN_BIT_OR_ASSIGN, "|=") : make_token(lexer, TOKEN_BIT_OR, "|"); + if (match(lexer, '|')) return add_token(lexer, TOKEN_OR, "||"); + return match(lexer, '=') ? add_token(lexer, TOKEN_BIT_OR_ASSIGN, "|=") : add_token(lexer, + TOKEN_BIT_OR, + "|"); case '+': - if (match(lexer, '%')) return match(lexer, '=') ? make_token(lexer, TOKEN_PLUS_MOD_ASSIGN, "+%=") : make_token(lexer, TOKEN_PLUS_MOD, "+%"); - if (match(lexer, '+')) return make_token(lexer, TOKEN_PLUSPLUS, "++"); - if (match(lexer, '=')) return make_token(lexer, TOKEN_PLUS_ASSIGN, "+="); - return make_token(lexer, TOKEN_PLUS, "+"); + if (match(lexer, '%')) return match(lexer, '=') ? add_token(lexer, TOKEN_PLUS_MOD_ASSIGN, "+%=") : add_token( + lexer, + TOKEN_PLUS_MOD, + "+%"); + if (match(lexer, '+')) return add_token(lexer, TOKEN_PLUSPLUS, "++"); + if (match(lexer, '=')) return add_token(lexer, TOKEN_PLUS_ASSIGN, "+="); + return add_token(lexer, TOKEN_PLUS, "+"); case '-': - if (match(lexer, '>')) return make_token(lexer, TOKEN_ARROW, "->"); - if (match(lexer, '%')) return match(lexer, '=') ? make_token(lexer, TOKEN_MINUS_MOD_ASSIGN, "-%=") : make_token(lexer, TOKEN_MINUS_MOD, "-%"); - if (match(lexer, '-')) return make_token(lexer, TOKEN_MINUSMINUS, "--"); - if (match(lexer, '=')) return make_token(lexer, TOKEN_MINUS_ASSIGN, "-="); - return make_token(lexer, TOKEN_MINUS, "-"); + if (match(lexer, '>')) return add_token(lexer, TOKEN_ARROW, "->"); + if (match(lexer, '%')) return match(lexer, '=') ? add_token(lexer, TOKEN_MINUS_MOD_ASSIGN, "-%=") : add_token( + lexer, + TOKEN_MINUS_MOD, + "-%"); + if (match(lexer, '-')) return add_token(lexer, TOKEN_MINUSMINUS, "--"); + if (match(lexer, '=')) return add_token(lexer, TOKEN_MINUS_ASSIGN, "-="); + return add_token(lexer, TOKEN_MINUS, "-"); default: if (is_alphanum_(c)) { @@ -665,9 +720,9 @@ Token lexer_scan_token(Lexer *lexer) } if (c < 0) { - return error_token(lexer, "The 0%x character may not be placed outside of a string or comment, did you perhaps forget a \" somewhere?", (uint8_t)c); + return add_error_token(lexer, "The 0%x character may not be placed outside of a string or comment, did you perhaps forget a \" somewhere?", (uint8_t)c); } - return error_token(lexer, "'%c' may not be placed outside of a string or comment, did you perhaps forget a \" somewhere?", c); + return add_error_token(lexer, "'%c' may not be placed outside of a string or comment, did you perhaps forget a \" somewhere?", c); } } @@ -677,12 +732,25 @@ File* lexer_current_file(Lexer *lexer) return lexer->current_file; } +#define tokenid(_ptr) ((unsigned)((TokenOld *)(_ptr) - ((TokenOld *)lexer->memory.ptr))) + + + void lexer_init_with_file(Lexer *lexer, File *file) { + file->token_start_id = toktype_arena.allocated; lexer->current_file = file; lexer->file_begin = lexer->current_file->contents; lexer->lexing_start = lexer->file_begin; lexer->current = lexer->lexing_start; + lexer->current_line = 1; + lexer->line_start = lexer->current; + lexer->lexer_index = file->token_start_id; + while(1) + { + if (!lexer_scan_token_inner(lexer)) break; + } + } #pragma mark --- Test methods @@ -690,6 +758,8 @@ void lexer_init_with_file(Lexer *lexer, File *file) void lexer_init_for_test(Lexer *lexer, const char *text, size_t len) { static File helper; + lexer->current_line = 1; + lexer->line_start = lexer->current; lexer->lexing_start = text; lexer->current = text; lexer->file_begin = text; @@ -700,7 +770,7 @@ void lexer_init_for_test(Lexer *lexer, const char *text, size_t len) lexer->current_file->name = "Test"; } -Token lexer_scan_ident_test(Lexer *lexer, const char *scan) +bool lexer_scan_ident_test(Lexer *lexer, const char *scan) { static File helper; lexer->lexing_start = scan; diff --git a/src/compiler/llvm_codegen.c b/src/compiler/llvm_codegen.c index 40006f1d0..74dc4dacd 100644 --- a/src/compiler/llvm_codegen.c +++ b/src/compiler/llvm_codegen.c @@ -98,7 +98,7 @@ static void gencontext_emit_global_variable_definition(GenContext *context, Decl decl->var.backend_debug_ref = LLVMDIBuilderCreateGlobalVariableExpression(context->debug.builder, NULL /*scope*/, decl->name, - source_range_len(decl->name_span), + 1, /*source_range_len(decl->name_span),*/ "linkagename", 2, context->debug.file, diff --git a/src/compiler/llvm_codegen_debug_info.c b/src/compiler/llvm_codegen_debug_info.c index a3aba8dc2..5155679d8 100644 --- a/src/compiler/llvm_codegen_debug_info.c +++ b/src/compiler/llvm_codegen_debug_info.c @@ -51,38 +51,24 @@ static inline LLVMMetadataRef gencontext_create_debug_type_from_decl(GenContext UNREACHABLE } -void gencontext_set_debug_location(GenContext *context, SourceRange source_range) +void gencontext_set_debug_location(GenContext *context, SourceSpan source_span) { - if (source_range.loc == INVALID_LOC) return; + if (!source_span.end_loc.index) return; - context->debug.current_range = source_range; -#ifdef TODOLATER - CurLoc = CGM.getContext().getSourceManager().getExpansionLoc(Loc); -#endif - // If we've changed files in the middle of a lexical scope go ahead - // and create a new lexical scope with file node if it's different - // from the one in the scope. - if (!vec_size(context->debug.lexical_block_stack)) return; - -#ifdef TODOLATE - if (auto *LBF = dyn_cast(Scope)) { - LexicalBlockStack.pop_back(); - LexicalBlockStack.emplace_back(DBuilder.createLexicalBlockFile( - LBF->getScope(), getOrCreateFile(CurLoc))); - } else if (isa(Scope) || - isa(Scope)) { - LexicalBlockStack.pop_back(); - LexicalBlockStack.emplace_back( - DBuilder.createLexicalBlockFile(Scope, getOrCreateFile(CurLoc))); - } -#endif + context->debug.current_range = source_span; + SourceLocation *location = TOKLOC(source_span.loc); + LLVMDIBuilderCreateDebugLocation(context->context, + location->line, + location->col, + *context->debug.lexical_block_stack, + /* inlined at */ 0); } -void gencontext_emit_debug_location(GenContext *context, SourceRange location) +void gencontext_emit_debug_location(GenContext *context, SourceSpan location) { gencontext_set_debug_location(context, location); - if (context->debug.current_range.loc == INVALID_LOC || vec_size(context->debug.lexical_block_stack) == 0) return; + if (!context->debug.current_range.loc.index || vec_size(context->debug.lexical_block_stack) == 0) return; LLVMMetadataRef scope = VECLAST(context->debug.lexical_block_stack); LLVMMetadataRef debug_location = LLVMDIBuilderCreateDebugLocation(context->context, 320, 12, scope, context->debug.inlined_at); diff --git a/src/compiler/llvm_codegen_expr.c b/src/compiler/llvm_codegen_expr.c index 1a58130f6..5c08bb020 100644 --- a/src/compiler/llvm_codegen_expr.c +++ b/src/compiler/llvm_codegen_expr.c @@ -899,6 +899,86 @@ LLVMValueRef gencontext_emit_trycatch_expr(GenContext *context, Expr *expr) return phi; } +static inline LLVMValueRef gencontext_emit_else_jump_expr(GenContext *context, Expr *expr) +{ + LLVMBasicBlockRef else_block = gencontext_create_free_block(context, "else_block"); + LLVMBasicBlockRef no_err_block = gencontext_create_free_block(context, "noerr_block"); + + // Store catch/error var + PUSH_ERROR(); + + // Set the catch/error var + context->error_var = NULL; + context->catch_block = else_block; + + LLVMValueRef value = gencontext_emit_expr(context, expr->else_expr.expr); + + // Restore. + POP_ERROR(); + + // Emit success and to end. + gencontext_emit_br(context, no_err_block); + + // Emit else + gencontext_emit_block(context, else_block); + gencontext_emit_stmt(context, expr->else_expr.else_stmt); + gencontext_emit_br(context, no_err_block); + + gencontext_emit_block(context, no_err_block); + return value; +} + +static LLVMValueRef gencontext_emit_else_expr(GenContext *context, Expr *expr) +{ + if (expr->else_expr.is_jump) return gencontext_emit_else_jump_expr(context, expr); + LLVMBasicBlockRef else_block = gencontext_create_free_block(context, "else_block"); + LLVMBasicBlockRef phi_block = gencontext_create_free_block(context, "phi_block"); + + // Store catch/error var + PUSH_ERROR(); + + // Set the catch/error var + context->error_var = NULL; + context->catch_block = else_block; + + LLVMValueRef normal_value = gencontext_emit_expr(context, expr->else_expr.expr); + + // Restore. + POP_ERROR(); + + // Emit success and jump to phi. + LLVMBasicBlockRef success_end_block = gencontext_current_block_if_in_use(context); + + if (success_end_block) gencontext_emit_br(context, phi_block); + + // Emit else + gencontext_emit_block(context, else_block); + LLVMValueRef else_value = gencontext_emit_expr(context, expr->else_expr.else_expr); + LLVMBasicBlockRef else_block_exit = gencontext_current_block_if_in_use(context); + + if (else_block_exit) gencontext_emit_br(context, phi_block); + + gencontext_emit_block(context, phi_block); + + if (!else_block_exit) + { + return normal_value; + } + if (!success_end_block) + { + return else_value; + } + + LLVMValueRef phi = LLVMBuildPhi(context->builder, llvm_type(expr->type), "val"); + + LLVMValueRef logic_values[2] = { normal_value, else_value }; + LLVMBasicBlockRef blocks[2] = { success_end_block, else_block_exit }; + LLVMAddIncoming(phi, logic_values, blocks, 2); + + return phi; + +} + static LLVMValueRef gencontext_emit_binary_expr(GenContext *context, Expr *expr) { BinaryOp binary_op = expr->binary_expr.operator; @@ -976,18 +1056,25 @@ LLVMValueRef gencontext_emit_ternary_expr(GenContext *context, Expr *expr) gencontext_emit_block(context, lhs_block); LLVMValueRef lhs = gencontext_emit_expr(context, expr->ternary_expr.then_expr); - LLVMBasicBlockRef lhs_exit = context->current_block; - gencontext_emit_br(context, phi_block); + LLVMBasicBlockRef lhs_exit = gencontext_current_block_if_in_use(context); + if (lhs_exit) gencontext_emit_br(context, phi_block); gencontext_emit_block(context, rhs_block); LLVMValueRef rhs = gencontext_emit_expr(context, expr->ternary_expr.else_expr); - LLVMBasicBlockRef rhs_exit = context->current_block; - gencontext_emit_br(context, phi_block); + LLVMBasicBlockRef rhs_exit = gencontext_current_block_if_in_use(context); + if (rhs_exit) gencontext_emit_br(context, phi_block); // Generate phi gencontext_emit_block(context, phi_block); + if (!rhs_exit) + { + return lhs; + } + if (!lhs_exit) + { + return rhs; + } LLVMValueRef phi = LLVMBuildPhi(context->builder, llvm_type(expr->type), "val"); - LLVMValueRef logic_values[2] = { lhs, rhs }; LLVMBasicBlockRef blocks[2] = { lhs_exit, rhs_exit }; LLVMAddIncoming(phi, logic_values, blocks, 2); @@ -1273,8 +1360,9 @@ static inline LLVMValueRef gencontext_emit_failable(GenContext *context, Expr *e LLVMBuildStore(context->builder, value, gencontext_emit_bitcast(context, context->error_var, type_get_ptr(fail->type))); } gencontext_emit_br(context, context->catch_block); - LLVMBasicBlockRef ignored_block = gencontext_create_free_block(context, ""); + LLVMBasicBlockRef ignored_block = gencontext_create_free_block(context, "postfailed"); gencontext_emit_block(context, ignored_block); + if (expr->type->canonical == type_void) return NULL; return LLVMGetUndef(llvm_type(expr->type)); } @@ -1325,7 +1413,7 @@ NESTED_RETRY: case EXPR_CATCH: return gencontext_emit_trycatch_expr(context, expr); case EXPR_ELSE: - TODO + return gencontext_emit_else_expr(context, expr); case EXPR_MACRO_BLOCK: return gencontext_emit_macro_block(context, expr); case EXPR_COMPOUND_LITERAL: diff --git a/src/compiler/llvm_codegen_function.c b/src/compiler/llvm_codegen_function.c index f29d5df6c..a7842c20a 100644 --- a/src/compiler/llvm_codegen_function.c +++ b/src/compiler/llvm_codegen_function.c @@ -153,8 +153,8 @@ void gencontext_emit_function_body(GenContext *context, Decl *decl) // Insert a return (and defer) if needed. if (context->current_block && !LLVMGetBasicBlockTerminator(context->current_block)) { - assert(decl->func.body->compound_stmt.defer_list.end == NULL); - gencontext_emit_defer(context, decl->func.body->compound_stmt.defer_list.start, NULL); + assert(!decl->func.body->compound_stmt.defer_list.end); + gencontext_emit_defer(context, decl->func.body->compound_stmt.defer_list.start, 0); gencontext_emit_implicit_return(context); } @@ -246,7 +246,6 @@ void gencontext_emit_function_decl(GenContext *context, Decl *decl) flags |= LLVMDIFlagPublic; break; } - SourcePosition decl_position = source_file_find_position(decl->name_span.loc); /* context->debug.function = LLVMDIBuilderCreateFunction(context->debug.builder, context->debug.compile_unit, decl->name, source_range_len(decl->name_span), diff --git a/src/compiler/llvm_codegen_internal.h b/src/compiler/llvm_codegen_internal.h index ee7d8d54a..12302577f 100644 --- a/src/compiler/llvm_codegen_internal.h +++ b/src/compiler/llvm_codegen_internal.h @@ -40,7 +40,7 @@ typedef struct LLVMMetadataRef file; LLVMMetadataRef compile_unit; LLVMMetadataRef function; - SourceRange current_range; + SourceSpan current_range; LLVMMetadataRef *lexical_block_stack; LLVMMetadataRef inlined_at; } DebugContext; @@ -119,12 +119,12 @@ void gencontext_generate_catch_block_if_needed(GenContext *context, Ast *ast); LLVMValueRef gencontext_emit_call_intrinsic(GenContext *context, unsigned intrinsic_id, LLVMTypeRef *types, LLVMValueRef *values, unsigned arg_count); void gencontext_emit_panic_on_true(GenContext *context, LLVMValueRef value, const char *panic_name); -void gencontext_emit_defer(GenContext *context, Ast *defer_start, Ast *defer_end); +void gencontext_emit_defer(GenContext *context, AstId defer_start, AstId defer_end); LLVMValueRef gencontext_emit_expr(GenContext *context, Expr *expr); LLVMValueRef gencontext_emit_assign_expr(GenContext *context, LLVMValueRef ref, Expr *expr, LLVMValueRef failable); LLVMMetadataRef gencontext_get_debug_type(GenContext *context, Type *type); -void gencontext_emit_debug_location(GenContext *context, SourceRange location); +void gencontext_emit_debug_location(GenContext *context, SourceSpan location); LLVMMetadataRef gencontext_create_builtin_debug_type(GenContext *context, Type *builtin_type); LLVMValueRef gencontext_emit_alloca(GenContext *context, LLVMTypeRef type, const char *name); void gencontext_emit_compound_stmt(GenContext *context, Ast *ast); @@ -138,6 +138,25 @@ static inline LLVMBasicBlockRef gencontext_create_free_block(GenContext *context { return LLVMCreateBasicBlockInContext(context->context, name); } + +static inline bool block_in_use(LLVMBasicBlockRef block) +{ + return LLVMGetFirstUse(LLVMBasicBlockAsValue(block)) != NULL; +} + +static inline LLVMBasicBlockRef gencontext_current_block_if_in_use(GenContext *context) +{ + LLVMBasicBlockRef block = context->current_block; + if (!LLVMGetFirstInstruction(block) && !LLVMGetFirstUse(LLVMBasicBlockAsValue(block))) + { + LLVMDeleteBasicBlock(block); + context->current_block = NULL; + context->current_block_is_target = false; + return NULL; + } + return block; +} + #define PUSH_ERROR() \ LLVMBasicBlockRef _old_catch = context->catch_block; \ LLVMValueRef _old_error_var = context->error_var @@ -173,7 +192,6 @@ static inline LLVMValueRef decl_failable_ref(Decl *decl) static inline LLVMValueRef decl_ref(Decl *decl) { - assert(decl->decl_kind == DECL_VAR); if (decl->decl_kind == DECL_VAR && decl->var.kind == VARDECL_ALIAS) return decl_ref(decl->var.alias); return decl->ref; } diff --git a/src/compiler/llvm_codegen_stmt.c b/src/compiler/llvm_codegen_stmt.c index 324179ba7..4884297ec 100644 --- a/src/compiler/llvm_codegen_stmt.c +++ b/src/compiler/llvm_codegen_stmt.c @@ -141,7 +141,7 @@ static inline void gencontext_emit_return(GenContext *context, Ast *ast) POP_ERROR(); - gencontext_emit_defer(context, ast->return_stmt.defer, NULL); + gencontext_emit_defer(context, ast->return_stmt.defer, 0); // Are we in an expression block? if (context->expr_block_exit) @@ -231,7 +231,7 @@ void gencontext_emit_if(GenContext *context, Ast *ast) POP_ERROR(); - Decl *label = ast->if_stmt.label; + Decl *label = ast->if_stmt.flow.label; if (label) { label->label.break_target = exit_block; @@ -349,7 +349,7 @@ void gencontext_emit_while_stmt(GenContext *context, Ast *ast) // Emit cond gencontext_emit_br(context, begin_block); gencontext_emit_block(context, begin_block); - DeferList defers = { NULL, NULL }; + DeferList defers = { 0, 0 }; Expr *cond = ast->while_stmt.cond; if (cond->expr_kind == EXPR_SCOPED_EXPR) { @@ -550,8 +550,8 @@ void gencontext_emit_switch_body(GenContext *context, LLVMValueRef switch_value, LLVMBasicBlockRef exit_block = gencontext_create_free_block(context, "switch.exit"); LLVMBasicBlockRef switch_block = gencontext_create_free_block(context, "switch.entry"); - switch_ast->switch_stmt.retry_block = switch_block; - switch_ast->switch_stmt.exit_block = exit_block; + switch_ast->switch_stmt.codegen.retry_block = switch_block; + switch_ast->switch_stmt.codegen.exit_block = exit_block; // We will now treat the fallthrough cases: // switch (i) @@ -577,7 +577,7 @@ void gencontext_emit_switch_body(GenContext *context, LLVMValueRef switch_value, Type *switch_type = switch_ast->switch_stmt.cond->type; LLVMValueRef switch_var = gencontext_emit_alloca(context, llvm_type(switch_type), ""); - switch_ast->switch_stmt.retry_var = switch_var; + switch_ast->switch_stmt.codegen.retry_var = switch_var; LLVMBuildStore(context->builder, switch_value, switch_var); gencontext_emit_br(context, switch_block); @@ -624,14 +624,15 @@ void gencontext_emit_switch(GenContext *context, Ast *ast) return gencontext_emit_switch_body(context, switch_value, ast); } -void gencontext_emit_defer(GenContext *context, Ast *defer_start, Ast *defer_end) +void gencontext_emit_defer(GenContext *context, AstId defer_start, AstId defer_end) { if (defer_start == defer_end) return; - Ast *defer = defer_start; + AstId defer = defer_start; while (defer && defer != defer_end) { - gencontext_emit_stmt(context, defer->defer_stmt.body); - defer = defer->defer_stmt.prev_defer; + Ast *def = astptr(defer); + gencontext_emit_stmt(context, def->defer_stmt.body); + defer = def->defer_stmt.prev_defer; } } @@ -639,7 +640,7 @@ void gencontext_emit_defer(GenContext *context, Ast *defer_start, Ast *defer_end void gencontext_emit_break(GenContext *context, Ast *ast) { gencontext_emit_defer(context, ast->contbreak_stmt.defers.start, ast->contbreak_stmt.defers.end); - Ast *jump_target = ast->contbreak_stmt.ast; + Ast *jump_target = astptr(ast->contbreak_stmt.ast); LLVMBasicBlockRef jump; switch (jump_target->ast_kind) { @@ -656,7 +657,7 @@ void gencontext_emit_break(GenContext *context, Ast *ast) jump = jump_target->do_stmt.break_block; break; case AST_SWITCH_STMT: - jump = jump_target->switch_stmt.exit_block; + jump = jump_target->switch_stmt.codegen.exit_block; break; default: UNREACHABLE @@ -666,7 +667,7 @@ void gencontext_emit_break(GenContext *context, Ast *ast) void gencontext_emit_continue(GenContext *context, Ast *ast) { gencontext_emit_defer(context, ast->contbreak_stmt.defers.start, ast->contbreak_stmt.defers.end); - Ast *jump_target = ast->contbreak_stmt.ast; + Ast *jump_target = astptr(ast->contbreak_stmt.ast); LLVMBasicBlockRef jump; switch (jump_target->ast_kind) { @@ -691,7 +692,7 @@ void gencontext_emit_continue(GenContext *context, Ast *ast) void gencontext_emit_next_stmt(GenContext *context, Ast *ast) { - Ast *jump_target = ast->next_stmt.case_switch_stmt; + Ast *jump_target = astptr(ast->next_stmt.case_switch_stmt); if (jump_target->ast_kind != AST_SWITCH_STMT) { gencontext_emit_defer(context, ast->next_stmt.defers.start, ast->next_stmt.defers.end); @@ -699,9 +700,9 @@ void gencontext_emit_next_stmt(GenContext *context, Ast *ast) return; } LLVMValueRef value = gencontext_emit_expr(context, ast->next_stmt.switch_expr); - LLVMBuildStore(context->builder, value, jump_target->switch_stmt.retry_var); + LLVMBuildStore(context->builder, value, jump_target->switch_stmt.codegen.retry_var); gencontext_emit_defer(context, ast->next_stmt.defers.start, ast->next_stmt.defers.end); - gencontext_emit_jmp(context, jump_target->switch_stmt.retry_block); + gencontext_emit_jmp(context, jump_target->switch_stmt.codegen.retry_block); } void gencontext_emit_scoped_stmt(GenContext *context, Ast *ast) diff --git a/src/compiler/module.c b/src/compiler/module.c index 3af6b753a..307717a2e 100644 --- a/src/compiler/module.c +++ b/src/compiler/module.c @@ -33,7 +33,7 @@ Decl *module_find_symbol(Module *module, const char *symbol, ModuleSymbolSearch return decl; } -Path *path_create_from_string(const char *string, size_t len, SourceRange span) +Path *path_create_from_string(Context *context, const char *string, size_t len, SourceSpan span) { Path *path = CALLOCS(Path); path->span = span; @@ -42,19 +42,19 @@ Path *path_create_from_string(const char *string, size_t len, SourceRange span) path->len = len; if (type != TOKEN_IDENT) { - sema_error_range(span, "A module name was expected here."); + SEMA_ERROR(path, "A module name was expected here."); return NULL; } return path; } -Path *path_find_parent_path(Path *path) +Path *path_find_parent_path(Context *context, Path *path) { const char *last_scope_chars = strrchr(path->module, ':'); // No parent if (!last_scope_chars) return NULL; - Path *parent_path = path_create_from_string(path->module, last_scope_chars - path->module - 1, INVALID_RANGE); + Path *parent_path = path_create_from_string(context, path->module, last_scope_chars - path->module - 1, INVALID_RANGE); // Should never fail. assert(parent_path); diff --git a/src/compiler/parse_expr.c b/src/compiler/parse_expr.c index 0a33e15b0..c793e2bf0 100644 --- a/src/compiler/parse_expr.c +++ b/src/compiler/parse_expr.c @@ -77,13 +77,11 @@ bool parse_param_list(Context *context, Expr ***result, bool allow_type, TokenTy *result = NULL; while (1) { - TypeInfo *type = NULL; Expr *expr = NULL; - SourceRange start = context->tok.span; // Special handling of [123] - if (context->tok.type == TOKEN_LBRACKET) + if (TOKEN_IS(TOKEN_LBRACKET)) { - expr = expr_new(EXPR_SUBSCRIPT, context->tok.span); + expr = EXPR_NEW_TOKEN(EXPR_SUBSCRIPT, context->tok); advance_and_verify(context, TOKEN_LBRACKET); expr->subscript_expr.index = TRY_EXPR_OR(parse_expr(context), false); CONSUME_OR(TOKEN_RBRACKET, false); @@ -99,7 +97,7 @@ bool parse_param_list(Context *context, Expr ***result, bool allow_type, TokenTy { return true; } - if (context->tok.type == param_end) return true; + if (TOKEN_IS(param_end)) return true; } } @@ -112,7 +110,7 @@ static Expr *parse_macro_ident(Context *context, Expr *left) bool had_error = false; macro_ident->identifier_expr.path = parse_path_prefix(context, &had_error); if (had_error) return poisoned_expr; - macro_ident->identifier_expr.identifier = context->tok.string; + macro_ident->identifier_expr.identifier = TOKSTR(context->tok); CONSUME_OR(TOKEN_IDENT, poisoned_expr); RANGE_EXTEND_PREV(macro_ident); return macro_ident; @@ -239,7 +237,7 @@ static Expr *parse_ternary_expr(Context *context, Expr *left_side) { assert(expr_ok(left_side)); - if (context->tok.type == TOKEN_QUESTION && token_may_end_expression(context->next_tok.type)) + if (TOKEN_IS(TOKEN_QUESTION) && token_may_end_expression(context->next_tok.type)) { return parse_check_failable(context, left_side); } @@ -275,7 +273,7 @@ static Expr *parse_ternary_expr(Context *context, Expr *left_side) static Expr *parse_grouping_expr(Context *context, Expr *left) { assert(!left && "Unexpected left hand side"); - Expr *expr = expr_new(EXPR_GROUP, context->tok.span); + Expr *expr = EXPR_NEW_TOKEN(EXPR_GROUP, context->tok); advance_and_verify(context, TOKEN_LPAREN); expr->group_expr = TRY_EXPR_OR(parse_expr(context), poisoned_expr); CONSUME_OR(TOKEN_RPAREN, poisoned_expr); @@ -294,7 +292,7 @@ static Expr *parse_grouping_expr(Context *context, Expr *left) */ Expr *parse_initializer(Context *context) { - if (context->tok.type == TOKEN_LBRACE) + if (TOKEN_IS(TOKEN_LBRACE)) { return parse_initializer_list(context); } @@ -346,7 +344,7 @@ static Expr *parse_binary(Context *context, Expr *left_side) advance(context); Expr *right_side; - if (context->tok.type == TOKEN_LBRACE && operator_type == TOKEN_EQ) + if (TOKEN_IS(TOKEN_LBRACE) && operator_type == TOKEN_EQ) { right_side = TRY_EXPR_OR(parse_initializer_list(context), poisoned_expr); } @@ -369,7 +367,7 @@ static Expr *parse_call_expr(Context *context, Expr *left) Expr **params = NULL; advance_and_verify(context, TOKEN_LPAREN); - if (context->tok.type != TOKEN_RPAREN) + if (!TOKEN_IS(TOKEN_RPAREN)) { if (!parse_param_list(context, ¶ms, 0, TOKEN_RPAREN)) return poisoned_expr; } @@ -404,10 +402,10 @@ static Expr *parse_access_expr(Context *context, Expr *left) advance_and_verify(context, TOKEN_DOT); Expr *access_expr = EXPR_NEW_EXPR(EXPR_ACCESS, left); access_expr->access_expr.parent = left; - access_expr->access_expr.sub_element = context->tok; + access_expr->access_expr.sub_element = context->tok.id; TRY_CONSUME_OR(TOKEN_IDENT, "Expected identifier", poisoned_expr); access_expr->span = left->span; - access_expr->span.end_loc = access_expr->access_expr.sub_element.span.end_loc; + access_expr->span.end_loc = access_expr->access_expr.sub_element; return access_expr; } @@ -415,7 +413,7 @@ static Expr *parse_access_expr(Context *context, Expr *left) static Expr *parse_identifier_with_path(Context *context, Path *path) { Expr *expr = EXPR_NEW_TOKEN(EXPR_IDENTIFIER, context->tok); - expr->identifier_expr.identifier = context->tok.string; + expr->identifier_expr.identifier = TOKSTR(context->tok); expr->identifier_expr.path = path; advance(context); return expr; @@ -451,7 +449,7 @@ static Expr *parse_maybe_scope(Context *context, Expr *left) static Expr *parse_try_expr(Context *context, Expr *left) { assert(!left && "Unexpected left hand side"); - Expr *try_expr = EXPR_NEW_TOKEN(context->tok.type == TOKEN_TRY ? EXPR_TRY : EXPR_CATCH, context->tok); + Expr *try_expr = EXPR_NEW_TOKEN(TOKEN_IS(TOKEN_TRY) ? EXPR_TRY : EXPR_CATCH, context->tok); advance(context); CONSUME_OR(TOKEN_LPAREN, poisoned_expr); try_expr->trycatch_expr = TRY_EXPR_OR(parse_expr(context), poisoned_expr); @@ -481,7 +479,7 @@ static Expr *parse_else_expr(Context *context, Expr *left) Ast *ast = TRY_AST_OR(parse_jump_stmt_no_eos(context), poisoned_expr); else_expr->else_expr.is_jump = true; else_expr->else_expr.else_stmt = ast; - if (context->tok.type != TOKEN_EOS) + if (!TOKEN_IS(TOKEN_EOS)) { SEMA_ERROR(ast, "An else jump statement must end with a ';'"); return poisoned_expr; @@ -499,8 +497,8 @@ static Expr *parse_integer(Context *context, Expr *left) { assert(!left && "Had left hand side"); Expr *expr_int = EXPR_NEW_TOKEN(EXPR_CONST, context->tok); - const char *string = context->tok.start; - const char *end = string + source_range_len(context->tok.span); + const char *string = TOKSTR(context->tok); + const char *end = string + TOKLEN(context->tok); if (string[0] == '\'') { union @@ -575,7 +573,7 @@ static Expr *parse_integer(Context *context, Expr *left) BigInt ten; bigint_init_unsigned(&ten, 10); BigInt res; - switch (source_range_len(context->tok.span) > 2 ? string[1] : '0') + switch (TOKLEN(context->tok) > 2 ? string[1] : '0') { case 'x': string += 2; @@ -643,18 +641,10 @@ static Expr *parse_double(Context *context, Expr *left) { assert(!left && "Had left hand side"); Expr *number = EXPR_NEW_TOKEN(EXPR_CONST, context->tok); - char *end = NULL; - // IMPROVE - long double fval = strtold(context->tok.start, &end); - if (end != source_range_len(context->tok.span) + context->tok.start) - { - SEMA_TOKEN_ERROR(context->tok, "Invalid float value"); - return poisoned_expr; - } - advance(context); - number->const_expr.f = fval; + number->const_expr.f = TOKREAL(context->tok.id); number->type = type_compfloat; number->const_expr.kind = TYPE_FXX; + advance(context); return number; } @@ -760,17 +750,18 @@ static Expr *parse_string_literal(Context *context, Expr *left) char *str = NULL; size_t len = 0; - while (context->tok.type == TOKEN_STRING) + while (TOKEN_IS(TOKEN_STRING)) { - char *new_string = malloc_arena(len + source_range_len(context->tok.span)); + char *new_string = malloc_arena(len + TOKLEN(context->tok)); if (str) memcpy(new_string, str, len); + const char *sourcestr = TOKSTR(context->tok); str = new_string; - for (unsigned i = 1; i < source_range_len(context->tok.span) - 1; i++) + for (unsigned i = 1; i < TOKLEN(context->tok) - 1; i++) { - if (context->tok.string[i] == '\\') + if (sourcestr[i] == '\\') { i++; - int scanned = append_esc_string_token(str, context->tok.string + i, &len) - 1; + int scanned = append_esc_string_token(str, sourcestr + i, &len) - 1; if (scanned < -1) { SEMA_TOKEN_ERROR(context->tok, "Invalid escape in string."); @@ -779,7 +770,7 @@ static Expr *parse_string_literal(Context *context, Expr *left) i += scanned; continue; } - str[len++] = context->tok.string[i]; + str[len++] = sourcestr[i]; } advance_and_verify(context, TOKEN_STRING); } @@ -797,7 +788,7 @@ static Expr *parse_bool(Context *context, Expr *left) { assert(!left && "Had left hand side"); Expr *number = EXPR_NEW_TOKEN(EXPR_CONST, context->tok); - number->const_expr = (ExprConst) { .b = context->tok.type == TOKEN_TRUE, .kind = TYPE_BOOL }; + number->const_expr = (ExprConst) { .b = TOKEN_IS(TOKEN_TRUE), .kind = TYPE_BOOL }; number->type = type_bool; number->resolve_status = RESOLVE_DONE; advance(context); @@ -837,7 +828,7 @@ Expr *parse_type_access_expr_after_type(Context *context, TypeInfo *type_info) } Expr *expr = expr_new(EXPR_TYPE_ACCESS, type_info->span); expr->type_access.type = type_info; - expr->type_access.name = context->tok; + expr->type_access.name = context->tok.id; advance(context); RANGE_EXTEND_PREV(expr); return parse_precedence_with_left_side(context, expr, PREC_CALL - 1); @@ -855,12 +846,12 @@ Expr *parse_type_access_expr_after_type(Context *context, TypeInfo *type_info) */ Expr *parse_type_expression_with_path(Context *context, Path *path) { - TypeInfo *type = type_info_new(TYPE_INFO_IDENTIFIER, path ? path->span : context->tok.span ); + TypeInfo *type = type_info_new(TYPE_INFO_IDENTIFIER, path ? path->span : source_span_from_token_id(context->tok.id)); type->unresolved.path = path; - type->unresolved.name_loc = context->tok; + type->unresolved.name_loc = context->tok.id; advance_and_verify(context, TOKEN_TYPE_IDENT); RANGE_EXTEND_PREV(type); - if (context->tok.type == TOKEN_LBRACE) + if (TOKEN_IS(TOKEN_LBRACE)) { return parse_type_compound_literal_expr_after_type(context, type); } diff --git a/src/compiler/parse_stmt.c b/src/compiler/parse_stmt.c index fae6e38a9..74ce0cf2d 100644 --- a/src/compiler/parse_stmt.c +++ b/src/compiler/parse_stmt.c @@ -23,9 +23,9 @@ static inline Ast *parse_declaration_stmt(Context *context) static inline Decl *parse_optional_label(Context *context, Ast *parent) { - if (context->tok.type != TOKEN_CONST_IDENT) return NULL; - Decl *decl = decl_new(DECL_LABEL, context->tok, VISIBLE_LOCAL); - decl->label.parent = parent; + if (!TOKEN_IS(TOKEN_CONST_IDENT)) return NULL; + Decl *decl = decl_new(DECL_LABEL, context->tok.id, VISIBLE_LOCAL); + decl->label.parent = astid(parent); advance_and_verify(context, TOKEN_CONST_IDENT); if (!try_consume(context, TOKEN_COLON)) { @@ -37,51 +37,55 @@ static inline Decl *parse_optional_label(Context *context, Ast *parent) static inline void parse_optional_label_target(Context *context, Label *label) { - if (context->tok.type == TOKEN_CONST_IDENT) + if (TOKEN_IS(TOKEN_CONST_IDENT)) { - label->span = context->tok.span; - label->name = context->tok.string; + label->span = context->tok.id; + label->name = TOKKSTR(context->tok); advance_and_verify(context, TOKEN_CONST_IDENT); } } static inline bool parse_asm_param(Context *context, AsmOperand **list) { + TODO + /* AsmOperand operand; // Reset parser - context->lexer.current = context->tok.span.loc + context->lexer.file_begin; + context->lexer.current = context->token->span.loc + context->lexer.file_begin; operand.constraints = lexer_scan_asm_constraint(&context->lexer); if (operand.constraints.type == TOKEN_INVALID_TOKEN) return false; // Restore state - context->tok = lexer_scan_token(&context->lexer); - context->next_tok = lexer_scan_token(&context->lexer); + TODO + //context->tok = lexer_scan_token(&context->lexer); + //context->next_tok = lexer_scan_token(&context->lexer); operand.expr = TRY_EXPR_OR(parse_expr(context), false); if (try_consume(context, TOKEN_AS)) { EXPECT_OR(TOKEN_IDENT, false); - operand.alias = context->tok; + //operand.alias = context->tok; advance(context); } vec_add(*list, operand); - return true; + return true;*/ } static inline bool parse_asm_paramlist(Context *context, AsmOperand **list) { - if (context->tok.type == TOKEN_EOS || context->tok.type == TOKEN_RPAREN) return true; + if (TOKEN_IS(TOKEN_EOS) || TOKEN_IS(TOKEN_RPAREN)) return true; while (1) { if (!parse_asm_param(context, list)) return false; - if (context->tok.type == TOKEN_EOS || context->tok.type == TOKEN_RPAREN) return true; + if (TOKEN_IS(TOKEN_EOS) || TOKEN_IS(TOKEN_RPAREN)) return true; CONSUME_OR(TOKEN_COMMA, false); } } static inline bool parse_asm_params(Context *context, Ast *asm_ast) { + /* // Might be empty. if (try_consume(context, TOKEN_RPAREN)) return true; @@ -106,7 +110,7 @@ static inline bool parse_asm_params(Context *context, Ast *asm_ast) while (1) { EXPECT_OR(TOKEN_IDENT, false); - vec_add(params->clobbers, context->tok); + vec_add(params->clobbers, context->token); if (!try_consume(context, TOKEN_COMMA)) break; } @@ -119,7 +123,7 @@ static inline bool parse_asm_params(Context *context, Ast *asm_ast) while (1) { EXPECT_OR(TOKEN_IDENT, false); - vec_add(params->labels, context->tok); + vec_add(params->labels, context->token); if (!try_consume(context, TOKEN_COMMA)) break; } @@ -127,6 +131,8 @@ static inline bool parse_asm_params(Context *context, Ast *asm_ast) CONSUME_OR(TOKEN_RPAREN, false); return true; + */ + TODO } /** * asm { ... } @@ -135,6 +141,8 @@ static inline bool parse_asm_params(Context *context, Ast *asm_ast) */ static inline Ast* parse_asm_stmt(Context *context) { + TODO + /* Ast *ast = AST_NEW_TOKEN(AST_ASM_STMT, context->tok); advance_and_verify(context, TOKEN_ASM); if (try_consume(context, TOKEN_LPAREN)) @@ -142,29 +150,31 @@ static inline Ast* parse_asm_stmt(Context *context) if (!parse_asm_params(context, ast)) return poisoned_ast; } - if (context->tok.type != TOKEN_LBRACE) + if (!TOKEN_IS(TOKEN_LBRACE)) { SEMA_TOKEN_ERROR(context->tok, "Expected '{' to start asm segment."); return poisoned_ast; } - context->lexer.current = context->next_tok.span.loc + context->lexer.file_begin; + context->lexer.current = context->next_tok->span.loc + context->lexer.file_begin; while (1) { - context->tok = lexer_scan_asm(&context->lexer); + TODO + //context->tok = lexer_scan_asm(&context->lexer); TokenType type = context->tok.type; if (type == TOKEN_RBRACE || type == TOKEN_EOF) break; - context->prev_tok_end = context->tok.span.end_loc; - vec_add(ast->asm_stmt.instructions, context->tok); + context->prev_tok_end = context->token->span.end_loc; + vec_add(ast->asm_stmt.instructions, context->token); } - if (context->tok.type == TOKEN_EOF) + if (TOKEN_IS(TOKEN_EOF)) { sema_error_at(context->prev_tok_end, "Unexpected end of file while parsing asm, did you forget a '}'?"); return poisoned_ast; } - assert(context->tok.type == TOKEN_RBRACE); - context->tok = lexer_scan_token(&context->lexer); - context->next_tok = lexer_scan_token(&context->lexer); + assert(TOKEN_IS(TOKEN_RBRACE)); + //context->tok = lexer_scan_token(&context->lexer); + //context->next_tok = lexer_scan_token(&context->lexer); return ast; + */ } @@ -178,7 +188,7 @@ static inline Ast* parse_do_stmt(Context *context) advance_and_verify(context, TOKEN_DO); - do_ast->do_stmt.label = TRY_DECL_OR(parse_optional_label(context, do_ast), poisoned_ast); + do_ast->do_stmt.flow.label = TRY_DECL_OR(parse_optional_label(context, do_ast), poisoned_ast); do_ast->do_stmt.body = TRY_AST(parse_stmt(context)); if (try_consume(context, TOKEN_WHILE)) @@ -221,7 +231,7 @@ static inline Ast* parse_catch_stmt(Context *context) Ast *catch_stmt = AST_NEW_TOKEN(AST_CATCH_STMT, context->tok); advance_and_verify(context, TOKEN_CATCH); - catch_stmt->catch_stmt.label = TRY_DECL_OR(parse_optional_label(context, catch_stmt), false); + catch_stmt->catch_stmt.flow.label = TRY_DECL_OR(parse_optional_label(context, catch_stmt), false); CONSUME_OR(TOKEN_LPAREN, poisoned_ast); @@ -229,7 +239,7 @@ static inline Ast* parse_catch_stmt(Context *context) CONSUME_OR(TOKEN_RPAREN, poisoned_ast); - if (context->tok.type == TOKEN_LBRACE && (context->next_tok.type == TOKEN_CASE || context->next_tok.type == TOKEN_DEFAULT)) + if (TOKEN_IS(TOKEN_LBRACE) && (context->next_tok.type == TOKEN_CASE || context->next_tok.type == TOKEN_DEFAULT)) { catch_stmt->catch_stmt.is_switch = true; if (!parse_switch_body(context, &catch_stmt->catch_stmt.cases, TOKEN_CASE, TOKEN_DEFAULT)) return poisoned_ast; @@ -262,7 +272,7 @@ static inline Ast* parse_while_stmt(Context *context) Ast *while_ast = AST_NEW_TOKEN(AST_WHILE_STMT, context->tok); advance_and_verify(context, TOKEN_WHILE); - while_ast->while_stmt.label = TRY_DECL_OR(parse_optional_label(context, while_ast), poisoned_ast); + while_ast->while_stmt.flow.label = TRY_DECL_OR(parse_optional_label(context, while_ast), poisoned_ast); CONSUME_OR(TOKEN_LPAREN, poisoned_ast); while_ast->while_stmt.cond = TRY_EXPR_OR(parse_decl_expr_list(context), poisoned_ast); @@ -294,7 +304,7 @@ static inline Ast* parse_if_stmt(Context *context) { Ast *if_ast = AST_NEW_TOKEN(AST_IF_STMT, context->tok); advance_and_verify(context, TOKEN_IF); - if_ast->if_stmt.label = TRY_DECL_OR(parse_optional_label(context, if_ast), poisoned_ast); + if_ast->if_stmt.flow.label = TRY_DECL_OR(parse_optional_label(context, if_ast), poisoned_ast); CONSUME_OR(TOKEN_LPAREN, poisoned_ast); if_ast->if_stmt.cond = TRY_EXPR_OR(parse_decl_expr_list(context), poisoned_ast); CONSUME_OR(TOKEN_RPAREN, poisoned_ast); @@ -391,7 +401,7 @@ bool parse_switch_body(Context *context, Ast ***cases, TokenType case_type, Toke } else { - SEMA_TOKEN_ERROR(context->tok, "A 'case' or 'default' would be needed here, '%.*s' is not allowed.", source_range_len(context->tok.span), context->tok.start); + SEMA_TOKEN_ERROR(context->tok, "A 'case' or 'default' would be needed here, '%.*s' is not allowed.", TOKLEN(context->tok.id), TOKSTR(context->tok.id)); return false; } vec_add((*cases), result); @@ -408,7 +418,7 @@ static inline Ast* parse_switch_stmt(Context *context) { Ast *switch_ast = AST_NEW_TOKEN(AST_SWITCH_STMT, context->tok); advance_and_verify(context, TOKEN_SWITCH); - switch_ast->switch_stmt.label = TRY_DECL_OR(parse_optional_label(context, switch_ast), poisoned_ast); + switch_ast->switch_stmt.flow.label = TRY_DECL_OR(parse_optional_label(context, switch_ast), poisoned_ast); CONSUME_OR(TOKEN_LPAREN, poisoned_ast); switch_ast->switch_stmt.cond = TRY_EXPR_OR(parse_decl_expr_list(context), poisoned_ast); CONSUME_OR(TOKEN_RPAREN, poisoned_ast); @@ -432,10 +442,10 @@ static inline Ast* parse_for_stmt(Context *context) { Ast *ast = AST_NEW_TOKEN(AST_FOR_STMT, context->tok); advance_and_verify(context, TOKEN_FOR); - ast->for_stmt.label = TRY_DECL_OR(parse_optional_label(context, ast), poisoned_ast); + ast->for_stmt.flow.label = TRY_DECL_OR(parse_optional_label(context, ast), poisoned_ast); CONSUME_OR(TOKEN_LPAREN, poisoned_ast); - if (context->tok.type != TOKEN_EOS) + if (!TOKEN_IS(TOKEN_EOS)) { ast->for_stmt.init = TRY_EXPR_OR(parse_decl_expr_list(context), poisoned_ast); } @@ -446,14 +456,14 @@ static inline Ast* parse_for_stmt(Context *context) CONSUME_OR(TOKEN_EOS, poisoned_ast); - if (context->tok.type != TOKEN_EOS) + if (!TOKEN_IS(TOKEN_EOS)) { ast->for_stmt.cond = TRY_EXPR_OR(parse_expr(context), poisoned_ast); } CONSUME_OR(TOKEN_EOS, poisoned_ast); - if (context->tok.type != TOKEN_RPAREN) + if (!TOKEN_IS(TOKEN_RPAREN)) { ast->for_stmt.incr = parse_expression_list(context); } @@ -488,9 +498,9 @@ static inline Ast* parse_next(Context *context) { Ast *ast = AST_NEW_TOKEN(AST_NEXT_STMT, context->tok); advance_and_verify(context, TOKEN_NEXT); - if (context->tok.type != TOKEN_EOS) + if (!TOKEN_IS(TOKEN_EOS)) { - if (context->tok.type == TOKEN_CONST_IDENT && context->next_tok.type == TOKEN_COLON) + if (TOKEN_IS(TOKEN_CONST_IDENT) && context->next_tok.type == TOKEN_COLON) { parse_optional_label_target(context, &ast->next_stmt.label); advance_and_verify(context, TOKEN_COLON); @@ -567,7 +577,7 @@ static inline Ast *parse_define_stmt(Context *context) Ast *ast = AST_NEW_TOKEN(AST_DEFINE_STMT, context->tok); advance_and_verify(context, TOKEN_DEFINE); - Decl *decl = decl_new_var(context->tok, NULL, VARDECL_LOCAL_CT, VISIBLE_LOCAL); + Decl *decl = decl_new_var(context->tok.id, NULL, VARDECL_LOCAL_CT, VISIBLE_LOCAL); ast->define_stmt = decl; switch (context->tok.type) @@ -619,11 +629,11 @@ static inline Ast *parse_ct_elif_stmt(Context *context) ast->ct_elif_stmt.then = TRY_AST(parse_compound_stmt(context)); - if (context->tok.type == TOKEN_CT_ELIF) + if (TOKEN_IS(TOKEN_CT_ELIF)) { ast->ct_elif_stmt.elif = TRY_AST(parse_ct_elif_stmt(context)); } - else if (context->tok.type == TOKEN_CT_ELSE) + else if (TOKEN_IS(TOKEN_CT_ELSE)) { ast->ct_elif_stmt.elif = TRY_AST(parse_ct_else_stmt(context)); } @@ -642,11 +652,11 @@ static inline Ast* parse_ct_if_stmt(Context *context) advance_and_verify(context, TOKEN_CT_IF); ast->ct_if_stmt.expr = TRY_EXPR_OR(parse_paren_expr(context), poisoned_ast); ast->ct_if_stmt.then = TRY_AST(parse_compound_stmt(context)); - if (context->tok.type == TOKEN_CT_ELIF) + if (TOKEN_IS(TOKEN_CT_ELIF)) { ast->ct_if_stmt.elif = TRY_AST(parse_ct_elif_stmt(context)); } - else if (context->tok.type == TOKEN_CT_ELSE) + else if (TOKEN_IS(TOKEN_CT_ELSE)) { ast->ct_if_stmt.elif = TRY_AST(parse_ct_else_stmt(context)); } @@ -665,8 +675,8 @@ static inline Ast *parse_return(Context *context) { advance_and_verify(context, TOKEN_RETURN); Ast *ast = AST_NEW_TOKEN(AST_RETURN_STMT, context->tok); - ast->return_stmt.defer = NULL; - if (context->tok.type != TOKEN_EOS) + ast->return_stmt.defer = 0; + if (!TOKEN_IS(TOKEN_EOS)) { ast->return_stmt.expr = TRY_EXPR_OR(parse_expr(context), poisoned_ast); } @@ -720,11 +730,11 @@ static inline Ast* parse_ct_for_stmt(Context *context) CONSUME_OR(TOKEN_LPAREN, poisoned_ast); if (context->next_tok.type == TOKEN_COMMA) { - ast->ct_for_stmt.index = context->tok; + ast->ct_for_stmt.index = context->tok.id; TRY_CONSUME_OR(TOKEN_CT_IDENT, "Expected a compile time index variable", poisoned_ast); advance_and_verify(context, TOKEN_COMMA); } - ast->ct_for_stmt.value = context->tok; + ast->ct_for_stmt.value = context->tok.id; TRY_CONSUME_OR(TOKEN_CT_IDENT, "Expected a compile time variable", poisoned_ast); TRY_CONSUME_OR(TOKEN_IN, "Expected 'in'.", poisoned_ast); ast->ct_for_stmt.expr = TRY_EXPR_OR(parse_expr(context), poisoned_ast); @@ -770,7 +780,7 @@ Ast *parse_stmt(Context *context) return parse_compound_stmt(context); case TOKEN_HALF: case TOKEN_QUAD: - SEMA_TOKEN_ERROR(context->next_tok, "Type is unsupported by platform."); + SEMA_TOKEN_ERROR(context->tok, "Type is unsupported by platform."); advance(context); return poisoned_ast; case TOKEN_VOID: @@ -982,7 +992,8 @@ Ast *parse_stmt(Context *context) advance(context); return AST_NEW_TOKEN(AST_NOP_STMT, context->tok); case TOKEN_EOF: - sema_error_at(context->tok.span.loc - 1, "Reached the end of the file when expecting a statement."); + // TODO + SEMA_TOKID_ERROR(context->tok.id, "Reached the end of the file when expecting a statement."); return poisoned_ast; } UNREACHABLE diff --git a/src/compiler/parser.c b/src/compiler/parser.c index 4655cdefc..9034381af 100644 --- a/src/compiler/parser.c +++ b/src/compiler/parser.c @@ -5,7 +5,6 @@ #include "compiler_internal.h" #include "parser_internal.h" -Token module = { .type = TOKEN_INVALID_TOKEN }; static Decl *parse_top_level(Context *context); @@ -22,6 +21,7 @@ static void context_store_lexer_state(Context *context) context->stored.lead_comment = context->lead_comment; context->stored.trailing_comment = context->trailing_comment; context->stored.next_lead_comment = context->next_lead_comment; + context->stored.lexer_index = context->lexer.lexer_index; } static void context_restore_lexer_state(Context *context) @@ -35,7 +35,7 @@ static void context_restore_lexer_state(Context *context) context->lead_comment = context->stored.lead_comment; context->next_lead_comment = context->stored.next_lead_comment; context->trailing_comment = context->stored.trailing_comment; - context->prev_tok_end = context->tok.span.end_loc; + context->lexer.lexer_index = context->stored.lexer_index; } #pragma mark --- Parser base methods @@ -50,12 +50,17 @@ inline void advance(Context *context) context->lead_comment = context->next_lead_comment; context->trailing_comment = NULL; context->next_lead_comment = NULL; - context->prev_tok_end = context->tok.span.end_loc; context->tok = context->next_tok; - while(1) { - context->next_tok = lexer_scan_token(&context->lexer); + if (context->tok.type == TOKEN_EOF) + { + context->next_tok = context->tok; + } + else + { + context->next_tok = lexer_advance(&context->lexer); + } if (context->next_tok.type == TOKEN_INVALID_TOKEN) continue; @@ -76,16 +81,15 @@ inline void advance(Context *context) // Handle doc comments if (context->next_tok.type == TOKEN_DOC_COMMENT) { - SourcePosition current_position = source_file_find_position_in_file(context->file, - context->tok.span.end_loc); - SourcePosition doc_position = source_file_find_position_in_file(context->file, context->next_tok.span.loc); + SourceLocation *curr = TOKKLOC(context->tok); + SourceLocation *next = TOKKLOC(context->next_tok); vec_add(context->comments, context->next_tok); - if (current_position.line == doc_position.line) + if (curr->line == next->line) { if (context->trailing_comment) { - sema_error_range(context->next_tok.span, "You have multiple trailing doc-style comments, should the second one go on the next line?"); + SEMA_TOKEN_ERROR(context->next_tok, "You have multiple trailing doc-style comments, should the second one go on the next line?"); } else { @@ -96,7 +100,7 @@ inline void advance(Context *context) { if (context->lead_comment) { - sema_error_range(context->next_tok.span, "You have multiple doc-style comments in a row, are all of them really meant to document the code that follows?"); + SEMA_TOKEN_ERROR(context->next_tok, "You have multiple doc-style comments in a row, are all of them really meant to document the code that follows?"); } else { @@ -129,7 +133,7 @@ bool consume(Context *context, TokenType type, const char *message, ...) va_list args; va_start(args, message); - sema_verror_range(context->tok.span, message, args); + sema_verror_range(TOKKLOC(context->tok), message, args); va_end(args); return false; } @@ -137,7 +141,7 @@ bool consume(Context *context, TokenType type, const char *message, ...) static inline bool consume_ident(Context *context, const char* name) { if (try_consume(context, TOKEN_IDENT)) return true; - if (context->tok.type == TOKEN_TYPE_IDENT || context->tok.type == TOKEN_CONST_IDENT) + if (TOKEN_IS(TOKEN_TYPE_IDENT) || TOKEN_IS(TOKEN_CONST_IDENT)) { SEMA_TOKEN_ERROR(context->tok, "A %s cannot start with a capital letter.", name); return false; @@ -148,12 +152,12 @@ static inline bool consume_ident(Context *context, const char* name) static bool consume_type_name(Context *context, const char* type) { - if (context->tok.type == TOKEN_IDENT) + if (TOKEN_IS(TOKEN_IDENT)) { SEMA_TOKEN_ERROR(context->tok, "Names of %ss must start with an upper case letter.", type); return false; } - if (context->tok.type == TOKEN_CONST_IDENT) + if (TOKEN_IS(TOKEN_CONST_IDENT)) { SEMA_TOKEN_ERROR(context->tok, "Names of %ss cannot be all upper case.", type); return false; @@ -164,7 +168,7 @@ static bool consume_type_name(Context *context, const char* type) bool consume_const_name(Context *context, const char* type) { - if (context->tok.type == TOKEN_IDENT || context->tok.type == TOKEN_TYPE_IDENT) + if (TOKEN_IS(TOKEN_IDENT) || TOKEN_IS(TOKEN_TYPE_IDENT)) { SEMA_TOKEN_ERROR(context->tok, "Names of %ss must be all upper case.", type); return false; @@ -179,7 +183,7 @@ bool consume_const_name(Context *context, const char* type) static void recover_top_level(Context *context) { advance(context); - while (context->tok.type != TOKEN_EOF) + while (!TOKEN_IS(TOKEN_EOF)) { switch (context->tok.type) { @@ -201,29 +205,21 @@ static void recover_top_level(Context *context) } -void error_at_current(Context *context, const char* message, ...) -{ - va_list args; - va_start(args, message); - sema_verror_range(context->next_tok.span, message, args); - va_end(args); -} - #pragma mark --- Parse paths static inline Path *parse_module_path(Context *context) { - assert(context->tok.type == TOKEN_IDENT); + assert(TOKEN_IS(TOKEN_IDENT)); char *scratch_ptr = context->path_scratch; size_t offset = 0; - SourceRange span = context->tok.span; - unsigned len = context->tok.span.end_loc - context->tok.span.loc; - memcpy(scratch_ptr, context->tok.start, len); + SourceSpan span = source_span_from_token_id(context->tok.id); + unsigned len = TOKLEN(context->tok); + memcpy(scratch_ptr, TOKSTR(context->tok), len); offset += len; - SourceRange last_range; + TokenId last_token; while (1) { - last_range = context->tok.span; + last_token = context->tok.id; if (!try_consume(context, TOKEN_IDENT)) { SEMA_TOKEN_ERROR(context->tok, "Each '::' must be followed by a regular lower case sub module name."); @@ -231,52 +227,52 @@ static inline Path *parse_module_path(Context *context) } if (!try_consume(context, TOKEN_SCOPE)) { - span = source_range_from_ranges(span, last_range); + span.end_loc = last_token; break; } scratch_ptr[offset++] = ':'; scratch_ptr[offset++] = ':'; - len = context->tok.span.end_loc - context->tok.span.loc; - memcpy(scratch_ptr + offset, context->tok.start, len); + len = TOKLEN(context->tok); + memcpy(scratch_ptr + offset, TOKSTR(context->tok), len); offset += len; } scratch_ptr[offset] = '\0'; - return path_create_from_string(scratch_ptr, offset, span); + return path_create_from_string(context, scratch_ptr, offset, span); } Path *parse_path_prefix(Context *context, bool *had_error) { *had_error = false; - if (context->tok.type != TOKEN_IDENT || context->next_tok.type != TOKEN_SCOPE) return NULL; + if (!TOKEN_IS(TOKEN_IDENT) || context->next_tok.type != TOKEN_SCOPE) return NULL; char *scratch_ptr = context->path_scratch; size_t offset = 0; Path *path = CALLOCS(Path); - path->span = context->tok.span; - unsigned len = context->tok.span.end_loc - context->tok.span.loc; - memcpy(scratch_ptr, context->tok.start, len); + path->span = source_span_from_token_id(context->tok.id); + unsigned len = TOKLEN(context->tok); + memcpy(scratch_ptr, TOKSTR(context->tok.id), len); offset += len; - SourceRange last_range = context->tok.span; + TokenId last_token = context->tok.id; advance(context); advance(context); - while (context->tok.type == TOKEN_IDENT && context->next_tok.type == TOKEN_SCOPE) + while (TOKEN_IS(TOKEN_IDENT) && context->next_tok.type == TOKEN_SCOPE) { - last_range = context->tok.span; + last_token = context->tok.id; scratch_ptr[offset++] = ':'; scratch_ptr[offset++] = ':'; - len = context->tok.span.end_loc - context->tok.span.loc; - memcpy(scratch_ptr + offset, context->tok.start, len); + len = TOKLEN(context->tok); + memcpy(scratch_ptr + offset, TOKSTR(context->tok.id), len); offset += len; advance(context); advance(context); } TokenType type = TOKEN_IDENT; - path->span = source_range_from_ranges(path->span, last_range); + path->span.end_loc = last_token; path->module = symtab_add(scratch_ptr, offset, fnv1a(scratch_ptr, offset), &type); if (type != TOKEN_IDENT) { - sema_error_range(path->span, "A module name was expected here."); + SEMA_ERROR(path, "A module name was expected here."); *had_error = true; return NULL; @@ -312,7 +308,7 @@ Path *parse_path_prefix(Context *context, bool *had_error) */ static inline TypeInfo *parse_base_type(Context *context) { - SourceRange range = context->tok.span; + SourceSpan range = source_span_from_token_id(context->tok.id); bool had_error; Path *path = parse_path_prefix(context, &had_error); if (had_error) return poisoned_type_info; @@ -320,7 +316,7 @@ static inline TypeInfo *parse_base_type(Context *context) { TypeInfo *type_info = type_info_new(TYPE_INFO_IDENTIFIER, range); type_info->unresolved.path = path; - type_info->unresolved.name_loc = context->tok; + type_info->unresolved.name_loc = context->tok.id; if (!consume_type_name(context, "types")) return poisoned_type_info; RANGE_EXTEND_PREV(type_info); return type_info; @@ -332,8 +328,8 @@ static inline TypeInfo *parse_base_type(Context *context) { case TOKEN_TYPE_IDENT: case TOKEN_CT_TYPE_IDENT: - type_info = type_info_new(TYPE_INFO_IDENTIFIER, context->tok.span); - type_info->unresolved.name_loc = context->tok; + type_info = type_info_new(TYPE_INFO_IDENTIFIER, source_span_from_token_id(context->tok.id)); + type_info->unresolved.name_loc = context->tok.id; break; case TOKEN_ERR: type_found = type_error; @@ -414,7 +410,7 @@ static inline TypeInfo *parse_base_type(Context *context) if (type_found) { assert(!type_info); - type_info = type_info_new(TYPE_INFO_IDENTIFIER, context->tok.span); + type_info = type_info_new(TYPE_INFO_IDENTIFIER, source_span_from_token_id(context->tok.id)); type_info->resolve_status = RESOLVE_DONE; type_info->type = type_found; } @@ -519,7 +515,7 @@ TypeInfo *parse_type(Context *context) */ Decl *parse_decl_after_type(Context *context, bool local, TypeInfo *type) { - if (context->tok.type == TOKEN_LPAREN) + if (TOKEN_IS(TOKEN_LPAREN)) { SEMA_TOKEN_ERROR(context->tok, "Expected '{'."); return poisoned_decl; @@ -527,13 +523,13 @@ Decl *parse_decl_after_type(Context *context, bool local, TypeInfo *type) EXPECT_IDENT_FOR_OR("variable_name", poisoned_decl); - Token name = context->tok; + TokenId name = context->tok.id; advance(context); Visibility visibility = local ? VISIBLE_LOCAL : VISIBLE_MODULE; Decl *decl = decl_new_var(name, type, VARDECL_LOCAL, visibility); - if (context->tok.type == TOKEN_EQ) + if (TOKEN_IS(TOKEN_EQ)) { if (!decl) { @@ -553,8 +549,8 @@ Decl *parse_decl_after_type(Context *context, bool local, TypeInfo *type) */ Decl *parse_decl(Context *context) { - bool local = context->tok.type == TOKEN_LOCAL; - bool constant = context->tok.type == TOKEN_CONST; + bool local = TOKEN_IS(TOKEN_LOCAL); + bool constant = TOKEN_IS(TOKEN_CONST); if (local || constant) advance(context); TypeInfo *type_info = parse_type(context); @@ -584,11 +580,11 @@ static inline Decl *parse_const_declaration(Context *context, Visibility visibil { advance_and_verify(context, TOKEN_CONST); - Decl *decl = decl_new_var(context->tok, NULL, VARDECL_CONST, visibility); + Decl *decl = DECL_NEW_VAR(NULL, VARDECL_CONST, visibility); // Parse the compile time constant. - if (context->tok.type == TOKEN_CT_IDENT) + if (TOKEN_IS(TOKEN_CT_IDENT)) { - if (!is_all_upper(context->tok.string)) + if (!is_all_upper(decl->name)) { SEMA_TOKEN_ERROR(context->tok, "Compile time constants must be all upper characters."); return poisoned_decl; @@ -600,8 +596,6 @@ static inline Decl *parse_const_declaration(Context *context, Visibility visibil { decl->var.type_info = TRY_TYPE_OR(parse_type(context), poisoned_decl); } - decl->name = context->tok.string; - decl->name_span = context->tok.span; if (!consume_const_name(context, "constant")) return poisoned_decl; } @@ -626,9 +620,9 @@ static inline Decl *parse_global_declaration(Context *context, Visibility visibi { TypeInfo *type = TRY_TYPE_OR(parse_type(context), poisoned_decl); - Decl *decl = decl_new_var(context->tok, type, VARDECL_GLOBAL, visibility); + Decl *decl = decl_new_var(context->tok.id, type, VARDECL_GLOBAL, visibility); - if (context->tok.type == TOKEN_FUNC) + if (TOKEN_IS(TOKEN_FUNC)) { SEMA_TOKEN_ERROR(context->tok, "'func' can't appear here, maybe you intended to put 'func' the type?"); advance(context); @@ -656,7 +650,7 @@ static inline Decl *parse_incremental_array(Context *context) return poisoned_decl; } CONSUME_OR(TOKEN_PLUS_ASSIGN, poisoned_decl); - Decl *decl = decl_new(DECL_ARRAY_VALUE, name, VISIBLE_LOCAL); + Decl *decl = decl_new(DECL_ARRAY_VALUE, name.id, VISIBLE_LOCAL); decl->incr_array_decl = TRY_EXPR_OR(parse_initializer(context), poisoned_decl); return decl; } @@ -740,8 +734,8 @@ bool parse_next_is_decl(Context *context) do { advance(context); advance(context); - } while (context->tok.type == TOKEN_IDENT && context->next_tok.type == TOKEN_SCOPE); - bool is_type = context->tok.type == TOKEN_TYPE_IDENT; + } while (TOKEN_IS(TOKEN_IDENT) && context->next_tok.type == TOKEN_SCOPE); + bool is_type = TOKEN_IS(TOKEN_TYPE_IDENT); context_restore_lexer_state(context); return is_type; default: @@ -791,8 +785,8 @@ bool parse_next_is_case_type(Context *context) do { advance(context); advance(context); - } while (context->tok.type == TOKEN_IDENT && context->next_tok.type == TOKEN_SCOPE); - bool is_type = context->tok.type == TOKEN_TYPE_IDENT; + } while (TOKEN_IS(TOKEN_IDENT) && context->next_tok.type == TOKEN_SCOPE); + bool is_type = TOKEN_IS(TOKEN_TYPE_IDENT); context_restore_lexer_state(context); return is_type; default: @@ -830,24 +824,24 @@ static inline bool parse_attributes(Context *context, Decl *parent_decl) Path *path = parse_path_prefix(context, &had_error); if (had_error) return false; - Attr *attr = malloc_arena(sizeof(Attr)); + Attr *attr = CALLOCS(Attr); - attr->name = context->tok; + attr->name = context->tok.id; attr->path = path; TRY_CONSUME_OR(TOKEN_IDENT, "Expected an attribute", false); - if (context->tok.type == TOKEN_LPAREN) + if (TOKEN_IS(TOKEN_LPAREN)) { attr->expr = TRY_EXPR_OR(parse_paren_expr(context), false); } - const char *name= attr->name.string; + const char *name = TOKSTR(attr->name); VECEACH(parent_decl->attributes, i) { Attr *other_attr = parent_decl->attributes[i]; - if (other_attr->name.string == name) + if (TOKSTR(other_attr->name) == name) { - SEMA_TOKEN_ERROR(attr->name, "Repeat of attribute '%s' here.", name); + SEMA_TOKID_ERROR(attr->name, "Repeat of attribute '%s' here.", name); return false; } } @@ -870,7 +864,7 @@ static inline bool parse_attributes(Context *context, Decl *parent_decl) static inline bool parse_param_decl(Context *context, Visibility parent_visibility, Decl*** parameters, bool type_only) { TypeInfo *type = TRY_TYPE_OR(parse_type(context), false); - Decl *param = decl_new_var(context->tok, type, VARDECL_PARAM, parent_visibility); + Decl *param = decl_new_var(context->tok.id, type, VARDECL_PARAM, parent_visibility); param->span = type->span; if (!try_consume(context, TOKEN_IDENT)) { @@ -881,14 +875,14 @@ static inline bool parse_param_decl(Context *context, Visibility parent_visibili if (!name && !type_only) { - if (context->tok.type != TOKEN_COMMA && context->tok.type != TOKEN_RPAREN) + if (!TOKEN_IS(TOKEN_COMMA) && !TOKEN_IS(TOKEN_RPAREN)) { - if (context->tok.type == TOKEN_CT_IDENT) + if (TOKEN_IS(TOKEN_CT_IDENT)) { SEMA_TOKEN_ERROR(context->tok, "Compile time identifiers are only allowed as macro parameters."); return false; } - sema_error_at(context->prev_tok_end, "Unexpected end of the parameter list, did you forget an ')'?"); + sema_error_at_prev_end(context->tok, "Unexpected end of the parameter list, did you forget an ')'?"); return false; } SEMA_ERROR(type, "The function parameter must be named."); @@ -991,30 +985,28 @@ bool parse_struct_body(Context *context, Decl *parent, Decl *parent_struct, Decl CONSUME_OR(TOKEN_LBRACE, false); assert(decl_is_struct_type(parent_struct)); - while (context->tok.type != TOKEN_RBRACE) + while (!TOKEN_IS(TOKEN_RBRACE)) { TokenType token_type = context->tok.type; if (token_type == TOKEN_STRUCT || token_type == TOKEN_UNION) { DeclKind decl_kind = decl_from_token(token_type); Decl *member; - Token name_replacement = context->tok; - name_replacement.string = "anon"; - Decl *strukt_type = decl_new_with_type(name_replacement, decl_kind, visible_parent->visibility); + const char *name = TOKSTR(context->tok); + Decl *strukt_type = decl_new_with_type(context->tok.id, decl_kind, visible_parent->visibility); if (context->next_tok.type != TOKEN_IDENT) { - member = decl_new(DECL_MEMBER, name_replacement, visible_parent->visibility); - member->member_decl.anonymous = true; + member = decl_new(DECL_MEMBER, NO_TOKEN_ID, visible_parent->visibility); advance(context); } else { advance(context); - member = decl_new(DECL_MEMBER, context->tok, visible_parent->visibility); - Decl *other = struct_find_name(visible_parent, context->tok.string); + member = decl_new(DECL_MEMBER, context->tok.id, visible_parent->visibility); + Decl *other = struct_find_name(visible_parent, TOKSTR(context->tok)); if (other) { - SEMA_TOKEN_ERROR(context->tok, "Duplicate member '%s' found.", context->tok.string); + SEMA_TOKEN_ERROR(context->tok, "Duplicate member '%s' found.", TOKSTR(context->tok.id)); SEMA_PREV(other, "Previous declaration with the same name was here."); decl_poison(visible_parent); decl_poison(other); @@ -1024,7 +1016,7 @@ bool parse_struct_body(Context *context, Decl *parent, Decl *parent_struct, Decl advance_and_verify(context, TOKEN_IDENT); } if (!parse_attributes(context, strukt_type)) return false; - if (!parse_struct_body(context, member, strukt_type, context->tok.type == TOKEN_IDENT ? strukt_type : visible_parent)) + if (!parse_struct_body(context, member, strukt_type, TOKEN_IS(TOKEN_IDENT) ? strukt_type : visible_parent)) { decl_poison(visible_parent); return false; @@ -1037,7 +1029,7 @@ bool parse_struct_body(Context *context, Decl *parent, Decl *parent_struct, Decl while (1) { EXPECT_OR(TOKEN_IDENT, false); - Decl *member = decl_new(DECL_MEMBER, context->tok, visible_parent->visibility); + Decl *member = decl_new(DECL_MEMBER, context->tok.id, visible_parent->visibility); Decl *other = struct_find_name(visible_parent, member->name); if (other) { @@ -1049,7 +1041,7 @@ bool parse_struct_body(Context *context, Decl *parent, Decl *parent_struct, Decl } add_struct_member(parent, parent_struct, member, type); advance(context); - if (context->tok.type != TOKEN_COMMA) break; + if (!TOKEN_IS(TOKEN_COMMA)) break; } CONSUME_OR(TOKEN_EOS, false); } @@ -1072,7 +1064,7 @@ static inline Decl *parse_struct_declaration(Context *context, Visibility visibi advance(context); const char* type_name = struct_union_name_from_token(type); - Token name = context->tok; + TokenId name = context->tok.id; if (!consume_type_name(context, type_name)) return poisoned_decl; Decl *decl = decl_new_with_type(name, decl_from_token(type), visibility); @@ -1086,7 +1078,7 @@ static inline Decl *parse_struct_declaration(Context *context, Visibility visibi { return poisoned_decl; } - DEBUG_LOG("Parsed %s %s completely.", type_name, name.string); + DEBUG_LOG("Parsed %s %s completely.", type_name, TOKSTR(name)); return decl; } @@ -1096,7 +1088,7 @@ static inline Decl *parse_struct_declaration(Context *context, Visibility visibi static inline Ast *parse_generics_statements(Context *context) { Ast *ast = AST_NEW_TOKEN(AST_COMPOUND_STMT, context->tok); - while (context->tok.type != TOKEN_RBRACE && context->tok.type != TOKEN_CASE && context->tok.type != TOKEN_DEFAULT) + while (!TOKEN_IS(TOKEN_RBRACE) && !TOKEN_IS(TOKEN_CASE) && !TOKEN_IS(TOKEN_DEFAULT)) { Ast *stmt = TRY_AST_OR(parse_stmt(context), poisoned_ast); ast->compound_stmt.stmts = VECADD(ast->compound_stmt.stmts, stmt); @@ -1123,27 +1115,27 @@ static inline Decl *parse_generics_declaration(Context *context, Visibility visi { advance_and_verify(context, TOKEN_GENERIC); TypeInfo *rtype = NULL; - if (context->tok.type != TOKEN_IDENT) + if (!TOKEN_IS(TOKEN_IDENT)) { rtype = TRY_TYPE_OR(parse_type(context), poisoned_decl); } bool had_error; Path *path = parse_path_prefix(context, &had_error); if (had_error) return poisoned_decl; - Decl *decl = decl_new(DECL_GENERIC, context->tok, visibility); + Decl *decl = decl_new(DECL_GENERIC, context->tok.id, visibility); decl->generic_decl.path = path; if (!consume_ident(context, "generic function name")) return poisoned_decl; decl->generic_decl.rtype = rtype; - Token *parameters = NULL; + TokenId *parameters = NULL; CONSUME_OR(TOKEN_LPAREN, poisoned_decl); while (!try_consume(context, TOKEN_RPAREN)) { - if (context->tok.type != TOKEN_IDENT) + if (!TOKEN_IS(TOKEN_IDENT)) { SEMA_TOKEN_ERROR(context->tok, "Expected an identifier."); return false; } - parameters = VECADD(parameters, context->tok); + parameters = VECADD(parameters, context->tok.id); advance(context); COMMA_RPAREN_OR(poisoned_decl); } @@ -1159,27 +1151,27 @@ static inline Decl *parse_define(Context *context, Visibility visibility) { advance_and_verify(context, TOKEN_DEFINE); TypeInfo *rtype = NULL; - if (context->tok.type != TOKEN_IDENT) + if (!TOKEN_IS(TOKEN_IDENT)) { rtype = TRY_TYPE_OR(parse_type(context), poisoned_decl); } bool had_error; Path *path = parse_path_prefix(context, &had_error); if (had_error) return poisoned_decl; - Decl *decl = decl_new(DECL_GENERIC, context->tok, visibility); + Decl *decl = decl_new(DECL_GENERIC, context->tok.id, visibility); decl->generic_decl.path = path; if (!consume_ident(context, "generic function name")) return poisoned_decl; decl->generic_decl.rtype = rtype; - Token *parameters = NULL; + TokenId *parameters = NULL; CONSUME_OR(TOKEN_LPAREN, poisoned_decl); while (!try_consume(context, TOKEN_RPAREN)) { - if (context->tok.type != TOKEN_IDENT) + if (!TOKEN_IS(TOKEN_IDENT)) { SEMA_TOKEN_ERROR(context->tok, "Expected an identifier."); return false; } - parameters = VECADD(parameters, context->tok); + parameters = VECADD(parameters, context->tok.id); advance(context); COMMA_RPAREN_OR(poisoned_decl); } @@ -1239,14 +1231,14 @@ static inline Decl *parse_attribute_declaration(Context *context, Visibility vis advance(context); if ((domains & last_domain) != 0) { - SEMA_TOKEN_ERROR(context->tok, "'%s' appeared more than once.", context->tok.string); + SEMA_TOKEN_ERROR(context->tok, "'%s' appeared more than once.", TOKSTR(context->tok.id)); continue; } domains |= last_domain; if (!try_consume(context, TOKEN_COMMA)) break; last_domain = TOKEN_TO_ATTR[context->tok.type]; } - Decl *decl = decl_new(DECL_ATTRIBUTE, context->tok, visibility); + Decl *decl = decl_new(DECL_ATTRIBUTE, context->tok.id, visibility); TRY_CONSUME_OR(TOKEN_IDENT, "Expected an attribute name.", poisoned_decl); if (last_domain == 0) { @@ -1288,8 +1280,8 @@ static inline bool parse_func_typedef(Context *context, Decl *decl, Visibility v static inline Decl *parse_typedef_declaration(Context *context, Visibility visibility) { advance_and_verify(context, TOKEN_TYPEDEF); - Decl *decl = decl_new_with_type(context->tok, DECL_TYPEDEF, visibility); - if (context->tok.type == TOKEN_FUNC) + Decl *decl = decl_new_with_type(context->tok.id, DECL_TYPEDEF, visibility); + if (TOKEN_IS(TOKEN_FUNC)) { if (!parse_func_typedef(context, decl, visibility)) return poisoned_decl; } @@ -1299,9 +1291,9 @@ static inline Decl *parse_typedef_declaration(Context *context, Visibility visib decl->typedef_decl.is_func = false; } CONSUME_OR(TOKEN_AS, poisoned_decl); - decl->name = context->tok.string; - decl->name_span = context->tok.span; - decl->type->name = context->tok.string; + decl->name = TOKSTR(context->tok); + decl->type->name = TOKSTR(context->tok); + decl->name_token = context->tok.id; if (!consume_type_name(context, "typedef")) return poisoned_decl; CONSUME_OR(TOKEN_EOS, poisoned_decl); return decl; @@ -1313,12 +1305,12 @@ static inline Decl *parse_macro_declaration(Context *context, Visibility visibil TypeInfo *rtype = NULL; bool failable = false; - if (context->tok.type != TOKEN_IDENT) + if (!TOKEN_IS(TOKEN_IDENT)) { rtype = TRY_TYPE_OR(parse_type(context), poisoned_decl); failable = try_consume(context, TOKEN_BANG); } - Decl *decl = decl_new(DECL_MACRO, context->tok, visibility); + Decl *decl = decl_new(DECL_MACRO, context->tok.id, visibility); decl->macro_decl.rtype = rtype; decl->macro_decl.failable = failable; TRY_CONSUME_OR(TOKEN_IDENT, "Expected a macro name here", poisoned_decl); @@ -1343,7 +1335,7 @@ static inline Decl *parse_macro_declaration(Context *context, Visibility visibil parm_type = TRY_TYPE_OR(parse_type(context), poisoned_decl); goto TEST_TYPE; } - Decl *param = decl_new_var(context->tok, parm_type, VARDECL_PARAM, visibility); + Decl *param = decl_new_var(context->tok.id, parm_type, VARDECL_PARAM, visibility); advance(context); params = VECADD(params, param); COMMA_RPAREN_OR(poisoned_decl); @@ -1364,7 +1356,7 @@ static inline Decl *parse_error_declaration(Context *context, Visibility visibil { advance_and_verify(context, TOKEN_ERR); - Decl *err_decl = decl_new_with_type(context->tok, DECL_ERR, visibility); + Decl *err_decl = decl_new_with_type(context->tok.id, DECL_ERR, visibility); if (!consume_type_name(context, "error type")) return poisoned_decl; @@ -1373,12 +1365,12 @@ static inline Decl *parse_error_declaration(Context *context, Visibility visibil while (!try_consume(context, TOKEN_RBRACE)) { TypeInfo *type = TRY_TYPE_OR(parse_type(context), poisoned_decl); - if (context->tok.type != TOKEN_IDENT) + if (!TOKEN_IS(TOKEN_IDENT)) { SEMA_TOKEN_ERROR(context->tok, "Expected an identifier here."); return poisoned_decl; } - Decl *member = decl_new(DECL_MEMBER, context->tok, visibility); + Decl *member = decl_new(DECL_MEMBER, context->tok.id, visibility); advance(context); add_struct_member(err_decl, err_decl, member, type); TRY_CONSUME_EOS_OR(poisoned_decl); @@ -1436,7 +1428,7 @@ static inline Decl *parse_enum_declaration(Context *context, Visibility visibili { advance_and_verify(context, TOKEN_ENUM); - Decl *decl = decl_new_with_type(context->tok, DECL_ENUM, visibility); + Decl *decl = DECL_NEW_WITH_TYPE(DECL_ENUM, visibility); if (!consume_type_name(context, "enum")) return poisoned_decl; @@ -1451,11 +1443,12 @@ static inline Decl *parse_enum_declaration(Context *context, Visibility visibili decl->enums.type_info = type ? type : type_info_new_base(type_int, decl->span); while (!try_consume(context, TOKEN_RBRACE)) { - Decl *enum_const = decl_new(DECL_ENUM_CONSTANT, context->tok, decl->visibility); + Decl *enum_const = DECL_NEW(DECL_ENUM_CONSTANT, decl->visibility); + const char *name = TOKSTR(context->tok); VECEACH(decl->enums.values, i) { Decl *other_constant = decl->enums.values[i]; - if (other_constant->name == context->tok.string) + if (other_constant->name == name) { SEMA_TOKEN_ERROR(context->tok, "This enum constant is declared twice."); SEMA_PREV(other_constant, "The previous declaration was here."); @@ -1519,21 +1512,21 @@ static inline Decl *parse_func_definition(Context *context, Visibility visibilit advance_and_verify(context, TOKEN_FUNC); TypeInfo *return_type = TRY_TYPE_OR(parse_type(context), poisoned_decl); - Decl *func = decl_new(DECL_FUNC, context->tok, visibility); + Decl *func = DECL_NEW(DECL_FUNC, visibility); func->func.function_signature.rtype = return_type; func->func.function_signature.failable = try_consume(context, TOKEN_BANG); - SourceRange start = context->tok.span; + SourceSpan start = source_span_from_token_id(context->tok.id); bool had_error; Path *path = parse_path_prefix(context, &had_error); if (had_error) return poisoned_decl; - if (path || context->tok.type == TOKEN_TYPE_IDENT) + if (path || TOKEN_IS(TOKEN_TYPE_IDENT)) { // Special case, actually an extension TRY_EXPECT_OR(TOKEN_TYPE_IDENT, "A type was expected after '::'.", poisoned_decl); // TODO span is incorrect TypeInfo *type = type_info_new(TYPE_INFO_IDENTIFIER, start); type->unresolved.path = path; - type->unresolved.name_loc = context->tok; + type->unresolved.name_loc = context->tok.id; func->func.type_parent = type; advance_and_verify(context, TOKEN_TYPE_IDENT); @@ -1541,8 +1534,8 @@ static inline Decl *parse_func_definition(Context *context, Visibility visibilit } EXPECT_IDENT_FOR_OR("function name", poisoned_decl); - func->name = context->tok.string; - func->name_span = context->tok.span; + func->name = TOKSTR(context->tok); + func->name_token = context->tok.id; advance_and_verify(context, TOKEN_IDENT); RANGE_EXTEND_PREV(func); if (!parse_opt_parameter_type_list(context, visibility, &(func->func.function_signature), is_interface)) return poisoned_decl; @@ -1550,11 +1543,11 @@ static inline Decl *parse_func_definition(Context *context, Visibility visibilit if (!parse_attributes(context, func)) return poisoned_decl; // TODO remove - is_interface = context->tok.type == TOKEN_EOS; + is_interface = TOKEN_IS(TOKEN_EOS); if (is_interface) { - if (context->tok.type == TOKEN_LBRACE) + if (TOKEN_IS(TOKEN_LBRACE)) { SEMA_TOKEN_ERROR(context->next_tok, "Functions bodies are not allowed in interface files."); return poisoned_decl; @@ -1577,7 +1570,7 @@ static inline Decl *parse_func_definition(Context *context, Visibility visibilit static inline bool parse_conditional_top_level(Context *context, Decl ***decls) { CONSUME_OR(TOKEN_LBRACE, false); - while (context->tok.type != TOKEN_RBRACE && context->tok.type != TOKEN_EOF) + while (!TOKEN_IS(TOKEN_RBRACE) && !TOKEN_IS(TOKEN_EOF)) { Decl *decl = parse_top_level(context); if (decl == NULL) continue; @@ -1596,26 +1589,26 @@ static inline bool parse_conditional_top_level(Context *context, Decl ***decls) static inline Decl *parse_ct_if_top_level(Context *context) { - Decl *ct = decl_new(DECL_CT_IF, context->tok, VISIBLE_LOCAL); + Decl *ct = DECL_NEW(DECL_CT_IF, VISIBLE_LOCAL); advance_and_verify(context, TOKEN_CT_IF); ct->ct_if_decl.expr = TRY_EXPR_OR(parse_paren_expr(context), poisoned_decl); if (!parse_conditional_top_level(context, &ct->ct_if_decl.then)) return poisoned_decl; CtIfDecl *ct_if_decl = &ct->ct_if_decl; - while (context->tok.type == TOKEN_CT_ELIF) + while (TOKEN_IS(TOKEN_CT_ELIF)) { advance_and_verify(context, TOKEN_CT_ELIF); - Decl *ct_elif = decl_new(DECL_CT_ELIF, context->tok, VISIBLE_LOCAL); + Decl *ct_elif = DECL_NEW(DECL_CT_ELIF, VISIBLE_LOCAL); ct_elif->ct_elif_decl.expr = TRY_EXPR_OR(parse_paren_expr(context), poisoned_decl); if (!parse_conditional_top_level(context, &ct_elif->ct_elif_decl.then)) return poisoned_decl; ct_if_decl->elif = ct_elif; ct_if_decl = &ct_elif->ct_elif_decl; } - if (context->tok.type == TOKEN_CT_ELSE) + if (TOKEN_IS(TOKEN_CT_ELSE)) { advance_and_verify(context, TOKEN_CT_ELSE); - Decl *ct_else = decl_new(DECL_CT_ELSE, context->tok, VISIBLE_LOCAL); + Decl *ct_else = DECL_NEW(DECL_CT_ELSE, VISIBLE_LOCAL); ct_if_decl->elif = ct_else; if (!parse_conditional_top_level(context, &ct_else->ct_else_decl)) return poisoned_decl; } @@ -1628,13 +1621,13 @@ static inline bool check_no_visibility_before(Context *context, Visibility visib switch (visibility) { case VISIBLE_PUBLIC: - SEMA_TOKEN_ERROR(context->tok, "Unexpected 'public' before '%.*s'.", source_range_len(context->tok.span), context->tok.start); + SEMA_TOKEN_ERROR(context->tok, "Unexpected 'public' before '%.*s'.", TOKLEN(context->tok.id), TOKSTR(context->tok.id)); return false; case VISIBLE_LOCAL: - SEMA_TOKEN_ERROR(context->tok, "Unexpected 'local' before '%.*s'.", source_range_len(context->tok.span), context->tok.start); + SEMA_TOKEN_ERROR(context->tok, "Unexpected 'local' before '%.*s'.", TOKLEN(context->tok.id), TOKSTR(context->tok.id)); return false; case VISIBLE_EXTERN: - SEMA_TOKEN_ERROR(context->tok, "Unexpected 'extern' before '%.*s'.", source_range_len(context->tok.span), context->tok.start); + SEMA_TOKEN_ERROR(context->tok, "Unexpected 'extern' before '%.*s'.", TOKLEN(context->tok.id), TOKSTR(context->tok.id)); return false; default: return true; @@ -1714,7 +1707,8 @@ static inline Decl *parse_top_level(Context *context) return parse_incremental_array(context); case TOKEN_EOF: assert(visibility != VISIBLE_MODULE); - sema_error_at(context->tok.span.loc - 1, "Expected a top level declaration'."); + TODO + //sema_error_at(context->token->span.loc - 1, "Expected a top level declaration'."); return poisoned_decl; default: // We could have included all fundamental types above, but do it here instead. @@ -1722,7 +1716,7 @@ static inline Decl *parse_top_level(Context *context) { return parse_global_declaration(context, visibility); } - error_at_current(context, "Unexpected token found"); + SEMA_TOKEN_ERROR(context->tok, "Unexpected symbol found"); return poisoned_decl; } } @@ -1742,7 +1736,7 @@ static inline Decl *parse_top_level(Context *context) * | module_params ',' module_param * ; */ -static inline bool parse_optional_module_params(Context *context, Token **tokens) +static inline bool parse_optional_module_params(Context *context, TokenId **tokens) { *tokens = NULL; @@ -1761,10 +1755,10 @@ static inline bool parse_optional_module_params(Context *context, Token **tokens switch (context->tok.type) { case TOKEN_IDENT: - sema_error_range(context->next_tok.span, "The module parameter must be a $ or #-prefixed name, did you forgot the '$'?"); + SEMA_TOKEN_ERROR(context->tok, "The module parameter must be a $ or #-prefixed name, did you forgot the '$'?"); return false; case TOKEN_COMMA: - sema_error_range(context->next_tok.span, "Unexpected ','"); + SEMA_TOKEN_ERROR(context->tok, "Unexpected ','"); return false; case TOKEN_CT_IDENT: case TOKEN_TYPE_IDENT: @@ -1773,7 +1767,7 @@ static inline bool parse_optional_module_params(Context *context, Token **tokens SEMA_TOKEN_ERROR(context->tok, "Only generic parameters are allowed here as parameters to the module."); return false; } - *tokens = VECADD(*tokens, context->next_tok); + *tokens = VECADD(*tokens, context->tok.id); advance(context); if (!try_consume(context, TOKEN_COMMA)) { @@ -1812,7 +1806,7 @@ static inline void parse_module(Context *context) } // Is this a generic module? - Token *generic_parameters = NULL; + TokenId *generic_parameters = NULL; if (!parse_optional_module_params(context, &generic_parameters)) { context_set_module(context, path, generic_parameters); @@ -1851,7 +1845,7 @@ static inline bool parse_import_selective(Context *context, Path *path) // Alias? if (!try_consume(context, TOKEN_AS)) { - return context_add_import(context, path, symbol, EMPTY_TOKEN); + return context_add_import(context, path, symbol, NO_TOKEN); } if (context->tok.type != symbol.type) { @@ -1888,14 +1882,14 @@ static inline bool parse_import(Context *context) { advance_and_verify(context, TOKEN_IMPORT); - if (context->tok.type != TOKEN_IDENT) + if (!TOKEN_IS(TOKEN_IDENT)) { SEMA_TOKEN_ERROR(context->tok, "Import statement should be followed by the name of the module to import."); return false; } Path *path = parse_module_path(context); - if (context->tok.type == TOKEN_COLON) + if (TOKEN_IS(TOKEN_COLON)) { while (1) { @@ -1905,7 +1899,7 @@ static inline bool parse_import(Context *context) } else { - context_add_import(context, path, EMPTY_TOKEN, EMPTY_TOKEN); + context_add_import(context, path, NO_TOKEN, NO_TOKEN); } TRY_CONSUME_EOS_OR(false); return true; @@ -1921,7 +1915,7 @@ static inline bool parse_import(Context *context) static inline void parse_imports(Context *context) { - while (context->tok.type == TOKEN_IMPORT) + while (TOKEN_IS(TOKEN_IMPORT)) { if (!parse_import(context)) recover_top_level(context); } @@ -1937,7 +1931,7 @@ static inline void parse_current(Context *context) advance(context); advance(context); parse_module(context); parse_imports(context); - while (context->tok.type != TOKEN_EOF) + while (!TOKEN_IS(TOKEN_EOF)) { Decl *decl = parse_top_level(context); if (decl_ok(decl)) diff --git a/src/compiler/parser_internal.h b/src/compiler/parser_internal.h index 454915580..fefcc56f4 100644 --- a/src/compiler/parser_internal.h +++ b/src/compiler/parser_internal.h @@ -4,16 +4,16 @@ // Use of this source code is governed by a LGPLv3.0 // a copy of which can be found in the LICENSE file. +#define TOKEN_IS(_type) (context->tok.type == _type) #define EXPECT_IDENT_FOR_OR(_name, _res) do { if (!expect_ident(context, _name)) return _res; } while(0) #define EXPECT_OR(_tok, _res) do { if (!expect(context, _tok)) return _res; } while(0) #define CONSUME_OR(_tok, _res) do { if (!expect(context, _tok)) return _res; advance(context); } while(0) #define TRY_EXPECT_OR(_tok, _message, _type) do { if (context->tok.type != _tok) { SEMA_TOKEN_ERROR(context->tok, _message); return _type; } } while(0) #define TRY_CONSUME_OR(_tok, _message, _type) do { if (!consume(context, _tok, _message)) return _type; } while(0) #define TRY_CONSUME(_tok, _message) TRY_CONSUME_OR(_tok, _message, poisoned_ast) -#define TRY_CONSUME_EOS_OR(_res) do { if (context->tok.type != TOKEN_EOS) { sema_error_at(context->prev_tok_end, "Expected ';'"); return _res; } advance(context); } while(0) +#define TRY_CONSUME_EOS_OR(_res) do { if (!TOKEN_IS(TOKEN_EOS)) { sema_error_at_prev_end(context->tok, "Expected ';'"); return _res; } advance(context); } while(0) #define TRY_CONSUME_EOS() TRY_CONSUME_EOS_OR(poisoned_ast) #define RETURN_AFTER_EOS(_ast) extend_ast_with_prev_token(context, ast); TRY_CONSUME_EOS_OR(poisoned_ast); return _ast -#define TRY_CONSUME_LBRACE() TRY_CONSUME(TOKEN_LBRACE, "Expected '{'") #define TRY_AST_OR(_ast_stmt, _res) ({ Ast* _ast = (_ast_stmt); if (!ast_ok(_ast)) return _res; _ast; }) #define TRY_AST(_ast_stmt) TRY_AST_OR(_ast_stmt, poisoned_ast) @@ -25,7 +25,7 @@ #define COMMA_RPAREN_OR(_res) \ -do { if (!try_consume(context, TOKEN_COMMA) && context->tok.type != TOKEN_RPAREN) { \ +do { if (!try_consume(context, TOKEN_COMMA) && !TOKEN_IS(TOKEN_RPAREN)) { \ SEMA_TOKEN_ERROR(context->tok, "Expected ',' or ')'"); return _res; } } while(0) @@ -54,7 +54,7 @@ Expr *parse_type_compound_literal_expr_after_type(Context *context, TypeInfo *ty Expr *parse_type_access_expr_after_type(Context *context, TypeInfo *type_info); bool parse_next_is_decl(Context *context); bool parse_next_is_case_type(Context *context); -void error_at_current(Context *context, const char* message, ...); + bool try_consume(Context *context, TokenType type); bool consume(Context *context, TokenType type, const char *message, ...); bool consume_const_name(Context *context, const char* type); diff --git a/src/compiler/sema_casts.c b/src/compiler/sema_casts.c index 2f20e4253..80a611e60 100644 --- a/src/compiler/sema_casts.c +++ b/src/compiler/sema_casts.c @@ -5,7 +5,7 @@ #include "compiler_internal.h" #include "bigint.h" -#define EXIT_T_MISMATCH() return sema_type_mismatch(left, canonical, cast_type) +#define EXIT_T_MISMATCH() return sema_type_mismatch(context, left, canonical, cast_type) #define IS_EXPLICT() #define RETURN_NON_CONST_CAST(kind) do { if (left->expr_kind != EXPR_CONST) { insert_cast(left, kind, canonical); return true; } } while (0) #define REQUIRE_EXPLICIT_CAST(_cast_type)\ @@ -26,7 +26,7 @@ static inline void insert_cast(Expr *expr, CastKind kind, Type *canonical) expr->type = canonical; } -static bool sema_type_mismatch(Expr *expr, Type *type, CastType cast_type) +static bool sema_type_mismatch(Context *context, Expr *expr, Type *type, CastType cast_type) { const char *action = ""; switch (cast_type) @@ -67,12 +67,12 @@ static bool sema_type_mismatch(Expr *expr, Type *type, CastType cast_type) } -bool erro(Expr* left, Type *from, Type *canonical, Type *type, CastType cast_type) +bool erro(Context *context, Expr* left, Type *from, Type *canonical, Type *type, CastType cast_type) { EXIT_T_MISMATCH(); } -bool ptxi(Expr *left, Type *canonical, Type *type, CastType cast_type) +bool ptxi(Context *context, Expr *left, Type *canonical, Type *type, CastType cast_type) { REQUIRE_EXPLICIT_CAST(cast_type); @@ -85,7 +85,7 @@ bool ptxi(Expr *left, Type *canonical, Type *type, CastType cast_type) } -bool ptbo(Expr *left, Type *canonical, Type *type, CastType cast_type) +bool ptbo(Context *context, Expr *left, Type *canonical, Type *type, CastType cast_type) { RETURN_NON_CONST_CAST(CAST_PTRBOOL); @@ -109,42 +109,42 @@ static inline bool may_implicitly_cast_ptr_to_ptr(Type *current_type, Type *targ } -bool stst(Expr* left, Type *from_canonical, Type *canonical, Type *type, CastType cast_type) +bool stst(Context *context, Expr* left, Type *from_canonical, Type *canonical, Type *type, CastType cast_type) { TODO } -bool unst(Expr* left, Type *from_canonical, Type *canonical, Type *type, CastType cast_type) +bool unst(Context *context, Expr* left, Type *from_canonical, Type *canonical, Type *type, CastType cast_type) { TODO } -bool stun(Expr* left, Type *from_canonical, Type *canonical, Type *type, CastType cast_type) +bool stun(Context *context, Expr* left, Type *from_canonical, Type *canonical, Type *type, CastType cast_type) { TODO } -bool unun(Expr* left, Type *from_canonical, Type *canonical, Type *type, CastType cast_type) +bool unun(Context *context, Expr* left, Type *from_canonical, Type *canonical, Type *type, CastType cast_type) { TODO } -bool arpt(Expr* left, Type *from_canonical, Type *canonical, Type *type, CastType cast_type) +bool arpt(Context *context, Expr* left, Type *from_canonical, Type *canonical, Type *type, CastType cast_type) { TODO } -bool arsa(Expr* left, Type *from_canonical, Type *canonical, Type *type, CastType cast_type) +bool arsa(Context *context, Expr* left, Type *from_canonical, Type *canonical, Type *type, CastType cast_type) { TODO } -bool ptpt(Expr* left, Type *from_canonical, Type *canonical, Type *type, CastType cast_type) +bool ptpt(Context *context, Expr* left, Type *from_canonical, Type *canonical, Type *type, CastType cast_type) { if (cast_type != CAST_TYPE_EXPLICIT && !may_implicitly_cast_ptr_to_ptr(from_canonical, canonical)) { if (cast_type == CAST_TYPE_OPTIONAL_IMPLICIT) return true; - return sema_type_mismatch(left, type, cast_type); + return sema_type_mismatch(context, left, type, cast_type); } RETURN_NON_CONST_CAST(CAST_PTRPTR); assert(left->const_expr.kind == TYPE_POINTER); @@ -152,7 +152,7 @@ bool ptpt(Expr* left, Type *from_canonical, Type *canonical, Type *type, CastTyp return true; } -bool strpt(Expr* left, Type *from_canonical, Type *canonical, Type *type, CastType cast_type) +bool strpt(Context *context, Expr* left, Type *from_canonical, Type *canonical, Type *type, CastType cast_type) { // TODO @@ -160,17 +160,17 @@ bool strpt(Expr* left, Type *from_canonical, Type *canonical, Type *type, CastTy return true; } -bool stpt(Expr* left, Type *from, Type *canonical, Type *type, CastType cast_type) +bool stpt(Context *context, Expr* left, Type *from, Type *canonical, Type *type, CastType cast_type) { if (canonical->pointer != type_char && canonical->pointer != type_byte) { - return sema_type_mismatch(left, type, cast_type); + return sema_type_mismatch(context, left, type, cast_type); } left->type = canonical; return true; } -void const_int_to_fp_cast(Expr *left, Type *canonical, Type *type) +void const_int_to_fp_cast(Context *context, Expr *left, Type *canonical, Type *type) { long double f = bigint_as_float(&left->const_expr.i); switch (canonical->type_kind) @@ -193,7 +193,7 @@ void const_int_to_fp_cast(Expr *left, Type *canonical, Type *type) * Bool into a signed or unsigned int. Explicit conversions only. * @return true unless this is not an explicit conversion. */ -bool boxi(Expr *left, Type *canonical, Type *type, CastType cast_type) +bool boxi(Context *context, Expr *left, Type *canonical, Type *type, CastType cast_type) { if (cast_type == CAST_TYPE_OPTIONAL_IMPLICIT) return true; if (cast_type != CAST_TYPE_EXPLICIT) EXIT_T_MISMATCH(); @@ -208,7 +208,7 @@ bool boxi(Expr *left, Type *canonical, Type *type, CastType cast_type) * Bool into a float. Explicit conversions only. * @return true unless this is not an explicit conversion. */ -bool bofp(Expr *left, Type *canonical, Type *type, CastType cast_type) +bool bofp(Context *context, Expr *left, Type *canonical, Type *type, CastType cast_type) { // if (cast_type >= CAST_TYPE_IMPLICIT_ASSIGN) EXIT_T_MISMATCH(); RETURN_NON_CONST_CAST(CAST_BOOLFP); @@ -223,7 +223,7 @@ bool bofp(Expr *left, Type *canonical, Type *type, CastType cast_type) * Convert from any into to bool. * @return true for any implicit conversion except assign and assign add. */ -bool xibo(Expr *left, Type *canonical, Type *type, CastType cast_type) +bool xibo(Context *context, Expr *left, Type *canonical, Type *type, CastType cast_type) { if (cast_type == CAST_TYPE_OPTIONAL_IMPLICIT) return true; // if (cast_type >= CAST_TYPE_IMPLICIT_ASSIGN) EXIT_T_MISMATCH(); @@ -238,7 +238,7 @@ bool xibo(Expr *left, Type *canonical, Type *type, CastType cast_type) * Convert from any float to bool * @return true for any implicit conversion except assign and assign add */ -bool fpbo(Expr *left, Type *canonical, Type *type, CastType cast_type) +bool fpbo(Context *context, Expr *left, Type *canonical, Type *type, CastType cast_type) { // if (cast_type >= CAST_TYPE_IMPLICIT_ASSIGN) EXIT_T_MISMATCH(); RETURN_NON_CONST_CAST(CAST_FPBOOL); @@ -253,7 +253,7 @@ bool fpbo(Expr *left, Type *canonical, Type *type, CastType cast_type) * Convert from any fp to fp * @return true for all except implicit assign (but allowing assign add) */ -bool fpfp(Expr* left, Type *from, Type *canonical, Type *type, CastType cast_type) +bool fpfp(Context *context, Expr* left, Type *from, Type *canonical, Type *type, CastType cast_type) { bool is_narrowing = from->builtin.bytesize < canonical->builtin.bytesize && from->type_kind != TYPE_FXX; @@ -270,7 +270,7 @@ bool fpfp(Expr* left, Type *from, Type *canonical, Type *type, CastType cast_typ * Convert from any floating point to int * @return true only on explicit conversions. */ -bool fpxi(Expr *left, Type *canonical, Type *type, CastType cast_type) +bool fpxi(Context *context, Expr *left, Type *canonical, Type *type, CastType cast_type) { REQUIRE_EXPLICIT_CAST(cast_type); @@ -299,7 +299,7 @@ bool fpxi(Expr *left, Type *canonical, Type *type, CastType cast_type) * Convert from compile time int to any signed or unsigned int * @return true unless the conversion was lossy. */ -bool ixxxi(Expr *left, Type *canonical, Type *type, CastType cast_type) +bool ixxxi(Context *context, Expr *left, Type *canonical, Type *type, CastType cast_type) { bool is_signed = canonical->type_kind < TYPE_U8; int bitsize = canonical->builtin.bitsize; @@ -321,17 +321,17 @@ bool ixxxi(Expr *left, Type *canonical, Type *type, CastType cast_type) * Convert from compile time int to any signed or unsigned int * @return true unless the conversion was lossy. */ -bool ixxen(Expr *left, Type *canonical, Type *type, CastType cast_type) +bool ixxen(Context *context, Expr *left, Type *canonical, Type *type, CastType cast_type) { assert(canonical->type_kind == TYPE_ENUM); canonical = canonical->decl->enums.type_info->type->canonical; - return ixxxi(left, canonical, type, cast_type); + return ixxxi(context, left, canonical, type, cast_type); } /** * Convert from compile time int to error union */ -bool ixxeu(Expr *left, Type *type) +bool ixxeu(Context *context, Expr *left, Type *type) { UNREACHABLE } @@ -340,7 +340,7 @@ bool ixxeu(Expr *left, Type *type) * Cast signed int -> signed int * @return true if this is a widening, an explicit cast or if it is an implicit assign add */ -bool sisi(Expr* left, Type *from_canonical, Type *canonical, Type *type, CastType cast_type) +bool sisi(Context *context, Expr* left, Type *from_canonical, Type *canonical, Type *type, CastType cast_type) { bool is_narrowing = from_canonical->builtin.bytesize > canonical->builtin.bytesize; @@ -364,7 +364,7 @@ bool sisi(Expr* left, Type *from_canonical, Type *canonical, Type *type, CastTyp * Cast unsigned int -> unsigned int * @return true if this was not a narrowing implicit assign or narrowing implicit assign add */ -bool uiui(Expr* left, Type *from_canonical, Type *canonical, Type *type, CastType cast_type) +bool uiui(Context *context, Expr* left, Type *from_canonical, Type *canonical, Type *type, CastType cast_type) { bool is_narrowing = from_canonical->builtin.bytesize > canonical->builtin.bytesize; @@ -389,7 +389,7 @@ bool uiui(Expr* left, Type *from_canonical, Type *canonical, Type *type, CastTyp * Cast unsigned int -> signed int * @return true if this is an explicit cast or if it is an implicit assign add or if it is a widening cast. */ -bool uisi(Expr* left, Type *from_canonical, Type *canonical, Type *type, CastType cast_type) +bool uisi(Context *context, Expr* left, Type *from_canonical, Type *canonical, Type *type, CastType cast_type) { bool is_widening = from_canonical->builtin.bytesize < canonical->builtin.bytesize; @@ -413,7 +413,7 @@ bool uisi(Expr* left, Type *from_canonical, Type *canonical, Type *type, CastTyp * Cast signed int -> unsigned int * @return true if this was an implicit add or or explicit cast. */ -bool siui(Expr *left, Type *canonical, Type *type, CastType cast_type) +bool siui(Context *context, Expr *left, Type *canonical, Type *type, CastType cast_type) { REQUIRE_EXPLICIT_CAST(cast_type); @@ -432,10 +432,10 @@ bool siui(Expr *left, Type *canonical, Type *type, CastType cast_type) * Cast a signed or unsigned integer -> floating point * @return true always */ -bool sifp(Expr *left, Type *canonical, Type *type) +bool sifp(Context *context, Expr *left, Type *canonical, Type *type) { RETURN_NON_CONST_CAST(CAST_SIFP); - const_int_to_fp_cast(left, canonical, type); + const_int_to_fp_cast(context, left, canonical, type); return true; } @@ -443,18 +443,18 @@ bool sifp(Expr *left, Type *canonical, Type *type) * Cast a signed or unsigned integer -> floating point * @return true always */ -bool uifp(Expr *left, Type *canonical, Type *type) +bool uifp(Context *context, Expr *left, Type *canonical, Type *type) { RETURN_NON_CONST_CAST(CAST_UIFP); - const_int_to_fp_cast(left, canonical, type); + const_int_to_fp_cast(context, left, canonical, type); return true; } -bool ixxfp(Expr *left, Type *canonical, Type *type, CastType cast_type) +bool ixxfp(Context *context, Expr *left, Type *canonical, Type *type, CastType cast_type) { assert(type_is_float(canonical)); assert(left->expr_kind == EXPR_CONST); - const_int_to_fp_cast(left, canonical, type); + const_int_to_fp_cast(context, left, canonical, type); return true; } @@ -462,7 +462,7 @@ bool ixxfp(Expr *left, Type *canonical, Type *type, CastType cast_type) * Convert a compile time into to a boolean. * @return true always */ -bool ixxbo(Expr *left, Type *type) +bool ixxbo(Context *context, Expr *left, Type *type) { assert(left->expr_kind == EXPR_CONST); expr_const_set_bool(&left->const_expr, bigint_cmp_zero(&left->const_expr.i) != CMP_EQ); @@ -471,9 +471,9 @@ bool ixxbo(Expr *left, Type *type) } -bool ussi(Expr* left, Type *from, Type *canonical, Type *type, CastType cast_type) +bool ussi(Context *context, Expr* left, Type *from, Type *canonical, Type *type, CastType cast_type) { - if (type->type_kind != TYPE_ENUM) return sema_type_mismatch(left, type, CAST_TYPE_EXPLICIT); + if (type->type_kind != TYPE_ENUM) return sema_type_mismatch(context, left, type, CAST_TYPE_EXPLICIT); if (cast_type != CAST_TYPE_EXPLICIT) EXIT_T_MISMATCH(); if (left->expr_kind == EXPR_IDENTIFIER && left->identifier_expr.decl->decl_kind == DECL_ENUM_CONSTANT) @@ -489,12 +489,12 @@ bool ussi(Expr* left, Type *from, Type *canonical, Type *type, CastType cast_typ return true; } -bool sius(Expr* left, Type *from, Type *canonical, Type *type, CastType cast_type) +bool sius(Context *context, Expr* left, Type *from, Type *canonical, Type *type, CastType cast_type) { TODO } -bool uius(Expr* left, Type *from, Type *canonical, Type *type, CastType cast_type) +bool uius(Context *context, Expr* left, Type *from, Type *canonical, Type *type, CastType cast_type) { TODO } @@ -503,7 +503,7 @@ bool uius(Expr* left, Type *from, Type *canonical, Type *type, CastType cast_typ * Cast comptime, signed or unsigned -> pointer. * @return true unless the constant value evaluates to zero. */ -bool xipt(Expr *left, Type *from, Type *canonical, Type *type, CastType cast_type) +bool xipt(Context *context, Expr *left, Type *from, Type *canonical, Type *type, CastType cast_type) { if (cast_type == CAST_TYPE_EXPLICIT && left->expr_kind == EXPR_CONST) { @@ -516,10 +516,10 @@ bool xipt(Expr *left, Type *from, Type *canonical, Type *type, CastType cast_typ expr_const_set_nil(&left->const_expr); left->type = type; } - return cast(left, type_is_unsigned(from) ? type_usize : type_isize, cast_type); + return cast(context, left, type_is_unsigned(from) ? type_usize : type_isize, cast_type); } -bool usus(Expr* left, Type *from, Type *canonical, Type *type, CastType cast_type) +bool usus(Context *context, Expr* left, Type *from, Type *canonical, Type *type, CastType cast_type) { assert(canonical->canonical == canonical); assert(canonical->type_kind == TYPE_POINTER); @@ -532,32 +532,32 @@ bool usus(Expr* left, Type *from, Type *canonical, Type *type, CastType cast_typ insert_cast(left, CAST_PTRPTR, canonical); return true; } - sema_type_mismatch(left, type, cast_type); + sema_type_mismatch(context, left, type, cast_type); return false; } insert_cast(left, CAST_PTRPTR, canonical); return true; } -bool xixi(Expr *left, Type *from_canonical, Type *canonical, Type *type, CastType cast_type) +bool xixi(Context *context, Expr *left, Type *from_canonical, Type *canonical, Type *type, CastType cast_type) { assert(from_canonical->canonical == from_canonical); switch (from_canonical->type_kind) { case TYPE_IXX: - return ixxxi(left, canonical, type, cast_type); + return ixxxi(context, left, canonical, type, cast_type); case ALL_SIGNED_INTS: - if (type_is_unsigned(canonical)) return siui(left, canonical, type, cast_type); - return sisi(left, from_canonical, canonical, type, cast_type); + if (type_is_unsigned(canonical)) return siui(context, left, canonical, type, cast_type); + return sisi(context, left, from_canonical, canonical, type, cast_type); case ALL_UNSIGNED_INTS: - if (type_is_unsigned(canonical)) return uiui(left, from_canonical, canonical, type, cast_type); - return uisi(left, from_canonical, canonical, type, cast_type); + if (type_is_unsigned(canonical)) return uiui(context, left, from_canonical, canonical, type, cast_type); + return uisi(context, left, from_canonical, canonical, type, cast_type); default: UNREACHABLE } } -bool enxi(Expr* left, Type *from, Type *canonical, Type *type, CastType cast_type) +bool enxi(Context *context, Expr* left, Type *from, Type *canonical, Type *type, CastType cast_type) { Type *enum_type = from->decl->enums.type_info->type; Type *enum_type_canonical = enum_type->canonical; @@ -573,31 +573,31 @@ bool enxi(Expr* left, Type *from, Type *canonical, Type *type, CastType cast_typ if (cast_type == CAST_TYPE_OPTIONAL_IMPLICIT) return true; SEMA_ERROR(left, "Cannot implictly convert '%s' with underlying type of '%s' to '%s'," " use an explicit cast if this is what you want.", type_to_error_string(from), - type_to_error_string(enum_type_canonical), type_to_error_string(canonical)); + type_to_error_string(enum_type_canonical), type_to_error_string(canonical)); return false; } // 3. Dispatch to the right cast: - return xixi(left, enum_type_canonical, canonical, type, cast_type); + return xixi(context, left, enum_type_canonical, canonical, type, cast_type); } -bool vava(Expr* left, Type *from, Type *canonical, Type *type, CastType cast_type) +bool vava(Context *context, Expr* left, Type *from, Type *canonical, Type *type, CastType cast_type) { TODO } -bool sapt(Expr* left, Type *from, Type *canonical, Type *type, CastType cast_type) +bool sapt(Context *context, Expr* left, Type *from, Type *canonical, Type *type, CastType cast_type) { bool is_subtype = type_is_subtype(canonical->pointer, from->array.base); if (!is_subtype) { if (cast_type == CAST_TYPE_OPTIONAL_IMPLICIT) return true; - return sema_type_mismatch(left, type, cast_type); + return sema_type_mismatch(context, left, type, cast_type); } insert_cast(left, CAST_SAPTR, canonical); return true; } -bool vasa(Expr* left, Type *from, Type *canonical, Type *type, CastType cast_type) +bool vasa(Context *context, Expr* left, Type *from, Type *canonical, Type *type, CastType cast_type) { TODO } @@ -605,12 +605,12 @@ bool vasa(Expr* left, Type *from, Type *canonical, Type *type, CastType cast_typ -bool xieu(Expr *left, Type *canonical, Type *type, CastType cast_type) +bool xieu(Context *context, Expr *left, Type *canonical, Type *type, CastType cast_type) { TODO } -bool xierr(Expr *left, Type *canonical, Type *type, CastType cast_type) +bool xierr(Context *context, Expr *left, Type *canonical, Type *type, CastType cast_type) { TODO } @@ -620,14 +620,14 @@ bool xierr(Expr *left, Type *canonical, Type *type, CastType cast_type) * Convert error union to error. This is always a required cast. * @return false if an error was reported. */ -bool eubool(Expr *left, Type *canonical, Type *type, CastType cast_type) +bool eubool(Context *context, Expr *left, Type *canonical, Type *type, CastType cast_type) { insert_cast(left, CAST_EUBOOL, canonical); return true; } -bool euer(Expr *left, Type *canonical, Type *type, CastType cast_type) +bool euer(Context *context, Expr *left, Type *canonical, Type *type, CastType cast_type) { REQUIRE_EXPLICIT_CAST(cast_type); insert_cast(left, CAST_EUER, canonical); @@ -635,65 +635,65 @@ bool euer(Expr *left, Type *canonical, Type *type, CastType cast_type) } -bool ereu(Expr *left, Type *canonical, Type *type, CastType cast_type) +bool ereu(Context *context, Expr *left, Type *canonical, Type *type, CastType cast_type) { insert_cast(left, CAST_EREU, canonical); return true; } -bool ptva(Expr* left, Type *from, Type *canonical, Type *type, CastType cast_type) +bool ptva(Context *context, Expr* left, Type *from, Type *canonical, Type *type, CastType cast_type) { TODO } -bool ptsa(Expr* left, Type *from, Type *canonical, Type *type, CastType cast_type) +bool ptsa(Context *context, Expr* left, Type *from, Type *canonical, Type *type, CastType cast_type) { if (from->pointer->type_kind != TYPE_ARRAY) { if (cast_type == CAST_TYPE_OPTIONAL_IMPLICIT) return true; - sema_type_mismatch(left, type, CAST_TYPE_EXPLICIT); + sema_type_mismatch(context, left, type, CAST_TYPE_EXPLICIT); return false; } if (!type_is_subtype(canonical->array.base, from->pointer->array.base)) { if (cast_type == CAST_TYPE_OPTIONAL_IMPLICIT) return true; - sema_type_mismatch(left, type, CAST_TYPE_EXPLICIT); + sema_type_mismatch(context, left, type, CAST_TYPE_EXPLICIT); return false; } insert_cast(left, CAST_APTSA, canonical); return true; } -bool usbo(Expr* left, Type *from, Type *canonical, Type *type, CastType cast_type) +bool usbo(Context *context, Expr* left, Type *from, Type *canonical, Type *type, CastType cast_type) { TODO } -bool vapt(Expr* left, Type *from, Type *canonical, Type *type, CastType cast_type) +bool vapt(Context *context, Expr* left, Type *from, Type *canonical, Type *type, CastType cast_type) { TODO } -bool cast_implicitly_to_runtime(Expr *expr) +bool cast_implicitly_to_runtime(Context *context, Expr *expr) { Type *canonical = expr->type->canonical; int success; switch (canonical->type_kind) { case TYPE_IXX: - return cast(expr, type_long, CAST_TYPE_IMPLICIT); + return cast(context, expr, type_long, CAST_TYPE_IMPLICIT); case TYPE_FXX: - return cast(expr, type_double, CAST_TYPE_IMPLICIT); + return cast(context, expr, type_double, CAST_TYPE_IMPLICIT); default: return true; } assert(success && "This should always work"); } -bool cast_implicit(Expr *expr, Type *to_type) +bool cast_implicit(Context *context, Expr *expr, Type *to_type) { if (!to_type) return true; - return cast(expr, to_type, CAST_TYPE_IMPLICIT); + return cast(context, expr, to_type, CAST_TYPE_IMPLICIT); } CastKind cast_to_bool_kind(Type *type) @@ -741,7 +741,7 @@ CastKind cast_to_bool_kind(Type *type) } -bool cast(Expr *expr, Type *to_type, CastType cast_type) +bool cast(Context *context, Expr *expr, Type *to_type, CastType cast_type) { Type *from_type = expr->type->canonical; Type *canonical = to_type->canonical; @@ -755,89 +755,89 @@ bool cast(Expr *expr, Type *to_type, CastType cast_type) break; case TYPE_BOOL: // Bool may convert into integers and floats but only explicitly. - if (type_is_integer(canonical)) return boxi(expr, canonical, to_type, cast_type); - if (type_is_float(canonical)) return bofp(expr, canonical, to_type, cast_type); + if (type_is_integer(canonical)) return boxi(context, expr, canonical, to_type, cast_type); + if (type_is_float(canonical)) return bofp(context, expr, canonical, to_type, cast_type); break; case TYPE_ERR_UNION: - if (to_type->type_kind == TYPE_BOOL) return eubool(expr, canonical, to_type, cast_type); - if (to_type->type_kind == TYPE_ERRTYPE) return euer(expr, canonical, to_type, cast_type); + if (to_type->type_kind == TYPE_BOOL) return eubool(context, expr, canonical, to_type, cast_type); + if (to_type->type_kind == TYPE_ERRTYPE) return euer(context, expr, canonical, to_type, cast_type); break; case TYPE_IXX: // Compile time integers may convert into ints, floats, bools - if (type_is_integer(canonical)) return ixxxi(expr, canonical, to_type, cast_type); - if (type_is_float(canonical)) return ixxfp(expr, canonical, to_type, cast_type); - if (canonical == type_bool) return ixxbo(expr, to_type); - if (canonical->type_kind == TYPE_POINTER) return xipt(expr, from_type, canonical, to_type, cast_type); - if (canonical->type_kind == TYPE_ENUM) return ixxen(expr, canonical, to_type, cast_type); + if (type_is_integer(canonical)) return ixxxi(context, expr, canonical, to_type, cast_type); + if (type_is_float(canonical)) return ixxfp(context, expr, canonical, to_type, cast_type); + if (canonical == type_bool) return ixxbo(context, expr, to_type); + if (canonical->type_kind == TYPE_POINTER) return xipt(context, expr, from_type, canonical, to_type, cast_type); + if (canonical->type_kind == TYPE_ENUM) return ixxen(context, expr, canonical, to_type, cast_type); break; case TYPE_I8: case TYPE_I16: case TYPE_I32: case TYPE_I64: - if (type_is_unsigned_integer(canonical)) return siui(expr, canonical, to_type, cast_type); - if (type_is_signed_integer(canonical)) return sisi(expr, from_type, canonical, to_type, cast_type); - if (type_is_float(canonical)) return sifp(expr, canonical, to_type); - if (canonical == type_bool) return xibo(expr, canonical, to_type, cast_type); - if (canonical->type_kind == TYPE_POINTER) return xipt(expr, from_type, canonical, to_type, cast_type); + if (type_is_unsigned_integer(canonical)) return siui(context, expr, canonical, to_type, cast_type); + if (type_is_signed_integer(canonical)) return sisi(context, expr, from_type, canonical, to_type, cast_type); + if (type_is_float(canonical)) return sifp(context, expr, canonical, to_type); + if (canonical == type_bool) return xibo(context, expr, canonical, to_type, cast_type); + if (canonical->type_kind == TYPE_POINTER) return xipt(context, expr, from_type, canonical, to_type, cast_type); break; case TYPE_U8: case TYPE_U16: case TYPE_U32: case TYPE_U64: - if (type_is_unsigned_integer(canonical)) return uiui(expr, from_type, canonical, to_type, cast_type); - if (type_is_signed_integer(canonical)) return uisi(expr, from_type, canonical, to_type, cast_type); - if (type_is_float(canonical)) return uifp(expr, canonical, to_type); - if (canonical == type_bool) return xibo(expr, canonical, to_type, cast_type); - if (canonical->type_kind == TYPE_POINTER) return xipt(expr, from_type, canonical, to_type, cast_type); + if (type_is_unsigned_integer(canonical)) return uiui(context, expr, from_type, canonical, to_type, cast_type); + if (type_is_signed_integer(canonical)) return uisi(context, expr, from_type, canonical, to_type, cast_type); + if (type_is_float(canonical)) return uifp(context, expr, canonical, to_type); + if (canonical == type_bool) return xibo(context, expr, canonical, to_type, cast_type); + if (canonical->type_kind == TYPE_POINTER) return xipt(context, expr, from_type, canonical, to_type, cast_type); break; case TYPE_F32: case TYPE_F64: case TYPE_FXX: - if (type_is_integer(canonical)) return fpxi(expr, canonical, to_type, cast_type); - if (canonical == type_bool) return fpbo(expr, canonical, to_type, cast_type); - if (type_is_float(canonical)) return fpfp(expr, from_type, canonical, to_type, cast_type); + if (type_is_integer(canonical)) return fpxi(context, expr, canonical, to_type, cast_type); + if (canonical == type_bool) return fpbo(context, expr, canonical, to_type, cast_type); + if (type_is_float(canonical)) return fpfp(context, expr, from_type, canonical, to_type, cast_type); break; case TYPE_POINTER: - if (type_is_integer(canonical)) return ptxi(expr, canonical, to_type, cast_type); - if (canonical->type_kind == TYPE_BOOL) return ptbo(expr, canonical, to_type, cast_type); - if (canonical->type_kind == TYPE_POINTER) return ptpt(expr, from_type, canonical, to_type, cast_type); - if (canonical->type_kind == TYPE_VARARRAY) return ptva(expr, from_type, canonical, to_type, cast_type); - if (canonical->type_kind == TYPE_SUBARRAY) return ptsa(expr, from_type, canonical, to_type, cast_type); + if (type_is_integer(canonical)) return ptxi(context, expr, canonical, to_type, cast_type); + if (canonical->type_kind == TYPE_BOOL) return ptbo(context, expr, canonical, to_type, cast_type); + if (canonical->type_kind == TYPE_POINTER) return ptpt(context, expr, from_type, canonical, to_type, cast_type); + if (canonical->type_kind == TYPE_VARARRAY) return ptva(context, expr, from_type, canonical, to_type, cast_type); + if (canonical->type_kind == TYPE_SUBARRAY) return ptsa(context, expr, from_type, canonical, to_type, cast_type); break; case TYPE_ENUM: - if (type_is_integer(canonical)) return enxi(expr, from_type, canonical, to_type, cast_type); + if (type_is_integer(canonical)) return enxi(context, expr, from_type, canonical, to_type, cast_type); break; case TYPE_ERRTYPE: - if (canonical->type_kind == TYPE_ERR_UNION) return ereu(expr, canonical, to_type, cast_type); + if (canonical->type_kind == TYPE_ERR_UNION) return ereu(context, expr, canonical, to_type, cast_type); break; case TYPE_FUNC: SEMA_ERROR(expr, "The function call is missing (...), if you want to take the address of a function it must be prefixed with '&'."); return false; case TYPE_STRUCT: - if (canonical->type_kind == TYPE_STRUCT) return stst(expr, from_type, canonical, to_type, cast_type); - if (canonical->type_kind == TYPE_UNION) return stun(expr, from_type, canonical, to_type, cast_type); + if (canonical->type_kind == TYPE_STRUCT) return stst(context, expr, from_type, canonical, to_type, cast_type); + if (canonical->type_kind == TYPE_UNION) return stun(context, expr, from_type, canonical, to_type, cast_type); break; case TYPE_UNION: - if (canonical->type_kind == TYPE_STRUCT) return unst(expr, from_type, canonical, to_type, cast_type); - if (canonical->type_kind == TYPE_UNION) return unun(expr, from_type, canonical, to_type, cast_type); + if (canonical->type_kind == TYPE_STRUCT) return unst(context, expr, from_type, canonical, to_type, cast_type); + if (canonical->type_kind == TYPE_UNION) return unun(context, expr, from_type, canonical, to_type, cast_type); break; case TYPE_TYPEDEF: UNREACHABLE case TYPE_STRING: - if (canonical->type_kind == TYPE_POINTER) return strpt(expr, from_type, canonical, to_type, cast_type); + if (canonical->type_kind == TYPE_POINTER) return strpt(context, expr, from_type, canonical, to_type, cast_type); break; case TYPE_ARRAY: // There is no valid cast from array to anything else. break; case TYPE_VARARRAY: - if (canonical->type_kind == TYPE_SUBARRAY) return vasa(expr, from_type, canonical, to_type, cast_type); - if (canonical->type_kind == TYPE_VARARRAY) return vava(expr, from_type, canonical, to_type, cast_type); - if (canonical->type_kind == TYPE_POINTER) return vapt(expr, from_type, canonical, to_type, cast_type); + if (canonical->type_kind == TYPE_SUBARRAY) return vasa(context, expr, from_type, canonical, to_type, cast_type); + if (canonical->type_kind == TYPE_VARARRAY) return vava(context, expr, from_type, canonical, to_type, cast_type); + if (canonical->type_kind == TYPE_POINTER) return vapt(context, expr, from_type, canonical, to_type, cast_type); break; case TYPE_SUBARRAY: - if (canonical->type_kind == TYPE_POINTER) return sapt(expr, from_type, canonical, to_type, cast_type); + if (canonical->type_kind == TYPE_POINTER) return sapt(context, expr, from_type, canonical, to_type, cast_type); break; } if (cast_type == CAST_TYPE_OPTIONAL_IMPLICIT) return true; - return sema_type_mismatch(expr, canonical, cast_type); + return sema_type_mismatch(context, expr, canonical, cast_type); } diff --git a/src/compiler/sema_decls.c b/src/compiler/sema_decls.c index cf25c1054..cb13d9f79 100644 --- a/src/compiler/sema_decls.c +++ b/src/compiler/sema_decls.c @@ -265,7 +265,7 @@ static inline bool sema_analyse_enum(Context *context, Decl *decl) // This will be evaluated later to catch the case if (!expr) { - expr = expr_new(EXPR_CONST, enum_value->name_span); + expr = expr_new(EXPR_CONST, source_span_from_token_id(enum_value->name_token)); expr->type = type; expr->resolve_status = RESOLVE_NOT_DONE; bigint_init_bigint(&expr->const_expr.i, &value); @@ -314,8 +314,8 @@ static inline bool sema_analyse_method(Context *context, Decl *decl) if (!type_may_have_sub_elements(parent_type->type)) { SEMA_ERROR(decl, - "Methods can not be associated with '%s'", - type_to_error_string(decl->func.type_parent->type)); + "Methods can not be associated with '%s'", + type_to_error_string(decl->func.type_parent->type)); return false; } Decl *parent = parent_type->type->decl; @@ -336,7 +336,7 @@ static inline bool sema_analyse_method(Context *context, Decl *decl) static inline AttributeType attribute_by_name(Attr *attr) { - const char *attribute = attr->name.string; + const char *attribute = TOKSTR(attr->name); for (unsigned i = 0; i < NUMBER_OF_ATTRIBUTES; i++) { if (attribute_list[i] == attribute) return (AttributeType)i; @@ -372,7 +372,7 @@ static AttributeType sema_analyse_attribute(Context *context, Attr *attr, Attrib AttributeType type = attribute_by_name(attr); if (type == ATTRIBUTE_NONE) { - SEMA_TOKEN_ERROR(attr->name, "There is no attribute with the name '%s', did you mistype?", attr->name.string); + SEMA_TOKID_ERROR(attr->name, "There is no attribute with the name '%s', did you mistype?", TOKSTR(attr->name)); return ATTRIBUTE_NONE; } static AttributeDomain attribute_domain[NUMBER_OF_ATTRIBUTES] = { @@ -389,7 +389,7 @@ static AttributeType sema_analyse_attribute(Context *context, Attr *attr, Attrib if ((attribute_domain[type] & domain) != domain) { - SEMA_TOKEN_ERROR(attr->name, "'%s' is not a valid %s attribute.", attr->name.string, attribute_domain_to_string(domain)); + SEMA_TOKID_ERROR(attr->name, "'%s' is not a valid %s attribute.", TOKSTR(attr->name), attribute_domain_to_string(domain)); return ATTRIBUTE_NONE; } switch (type) @@ -399,7 +399,7 @@ static AttributeType sema_analyse_attribute(Context *context, Attr *attr, Attrib case ATTRIBUTE_ALIGN: if (!attr->expr) { - SEMA_TOKEN_ERROR(attr->name, "'align' requires an power-of-2 argument, e.g. align(8)."); + SEMA_TOKID_ERROR(attr->name, "'align' requires an power-of-2 argument, e.g. align(8)."); return ATTRIBUTE_NONE; } if (!sema_analyse_expr(context, type_usize, attr->expr)) return false; @@ -434,7 +434,7 @@ static AttributeType sema_analyse_attribute(Context *context, Attr *attr, Attrib case ATTRIBUTE_CNAME: if (!attr->expr) { - SEMA_TOKEN_ERROR(attr->name, "'%s' requires a string argument, e.g. %s(\"foo\").", attr->name.string, attr->name.string); + SEMA_TOKID_ERROR(attr->name, "'%s' requires a string argument, e.g. %s(\"foo\").", TOKSTR(attr->name), TOKSTR(attr->name)); return ATTRIBUTE_NONE; } if (!sema_analyse_expr(context, NULL, attr->expr)) return false; @@ -447,7 +447,7 @@ static AttributeType sema_analyse_attribute(Context *context, Attr *attr, Attrib default: if (attr->expr) { - SEMA_ERROR(attr->expr, "'%s' should not have any arguments.", attr->name.string); + SEMA_ERROR(attr->expr, "'%s' should not have any arguments.", TOKSTR(attr->name)); return ATTRIBUTE_NONE; } return type; @@ -499,12 +499,12 @@ static inline bool sema_analyse_func(Context *context, Decl *decl) #undef SET_ATTR if (had) { - SEMA_TOKEN_ERROR(attr->name, "Attribute occurred twice, please remove one."); + SEMA_TOKID_ERROR(attr->name, "Attribute occurred twice, please remove one."); return decl_poison(decl); } if (decl->func.attr_inline && decl->func.attr_noinline) { - SEMA_TOKEN_ERROR(attr->name, "A function cannot be 'inline' and 'noinline' at the same time."); + SEMA_TOKID_ERROR(attr->name, "A function cannot be 'inline' and 'noinline' at the same time."); return decl_poison(decl); } } @@ -582,7 +582,7 @@ static inline bool sema_analyse_global(Context *context, Decl *decl) #undef SET_ATTR if (had) { - SEMA_TOKEN_ERROR(attr->name, "Attribute occurred twice, please remove one."); + SEMA_TOKID_ERROR(attr->name, "Attribute occurred twice, please remove one."); return decl_poison(decl); } } diff --git a/src/compiler/sema_expr.c b/src/compiler/sema_expr.c index 5272cba12..3eca7dff5 100644 --- a/src/compiler/sema_expr.c +++ b/src/compiler/sema_expr.c @@ -7,7 +7,6 @@ /* * TODOs - * - Check all returns correctly * - Disallow jumping in and out of an expression block. */ @@ -19,6 +18,7 @@ static bool sema_expr_analyse_type_access(Context *context, Type *to, Expr *expr static Decl *decl_copy_local_from_macro(Context *context, Decl *to_copy); static TypeInfo *type_info_copy_from_macro(Context *context, TypeInfo *source); +#define MACRO_COPY_DECL(x) x = decl_copy_local_from_macro(context, x) #define MACRO_COPY_EXPR(x) x = expr_copy_from_macro(context, x) #define MACRO_COPY_TYPE(x) x = type_info_copy_from_macro(context, x) #define MACRO_COPY_TYPE_LIST(x) x = type_info_copy_list_from_macro(context, x) @@ -121,21 +121,21 @@ static ExprFailableStatus expr_is_failable(Expr *expr) } -static inline bool sema_type_error_on_binop(Expr *expr) +static inline bool sema_type_error_on_binop(Context *context, Expr *expr) { const char *c = token_type_to_string(binaryop_to_token(expr->binary_expr.operator)); SEMA_ERROR(expr, "%s is not defined in the expression '%s' %s '%s'.", - c, type_to_error_string(expr->binary_expr.left->type), - c, type_to_error_string(expr->binary_expr.right->type)); + c, type_to_error_string(expr->binary_expr.left->type), + c, type_to_error_string(expr->binary_expr.right->type)); return false; } -static bool expr_cast_to_index(Expr *index) +static bool expr_cast_to_index(Context *context, Expr *index) { if (index->type->canonical->type_kind == type_usize->canonical->type_kind) return true; - if (index->expr_kind != EXPR_RANGE) return cast_implicit(index, type_isize); - if (!cast_implicit(index->range_expr.left, type_isize)) return false; - if (!cast_implicit(index->range_expr.right, type_isize)) return false; + if (index->expr_kind != EXPR_RANGE) return cast_implicit(context, index, type_isize); + if (!cast_implicit(context, index->range_expr.left, type_isize)) return false; + if (!cast_implicit(context, index->range_expr.right, type_isize)) return false; index->type = type_isize; return true; } @@ -148,7 +148,7 @@ static inline bool sema_expr_analyse_ternary(Context *context, Type *to, Expr *e if (left) { if (!sema_analyse_expr(context, type_bool, cond)) return expr_poison(expr); - if (!cast_implicit(cond, type_bool)) return expr_poison(expr); + if (!cast_implicit(context, cond, type_bool)) return expr_poison(expr); if (!sema_analyse_expr(context, to, left)) return expr_poison(expr); expr->failable = left->failable | cond->failable; } @@ -174,8 +174,8 @@ static inline bool sema_expr_analyse_ternary(Context *context, Type *to, Expr *e Type *right_canonical = right->type->canonical; if (type_is_ct(left_canonical) && type_is_ct(right_canonical)) { - if (!cast_implicitly_to_runtime(left)) return false; - if (!cast_implicitly_to_runtime(right)) return false; + if (!cast_implicitly_to_runtime(context, left)) return false; + if (!cast_implicitly_to_runtime(context, right)) return false; left_canonical = left->type->canonical; right_canonical = right->type->canonical; } @@ -185,10 +185,10 @@ static inline bool sema_expr_analyse_ternary(Context *context, Type *to, Expr *e if (!max) { SEMA_ERROR(expr, "Cannot find a common parent type of '%s' and '%s'", - type_to_error_string(left_canonical), type_to_error_string(right_canonical)); + type_to_error_string(left_canonical), type_to_error_string(right_canonical)); return false; } - if (!cast_implicit(left, max) || !cast_implicit(right, max)) return false; + if (!cast_implicit(context, left, max) || !cast_implicit(context, right, max)) return false; } expr->type = left->type; @@ -209,7 +209,7 @@ static inline Decl *decl_copy_label_from_macro(Context *context, Decl *to_copy, { if (!to_copy) return NULL; to_copy = decl_copy_local_from_macro(context, to_copy); - to_copy->label.parent = ast; + to_copy->label.parent = astid(ast); return to_copy; } @@ -268,10 +268,10 @@ static inline bool sema_expr_analyse_identifier(Context *context, Type *to, Expr if (ambiguous_decl) { SEMA_ERROR(expr, - "Ambiguous symbol '%s' – both defined in %s and %s, please add the module name to resolve the ambiguity", - expr->identifier_expr.identifier, - decl->module->name->module, - ambiguous_decl->module->name->module); + "Ambiguous symbol '%s' – both defined in %s and %s, please add the module name to resolve the ambiguity", + expr->identifier_expr.identifier, + decl->module->name->module, + ambiguous_decl->module->name->module); return false; } @@ -322,7 +322,7 @@ static inline bool sema_expr_analyse_binary_sub_expr(Context *context, Type *to, return sema_analyse_expr(context, to, left) & sema_analyse_expr(context, to, right); } -static inline int find_index_of_named_parameter(Decl** func_params, Expr *expr) +static inline int find_index_of_named_parameter(Context *context, Decl** func_params, Expr *expr) { if (expr->expr_kind != EXPR_IDENTIFIER || expr->identifier_expr.path) { @@ -359,7 +359,7 @@ static inline bool sema_expr_analyse_func_invocation(Context *context, FunctionS if (!is_implicit && arg->expr_kind == EXPR_BINARY && arg->binary_expr.operator == BINARYOP_ASSIGN) { uses_named_parameters = true; - int index = find_index_of_named_parameter(func_params, arg->binary_expr.left); + int index = find_index_of_named_parameter(context, func_params, arg->binary_expr.left); if (index < 0) return false; if (actual_args[index]) { @@ -460,7 +460,7 @@ static inline Type *unify_returns(Context *context, Type *to) SEMA_ERROR(return_stmt, "The return must be a value of type '%s'.", type_to_error_string(to)); return NULL; } - if (!cast_implicit(ret_expr, to)) + if (!cast_implicit(context, ret_expr, to)) { return NULL; } @@ -475,7 +475,7 @@ static inline Type *unify_returns(Context *context, Type *to) if (!max) { SEMA_ERROR(return_stmt, "Cannot find a common parent type of '%s' and '%s'", - type_to_error_string(to), type_to_error_string(right_canonical)); + type_to_error_string(to), type_to_error_string(right_canonical)); SEMA_PREV(context->returns[i - 1], "The previous return was here."); return false; } @@ -488,7 +488,7 @@ static inline Type *unify_returns(Context *context, Type *to) { Ast *return_stmt = context->returns[i]; Expr *ret_expr = return_stmt->return_stmt.expr; - if (!cast_implicit(ret_expr, to)) + if (!cast_implicit(context, ret_expr, to)) { return NULL; } @@ -677,7 +677,7 @@ static inline bool sema_expr_analyse_range(Context *context, Type *to, Expr *exp if (left_canonical != right_canonical) { Type *type = type_find_max_type(left_canonical, right_canonical); - if (!cast_implicit(left, type) || !cast_implicit(right, type)) return expr_poison(expr); + if (!cast_implicit(context, left, type) || !cast_implicit(context, right, type)) return expr_poison(expr); } if (left->expr_kind == EXPR_CONST && right->expr_kind == EXPR_CONST) { @@ -691,11 +691,11 @@ static inline bool sema_expr_analyse_range(Context *context, Type *to, Expr *exp return true; } -static bool expr_check_index_in_range(Type *type, Expr *index) +static bool expr_check_index_in_range(Context *context, Type *type, Expr *index) { if (index->expr_kind == EXPR_RANGE) { - return expr_check_index_in_range(type, index->range_expr.left) & expr_check_index_in_range(type, index->range_expr.right); + return expr_check_index_in_range(context, type, index->range_expr.left) & expr_check_index_in_range(context, type, index->range_expr.right); } assert(type == type->canonical); if (index->expr_kind == EXPR_CONST) @@ -711,7 +711,7 @@ static bool expr_check_index_in_range(Type *type, Expr *index) if (bigint_cmp(&size, &index->const_expr.i) != CMP_GT) { SEMA_ERROR(index, "Array index out of bounds, was %s, exceeding max index of %llu.", - bigint_to_error_string(&index->const_expr.i, 10), type->array.len - 1); + bigint_to_error_string(&index->const_expr.i, 10), type->array.len - 1); return false; } FALLTHROUGH; @@ -756,10 +756,10 @@ static inline bool sema_expr_analyse_subscript_after_parent_resolution(Context * } // Unless we already have type_usize, cast to type_isize; - if (!expr_cast_to_index(index)) return false; + if (!expr_cast_to_index(context, index)) return false; // Check range - if (!expr_check_index_in_range(type, index)) return false; + if (!expr_check_index_in_range(context, type, index)) return false; expr->failable |= index->failable; if (index->expr_kind == EXPR_RANGE) @@ -780,7 +780,7 @@ static inline bool sema_expr_analyse_subscript(Context *context, Type *to, Expr static inline bool sema_expr_analyse_method(Context *context, Expr *expr, Decl *decl, bool is_pointer) { - const char *name = expr->access_expr.sub_element.string; + const char *name = TOKSTR(expr->access_expr.sub_element); VECEACH(decl->methods, i) { Decl *function = decl->methods[i]; @@ -846,7 +846,9 @@ static bool sema_expr_analyse_type_access(Context *context, Type *to, Expr *expr TypeInfo *type_info = expr->type_access.type; if (!sema_resolve_type_info(context, type_info)) return false; Type *canonical = type_info->type->canonical; - if (expr->type_access.name.type == TOKEN_TYPEID) + TokenType type = TOKTYPE(expr->type_access.name); + const char *name = TOKSTR(expr->type_access.name); + if (type == TOKEN_TYPEID) { expr->type = type_typeid; expr->expr_kind = EXPR_TYPEID; @@ -865,16 +867,16 @@ static bool sema_expr_analyse_type_access(Context *context, Type *to, Expr *expr switch (decl->decl_kind) { case DECL_ENUM: - if (expr->type_access.name.type == TOKEN_CONST_IDENT) + if (type == TOKEN_CONST_IDENT) { - if (!sema_expr_analyse_enum_constant(expr, expr->type_access.name.string, decl)) + if (!sema_expr_analyse_enum_constant(expr, name, decl)) { - SEMA_ERROR(expr, "'%s' has no enumeration value '%s'.", decl->name, expr->type_access.name.string); + SEMA_ERROR(expr, "'%s' has no enumeration value '%s'.", decl->name, name); return false; } return true; } - if (expr->type_access.name.start == kw_sizeof) + if (name == kw_sizeof) { expr_rewrite_to_int_const(expr, type_usize, type_size(decl->enums.type_info->type)); return true; @@ -883,7 +885,7 @@ static bool sema_expr_analyse_type_access(Context *context, Type *to, Expr *expr case DECL_ERR: case DECL_UNION: case DECL_STRUCT: - if (expr->type_access.name.start == kw_sizeof) + if (name == kw_sizeof) { expr_rewrite_to_int_const(expr, type_usize, type_size(decl->type)); return true; @@ -897,7 +899,7 @@ static bool sema_expr_analyse_type_access(Context *context, Type *to, Expr *expr VECEACH(decl->methods, i) { Decl *function = decl->methods[i]; - if (expr->type_access.name.string == function->name) + if (name == function->name) { expr->type_access.decl = function; expr->type = function->type; @@ -907,14 +909,14 @@ static bool sema_expr_analyse_type_access(Context *context, Type *to, Expr *expr VECEACH(decl->strukt.members, i) { Decl *member = decl->strukt.members[i]; - if (expr->type_access.name.string == member->name) + if (name == member->name) { expr->type_access.decl = member; expr->type = member->member_decl.reference_type; return true; } } - SEMA_ERROR(expr, "No function or member '%s.%s' found.", type_to_error_string(type_info->type), expr->type_access.name.string); + SEMA_ERROR(expr, "No function or member '%s.%s' found.", type_to_error_string(type_info->type), name); return false; } @@ -922,8 +924,7 @@ static inline bool sema_expr_analyse_member_access(Context *context, Expr *expr) { Type *type = expr->access_expr.parent->type->decl->member_decl.type_info->type; Type *canonical = type->canonical; - Token token = expr->access_expr.sub_element; - const char *sub_element = token.string; + const char *sub_element = TOKSTR(expr->access_expr.sub_element); if (sub_element == kw_sizeof) { expr_rewrite_to_int_const(expr, type_usize, type_size(canonical)); @@ -944,14 +945,14 @@ static inline bool sema_expr_analyse_member_access(Context *context, Expr *expr) switch (decl->decl_kind) { case DECL_ENUM: - if (token.type == TOKEN_CONST_IDENT) + if (TOKTYPE(expr->access_expr.sub_element) == TOKEN_CONST_IDENT) { if (!sema_expr_analyse_enum_constant(expr, sub_element, decl)) { SEMA_ERROR(expr, - "'%s' has no enumeration value '%s'.", - decl->name, - sub_element); + "'%s' has no enumeration value '%s'.", + decl->name, + sub_element); return false; } return true; @@ -990,9 +991,9 @@ static inline bool sema_expr_analyse_member_access(Context *context, Expr *expr) } } SEMA_ERROR(expr, - "No function or member '%s.%s' found.", - type_to_error_string(type), - sub_element); + "No function or member '%s.%s' found.", + type_to_error_string(type), + sub_element); return false; } @@ -1020,7 +1021,7 @@ static inline bool sema_expr_analyse_access(Context *context, Expr *expr) } if (!type_may_have_sub_elements(type)) { - SEMA_ERROR(expr, "Cannot access '%s' on '%s'", expr->access_expr.sub_element.string, type_to_error_string(parent_type)); + SEMA_ERROR(expr, "Cannot access '%s' on '%s'", TOKSTR(expr->access_expr.sub_element), type_to_error_string(parent_type)); return false; } Decl *decl = type->decl; @@ -1035,7 +1036,7 @@ static inline bool sema_expr_analyse_access(Context *context, Expr *expr) default: UNREACHABLE } - Decl *member = strukt_recursive_search_member(decl, expr->access_expr.sub_element.string); + Decl *member = strukt_recursive_search_member(decl, TOKSTR(expr->access_expr.sub_element)); if (!member) { return sema_expr_analyse_method(context, expr, decl, is_pointer); @@ -1098,10 +1099,11 @@ static DesignatedPath *sema_analyse_init_access(Context *context, DesignatedPath { DesignatedPath *last_path = sema_analyse_init_path(context, parent, access_expr->access_expr.parent, has_found_match, has_reported_error); if (!last_path) return NULL; - DesignatedPath *path = sema_analyse_init_identifier_string(context, last_path, access_expr->access_expr.sub_element.string, has_found_match, has_reported_error); + DesignatedPath *path = sema_analyse_init_identifier_string(context, last_path, + TOKSTR(access_expr->access_expr.sub_element), has_found_match, has_reported_error); if (!path && has_found_match && !has_reported_error) { - SEMA_TOKEN_ERROR(access_expr->access_expr.sub_element, "'%s' is not a valid sub member.", access_expr->access_expr.sub_element.string); + SEMA_TOKID_ERROR(access_expr->access_expr.sub_element, "'%s' is not a valid sub member.", TOKSTR(access_expr->access_expr.sub_element)); *has_reported_error = true; } return path; @@ -1141,14 +1143,14 @@ static DesignatedPath *sema_analyse_init_subscript(Context *context, DesignatedP } // Unless we already have type_usize, cast to type_isize; - if (!expr_cast_to_index(index)) + if (!expr_cast_to_index(context, index)) { *has_reported_error = true; return NULL; } // Check range - if (!expr_check_index_in_range(type->canonical, index)) + if (!expr_check_index_in_range(context, type->canonical, index)) { *has_reported_error = true; return NULL; @@ -1398,11 +1400,11 @@ static inline bool sema_expr_analyse_cast(Context *context, Type *to, Expr *expr if (!sema_resolve_type_info(context, expr->cast_expr.type_info)) return false; if (!sema_analyse_expr_of_required_type(context, NULL, inner, true)) return false; - if (!cast(inner, expr->cast_expr.type_info->type, CAST_TYPE_EXPLICIT)) return false; + if (!cast(context, inner, expr->cast_expr.type_info->type, CAST_TYPE_EXPLICIT)) return false; // TODO above is probably not right, cast type not set. // Overwrite cast. - SourceRange loc = expr->span; + SourceSpan loc = expr->span; *expr = *inner; expr->span = loc; expr->failable = expr->failable; @@ -1433,7 +1435,7 @@ static inline bool sema_expr_analyse_fail_check(Context *context, Expr *expr) if (!inner->failable) { SEMA_ERROR(expr, "You can only check a failable type e.g. '%s!' not '%s'.", - type_to_error_string(inner->type), type_to_error_string(inner->type)); + type_to_error_string(inner->type), type_to_error_string(inner->type)); return false; } if (inner->expr_kind == EXPR_IDENTIFIER && (context->current_scope->flags & SCOPE_COND)) @@ -1623,27 +1625,27 @@ static bool sema_expr_analyse_add_sub_assign(Context *context, Expr *expr, Expr if (is_mod) { SEMA_ERROR(expr, "Cannot use %s with pointer arithmetics, use %s instead.", - token_type_to_string(binaryop_to_token(expr->binary_expr.operator)), - token_type_to_string(binaryop_to_token(binary_mod_op_to_non_mod(expr->binary_expr.operator)))); + token_type_to_string(binaryop_to_token(expr->binary_expr.operator)), + token_type_to_string(binaryop_to_token(binary_mod_op_to_non_mod(expr->binary_expr.operator)))); return false; } // 5. Convert any compile time values to runtime - if (!cast_implicitly_to_runtime(right)) return false; + if (!cast_implicitly_to_runtime(context, right)) return false; // 6. Finally, check that the right side is indeed an integer. if (!type_is_integer(right->type->canonical)) { SEMA_ERROR(right, "The right side was '%s' but only integers are valid on the right side of %s when the left side is a pointer.", - type_to_error_string(right->type), - token_type_to_string(binaryop_to_token(expr->binary_expr.operator))); + type_to_error_string(right->type), + token_type_to_string(binaryop_to_token(expr->binary_expr.operator))); return false; } return true; } // 5. Otherwise we cast rhs to lhs - if (!cast_implicit(right, left->type)) return false; + if (!cast_implicit(context, right, left->type)) return false; // 6. We expect a numeric type on both left and right if (!type_is_numeric(left->type)) @@ -1656,18 +1658,18 @@ static bool sema_expr_analyse_add_sub_assign(Context *context, Expr *expr, Expr if (is_mod && !type_is_integer(left->type->canonical)) { SEMA_ERROR(expr, "%s can only be used for integer arithmetics, for other cases use %s instead.", - token_type_to_string(binaryop_to_token(expr->binary_expr.operator)), - token_type_to_string(binaryop_to_token(binary_mod_op_to_non_mod(expr->binary_expr.operator)))); + token_type_to_string(binaryop_to_token(expr->binary_expr.operator)), + token_type_to_string(binaryop_to_token(binary_mod_op_to_non_mod(expr->binary_expr.operator)))); return false; } return true; } -static bool binary_arithmetic_promotion(Expr *left, Expr *right, Type *left_type, Type *right_type) +static bool binary_arithmetic_promotion(Context *context, Expr *left, Expr *right, Type *left_type, Type *right_type) { Type *max = type_find_max_type(left_type, right_type); - return max && type_is_numeric(max) && cast_implicit(left, max) && cast_implicit(right, max); + return max && type_is_numeric(max) && cast_implicit(context, left, max) && cast_implicit(context, right, max); } /** @@ -1716,7 +1718,7 @@ static bool sema_expr_analyse_sub(Context *context, Type *to, Expr *expr, Expr * } // 5. Cast any compile time int into runtime version if we have a compile time constant. - if (!cast_implicitly_to_runtime(right)) return false; + if (!cast_implicitly_to_runtime(context, right)) return false; // 6. No need for further casts, just it is an integer. if (!type_is_integer(right_type)) @@ -1730,7 +1732,7 @@ static bool sema_expr_analyse_sub(Context *context, Type *to, Expr *expr, Expr * } // 7. Attempt arithmetic promotion, to promote both to a common type. - if (!binary_arithmetic_promotion(left, right, left_type, right_type)) + if (!binary_arithmetic_promotion(context, left, right, left_type, right_type)) { SEMA_ERROR(expr, "Cannot subtract '%s' from '%s'", type_to_error_string(left_type), type_to_error_string(right_type)); return false; @@ -1803,14 +1805,14 @@ static bool sema_expr_analyse_add(Context *context, Type *to, Expr *expr, Expr * if (!type_is_any_integer(right_type)) { SEMA_ERROR(right, "A value of type '%s' cannot be added to '%s', an integer was expected here.", - type_to_error_string(right->type), - type_to_error_string(left->type)); + type_to_error_string(right->type), + type_to_error_string(left->type)); return false; } // 4b. Cast it to usize or isize depending on underlying type. // Either is fine, but it looks a bit nicer if we actually do this and keep the sign. - bool success = cast_implicit(right, type_is_unsigned(right_type) ? type_usize : type_isize); + bool success = cast_implicit(context, right, type_is_unsigned(right_type) ? type_usize : type_isize); // No need to check the cast we just ensured it was an integer. assert(success && "This should always work"); @@ -1828,7 +1830,7 @@ static bool sema_expr_analyse_add(Context *context, Type *to, Expr *expr, Expr * // 5. Do the binary arithmetic promotion (finding a common super type) // If none can be find, send an error. - if (!binary_arithmetic_promotion(left, right, left_type, right_type)) + if (!binary_arithmetic_promotion(context, left, right, left_type, right_type)) { SEMA_ERROR(expr, "Cannot add '%s' to '%s'", type_to_error_string(left_type), type_to_error_string(right_type)); return false; @@ -1886,7 +1888,7 @@ static bool sema_expr_analyse_mult(Context *context, Type *to, Expr *expr, Expr Type *right_type = right->type->canonical; // 2. Perform promotion to a common type. - if (!binary_arithmetic_promotion(left, right, left_type, right_type)) + if (!binary_arithmetic_promotion(context, left, right, left_type, right_type)) { SEMA_ERROR(expr, "Cannot multiply '%s' with '%s'", type_to_error_string(left->type), type_to_error_string(right->type)); return false; @@ -1951,7 +1953,7 @@ static bool sema_expr_analyse_div(Context *context, Type *to, Expr *expr, Expr * Type *right_type = right->type->canonical; // 2. Perform promotion to a common type. - if (!binary_arithmetic_promotion(left, right, left_type, right_type)) + if (!binary_arithmetic_promotion(context, left, right, left_type, right_type)) { SEMA_ERROR(expr, "Cannot divide '%s' by '%s'.", type_to_error_string(left_type), type_to_error_string(right_type)); return false; @@ -2016,7 +2018,7 @@ static bool sema_expr_analyse_mod(Context *context, Type *to, Expr *expr, Expr * // 2. Make sure we have some sort of integer on both sides. if (!type_is_any_integer(right->type->canonical) || !type_is_any_integer(left->type->canonical)) { - return sema_type_error_on_binop(expr); + return sema_type_error_on_binop(context, expr); } // 3. a % 0 is not valid, so detect it. @@ -2051,7 +2053,7 @@ static bool sema_expr_analyse_bit(Context *context, Type *to, Expr *expr, Expr * // 2. Check that both are integers. if (!both_any_integer(left, right)) { - return sema_type_error_on_binop(expr); + return sema_type_error_on_binop(context, expr); } // 3. Promote to the same type. @@ -2059,9 +2061,9 @@ static bool sema_expr_analyse_bit(Context *context, Type *to, Expr *expr, Expr * Type *left_type = left->type->canonical; Type *right_type = right->type->canonical; - if (!binary_arithmetic_promotion(left, right, left_type, right_type)) + if (!binary_arithmetic_promotion(context, left, right, left_type, right_type)) { - return sema_type_error_on_binop(expr); + return sema_type_error_on_binop(context, expr); } // 4. Do constant folding if both sides are constant. @@ -2101,7 +2103,7 @@ static bool sema_expr_analyse_shift(Context *context, Type *to, Expr *expr, Expr // 2. Only integers may be shifted. if (!both_any_integer(left, right)) { - return sema_type_error_on_binop(expr); + return sema_type_error_on_binop(context, expr); } // 3. For a constant right hand side we will make a series of checks. @@ -2153,17 +2155,17 @@ static bool sema_expr_analyse_shift(Context *context, Type *to, Expr *expr, Expr } // 5. We might have the case 2 << x. In that case we will to cast the left hand side to the receiving type. - if (!cast_implicit(left, to)) return false; + if (!cast_implicit(context, left, to)) return false; // 6. As a last out, we make sure that a comptime int has a real type by casting to the right side (which must be non constant) if (type_is_ct(left->type)) { assert(!type_is_ct(right->type)); - cast(left, right->type, CAST_TYPE_EXPLICIT); + cast(context, left, right->type, CAST_TYPE_EXPLICIT); } // 7. On LLVM, left and right types must match. - cast(right, left->type, CAST_TYPE_EXPLICIT); + cast(context, right, left->type, CAST_TYPE_EXPLICIT); expr->type = left->type; return true; @@ -2186,7 +2188,7 @@ static bool sema_expr_analyse_shift_assign(Context *context, Expr *expr, Expr *l } // 2. Only integers may be shifted. - if (!both_any_integer(left, right)) return sema_type_error_on_binop(expr); + if (!both_any_integer(left, right)) return sema_type_error_on_binop(context, expr); // 3. For a constant right hand side we will make a series of checks. if (is_const(right)) @@ -2213,7 +2215,7 @@ static bool sema_expr_analyse_shift_assign(Context *context, Expr *expr, Expr *l expr->type = left->type; // 5. This is already checked as ok - cast(right, left->type, CAST_TYPE_EXPLICIT); + cast(context, right, left->type, CAST_TYPE_EXPLICIT); return true; } @@ -2222,7 +2224,7 @@ static bool sema_expr_analyse_shift_assign(Context *context, Expr *expr, Expr *l static bool sema_expr_analyse_and(Context *context, Expr *expr, Expr *left, Expr *right) { if (!sema_analyse_expr(context, type_bool, left) & sema_analyse_expr(context, type_bool, right)) return false; - if (!cast_implicit(left, type_bool) || !cast_implicit(right, type_bool)) return false; + if (!cast_implicit(context, left, type_bool) || !cast_implicit(context, right, type_bool)) return false; expr->type = type_bool; if (both_const(left, right)) @@ -2236,7 +2238,7 @@ static bool sema_expr_analyse_and(Context *context, Expr *expr, Expr *left, Expr static bool sema_expr_analyse_or(Context *context, Expr *expr, Expr *left, Expr *right) { if (!sema_expr_analyse_binary_sub_expr(context, NULL, left, right)) return false; - if (!cast_implicit(left, type_bool) || !cast_implicit(right, type_bool)) return false; + if (!cast_implicit(context, left, type_bool) || !cast_implicit(context, right, type_bool)) return false; if (both_const(left, right)) { @@ -2249,7 +2251,7 @@ static bool sema_expr_analyse_or(Context *context, Expr *expr, Expr *left, Expr -static void cast_to_max_bit_size(Expr *left, Expr *right, Type *left_type, Type *right_type) +static void cast_to_max_bit_size(Context *context, Expr *left, Expr *right, Type *left_type, Type *right_type) { int bit_size_left = left_type->builtin.bitsize; int bit_size_right = right_type->builtin.bitsize; @@ -2260,14 +2262,14 @@ static void cast_to_max_bit_size(Expr *left, Expr *right, Type *left_type, Type Type *to = left->type->type_kind < TYPE_U8 ? type_signed_int_by_bitsize(bit_size_right) : type_unsigned_int_by_bitsize(bit_size_right); - bool success = cast_implicit(left, to); + bool success = cast_implicit(context, left, to); assert(success); return; } Type *to = right->type->type_kind < TYPE_U8 ? type_signed_int_by_bitsize(bit_size_right) : type_unsigned_int_by_bitsize(bit_size_right); - bool success = cast_implicit(right, to); + bool success = cast_implicit(context, right, to); assert(success); } @@ -2293,7 +2295,7 @@ static bool sema_expr_analyse_comp(Context *context, Expr *expr, Expr *left, Exp || (type_is_signed(left_type) && type_is_unsigned(right_type))) { // 2a. Resize so that both sides have the same bit width. This will always work. - cast_to_max_bit_size(left, right, left_type, right_type); + cast_to_max_bit_size(context, left, right, left_type, right_type); } else { @@ -2304,7 +2306,7 @@ static bool sema_expr_analyse_comp(Context *context, Expr *expr, Expr *left, Exp if (!max) { SEMA_ERROR(expr, "'%s' and '%s' are different types and cannot be compared.", - type_to_error_string(left->type), type_to_error_string(right->type)); + type_to_error_string(left->type), type_to_error_string(right->type)); }; // 5. Most types can do equality, but not all can do comparison, @@ -2349,8 +2351,8 @@ static bool sema_expr_analyse_comp(Context *context, Expr *expr, Expr *left, Exp } // 6. Do the implicit cast. - if (!cast_implicit(left, max)) goto ERR; - if (!cast_implicit(right, max)) goto ERR; + if (!cast_implicit(context, left, max)) goto ERR; + if (!cast_implicit(context, right, max)) goto ERR; } // 7. Do constant folding. @@ -2758,10 +2760,10 @@ static inline bool sema_expr_analyse_else(Context *context, Type *to, Expr *expr // Here we might need to insert casts. Type *common = type_find_max_type(type, expr->else_expr.else_expr->type); - if (!cast_implicit(expr->else_expr.else_expr, common)) return false; + if (!cast_implicit(context, expr->else_expr.else_expr, common)) return false; expr->type = common; - return cast_implicit(expr->else_expr.expr, common); + return cast_implicit(context, expr->else_expr.expr, common); } static Ast *ast_shallow_copy(Ast *source) @@ -2944,6 +2946,11 @@ static Expr **expr_copy_expr_list_from_macro(Context *context, Expr **expr_list) } +static inline void copy_flow(Context *context, Ast *ast) +{ + ast->flow.label = decl_copy_label_from_macro(context, ast->flow.label, ast); +} + static TypeInfo** type_info_copy_list_from_macro(Context *context, TypeInfo **to_copy) { TypeInfo **result = NULL; @@ -2985,9 +2992,10 @@ static Ast *ast_copy_from_macro(Context *context, Ast *source) return ast; break; case AST_CATCH_STMT: + copy_flow(context, ast); if (ast->catch_stmt.has_err_var) { - TODO + MACRO_COPY_DECL(ast->catch_stmt.err_var); } else { @@ -3029,7 +3037,7 @@ static Ast *ast_copy_from_macro(Context *context, Ast *source) MACRO_COPY_AST_LIST(ast->ct_switch_stmt.body); return ast; case AST_DECLARE_STMT: - ast->declare_stmt = decl_copy_local_from_macro(context, ast->declare_stmt); + MACRO_COPY_DECL(ast->declare_stmt); return ast; case AST_DEFAULT_STMT: MACRO_COPY_AST(ast->case_stmt.body); @@ -3039,7 +3047,7 @@ static Ast *ast_copy_from_macro(Context *context, Ast *source) MACRO_COPY_AST(ast->defer_stmt.body); return ast; case AST_DO_STMT: - ast->do_stmt.label = decl_copy_label_from_macro(context, ast->do_stmt.label, ast); + copy_flow(context, ast); MACRO_COPY_AST(ast->do_stmt.body); MACRO_COPY_EXPR(ast->do_stmt.expr); return ast; @@ -3047,14 +3055,14 @@ static Ast *ast_copy_from_macro(Context *context, Ast *source) MACRO_COPY_EXPR(ast->expr_stmt); return ast; case AST_FOR_STMT: - ast->for_stmt.label = decl_copy_label_from_macro(context, ast->for_stmt.label, ast); + copy_flow(context, ast); MACRO_COPY_EXPR(ast->for_stmt.cond); MACRO_COPY_EXPR(ast->for_stmt.incr); MACRO_COPY_AST(ast->for_stmt.body); MACRO_COPY_EXPR(ast->for_stmt.init); return ast; case AST_IF_STMT: - ast->if_stmt.label = decl_copy_label_from_macro(context, ast->if_stmt.label, ast); + copy_flow(context, ast); MACRO_COPY_EXPR(ast->if_stmt.cond); MACRO_COPY_AST(ast->if_stmt.else_body); MACRO_COPY_AST(ast->if_stmt.then_body); @@ -3067,7 +3075,7 @@ static Ast *ast_copy_from_macro(Context *context, Ast *source) TODO return ast; case AST_SWITCH_STMT: - ast->switch_stmt.label = decl_copy_label_from_macro(context, ast->switch_stmt.label, ast); + copy_flow(context, ast); MACRO_COPY_EXPR(ast->switch_stmt.cond); MACRO_COPY_AST_LIST(ast->switch_stmt.cases); return ast; @@ -3078,7 +3086,7 @@ static Ast *ast_copy_from_macro(Context *context, Ast *source) TODO return ast; case AST_WHILE_STMT: - ast->while_stmt.label = decl_copy_label_from_macro(context, ast->for_stmt.label, ast); + copy_flow(context, ast); MACRO_COPY_EXPR(ast->while_stmt.cond); MACRO_COPY_AST(ast->while_stmt.body); return ast; @@ -3090,23 +3098,6 @@ static Ast *ast_copy_from_macro(Context *context, Ast *source) } -static inline bool sema_expr_analyse_macro_call2(Context *context, Type *to, Expr *expr, Decl *macro) -{ - Ast *macro_parent; - // TODO handle loops - Decl *stored_macro = context->evaluating_macro; - Type *stored_rtype = context->rtype; - context->evaluating_macro = macro; - context->rtype = macro->macro_decl.rtype->type; - // Handle escaping macro - bool success = sema_analyse_statement(context, macro->macro_decl.body); - context->evaluating_macro = stored_macro; - context->rtype = stored_rtype; - if (!success) return false; - - TODO - return success; -} static inline bool sema_expr_analyse_macro_ident(Context *context, Type *to, Expr *expr) { @@ -3160,15 +3151,12 @@ static inline bool sema_expr_analyse_expr_block(Context *context, Type *to, Expr } } - if (!vec_size(context->returns)) + if (!context->current_scope->jump_end && to) { - if (to) - { - SEMA_ERROR(expr, "Expected at least one return out of expression block to return a value of type %s.", type_to_error_string(to)); - success = false; - } - goto EXIT; + SEMA_ERROR(expr, "Expected the block to return with a value of type %s.", type_to_error_string(to)); + success = false; } + if (!vec_size(context->returns)) goto EXIT; Expr *first_return_expr = context->returns[0]->return_stmt.expr; Type *left_canonical = first_return_expr ? first_return_expr->type->canonical : type_void; @@ -3224,7 +3212,7 @@ static inline bool sema_expr_analyse_failable(Context *context, Type *to, Expr * SEMA_ERROR(inner, "It looks like you added one too many '!' after the error."); return false; } - if (type->type_kind != TYPE_ERRTYPE) + if (type->type_kind != TYPE_ERRTYPE && type->type_kind != TYPE_ERR_UNION) { SEMA_ERROR(inner, "You cannot use the '!' operator on expressions of type '%s'", type_to_error_string(type)); return false; @@ -3328,7 +3316,7 @@ bool sema_analyse_expr_of_required_type(Context *context, Type *to, Expr *expr, SEMA_ERROR(expr, "'%s!' cannot be implicitly cast to '%s'.", type_to_error_string(expr->type), type_to_error_string(to)); return false; } - return cast_implicit(expr, to); + return cast_implicit(context, expr, to); } bool sema_analyse_expr(Context *context, Type *to, Expr *expr) @@ -3359,7 +3347,7 @@ bool sema_analyse_expr(Context *context, Type *to, Expr *expr) return false; } } - return to ? cast(expr, to, CAST_TYPE_OPTIONAL_IMPLICIT) : true; + return to ? cast(context, expr, to, CAST_TYPE_OPTIONAL_IMPLICIT) : true; } bool sema_analyse_expr_may_be_function(Context *context, Expr *expr) diff --git a/src/compiler/sema_internal.h b/src/compiler/sema_internal.h index 7cbe18b2d..be0e43d4a 100644 --- a/src/compiler/sema_internal.h +++ b/src/compiler/sema_internal.h @@ -11,7 +11,7 @@ int sema_check_comp_time_bool(Context *context, Expr *expr); bool sema_analyse_function_body(Context *context, Decl *func); void context_pop_scope(Context *context); void context_push_scope_with_flags(Context *context, ScopeFlags flags); -#define PUSH_X(ast, X) Ast *_old_##X##_defer = context->X##_defer; Ast *_old_##X = context->X##_target; context->X##_target = ast; context->X##_defer = context->current_scope->defers.start +#define PUSH_X(ast, X) AstId _old_##X##_defer = context->X##_defer; AstId _old_##X = context->X##_target; context->X##_target = astid(ast); context->X##_defer = context->current_scope->defers.start #define POP_X(X) context->X##_target = _old_##X; context->X##_defer = _old_##X##_defer #define PUSH_CONTINUE(ast) PUSH_X(ast, continue) #define POP_CONTINUE() POP_X(continue) @@ -21,10 +21,3 @@ void context_push_scope_with_flags(Context *context, ScopeFlags flags); #define POP_NEXT() POP_X(next); context->next_switch = _old_next_switch #define PUSH_BREAKCONT(ast) PUSH_CONTINUE(ast); PUSH_BREAK(ast) #define POP_BREAKCONT() POP_CONTINUE(); POP_BREAK() - -#define PUSH_FAILABLES() \ - unsigned _prev_failables = context->failables_found; \ - context->failables_found = 0; - -#define POP_FAILABLES() \ - ({ unsigned _failables = context->failables_found; context->failables_found = _prev_failables; _failables; }) diff --git a/src/compiler/sema_name_resolution.c b/src/compiler/sema_name_resolution.c index f6a86842f..75d263f85 100644 --- a/src/compiler/sema_name_resolution.c +++ b/src/compiler/sema_name_resolution.c @@ -36,7 +36,7 @@ static Decl *sema_resolve_path_symbol(Context *context, const char *symbol, Path { Decl *import = context->imports[i]; // Partial imports - if (import->import.symbol.string && import->import.symbol.string != symbol) continue; + if (TOKVALID(import->import.symbol) && TOKSTR(import->import.symbol) != symbol) continue; // Full import, first match the subpath. if (path->len > import->import.path->len) continue; if (!matches_subpath(import->import.path, path)) continue; diff --git a/src/compiler/sema_stmts.c b/src/compiler/sema_stmts.c index fd66afe26..513226cca 100644 --- a/src/compiler/sema_stmts.c +++ b/src/compiler/sema_stmts.c @@ -15,14 +15,15 @@ void context_push_scope_with_flags(Context *context, ScopeFlags flags) } ScopeFlags previous_flags = context->current_scope->flags; Ast *previous_defer = context->current_scope->current_defer; - Ast *parent_defer = context->current_scope->defers.start; + AstId parent_defer = context->current_scope->defers.start; context->current_scope++; context->current_scope->scope_id = ++context->scope_id; + context->current_scope->allow_dead_code = false; + context->current_scope->jump_end = false; if (context->scope_id == 0) { FATAL_ERROR("Too many scopes."); } - context->current_scope->exit = EXIT_NONE; context->current_scope->local_decl_start = context->last_local; context->current_scope->current_defer = previous_defer; context->current_scope->defers.start = parent_defer; @@ -40,12 +41,12 @@ void context_push_scope_with_flags(Context *context, ScopeFlags flags) { context->current_scope->flags = previous_flags | SCOPE_MACRO; } - context->current_scope->flags_created = flags; } void context_push_scope_with_label(Context *context, Decl *label) { context_push_scope_with_flags(context, SCOPE_NONE); + if (label) { label->label.defer = context->current_scope->defers.end; @@ -70,28 +71,19 @@ static inline void context_pop_defers_to(Context *context, DeferList *list) context_pop_defers(context); } -static inline void context_add_exit(Context *context, ExitType exit) -{ - if (!context->current_scope->exit) context->current_scope->exit = exit; -} void context_pop_scope(Context *context) { assert(context->current_scope != &context->scopes[0]); context->last_local = context->current_scope->local_decl_start; - ExitType exit_type = context->current_scope->exit; assert (context->current_scope->defers.end == context->current_scope->defers.start); context->current_scope--; - if (!context->current_scope->exit && exit_type) - { - context->current_scope->exit = exit_type; - } } static Expr *context_pop_defers_and_wrap_expr(Context *context, Expr *expr) { - DeferList defers = { NULL, NULL }; + DeferList defers = { 0, 0 }; context_pop_defers_to(context, &defers); if (defers.end == defers.start) return expr; Expr *wrap = expr_new(EXPR_SCOPED_EXPR, expr->span); @@ -104,12 +96,12 @@ static Expr *context_pop_defers_and_wrap_expr(Context *context, Expr *expr) static void context_pop_defers_and_replace_ast(Context *context, Ast *ast) { - DeferList defers = { NULL, NULL }; + DeferList defers = { 0, 0 }; context_pop_defers_to(context, &defers); if (defers.end == defers.start) return; if (ast->ast_kind == AST_DEFER_STMT) { - assert(defers.start == ast); + assert(defers.start == astid(ast)); *ast = *ast->defer_stmt.body; return; } @@ -122,8 +114,6 @@ static void context_pop_defers_and_replace_ast(Context *context, Ast *ast) #pragma mark --- Helper functions -#define UPDATE_EXIT(exit_type) \ - do { if (!context->current_scope->exit) context->current_scope->exit = exit_type; } while(0) #pragma mark --- Sema analyse stmts @@ -132,7 +122,7 @@ static void context_pop_defers_and_replace_ast(Context *context, Ast *ast) static inline bool sema_analyse_block_return_stmt(Context *context, Ast *statement) { assert(context->current_scope->flags & SCOPE_EXPR_BLOCK); - UPDATE_EXIT(EXIT_RETURN); + context->current_scope->jump_end = true; if (statement->return_stmt.expr) { if (!sema_analyse_expr_of_required_type(context, @@ -151,9 +141,7 @@ static inline bool sema_analyse_return_stmt(Context *context, Ast *statement) { return sema_analyse_block_return_stmt(context, statement); } - - UPDATE_EXIT(EXIT_RETURN); - + context->current_scope->jump_end = true; Type *expected_rtype = context->rtype; Expr *return_expr = statement->return_stmt.expr; statement->return_stmt.defer = context->current_scope->defers.start; @@ -172,7 +160,7 @@ static inline bool sema_analyse_return_stmt(Context *context, Ast *statement) } return true; } - if (expected_rtype == type_void) + if (expected_rtype == type_void && !context->failable_return) { SEMA_ERROR(statement, "You can't return a value from a void function, you need to add a return type."); return false; @@ -243,12 +231,12 @@ static inline bool sema_analyse_cond(Context *context, Expr *expr, bool cast_to_ if (last->expr_stmt->failable) { SEMA_ERROR(last, "'%s!' cannot be converted into '%s'.", - type_to_error_string(last->expr_stmt->type), + type_to_error_string(last->expr_stmt->type), cast_to_bool ? "bool" : type_to_error_string(last->expr_stmt->type)); } if (cast_to_bool) { - if (!cast_implicit(last->expr_stmt, type_bool)) return false; + if (!cast_implicit(context, last->expr_stmt, type_bool)) return false; } return true; case AST_DECLARE_STMT: @@ -263,7 +251,7 @@ static inline bool sema_analyse_cond(Context *context, Expr *expr, bool cast_to_ if (init->failable && !decl->var.unwrap) { SEMA_ERROR(last, "'%s!' cannot be converted into '%s'.", - type_to_error_string(last->expr_stmt->type), + type_to_error_string(last->expr_stmt->type), cast_to_bool ? "bool" : type_to_error_string(init->type)); } if (!decl->var.unwrap && cast_to_bool && init->type->type_kind != TYPE_BOOL && @@ -285,7 +273,7 @@ static inline bool sema_analyse_while_stmt(Context *context, Ast *statement) Ast *body = statement->while_stmt.body; context_push_scope(context); bool success = sema_analyse_cond(context, cond, true); - context_push_scope_with_label(context, statement->while_stmt.label); + context_push_scope_with_label(context, statement->while_stmt.flow.label); PUSH_BREAKCONT(statement); success = success && sema_analyse_statement(context, body); @@ -304,18 +292,29 @@ static inline bool sema_analyse_do_stmt(Context *context, Ast *statement) Expr *expr = statement->do_stmt.expr; Ast *body = statement->do_stmt.body; bool success; - context_push_scope_with_label(context, statement->do_stmt.label); + context_push_scope_with_label(context, statement->do_stmt.flow.label); PUSH_BREAKCONT(statement); success = sema_analyse_statement(context, body); context_pop_defers_and_replace_ast(context, body); POP_BREAKCONT(); + statement->do_stmt.flow.no_exit = context->current_scope->jump_end; context_pop_scope(context); if (!success) return false; if (!statement->do_stmt.expr) return success; + context_push_scope(context); success = sema_analyse_expr_of_required_type(context, type_bool, expr, false); statement->do_stmt.expr = context_pop_defers_and_wrap_expr(context, expr); context_pop_scope(context); + + // while (1) with no break means that we've reached a statement which ends with a jump. + if (statement->do_stmt.expr->expr_kind == EXPR_CONST && statement->do_stmt.expr->const_expr.b) + { + if (statement->do_stmt.flow.no_exit && !statement->do_stmt.flow.has_break) + { + context->current_scope->jump_end = true; + } + } return success; } @@ -367,8 +366,8 @@ static inline bool sema_analyse_defer_stmt(Context *context, Ast *statement) { // TODO special parsing of "catch" context_push_scope_with_flags(context, SCOPE_DEFER); // NOLINT(hicpp-signed-bitwise) - context->current_scope->defers.start = NULL; - context->current_scope->defers.end = NULL; + context->current_scope->defers.start = 0; + context->current_scope->defers.end = 0; context->current_scope->current_defer = statement; PUSH_CONTINUE(statement); @@ -388,7 +387,7 @@ static inline bool sema_analyse_defer_stmt(Context *context, Ast *statement) if (!success) return false; statement->defer_stmt.prev_defer = context->current_scope->defers.start; - context->current_scope->defers.start = statement; + context->current_scope->defers.start = astid(statement); return true; } @@ -399,6 +398,7 @@ static inline bool sema_analyse_for_stmt(Context *context, Ast *statement) // Enter for scope context_push_scope(context); + bool is_infinite = statement->for_stmt.cond == NULL; if (statement->for_stmt.init) { success = sema_analyse_decl_expr_list(context, statement->for_stmt.init); @@ -410,6 +410,12 @@ static inline bool sema_analyse_for_stmt(Context *context, Ast *statement) Expr *cond = statement->for_stmt.cond; success = sema_analyse_expr_of_required_type(context, type_bool, cond, false); statement->for_stmt.cond = context_pop_defers_and_wrap_expr(context, cond); + // If this is const true, then set this to infinte and remove the expression. + if (statement->for_stmt.cond->expr_kind == EXPR_CONST && statement->for_stmt.cond->const_expr.b) + { + statement->for_stmt.cond = NULL; + is_infinite = true; + } // Conditional scope end context_pop_scope(context); } @@ -430,9 +436,10 @@ static inline bool sema_analyse_for_stmt(Context *context, Ast *statement) } // Create the for body scope. - context_push_scope_with_label(context, statement->for_stmt.label); + context_push_scope_with_label(context, statement->for_stmt.flow.label); PUSH_BREAKCONT(statement); success = sema_analyse_statement(context, statement->for_stmt.body); + statement->for_stmt.flow.no_exit = context->current_scope->jump_end; POP_BREAKCONT(); // End for body scope context_pop_defers_and_replace_ast(context, statement->for_stmt.body); @@ -440,6 +447,10 @@ static inline bool sema_analyse_for_stmt(Context *context, Ast *statement) context_pop_defers_and_replace_ast(context, statement); // End for scope context_pop_scope(context); + if (statement->for_stmt.flow.no_exit && is_infinite && !statement->for_stmt.flow.has_break) + { + context->current_scope->jump_end = true; + } return success; } @@ -461,33 +472,42 @@ static inline bool sema_analyse_if_stmt(Context *context, Ast *statement) if (statement->if_stmt.then_body->ast_kind != AST_COMPOUND_STMT) { SEMA_ERROR(statement->if_stmt.then_body, - "if-statements with an 'else' must use '{ }' even around a single statement."); + "if-statements with an 'else' must use '{ }' even around a single statement."); success = false; } if (success && statement->if_stmt.else_body->ast_kind != AST_COMPOUND_STMT) { SEMA_ERROR(statement->if_stmt.else_body, - "An 'else' must use '{ }' even around a single statement."); + "An 'else' must use '{ }' even around a single statement."); success = false; } } - ExitType prev_exit = context->current_scope->exit; - context_push_scope_with_label(context, statement->if_stmt.label); + if (context->current_scope->jump_end && !context->current_scope->allow_dead_code) + { + SEMA_ERROR(statement->if_stmt.then_body, "This code can never be executed."); + success = false; + } + + context_push_scope_with_label(context, statement->if_stmt.flow.label); + success = success && sema_analyse_statement(context, statement->if_stmt.then_body); + bool then_jump = context->current_scope->jump_end; context_pop_scope(context); - ExitType if_exit = context->current_scope->exit; - ExitType else_exit = prev_exit; + bool else_jump = false; if (statement->if_stmt.else_body) { - context_push_scope_with_label(context, statement->if_stmt.label); - context->current_scope->exit = prev_exit; + context_push_scope_with_label(context, statement->if_stmt.flow.label); success = success && sema_analyse_statement(context, statement->if_stmt.else_body); - else_exit = context->current_scope->exit; + else_jump = context->current_scope->jump_end; context_pop_scope(context); } - context->current_scope->exit = else_exit < if_exit ? else_exit : if_exit; context_pop_defers_and_replace_ast(context, statement); context_pop_scope(context); + + if (then_jump && else_jump && !statement->flow.has_break) + { + context->current_scope->jump_end = true; + } return success; } @@ -523,7 +543,7 @@ static inline Decl *sema_analyse_label(Context *context, Ast *stmt) } if (target->decl_kind != DECL_LABEL) { - sema_error_range(stmt->contbreak_stmt.label.span, "Expected the name to match a label, not a constant."); + SEMA_TOKID_ERROR(stmt->contbreak_stmt.label.span, "Expected the name to match a label, not a constant."); return poisoned_decl; } if (context->current_scope->current_defer) @@ -532,7 +552,7 @@ static inline Decl *sema_analyse_label(Context *context, Ast *stmt) if (scope->current_defer != context->current_scope->current_defer) { SEMA_ERROR(stmt, stmt->ast_kind == AST_BREAK_STMT ? "You cannot break out of a defer." : "You cannot use continue out of a defer."); - return false; + return poisoned_decl; } } return target; @@ -549,6 +569,7 @@ static bool context_labels_exist_in_scope(Context *context) static bool sema_analyse_break_stmt(Context *context, Ast *statement) { + context->current_scope->jump_end = true; if (!context->break_target && !statement->contbreak_stmt.label.name) { if (context_labels_exist_in_scope(context)) @@ -562,33 +583,31 @@ static bool sema_analyse_break_stmt(Context *context, Ast *statement) return false; } - UPDATE_EXIT(EXIT_BREAK); - statement->contbreak_stmt.defers.start = context->current_scope->defers.start; - if (statement->contbreak_stmt.label.name) { Decl *target = sema_analyse_label(context, statement); if (!decl_ok(target)) return false; + astptr(target->label.parent)->flow.has_break = true; statement->contbreak_stmt.ast = target->label.parent; statement->contbreak_stmt.defers.end = target->label.defer; return true; } statement->contbreak_stmt.defers.end = context->break_defer; statement->contbreak_stmt.ast = context->break_target; + astptr(context->break_target)->flow.has_break = true; return true; } static bool sema_analyse_next_stmt(Context *context, Ast *statement) { + context->current_scope->jump_end = true; if (!context->next_target && !statement->next_stmt.label.name) { SEMA_ERROR(statement, "'next' is not allowed here."); return false; } - UPDATE_EXIT(EXIT_NEXT); - Ast *parent = context->next_switch; if (statement->next_stmt.label.name) @@ -602,27 +621,28 @@ static bool sema_analyse_next_stmt(Context *context, Ast *statement) } if (target->decl_kind != DECL_LABEL) { - sema_error_range(statement->next_stmt.label.span, "Expected the name to match a label, not a constant."); + SEMA_TOKID_ERROR(statement->next_stmt.label.span, "Expected the name to match a label, not a constant."); return false; } - if (target->label.parent->ast_kind != AST_SWITCH_STMT && target->label.parent->ast_kind != AST_CATCH_STMT) + parent = astptr(target->label.parent); + AstKind kind = parent->ast_kind; + if (kind != AST_SWITCH_STMT && kind != AST_CATCH_STMT) { - sema_error_range(statement->next_stmt.label.span, "Expected the label to match a 'switch' or 'catch' statement."); + SEMA_TOKID_ERROR(statement->next_stmt.label.span, "Expected the label to match a 'switch' or 'catch' statement."); return false; } - parent = target->label.parent; bool defer_mismatch = false; if (parent->ast_kind == AST_SWITCH_STMT) { - defer_mismatch = context->current_scope->current_defer != parent->switch_stmt.defer; + defer_mismatch = context->current_scope->current_defer != context_find_scope_by_id(context, parent->switch_stmt.scope_id)->current_defer; } else { - defer_mismatch = context->current_scope->current_defer != parent->catch_stmt.defer; + defer_mismatch = context->current_scope->current_defer != context_find_scope_by_id(context, parent->catch_stmt.scope_id)->current_defer; } if (defer_mismatch) { - SEMA_ERROR(statement, "This 'next' would jump out of a defer which isn't possible."); + SEMA_ERROR(statement, "This 'next' would jump out of a defer which is not allowed."); return false; } assert(statement->next_stmt.target); @@ -630,7 +650,7 @@ static bool sema_analyse_next_stmt(Context *context, Ast *statement) statement->next_stmt.defers.start = context->current_scope->defers.start; statement->next_stmt.defers.end = parent->switch_stmt.defer; - + // Plain next. if (!statement->next_stmt.target) { if (!context->next_target) @@ -674,13 +694,13 @@ static bool sema_analyse_next_stmt(Context *context, Ast *statement) } if (case_stmt->case_stmt.type_info->type->canonical == statement->next_stmt.type_info->type->canonical) { - statement->next_stmt.case_switch_stmt = case_stmt; + statement->next_stmt.case_switch_stmt = astid(case_stmt); return true; } } if (default_stmt) { - statement->next_stmt.case_switch_stmt = default_stmt; + statement->next_stmt.case_switch_stmt = astid(default_stmt); return true; } SEMA_ERROR(statement->next_stmt.type_info, "There is no case for type '%s'.", type_to_error_string(statement->next_stmt.type_info->type)); @@ -695,7 +715,7 @@ static bool sema_analyse_next_stmt(Context *context, Ast *statement) if (!sema_analyse_expr(context, parent->switch_stmt.cond->type, target)) return false; - if (!cast_implicit(target, parent->switch_stmt.cond->type)) return false; + if (!cast_implicit(context, target, parent->switch_stmt.cond->type)) return false; if (target->expr_kind == EXPR_CONST) { @@ -711,48 +731,47 @@ static bool sema_analyse_next_stmt(Context *context, Ast *statement) } if (expr_const_compare(&target->const_expr, &case_stmt->case_stmt.expr->const_expr, BINARYOP_EQ)) { - statement->next_stmt.case_switch_stmt = case_stmt; + statement->next_stmt.case_switch_stmt = astid(case_stmt); return true; } } if (default_stmt) { - statement->next_stmt.case_switch_stmt = default_stmt; + statement->next_stmt.case_switch_stmt = astid(default_stmt); return true; } SEMA_ERROR(statement, "The 'next' needs to jump to an exact case statement."); return false; } - statement->next_stmt.case_switch_stmt = parent; + statement->next_stmt.case_switch_stmt = astid(parent); statement->next_stmt.switch_expr = target; return true; } static bool sema_analyse_continue_stmt(Context *context, Ast *statement) { + context->current_scope->jump_end = true; + statement->contbreak_stmt.defers.start = context->current_scope->defers.start; - if (!context->break_target && !statement->contbreak_stmt.label.name) + if (!context->continue_target && !statement->contbreak_stmt.label.name) { SEMA_ERROR(statement, "'continue' is not allowed here."); return false; } - UPDATE_EXIT(EXIT_CONTINUE); - - statement->contbreak_stmt.defers.start = context->current_scope->defers.start; - if (statement->contbreak_stmt.label.name) { Decl *target = sema_analyse_label(context, statement); if (!decl_ok(target)) return false; - switch (target->label.parent->ast_kind) + Ast *parent = astptr(target->label.parent); + switch (parent->ast_kind) { case AST_FOR_STMT: case AST_WHILE_STMT: break; case AST_DO_STMT: - if (target->label.parent->do_stmt.expr) break; + if (parent->do_stmt.expr) break; FALLTHROUGH; default: SEMA_ERROR(statement, "'continue' may only be used with 'for', 'while' and 'do-while' statements."); @@ -763,7 +782,7 @@ static bool sema_analyse_continue_stmt(Context *context, Ast *statement) return true; } statement->contbreak_stmt.defers.end = context->continue_defer; - statement->contbreak_stmt.ast = context->break_target; + statement->contbreak_stmt.ast = context->continue_target; return true; } @@ -841,10 +860,10 @@ static bool sema_analyse_case_expr(Context *context, Type* to_type, Ast *case_st // in the case. In that case we do an implicit conversion. if (to_type_canonical->type_kind == TYPE_ENUM && type_is_any_integer(case_expr->type)) { - return cast(case_expr, to_type, CAST_TYPE_EXPLICIT); + return cast(context, case_expr, to_type, CAST_TYPE_EXPLICIT); } - return cast_implicit(case_expr, to_type); + return cast_implicit(context, case_expr, to_type); } @@ -932,9 +951,8 @@ static inline bool sema_check_value_case(Context *context, Type *switch_type, As return true; } -static bool sema_analyse_switch_body(Context *context, Ast *statement, SourceRange expr_span, Type *switch_type, Ast **cases) +static bool sema_analyse_switch_body(Context *context, Ast *statement, SourceSpan expr_span, Type *switch_type, Ast **cases) { - // TODO switch next/break labels bool use_type_id = false; switch (switch_type->type_kind) { @@ -949,20 +967,17 @@ static bool sema_analyse_switch_body(Context *context, Ast *statement, SourceRan case TYPE_STRING: break; default: - sema_error_range(expr_span, "It is not possible to switch over '%s'.", type_to_error_string(switch_type)); + sema_error_range3(expr_span, "It is not possible to switch over '%s'.", type_to_error_string(switch_type)); return false; } Ast *default_case = NULL; assert(context->current_scope->defers.start == context->current_scope->defers.end); - ExitType prev_exit = context->current_scope->exit; bool exhaustive = false; - ExitType lowest_exit = EXIT_NONE; unsigned case_count = vec_size(cases); bool success = true; for (unsigned i = 0; i < case_count; i++) { - context->current_scope->exit = prev_exit; Ast *stmt = cases[i]; switch (stmt->ast_kind) { @@ -998,45 +1013,31 @@ static bool sema_analyse_switch_body(Context *context, Ast *statement, SourceRan UNREACHABLE; } } + + bool all_jump_end = exhaustive; for (unsigned i = 0; i < case_count; i++) { - context->current_scope->exit = prev_exit; Ast *stmt = cases[i]; context_push_scope(context); PUSH_BREAK(statement); Ast *next = (i < case_count - 1) ? cases[i + 1] : NULL; PUSH_NEXT(next, statement); - success = success && (!stmt->case_stmt.body || sema_analyse_compound_statement_no_scope(context, stmt->case_stmt.body)); - ExitType case_exit = context->current_scope->exit; - if (case_exit != lowest_exit) - { - switch (case_exit) - { - case EXIT_NONE: - case EXIT_BREAK: - lowest_exit = EXIT_BREAK; - break; - case EXIT_NEXT: - // We ignore this completely - break; - default: - if (!lowest_exit || lowest_exit > case_exit) lowest_exit = case_exit; - break; - } - } + Ast *body = stmt->case_stmt.body; + success = success && (!body || sema_analyse_compound_statement_no_scope(context, body)); POP_BREAK(); POP_NEXT(); + bool x = + all_jump_end &= (!body | context->current_scope->jump_end); context_pop_scope(context); } - if (lowest_exit <= EXIT_BREAK) lowest_exit = prev_exit; - // Check exhaustive use. - context->current_scope->exit = exhaustive ? lowest_exit : EXIT_NONE; + statement->flow.no_exit = all_jump_end; if (!success) return false; return success; } static bool sema_analyse_switch_stmt(Context *context, Ast *statement) { - context_push_scope_with_label(context, statement->switch_stmt.label); + statement->switch_stmt.scope_id = context->current_scope->scope_id; + context_push_scope_with_label(context, statement->switch_stmt.flow.label); Expr *cond = statement->switch_stmt.cond; if (!sema_analyse_cond(context, cond, false)) return false; @@ -1047,8 +1048,11 @@ static bool sema_analyse_switch_stmt(Context *context, Ast *statement) switch_type->canonical, statement->switch_stmt.cases); if (success) context_pop_defers_and_replace_ast(context, statement); - context_pop_scope(context); + if (statement->flow.no_exit && !statement->flow.has_break) + { + context->current_scope->jump_end = true; + } return success; } @@ -1063,9 +1067,9 @@ static bool sema_analyse_catch_stmt(Context *context, Ast *statement) Expr *error_expr = catch_expr; Decl *unwrapped = NULL; - context_push_scope_with_label(context, statement->catch_stmt.label); + statement->catch_stmt.scope_id = context->current_scope->scope_id; + context_push_scope_with_label(context, statement->catch_stmt.flow.label); - Expr *maybe_unwrapped = NULL; statement->catch_stmt.defer = context->current_scope->defers.start; if (catch_expr->expr_kind == EXPR_BINARY && catch_expr->binary_expr.operator == BINARYOP_ASSIGN) { @@ -1079,10 +1083,7 @@ static bool sema_analyse_catch_stmt(Context *context, Ast *statement) &ambiguous_decl); if (!error_var_decl) { - - error_var = decl_new_var((Token) { .span = left->span, .string = left->identifier_expr.identifier }, - type_info_new_base(type_error, left->span), - VARDECL_LOCAL, + error_var = decl_new_var(left->span.loc, type_info_new_base(type_error, left->span), VARDECL_LOCAL, VISIBLE_LOCAL); error_var->type = type_error; Expr *right = catch_expr->binary_expr.right; @@ -1106,10 +1107,13 @@ static bool sema_analyse_catch_stmt(Context *context, Ast *statement) { const char *error_type = type_to_error_string(error_expr->type); if (error_expr->expr_kind == EXPR_IDENTIFIER - && error_expr->identifier_expr.decl->decl_kind == DECL_VAR - && error_expr->identifier_expr.decl->var.kind == VARDECL_ALIAS) + && error_expr->identifier_expr.decl->decl_kind == DECL_VAR + && error_expr->identifier_expr.decl->var.kind == VARDECL_ALIAS) { - SEMA_ERROR(error_expr, "'%s' is unwrapped to '%s' here, so it cannot be caught.", error_expr->identifier_expr.decl->name, error_type); + SEMA_ERROR(error_expr, + "'%s' is unwrapped to '%s' here, so it cannot be caught.", + error_expr->identifier_expr.decl->name, + error_type); success = false; goto EXIT; } @@ -1130,24 +1134,23 @@ static bool sema_analyse_catch_stmt(Context *context, Ast *statement) if (statement->catch_stmt.is_switch) { - success = sema_analyse_switch_body(context, statement, error_expr->span, type_error, statement->catch_stmt.cases); + success = sema_analyse_switch_body(context, + statement, + error_expr->span, + type_error, + statement->catch_stmt.cases); } else { success = sema_analyse_statement(context, statement->catch_stmt.body); + if (context->current_scope->jump_end) statement->flow.no_exit = true; } - bool was_exit = context->current_scope->exit == EXIT_RETURN; if (success) context_pop_defers_and_replace_ast(context, statement); context_pop_scope(context); - - if (error_var) - { - } - EXIT: if (success) { - if (unwrapped && was_exit) + if (unwrapped && !statement->flow.has_break && statement->flow.no_exit) { Decl *decl = COPY(unwrapped); decl->var.kind = VARDECL_ALIAS; @@ -1216,17 +1219,27 @@ static bool sema_analyse_compound_stmt(Context *context, Ast *statement) { context_push_scope(context); bool success = sema_analyse_compound_statement_no_scope(context, statement); + bool ends_with_jump = context->current_scope->jump_end; context_pop_scope(context); + context->current_scope->jump_end = ends_with_jump; return success; } - static inline bool sema_analyse_statement_inner(Context *context, Ast *statement) { + if (statement->ast_kind == AST_POISONED) + { + return false; + } + if (context->current_scope->jump_end && !context->current_scope->allow_dead_code) + { + //SEMA_ERROR(statement, "This code will never execute."); + context->current_scope->allow_dead_code = true; + //return false; + } switch (statement->ast_kind) { case AST_POISONED: - return false; case AST_SCOPED_STMT: UNREACHABLE case AST_DEFINE_STMT: @@ -1317,10 +1330,10 @@ bool sema_analyse_function_body(Context *context, Decl *func) context->in_macro = 0; context->macro_counter = 0; context->macro_nesting = 0; - context->continue_target = NULL; - context->next_target = NULL; - context->next_switch = NULL; - context->break_target = NULL; + context->continue_target = 0; + context->next_target = 0; + context->next_switch = 0; + context->break_target = 0; func->func.annotations = CALLOCS(FuncAnnotations); context_push_scope(context); Decl **params = signature->params; @@ -1331,7 +1344,7 @@ bool sema_analyse_function_body(Context *context, Decl *func) } if (!sema_analyse_compound_statement_no_scope(context, func->func.body)) return false; assert(context->current_scope == &context->scopes[1]); - if (context->current_scope->exit != EXIT_RETURN) + if (!context->current_scope->jump_end) { Type *canonical_rtype = signature->rtype->type->canonical; if (canonical_rtype != type_void) diff --git a/src/compiler/sema_types.c b/src/compiler/sema_types.c index 525cd9901..8e7842e61 100644 --- a/src/compiler/sema_types.c +++ b/src/compiler/sema_types.c @@ -60,12 +60,12 @@ static bool sema_resolve_type_identifier(Context *context, TypeInfo *type_info) { Decl *ambiguous_decl; Decl *decl = sema_resolve_symbol(context, - type_info->unresolved.name_loc.string, + TOKSTR(type_info->unresolved.name_loc), type_info->unresolved.path, &ambiguous_decl); if (!decl) { - SEMA_TOKEN_ERROR(type_info->unresolved.name_loc, "Unknown type '%s'.", type_info->unresolved.name_loc.string); + SEMA_TOKID_ERROR(type_info->unresolved.name_loc, "Unknown type '%s'.", TOKSTR(type_info->unresolved.name_loc)); return type_info_poison(type_info); } @@ -78,9 +78,9 @@ static bool sema_resolve_type_identifier(Context *context, TypeInfo *type_info) if (ambiguous_decl) { - SEMA_TOKEN_ERROR(type_info->unresolved.name_loc, + SEMA_TOKID_ERROR(type_info->unresolved.name_loc, "Ambiguous type '%s' – both defined in %s and %s, please add the module name to resolve the ambiguity", - type_info->unresolved.name_loc.string, + TOKSTR(type_info->unresolved.name_loc), decl->module->name->module, ambiguous_decl->module->name->module); return type_info_poison(type_info); @@ -98,7 +98,7 @@ static bool sema_resolve_type_identifier(Context *context, TypeInfo *type_info) } type_info->type = decl->type; type_info->resolve_status = RESOLVE_DONE; - DEBUG_LOG("Resolved %s.", type_info->unresolved.name_loc.string); + DEBUG_LOG("Resolved %s.", TOKSTR(type_info->unresolved.name_loc)); return true; case DECL_POISONED: return type_info_poison(type_info); @@ -110,7 +110,7 @@ static bool sema_resolve_type_identifier(Context *context, TypeInfo *type_info) case DECL_MACRO: case DECL_GENERIC: case DECL_LABEL: - SEMA_TOKEN_ERROR(type_info->unresolved.name_loc, "This is not a type."); + SEMA_TOKID_ERROR(type_info->unresolved.name_loc, "This is not a type."); return type_info_poison(type_info); case DECL_CT_ELSE: case DECL_CT_IF: @@ -130,9 +130,9 @@ bool sema_resolve_type_shallow(Context *context, TypeInfo *type_info) if (type_info->resolve_status == RESOLVE_RUNNING) { // TODO this is incorrect for unresolved expressions - SEMA_TOKEN_ERROR(type_info->unresolved.name_loc, + SEMA_TOKID_ERROR(type_info->unresolved.name_loc, "Circular dependency resolving type '%s'.", - type_info->unresolved.name_loc.string); + TOKSTR(type_info->unresolved.name_loc)); return type_info_poison(type_info); } diff --git a/src/compiler/semantic_analyser.c b/src/compiler/semantic_analyser.c index cb77be662..22ad99b7b 100644 --- a/src/compiler/semantic_analyser.c +++ b/src/compiler/semantic_analyser.c @@ -10,7 +10,6 @@ void sema_shadow_error(Decl *decl, Decl *old) SEMA_PREV(old, "The previous use of '%s' was here.", decl->name); } - bool sema_resolve_type_info(Context *context, TypeInfo *type_info) { if (!sema_resolve_type_shallow(context, type_info)) return false; diff --git a/src/compiler/source_file.c b/src/compiler/source_file.c index 3c813c9a5..427ed1ffa 100644 --- a/src/compiler/source_file.c +++ b/src/compiler/source_file.c @@ -67,20 +67,6 @@ void source_file_append_line_end(File *file, SourceLoc loc) vec_add(file->lines, file->current_line_start); } -SourceRange source_range_from_ranges(SourceRange first, SourceRange last) -{ - return (SourceRange) { - .loc = first.loc, - .end_loc = last.end_loc - }; -} - -SourcePosition source_file_find_position(SourceLoc loc) -{ - File *file = source_file_from_position(loc); - return source_file_find_position_in_file(file, loc); -} - SourcePosition source_file_find_position_in_file(File *file, SourceLoc loc) { assert(file->start_id <= loc); @@ -117,36 +103,4 @@ SourcePosition source_file_find_position_in_file(File *file, SourceLoc loc) } } -File *source_file_from_position(SourceLoc loc) -{ - if (loc == INVALID_LOC) - { - pseudo_file.contents = "---"; - return &pseudo_file; - } - static File *last_file = NULL; - //if (!last_file) last_file = lexer_current_file(); - //if (last_file->start_id <= loc && loc < last_file->end_id) return last_file; - unsigned low = 0; - unsigned high = vec_size(source_files.files) - 1; - //assert(vec_size(source_files.files) > 1); - while (1) - { - // Binary search - unsigned mid = (high + low) / 2; - File *file = source_files.files[mid]; - if (file->start_id > loc) - { - high = mid - 1; - continue; - } - if (file->end_id < loc) - { - low = mid + 1; - continue; - } - return last_file = file; - } -} - diff --git a/src/compiler/symtab.c b/src/compiler/symtab.c index 61af11a82..01645cfec 100644 --- a/src/compiler/symtab.c +++ b/src/compiler/symtab.c @@ -40,6 +40,7 @@ const char *kw_main; const char *kw_sizeof; const char *kw_offsetof; + void symtab_init(uint32_t capacity) { assert (is_power_of_two(capacity) && "Must be a power of two"); diff --git a/src/compiler/types.c b/src/compiler/types.c index 24ff41a16..75574b846 100644 --- a/src/compiler/types.c +++ b/src/compiler/types.c @@ -141,46 +141,6 @@ const char *type_to_error_string(Type *type) UNREACHABLE } -static void type_append_signature_name_user_defined(Decl *decl, char *dst, size_t *offset) -{ - switch (decl->decl_kind) - { - case DECL_FUNC: - { - assert(decl->func.function_signature.mangled_signature); - int len = sprintf(dst + *offset, "func %s", decl->func.function_signature.mangled_signature); - *offset += len; - return; - } - case DECL_POISONED: - case DECL_VAR: - case DECL_ENUM_CONSTANT: - case DECL_TYPEDEF: - case DECL_ARRAY_VALUE: - case DECL_IMPORT: - case DECL_MACRO: - case DECL_GENERIC: - case DECL_CT_IF: - case DECL_CT_ELSE: - case DECL_CT_ELIF: - case DECL_ATTRIBUTE: - case DECL_MEMBER: - case DECL_LABEL: - UNREACHABLE - case DECL_STRUCT: - case DECL_UNION: - case DECL_ENUM: - case DECL_ERR: - { - unsigned len = source_range_len(decl->name_span); - memcpy(dst + *offset, decl->name, len); - *offset += len; - return; - - } - } - UNREACHABLE -} void type_append_signature_name(Type *type, char *dst, size_t *offset) { type = type->canonical; diff --git a/src/compiler_tests/tests.c b/src/compiler_tests/tests.c index f54ff9fdf..da454c55b 100644 --- a/src/compiler_tests/tests.c +++ b/src/compiler_tests/tests.c @@ -31,9 +31,14 @@ static void test_lexer(void) const char* interned = symtab_add(token, len[i], fnv1a(token, len[i]), &lookup); if (lookup != TOKEN_IDENT) { - Token scanned = lexer_scan_ident_test(&lexer, token); - TEST_ASSERT(scanned.type == i, "Mismatch scanning: was '%s', expected '%s' - lookup: %s - interned: %s.", - token_type_to_string(scanned.type), + if (!lexer_scan_ident_test(&lexer, token)) + { + TEST_ASSERT(false, "Failed to scan token %s", token); + } + int index = toktype_arena.allocated; + TokenType type_scanned = (TokenType)(toktypeptr(index - 1))[0]; + TEST_ASSERT(type_scanned == (TokenType)i, "Mismatch scanning: was '%s', expected '%s' - lookup: %s - interned: %s.", + token_type_to_string(type_scanned), token_type_to_string(i), token_type_to_string(lookup), interned); @@ -58,7 +63,7 @@ static void test_lexer(void) { #pragma clang diagnostic push #pragma clang diagnostic ignored "-Wunused-variable" - volatile TokenType t = lexer_scan_ident_test(&lexer, tokens[i]).type; + volatile bool t = lexer_scan_ident_test(&lexer, tokens[i]); #pragma clang diagnostic pop } } @@ -84,7 +89,7 @@ static void test_lexer(void) Token token; while (1) { - token = lexer_scan_token(&lexer); + token = lexer_advance(&lexer); if (token.type == TOKEN_EOF) break; TEST_ASSERT(token.type != TOKEN_INVALID_TOKEN, "Got invalid token"); diff --git a/src/utils/common.h b/src/utils/common.h index 31c18adf8..7dd93912c 100644 --- a/src/utils/common.h +++ b/src/utils/common.h @@ -18,4 +18,12 @@ #define PROJECT_TOML "project.toml" #ifndef __unused #define __unused +#endif + +#if defined( _WIN32 ) || defined( __WIN32__ ) || defined( _WIN64 ) +#define PLATFORM_WINDOWS 1 +#define PLATFORM_POSIX 0 +#else +#define PLATFORM_WINDOWS 0 +#define PLATFORM_POSIX 1 #endif \ No newline at end of file diff --git a/src/utils/malloc.c b/src/utils/malloc.c index 372c53ddc..f361df02b 100644 --- a/src/utils/malloc.c +++ b/src/utils/malloc.c @@ -3,28 +3,19 @@ // a copy of which can be found in the LICENSE file. #include "common.h" +#include "vmem.h" #define KB 1024ul // Use 1MB at a time. #define MB (KB * 1024ul) -#define BUCKET_SIZE MB -#define STARTING_ARENA_BUCKETS 16 -static uint8_t **arena_buckets; -static size_t arena_buckets_used; -static size_t arena_buckets_array_size; -static size_t current_use; -static void *current_arena; static int allocations_done; +static Vmem arena; + void memory_init(void) { - arena_buckets = malloc(STARTING_ARENA_BUCKETS * sizeof(void *)); - arena_buckets_used = 1; - arena_buckets_array_size = STARTING_ARENA_BUCKETS; - arena_buckets[0] = malloc(BUCKET_SIZE); + vmem_init(&arena, 4 * 1024); allocations_done = 0; - current_use = 0; - current_arena = arena_buckets[0]; } // Simple bump allocator with buckets. @@ -32,95 +23,40 @@ void *malloc_arena(size_t mem) { assert(mem > 0); // Round to multiple of 16 - size_t oldmem = mem; - mem = (mem + 15u) & ~15ull; - assert(mem >= oldmem); - if (mem >= BUCKET_SIZE / 4) - { - void *ret = malloc(mem); - ASSERT(ret, "Out of memory."); - return malloc(mem); - } - if (current_use + mem > BUCKET_SIZE) - { - if (arena_buckets_used == arena_buckets_array_size) - { - arena_buckets_array_size *= 2; - arena_buckets = realloc(arena_buckets, arena_buckets_array_size * sizeof(void *)); - ASSERT(arena_buckets, "Ran out of memory after allocating %ld KB", BUCKET_SIZE * arena_buckets_used / KB); - } - current_arena = malloc(BUCKET_SIZE); - ASSERT(current_arena, "Ran out of memory after allocating %ld KB", BUCKET_SIZE * arena_buckets_used / KB); - arena_buckets[arena_buckets_used++] = current_arena; - current_use = 0; - } - uint8_t *ptr = current_arena + current_use; - current_use += mem; + mem = (mem + 15U) & ~15ULL; allocations_done++; - if (mem > 4096) - { - // printf("Allocated large chunk %llu\n", (unsigned long long)mem); - } - return (void *)ptr; - + return vmem_alloc(&arena, mem); } void print_arena_status(void) { printf("-- ARENA INFO -- \n"); - printf(" * Memory used: %ld Kb\n", ((arena_buckets_used - 1) * BUCKET_SIZE + current_use) / 1024); - printf(" * Buckets used: %d\n", (int)arena_buckets_used); + printf(" * Memory used: %ld Kb\n", arena.allocated / 1024); printf(" * Allocations: %d\n", allocations_done); } void free_arena(void) { - for (uint32_t i = 0; i < arena_buckets_used; i++) - { - free(arena_buckets[i]); - } - current_arena = NULL; - arena_buckets_used = 0; - arena_buckets = NULL; - arena_buckets_array_size = 0; - current_use = 0; + vmem_free(&arena); } void run_arena_allocator_tests(void) { printf("Begin arena allocator testing.\n"); - bool was_init = arena_buckets != NULL; + bool was_init = arena.ptr != NULL; if (!was_init) memory_init(); free_arena(); memory_init(); ASSERT(malloc_arena(10) != malloc_arena(10), "Expected different values..."); printf("-- Tested basic allocation - OK.\n"); - ASSERT(current_use == 32, "Expected allocations rounded to next 16 bytes"); + ASSERT(arena.allocated == 32, "Expected allocations rounded to next 16 bytes"); malloc_arena(1); - ASSERT(current_use == 48, "Expected allocations rounded to next 16 bytes"); + ASSERT(arena.allocated == 48, "Expected allocations rounded to next 16 bytes"); printf("-- Tested allocation alignment - OK.\n"); - EXPECT("buckets in use", arena_buckets_used, 1); - for (int i = 0; i < 8; i++) - { - ASSERT(malloc_arena(BUCKET_SIZE / 8), "Should be possible to allocate this"); - } - EXPECT("buckets in use", arena_buckets_used, 2); - for (int i = 0; i < 7; i++) - { - ASSERT(malloc_arena(BUCKET_SIZE / 8), "Should be possible to allocate this"); - } - EXPECT("buckets in use", arena_buckets_used, 2); - ASSERT(malloc_arena(BUCKET_SIZE / 8), "Expected alloc to pass"); - EXPECT("buckets in use", arena_buckets_used, 3); - for (size_t i = 0; i < 8 * STARTING_ARENA_BUCKETS; i++) - { - ASSERT(malloc_arena(BUCKET_SIZE / 8), "Should be possible to allocate this"); - } - EXPECT("buckets in use", arena_buckets_used, STARTING_ARENA_BUCKETS + 3); - printf("-- Test switching buckets - OK.\n"); + ASSERT(malloc_arena(1024 * 1024) != NULL, "Expected allocation to work"); free_arena(); - ASSERT(arena_buckets_array_size == 0, "Arena not freed?"); + ASSERT(arena.allocated == 0, "Arena not freed?"); printf("-- Test freeing arena - OK.\n"); if (was_init) memory_init(); } diff --git a/src/utils/malloc.h b/src/utils/malloc.h index 45a718bc3..02f636e7b 100644 --- a/src/utils/malloc.h +++ b/src/utils/malloc.h @@ -4,5 +4,15 @@ // Use of this source code is governed by the GNU LGPLv3.0 license // a copy of which can be found in the LICENSE file. -#include "common.h" +#include "vmem.h" +#define ARENA_DEF(name, type) \ +extern Vmem name##_arena; \ +typedef unsigned type##Id; \ +static inline type *name##_alloc(void) { return (type *)vmem_alloc(&name##_arena, sizeof(type)); } \ +static inline type *name##_calloc(void) { \ + type *ptr = name##_alloc(); \ + memset(ptr, 0, sizeof(type)); \ + return ptr; } \ +static inline type *name##ptr(type ## Id id) { return ((type *)name##_arena.ptr) + id; } \ +static inline type##Id name##id(type *ptr) { return (unsigned) { ptr - ((type *)name##_arena.ptr) }; } diff --git a/src/utils/vmem.c b/src/utils/vmem.c new file mode 100644 index 000000000..076b3a0ba --- /dev/null +++ b/src/utils/vmem.c @@ -0,0 +1,86 @@ +// Copyright (c) 2020 Christoffer Lerno. All rights reserved. +// Use of this source code is governed by a LGPLv3.0 +// a copy of which can be found in the LICENSE file. + +#include "vmem.h" + +#if PLATFORM_POSIX +#include +#endif + +#if PLATFORM_WINDOWS +#include +#define COMMIT_PAGE_SIZE 0x10000 +#endif + + +static inline void mmap_init(Vmem *vmem, size_t size) +{ + vmem->size = size; +#if PLATFORM_WINDOWS + void* ptr = VirtualAlloc(0, size, MEM_RESERVE, PAGE_NOACCESS); + vmem->committed = 0; + if (!ptr) + { + FATAL_ERROR("Failed to map virtual memory block"); + } +#elif PLATFORM_POSIX + void* ptr = mmap(0, size, PROT_READ | PROT_WRITE, MAP_PRIVATE | MAP_ANON | MAP_NORESERVE, -1, 0); + if ((ptr == MAP_FAILED) || !ptr) + { + FATAL_ERROR("Failed to map virtual memory block"); + } +#else + FATAL_ERROR("Unsupported platform."); +#endif + vmem->ptr = ptr; + vmem->allocated = 0; +} + +static inline void* mmap_allocate(Vmem *vmem, size_t to_allocate) +{ + size_t allocated_after = to_allocate + vmem->allocated; +#if PLATFORM_WINDOWS + size_t blocks_committed = vmem->committed / COMMIT_PAGE_SIZE; + size_t end_block = (allocated_after) / COMMIT_PAGE_SIZE; + size_t blocks_to_allocate = end_block - blocks_committed; + if (blocks_to_allocate > 0) + { + size_t to_commit = blocks_to_allocate * COMMIT_PAGE_SIZE; + void *res = VirtualAlloc(vmem->ptr + vmem->committed, to_commit, MEM_COMMIT, PAGE_READWRITE); + if (!res) FATAL_ERROR("Failed to allocate more memory."); + vmem->committed += to_commit; + } +#endif + void *ptr = ((uint8_t *)vmem->ptr) + vmem->allocated; +#ifndef NDEBUG + for (size_t i = vmem->allocated; i < allocated_after; i++) + { + ((uint8_t *)vmem->ptr)[i] = 0xAA; + } +#endif + vmem->allocated = allocated_after; + return ptr; +} + +void vmem_init(Vmem *vmem, size_t size_in_mb) +{ + mmap_init(vmem, 1024 * 1024 * size_in_mb); +} + +void *vmem_alloc(Vmem *vmem, size_t alloc) +{ + return mmap_allocate(vmem, alloc); +} + +void vmem_free(Vmem *vmem) +{ +#if PLATFORM_WINDOWS + VirtualFree(vmem->ptr, 0, MEM_RELEASE); +#elif PLATFORM_POSIX + munmap(vmem->ptr, vmem->size); +#endif + vmem->allocated = 0; + vmem->ptr = 0; + vmem->size = 0; +} \ No newline at end of file diff --git a/src/utils/vmem.h b/src/utils/vmem.h new file mode 100644 index 000000000..be4143932 --- /dev/null +++ b/src/utils/vmem.h @@ -0,0 +1,21 @@ +#pragma once + +// Copyright (c) 2020 Christoffer Lerno. All rights reserved. +// Use of this source code is governed by a LGPLv3.0 +// a copy of which can be found in the LICENSE file. + +#include "common.h" + +typedef struct +{ + void *ptr; + size_t allocated; + size_t size; +#if PLATFORM_WINDOWS + size_t committed; +#endif +} Vmem; + +void vmem_init(Vmem *vmem, size_t size_in_mb); +void *vmem_alloc(Vmem *vmem, size_t alloc); +void vmem_free(Vmem *vmem);