Pre lexing and mmap allocation together with exact exits.

This commit is contained in:
Christoffer Lerno
2020-07-11 12:38:25 +02:00
committed by Christoffer Lerno
parent 3e76ee2643
commit b4c661eaad
37 changed files with 1557 additions and 1358 deletions

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

@@ -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, ...)
{

View File

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

View File

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

View File

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

View File

@@ -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<llvm::DILexicalBlockFile>(Scope)) {
LexicalBlockStack.pop_back();
LexicalBlockStack.emplace_back(DBuilder.createLexicalBlockFile(
LBF->getScope(), getOrCreateFile(CurLoc)));
} else if (isa<llvm::DILexicalBlock>(Scope) ||
isa<llvm::DISubprogram>(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);

View File

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

View File

@@ -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),

View File

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

View File

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

View File

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

View File

@@ -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, &params, 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);
}

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

@@ -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");

View File

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

View File

@@ -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");

View File

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

View File

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

View File

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

86
src/utils/vmem.c Normal file
View File

@@ -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 <sys/mman.h>
#endif
#if PLATFORM_WINDOWS
#include <Windows.h>
#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;
}

21
src/utils/vmem.h Normal file
View File

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