mirror of
https://github.com/c3lang/c3c.git
synced 2026-02-27 12:01:16 +00:00
Pre lexing and mmap allocation together with exact exits.
This commit is contained in:
committed by
Christoffer Lerno
parent
3e76ee2643
commit
b4c661eaad
@@ -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)
|
||||
|
||||
|
||||
@@ -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");
|
||||
}
|
||||
|
||||
}
|
||||
@@ -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);
|
||||
}
|
||||
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -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;
|
||||
}
|
||||
|
||||
|
||||
@@ -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]);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -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, ...)
|
||||
{
|
||||
|
||||
@@ -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,
|
||||
|
||||
|
||||
@@ -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;
|
||||
|
||||
@@ -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,
|
||||
|
||||
@@ -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);
|
||||
|
||||
@@ -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:
|
||||
|
||||
@@ -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),
|
||||
|
||||
@@ -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;
|
||||
}
|
||||
|
||||
@@ -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)
|
||||
|
||||
@@ -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);
|
||||
|
||||
@@ -77,13 +77,11 @@ bool parse_param_list(Context *context, Expr ***result, bool allow_type, TokenTy
|
||||
*result = NULL;
|
||||
while (1)
|
||||
{
|
||||
TypeInfo *type = NULL;
|
||||
Expr *expr = NULL;
|
||||
SourceRange start = context->tok.span;
|
||||
// Special handling of [123]
|
||||
if (context->tok.type == TOKEN_LBRACKET)
|
||||
if (TOKEN_IS(TOKEN_LBRACKET))
|
||||
{
|
||||
expr = expr_new(EXPR_SUBSCRIPT, context->tok.span);
|
||||
expr = EXPR_NEW_TOKEN(EXPR_SUBSCRIPT, context->tok);
|
||||
advance_and_verify(context, TOKEN_LBRACKET);
|
||||
expr->subscript_expr.index = TRY_EXPR_OR(parse_expr(context), false);
|
||||
CONSUME_OR(TOKEN_RBRACKET, false);
|
||||
@@ -99,7 +97,7 @@ bool parse_param_list(Context *context, Expr ***result, bool allow_type, TokenTy
|
||||
{
|
||||
return true;
|
||||
}
|
||||
if (context->tok.type == param_end) return true;
|
||||
if (TOKEN_IS(param_end)) return true;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -112,7 +110,7 @@ static Expr *parse_macro_ident(Context *context, Expr *left)
|
||||
bool had_error = false;
|
||||
macro_ident->identifier_expr.path = parse_path_prefix(context, &had_error);
|
||||
if (had_error) return poisoned_expr;
|
||||
macro_ident->identifier_expr.identifier = context->tok.string;
|
||||
macro_ident->identifier_expr.identifier = TOKSTR(context->tok);
|
||||
CONSUME_OR(TOKEN_IDENT, poisoned_expr);
|
||||
RANGE_EXTEND_PREV(macro_ident);
|
||||
return macro_ident;
|
||||
@@ -239,7 +237,7 @@ static Expr *parse_ternary_expr(Context *context, Expr *left_side)
|
||||
{
|
||||
assert(expr_ok(left_side));
|
||||
|
||||
if (context->tok.type == TOKEN_QUESTION && token_may_end_expression(context->next_tok.type))
|
||||
if (TOKEN_IS(TOKEN_QUESTION) && token_may_end_expression(context->next_tok.type))
|
||||
{
|
||||
return parse_check_failable(context, left_side);
|
||||
}
|
||||
@@ -275,7 +273,7 @@ static Expr *parse_ternary_expr(Context *context, Expr *left_side)
|
||||
static Expr *parse_grouping_expr(Context *context, Expr *left)
|
||||
{
|
||||
assert(!left && "Unexpected left hand side");
|
||||
Expr *expr = expr_new(EXPR_GROUP, context->tok.span);
|
||||
Expr *expr = EXPR_NEW_TOKEN(EXPR_GROUP, context->tok);
|
||||
advance_and_verify(context, TOKEN_LPAREN);
|
||||
expr->group_expr = TRY_EXPR_OR(parse_expr(context), poisoned_expr);
|
||||
CONSUME_OR(TOKEN_RPAREN, poisoned_expr);
|
||||
@@ -294,7 +292,7 @@ static Expr *parse_grouping_expr(Context *context, Expr *left)
|
||||
*/
|
||||
Expr *parse_initializer(Context *context)
|
||||
{
|
||||
if (context->tok.type == TOKEN_LBRACE)
|
||||
if (TOKEN_IS(TOKEN_LBRACE))
|
||||
{
|
||||
return parse_initializer_list(context);
|
||||
}
|
||||
@@ -346,7 +344,7 @@ static Expr *parse_binary(Context *context, Expr *left_side)
|
||||
advance(context);
|
||||
|
||||
Expr *right_side;
|
||||
if (context->tok.type == TOKEN_LBRACE && operator_type == TOKEN_EQ)
|
||||
if (TOKEN_IS(TOKEN_LBRACE) && operator_type == TOKEN_EQ)
|
||||
{
|
||||
right_side = TRY_EXPR_OR(parse_initializer_list(context), poisoned_expr);
|
||||
}
|
||||
@@ -369,7 +367,7 @@ static Expr *parse_call_expr(Context *context, Expr *left)
|
||||
|
||||
Expr **params = NULL;
|
||||
advance_and_verify(context, TOKEN_LPAREN);
|
||||
if (context->tok.type != TOKEN_RPAREN)
|
||||
if (!TOKEN_IS(TOKEN_RPAREN))
|
||||
{
|
||||
if (!parse_param_list(context, ¶ms, 0, TOKEN_RPAREN)) return poisoned_expr;
|
||||
}
|
||||
@@ -404,10 +402,10 @@ static Expr *parse_access_expr(Context *context, Expr *left)
|
||||
advance_and_verify(context, TOKEN_DOT);
|
||||
Expr *access_expr = EXPR_NEW_EXPR(EXPR_ACCESS, left);
|
||||
access_expr->access_expr.parent = left;
|
||||
access_expr->access_expr.sub_element = context->tok;
|
||||
access_expr->access_expr.sub_element = context->tok.id;
|
||||
TRY_CONSUME_OR(TOKEN_IDENT, "Expected identifier", poisoned_expr);
|
||||
access_expr->span = left->span;
|
||||
access_expr->span.end_loc = access_expr->access_expr.sub_element.span.end_loc;
|
||||
access_expr->span.end_loc = access_expr->access_expr.sub_element;
|
||||
return access_expr;
|
||||
}
|
||||
|
||||
@@ -415,7 +413,7 @@ static Expr *parse_access_expr(Context *context, Expr *left)
|
||||
static Expr *parse_identifier_with_path(Context *context, Path *path)
|
||||
{
|
||||
Expr *expr = EXPR_NEW_TOKEN(EXPR_IDENTIFIER, context->tok);
|
||||
expr->identifier_expr.identifier = context->tok.string;
|
||||
expr->identifier_expr.identifier = TOKSTR(context->tok);
|
||||
expr->identifier_expr.path = path;
|
||||
advance(context);
|
||||
return expr;
|
||||
@@ -451,7 +449,7 @@ static Expr *parse_maybe_scope(Context *context, Expr *left)
|
||||
static Expr *parse_try_expr(Context *context, Expr *left)
|
||||
{
|
||||
assert(!left && "Unexpected left hand side");
|
||||
Expr *try_expr = EXPR_NEW_TOKEN(context->tok.type == TOKEN_TRY ? EXPR_TRY : EXPR_CATCH, context->tok);
|
||||
Expr *try_expr = EXPR_NEW_TOKEN(TOKEN_IS(TOKEN_TRY) ? EXPR_TRY : EXPR_CATCH, context->tok);
|
||||
advance(context);
|
||||
CONSUME_OR(TOKEN_LPAREN, poisoned_expr);
|
||||
try_expr->trycatch_expr = TRY_EXPR_OR(parse_expr(context), poisoned_expr);
|
||||
@@ -481,7 +479,7 @@ static Expr *parse_else_expr(Context *context, Expr *left)
|
||||
Ast *ast = TRY_AST_OR(parse_jump_stmt_no_eos(context), poisoned_expr);
|
||||
else_expr->else_expr.is_jump = true;
|
||||
else_expr->else_expr.else_stmt = ast;
|
||||
if (context->tok.type != TOKEN_EOS)
|
||||
if (!TOKEN_IS(TOKEN_EOS))
|
||||
{
|
||||
SEMA_ERROR(ast, "An else jump statement must end with a ';'");
|
||||
return poisoned_expr;
|
||||
@@ -499,8 +497,8 @@ static Expr *parse_integer(Context *context, Expr *left)
|
||||
{
|
||||
assert(!left && "Had left hand side");
|
||||
Expr *expr_int = EXPR_NEW_TOKEN(EXPR_CONST, context->tok);
|
||||
const char *string = context->tok.start;
|
||||
const char *end = string + source_range_len(context->tok.span);
|
||||
const char *string = TOKSTR(context->tok);
|
||||
const char *end = string + TOKLEN(context->tok);
|
||||
if (string[0] == '\'')
|
||||
{
|
||||
union
|
||||
@@ -575,7 +573,7 @@ static Expr *parse_integer(Context *context, Expr *left)
|
||||
BigInt ten;
|
||||
bigint_init_unsigned(&ten, 10);
|
||||
BigInt res;
|
||||
switch (source_range_len(context->tok.span) > 2 ? string[1] : '0')
|
||||
switch (TOKLEN(context->tok) > 2 ? string[1] : '0')
|
||||
{
|
||||
case 'x':
|
||||
string += 2;
|
||||
@@ -643,18 +641,10 @@ static Expr *parse_double(Context *context, Expr *left)
|
||||
{
|
||||
assert(!left && "Had left hand side");
|
||||
Expr *number = EXPR_NEW_TOKEN(EXPR_CONST, context->tok);
|
||||
char *end = NULL;
|
||||
// IMPROVE
|
||||
long double fval = strtold(context->tok.start, &end);
|
||||
if (end != source_range_len(context->tok.span) + context->tok.start)
|
||||
{
|
||||
SEMA_TOKEN_ERROR(context->tok, "Invalid float value");
|
||||
return poisoned_expr;
|
||||
}
|
||||
advance(context);
|
||||
number->const_expr.f = fval;
|
||||
number->const_expr.f = TOKREAL(context->tok.id);
|
||||
number->type = type_compfloat;
|
||||
number->const_expr.kind = TYPE_FXX;
|
||||
advance(context);
|
||||
return number;
|
||||
}
|
||||
|
||||
@@ -760,17 +750,18 @@ static Expr *parse_string_literal(Context *context, Expr *left)
|
||||
char *str = NULL;
|
||||
size_t len = 0;
|
||||
|
||||
while (context->tok.type == TOKEN_STRING)
|
||||
while (TOKEN_IS(TOKEN_STRING))
|
||||
{
|
||||
char *new_string = malloc_arena(len + source_range_len(context->tok.span));
|
||||
char *new_string = malloc_arena(len + TOKLEN(context->tok));
|
||||
if (str) memcpy(new_string, str, len);
|
||||
const char *sourcestr = TOKSTR(context->tok);
|
||||
str = new_string;
|
||||
for (unsigned i = 1; i < source_range_len(context->tok.span) - 1; i++)
|
||||
for (unsigned i = 1; i < TOKLEN(context->tok) - 1; i++)
|
||||
{
|
||||
if (context->tok.string[i] == '\\')
|
||||
if (sourcestr[i] == '\\')
|
||||
{
|
||||
i++;
|
||||
int scanned = append_esc_string_token(str, context->tok.string + i, &len) - 1;
|
||||
int scanned = append_esc_string_token(str, sourcestr + i, &len) - 1;
|
||||
if (scanned < -1)
|
||||
{
|
||||
SEMA_TOKEN_ERROR(context->tok, "Invalid escape in string.");
|
||||
@@ -779,7 +770,7 @@ static Expr *parse_string_literal(Context *context, Expr *left)
|
||||
i += scanned;
|
||||
continue;
|
||||
}
|
||||
str[len++] = context->tok.string[i];
|
||||
str[len++] = sourcestr[i];
|
||||
}
|
||||
advance_and_verify(context, TOKEN_STRING);
|
||||
}
|
||||
@@ -797,7 +788,7 @@ static Expr *parse_bool(Context *context, Expr *left)
|
||||
{
|
||||
assert(!left && "Had left hand side");
|
||||
Expr *number = EXPR_NEW_TOKEN(EXPR_CONST, context->tok);
|
||||
number->const_expr = (ExprConst) { .b = context->tok.type == TOKEN_TRUE, .kind = TYPE_BOOL };
|
||||
number->const_expr = (ExprConst) { .b = TOKEN_IS(TOKEN_TRUE), .kind = TYPE_BOOL };
|
||||
number->type = type_bool;
|
||||
number->resolve_status = RESOLVE_DONE;
|
||||
advance(context);
|
||||
@@ -837,7 +828,7 @@ Expr *parse_type_access_expr_after_type(Context *context, TypeInfo *type_info)
|
||||
}
|
||||
Expr *expr = expr_new(EXPR_TYPE_ACCESS, type_info->span);
|
||||
expr->type_access.type = type_info;
|
||||
expr->type_access.name = context->tok;
|
||||
expr->type_access.name = context->tok.id;
|
||||
advance(context);
|
||||
RANGE_EXTEND_PREV(expr);
|
||||
return parse_precedence_with_left_side(context, expr, PREC_CALL - 1);
|
||||
@@ -855,12 +846,12 @@ Expr *parse_type_access_expr_after_type(Context *context, TypeInfo *type_info)
|
||||
*/
|
||||
Expr *parse_type_expression_with_path(Context *context, Path *path)
|
||||
{
|
||||
TypeInfo *type = type_info_new(TYPE_INFO_IDENTIFIER, path ? path->span : context->tok.span );
|
||||
TypeInfo *type = type_info_new(TYPE_INFO_IDENTIFIER, path ? path->span : source_span_from_token_id(context->tok.id));
|
||||
type->unresolved.path = path;
|
||||
type->unresolved.name_loc = context->tok;
|
||||
type->unresolved.name_loc = context->tok.id;
|
||||
advance_and_verify(context, TOKEN_TYPE_IDENT);
|
||||
RANGE_EXTEND_PREV(type);
|
||||
if (context->tok.type == TOKEN_LBRACE)
|
||||
if (TOKEN_IS(TOKEN_LBRACE))
|
||||
{
|
||||
return parse_type_compound_literal_expr_after_type(context, type);
|
||||
}
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -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))
|
||||
|
||||
@@ -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);
|
||||
|
||||
@@ -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);
|
||||
}
|
||||
|
||||
@@ -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);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -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)
|
||||
|
||||
@@ -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; })
|
||||
|
||||
@@ -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;
|
||||
|
||||
@@ -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)
|
||||
|
||||
@@ -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);
|
||||
}
|
||||
|
||||
|
||||
@@ -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;
|
||||
|
||||
@@ -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;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
|
||||
@@ -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");
|
||||
|
||||
@@ -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;
|
||||
|
||||
@@ -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");
|
||||
|
||||
|
||||
@@ -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
|
||||
@@ -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();
|
||||
}
|
||||
|
||||
@@ -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
86
src/utils/vmem.c
Normal 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
21
src/utils/vmem.h
Normal 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);
|
||||
Reference in New Issue
Block a user