Introduced a Lexer context, comment parsing now actually works properly. Token use in decl/ast/expr is moved to SourceRange instead. And the SourceRange used start/end, which is better than using start + len for many uses.

This commit is contained in:
Christoffer Lerno
2020-01-23 19:38:48 +01:00
parent cdc1bfe267
commit 7b4ed09517
26 changed files with 1848 additions and 1754 deletions

View File

@@ -1,8 +1,8 @@
import curl; import curl;
int main(void) func int main(void)
{ {
try Curl curl = Curl.new(); try Curl curl = curl::newCurl();
catch (error e) catch (error e)
{ {

View File

@@ -2,6 +2,15 @@ module bar;
typedef int as Bob; typedef int as Bob;
/* hello *//* there */
/+ why /+ you /* lucky +/ +/
// Whut
// Here
//
//---
/*
Hello
*/
struct Test struct Test
{ {
@@ -91,6 +100,7 @@ func int test3()
return 5; return 5;
} }
typedef func void() as FEok;
typedef func void(int) as Foo; typedef func void(int) as Foo;
//typedef int as Foo; //typedef int as Foo;
@@ -111,6 +121,16 @@ func void bob()
} }
func int xxxx(int x)
{
{
defer printf("Defer says hello!\n");
LABEL:
x--;
}
if (x > 0) goto LABEL;
return 1;
}
func int main(int x) func int main(int x)
{ {
@@ -189,6 +209,9 @@ JUMP:
func void test2(int* x, int y, int z) func void test2(int* x, int y, int z)
{ {
*(&(&x)[0]);
float cheat = cast(int, x);
x++; x++;
z = 0; z = 0;
z ? y : z; z ? y : z;

View File

@@ -9,7 +9,9 @@ Decl *decl_new(DeclKind decl_kind, Token name, Visibility visibility)
assert(name.string); assert(name.string);
Decl *decl = CALLOCS(Decl); Decl *decl = CALLOCS(Decl);
decl->decl_kind = decl_kind; decl->decl_kind = decl_kind;
decl->name = name; decl->name_span = name.span;
decl->span = name.span;
decl->name = name.string;
decl->visibility = visibility; decl->visibility = visibility;
return decl; return decl;
} }
@@ -22,11 +24,11 @@ void decl_set_external_name(Decl *decl)
{ {
if (decl->visibility == VISIBLE_EXTERN) if (decl->visibility == VISIBLE_EXTERN)
{ {
decl->external_name = decl->name.string; decl->external_name = decl->name;
return; return;
} }
char buffer[1024]; char buffer[1024];
uint32_t len = sprintf(buffer, "%s::%s", decl->module->name->module, decl->name.string); uint32_t len = sprintf(buffer, "%s::%s", decl->module->name->module, decl->name);
assert(len); assert(len);
TokenType type = TOKEN_INVALID_TOKEN; TokenType type = TOKEN_INVALID_TOKEN;
decl->external_name = symtab_add(buffer, len, fnv1a(buffer, len), &type); decl->external_name = symtab_add(buffer, len, fnv1a(buffer, len), &type);
@@ -64,7 +66,6 @@ Decl *decl_new_with_type(Token name, DeclKind decl_type, Visibility visibility)
case DECL_ARRAY_VALUE: case DECL_ARRAY_VALUE:
case DECL_IMPORT: case DECL_IMPORT:
case DECL_MACRO: case DECL_MACRO:
case DECL_MULTI_DECL:
case DECL_GENERIC: case DECL_GENERIC:
case DECL_CT_IF: case DECL_CT_IF:
case DECL_CT_ELSE: case DECL_CT_ELSE:
@@ -113,22 +114,29 @@ Decl *struct_find_name(Decl *decl, const char* name)
VECEACH(compare_members, i) VECEACH(compare_members, i)
{ {
Decl *member = compare_members[i]; Decl *member = compare_members[i];
if (member->name.type == TOKEN_INVALID_TOKEN) if (!member->name)
{ {
Decl *found = struct_find_name(member, name); Decl *found = struct_find_name(member, name);
if (found) return found; if (found) return found;
} }
else if (member->name.string == name) return member; else if (member->name == name) return member;
} }
return NULL; return NULL;
} }
Ast *ast_from_expr(Expr *expr)
{
if (!expr_ok(expr)) return &poisoned_ast;
Ast *ast = AST_NEW(AST_EXPR_STMT, expr->span);
ast->expr_stmt = expr;
return ast;
}
Expr *expr_new(ExprKind kind, Token start) Expr *expr_new(ExprKind kind, SourceRange start)
{ {
Expr *expr = malloc_arena(sizeof(Expr)); Expr *expr = malloc_arena(sizeof(Expr));
expr->expr_kind = kind; expr->expr_kind = kind;
expr->loc = start; expr->span = start;
expr->type = NULL; expr->type = NULL;
return expr; return expr;
} }
@@ -344,21 +352,21 @@ void fprint_type_recursive(FILE *file, Type *type, int indent)
fprintf_indented(file, indent, "(type-func %s)\n", type->func.signature->mangled_signature); fprintf_indented(file, indent, "(type-func %s)\n", type->func.signature->mangled_signature);
return; return;
case TYPE_STRUCT: case TYPE_STRUCT:
fprintf_indented(file, indent, "(struct %s::%s)\n", type->decl->module->name, type->decl->name.string); fprintf_indented(file, indent, "(struct %s::%s)\n", type->decl->module->name, type->decl->name);
return; return;
case TYPE_UNION: case TYPE_UNION:
fprintf_indented(file, indent, "(union %s::%s)\n", type->decl->module->name, type->decl->name.string); fprintf_indented(file, indent, "(union %s::%s)\n", type->decl->module->name, type->decl->name);
return; return;
case TYPE_ENUM: case TYPE_ENUM:
fprintf_indented(file, indent, "(enum %s::%s)\n", type->decl->module->name, type->decl->name.string); fprintf_indented(file, indent, "(enum %s::%s)\n", type->decl->module->name, type->decl->name);
return; return;
case TYPE_ERROR: case TYPE_ERROR:
fprintf_indented(file, indent, "(error %s::%s)\n", type->decl->module->name, type->decl->name.string); fprintf_indented(file, indent, "(error %s::%s)\n", type->decl->module->name, type->decl->name);
return; return;
case TYPE_TYPEDEF: case TYPE_TYPEDEF:
if (type->canonical != type) if (type->canonical != type)
{ {
fprintf_indented(file, indent, "(user-defined %s::%s\n", type->decl->module->name, type->decl->name.string); fprintf_indented(file, indent, "(user-defined %s::%s\n", type->decl->module->name, type->decl->name);
fprint_type_recursive(file, type->canonical, indent + 1); fprint_type_recursive(file, type->canonical, indent + 1);
fprint_endparen(file, indent); fprint_endparen(file, indent);
break; break;
@@ -504,7 +512,7 @@ void fprint_expr_recursive(FILE *file, Expr *expr, int indent)
switch (expr->expr_kind) switch (expr->expr_kind)
{ {
case EXPR_IDENTIFIER: case EXPR_IDENTIFIER:
fprintf_indented(file, indent, "(ident %s\n", expr->identifier_expr.identifier.string); fprintf_indented(file, indent, "(ident %s\n", expr->identifier_expr.identifier);
fprint_expr_common(file, expr, indent + 1); fprint_expr_common(file, expr, indent + 1);
break; break;
case EXPR_CONST: case EXPR_CONST:
@@ -675,13 +683,8 @@ void fprint_decl_recursive(FILE *file, Decl *decl, int indent)
{ {
switch (decl->decl_kind) switch (decl->decl_kind)
{ {
case DECL_MULTI_DECL:
fprintf_indented(file, indent, "(multi-decl\n");
fprint_decl_list(file, decl->multi_decl, indent + 1);
fprint_endparen(file, indent);
break;
case DECL_VAR: case DECL_VAR:
fprintf_indented(file, indent, "(var-%s %s\n", decl_var_to_string(decl->var.kind), decl->name.string ?: ""); fprintf_indented(file, indent, "(var-%s %s\n", decl_var_to_string(decl->var.kind), decl->name ?: "");
fprint_type_info_recursive(file, decl->var.type_info, indent + 1); fprint_type_info_recursive(file, decl->var.type_info, indent + 1);
if (decl->var.init_expr) if (decl->var.init_expr)
{ {
@@ -690,7 +693,7 @@ void fprint_decl_recursive(FILE *file, Decl *decl, int indent)
fprint_endparen(file, indent); fprint_endparen(file, indent);
break; break;
case DECL_MACRO: case DECL_MACRO:
fprintf_indented(file, indent, "(macro %s\n", decl->name.string); fprintf_indented(file, indent, "(macro %s\n", decl->name);
fprint_type_info_recursive(file, decl->macro_decl.rtype, indent + 1); fprint_type_info_recursive(file, decl->macro_decl.rtype, indent + 1);
fprint_indent(file, indent + 1); fprint_indent(file, indent + 1);
fprintf(file, "(params\n"); fprintf(file, "(params\n");
@@ -700,7 +703,7 @@ void fprint_decl_recursive(FILE *file, Decl *decl, int indent)
fprint_endparen(file, indent); fprint_endparen(file, indent);
break; break;
case DECL_FUNC: case DECL_FUNC:
fprintf_indented(file, indent, "(func %s\n", decl->name.string); fprintf_indented(file, indent, "(func %s\n", decl->name);
if (decl->func.type_parent) if (decl->func.type_parent)
{ {
fprint_indent(file, indent + 1); fprint_indent(file, indent + 1);
@@ -714,41 +717,41 @@ void fprint_decl_recursive(FILE *file, Decl *decl, int indent)
fprint_endparen(file, indent); fprint_endparen(file, indent);
break; break;
case DECL_STRUCT: case DECL_STRUCT:
fprintf_indented(file, indent, "(struct %s\n", decl->name.string); fprintf_indented(file, indent, "(struct %s\n", decl->name);
fprint_decl_list(file, decl->strukt.members, indent + 1); fprint_decl_list(file, decl->strukt.members, indent + 1);
fprint_endparen(file, indent); fprint_endparen(file, indent);
break; break;
case DECL_UNION: case DECL_UNION:
fprintf_indented(file, indent, "(union %s\n", decl->name.string); fprintf_indented(file, indent, "(union %s\n", decl->name);
fprint_decl_list(file, decl->strukt.members, indent + 1); fprint_decl_list(file, decl->strukt.members, indent + 1);
fprint_endparen(file, indent); fprint_endparen(file, indent);
break; break;
case DECL_ENUM: case DECL_ENUM:
fprintf_indented(file, indent, "(enum %s\n", decl->name.string); fprintf_indented(file, indent, "(enum %s\n", decl->name);
fprint_type_info_recursive(file, decl->enums.type_info, indent + 1); fprint_type_info_recursive(file, decl->enums.type_info, indent + 1);
fprint_decl_list(file, decl->enums.values, indent + 1); fprint_decl_list(file, decl->enums.values, indent + 1);
fprint_endparen(file, indent); fprint_endparen(file, indent);
break; break;
case DECL_ERROR: case DECL_ERROR:
fprintf_indented(file, indent, "(error %s\n", decl->name.string); fprintf_indented(file, indent, "(error %s\n", decl->name);
fprint_decl_list(file, decl->error.error_constants, indent + 1); fprint_decl_list(file, decl->error.error_constants, indent + 1);
fprint_endparen(file, indent); fprint_endparen(file, indent);
break; break;
case DECL_ENUM_CONSTANT: case DECL_ENUM_CONSTANT:
if (!decl->enum_constant.expr) if (!decl->enum_constant.expr)
{ {
fprintf_indented(file, indent, "(enum-constant %s)\n", decl->name.string); fprintf_indented(file, indent, "(enum-constant %s)\n", decl->name);
return; return;
} }
fprintf_indented(file, indent, "(enum-constant %s\n", decl->name.string); fprintf_indented(file, indent, "(enum-constant %s\n", decl->name);
fprint_expr_recursive(file, decl->enum_constant.expr, indent + 1); fprint_expr_recursive(file, decl->enum_constant.expr, indent + 1);
fprint_endparen(file, indent); fprint_endparen(file, indent);
break; break;
case DECL_ERROR_CONSTANT: case DECL_ERROR_CONSTANT:
fprintf_indented(file, indent, "(error-constant %s)\n", decl->name.string); fprintf_indented(file, indent, "(error-constant %s)\n", decl->name);
break; break;
case DECL_GENERIC: case DECL_GENERIC:
fprintf_indented(file, indent, "(generic %s\n", decl->name.string); fprintf_indented(file, indent, "(generic %s\n", decl->name);
fprint_indent(file, indent + 1); fprint_indent(file, indent + 1);
fprintf(file, "(params\n"); fprintf(file, "(params\n");
{ {
@@ -771,7 +774,7 @@ void fprint_decl_recursive(FILE *file, Decl *decl, int indent)
fprint_endparen(file, indent); fprint_endparen(file, indent);
break; break;
case DECL_TYPEDEF: case DECL_TYPEDEF:
fprintf_indented(file, indent, "(typedef %s\n", decl->name.string); fprintf_indented(file, indent, "(typedef %s\n", decl->name);
if (decl->typedef_decl.is_func) if (decl->typedef_decl.is_func)
{ {
fprint_func_signature(file, &decl->typedef_decl.function_signature, indent + 1); fprint_func_signature(file, &decl->typedef_decl.function_signature, indent + 1);
@@ -816,7 +819,7 @@ void fprint_decl_recursive(FILE *file, Decl *decl, int indent)
fprint_endparen(file, indent); fprint_endparen(file, indent);
return; return;
case DECL_IMPORT: case DECL_IMPORT:
fprintf_indented(file, indent, "(import %s", decl->name.string); fprintf_indented(file, indent, "(import %s", decl->name);
TODO TODO
fprint_endparen(file, indent); fprint_endparen(file, indent);
break; break;
@@ -848,6 +851,18 @@ static void fprint_ast_recursive(FILE *file, Ast *ast, int indent)
fprint_indent(file, indent); fprint_indent(file, indent);
switch (ast->ast_kind) switch (ast->ast_kind)
{ {
case AST_FUNCTION_BLOCK_STMT:
if (!ast->compound_stmt.stmts)
{
fprintf(file, "(function_block)\n");
return;
}
fprintf(file, "(function_block\n");
{
fprint_asts_recursive(file, ast->compound_stmt.stmts, indent + 1);
}
break;
case AST_COMPOUND_STMT: case AST_COMPOUND_STMT:
if (!ast->compound_stmt.stmts) if (!ast->compound_stmt.stmts)
{ {
@@ -931,7 +946,7 @@ static void fprint_ast_recursive(FILE *file, Ast *ast, int indent)
} }
if (ast->for_stmt.incr) if (ast->for_stmt.incr)
{ {
fprint_expr_recursive(file, ast->for_stmt.incr, indent + 1); fprint_ast_recursive(file, ast->for_stmt.incr, indent + 1);
} }
else else
{ {
@@ -1010,10 +1025,10 @@ static void fprint_ast_recursive(FILE *file, Ast *ast, int indent)
TODO TODO
break; break;
case AST_GOTO_STMT: case AST_GOTO_STMT:
fprintf(file, "(goto %s)\n", ast->token.string); fprintf(file, "(goto %s)\n", ast->goto_stmt.label_name);
return; return;
case AST_LABEL: case AST_LABEL:
fprintf(file, "(label %s)\n", ast->token.string); fprintf(file, "(label %s)\n", ast->label_stmt.name);
return; return;
case AST_NOP_STMT: case AST_NOP_STMT:
TODO TODO
@@ -1040,5 +1055,5 @@ void fprint_decl(FILE *file, Decl *dec)
fprint_decl_recursive(file, dec, 0); fprint_decl_recursive(file, dec, 0);
} }
Module poisoned_module = { .name = NULL }; Module poisoned_module = { .name = NULL };
Decl all_error = { .decl_kind = DECL_ERROR, .name = { .type = TOKEN_INVALID_TOKEN, .string = NULL } }; Decl all_error = { .decl_kind = DECL_ERROR, .name = NULL };

View File

@@ -38,7 +38,7 @@ static bool sema_type_mismatch(Expr *expr, Type *type, CastType cast_type)
break; break;
} }
SEMA_ERROR(expr->loc, "Cannot %s '%s' to '%s'", action, type_to_error_string(expr->type), type_to_error_string(type)); SEMA_ERROR(expr, "Cannot %s '%s' to '%s'", action, type_to_error_string(expr->type), type_to_error_string(type));
return false; return false;
} }
@@ -294,7 +294,7 @@ bool sisi(Expr* left, Type *from, Type *canonical, Type *type, CastType cast_typ
{ {
if ((i > int_type_max[index]) || (i < int_type_min[index])) if ((i > int_type_max[index]) || (i < int_type_min[index]))
{ {
SEMA_ERROR(left->loc, "'%lld' does not fit into '%s'", i, canonical->name); SEMA_ERROR(left, "'%lld' does not fit into '%s'", i, canonical->name);
return false; return false;
} }
} }
@@ -383,7 +383,7 @@ bool uisi(Expr* left, Type *from, Type *canonical, Type *type, CastType cast_typ
{ {
if (left->const_expr.i > (uint64_t)int_type_max[index]) if (left->const_expr.i > (uint64_t)int_type_max[index])
{ {
SEMA_ERROR(left->loc, "Cannot implicitly convert value '%llu' into %s - it will not fit.", left->const_expr.i, type_to_error_string(type)); SEMA_ERROR(left, "Cannot implicitly convert value '%llu' into %s - it will not fit.", left->const_expr.i, type_to_error_string(type));
return false; return false;
} }
} }
@@ -413,7 +413,7 @@ bool uiui(Expr* left, Type *from, Type *canonical, Type *type, CastType cast_typ
{ {
if (left->const_expr.i > uint_type_max[index]) if (left->const_expr.i > uint_type_max[index])
{ {
SEMA_ERROR(left->loc, "Cannot implicitly convert value '%llu' into %s - it will not fit.", type_to_error_string(type)); SEMA_ERROR(left, "Cannot implicitly convert value '%llu' into %s - it will not fit.", type_to_error_string(type));
return false; return false;
} }
} }

View File

@@ -20,11 +20,12 @@ static void compiler_lex(BuildTarget *target)
bool loaded = false; bool loaded = false;
File *file = source_file_load(target->sources[i], &loaded); File *file = source_file_load(target->sources[i], &loaded);
if (loaded) continue; if (loaded) continue;
lexer_add_file_for_lexing(file); Lexer lexer;
lexer_add_file_for_lexing(&lexer, file);
printf("# %s\n", file->full_path); printf("# %s\n", file->full_path);
while (1) while (1)
{ {
Token token = lexer_scan_token(); Token token = lexer_scan_token(&lexer);
printf("%s ", token_type_to_string(token.type)); printf("%s ", token_type_to_string(token.type));
if (token.type == TOKEN_EOF) break; if (token.type == TOKEN_EOF) break;
} }
@@ -212,9 +213,9 @@ Module *compiler_find_or_create_module(Path *module_name)
void compiler_register_public_symbol(Decl *decl) void compiler_register_public_symbol(Decl *decl)
{ {
Decl *prev = stable_get(&compiler.global_symbols, decl->name.string); Decl *prev = stable_get(&compiler.global_symbols, decl->name);
// If the previous symbol was already declared globally, remove it. // If the previous symbol was already declared globally, remove it.
stable_set(&compiler.global_symbols, decl->name.string, prev ? &poisoned_decl : decl); stable_set(&compiler.global_symbols, decl->name, prev ? &poisoned_decl : decl);
STable *sub_module_space = stable_get(&compiler.qualified_symbols, decl->module->name->module); STable *sub_module_space = stable_get(&compiler.qualified_symbols, decl->module->name->module);
if (!sub_module_space) if (!sub_module_space)
{ {
@@ -222,6 +223,6 @@ void compiler_register_public_symbol(Decl *decl)
stable_init(sub_module_space, 0x100); stable_init(sub_module_space, 0x100);
stable_set(&compiler.qualified_symbols, decl->module->name->module, sub_module_space); stable_set(&compiler.qualified_symbols, decl->module->name->module, sub_module_space);
} }
prev = stable_get(sub_module_space, decl->name.string); prev = stable_get(sub_module_space, decl->name);
stable_set(sub_module_space, decl->name.string, prev ? &poisoned_decl : decl); stable_set(sub_module_space, decl->name, prev ? &poisoned_decl : decl);
} }

View File

@@ -3,6 +3,7 @@
// Use of this source code is governed by the GNU LGPLv3.0 license // Use of this source code is governed by the GNU LGPLv3.0 license
// a copy of which can be found in the LICENSE file. // a copy of which can be found in the LICENSE file.
#include <histedit.h>
#include "../utils/common.h" #include "../utils/common.h"
#include "../utils/errors.h" #include "../utils/errors.h"
#include "../utils/lib.h" #include "../utils/lib.h"
@@ -17,6 +18,7 @@ typedef uint32_t SourceLoc;
#define MAX_LOCALS 0xFFFF #define MAX_LOCALS 0xFFFF
#define MAX_SCOPE_DEPTH 0xFF #define MAX_SCOPE_DEPTH 0xFF
#define MAX_PATH 1024 #define MAX_PATH 1024
#define MAX_DEFERS 0xFFFF
typedef struct _Ast Ast; typedef struct _Ast Ast;
typedef struct _Decl Decl; typedef struct _Decl Decl;
@@ -24,15 +26,21 @@ typedef struct _TypeInfo TypeInfo;
typedef struct _Expr Expr; typedef struct _Expr Expr;
typedef struct _Module Module; typedef struct _Module Module;
typedef struct _Type Type; typedef struct _Type Type;
typedef uint16_t DeferId;
typedef bool(*CastFunc)(Expr *, Type *, Type *, Type *, CastType cast_type); typedef bool(*CastFunc)(Expr *, Type *, Type *, Type *, CastType cast_type);
typedef struct typedef struct
{ {
SourceLoc loc; SourceLoc loc;
uint32_t length; SourceLoc end_loc;
} SourceRange; } SourceRange;
typedef struct
{
DeferId start;
DeferId end;
} DeferList;
typedef struct typedef struct
{ {
@@ -74,9 +82,8 @@ typedef struct
const char *full_path; const char *full_path;
SourceLoc start_id; SourceLoc start_id;
SourceLoc end_id; SourceLoc end_id;
SourceLoc *line_start; SourceLoc *lines;
SourceLoc current_line_start; SourceLoc current_line_start;
int last_line_found;
} File; } File;
typedef struct typedef struct
@@ -287,7 +294,9 @@ typedef struct
typedef struct _Decl typedef struct _Decl
{ {
Token name; const char *name;
SourceRange name_span;
SourceRange span;
const char *external_name; const char *external_name;
DeclKind decl_kind : 6; DeclKind decl_kind : 6;
Visibility visibility : 2; Visibility visibility : 2;
@@ -326,7 +335,6 @@ typedef struct _Decl
FuncDecl func; FuncDecl func;
AttrDecl attr; AttrDecl attr;
TypedefDecl typedef_decl; TypedefDecl typedef_decl;
Decl** multi_decl;
MacroDecl macro_decl; MacroDecl macro_decl;
GenericDecl generic_decl; GenericDecl generic_decl;
CtIfDecl ct_if_decl; CtIfDecl ct_if_decl;
@@ -428,7 +436,7 @@ typedef struct
typedef struct typedef struct
{ {
Path *path; Path *path;
Token identifier; const char *identifier;
bool is_ref; bool is_ref;
Decl *decl; Decl *decl;
} ExprIdentifier; } ExprIdentifier;
@@ -455,7 +463,7 @@ struct _Expr
{ {
ExprKind expr_kind : 8; ExprKind expr_kind : 8;
ResolveStatus resolve_status : 3; ResolveStatus resolve_status : 3;
Token loc; SourceRange span;
Type *type; Type *type;
union { union {
ExprCast cast_expr; ExprCast cast_expr;
@@ -486,14 +494,15 @@ typedef struct
typedef struct typedef struct
{ {
struct _Ast **stmts; struct _Ast **stmts;
// DeferList defer_list; TODO DeferList defer_list;
} AstCompoundStmt; } AstCompoundStmt;
typedef struct typedef struct
{ {
const char *name;
uint16_t last_goto; uint16_t last_goto;
bool is_used : 1; bool is_used : 1;
struct _Ast *defer; Ast *defer;
struct _Ast *in_defer; struct _Ast *in_defer;
void *backend_value; void *backend_value;
} AstLabelStmt; } AstLabelStmt;
@@ -501,7 +510,7 @@ typedef struct
typedef struct typedef struct
{ {
Expr *expr; // May be NULL Expr *expr; // May be NULL
struct _Ast *defer; Ast *defer;
} AstReturnStmt; } AstReturnStmt;
typedef struct typedef struct
@@ -515,6 +524,8 @@ typedef struct
{ {
Expr *expr; Expr *expr;
Ast *body; Ast *body;
DeferList expr_defer;
DeferList body_defer;
} AstDoStmt; } AstDoStmt;
typedef struct typedef struct
@@ -554,8 +565,9 @@ typedef struct
{ {
Ast *init; Ast *init;
Expr *cond; Expr *cond;
Expr *incr; Ast *incr;
Ast *body; Ast *body;
DeferList cond_defer;
} AstForStmt; } AstForStmt;
@@ -563,8 +575,9 @@ typedef struct
typedef struct typedef struct
{ {
GotoType type : 2; GotoType type : 2;
const char *label_name;
Ast *label; Ast *label;
struct _Ast *defer; Ast *defer;
union union
{ {
struct _Ast *in_defer; struct _Ast *in_defer;
@@ -577,6 +590,7 @@ typedef struct _AstDeferStmt
bool emit_boolean : 1; bool emit_boolean : 1;
struct _Ast *body; // Compound statement struct _Ast *body; // Compound statement
struct _Ast *prev_defer; struct _Ast *prev_defer;
DeferId id;
} AstDeferStmt; } AstDeferStmt;
typedef struct _AstCatchStmt typedef struct _AstCatchStmt
@@ -626,14 +640,14 @@ typedef struct
typedef struct _Ast typedef struct _Ast
{ {
SourceRange span;
AstKind ast_kind : 8; AstKind ast_kind : 8;
ExitType exit : 3; ExitType exit : 3;
Token token;
union union
{ {
AstAttribute attribute; AstAttribute attribute;
AstCompoundStmt compound_stmt; AstCompoundStmt compound_stmt;
AstCompoundStmt function_block_stmt;
Decl *declare_stmt; Decl *declare_stmt;
Expr *expr_stmt; Expr *expr_stmt;
Expr *throw_stmt; Expr *throw_stmt;
@@ -690,11 +704,24 @@ typedef struct _DynamicScope
ScopeFlags flags_created; ScopeFlags flags_created;
unsigned errors; unsigned errors;
Decl **local_decl_start; Decl **local_decl_start;
unsigned defer_start; DeferId defer_top;
DeferId defer_last;
ExitType exit; ExitType exit;
} DynamicScope; } DynamicScope;
typedef struct
{
const char *file_begin;
const char *lexing_start;
const char *current;
uint16_t source_file;
File *current_file;
SourceLoc last_in_range;
Token tok;
Token next_tok;
} Lexer;
typedef struct _Context typedef struct _Context
{ {
BuildTarget *target; BuildTarget *target;
@@ -705,7 +732,6 @@ typedef struct _Context
Decl *specified_imports; Decl *specified_imports;
Module *module; Module *module;
STable local_symbols; STable local_symbols;
Decl **header_declarations;
Decl **enums; Decl **enums;
Decl **error_types; Decl **error_types;
Decl **types; Decl **types;
@@ -718,6 +744,10 @@ typedef struct _Context
Decl **last_local; Decl **last_local;
Ast **labels; Ast **labels;
Ast **gotos; Ast **gotos;
Token *comments;
Token *lead_comment;
Token *trailing_comment;
Token *next_lead_comment;
DynamicScope *current_scope; DynamicScope *current_scope;
Decl *evaluating_macro; Decl *evaluating_macro;
Type *rtype; Type *rtype;
@@ -729,6 +759,18 @@ typedef struct _Context
STable external_symbols; STable external_symbols;
Decl **external_symbol_list; Decl **external_symbol_list;
}; };
STable scratch_table;
Lexer lexer;
SourceLoc prev_tok_end;
Token tok;
Token next_tok;
struct
{
const char *current;
const char *start;
Token tok;
Token next_tok;
} stored;
} Context; } Context;
typedef struct typedef struct
@@ -739,7 +781,6 @@ typedef struct
Type **type; Type **type;
} Compiler; } Compiler;
extern Context *current_context;
extern Compiler compiler; extern Compiler compiler;
extern Ast poisoned_ast; extern Ast poisoned_ast;
extern Decl poisoned_decl; extern Decl poisoned_decl;
@@ -749,8 +790,6 @@ extern TypeInfo poisoned_type_info;
extern Module poisoned_module; extern Module poisoned_module;
extern Diagnostics diagnostics; extern Diagnostics diagnostics;
extern Token next_tok;
extern Token tok;
extern Decl all_error; extern Decl all_error;
extern Type *type_bool, *type_void, *type_string, *type_voidptr; extern Type *type_bool, *type_void, *type_string, *type_voidptr;
@@ -771,20 +810,35 @@ extern Type t_voidstar;
extern const char *main_name; extern const char *main_name;
#define AST_NEW(_kind, _token) new_ast(_kind, _token) #define AST_NEW_TOKEN(_kind, _token) new_ast(_kind, _token.span)
#define AST_NEW(_kind, _loc) new_ast(_kind, _loc)
static inline bool ast_ok(Ast *ast) { return ast == NULL || ast->ast_kind != AST_POISONED; } 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 bool ast_poison(Ast *ast) { ast->ast_kind = AST_POISONED; return false; }
static inline Ast *new_ast(AstKind kind, Token token) Ast *ast_from_expr(Expr *expr);
static inline Ast *new_ast(AstKind kind, SourceRange range)
{ {
Ast *ast = malloc_arena(sizeof(Ast)); Ast *ast = malloc_arena(sizeof(Ast));
memset(ast, 0, sizeof(Ast)); memset(ast, 0, sizeof(Ast));
ast->token = token; ast->span = range;
ast->ast_kind = kind; ast->ast_kind = kind;
ast->exit = EXIT_NONE; ast->exit = EXIT_NONE;
return ast; 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;
return ast;
}
void builtin_setup(); void builtin_setup();
@@ -852,16 +906,12 @@ Module *compiler_find_or_create_module(Path *module_name);
void compiler_register_public_symbol(Decl *decl); void compiler_register_public_symbol(Decl *decl);
Context *context_create(File *file, BuildTarget *target); Context *context_create(File *file, BuildTarget *target);
void context_push(Context *context);
void context_register_global_decl(Context *context, Decl *decl); void context_register_global_decl(Context *context, Decl *decl);
void context_register_external_symbol(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_add_import(Context *context, Path *path, Token symbol, Token alias);
bool context_set_module_from_filename(Context *context); 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, Token *generic_parameters);
void context_print_ast(Context *context, FILE *file); void context_print_ast(Context *context, FILE *file);
Decl *context_find_ident(Context *context, const char *symbol);
void context_add_header_decl(Context *context, Decl *decl);
bool context_add_local(Context *context, Decl *decl);
Decl *decl_new(DeclKind decl_kind, Token name, Visibility visibility); 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_with_type(Token name, DeclKind decl_type, Visibility visibility);
@@ -883,16 +933,16 @@ void diag_reset(void);
void diag_error_range(SourceRange span, const char *message, ...); 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(SourceRange span, const char *message, va_list args);
#define EXPR_NEW_EXPR(_kind, _expr) expr_new(_kind, _expr->loc) #define EXPR_NEW_EXPR(_kind, _expr) expr_new(_kind, _expr->span)
#define EXPR_NEW_TOKEN(_kind, _tok) expr_new(_kind, _tok) #define EXPR_NEW_TOKEN(_kind, _tok) expr_new(_kind, _tok.span)
Expr *expr_new(ExprKind kind, Token start); Expr *expr_new(ExprKind kind, SourceRange start);
static inline bool expr_ok(Expr *expr) { return expr == NULL || expr->expr_kind != EXPR_POISONED; } 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 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) static inline void expr_replace(Expr *expr, Expr *replacement)
{ {
Token loc = expr->loc; SourceRange loc = expr->span;
*expr = *replacement; *expr = *replacement;
expr->loc = loc; expr->span = loc;
} }
void fprint_ast(FILE *file, Ast *ast); void fprint_ast(FILE *file, Ast *ast);
@@ -901,31 +951,13 @@ void fprint_type_info_recursive(FILE *file, TypeInfo *type_info, int indent);
void fprint_expr_recursive(FILE *file, Expr *expr, int indent); void fprint_expr_recursive(FILE *file, Expr *expr, int indent);
Token lexer_scan_token(void); Token lexer_scan_token(Lexer *lexer);
Token lexer_scan_ident_test(const char *scan); Token lexer_scan_ident_test(Lexer *lexer, const char *scan);
void lexer_test_setup(const char *text, size_t len); void lexer_test_setup(Lexer *lexer, const char *text, size_t len);
void lexer_add_file_for_lexing(File *file); void lexer_add_file_for_lexing(Lexer *lexer, File *file);
File* lexer_current_file(void); File* lexer_current_file(Lexer *lexer);
void lexer_check_init(void); void lexer_check_init(void);
void lexer_store_state(void);
void lexer_restore_state(void);
static inline void advance(void)
{
tok = next_tok;
while (1)
{
next_tok = lexer_scan_token();
// printf(">>> %.*s => %s\n", tok.length, tok.start, token_type_to_string(tok.type));
if (next_tok.type != TOKEN_INVALID_TOKEN) break;
}
}
static inline void advance_and_verify(TokenType token_type)
{
assert(tok.type == token_type);
advance();
}
typedef enum typedef enum
{ {
@@ -942,12 +974,12 @@ Path *path_find_parent_path(Path *path);
const char *resolve_status_to_string(ResolveStatus status); const char *resolve_status_to_string(ResolveStatus status);
#define SEMA_ERROR(_tok, ...) sema_error_range(_tok.span, __VA_ARGS__) #define SEMA_TOKEN_ERROR(_tok, ...) sema_error_range(_tok.span, __VA_ARGS__)
void sema_init(File *file); #define SEMA_ERROR(_node, ...) sema_error_range(_node->span, __VA_ARGS__)
#define SEMA_PREV(_node, ...) sema_prev_at_range(_node->span, __VA_ARGS__)
void sema_analysis_pass_process_imports(Context *context); void sema_analysis_pass_process_imports(Context *context);
void sema_analysis_pass_conditional_compilation(Context *context); void sema_analysis_pass_conditional_compilation(Context *context);
void sema_analysis_pass_decls(Context *context); void sema_analysis_pass_decls(Context *context);
void sema_analysis_pass_3(Context *context);
bool sema_add_local(Context *context, Decl *decl); bool sema_add_local(Context *context, Decl *decl);
bool sema_analyse_statement(Context *context, Ast *statement); bool sema_analyse_statement(Context *context, Ast *statement);
@@ -958,7 +990,7 @@ void sema_error_at(SourceLoc loc, const char *message, ...);
void sema_error_range(SourceRange range, 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_at(SourceLoc loc, const char *message, va_list args);
void sema_verror_range(SourceRange range, const char *message, va_list args); void sema_verror_range(SourceRange range, const char *message, va_list args);
void sema_error(const char *message, ...); void sema_error(Context *context, const char *message, ...);
void sema_prev_at_range(SourceRange span, 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(SourceLoc loc, const char *message, ...);
void sema_shadow_error(Decl *decl, Decl *old); void sema_shadow_error(Decl *decl, Decl *old);
@@ -969,7 +1001,7 @@ 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_in_file(File *file, SourceLoc loc);
SourcePosition source_file_find_position(SourceLoc loc); SourcePosition source_file_find_position(SourceLoc loc);
SourceRange source_range_from_ranges(SourceRange first, SourceRange last); SourceRange source_range_from_ranges(SourceRange first, SourceRange last);
static inline unsigned source_range_len(SourceRange range) { return range.end_loc - range.loc; }
void stable_init(STable *table, uint32_t initial_size); void stable_init(STable *table, uint32_t initial_size);
void *stable_set(STable *table, const char *key, void *value); void *stable_set(STable *table, const char *key, void *value);
@@ -1112,4 +1144,5 @@ static inline const char* struct_union_name_from_token(TokenType type)
#define BACKEND_TYPE_GLOBAL(type) gencontext_get_llvm_type(NULL, type) #define BACKEND_TYPE_GLOBAL(type) gencontext_get_llvm_type(NULL, type)
#define DEBUG_TYPE(type) gencontext_get_debug_type(context, type) #define DEBUG_TYPE(type) gencontext_get_debug_type(context, type)
void advance(Context *context);
void advance_and_verify(Context *context, TokenType token_type);

View File

@@ -4,7 +4,6 @@
#include "compiler_internal.h" #include "compiler_internal.h"
Context *current_context;
Context *context_create(File *file, BuildTarget *target) Context *context_create(File *file, BuildTarget *target)
{ {
@@ -14,43 +13,10 @@ Context *context_create(File *file, BuildTarget *target)
context->target = target; context->target = target;
stable_init(&context->local_symbols, 256); stable_init(&context->local_symbols, 256);
stable_init(&context->external_symbols, 256); stable_init(&context->external_symbols, 256);
stable_init(&context->scratch_table, 32);
return context; return context;
} }
void context_push(Context *context)
{
current_context = context;
}
void context_add_header_decl(Context *context, Decl *decl)
{
DEBUG_LOG("Adding %s to header", decl->name.string);
vec_add(context->header_declarations, decl);
}
bool context_add_local(Context *context, Decl *decl)
{
Decl *other = context_find_ident(context, decl->name.string);
if (other)
{
sema_shadow_error(decl, other);
decl_poison(decl);
decl_poison(other);
return false;
}
Decl *** vars = &context->active_function_for_analysis->func.annotations->vars;
unsigned num_vars = vec_size(*vars);
if (num_vars == MAX_LOCALS - 1 || context->last_local == &context->locals[MAX_LOCALS - 1])
{
SEMA_ERROR(decl->name, "Reached the maximum number of locals.");
return false;
}
decl->var.id = num_vars;
*vars = VECADD(*vars, decl);
context->last_local[0] = decl;
context->last_local++;
return true;
}
static inline bool create_module_or_check_name(Context *context, Path *module_name) static inline bool create_module_or_check_name(Context *context, Path *module_name)
{ {
@@ -74,7 +40,7 @@ bool context_set_module_from_filename(Context *context)
int len = filename_to_module(context->file->full_path, buffer); int len = filename_to_module(context->file->full_path, buffer);
if (!len) if (!len)
{ {
sema_error("The filename '%s' could not be converted to a valid module name, try using an explicit module name."); sema_error(context, "The filename '%s' could not be converted to a valid module name, try using an explicit module name.");
return false; return false;
} }
@@ -82,7 +48,7 @@ bool context_set_module_from_filename(Context *context)
const char *module_name = symtab_add(buffer, (uint32_t) len, fnv1a(buffer, (uint32_t) len), &type); const char *module_name = symtab_add(buffer, (uint32_t) len, fnv1a(buffer, (uint32_t) len), &type);
if (type != TOKEN_IDENT) if (type != TOKEN_IDENT)
{ {
sema_error("Generating a filename from the file '%s' resulted in a name that is a reserved keyword, " 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."); "try using an explicit module name.");
return false; return false;
} }
@@ -162,7 +128,6 @@ void context_register_global_decl(Context *context, Decl *decl)
case DECL_ERROR_CONSTANT: case DECL_ERROR_CONSTANT:
case DECL_ARRAY_VALUE: case DECL_ARRAY_VALUE:
case DECL_IMPORT: case DECL_IMPORT:
case DECL_MULTI_DECL:
case DECL_CT_ELSE: case DECL_CT_ELSE:
case DECL_CT_ELIF: case DECL_CT_ELIF:
case DECL_ATTRIBUTE: case DECL_ATTRIBUTE:
@@ -173,17 +138,17 @@ void context_register_global_decl(Context *context, Decl *decl)
vec_add(context->ct_ifs, decl); vec_add(context->ct_ifs, decl);
return; return;
} }
DEBUG_LOG("Registering symbol '%s'.", decl->name.string); DEBUG_LOG("Registering symbol '%s'.", decl->name);
Decl *old = stable_set(&context->local_symbols, decl->name.string, decl); Decl *old = stable_set(&context->local_symbols, decl->name, decl);
if (!old && decl->visibility != VISIBLE_LOCAL) if (!old && decl->visibility != VISIBLE_LOCAL)
{ {
old = stable_set(&context->module->symbols, decl->name.string, decl); old = stable_set(&context->module->symbols, decl->name, decl);
} }
if (!old && decl->visibility == VISIBLE_PUBLIC) if (!old && decl->visibility == VISIBLE_PUBLIC)
{ {
compiler_register_public_symbol(decl); compiler_register_public_symbol(decl);
old = stable_set(&context->module->public_symbols, decl->name.string, decl); old = stable_set(&context->module->public_symbols, decl->name, decl);
} }
if (old != NULL) if (old != NULL)
{ {

View File

@@ -46,15 +46,15 @@ static void print_error(SourceRange source_range, const char *message, PrintType
break; break;
} }
} }
size_t lines_in_file = vec_size(position.file->line_start); size_t lines_in_file = vec_size(position.file->lines);
for (unsigned i = LINES_SHOWN; i > 0; i--) for (unsigned i = LINES_SHOWN; i > 0; i--)
{ {
if (position.line < i) continue; if (position.line < i) continue;
uint32_t line_number = position.line + 1 - i; uint32_t line_number = position.line + 1 - i;
SourceLoc line_start = position.file->line_start[line_number - 1]; SourceLoc line_start = position.file->lines[line_number - 1];
SourceLoc line_end = line_number == lines_in_file ? position.file->end_id : SourceLoc line_end = line_number == lines_in_file ? position.file->end_id :
position.file->line_start[line_number]; position.file->lines[line_number];
uint32_t line_len = line_end - line_start - 1; uint32_t line_len = line_end - line_start - 1;
eprintf(number_buffer, line_number, line_len, position.file->contents + line_start - position.file->start_id); eprintf(number_buffer, line_number, line_len, position.file->contents + line_start - position.file->start_id);
} }
@@ -74,7 +74,7 @@ static void print_error(SourceRange source_range, const char *message, PrintType
eprintf(" "); eprintf(" ");
} }
} }
for (uint32_t i = 0; i < source_range.length; i++) for (uint32_t i = 0; i < source_range_len(source_range); i++)
{ {
eprintf("^"); eprintf("^");
} }
@@ -142,7 +142,7 @@ void sema_error_range(SourceRange range, const char *message, ...)
void sema_verror_at(SourceLoc loc, const char *message, va_list args) void sema_verror_at(SourceLoc loc, const char *message, va_list args)
{ {
vprint_error((SourceRange) { loc, 1 }, message, args); vprint_error((SourceRange) { loc, loc + 1 }, message, args);
diagnostics.errors++; diagnostics.errors++;
} }
@@ -152,9 +152,9 @@ void sema_verror_range(SourceRange range, const char *message, va_list args)
diagnostics.errors++; diagnostics.errors++;
} }
void sema_error(const char *message, ...) void sema_error(Context *context, const char *message, ...)
{ {
File *file = lexer_current_file(); File *file = lexer_current_file(&context->lexer);
va_list list; va_list list;
va_start(list, message); va_start(list, message);
eprintf("(%s:0) Error: ", file->name); eprintf("(%s:0) Error: ", file->name);
@@ -179,7 +179,7 @@ void sema_prev_at(SourceLoc loc, const char *message, ...)
va_start(args, message); va_start(args, message);
char buffer[256]; char buffer[256];
vsnprintf(buffer, 256, message, args); vsnprintf(buffer, 256, message, args);
print_error((SourceRange){ loc, 1 }, buffer, PRINT_TYPE_PREV); print_error((SourceRange){ loc, loc + 1 }, buffer, PRINT_TYPE_PREV);
va_end(args); va_end(args);
} }

View File

@@ -88,6 +88,7 @@ typedef enum
AST_DO_STMT, AST_DO_STMT,
AST_EXPR_STMT, AST_EXPR_STMT,
AST_FOR_STMT, AST_FOR_STMT,
AST_FUNCTION_BLOCK_STMT,
AST_GENERIC_CASE_STMT, AST_GENERIC_CASE_STMT,
AST_GENERIC_DEFAULT_STMT, AST_GENERIC_DEFAULT_STMT,
AST_GOTO_STMT, AST_GOTO_STMT,
@@ -201,7 +202,6 @@ typedef enum
DECL_ARRAY_VALUE, DECL_ARRAY_VALUE,
DECL_IMPORT, DECL_IMPORT,
DECL_MACRO, DECL_MACRO,
DECL_MULTI_DECL,
DECL_GENERIC, DECL_GENERIC,
DECL_CT_IF, DECL_CT_IF,
DECL_CT_ELSE, DECL_CT_ELSE,
@@ -251,13 +251,6 @@ typedef enum
} GotoType; } GotoType;
typedef enum
{
LEXER_STATE_NORMAL,
LEXER_STATE_DOCS_PARSE,
LEXER_STATE_DOCS_PARSE_DIRECTIVE,
} LexerState;
typedef enum typedef enum
{ {
NUMBER_TYPE_BOOL, NUMBER_TYPE_BOOL,
@@ -286,9 +279,8 @@ typedef enum
SCOPE_NONE = 0, SCOPE_NONE = 0,
SCOPE_BREAK = 1 << 0, SCOPE_BREAK = 1 << 0,
SCOPE_CONTINUE = 1 << 1, SCOPE_CONTINUE = 1 << 1,
SCOPE_CONTROL = 1 << 2, SCOPE_NEXT = 1 << 2,
SCOPE_NEXT = 1 << 3, SCOPE_DEFER = 1 << 3,
SCOPE_DEFER = 1 << 4,
} ScopeFlags; } ScopeFlags;
typedef enum typedef enum
@@ -417,12 +409,15 @@ typedef enum
// Otherwise we allow things like "@ foo" which would be pretty bad. // Otherwise we allow things like "@ foo" which would be pretty bad.
TOKEN_AT_IDENT, // @foobar TOKEN_AT_IDENT, // @foobar
TOKEN_HASH_IDENT, // #foobar TOKEN_HASH_IDENT, // #foobar
TOKEN_CT_IDENT, // $foobar TOKEN_CT_IDENT, // $foobar
TOKEN_STRING, // "Teststring" TOKEN_STRING, // "Teststring"
TOKEN_INTEGER, // 123 0x23 0b10010 0o327 TOKEN_INTEGER, // 123 0x23 0b10010 0o327
TOKEN_REAL, // 0x23.2p-2a 43.23e23 TOKEN_REAL, // 0x23.2p-2a 43.23e23
TOKEN_COMMENT, // Comment
TOKEN_DOC_COMMENT, // Doc Comment
// Keywords // Keywords
TOKEN_ALIAS, // Reserved TOKEN_ALIAS, // Reserved
TOKEN_AS, TOKEN_AS,

View File

@@ -37,8 +37,11 @@ static bool expr_is_ltype(Expr *expr)
static inline bool sema_type_error_on_binop(Expr *expr) static inline bool sema_type_error_on_binop(Expr *expr)
{ {
const char *c = token_type_to_string(binaryop_to_token(expr->binary_expr.operator)); const char *c = token_type_to_string(binaryop_to_token(expr->binary_expr.operator));
SEMA_ERROR(expr->loc, "Cannot perform '%s' %s '%s'.", SEMA_ERROR(expr,
type_to_error_string(expr->binary_expr.left->type), c, type_to_error_string(expr->binary_expr.right->type)); "Cannot perform '%s' %s '%s'.",
type_to_error_string(expr->binary_expr.left->type),
c,
type_to_error_string(expr->binary_expr.right->type));
return false; return false;
} }
@@ -60,7 +63,7 @@ static inline bool sema_expr_analyse_ternary(Context *context, Type *to, Expr *e
Type *type = cond->type->canonical; Type *type = cond->type->canonical;
if (type->type_kind != TYPE_BOOL && cast_to_bool_kind(type) == CAST_ERROR) if (type->type_kind != TYPE_BOOL && cast_to_bool_kind(type) == CAST_ERROR)
{ {
SEMA_ERROR(cond->loc, "Cannot convert expression to boolean."); SEMA_ERROR(cond, "Cannot convert expression to boolean.");
return false; return false;
} }
left = cond; left = cond;
@@ -76,8 +79,8 @@ static inline bool sema_expr_analyse_ternary(Context *context, Type *to, Expr *e
Type *max = type_find_max_type(left_canonical, right_canonical); Type *max = type_find_max_type(left_canonical, right_canonical);
if (!max) if (!max)
{ {
SEMA_ERROR(expr->loc, "Cannot find a common parent type of '%s' and '%s'", 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; return false;
} }
if (!cast_implicit(left, max) || !cast_implicit(right, max)) return false; if (!cast_implicit(left, max) || !cast_implicit(right, max)) return false;
@@ -92,25 +95,27 @@ static inline bool sema_expr_analyse_identifier(Context *context, Type *to, Expr
{ {
// TODO what about struct functions // TODO what about struct functions
Decl *ambiguous_decl; Decl *ambiguous_decl;
Decl *decl = sema_resolve_symbol(context, expr->identifier_expr.identifier.string, expr->identifier_expr.path, &ambiguous_decl); Decl *decl = sema_resolve_symbol(context, expr->identifier_expr.identifier, expr->identifier_expr.path, &ambiguous_decl);
if (!decl) if (!decl)
{ {
SEMA_ERROR(expr->identifier_expr.identifier, "Unknown symbol '%s'.", expr->identifier_expr.identifier.string); SEMA_ERROR(expr, "Unknown symbol '%s'.", expr->identifier_expr.identifier);
return false; return false;
} }
if (ambiguous_decl) if (ambiguous_decl)
{ {
SEMA_ERROR(expr->identifier_expr.identifier, "Ambiguous symbol '%s' both defined in %s and %s, please add the module name to resolve the ambiguity", SEMA_ERROR(expr,
expr->identifier_expr.identifier.string, "Ambiguous symbol '%s' both defined in %s and %s, please add the module name to resolve the ambiguity",
decl->module->name->module, ambiguous_decl->module->name->module); expr->identifier_expr.identifier,
decl->module->name->module,
ambiguous_decl->module->name->module);
return false; return false;
} }
if (decl->decl_kind == DECL_FUNC && !expr->identifier_expr.path && decl->module != context->module) if (decl->decl_kind == DECL_FUNC && !expr->identifier_expr.path && decl->module != context->module)
{ {
SEMA_ERROR(expr->identifier_expr.identifier, "Functions from other modules, must be prefixed with the module name"); SEMA_ERROR(expr, "Functions from other modules, must be prefixed with the module name");
return false; return false;
} }
@@ -191,7 +196,7 @@ static inline bool sema_expr_analyse_call(Context *context, Type *to, Expr *expr
case DECL_POISONED: case DECL_POISONED:
return false; return false;
default: default:
SEMA_ERROR(expr->loc, "The expression cannot be called."); SEMA_ERROR(expr, "The expression cannot be called.");
return false; return false;
} }
} }
@@ -227,7 +232,7 @@ static inline bool sema_expr_analyse_subscript(Context *context, Type *to, Expr
inner_type = type_char; inner_type = type_char;
break; break;
default: default:
SEMA_ERROR(expr->subscript_expr.expr->loc, "Cannot index '%s'.", type_to_error_string(type)); SEMA_ERROR(expr->subscript_expr.expr, "Cannot index '%s'.", type_to_error_string(type));
return false; return false;
} }
@@ -243,13 +248,13 @@ static inline bool sema_expr_analyse_method_function(Context *context, Expr *exp
VECEACH(decl->method_functions, i) VECEACH(decl->method_functions, i)
{ {
Decl *function = decl->method_functions[i]; Decl *function = decl->method_functions[i];
if (function->name.string == name) if (function->name == name)
{ {
// TODO // TODO
return true; return true;
} }
} }
SEMA_ERROR(expr->loc, "Cannot find method function '%s.%s'", decl->name.string, name); SEMA_ERROR(expr, "Cannot find method function '%s.%s'", decl->name, name);
return false; return false;
} }
@@ -259,14 +264,14 @@ static inline bool sema_expr_analyse_enum_constant(Context *context, Expr *expr,
VECEACH(decl->enums.values, i) VECEACH(decl->enums.values, i)
{ {
Decl *enum_constant = decl->enums.values[i]; Decl *enum_constant = decl->enums.values[i];
if (enum_constant->name.string == name) if (enum_constant->name == name)
{ {
assert(enum_constant->resolve_status == RESOLVE_DONE); assert(enum_constant->resolve_status == RESOLVE_DONE);
expr_replace(expr, enum_constant->enum_constant.expr); expr_replace(expr, enum_constant->enum_constant.expr);
return true; return true;
} }
} }
SEMA_ERROR(expr->loc, "'%s' has no enumeration value '%s'.", decl->name.string, name); SEMA_ERROR(expr, "'%s' has no enumeration value '%s'.", decl->name, name);
return false; return false;
} }
@@ -276,7 +281,7 @@ static inline bool sema_expr_analyse_error_constant(Context *context, Expr *expr
VECEACH(decl->error.error_constants, i) VECEACH(decl->error.error_constants, i)
{ {
Decl *error_constant = decl->error.error_constants[i]; Decl *error_constant = decl->error.error_constants[i];
if (error_constant->name.string == name) if (error_constant->name == name)
{ {
assert(error_constant->resolve_status == RESOLVE_DONE); assert(error_constant->resolve_status == RESOLVE_DONE);
expr->type = decl->type; expr->type = decl->type;
@@ -286,7 +291,7 @@ static inline bool sema_expr_analyse_error_constant(Context *context, Expr *expr
return true; return true;
} }
} }
SEMA_ERROR(expr->loc, "'%s' has no error type '%s'.", decl->name.string, name); SEMA_ERROR(expr, "'%s' has no error type '%s'.", decl->name, name);
return false; return false;
} }
@@ -296,8 +301,8 @@ static Decl *strukt_recursive_search_member(Decl *strukt, const char *name, int
{ {
(*index)++; (*index)++;
Decl *member = strukt->strukt.members[i]; Decl *member = strukt->strukt.members[i];
if (member->name.string == name) return member; if (member->name == name) return member;
if (!member->name.string && decl_is_struct_type(member)) if (!member->name && decl_is_struct_type(member))
{ {
Decl *result = strukt_recursive_search_member(member, name, index); Decl *result = strukt_recursive_search_member(member, name, index);
if (result) return result; if (result) return result;
@@ -319,7 +324,7 @@ static inline bool sema_expr_analyse_access(Context *context, Type *to, Expr *ex
} }
if (!type_may_have_method_functions(type)) if (!type_may_have_method_functions(type))
{ {
SEMA_ERROR(expr->loc, "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'", expr->access_expr.sub_element.string, type_to_error_string(parent_type));
return false; return false;
} }
Decl *decl = type->decl; Decl *decl = type->decl;
@@ -338,12 +343,12 @@ static inline bool sema_expr_analyse_access(Context *context, Type *to, Expr *ex
Decl *member = strukt_recursive_search_member(decl, expr->access_expr.sub_element.string, &index); Decl *member = strukt_recursive_search_member(decl, expr->access_expr.sub_element.string, &index);
if (!member) if (!member)
{ {
SEMA_ERROR(expr->access_expr.sub_element, "There is no element '%s.%s'.", decl->name.string, expr->access_expr.sub_element.string); SEMA_TOKEN_ERROR(expr->access_expr.sub_element, "There is no element '%s.%s'.", decl->name, expr->access_expr.sub_element.string);
return false; return false;
} }
if (is_pointer) if (is_pointer)
{ {
Expr *deref = expr_new(EXPR_UNARY, expr->loc); Expr *deref = expr_new(EXPR_UNARY, expr->span);
deref->unary_expr.operator = UNARYOP_DEREF; deref->unary_expr.operator = UNARYOP_DEREF;
deref->unary_expr.expr = expr->access_expr.parent; deref->unary_expr.expr = expr->access_expr.parent;
deref->resolve_status = RESOLVE_DONE; deref->resolve_status = RESOLVE_DONE;
@@ -361,7 +366,7 @@ static inline bool sema_expr_analyse_type_access(Context *context, Type *to, Exp
if (!sema_resolve_type_info(context, type_info)) return false; if (!sema_resolve_type_info(context, type_info)) return false;
if (!type_may_have_method_functions(type_info->type)) if (!type_may_have_method_functions(type_info->type))
{ {
SEMA_ERROR(expr->loc, "'%s' does not have method functions.", type_to_error_string(type_info->type)); SEMA_ERROR(expr, "'%s' does not have method functions.", type_to_error_string(type_info->type));
return false; return false;
} }
Decl *decl = type_info->type->decl; Decl *decl = type_info->type->decl;
@@ -384,14 +389,14 @@ static inline bool sema_expr_analyse_type_access(Context *context, Type *to, Exp
VECEACH(type_info->type->decl->method_functions, i) VECEACH(type_info->type->decl->method_functions, i)
{ {
Decl *function = type_info->type->decl->method_functions[i]; Decl *function = type_info->type->decl->method_functions[i];
if (expr->type_access.name.string == function->name.string) if (expr->type_access.name.string == function->name)
{ {
expr->type_access.method = function; expr->type_access.method = function;
expr->type = function->func.function_signature.rtype->type; expr->type = function->func.function_signature.rtype->type;
return true; return true;
} }
} }
SEMA_ERROR(expr->loc, "No function '%s.%s' found.", type_to_error_string(type_info->type), expr->type_access.name.string); SEMA_ERROR(expr, "No function '%s.%s' found.", type_to_error_string(type_info->type), expr->type_access.name.string);
return false; return false;
} }
@@ -399,7 +404,7 @@ static inline Decl *decl_find_by_name(Decl** decls, const char *name)
{ {
VECEACH(decls, i) VECEACH(decls, i)
{ {
if (decls[i]->name.string == name) return decls[i]; if (decls[i]->name == name) return decls[i];
} }
return NULL; return NULL;
} }
@@ -428,7 +433,7 @@ static inline bool sema_expr_analyse_struct_initializer_list(Context *context, T
{ {
if (field->expr_kind == EXPR_IDENTIFIER) if (field->expr_kind == EXPR_IDENTIFIER)
{ {
decl = decl_find_by_name(members, field->identifier_expr.identifier.string); decl = decl_find_by_name(members, field->identifier_expr.identifier);
} }
TODO TODO
} }
@@ -436,7 +441,7 @@ static inline bool sema_expr_analyse_struct_initializer_list(Context *context, T
{ {
if (i >= size) if (i >= size)
{ {
SEMA_ERROR(field->loc, "Too many elements in initializer"); SEMA_ERROR(field, "Too many elements in initializer");
return false; return false;
} }
decl = members[i]; decl = members[i];
@@ -464,7 +469,7 @@ static inline bool sema_expr_analyse_initializer_list(Context *context, Type *to
default: default:
break; break;
} }
SEMA_ERROR(expr->loc, "Cannot assign expression to '%s'.", type_to_error_string(to)); SEMA_ERROR(expr, "Cannot assign expression to '%s'.", type_to_error_string(to));
return false; return false;
} }
@@ -494,9 +499,9 @@ static inline bool sema_expr_analyse_cast(Context *context, Type *to, Expr *expr
// TODO above is probably not right, cast type not set. // TODO above is probably not right, cast type not set.
// Overwrite cast. // Overwrite cast.
Token loc = expr->loc; SourceRange loc = expr->span;
*expr = *inner; *expr = *inner;
expr->loc = loc; expr->span = loc;
return true; return true;
} }
@@ -508,7 +513,7 @@ static bool sema_expr_analyse_assign(Context *context, Type *to, Expr *expr, Exp
if (!expr_is_ltype(left)) if (!expr_is_ltype(left))
{ {
SEMA_ERROR(left->loc, "Expression is not assignable."); SEMA_ERROR(left, "Expression is not assignable.");
return false; return false;
} }
if (!sema_analyse_expr(context, left->type, right)) return false; if (!sema_analyse_expr(context, left->type, right)) return false;
@@ -527,7 +532,7 @@ static bool sema_expr_analyse_bit_and_assign(Context *context, Type *to, Expr *e
if (!type_is_number(left->type)) if (!type_is_number(left->type))
{ {
SEMA_ERROR(left->loc, "Expected a numeric type here."); SEMA_ERROR(left, "Expected a numeric type here.");
return false; return false;
} }
@@ -535,7 +540,7 @@ static bool sema_expr_analyse_bit_and_assign(Context *context, Type *to, Expr *e
if (!type_is_number(right->type)) if (!type_is_number(right->type))
{ {
SEMA_ERROR(right->loc, "Expected a numeric type here."); SEMA_ERROR(right, "Expected a numeric type here.");
return false; return false;
} }
@@ -549,7 +554,7 @@ static bool sema_expr_analyse_bit_or_assign(Context *context, Type *to, Expr *ex
if (!type_is_number(left->type)) if (!type_is_number(left->type))
{ {
SEMA_ERROR(left->loc, "Expected a numeric type here."); SEMA_ERROR(left, "Expected a numeric type here.");
return false; return false;
} }
@@ -557,7 +562,7 @@ static bool sema_expr_analyse_bit_or_assign(Context *context, Type *to, Expr *ex
if (!type_is_number(right->type)) if (!type_is_number(right->type))
{ {
SEMA_ERROR(right->loc, "Expected a numeric type here."); SEMA_ERROR(right, "Expected a numeric type here.");
return false; return false;
} }
@@ -571,7 +576,7 @@ static bool sema_expr_analyse_bit_xor_assign(Context *context, Type *to, Expr *e
if (!type_is_number(left->type)) if (!type_is_number(left->type))
{ {
SEMA_ERROR(left->loc, "Expected a numeric type here."); SEMA_ERROR(left, "Expected a numeric type here.");
return false; return false;
} }
@@ -579,7 +584,7 @@ static bool sema_expr_analyse_bit_xor_assign(Context *context, Type *to, Expr *e
if (!type_is_number(right->type)) if (!type_is_number(right->type))
{ {
SEMA_ERROR(right->loc, "Expected a numeric type here."); SEMA_ERROR(right, "Expected a numeric type here.");
return false; return false;
} }
@@ -594,7 +599,7 @@ static bool sema_expr_analyse_div_assign(Context *context, Type *to, Expr *expr,
if (!type_is_number(left->type)) if (!type_is_number(left->type))
{ {
SEMA_ERROR(left->loc, "Expected a numeric type here."); SEMA_ERROR(left, "Expected a numeric type here.");
return false; return false;
} }
@@ -602,7 +607,7 @@ static bool sema_expr_analyse_div_assign(Context *context, Type *to, Expr *expr,
if (!type_is_number(right->type)) if (!type_is_number(right->type))
{ {
SEMA_ERROR(right->loc, "Expected a numeric type here."); SEMA_ERROR(right, "Expected a numeric type here.");
return false; return false;
} }
@@ -616,7 +621,7 @@ static bool sema_expr_analyse_mult_assign(Context *context, Type *to, Expr *expr
if (!type_is_number(left->type)) if (!type_is_number(left->type))
{ {
SEMA_ERROR(left->loc, "Expected a numeric type here."); SEMA_ERROR(left, "Expected a numeric type here.");
return false; return false;
} }
@@ -624,7 +629,7 @@ static bool sema_expr_analyse_mult_assign(Context *context, Type *to, Expr *expr
if (!type_is_number(right->type)) if (!type_is_number(right->type))
{ {
SEMA_ERROR(right->loc, "Expected a numeric type here."); SEMA_ERROR(right, "Expected a numeric type here.");
return false; return false;
} }
@@ -647,7 +652,7 @@ static bool sema_expr_analyse_sub_assign(Context *context, Type *to, Expr *expr,
Type *right_type = right->type->canonical; Type *right_type = right->type->canonical;
if (!type_is_integer(right_type)) if (!type_is_integer(right_type))
{ {
SEMA_ERROR(right->loc, "Expected an integer type instead."); SEMA_ERROR(right, "Expected an integer type instead.");
return false; return false;
} }
expr->type = left->type; expr->type = left->type;
@@ -658,13 +663,13 @@ static bool sema_expr_analyse_sub_assign(Context *context, Type *to, Expr *expr,
if (!type_is_number(left->type)) if (!type_is_number(left->type))
{ {
SEMA_ERROR(left->loc, "Expected a numeric type here."); SEMA_ERROR(left, "Expected a numeric type here.");
return false; return false;
} }
if (!type_is_number(right->type)) if (!type_is_number(right->type))
{ {
SEMA_ERROR(right->loc, "Expected a numeric type here."); SEMA_ERROR(right, "Expected a numeric type here.");
return false; return false;
} }
@@ -687,7 +692,7 @@ static bool sema_expr_analyse_add_assign(Context *context, Type *to, Expr *expr,
Type *right_type = right->type->canonical; Type *right_type = right->type->canonical;
if (!type_is_integer(right_type)) if (!type_is_integer(right_type))
{ {
SEMA_ERROR(right->loc, "Expected an integer type instead."); SEMA_ERROR(right, "Expected an integer type instead.");
return false; return false;
} }
expr->type = left->type; expr->type = left->type;
@@ -698,13 +703,13 @@ static bool sema_expr_analyse_add_assign(Context *context, Type *to, Expr *expr,
if (!type_is_number(left->type)) if (!type_is_number(left->type))
{ {
SEMA_ERROR(left->loc, "Expected a numeric type here."); SEMA_ERROR(left, "Expected a numeric type here.");
return false; return false;
} }
if (!type_is_number(right->type)) if (!type_is_number(right->type))
{ {
SEMA_ERROR(right->loc, "Expected a numeric type here."); SEMA_ERROR(right, "Expected a numeric type here.");
return false; return false;
} }
@@ -750,7 +755,7 @@ static bool sema_expr_analyse_sub(Context *context, Type *to, Expr *expr, Expr *
return true; return true;
ERR: ERR:
SEMA_ERROR(expr->loc, "Cannot subtract '%s' from '%s'", type_to_error_string(left_type), type_to_error_string(right_type)); SEMA_ERROR(expr, "Cannot subtract '%s' from '%s'", type_to_error_string(left_type), type_to_error_string(right_type));
return false; return false;
} }
@@ -787,7 +792,7 @@ static bool sema_expr_analyse_add(Context *context, Type *to, Expr *expr, Expr *
return true; return true;
ERR: ERR:
SEMA_ERROR(expr->loc, "Cannot add '%s' to '%s'", type_to_error_string(left_type), type_to_error_string(right_type)); SEMA_ERROR(expr, "Cannot add '%s' to '%s'", type_to_error_string(left_type), type_to_error_string(right_type));
return false; return false;
} }
@@ -806,7 +811,7 @@ static bool sema_expr_analyse_mult(Context *context, Type *to, Expr *expr, Expr
return true; return true;
ERR: ERR:
SEMA_ERROR(expr->loc, "Cannot multiply '%s' and '%s'", type_to_error_string(left_type), type_to_error_string(right_type)); SEMA_ERROR(expr, "Cannot multiply '%s' and '%s'", type_to_error_string(left_type), type_to_error_string(right_type));
return false; return false;
} }
@@ -827,14 +832,14 @@ static bool sema_expr_analyse_div(Context *context, Type *to, Expr *expr, Expr *
case CONST_INT: case CONST_INT:
if (right->const_expr.i == 0) if (right->const_expr.i == 0)
{ {
SEMA_ERROR(right->loc, "Division by zero not allowed."); SEMA_ERROR(right, "Division by zero not allowed.");
return false; return false;
} }
break; break;
case CONST_FLOAT: case CONST_FLOAT:
if (right->const_expr.f == 0) if (right->const_expr.f == 0)
{ {
SEMA_ERROR(right->loc, "Division by zero not allowed."); SEMA_ERROR(right, "Division by zero not allowed.");
return false; return false;
} }
break; break;
@@ -849,7 +854,7 @@ static bool sema_expr_analyse_div(Context *context, Type *to, Expr *expr, Expr *
return true; return true;
ERR: ERR:
SEMA_ERROR(expr->loc, "Cannot divide '%s' by '%s'", type_to_error_string(left_type), type_to_error_string(right_type)); SEMA_ERROR(expr, "Cannot divide '%s' by '%s'", type_to_error_string(left_type), type_to_error_string(right_type));
return false; return false;
} }
@@ -862,7 +867,7 @@ static bool sema_expr_analyse_mod(Context *context, Type *to, Expr *expr, Expr *
if (right->expr_kind == EXPR_CONST && right->const_expr.i == 0) if (right->expr_kind == EXPR_CONST && right->const_expr.i == 0)
{ {
SEMA_ERROR(expr->binary_expr.right->loc, "Cannot perform mod by zero."); SEMA_ERROR(expr->binary_expr.right, "Cannot perform mod by zero.");
return false; return false;
} }
// TODO Insert trap on negative right. // TODO Insert trap on negative right.
@@ -946,7 +951,7 @@ static bool sema_expr_analyse_shr(Context *context, Type *to, Expr *expr, Expr *
{ {
if (right->const_expr.i > left->type->canonical->builtin.bitsize) if (right->const_expr.i > left->type->canonical->builtin.bitsize)
{ {
SEMA_ERROR(right->loc, "Rightshift exceeds bitsize of '%s'", type_to_error_string(left->type)); SEMA_ERROR(right, "Rightshift exceeds bitsize of '%s'", type_to_error_string(left->type));
return false; return false;
} }
if (left->expr_kind == EXPR_CONST) if (left->expr_kind == EXPR_CONST)
@@ -970,7 +975,7 @@ static bool sema_expr_analyse_shr_assign(Context *context, Type *to, Expr *expr,
if (!expr_is_ltype(left)) if (!expr_is_ltype(left))
{ {
SEMA_ERROR(left->loc, "Expression is not assignable."); SEMA_ERROR(left, "Expression is not assignable.");
return false; return false;
} }
@@ -981,7 +986,7 @@ static bool sema_expr_analyse_shr_assign(Context *context, Type *to, Expr *expr,
{ {
if (right->const_expr.i > left->type->canonical->builtin.bitsize) if (right->const_expr.i > left->type->canonical->builtin.bitsize)
{ {
SEMA_ERROR(right->loc, "Rightshift exceeds bitsize of '%s'", type_to_error_string(left->type)); SEMA_ERROR(right, "Rightshift exceeds bitsize of '%s'", type_to_error_string(left->type));
return false; return false;
} }
} }
@@ -1007,7 +1012,7 @@ static bool sema_expr_analyse_shl(Context *context, Type *to, Expr *expr, Expr *
{ {
if (right->const_expr.i > left->type->canonical->builtin.bitsize) if (right->const_expr.i > left->type->canonical->builtin.bitsize)
{ {
SEMA_ERROR(right->loc, "Leftshift exceeds bitsize of '%s'", type_to_error_string(left->type)); SEMA_ERROR(right, "Leftshift exceeds bitsize of '%s'", type_to_error_string(left->type));
return false; return false;
} }
if (left->expr_kind == EXPR_CONST) if (left->expr_kind == EXPR_CONST)
@@ -1031,7 +1036,7 @@ static bool sema_expr_analyse_shl_assign(Context *context, Type *to, Expr *expr,
if (!expr_is_ltype(left)) if (!expr_is_ltype(left))
{ {
SEMA_ERROR(left->loc, "Expression is not assignable."); SEMA_ERROR(left, "Expression is not assignable.");
return false; return false;
} }
@@ -1044,7 +1049,7 @@ static bool sema_expr_analyse_shl_assign(Context *context, Type *to, Expr *expr,
{ {
if (right->const_expr.i > left->type->canonical->builtin.bitsize) if (right->const_expr.i > left->type->canonical->builtin.bitsize)
{ {
SEMA_ERROR(right->loc, "Leftshift exceeds bitsize of '%s'", type_to_error_string(left->type)); SEMA_ERROR(right, "Leftshift exceeds bitsize of '%s'", type_to_error_string(left->type));
return false; return false;
} }
} }
@@ -1095,7 +1100,7 @@ static bool sema_expr_analyse_comp(Context *context, Type *to, Expr *expr, Expr
bool success = max && cast_implicit(left, max) && cast_implicit(right, max); bool success = max && cast_implicit(left, max) && cast_implicit(right, max);
if (!success) if (!success)
{ {
SEMA_ERROR(expr->loc, "Cannot implicitly convert types to evaluate '%s' %s '%s'", type_to_error_string(left_type), token_type_to_string(binaryop_to_token(expr->binary_expr.operator)), type_to_error_string(right_type)); SEMA_ERROR(expr, "Cannot implicitly convert types to evaluate '%s' %s '%s'", type_to_error_string(left_type), token_type_to_string(binaryop_to_token(expr->binary_expr.operator)), type_to_error_string(right_type));
return false; return false;
} }
if (both_const(left, right)) if (both_const(left, right))
@@ -1157,12 +1162,12 @@ static bool sema_expr_analyse_deref(Context *context, Type *to, Expr *expr, Expr
Type *canonical = inner->type->canonical; Type *canonical = inner->type->canonical;
if (canonical->type_kind != TYPE_POINTER) if (canonical->type_kind != TYPE_POINTER)
{ {
SEMA_ERROR(inner->loc, "Cannot take the dereference of a value of type '%s'", type_to_error_string(inner->type)); SEMA_ERROR(inner, "Cannot take the dereference of a value of type '%s'", type_to_error_string(inner->type));
return false; return false;
} }
if (inner->expr_kind == EXPR_CONST) if (inner->expr_kind == EXPR_CONST)
{ {
SEMA_ERROR(inner->loc, "Dereferencing nil is not allowed."); SEMA_ERROR(inner, "Dereferencing nil is not allowed.");
return false; return false;
} }
Type *deref_type = inner->type->type_kind != TYPE_POINTER ? inner->type : canonical; Type *deref_type = inner->type->type_kind != TYPE_POINTER ? inner->type : canonical;
@@ -1174,7 +1179,7 @@ static bool sema_expr_analyse_addr(Context *context, Type *to, Expr *expr, Expr
{ {
if (!expr_is_ltype(inner)) if (!expr_is_ltype(inner))
{ {
SEMA_ERROR(inner->loc, "Cannot take the address of a value of type '%s'", type_to_error_string(inner->type)); SEMA_ERROR(inner, "Cannot take the address of a value of type '%s'", type_to_error_string(inner->type));
return false; return false;
} }
expr->type = type_get_ptr(inner->type); expr->type = type_get_ptr(inner->type);
@@ -1186,7 +1191,7 @@ static bool sema_expr_analyse_neg(Context *context, Type *to, Expr *expr, Expr *
Type *canonical = inner->type->canonical; Type *canonical = inner->type->canonical;
if (!builtin_may_negate(canonical)) if (!builtin_may_negate(canonical))
{ {
SEMA_ERROR(expr->loc, "Cannot negate %s.", type_to_error_string(inner->type)); SEMA_ERROR(expr, "Cannot negate %s.", type_to_error_string(inner->type));
return false; return false;
} }
if (inner->expr_kind != EXPR_CONST) if (inner->expr_kind != EXPR_CONST)
@@ -1214,7 +1219,7 @@ static bool sema_expr_analyse_bit_not(Context *context, Type *to, Expr *expr, Ex
Type *canonical = inner->type->canonical; Type *canonical = inner->type->canonical;
if (!type_is_integer(canonical) && canonical != type_bool) if (!type_is_integer(canonical) && canonical != type_bool)
{ {
SEMA_ERROR(expr->loc, "Cannot bit negate %s.", type_to_error_string(inner->type)); SEMA_ERROR(expr, "Cannot bit negate %s.", type_to_error_string(inner->type));
} }
if (inner->expr_kind != EXPR_CONST) if (inner->expr_kind != EXPR_CONST)
{ {
@@ -1296,7 +1301,7 @@ static bool sema_expr_analyse_not(Context *context, Type *to, Expr *expr, Expr *
case TYPE_STRING: case TYPE_STRING:
case TYPE_ENUM: case TYPE_ENUM:
case TYPE_ERROR: case TYPE_ERROR:
SEMA_ERROR(expr->loc, "Cannot use 'not' on %s", type_to_error_string(inner->type)); SEMA_ERROR(expr, "Cannot use 'not' on %s", type_to_error_string(inner->type));
return false; return false;
} }
UNREACHABLE UNREACHABLE
@@ -1306,12 +1311,12 @@ static inline bool sema_expr_analyse_incdec(Context *context, Type *to, Expr *ex
{ {
if (!expr_is_ltype(inner)) if (!expr_is_ltype(inner))
{ {
SEMA_ERROR(inner->loc, "Expression cannot be assigned to"); SEMA_ERROR(inner, "Expression cannot be assigned to");
return false; return false;
} }
if (!type_is_number(inner->type->canonical) && inner->type->canonical->type_kind != TYPE_POINTER) if (!type_is_number(inner->type->canonical) && inner->type->canonical->type_kind != TYPE_POINTER)
{ {
SEMA_ERROR(inner->loc, "Expression must be a number or a pointer"); SEMA_ERROR(inner, "Expression must be a number or a pointer");
return false; return false;
} }
expr->type = inner->type; expr->type = inner->type;
@@ -1516,7 +1521,7 @@ bool sema_analyse_expr(Context *context, Type *to, Expr *expr)
expr->resolve_status = RESOLVE_RUNNING; expr->resolve_status = RESOLVE_RUNNING;
break; break;
case RESOLVE_RUNNING: case RESOLVE_RUNNING:
SEMA_ERROR(expr->loc, "Recursive resolution of expression"); SEMA_ERROR(expr, "Recursive resolution of expression");
return expr_poison(expr); return expr_poison(expr);
case RESOLVE_DONE: case RESOLVE_DONE:
return expr_ok(expr); return expr_ok(expr);

File diff suppressed because it is too large Load Diff

View File

@@ -46,7 +46,7 @@ static void gencontext_emit_global_variable_definition(GenContext *context, Decl
} }
// TODO fix name // TODO fix name
decl->var.backend_ref = LLVMAddGlobal(context->module, decl->type->backend_type, decl->name.string); decl->var.backend_ref = LLVMAddGlobal(context->module, decl->type->backend_type, decl->name);
// If read only: LLVMSetGlobalConstant(decl->var.backend_ref, 1); // If read only: LLVMSetGlobalConstant(decl->var.backend_ref, 1);
@@ -70,8 +70,8 @@ static void gencontext_emit_global_variable_definition(GenContext *context, Decl
{ {
decl->var.backend_debug_ref = LLVMDIBuilderCreateGlobalVariableExpression(context->debug.builder, decl->var.backend_debug_ref = LLVMDIBuilderCreateGlobalVariableExpression(context->debug.builder,
NULL /*scope*/, NULL /*scope*/,
decl->name.string, decl->name,
decl->name.span.length, source_range_len(decl->name_span),
"linkagename", "linkagename",
2, 2,
context->debug.file, context->debug.file,

View File

@@ -14,7 +14,6 @@ static inline LLVMMetadataRef gencontext_create_debug_type_from_decl(GenContext
case DECL_ENUM_CONSTANT: case DECL_ENUM_CONSTANT:
case DECL_POISONED: case DECL_POISONED:
case DECL_GENERIC: case DECL_GENERIC:
case DECL_MULTI_DECL:
case DECL_MACRO: case DECL_MACRO:
case DECL_CT_IF: case DECL_CT_IF:
case DECL_CT_ELSE: case DECL_CT_ELSE:

View File

@@ -34,14 +34,16 @@ static inline LLVMValueRef gencontext_emit_sub_int(GenContext *context, Type *ty
static inline LLVMValueRef gencontext_emit_subscript_addr(GenContext *context, Expr *expr) static inline LLVMValueRef gencontext_emit_subscript_addr(GenContext *context, Expr *expr)
{ {
LLVMValueRef index = gencontext_emit_expr(context, expr->subscript_expr.index); LLVMValueRef index = gencontext_emit_expr(context, expr->subscript_expr.index);
switch (expr->subscript_expr.expr->type->canonical->type_kind) Type *type = expr->subscript_expr.expr->type->canonical;
switch (type->type_kind)
{ {
case TYPE_ARRAY: case TYPE_ARRAY:
TODO TODO
case TYPE_POINTER: case TYPE_POINTER:
return LLVMBuildGEP(context->builder, return LLVMBuildGEP2(context->builder,
gencontext_emit_expr(context, expr->subscript_expr.expr), BACKEND_TYPE(type->pointer),
&index, 1, "[]"); gencontext_emit_expr(context, expr->subscript_expr.expr),
&index, 1, "[]");
case TYPE_VARARRAY: case TYPE_VARARRAY:
case TYPE_SUBARRAY: case TYPE_SUBARRAY:
case TYPE_STRING: case TYPE_STRING:
@@ -54,7 +56,7 @@ static inline LLVMValueRef gencontext_emit_subscript_addr(GenContext *context, E
static inline LLVMValueRef gencontext_emit_access_addr(GenContext *context, Expr *expr) static inline LLVMValueRef gencontext_emit_access_addr(GenContext *context, Expr *expr)
{ {
LLVMValueRef value = gencontext_emit_address(context, expr->access_expr.parent); LLVMValueRef value = gencontext_emit_address(context, expr->access_expr.parent);
return LLVMBuildStructGEP(context->builder, value, (unsigned)expr->access_expr.index, ""); return LLVMBuildStructGEP2(context->builder, BACKEND_TYPE(expr->access_expr.parent->type), value, (unsigned)expr->access_expr.index, "");
} }
LLVMValueRef gencontext_emit_address(GenContext *context, Expr *expr) LLVMValueRef gencontext_emit_address(GenContext *context, Expr *expr)
@@ -216,7 +218,7 @@ LLVMValueRef gencontext_emit_unary_expr(GenContext *context, Expr *expr)
case UNARYOP_ADDR: case UNARYOP_ADDR:
return gencontext_emit_address(context, expr->unary_expr.expr); return gencontext_emit_address(context, expr->unary_expr.expr);
case UNARYOP_DEREF: case UNARYOP_DEREF:
return LLVMBuildLoad(context->builder, gencontext_emit_expr(context, expr->unary_expr.expr), "deref"); return LLVMBuildLoad2(context->builder, BACKEND_TYPE(expr->unary_expr.expr->type), gencontext_emit_expr(context, expr->unary_expr.expr), "deref");
case UNARYOP_INC: case UNARYOP_INC:
return gencontext_emit_pre_inc_dec(context, expr->unary_expr.expr, 1, false); return gencontext_emit_pre_inc_dec(context, expr->unary_expr.expr, 1, false);
case UNARYOP_DEC: case UNARYOP_DEC:
@@ -514,7 +516,7 @@ LLVMValueRef gencontext_emit_ternary_expr(GenContext *context, Expr *expr)
static LLVMValueRef gencontext_emit_identifier_expr(GenContext *context, Expr *expr) static LLVMValueRef gencontext_emit_identifier_expr(GenContext *context, Expr *expr)
{ {
return LLVMBuildLoad2(context->builder, expr->identifier_expr.decl->type->canonical->backend_type, return LLVMBuildLoad2(context->builder, expr->identifier_expr.decl->type->canonical->backend_type,
expr->identifier_expr.decl->var.backend_ref, expr->identifier_expr.decl->name.string); expr->identifier_expr.decl->var.backend_ref, expr->identifier_expr.decl->name);
} }
LLVMValueRef gencontext_emit_const_expr(GenContext *context, Expr *expr) LLVMValueRef gencontext_emit_const_expr(GenContext *context, Expr *expr)
@@ -575,7 +577,7 @@ static inline LLVMValueRef gencontext_emit_access_expr(GenContext *context, Expr
{ {
// Improve, add string description to the access? // Improve, add string description to the access?
LLVMValueRef value = gencontext_emit_address(context, expr->access_expr.parent); LLVMValueRef value = gencontext_emit_address(context, expr->access_expr.parent);
LLVMValueRef val = LLVMBuildStructGEP(context->builder, value, (unsigned)expr->access_expr.index, ""); LLVMValueRef val = LLVMBuildStructGEP2(context->builder, BACKEND_TYPE(expr->access_expr.parent->type), value, (unsigned)expr->access_expr.index, "");
return LLVMBuildLoad2(context->builder, gencontext_get_llvm_type(context, expr->type), val, ""); return LLVMBuildLoad2(context->builder, gencontext_get_llvm_type(context, expr->type), val, "");
} }
@@ -612,6 +614,13 @@ static inline LLVMValueRef gencontext_emit_struct_init_values_expr(GenContext *c
TODO TODO
} }
LLVMValueRef gencontext_emit_ast_expr(GenContext *context, Ast *expr)
{
assert(expr->ast_kind == AST_EXPR_STMT);
LLVMValueRef value = gencontext_emit_expr(context, expr->expr_stmt);
// gencontext_emit_defer(context, expr);
return value;
}
LLVMValueRef gencontext_emit_expr(GenContext *context, Expr *expr) LLVMValueRef gencontext_emit_expr(GenContext *context, Expr *expr)
{ {

View File

@@ -78,7 +78,7 @@ static inline void gencontext_emit_parameter(GenContext *context, Decl *decl, un
assert(decl->decl_kind == DECL_VAR && decl->var.kind == VARDECL_PARAM); assert(decl->decl_kind == DECL_VAR && decl->var.kind == VARDECL_PARAM);
// Allocate room on stack and copy. // Allocate room on stack and copy.
decl->var.backend_ref = gencontext_emit_alloca(context, BACKEND_TYPE(decl->type), decl->name.string); decl->var.backend_ref = gencontext_emit_alloca(context, BACKEND_TYPE(decl->type), decl->name);
LLVMBuildStore(context->builder, LLVMGetParam(context->function, index), decl->var.backend_ref); LLVMBuildStore(context->builder, LLVMGetParam(context->function, index), decl->var.backend_ref);
} }
@@ -109,7 +109,7 @@ void gencontext_emit_function_body(GenContext *context, Decl *decl)
VECEACH(decl->func.labels, i) VECEACH(decl->func.labels, i)
{ {
Ast *label = decl->func.labels[i]; Ast *label = decl->func.labels[i];
label->label_stmt.backend_value = gencontext_create_free_block(context, label->token.string); label->label_stmt.backend_value = gencontext_create_free_block(context, label->label_stmt.name);
} }
gencontext_emit_compound_stmt(context, decl->func.body); gencontext_emit_compound_stmt(context, decl->func.body);
@@ -178,11 +178,11 @@ void gencontext_emit_function_decl(GenContext *context, Decl *decl)
flags |= LLVMDIFlagPublic; flags |= LLVMDIFlagPublic;
break; break;
} }
SourcePosition decl_position = source_file_find_position(decl->name.span.loc); SourcePosition decl_position = source_file_find_position(decl->name_span.loc);
context->debug.function = LLVMDIBuilderCreateFunction(context->debug.builder, context->debug.function = LLVMDIBuilderCreateFunction(context->debug.builder,
context->debug.compile_unit, context->debug.compile_unit,
decl->name.string, decl->name.span.length, decl->name, source_range_len(decl->name_span),
decl->name.string, decl->name.span.length, decl->name, source_range_len(decl->name_span),
context->debug.file, context->debug.file,
decl_position.line, decl_position.line,
decl->type->backend_debug_type, decl->type->backend_debug_type,
@@ -228,7 +228,6 @@ void gencontext_emit_extern_decl(GenContext *context, Decl *decl)
case DECL_ARRAY_VALUE: case DECL_ARRAY_VALUE:
case DECL_IMPORT: case DECL_IMPORT:
case DECL_MACRO: case DECL_MACRO:
case DECL_MULTI_DECL:
case DECL_GENERIC: case DECL_GENERIC:
case DECL_CT_IF: case DECL_CT_IF:
case DECL_CT_ELSE: case DECL_CT_ELSE:

View File

@@ -72,7 +72,9 @@ typedef struct
void gencontext_begin_module(GenContext *context); void gencontext_begin_module(GenContext *context);
void gencontext_end_module(GenContext *context); void gencontext_end_module(GenContext *context);
void gencontext_emit_stmt(GenContext *context, Ast *ast); void gencontext_emit_stmt(GenContext *context, Ast *ast);
void gencontext_emit_defer(GenContext *context, DeferList defer_list);
LLVMValueRef gencontext_emit_expr(GenContext *context, Expr *expr); LLVMValueRef gencontext_emit_expr(GenContext *context, Expr *expr);
LLVMValueRef gencontext_emit_ast_expr(GenContext *context, Ast *expr);
LLVMMetadataRef gencontext_get_debug_type(GenContext *context, Type *type); 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, SourceRange location);
LLVMMetadataRef gencontext_create_builtin_debug_type(GenContext *context, Type *builtin_type); LLVMMetadataRef gencontext_create_builtin_debug_type(GenContext *context, Type *builtin_type);

View File

@@ -22,7 +22,7 @@ static LLVMValueRef gencontext_emit_decl(GenContext *context, Ast *ast)
{ {
Decl *decl = ast->declare_stmt; Decl *decl = ast->declare_stmt;
decl->var.backend_ref = gencontext_emit_alloca(context, BACKEND_TYPE(decl->type), decl->name.string); decl->var.backend_ref = gencontext_emit_alloca(context, BACKEND_TYPE(decl->type), decl->name);
// TODO NRVO // TODO NRVO
// TODO debug info // TODO debug info
/* /*
@@ -99,6 +99,13 @@ static inline void gencontext_emit_return(GenContext *context, Ast *ast)
{ {
// Ensure we are on a branch that is non empty. // Ensure we are on a branch that is non empty.
if (!gencontext_check_block_branch_emit(context)) return; if (!gencontext_check_block_branch_emit(context)) return;
Ast *defer = ast->return_stmt.defer;
while (defer)
{
gencontext_emit_stmt(context, defer->defer_stmt.body);
// TODO boolean
defer = defer->defer_stmt.prev_defer;
}
if (!ast->return_stmt.expr) if (!ast->return_stmt.expr)
{ {
LLVMBuildRetVoid(context->builder); LLVMBuildRetVoid(context->builder);
@@ -109,7 +116,6 @@ static inline void gencontext_emit_return(GenContext *context, Ast *ast)
context->current_block = NULL; context->current_block = NULL;
LLVMBasicBlockRef post_ret_block = gencontext_create_free_block(context, "ret"); LLVMBasicBlockRef post_ret_block = gencontext_create_free_block(context, "ret");
gencontext_emit_block(context, post_ret_block); gencontext_emit_block(context, post_ret_block);
} }
@@ -219,6 +225,7 @@ void gencontext_emit_for_stmt(GenContext *context, Ast *ast)
gencontext_emit_br(context, cond_block); gencontext_emit_br(context, cond_block);
gencontext_emit_block(context, cond_block); gencontext_emit_block(context, cond_block);
value = gencontext_emit_expr(context, ast->for_stmt.cond); value = gencontext_emit_expr(context, ast->for_stmt.cond);
gencontext_emit_defer(context, ast->for_stmt.cond_defer);
// If we have a body, conditionally jump to it. // If we have a body, conditionally jump to it.
if (body_block) if (body_block)
{ {
@@ -251,7 +258,7 @@ void gencontext_emit_for_stmt(GenContext *context, Ast *ast)
{ {
// Emit the block // Emit the block
gencontext_emit_block(context, inc_block); gencontext_emit_block(context, inc_block);
gencontext_emit_expr(context, ast->for_stmt.incr); gencontext_emit_expr(context, ast->for_stmt.incr->expr_stmt);
} }
// Loop back. // Loop back.
@@ -451,11 +458,23 @@ void gencontext_emit_switch(GenContext *context, Ast *ast)
gencontext_emit_block(context, exit_block); gencontext_emit_block(context, exit_block);
} }
void gencontext_emit_defer(GenContext *context, DeferList defer_list)
{
if (defer_list.start == defer_list.end) return;
Ast *defer = context->ast_context->defers[defer_list.start - 1];
while (defer && defer->defer_stmt.id != defer_list.end)
{
gencontext_emit_stmt(context, defer->defer_stmt.body);
// TODO boolean
}
}
void gencontext_emit_stmt(GenContext *context, Ast *ast) void gencontext_emit_stmt(GenContext *context, Ast *ast)
{ {
switch (ast->ast_kind) switch (ast->ast_kind)
{ {
case AST_FUNCTION_BLOCK_STMT:
TODO
case AST_POISONED: case AST_POISONED:
UNREACHABLE UNREACHABLE
case AST_EXPR_STMT: case AST_EXPR_STMT:
@@ -495,9 +514,9 @@ void gencontext_emit_stmt(GenContext *context, Ast *ast)
gencontext_emit_jmp(context, context->break_continue_stack[context->break_continue_stack_index - 1].next_block); gencontext_emit_jmp(context, context->break_continue_stack[context->break_continue_stack_index - 1].next_block);
break; break;
case AST_NOP_STMT: case AST_NOP_STMT:
case AST_DEFER_STMT:
break; break;
case AST_CATCH_STMT: case AST_CATCH_STMT:
case AST_DEFER_STMT:
case AST_TRY_STMT: case AST_TRY_STMT:
case AST_THROW_STMT: case AST_THROW_STMT:
// Should have been lowered. // Should have been lowered.

View File

@@ -15,7 +15,6 @@ static inline LLVMTypeRef gencontext_create_llvm_type_from_decl(GenContext *cont
case DECL_ENUM_CONSTANT: case DECL_ENUM_CONSTANT:
case DECL_POISONED: case DECL_POISONED:
case DECL_GENERIC: case DECL_GENERIC:
case DECL_MULTI_DECL:
case DECL_MACRO: case DECL_MACRO:
case DECL_CT_IF: case DECL_CT_IF:
case DECL_CT_ELSE: case DECL_CT_ELSE:

File diff suppressed because it is too large Load Diff

View File

@@ -67,7 +67,7 @@ Decl *sema_resolve_symbol(Context *context, const char *symbol, Path *path, Decl
Decl **current = context->last_local - 1; Decl **current = context->last_local - 1;
while (current >= first) while (current >= first)
{ {
if (current[0]->name.string == symbol) return current[0]; if (current[0]->name == symbol) return current[0];
current--; current--;
} }
} }
@@ -108,7 +108,7 @@ Decl *sema_resolve_symbol(Context *context, const char *symbol, Path *path, Decl
bool sema_add_local(Context *context, Decl *decl) bool sema_add_local(Context *context, Decl *decl)
{ {
Decl *dummy; Decl *dummy;
Decl *other = sema_resolve_symbol(context, decl->name.string, NULL, &dummy); Decl *other = sema_resolve_symbol(context, decl->name, NULL, &dummy);
if (other) if (other)
{ {
sema_shadow_error(decl, other); sema_shadow_error(decl, other);
@@ -120,7 +120,7 @@ bool sema_add_local(Context *context, Decl *decl)
unsigned num_vars = vec_size(*vars); unsigned num_vars = vec_size(*vars);
if (num_vars == MAX_LOCALS - 1 || context->last_local == &context->locals[MAX_LOCALS - 1]) if (num_vars == MAX_LOCALS - 1 || context->last_local == &context->locals[MAX_LOCALS - 1])
{ {
SEMA_ERROR(decl->name, "Reached the maximum number of locals."); SEMA_ERROR(decl, "Reached the maximum number of locals.");
return false; return false;
} }
decl->var.id = num_vars; decl->var.id = num_vars;

View File

@@ -6,6 +6,12 @@
typedef bool(*AstAnalysis)(Context *, Ast*); typedef bool(*AstAnalysis)(Context *, Ast*);
static inline DeferId defer_id_from_ast(Ast *ast)
{
if (!ast) return 0;
assert(ast->ast_kind == AST_DEFER_STMT);
return ast->defer_stmt.id;
}
static inline Type *ast_cond_type(Ast *ast) static inline Type *ast_cond_type(Ast *ast)
{ {
assert(ast->ast_kind == AST_DECL_EXPR_LIST); assert(ast->ast_kind == AST_DECL_EXPR_LIST);
@@ -21,47 +27,11 @@ static inline Type *ast_cond_type(Ast *ast)
} }
} }
void sema_init(File *file)
{
}
void sema_shadow_error(Decl *decl, Decl *old) void sema_shadow_error(Decl *decl, Decl *old)
{ {
sema_error_range(decl->name.span, "The '%s' would shadow a previous declaration.", decl->name.string); SEMA_ERROR(decl, "The '%s' would shadow a previous declaration.", decl->name);
sema_prev_at_range(old->name.span, "The previous use of '%s' was here.", decl->name.string); SEMA_PREV(old, "The previous use of '%s' was here.", decl->name);
}
Decl *context_find_ident(Context *context, const char *symbol)
{
Decl **first = &context->locals[0];
Decl **current = context->last_local - 1;
while (current >= first)
{
if (current[0]->name.string == symbol) return current[0];
current--;
}
Decl *found = module_find_symbol(context->module, symbol, MODULE_SYMBOL_SEARCH_THIS);
if (found) return found;
Decl *symbol_found = NULL;
VECEACH(context->imports, i)
{
Decl *import = context->imports[i];
// Partial imports
if (import->import.symbol.string && import->import.symbol.string != symbol) continue;
Decl *decl = module_find_symbol(import->module, symbol, MODULE_SYMBOL_SEARCH_EXTERNAL);
if (!decl) continue;
if (symbol_found)
{
symbol_found = NULL;
continue;
}
symbol_found = decl;
}
return symbol_found;
} }
@@ -72,10 +42,12 @@ static inline void context_push_scope_with_flags(Context *context, ScopeFlags fl
FATAL_ERROR("Too deeply nested scopes."); FATAL_ERROR("Too deeply nested scopes.");
} }
ScopeFlags previous_flags = context->current_scope->flags; ScopeFlags previous_flags = context->current_scope->flags;
DeferId parent_defer = context->current_scope->defer_last;
context->current_scope++; context->current_scope++;
context->current_scope->exit = EXIT_NONE; context->current_scope->exit = EXIT_NONE;
context->current_scope->local_decl_start = context->last_local; context->current_scope->local_decl_start = context->last_local;
context->current_scope->defer_start = vec_size(context->defers); context->current_scope->defer_top = parent_defer;
context->current_scope->defer_last = parent_defer;
context->current_scope->flags = previous_flags | flags; context->current_scope->flags = previous_flags | flags;
context->current_scope->flags_created = flags; context->current_scope->flags_created = flags;
} }
@@ -85,14 +57,15 @@ static inline void context_push_scope(Context *context)
context_push_scope_with_flags(context, SCOPE_NONE); context_push_scope_with_flags(context, SCOPE_NONE);
} }
static inline void context_pop_scope(Context *context) static inline void context_pop_scope(Context *context, Ast **ast, Expr **expr)
{ {
assert(context->current_scope != &context->scopes[0]); assert(context->current_scope != &context->scopes[0]);
context->last_local = context->current_scope->local_decl_start; context->last_local = context->current_scope->local_decl_start;
assert(vec_size(context->defers) == context->current_scope->defer_start);
ExitType exit_type = context->current_scope->exit; ExitType exit_type = context->current_scope->exit;
vec_resize(context->defers, context->current_scope->defer_start); if (context->current_scope->defer_top != context->current_scope->defer_last)
{
TODO;
}
context->current_scope--; context->current_scope--;
if (context->current_scope->exit < exit_type) if (context->current_scope->exit < exit_type)
{ {
@@ -113,26 +86,6 @@ static bool sema_resolve_ptr_type(Context *context, TypeInfo *type_info)
return true; return true;
} }
static void sema_build_defer_chain(Context *context, Ast ***statement_list)
{
unsigned size = vec_size(context->defers);
unsigned start = context->current_scope->defer_start;
for (unsigned i = size; i > start; i--)
{
vec_add(*statement_list, context->defers[i - 1]);
}
}
static void sema_release_defer_chain(Context *context, Ast ***statement_list)
{
unsigned size = vec_size(context->defers);
unsigned start = context->current_scope->defer_start;
for (unsigned i = size; i > start; i--)
{
vec_add(*statement_list, context->defers[i - 1]->defer_stmt.body);
}
vec_resize(context->defers, start);
}
static bool sema_resolve_array_type(Context *context, TypeInfo *type) static bool sema_resolve_array_type(Context *context, TypeInfo *type)
{ {
@@ -145,7 +98,7 @@ static bool sema_resolve_array_type(Context *context, TypeInfo *type)
if (!sema_analyse_expr(context, type_usize, type->array.len)) return type_info_poison(type); if (!sema_analyse_expr(context, type_usize, type->array.len)) return type_info_poison(type);
if (type->array.len->expr_kind != EXPR_CONST) if (type->array.len->expr_kind != EXPR_CONST)
{ {
SEMA_ERROR(type->array.len->loc, "Expected a constant value as array size."); SEMA_ERROR(type->array.len, "Expected a constant value as array size.");
return type_info_poison(type); return type_info_poison(type);
} }
} }
@@ -195,7 +148,7 @@ static inline bool sema_analyse_struct_member(Context *context, Decl *decl)
static inline bool sema_analyse_struct_union(Context *context, Decl *decl) static inline bool sema_analyse_struct_union(Context *context, Decl *decl)
{ {
DEBUG_LOG("Beginning analysis of %s.", decl->name.string); DEBUG_LOG("Beginning analysis of %s.", decl->name);
assert(decl->decl_kind == DECL_STRUCT || decl->decl_kind == DECL_UNION); assert(decl->decl_kind == DECL_STRUCT || decl->decl_kind == DECL_UNION);
VECEACH(decl->strukt.members, i) VECEACH(decl->strukt.members, i)
{ {
@@ -233,7 +186,7 @@ static inline bool sema_analyse_function_param(Context *context, Decl *param, bo
param->type = param->var.type_info->type; param->type = param->var.type_info->type;
if (param->var.init_expr && !is_function) if (param->var.init_expr && !is_function)
{ {
SEMA_ERROR(param->var.init_expr->loc, "Function types may not have default arguments."); SEMA_ERROR(param->var.init_expr, "Function types may not have default arguments.");
return false; return false;
} }
if (param->var.init_expr) if (param->var.init_expr)
@@ -242,7 +195,7 @@ static inline bool sema_analyse_function_param(Context *context, Decl *param, bo
if (!sema_analyse_expr(context, param->type, expr)) return false; if (!sema_analyse_expr(context, param->type, expr)) return false;
if (expr->expr_kind != EXPR_CONST) if (expr->expr_kind != EXPR_CONST)
{ {
SEMA_ERROR(expr->loc, "Only constant expressions may be used as default values."); SEMA_ERROR(expr, "Only constant expressions may be used as default values.");
return false; return false;
} }
} }
@@ -260,7 +213,8 @@ static inline Type *sema_analyse_function_signature(Context *context, FunctionSi
type_append_signature_name(signature->rtype->type, buffer, &buffer_write_offset); type_append_signature_name(signature->rtype->type, buffer, &buffer_write_offset);
buffer[buffer_write_offset++] = '('; buffer[buffer_write_offset++] = '(';
} }
// TODO check parameter name appearing more than once. STable *names = &context->scratch_table;
stable_clear(names);
VECEACH(signature->params, i) VECEACH(signature->params, i)
{ {
Decl *param = signature->params[i]; Decl *param = signature->params[i];
@@ -278,8 +232,26 @@ static inline Type *sema_analyse_function_signature(Context *context, FunctionSi
buffer[buffer_write_offset++] = ','; buffer[buffer_write_offset++] = ',';
} }
type_append_signature_name(param->var.type_info->type, buffer, &buffer_write_offset); type_append_signature_name(param->var.type_info->type, buffer, &buffer_write_offset);
if (param->name)
{
Decl *prev = stable_set(names, param->name, param);
if (prev)
{
SEMA_ERROR(param, "Duplicate parameter name %s.", param->name);
SEMA_PREV(prev, "Previous use of the name was here.");
decl_poison(prev);
decl_poison(param);
all_ok = false;
}
}
}
if (signature->variadic)
{
buffer[buffer_write_offset++] = ',';
buffer[buffer_write_offset++] = '.';
buffer[buffer_write_offset++] = '.';
buffer[buffer_write_offset++] = '.';
} }
// TODO variadic
buffer[buffer_write_offset++] = ')'; buffer[buffer_write_offset++] = ')';
if (vec_size(signature->throws)) if (vec_size(signature->throws))
{ {
@@ -335,6 +307,7 @@ static inline bool sema_analyse_return_stmt(Context *context, Ast *statement)
context->current_scope->exit = EXIT_RETURN; context->current_scope->exit = EXIT_RETURN;
Type *expected_rtype = context->rtype; Type *expected_rtype = context->rtype;
Expr *return_expr = statement->return_stmt.expr; Expr *return_expr = statement->return_stmt.expr;
statement->return_stmt.defer = VECLAST(context->defers);
if (return_expr == NULL) if (return_expr == NULL)
{ {
if (!expected_rtype) if (!expected_rtype)
@@ -345,7 +318,7 @@ static inline bool sema_analyse_return_stmt(Context *context, Ast *statement)
} }
if (expected_rtype->canonical != type_void) if (expected_rtype->canonical != type_void)
{ {
SEMA_ERROR(statement->token, "Expected to return a result of type %s.", type_to_error_string(expected_rtype)); SEMA_ERROR(statement, "Expected to return a result of type %s.", type_to_error_string(expected_rtype));
return false; return false;
} }
return true; return true;
@@ -382,7 +355,7 @@ static inline bool sema_analyse_var_decl(Context *context, Decl *decl)
static inline Ast *convert_expr_to_ast(Expr *expr) static inline Ast *convert_expr_to_ast(Expr *expr)
{ {
Ast *ast = new_ast(AST_EXPR_STMT, expr->loc); Ast *ast = AST_NEW(AST_EXPR_STMT, expr->span);
ast->expr_stmt = expr; ast->expr_stmt = expr;
return ast; return ast;
} }
@@ -391,9 +364,9 @@ static inline Expr *convert_decl_to_expr(Context *context, Decl *decl)
assert(decl->decl_kind == DECL_VAR); assert(decl->decl_kind == DECL_VAR);
assert(decl->decl_kind == VARDECL_LOCAL); assert(decl->decl_kind == VARDECL_LOCAL);
if (!decl->var.init_expr) return NULL; if (!decl->var.init_expr) return NULL;
Expr *assign_expr = expr_new(EXPR_BINARY, decl->name); Expr *assign_expr = expr_new(EXPR_BINARY, decl->span);
assign_expr->resolve_status = RESOLVE_DONE; assign_expr->resolve_status = RESOLVE_DONE;
Expr *identifier = expr_new(EXPR_IDENTIFIER, decl->name); Expr *identifier = expr_new(EXPR_IDENTIFIER, decl->span);
identifier->resolve_status = RESOLVE_DONE; identifier->resolve_status = RESOLVE_DONE;
identifier->identifier_expr.identifier = decl->name; identifier->identifier_expr.identifier = decl->name;
identifier->identifier_expr.decl = decl; identifier->identifier_expr.decl = decl;
@@ -413,7 +386,7 @@ static inline bool convert_decl_for_cond(Context *context, Decl *decl, Ast*** st
{ {
if (is_last) if (is_last)
{ {
SEMA_ERROR(decl->name, "Expected an initializer for '%s'.", decl->name.string); SEMA_ERROR(decl, "Expected an initializer for '%s'.", decl->name);
return false; return false;
} }
// Simply skip declarations if they don't have an initializer, since they're already registered anyway. // Simply skip declarations if they don't have an initializer, since they're already registered anyway.
@@ -431,52 +404,10 @@ static inline bool convert_decl_for_cond(Context *context, Decl *decl, Ast*** st
return true; return true;
} }
static inline bool convert_stmt_for_cond(Context *context, Ast *stmt, Ast*** stmt_list, Expr** last, bool is_last)
static inline bool sema_analyse_function_block_stmt(Context *context, Ast *stmt)
{ {
if (stmt->ast_kind == AST_EXPR_STMT) TODO
{
if (is_last)
{
*last = stmt->expr_stmt;
return true;
}
*stmt_list = VECADD(*stmt_list, stmt);
return true;
}
assert(stmt->ast_kind == AST_DECLARE_STMT);
Decl *decl = stmt->declare_stmt;
if (decl->decl_kind != DECL_MULTI_DECL)
{
return convert_decl_for_cond(context, decl, stmt_list, last, is_last);
}
Decl **decls = decl->multi_decl;
assert(vec_size(decls) > 0);
unsigned last_element = vec_size(decls) - 1;
for (unsigned i = 0; i <= last_element; i++)
{
Decl *sub_decl = decls[i];
if (!convert_decl_for_cond(context, sub_decl, stmt_list, last, is_last && last_element == i)) return false;
}
return true;
}
static inline bool decl_or_expr_to_expr_stmt(Context *context, Ast *stmt)
{
if (stmt->ast_kind == AST_EXPR_STMT) return true;
assert(stmt->ast_kind == AST_DECLARE_STMT);
stmt->ast_kind = AST_EXPR_STMT;
Decl *decl = stmt->declare_stmt;
assert(decl->decl_kind == DECL_VAR);
assert(decl->decl_kind == VARDECL_LOCAL);
if (decl->var.init_expr == NULL)
{
SEMA_ERROR(decl->name, "'%s' needs to be assigned.", decl->name.string);
return false;
}
stmt->expr_stmt = decl->var.init_expr;
return true;
} }
static inline bool sema_analyse_decl_expr_list(Context *context, Ast *stmt) static inline bool sema_analyse_decl_expr_list(Context *context, Ast *stmt)
@@ -498,7 +429,7 @@ static inline bool sema_analyse_cond(Context *context, Ast *stmt, bool cast_to_b
size_t size = vec_size(stmt->decl_expr_stmt); size_t size = vec_size(stmt->decl_expr_stmt);
if (!size) if (!size)
{ {
SEMA_ERROR(stmt->token, "Expected a boolean expression"); SEMA_ERROR(stmt, "Expected a boolean expression");
return false; return false;
} }
@@ -518,13 +449,13 @@ static inline bool sema_analyse_cond(Context *context, Ast *stmt, bool cast_to_b
Expr *init = last->declare_stmt->var.init_expr; Expr *init = last->declare_stmt->var.init_expr;
if (!init) if (!init)
{ {
SEMA_ERROR(last->token, "Expected a declaration with initializer."); SEMA_ERROR(last, "Expected a declaration with initializer.");
return false; return false;
} }
if (cast_to_bool && init->type->type_kind != TYPE_BOOL && if (cast_to_bool && init->type->type_kind != TYPE_BOOL &&
cast_to_bool_kind(last->declare_stmt->var.type_info->type) == CAST_ERROR) cast_to_bool_kind(last->declare_stmt->var.type_info->type) == CAST_ERROR)
{ {
SEMA_ERROR(last->declare_stmt->var.init_expr->loc, "The expression needs to be convertible to a boolean."); SEMA_ERROR(last->declare_stmt->var.init_expr, "The expression needs to be convertible to a boolean.");
return false; return false;
} }
return true; return true;
@@ -539,14 +470,15 @@ static inline bool sema_analyse_while_stmt(Context *context, Ast *statement)
Ast *decl = statement->while_stmt.decl; Ast *decl = statement->while_stmt.decl;
Ast *cond = statement->while_stmt.cond; Ast *cond = statement->while_stmt.cond;
Ast *body = statement->while_stmt.body; Ast *body = statement->while_stmt.body;
context_push_scope_with_flags(context, SCOPE_CONTROL); context_push_scope(context);
bool success = !decl || sema_analyse_statement(context, decl); bool success = !decl || sema_analyse_statement(context, decl);
context_push_scope(context);
success = success && sema_analyse_cond(context, cond, true); success = success && sema_analyse_cond(context, cond, true);
context_push_scope_with_flags(context, SCOPE_BREAK | SCOPE_CONTINUE); // NOLINT(hicpp-signed-bitwise) context_push_scope_with_flags(context, SCOPE_BREAK | SCOPE_CONTINUE); // NOLINT(hicpp-signed-bitwise)
success = success && sema_analyse_statement(context, body); success = success && sema_analyse_statement(context, body);
context_pop_scope(context); context_pop_scope(context, &body, NULL);
context_pop_scope(context); context_pop_scope(context, &cond, NULL);
context_pop_scope(context, &decl, NULL);
if (!success) return false; if (!success) return false;
return success; return success;
} }
@@ -558,28 +490,15 @@ static inline bool sema_analyse_do_stmt(Context *context, Ast *statement)
bool success; bool success;
context_push_scope_with_flags(context, SCOPE_BREAK | SCOPE_CONTINUE); // NOLINT(hicpp-signed-bitwise) context_push_scope_with_flags(context, SCOPE_BREAK | SCOPE_CONTINUE); // NOLINT(hicpp-signed-bitwise)
success = sema_analyse_statement(context, body); success = sema_analyse_statement(context, body);
context_pop_scope(context); context_pop_scope(context, &body, NULL);
if (!success) return false; if (!success) return false;
context_push_scope_with_flags(context, SCOPE_CONTROL); context_push_scope(context);
success = sema_analyse_expr(context, type_bool, expr); success = sema_analyse_expr(context, type_bool, expr);
context_pop_scope(context); context_pop_scope(context, NULL, &expr);
return success; return success;
} }
static inline bool sema_analyse_multi_decl(Context *context, Ast *statement)
{
Decl *decl = statement->declare_stmt;
VECEACH(statement->declare_stmt->multi_decl, i)
{
if (!sema_analyse_var_decl(context, statement->declare_stmt->multi_decl[i]))
{
decl_poison(decl);
return false;
}
}
return true;
}
static inline bool sema_analyse_declare_stmt(Context *context, Ast *statement) static inline bool sema_analyse_declare_stmt(Context *context, Ast *statement)
{ {
@@ -601,34 +520,57 @@ static inline bool sema_analyse_defer_stmt(Context *context, Ast *statement)
bool success = sema_analyse_statement(context, statement->defer_stmt.body); bool success = sema_analyse_statement(context, statement->defer_stmt.body);
context_pop_scope(context); context_pop_scope(context, &statement->defer_stmt.body, NULL);
if (!success) return false; if (!success) return false;
statement->defer_stmt.prev_defer = VECLAST(context->defers);
vec_add(context->defers, statement); vec_add(context->defers, statement);
statement->defer_stmt.id = vec_size(context->defers);
return true; return true;
} }
static inline bool sema_analyse_default_stmt(Context *context, Ast *statement) static inline bool sema_analyse_default_stmt(Context *context, Ast *statement)
{ {
SEMA_ERROR(statement->token, "Unexpected 'default' outside of switch"); SEMA_ERROR(statement, "Unexpected 'default' outside of switch");
return false; return false;
} }
static inline bool sema_analyse_for_stmt(Context *context, Ast *statement) static inline bool sema_analyse_for_stmt(Context *context, Ast *statement)
{ {
context_push_scope_with_flags(context, SCOPE_CONTROL); bool success = true;
bool success = !statement->for_stmt.init || sema_analyse_statement(context, statement->for_stmt.init); // Enter for scope
context_push_scope(context);
success = success && (!statement->for_stmt.cond || sema_analyse_expr(context, type_bool, statement->for_stmt.cond)); if (statement->for_stmt.init)
success = success && (!statement->for_stmt.incr || sema_analyse_expr(context, NULL, statement->for_stmt.incr)); {
context_pop_scope(context); success = sema_analyse_statement(context, statement->for_stmt.init);
}
if (success && statement->for_stmt.cond)
{
// Conditional scope start
context_push_scope(context);
success = sema_analyse_expr(context, type_bool, statement->for_stmt.cond);
// Conditional scope end
context_pop_scope(context, NULL, &statement->for_stmt.cond);
}
if (success && statement->for_stmt.incr)
{
// Incr scope start
context_push_scope(context);
success = sema_analyse_statement(context, statement->for_stmt.incr);
// Incr scope end
context_pop_scope(context, &statement->for_stmt.incr, NULL);
}
if (!success) return false; if (!success) return false;
// Create the for body scope.
context_push_scope_with_flags(context, SCOPE_BREAK | SCOPE_CONTINUE); // NOLINT(hicpp-signed-bitwise) context_push_scope_with_flags(context, SCOPE_BREAK | SCOPE_CONTINUE); // NOLINT(hicpp-signed-bitwise)
success = sema_analyse_statement(context, statement->for_stmt.body); success = sema_analyse_statement(context, statement->for_stmt.body);
context_pop_scope(context); // End for body scope
context_pop_scope(context, &statement->for_stmt.body, NULL);
// End for scope
context_pop_scope(context, &statement, NULL);
return success; return success;
} }
@@ -637,7 +579,7 @@ static inline bool sema_analyse_goto_stmt(Context *context, Ast *statement)
VECEACH(context->labels, i) VECEACH(context->labels, i)
{ {
Ast *label = context->labels[i]; Ast *label = context->labels[i];
if (statement->token.string == label->token.string) if (statement->goto_stmt.label_name == label->label_stmt.name)
{ {
statement->goto_stmt.type = GOTO_JUMP_BACK; statement->goto_stmt.type = GOTO_JUMP_BACK;
label->label_stmt.is_used = true; label->label_stmt.is_used = true;
@@ -655,21 +597,34 @@ static inline bool sema_analyse_if_stmt(Context *context, Ast *statement)
// if (!x) A(); else B(); // if (!x) A(); else B();
// into // into
// if (x) B(); else A(); // if (x) B(); else A();
context_push_scope(context);
Ast *cond = statement->if_stmt.cond; Ast *cond = statement->if_stmt.cond;
context_push_scope_with_flags(context, SCOPE_CONTROL); context_push_scope(context);
bool success = sema_analyse_cond(context, cond, true); bool success = sema_analyse_cond(context, cond, true);
if (statement->if_stmt.else_body)
{
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.");
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.");
success = false;
}
}
context_push_scope(context); context_push_scope(context);
success = success && sema_analyse_statement(context, statement->if_stmt.then_body); success = success && sema_analyse_statement(context, statement->if_stmt.then_body);
context_pop_scope(context); context_pop_scope(context, &statement->if_stmt.then_body, NULL);
// TODO null flowcheck // TODO null flowcheck
if (statement->if_stmt.else_body) if (statement->if_stmt.else_body)
{ {
context_push_scope(context); context_push_scope(context);
success = success && sema_analyse_statement(context, statement->if_stmt.else_body); success = success && sema_analyse_statement(context, statement->if_stmt.else_body);
context_pop_scope(context); context_pop_scope(context, &statement->if_stmt.else_body, NULL);
} }
context_pop_scope(context); context_pop_scope(context, &statement, NULL);
return success; return success;
} }
@@ -678,10 +633,10 @@ static inline bool sema_analyse_label(Context *context, Ast *statement)
VECEACH(context->labels, i) VECEACH(context->labels, i)
{ {
Ast *label = context->labels[i]; Ast *label = context->labels[i];
if (label->token.string == statement->token.string) if (label->label_stmt.name == statement->label_stmt.name)
{ {
SEMA_ERROR(tok, "This duplicate label '%s'.", statement->token.string); SEMA_ERROR(statement, "This duplicate label '%s'.", statement->label_stmt.name);
sema_prev_at_range(label->token.span, "The previous declaration was here."); sema_prev_at_range(label->span, "The previous declaration was here.");
ast_poison(label); ast_poison(label);
ast_poison(statement); ast_poison(statement);
return false; return false;
@@ -691,7 +646,7 @@ static inline bool sema_analyse_label(Context *context, Ast *statement)
VECEACH(context->gotos, i) VECEACH(context->gotos, i)
{ {
Ast *the_goto = context->gotos[i]; Ast *the_goto = context->gotos[i];
if (the_goto->token.string == statement->token.string) if (the_goto->goto_stmt.label_name == statement->label_stmt.name)
{ {
the_goto->goto_stmt.type = GOTO_JUMP_FORWARD; the_goto->goto_stmt.type = GOTO_JUMP_FORWARD;
the_goto->goto_stmt.label = statement; the_goto->goto_stmt.label = statement;
@@ -723,7 +678,7 @@ static bool sema_analyse_break_stmt(Context *context, Ast *statement)
{ {
if (!(context->current_scope->flags & SCOPE_BREAK)) // NOLINT(hicpp-signed-bitwise) if (!(context->current_scope->flags & SCOPE_BREAK)) // NOLINT(hicpp-signed-bitwise)
{ {
SEMA_ERROR(statement->token, "'break' is not allowed here."); SEMA_ERROR(statement, "'break' is not allowed here.");
return false; return false;
} }
return true; return true;
@@ -731,7 +686,7 @@ static bool sema_analyse_break_stmt(Context *context, Ast *statement)
static bool sema_analyse_case_stmt(Context *context, Ast *statement) static bool sema_analyse_case_stmt(Context *context, Ast *statement)
{ {
SEMA_ERROR(statement->token, "Unexpected 'case' outside of switch"); SEMA_ERROR(statement, "Unexpected 'case' outside of switch");
return false; return false;
} }
@@ -739,10 +694,9 @@ static bool sema_analyse_continue_stmt(Context *context, Ast *statement)
{ {
if (!(context->current_scope->flags & SCOPE_CONTINUE)) // NOLINT(hicpp-signed-bitwise) if (!(context->current_scope->flags & SCOPE_CONTINUE)) // NOLINT(hicpp-signed-bitwise)
{ {
SEMA_ERROR(statement->token, "'continue' is not allowed here."); SEMA_ERROR(statement, "'continue' is not allowed here.");
return false; return false;
} }
sema_build_defer_chain(context, &statement->continue_stmt.defers);
return true; return true;
} }
@@ -759,7 +713,7 @@ static int sema_check_comp_time_bool(Context *context, Expr *expr)
if (!sema_analyse_expr(context, type_bool, expr)) return -1; if (!sema_analyse_expr(context, type_bool, expr)) return -1;
if (expr->expr_kind != EXPR_CONST) if (expr->expr_kind != EXPR_CONST)
{ {
SEMA_ERROR(expr->loc, "$if requires a compile time constant value."); SEMA_ERROR(expr, "$if requires a compile time constant value.");
return -1; return -1;
} }
return expr->const_expr.b; return expr->const_expr.b;
@@ -807,14 +761,14 @@ static bool sema_analyse_switch_case(Context *context, Ast*** prev_cases, Ast *c
if (*prev_case) if (*prev_case)
{ {
// sema_build_defer_chain(context, prev_cases); // sema_build_defer_chain(context, prev_cases);
context_pop_scope(context); context_pop_scope(context, prev_case, NULL);
*prev_case = NULL; *prev_case = NULL;
} }
Expr *case_expr = case_stmt->case_stmt.expr; Expr *case_expr = case_stmt->case_stmt.expr;
if (!sema_analyse_expr(context, switch_type, case_expr)) return false; if (!sema_analyse_expr(context, switch_type, case_expr)) return false;
if (case_expr->expr_kind != EXPR_CONST) if (case_expr->expr_kind != EXPR_CONST)
{ {
SEMA_ERROR(case_expr->loc, "This must be a constant expression."); SEMA_ERROR(case_expr, "This must be a constant expression.");
return false; return false;
} }
assert(case_expr->const_expr.type == CONST_INT); assert(case_expr->const_expr.type == CONST_INT);
@@ -826,8 +780,8 @@ static bool sema_analyse_switch_case(Context *context, Ast*** prev_cases, Ast *c
{ {
if ((*prev_cases)[i]->case_stmt.val == val) if ((*prev_cases)[i]->case_stmt.val == val)
{ {
SEMA_ERROR(case_stmt->token, "Duplicate case value."); SEMA_ERROR(case_stmt, "Duplicate case value.");
sema_prev_at_range((*prev_cases)[i]->token.span, "Previous use was here."); sema_prev_at_range((*prev_cases)[i]->span, "Previous use was here.");
return false; return false;
} }
} }
@@ -842,7 +796,7 @@ static bool sema_analyse_switch_case(Context *context, Ast*** prev_cases, Ast *c
case_stmt->case_stmt.block = NULL; case_stmt->case_stmt.block = NULL;
if (*prev_case) if (*prev_case)
{ {
context_pop_scope(context); context_pop_scope(context, prev_case, NULL);
} }
context_push_scope(context); context_push_scope(context);
*prev_case = case_stmt; *prev_case = case_stmt;
@@ -851,7 +805,7 @@ static bool sema_analyse_switch_case(Context *context, Ast*** prev_cases, Ast *c
} }
if (!*prev_case) if (!*prev_case)
{ {
SEMA_ERROR(case_stmt->token, "Expected a 'case' or 'default' statement."); SEMA_ERROR(case_stmt, "Expected a 'case' or 'default' statement.");
return false; return false;
} }
if (case_stmt->ast_kind == AST_NEXT_STMT) if (case_stmt->ast_kind == AST_NEXT_STMT)
@@ -865,7 +819,7 @@ static bool sema_analyse_switch_case(Context *context, Ast*** prev_cases, Ast *c
} }
if (!(*prev_case)->case_stmt.block) if (!(*prev_case)->case_stmt.block)
{ {
(*prev_case)->case_stmt.block = new_ast(AST_COMPOUND_STMT, (*prev_case)->token); (*prev_case)->case_stmt.block = AST_NEW(AST_COMPOUND_STMT, (*prev_case)->span);
} }
vec_add((*prev_case)->case_stmt.block->compound_stmt.stmts, case_stmt); vec_add((*prev_case)->case_stmt.block->compound_stmt.stmts, case_stmt);
return true; return true;
@@ -873,7 +827,7 @@ static bool sema_analyse_switch_case(Context *context, Ast*** prev_cases, Ast *c
static bool sema_analyse_switch_stmt(Context *context, Ast *statement) static bool sema_analyse_switch_stmt(Context *context, Ast *statement)
{ {
context_push_scope_with_flags(context, SCOPE_CONTROL); context_push_scope(context);
bool success = sema_analyse_statement(context, statement->switch_stmt.cond); bool success = sema_analyse_statement(context, statement->switch_stmt.cond);
Ast *cond = statement->switch_stmt.cond; Ast *cond = statement->switch_stmt.cond;
success = success && sema_analyse_cond(context, cond, false); success = success && sema_analyse_cond(context, cond, false);
@@ -883,7 +837,7 @@ static bool sema_analyse_switch_stmt(Context *context, Ast *statement)
Type *switch_type = ast_cond_type(cond)->canonical; Type *switch_type = ast_cond_type(cond)->canonical;
if (!type_is_integer(switch_type)) if (!type_is_integer(switch_type))
{ {
SEMA_ERROR(cond->token, "Expected an integer or enum type, was '%s'.", type_to_error_string(switch_type)); SEMA_ERROR(cond, "Expected an integer or enum type, was '%s'.", type_to_error_string(switch_type));
return false; return false;
} }
Ast *in_case = NULL; Ast *in_case = NULL;
@@ -893,10 +847,10 @@ static bool sema_analyse_switch_stmt(Context *context, Ast *statement)
} }
if (in_case) if (in_case)
{ {
context_pop_scope(context); context_pop_scope(context, &in_case, NULL);
} }
context_pop_scope(context); context_pop_scope(context, &cond, NULL);
context_pop_scope(context); context_pop_scope(context, &statement, NULL);
return success; return success;
} }
@@ -923,52 +877,116 @@ static bool sema_analyse_compound_stmt(Context *context, Ast *statement)
{ {
context_push_scope(context); context_push_scope(context);
bool success = sema_analyse_compound_statement_no_scope(context, statement); bool success = sema_analyse_compound_statement_no_scope(context, statement);
context_pop_scope(context); context_pop_scope(context, &statement, NULL);
return success; return success;
} }
static AstAnalysis AST_ANALYSIS[AST_WHILE_STMT + 1] = static inline bool sema_analyse_statement_inner(Context *context, Ast *statement)
{ {
[AST_ASM_STMT] = &sema_analyse_asm_stmt, switch (statement->ast_kind)
[AST_ATTRIBUTE] = NULL, {
[AST_BREAK_STMT] = &sema_analyse_break_stmt, case AST_POISONED:
[AST_CASE_STMT] = &sema_analyse_case_stmt, return false;
[AST_CATCH_STMT] = &sema_analyse_catch_stmt, case AST_ATTRIBUTE:
[AST_COMPOUND_STMT] = &sema_analyse_compound_stmt, UNREACHABLE
[AST_CONTINUE_STMT] = &sema_analyse_continue_stmt, case AST_ASM_STMT:
[AST_CT_IF_STMT] = &sema_analyse_ct_if_stmt, return sema_analyse_asm_stmt(context, statement);
[AST_DECLARE_STMT] = &sema_analyse_declare_stmt, case AST_BREAK_STMT:
[AST_DEFAULT_STMT] = &sema_analyse_default_stmt, return sema_analyse_break_stmt(context, statement);
[AST_DEFER_STMT] = &sema_analyse_defer_stmt, case AST_CASE_STMT:
[AST_DO_STMT] = &sema_analyse_do_stmt, return sema_analyse_case_stmt(context, statement);
[AST_EXPR_STMT] = &sema_analyse_expr_stmt, case AST_CATCH_STMT:
[AST_FOR_STMT] = &sema_analyse_for_stmt, return sema_analyse_catch_stmt(context, statement);
[AST_GOTO_STMT] = &sema_analyse_goto_stmt, case AST_COMPOUND_STMT:
[AST_IF_STMT] = &sema_analyse_if_stmt, return sema_analyse_compound_stmt(context, statement);
[AST_LABEL] = &sema_analyse_label, case AST_CONTINUE_STMT:
[AST_NOP_STMT] = &sema_analyse_nop_stmt, return sema_analyse_continue_stmt(context, statement);
[AST_RETURN_STMT] = &sema_analyse_return_stmt, case AST_CT_IF_STMT:
[AST_SWITCH_STMT] = &sema_analyse_switch_stmt, return sema_analyse_ct_if_stmt(context, statement);
[AST_TRY_STMT] = &sema_analyse_try_stmt, case AST_DECLARE_STMT:
[AST_THROW_STMT] = &sema_analyse_throw_stmt, return sema_analyse_declare_stmt(context, statement);
[AST_NEXT_STMT] = NULL, // Never reached case AST_DEFAULT_STMT:
[AST_VOLATILE_STMT] = &sema_analyse_volatile_stmt, return sema_analyse_default_stmt(context, statement);
[AST_WHILE_STMT] = &sema_analyse_while_stmt, case AST_DEFER_STMT:
[AST_DECL_EXPR_LIST] = &sema_analyse_decl_expr_list, return sema_analyse_defer_stmt(context, statement);
}; case AST_DO_STMT:
return sema_analyse_do_stmt(context, statement);
case AST_EXPR_STMT:
return sema_analyse_expr_stmt(context, statement);
case AST_FOR_STMT:
return sema_analyse_for_stmt(context, statement);
case AST_GOTO_STMT:
return sema_analyse_goto_stmt(context, statement);
case AST_IF_STMT:
return sema_analyse_if_stmt(context, statement);
case AST_LABEL:
return sema_analyse_label(context, statement);
case AST_NOP_STMT:
return sema_analyse_nop_stmt(context, statement);
case AST_RETURN_STMT:
return sema_analyse_return_stmt(context, statement);
case AST_SWITCH_STMT:
return sema_analyse_switch_stmt(context, statement);
case AST_THROW_STMT:
return sema_analyse_throw_stmt(context, statement);
case AST_TRY_STMT:
return sema_analyse_try_stmt(context, statement);
case AST_NEXT_STMT:
UNREACHABLE
case AST_VOLATILE_STMT:
return sema_analyse_volatile_stmt(context, statement);
case AST_WHILE_STMT:
return sema_analyse_while_stmt(context, statement);
case AST_DECL_EXPR_LIST:
return sema_analyse_decl_expr_list(context, statement);
case AST_FUNCTION_BLOCK_STMT:
return sema_analyse_function_block_stmt(context, statement);
case AST_CT_ELIF_STMT:
case AST_CT_ELSE_STMT:
UNREACHABLE
case AST_CT_FOR_STMT:
case AST_CT_SWITCH_STMT:
case AST_CT_DEFAULT_STMT:
case AST_CT_CASE_STMT:
case AST_GENERIC_CASE_STMT:
case AST_GENERIC_DEFAULT_STMT:
TODO
}
}
bool sema_analyse_statement(Context *context, Ast *statement) bool sema_analyse_statement(Context *context, Ast *statement)
{ {
if (AST_ANALYSIS[statement->ast_kind](context, statement)) return true; if (sema_analyse_statement_inner(context, statement)) return true;
return ast_poison(statement); return ast_poison(statement);
} }
static inline int defer_depth(Ast *defer_stmt)
{
int depth = 0;
while (defer_stmt)
{
defer_stmt = defer_stmt->defer_stmt.prev_defer;
depth++;
}
return depth;
}
static inline void defer_list_walk_to_common_depth(Ast **defer_stmt, int this_depth, int other_depth)
{
int steps = this_depth - other_depth;
for (int i = 0; i < steps; i++)
{
*defer_stmt = (*defer_stmt)->defer_stmt.prev_defer;
}
}
static inline bool sema_analyse_function_body(Context *context, Decl *func) static inline bool sema_analyse_function_body(Context *context, Decl *func)
{ {
context->active_function_for_analysis = func; context->active_function_for_analysis = func;
context->rtype = func->func.function_signature.rtype->type; context->rtype = func->func.function_signature.rtype->type;
context->current_scope = &context->scopes[0]; context->current_scope = &context->scopes[0];
context->current_scope->local_decl_start = 0; // Clean out the current scope.
memset(context->current_scope, 0, sizeof(*context->current_scope));
context->labels = NULL; context->labels = NULL;
context->gotos = NULL; context->gotos = NULL;
context->last_local = &context->locals[0]; context->last_local = &context->locals[0];
@@ -985,13 +1003,54 @@ static inline bool sema_analyse_function_body(Context *context, Decl *func)
{ {
if (func->func.function_signature.rtype->type->canonical != type_void) if (func->func.function_signature.rtype->type->canonical != type_void)
{ {
SEMA_ERROR(func->name, "Missing return statement at the end of the function."); SEMA_ERROR(func, "Missing return statement at the end of the function.");
return false; return false;
} }
sema_release_defer_chain(context, &func->func.body->compound_stmt.stmts); }
VECEACH(context->gotos, i)
{
Ast *goto_stmt = context->gotos[i];
Ast *label_target = goto_stmt->goto_stmt.label;
if (!label_target)
{
SEMA_ERROR(goto_stmt, "Goto to a missing label %s.", goto_stmt->goto_stmt.label_name);
return false;
}
// If there are no defers, then that's fine.
if (!goto_stmt->goto_stmt.defer && !label_target->label_stmt.defer) continue;
// First we need to search for the common depth.
int label_depth = defer_depth(label_target->label_stmt.defer);
int goto_depth = defer_depth(goto_stmt->goto_stmt.defer);
Ast *common_depth_label = label_target->label_stmt.defer;
Ast *common_depth_goto = goto_stmt->goto_stmt.defer;
// Now walk up to the common depth.
defer_list_walk_to_common_depth(&common_depth_label, label_depth, goto_depth);
defer_list_walk_to_common_depth(&common_depth_goto, goto_depth, label_depth);
// We might still not match, so walk upwards until we have a match:
while (common_depth_goto != common_depth_label)
{
assert(common_depth_goto && common_depth_label);
common_depth_goto = common_depth_goto->defer_stmt.prev_defer;
common_depth_label = common_depth_label->defer_stmt.prev_defer;
}
// We now know the top defer (which we won't actually generate)
goto_stmt->goto_stmt.defer_end = common_depth_goto;
// Mark all defers that occur on the way "up" to the common depth conditional.
Ast *current = label_target->label_stmt.defer;
while (current != common_depth_goto)
{
current->defer_stmt.emit_boolean = true;
}
} }
func->func.labels = context->labels; func->func.labels = context->labels;
context_pop_scope(context); context_pop_scope(context, &func->func.body, NULL);
context->current_scope = NULL; context->current_scope = NULL;
return true; return true;
} }
@@ -1003,28 +1062,28 @@ static inline bool sema_analyse_method_function(Context *context, Decl *decl)
if (!sema_resolve_type_info(context, parent_type)) return false; if (!sema_resolve_type_info(context, parent_type)) return false;
if (!type_may_have_method_functions(parent_type->type)) if (!type_may_have_method_functions(parent_type->type))
{ {
SEMA_ERROR(decl->name, "Method functions can not be associated with '%s'", type_to_error_string(decl->func.type_parent->type)); SEMA_ERROR(decl, "Method functions can not be associated with '%s'", type_to_error_string(decl->func.type_parent->type));
return false; return false;
} }
Decl *parent = parent_type->type->decl; Decl *parent = parent_type->type->decl;
VECEACH(parent->method_functions, i) VECEACH(parent->method_functions, i)
{ {
Decl *function = parent->method_functions[i]; Decl *function = parent->method_functions[i];
if (function->name.string == decl->name.string) if (function->name == decl->name)
{ {
SEMA_ERROR(decl->name, "Duplicate name '%s' for method function.", function->name); SEMA_ERROR(decl, "Duplicate name '%s' for method function.", function->name);
sema_prev_at_range(function->name.span, "Previous definition here."); SEMA_PREV(function, "Previous definition here.");
return false; return false;
} }
} }
DEBUG_LOG("Method function '%s.%s' analysed.", parent->name.string, decl->name.string); DEBUG_LOG("Method function '%s.%s' analysed.", parent->name, decl->name);
vec_add(parent->method_functions, decl); vec_add(parent->method_functions, decl);
return true; return true;
} }
static inline bool sema_analyse_func(Context *context, Decl *decl) static inline bool sema_analyse_func(Context *context, Decl *decl)
{ {
DEBUG_LOG("Analysing function %s", decl->name.string); DEBUG_LOG("Analysing function %s", decl->name);
Type *func_type = sema_analyse_function_signature(context, &decl->func.function_signature, true); Type *func_type = sema_analyse_function_signature(context, &decl->func.function_signature, true);
decl->type = func_type; decl->type = func_type;
if (!func_type) return decl_poison(decl); if (!func_type) return decl_poison(decl);
@@ -1033,11 +1092,11 @@ static inline bool sema_analyse_func(Context *context, Decl *decl)
if (!sema_analyse_method_function(context, decl)) return decl_poison(decl); if (!sema_analyse_method_function(context, decl)) return decl_poison(decl);
} }
if (decl->func.body && !sema_analyse_function_body(context, decl)) return decl_poison(decl); if (decl->func.body && !sema_analyse_function_body(context, decl)) return decl_poison(decl);
if (decl->name.string == main_name) if (decl->name == main_name)
{ {
if (decl->visibility == VISIBLE_LOCAL) if (decl->visibility == VISIBLE_LOCAL)
{ {
SEMA_ERROR(decl->name, "'main' cannot have local visibility."); SEMA_ERROR(decl, "'main' cannot have local visibility.");
return false; return false;
} }
decl->visibility = VISIBLE_EXTERN; decl->visibility = VISIBLE_EXTERN;
@@ -1068,7 +1127,7 @@ static inline bool sema_analyse_global(Context *context, Decl *decl)
if (!sema_analyse_expr(context, decl->type, decl->var.init_expr)) return false; if (!sema_analyse_expr(context, decl->type, decl->var.init_expr)) return false;
if (decl->var.init_expr->expr_kind != EXPR_CONST) if (decl->var.init_expr->expr_kind != EXPR_CONST)
{ {
SEMA_ERROR(decl->var.init_expr->loc, "The expression must be a constant value."); SEMA_ERROR(decl->var.init_expr, "The expression must be a constant value.");
return false; return false;
} }
} }
@@ -1122,7 +1181,7 @@ static inline bool sema_analyse_enum(Context *context, Decl *decl)
Expr *expr = enum_value->enum_constant.expr; Expr *expr = enum_value->enum_constant.expr;
if (!expr) if (!expr)
{ {
expr = expr_new(EXPR_CONST, EMPTY_TOKEN); expr = expr_new(EXPR_CONST, INVALID_RANGE);
expr->type = type; expr->type = type;
expr->resolve_status = RESOLVE_DONE; expr->resolve_status = RESOLVE_DONE;
expr->const_expr.type = CONST_INT; expr->const_expr.type = CONST_INT;
@@ -1138,7 +1197,7 @@ static inline bool sema_analyse_enum(Context *context, Decl *decl)
assert(type_is_integer(expr->type->canonical)); assert(type_is_integer(expr->type->canonical));
if (expr->expr_kind != EXPR_CONST) if (expr->expr_kind != EXPR_CONST)
{ {
SEMA_ERROR(expr->loc, "Expected a constant expression for enum"); SEMA_ERROR(expr, "Expected a constant expression for enum");
success = false; success = false;
} }
enum_value->resolve_status = RESOLVE_DONE; enum_value->resolve_status = RESOLVE_DONE;
@@ -1157,10 +1216,10 @@ bool sema_analyse_decl(Context *context, Decl *decl)
{ {
if (decl->resolve_status == RESOLVE_DONE) return decl_ok(decl); if (decl->resolve_status == RESOLVE_DONE) return decl_ok(decl);
DEBUG_LOG("Analyse %s", decl->name.string); DEBUG_LOG("Analyse %s", decl->name);
if (decl->resolve_status == RESOLVE_RUNNING) if (decl->resolve_status == RESOLVE_RUNNING)
{ {
SEMA_ERROR(decl->name, "Recursive dependency on %s.", decl->name.string); SEMA_ERROR(decl, "Recursive dependency on %s.", decl->name);
decl_poison(decl); decl_poison(decl);
return false; return false;
} }
@@ -1208,7 +1267,6 @@ bool sema_analyse_decl(Context *context, Decl *decl)
case DECL_ENUM_CONSTANT: case DECL_ENUM_CONSTANT:
case DECL_ERROR_CONSTANT: case DECL_ERROR_CONSTANT:
case DECL_ARRAY_VALUE: case DECL_ARRAY_VALUE:
case DECL_MULTI_DECL:
case DECL_CT_ELSE: case DECL_CT_ELSE:
case DECL_CT_ELIF: case DECL_CT_ELIF:
UNREACHABLE UNREACHABLE
@@ -1273,7 +1331,7 @@ void sema_analysis_pass_process_imports(Context *context)
Module *module = stable_get(&compiler.modules, path->module); Module *module = stable_get(&compiler.modules, path->module);
if (!module) if (!module)
{ {
SEMA_ERROR(import->name, "No module named '%s' could be found.", path->module); SEMA_ERROR(import, "No module named '%s' could be found.", path->module);
decl_poison(import); decl_poison(import);
continue; continue;
} }
@@ -1333,14 +1391,14 @@ static bool sema_resolve_type_identifier(Context *context, TypeInfo *type_info)
if (!decl) if (!decl)
{ {
SEMA_ERROR(type_info->unresolved.name_loc, "Unknown type '%s'.", type_info->unresolved.name_loc.string); SEMA_TOKEN_ERROR(type_info->unresolved.name_loc, "Unknown type '%s'.", type_info->unresolved.name_loc.string);
return type_info_poison(type_info); return type_info_poison(type_info);
} }
if (ambiguous_decl) if (ambiguous_decl)
{ {
SEMA_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, SEMA_TOKEN_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,
decl->module->name->module, ambiguous_decl->module->name->module); decl->module->name->module, ambiguous_decl->module->name->module);
return type_info_poison(type_info); return type_info_poison(type_info);
} }
switch (decl->decl_kind) switch (decl->decl_kind)
@@ -1376,9 +1434,8 @@ static bool sema_resolve_type_identifier(Context *context, TypeInfo *type_info)
case DECL_IMPORT: case DECL_IMPORT:
case DECL_MACRO: case DECL_MACRO:
case DECL_GENERIC: case DECL_GENERIC:
SEMA_ERROR(type_info->unresolved.name_loc, "This is not a type."); SEMA_TOKEN_ERROR(type_info->unresolved.name_loc, "This is not a type.");
return type_info_poison(type_info); return type_info_poison(type_info);
case DECL_MULTI_DECL:
case DECL_CT_ELSE: case DECL_CT_ELSE:
case DECL_CT_IF: case DECL_CT_IF:
case DECL_CT_ELIF: case DECL_CT_ELIF:
@@ -1396,7 +1453,7 @@ bool sema_resolve_type_shallow(Context *context, TypeInfo *type_info)
if (type_info->resolve_status == RESOLVE_RUNNING) if (type_info->resolve_status == RESOLVE_RUNNING)
{ {
// TODO this is incorrect for unresolved expressions // TODO this is incorrect for unresolved expressions
SEMA_ERROR(type_info->unresolved.name_loc, "Circular dependency resolving type '%s'.", type_info->unresolved.name_loc.string); SEMA_TOKEN_ERROR(type_info->unresolved.name_loc, "Circular dependency resolving type '%s'.", type_info->unresolved.name_loc.string);
return type_info_poison(type_info); return type_info_poison(type_info);
} }

View File

@@ -44,7 +44,7 @@ File *source_file_load(const char *filename, bool *already_loaded)
size_t size; size_t size;
const char* source_text = read_file(filename, &size); const char* source_text = read_file(filename, &size);
File *file = malloc(sizeof(File)); File *file = CALLOCS(File);
file->full_path = full_path; file->full_path = full_path;
file->start_id = vec_size(source_files.files) ? VECLAST(source_files.files)->end_id : 0; file->start_id = vec_size(source_files.files) ? VECLAST(source_files.files)->end_id : 0;
@@ -53,10 +53,10 @@ File *source_file_load(const char *filename, bool *already_loaded)
ASSERT(file->start_id + size < UINT32_MAX, "Total files loaded exceeded %d bytes", UINT32_MAX); ASSERT(file->start_id + size < UINT32_MAX, "Total files loaded exceeded %d bytes", UINT32_MAX);
file->end_id = (SourceLoc) (file->start_id + size); file->end_id = (SourceLoc) (file->start_id + size);
size_t pre_allocated_lines = size / 40; size_t pre_allocated_lines = size / 40;
file->line_start = VECNEW(SourceLoc, pre_allocated_lines < 16 ? 16 : pre_allocated_lines); file->lines = VECNEW(SourceLoc, pre_allocated_lines < 16 ? 16 : pre_allocated_lines);
VECADD(file->line_start, file->start_id); vec_add(file->lines, file->start_id);
path_get_dir_and_filename_from_full(file->full_path, &file->name, &file->dir_path); path_get_dir_and_filename_from_full(file->full_path, &file->name, &file->dir_path);
VECADD(source_files.files, file); vec_add(source_files.files, file);
return file; return file;
} }
@@ -64,14 +64,14 @@ void source_file_append_line_end(File *file, SourceLoc loc)
{ {
if (file->current_line_start > loc) return; if (file->current_line_start > loc) return;
file->current_line_start = loc + 1; file->current_line_start = loc + 1;
VECADD(file->line_start, file->current_line_start); vec_add(file->lines, file->current_line_start);
} }
SourceRange source_range_from_ranges(SourceRange first, SourceRange last) SourceRange source_range_from_ranges(SourceRange first, SourceRange last)
{ {
return (SourceRange) { return (SourceRange) {
.loc = first.loc, .loc = first.loc,
.length = last.loc - first.loc + last.length .end_loc = last.end_loc
}; };
} }
@@ -85,7 +85,7 @@ SourcePosition source_file_find_position_in_file(File *file, SourceLoc loc)
{ {
assert(file->start_id <= loc); assert(file->start_id <= loc);
size_t lines = vec_size(file->line_start); size_t lines = vec_size(file->lines);
unsigned low = 0; unsigned low = 0;
unsigned high = lines; unsigned high = lines;
while (1) while (1)
@@ -95,13 +95,13 @@ SourcePosition source_file_find_position_in_file(File *file, SourceLoc loc)
uint32_t mid = (high + low) / 2; uint32_t mid = (high + low) / 2;
// Mid is before the location. // Mid is before the location.
SourceLoc line_start = file->line_start[mid]; SourceLoc line_start = file->lines[mid];
if (line_start > loc) if (line_start > loc)
{ {
high = mid; high = mid;
continue; continue;
} }
if (mid + 1 != lines && file->line_start[mid + 1] < loc) if (mid + 1 != lines && file->lines[mid + 1] <= loc)
{ {
low = mid; low = mid;
continue; continue;

View File

@@ -159,6 +159,12 @@ const char *token_type_to_string(TokenType type)
case TOKEN_REAL: case TOKEN_REAL:
return "FLOAT"; return "FLOAT";
// Comments
case TOKEN_COMMENT:
return "COMMENT";
case TOKEN_DOC_COMMENT:
return "DOC_COMMENT";
// Keywords // Keywords
case TOKEN_ALIAS: case TOKEN_ALIAS:
return "alias"; return "alias";

View File

@@ -113,7 +113,6 @@ static void type_append_signature_name_user_defined(Decl *decl, char *dst, size_
case DECL_ARRAY_VALUE: case DECL_ARRAY_VALUE:
case DECL_IMPORT: case DECL_IMPORT:
case DECL_MACRO: case DECL_MACRO:
case DECL_MULTI_DECL:
case DECL_GENERIC: case DECL_GENERIC:
case DECL_CT_IF: case DECL_CT_IF:
case DECL_CT_ELSE: case DECL_CT_ELSE:
@@ -124,9 +123,13 @@ static void type_append_signature_name_user_defined(Decl *decl, char *dst, size_
case DECL_UNION: case DECL_UNION:
case DECL_ENUM: case DECL_ENUM:
case DECL_ERROR: case DECL_ERROR:
memcpy(dst + *offset, decl->name.string, decl->name.span.length); {
*offset += decl->name.span.length; unsigned len = source_range_len(decl->name_span);
memcpy(dst + *offset, decl->name, len);
*offset += len;
return; return;
}
} }
UNREACHABLE UNREACHABLE
} }

View File

@@ -21,6 +21,7 @@ static void test_lexer(void)
const int EXPECTED_TOKENS = 12 + 73 + 9; const int EXPECTED_TOKENS = 12 + 73 + 9;
const char* tokens[TOKEN_EOF]; const char* tokens[TOKEN_EOF];
int len[TOKEN_EOF]; int len[TOKEN_EOF];
Lexer lexer;
lexer_check_init(); lexer_check_init();
for (int i = 1; i < TOKEN_EOF; i++) for (int i = 1; i < TOKEN_EOF; i++)
{ {
@@ -31,7 +32,7 @@ static void test_lexer(void)
const char* interned = symtab_add(token, len[i], fnv1a(token, len[i]), &lookup); const char* interned = symtab_add(token, len[i], fnv1a(token, len[i]), &lookup);
if (lookup != TOKEN_IDENT) if (lookup != TOKEN_IDENT)
{ {
Token scanned = lexer_scan_ident_test(token); Token scanned = lexer_scan_ident_test(&lexer, token);
TEST_ASSERT(scanned.type == i, "Mismatch scanning: was '%s', expected '%s' - lookup: %s - interned: %s.", TEST_ASSERT(scanned.type == i, "Mismatch scanning: was '%s', expected '%s' - lookup: %s - interned: %s.",
token_type_to_string(scanned.type), token_type_to_string(scanned.type),
token_type_to_string(i), token_type_to_string(i),
@@ -56,7 +57,7 @@ static void test_lexer(void)
{ {
for (int i = 1; i < TOKEN_EOF; i++) for (int i = 1; i < TOKEN_EOF; i++)
{ {
volatile TokenType t = lexer_scan_ident_test(tokens[i]).type; volatile TokenType t = lexer_scan_ident_test(&lexer, tokens[i]).type;
} }
} }
@@ -77,11 +78,11 @@ static void test_lexer(void)
size_t test_len = strlen(test_parse); size_t test_len = strlen(test_parse);
for (int b = 0; b < BENCH_REPEATS; b++) for (int b = 0; b < BENCH_REPEATS; b++)
{ {
lexer_test_setup(test_parse, test_len); lexer_test_setup(&lexer, test_parse, test_len);
Token token; Token token;
while (1) while (1)
{ {
token = lexer_scan_token(); token = lexer_scan_token(&lexer);
if (token.type == TOKEN_EOF) break; if (token.type == TOKEN_EOF) break;
TEST_ASSERT(token.type != TOKEN_INVALID_TOKEN, "Got invalid token"); TEST_ASSERT(token.type != TOKEN_INVALID_TOKEN, "Got invalid token");
@@ -103,7 +104,7 @@ void test_file(void)
File file; File file;
memset(&file, 0, sizeof(file)); memset(&file, 0, sizeof(file));
file.start_id = 3; file.start_id = 3;
VECADD(file.line_start, file.start_id); VECADD(file.lines, file.start_id);
TEST_ASSERT(source_file_find_position_in_file(&file, 3).line == 1, "Expected first line"); TEST_ASSERT(source_file_find_position_in_file(&file, 3).line == 1, "Expected first line");
TEST_ASSERT(source_file_find_position_in_file(&file, 10).line == 1, "Expected first line"); TEST_ASSERT(source_file_find_position_in_file(&file, 10).line == 1, "Expected first line");
source_file_append_line_end(&file, 9); source_file_append_line_end(&file, 9);

View File

@@ -274,7 +274,8 @@ static inline void* _expand(void *vec, size_t element_size)
_vec = __temp; }) _vec = __temp; })
#define vec_add(_vec, _value) do { (_vec) = VECADD((_vec), _value); } while (0) #define vec_add(_vec, _value) do { (_vec) = VECADD((_vec), _value); } while (0)
#define VECLAST(_vec) ( (_vec) ? (_vec)[vec_size(_vec) - 1] : NULL) #define VECLAST(_vec) ({ unsigned _size = vec_size(_vec); _size ? (_vec)[_size - 1] : NULL; })
static inline bool is_all_upper(const char* string) static inline bool is_all_upper(const char* string)
{ {