More casts done, bugs fixed, codegen expanded, correct ordering in codegen, if, label, goto, break, switch, continue, compile time if analysed,

This commit is contained in:
Christoffer Lerno
2019-09-07 00:58:56 +02:00
parent 0dba2b8569
commit 3b2051ea80
12 changed files with 1104 additions and 382 deletions

View File

@@ -12,9 +12,70 @@ struct Bar
Foo* fooPtr;
}
$if (1)
{
struct Ogg
{
Zed *bob;
}
struct DOgg
{
Zed bob;
}
struct Zed
{
Foo b;
}
}
func int boo()
{
Zed zfe;
int eok = 0;
{
eok = 2;
}
switch (eok)
{
case 1:
eok++;
next;
case 3:
eok++;
next;
eok--;
case 2:
eok--;
default:
eok--;
break;
}
if (eok > 0)
{
eok++;
}
else
{
eok--;
}
int xfeef = -eok;
/*
bool xoek = !eok;
int oekfefo = ~eok;
int *booe = &eok;
int **de = &booe;
int &xfok = &eok;
int &&bo = &xfok;
int e12 = **bo;
int fe = *(&eok);
int x2 = *xfok;*/
int x1 = 2;
FOO:
x1 = x1 + 1;
goto FOO;
bool z = 123 > 3.0;
{
int x = 0;
@@ -34,8 +95,10 @@ func void while_test()
{
int a = 10;
while (int b = 37; a > 0)
while (int b = 37; a < 0)
{
a++;
int xy = 1;
}
}
@@ -59,3 +122,7 @@ func void test()
return;
}
func void main()
{
}

View File

@@ -7,14 +7,18 @@
#define EXIT_T_MISMATCH() return sema_type_mismatch(left, canonical, cast_type)
static inline void insert_cast(Expr *expr, CastKind kind, Type *type)
static inline void insert_cast(Expr *expr, CastKind kind, Type *canonical)
{
Expr *inner = malloc_arena(sizeof(Expr));
assert(expr->resolve_status == RESOLVE_DONE);
assert(expr->type->canonical);
assert(canonical->resolve_status == RESOLVE_DONE);
assert(canonical->canonical == canonical);
*inner = *expr;
expr->expr_kind = EXPR_CAST;
expr->expr_cast.kind = kind;
expr->expr_cast.expr = inner;
expr->type = type;
expr->type = canonical;
}
static bool sema_type_mismatch(Expr *expr, Type *type, CastType cast_type)
@@ -34,7 +38,7 @@ static bool sema_type_mismatch(Expr *expr, Type *type, CastType cast_type)
break;
}
SEMA_ERROR(expr->loc, "Cannot %s '%s' to '%s'", action, expr->type->name_loc.string, type->name_loc.string);
SEMA_ERROR(expr->loc, "Cannot %s '%s' to '%s'", action, type_to_error_string(expr->type), type_to_error_string(type));
return false;
}
@@ -343,7 +347,7 @@ bool uisi(Expr* left, Type *canonical, Type *type, CastType cast_type)
{
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->name_loc.string);
SEMA_ERROR(left->loc, "Cannot implicitly convert value '%llu' into %s - it will not fit.", left->const_expr.i, type_to_error_string(type));
return false;
}
}
@@ -373,7 +377,7 @@ bool uiui(Expr* left, Type *canonical, Type *type, CastType cast_type)
{
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->name_loc.string);
SEMA_ERROR(left->loc, "Cannot implicitly convert value '%llu' into %s - it will not fit.", type_to_error_string(type));
return false;
}
}
@@ -437,7 +441,26 @@ bool xipt(Expr* left, Type *canonical, Type *type, CastType cast_type)
bool usus(Expr* left, Type *canonical, Type *type, CastType cast_type)
{
TODO
Type *left_canonical = left->type->canonical;
assert(canonical->canonical == canonical);
assert(canonical->type_kind == TYPE_POINTER);
assert(left_canonical->type_kind == TYPE_POINTER);
if (cast_type != CAST_TYPE_EXPLICIT)
{
if (type_is_subtype(left_canonical->base, canonical->base))
{
if (!left_canonical->base->nullable || canonical->base->nullable)
{
insert_cast(left, CAST_PTRPTR, canonical);
return true;
}
}
sema_type_mismatch(left, type, cast_type);
return false;
}
insert_cast(left, CAST_PTRPTR, canonical);
return true;
}
bool usui(Expr* left, Type *canonical, Type *type, CastType cast_type)
@@ -520,7 +543,7 @@ bool cast_arithmetic(Expr *expr, Expr *other, const char *action)
return cast(expr, preferred_type, CAST_TYPE_IMPLICIT);
ERR:
SEMA_ERROR(expr->loc, "Cannot upcast to resolve '%s' %s '%s'", expr->type->name_loc.string, action, other->type->name_loc.string);
SEMA_ERROR(expr->loc, "Cannot upcast to resolve '%s' %s '%s'", type_to_error_string(expr->type), action, type_to_error_string(other->type));
return false;
}
@@ -555,5 +578,5 @@ bool cast(Expr *expr, Type *to_type, CastType cast_type)
return false;
}
CastFunc func = BUILTIN_CONVERSION[from_type->type_kind - TYPE_BOOL][to_type->type_kind - TYPE_BOOL];
return func(expr, to_type, canonical, cast_type);
return func(expr, canonical, to_type, cast_type);
}

View File

@@ -68,7 +68,7 @@ static void print_typename(FILE *file, Type *type)
fprintf(file, "uint16_t");
break;
case TYPE_U32:
fprintf(file, "int32_t");
fprintf(file, "uint32_t");
break;
case TYPE_U64:
fprintf(file, "uint64_t");
@@ -119,19 +119,14 @@ static inline void codegen_compound_stmt(Context *context, Ast *ast, int indent)
PRINTF("}\n");
}
static inline void codegen_emit_cast(Context *context, Type *canonical)
{
assert(canonical == canonical->canonical);
PRINTF("(");
TODO
}
static inline int codegen_emit_call_expr(Context *context, Expr *expr, int indent)
{
// TODO properly
INDENT();
PRINTTYPE(expr->type);
PRINTF(" _%d = %s();\n", ++context->unique_index, expr->call_expr.function->identifier_expr.decl->name.string);
Decl *func = expr->call_expr.function->identifier_expr.decl;
PRINTF(" _%d = %s__%s();\n", ++context->unique_index, func->module->name, func->name.string);
return context->unique_index;
}
@@ -243,7 +238,7 @@ static int codegen_emit_assign_expr(Context *context, Expr *expr, int indent)
if (expr->binary_expr.left->expr_kind == EXPR_IDENTIFIER)
{
INDENT();
PRINTF("%s = _%d;\n", left->identifier_expr.identifier.string, index);
PRINTF("_%d_%s = _%d;\n", left->identifier_expr.decl->var.id, left->identifier_expr.identifier.string, index);
return index;
}
else
@@ -294,6 +289,93 @@ static int codegen_emit_binary_expr(Context *context, Expr *expr, int indent)
UNREACHABLE
}
}
static int codegen_emit_post_unary_expr(Context *context, Expr *expr, int indent)
{
int index = ++context->unique_index;
int index2;
Expr *inner = expr->post_expr.expr;
switch (expr->post_expr.operator)
{
case TOKEN_PLUSPLUS:
case TOKEN_MINUSMINUS:
INDENT();
PRINTTYPE(expr->type);
if (inner->expr_kind == EXPR_IDENTIFIER)
{
PRINTF(" _%d = _%d_%s%s;\n", index, inner->identifier_expr.decl->var.id, inner->identifier_expr.decl->name.string, token_type_to_string(expr->post_expr.operator));
return index;
}
else
{
assert(inner->expr_kind == EXPR_UNARY && inner->unary_expr.operator == TOKEN_STAR);
index2 = codegen_emit_expr(context, inner->unary_expr.expr, indent);
PRINTF(" _%d = (*_%d)%s;\n", index, index2, token_type_to_string(expr->post_expr.operator));
return index;
}
default:
UNREACHABLE
}
}
static void codegen_print_ltype(Context *context, Expr *expr, int indent)
{
}
static int codegen_emit_unary_expr(Context *context, Expr *expr, int indent)
{
int index = ++context->unique_index;
int index2;
Expr *inner = expr->unary_expr.expr;
switch (expr->unary_expr.operator)
{
case TOKEN_MINUS:
case TOKEN_NOT:
index2 = codegen_emit_expr(context, inner, indent);
INDENT();
PRINTTYPE(expr->type);
PRINTF(" _%d = %s_%d;\n", index, token_type_to_string(expr->unary_expr.operator), index2);
return index;
case TOKEN_BIT_NOT:
index2 = codegen_emit_expr(context, inner, indent);
INDENT();
PRINTTYPE(expr->type);
PRINTF(" _%d = (", index);
PRINTTYPE(expr->type);
PRINTF(")~((");
PRINTTYPE(type_unsigned_int_by_size(inner->type->canonical->builtin.bytesize));
PRINTF(")_%d);\n", index2);
return index;
case TOKEN_PLUSPLUS:
case TOKEN_MINUSMINUS:
case TOKEN_STAR:
if (inner->expr_kind == EXPR_IDENTIFIER)
{
INDENT();
PRINTTYPE(expr->type);
PRINTF(" _%d = %s_%d_%s;\n", index, token_type_to_string(expr->post_expr.operator), inner->identifier_expr.decl->var.id, inner->identifier_expr.decl->name.string);
return index;
}
else
{
index2 = codegen_emit_expr(context, inner->unary_expr.expr, indent);
INDENT();
PRINTTYPE(expr->type);
PRINTF(" _%d = %s_%d;\n", index, token_type_to_string(expr->post_expr.operator), index2);
return index;
}
case TOKEN_AMP:
INDENT();
PRINTTYPE(expr->type);
assert(inner->expr_kind == EXPR_IDENTIFIER);
PRINTF(" _%d = &_%d_%s;\n", index, inner->identifier_expr.decl->var.id, inner->identifier_expr.decl->name.string);
return index;
default:
UNREACHABLE
}
}
static int codegen_emit_expr(Context *context, Expr *expr, int indent)
{
switch (expr->expr_kind)
@@ -308,6 +390,10 @@ static int codegen_emit_expr(Context *context, Expr *expr, int indent)
return codegen_emit_cast_expr(context, expr, indent);
case EXPR_BINARY:
return codegen_emit_binary_expr(context, expr, indent);
case EXPR_POST_UNARY:
return codegen_emit_post_unary_expr(context, expr, indent);
case EXPR_UNARY:
return codegen_emit_unary_expr(context, expr, indent);
default:
TODO
}
@@ -340,7 +426,18 @@ static inline void codegen_declare_stmt(Context *context, Ast *ast, int indent)
}
}
static inline void codegen_emit_for_smt(Context *context, Ast *ast, int indent)
static inline void codegen_emit_goto_stmt(Context *context, Ast *ast, int indent)
{
INDENT();
PRINTF("goto _L_%s;\n", ast->token.string);
}
static inline void codegen_emit_label_smt(Context *context, Ast *ast, int indent)
{
PRINTF("_L_%s:;\n", ast->token.string);
}
static inline void codegen_emit_for_stmt(Context *context, Ast *ast, int indent)
{
INDENT();
int loop = ++context->unique_index;
@@ -358,7 +455,7 @@ static inline void codegen_emit_for_smt(Context *context, Ast *ast, int indent)
INDENT();
PRINTF("// --- Loop condition ---\n");
INDENT();
PRINTF("_FOR_%d:\n", loop);
PRINTF("_FOR_%d:;\n", loop);
if (ast->for_stmt.cond->cond_stmt.expr)
{
int res = codegen_emit_expr(context, ast->for_stmt.cond->cond_stmt.expr, indent);
@@ -378,20 +475,21 @@ static inline void codegen_emit_for_smt(Context *context, Ast *ast, int indent)
PRINTF("// --- End for id:%d --- \n", loop);
}
static inline void codegen_emit_do_smt(Context *context, Ast *ast, int indent)
static inline void codegen_emit_do_stmt(Context *context, Ast *ast, int indent)
{
INDENT();
int loop = ++context->unique_index;
PRINTF("// --- Begin do id:%d ---\n", loop);
INDENT();
PRINTF("_DO_%d_BEGIN:\n", loop);
PRINTF("_DO_%d_BEGIN:;\n", loop);
INDENT();
PRINTF("// --- Body ---\n");
codegen_ast(context, ast->do_stmt.body, indent);
INDENT();
PRINTF("// --- End ---\n");
INDENT();
PRINTF("_DO_%d_CONTINUE:\n", loop);
PRINTF("_DO_%d_CONTINUE:;\n", loop);
INDENT();
PRINTF("// --- Loop condition ---\n");
int res = codegen_emit_expr(context, ast->do_stmt.expr, indent);
@@ -403,6 +501,45 @@ static inline void codegen_emit_do_smt(Context *context, Ast *ast, int indent)
PRINTF("// --- End do id:%d --- \n", loop);
}
static inline void codegen_emit_if_stmt(Context *context, Ast *ast, int indent)
{
INDENT();
PRINTF("// --- Begin if ---\n");
Ast **stmts = ast->if_stmt.cond->cond_stmt.stmts;
if (stmts)
{
INDENT();
PRINTF("// --- Prelude ---\n");
VECEACH(stmts, i)
{
codegen_ast(context, stmts[i], indent);
}
}
int res = codegen_emit_expr(context, ast->if_stmt.cond->cond_stmt.expr, indent);
INDENT();
PRINTF("if (!_%i)\n", res);
if (ast->if_stmt.then_body->ast_kind == AST_COMPOUND_STMT)
{
codegen_ast(context, ast->if_stmt.then_body, indent + 0);
}
else
{
INDENT();
PRINTF("{\n");
codegen_ast(context, ast->if_stmt.then_body, indent + 1);
INDENT();
PRINTF("}\n");
}
if (ast->if_stmt.else_body)
{
INDENT();
PRINTF("else\n");
codegen_ast(context, ast->if_stmt.else_body, indent);
}
INDENT();
PRINTF("// --- End for if --- \n");
}
static inline void codegen_emit_stmt_list(Context *context, Ast *ast, int indent)
{
VECEACH(ast->stmt_list, i)
@@ -411,6 +548,72 @@ static inline void codegen_emit_stmt_list(Context *context, Ast *ast, int indent
}
}
static void codegen_emit_switch_stmt(Context *context, Ast *ast, int indent)
{
Ast *cond = ast->switch_stmt.cond;
VECEACH(cond->cond_stmt.stmts, i)
{
codegen_ast(context, cond->cond_stmt.stmts[i], indent);
}
int expr = codegen_emit_expr(context, cond->cond_stmt.expr, indent);
INDENT();
PRINTF("switch(_%d)\n", expr);
INDENT();
PRINTF("{\n");
indent++;
VECEACH(ast->switch_stmt.cases, i)
{
Ast *the_case = ast->switch_stmt.cases[i];
assert(the_case->ast_kind == AST_CASE_STMT);
INDENT();
switch (the_case->case_stmt.value_type)
{
case CASE_VALUE_INT:
PRINTF("case %lld:;\n", (int64_t) the_case->case_stmt.val);
break;
case CASE_VALUE_UINT:
PRINTF("case %llu:;\n", (int64_t) the_case->case_stmt.val);
break;
case CASE_VALUE_DEFAULT:
PRINTF("default:;\n");
break;
}
indent++;
bool ends_with_next = false;
Ast *block = the_case->case_stmt.block;
if (block)
{
if (VECLAST(block->compound_stmt.stmts)->ast_kind == AST_NEXT_STMT)
{
ends_with_next = true;
vec_pop(block->compound_stmt.stmts);
}
codegen_ast(context, block, indent);
}
if (!ends_with_next)
{
INDENT();
PRINTF("break;\n");
if (the_case->case_stmt.has_next)
{
INDENT();
PRINTF("_EXIT_%zx:;\n", (size_t)the_case);
}
}
indent--;
}
indent--;
INDENT();
PRINTF("}\n");
}
static void codegen_emit_break_stmt(Context *context, Ast *ast, int indent)
{
INDENT();
PRINTF("break;\n");
}
static void codegen_ast(Context *context, Ast *ast, int indent)
{
switch (ast->ast_kind)
@@ -422,10 +625,11 @@ static void codegen_ast(Context *context, Ast *ast, int indent)
case AST_ATTRIBUTE:
break;
case AST_BREAK_STMT:
break;
codegen_emit_break_stmt(context, ast, indent);
return;
case AST_CASE_STMT:
break;
case AST_CATCH_STMT:
case AST_DEFAULT_STMT:
UNREACHABLE
case AST_COMPOUND_STMT:
codegen_compound_stmt(context, ast, indent);
@@ -443,27 +647,33 @@ static void codegen_ast(Context *context, Ast *ast, int indent)
case AST_DECLARE_STMT:
codegen_declare_stmt(context, ast, indent);
return;
case AST_DEFAULT_STMT:
break;
case AST_DEFER_STMT:
break;
case AST_DO_STMT:
codegen_emit_do_smt(context, ast, indent);
codegen_emit_do_stmt(context, ast, indent);
return;
case AST_IF_STMT:
codegen_emit_if_stmt(context, ast, indent);
return;
case AST_EXPR_STMT:
codegen_emit_expr(context, ast->expr_stmt, indent);
return;
case AST_FOR_STMT:
codegen_emit_for_smt(context, ast, indent);
codegen_emit_for_stmt(context, ast, indent);
return;
case AST_GOTO_STMT:
break;
case AST_IF_STMT:
break;
codegen_emit_goto_stmt(context, ast, indent);
return;
case AST_LABEL:
break;
codegen_emit_label_smt(context, ast, indent);
return;
case AST_NOP_STMT:
break;
INDENT();
PRINTF("// NOP");
return;
case AST_SWITCH_STMT:
codegen_emit_switch_stmt(context, ast, indent);
return;
case AST_RETURN_STMT:
if (ast->return_stmt.expr)
{
@@ -478,14 +688,14 @@ static void codegen_ast(Context *context, Ast *ast, int indent)
PRINTF("return;\n");
}
return;
case AST_SWITCH_STMT:
break;
case AST_THROW_STMT:
break;
case AST_TRY_STMT:
break;
case AST_NEXT_STMT:
break;
INDENT();
PRINTF("goto _EXIT_%zx;\n", (size_t)ast->next_stmt);
return;
case AST_VOLATILE_STMT:
break;
case AST_WHILE_STMT:
@@ -503,12 +713,25 @@ static void codegen_ast(Context *context, Ast *ast, int indent)
static inline void codegen_func_decl(Context *context, Decl *decl)
{
if (strcmp("main", decl->name.string) == 0)
{
// TODO
PRINTF("int main()");
return;
}
if (decl->visibility != VISIBLE_PUBLIC)
{
PRINTF("static ");
}
print_typename(context->codegen_output, decl->func.function_signature.rtype);
if (strcmp("main", decl->name.string) == 0)
{
PRINTF(" %s()", decl->name.string);
}
else
{
PRINTF(" %s__%s()", decl->module->name, decl->name.string);
}
}
static inline void codegen_func(Context *context, Decl *decl)
@@ -685,13 +908,19 @@ static inline void codegen_top_level_decl(Context *context, Decl *decl)
}
void codegen(Context *context)
{
VECEACH(context->declarations, i)
VECEACH(context->header_declarations, i)
{
codegen_top_level_decl_header(context, context->declarations[i]);
codegen_top_level_decl_header(context, context->header_declarations[i]);
}
VECEACH(context->declarations, i)
VECEACH(context->header_declarations, i)
{
codegen_top_level_decl(context, context->declarations[i]);
codegen_top_level_decl(context, context->header_declarations[i]);
}
VECEACH(context->vars, i)
{
codegen_top_level_decl(context, context->vars[i]);
}
}

View File

@@ -55,8 +55,13 @@ void compiler_compile()
diag_reset();
parse_file(file);
sema_analysis(current_context);
current_context->codegen_output = stdout;
FILE *f = fopen("test.c","w");
fprintf(f, "#include <stdbool.h>\n#include <stdint.h>\n");
current_context->codegen_output = f;
codegen(current_context);
fclose(f);
system("cc test.c && ./a.out");
}
exit(EXIT_SUCCESS);
}

View File

@@ -443,13 +443,24 @@ typedef struct
typedef struct
{
union
{
Expr *expr;
struct
{
uint64_t val;
CaseValueType value_type : 3;
bool has_next;
};
};
Ast *block;
} AstCaseStmt;
typedef struct
{
Ast *cond;
Ast *body;
Ast **cases;
} AstSwitchStmt;
typedef struct
@@ -467,20 +478,10 @@ typedef struct
} AstCondStmt;
typedef struct
{
DeclExprType list_type : 2;
union
{
Decl *decl;
Expr *expr;
};
} AstDeclExprList;
typedef struct
{
GotoType type : 2;
Ast *label;
struct _Ast *defer;
union
{
@@ -539,16 +540,16 @@ typedef struct _Ast
AstDeferStmt defer_stmt;
AstSwitchStmt switch_stmt;
AstCaseStmt case_stmt;
Ast* next_stmt;
AstCatchStmt catch_stmt;
AstGotoStmt goto_stmt;
AstForStmt for_stmt;
AstCondStmt cond_stmt;
AstCtIfStmt ct_if_stmt;
AstCtIfStmt ct_elif_stmt;
struct _Ast* ct_else_stmt;
AstDeclExprList decl_expr_list;
Ast *ct_else_stmt;
AstGenericCaseStmt generic_case_stmt;
struct _Ast* generic_default_stmt;
Ast *generic_default_stmt;
Ast** stmt_list;
};
} Ast;
@@ -592,18 +593,24 @@ typedef struct _Context
Decl** imports;
Module *module;
STable local_symbols;
Decl **declarations;
Decl **header_declarations;
Decl **enums;
Decl **types;
Decl **functions;
Decl **vars;
Decl **ct_ifs;
Decl *active_function_for_analysis;
FILE *codegen_output;
Decl *locals[MAX_LOCALS];
Decl **last_local;
DynamicScope scopes[MAX_SCOPE_DEPTH];
Ast **labels;
Ast **gotos;
DynamicScope *current_scope;
int unique_index;
Decl *evaluating_macro;
Type *rtype;
int in_volatile_section;
Decl *locals[MAX_LOCALS];
DynamicScope scopes[MAX_SCOPE_DEPTH];
} Context;
extern Context *current_context;
@@ -703,7 +710,7 @@ bool cast_to_runtime(Expr *expr);
void codegen(Context *context);
bool sema_expr_analysis(Context *context, Expr *expr);
bool sema_analyse_expr(Context *context, Expr *expr);
Context *context_create(File *file);
void context_push(Context *context);
@@ -713,12 +720,13 @@ bool context_set_module_from_filename(Context *context);
bool context_set_module(Context *context, Token module_name, Token *generic_parameters);
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);
Decl *decl_new(DeclKind decl_kind, Token name, Visibility visibility);
Decl *decl_new_user_defined_type(Token name, DeclKind decl_type, Visibility visibility);
Decl *decl_new_var(Token name, Type *type, VarDeclKind kind, Visibility visibility);
static inline bool decl_ok(Decl *decl) { return decl->decl_kind != DECL_POISONED; }
static inline Decl *decl_poison(Decl *decl) { decl->decl_kind = DECL_POISONED; return decl; }
static inline Decl *decl_poison(Decl *decl) { decl->decl_kind = DECL_POISONED; decl->resolve_status = RESOLVE_DONE; return decl; }
static inline DeclKind decl_from_token(TokenType type)
{
if (type == TOKEN_STRUCT) return DECL_STRUCT;
@@ -784,6 +792,7 @@ void sema_analysis(Context *context);
bool sema_analyse_statement(Context *context, Ast *statement);
bool sema_resolve_type(Context *context, Type *type);
bool sema_resolve_type_shallow(Context *context, Type *type);
void sema_error_at(SourceLoc loc, const char *message, ...);
void sema_error_range(SourceRange range, const char *message, ...);
void sema_verror_at(SourceLoc loc, const char *message, va_list args);
@@ -791,6 +800,7 @@ void sema_verror_range(SourceRange range, const char *message, va_list args);
void sema_error(const char *message, ...);
void sema_prev_at_range(SourceRange span, const char *message, ...);
void sema_prev_at(SourceLoc loc, const char *message, ...);
void sema_shadow_error(Decl *decl, Decl *old);
File *source_file_load(const char *filename, bool *already_loaded);
File *source_file_from_position(SourceLoc loc);
@@ -819,7 +829,8 @@ Type *type_get_canonical_ptr(Type *ptr_type);
Type *type_get_canonical_array(Type *arr_type);
Type *type_signed_int_by_size(int bitsize);
Type *type_unsigned_int_by_size(int bitsize);
bool type_is_subtype(Type *type, Type *possible_subtype);
const char *type_to_error_string(Type *type);
size_t type_size(Type *canonical);
static inline bool type_is_builtin(TypeKind kind) { return kind >= TYPE_VOID && kind <= TYPE_FXX; }
static inline bool type_is_signed(Type *type) { return type->type_kind >= TYPE_I8 && type->type_kind <= TYPE_IXX; }

View File

@@ -20,6 +20,12 @@ 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);
}
static inline bool create_module_or_check_name(Context *context, Token module_name)
{
context->module_name = module_name;
@@ -80,14 +86,60 @@ bool context_set_module(Context *context, Token module_name, Token *generic_para
void context_register_global_decl(Context *context, Decl *decl)
{
decl->module = context->module;
if (decl->decl_kind == DECL_CT_IF)
switch (decl->decl_kind)
{
context->ct_ifs = VECADD(context->ct_ifs, decl);
case DECL_POISONED:
case DECL_MACRO:
case DECL_GENERIC:
break;
case DECL_FUNC:
vec_add(context->functions, decl);
break;
case DECL_VAR:
vec_add(context->vars, decl);
break;
case DECL_STRUCT:
case DECL_UNION:
case DECL_TYPEDEF:
vec_add(context->types, decl);
break;
case DECL_ENUM:
vec_add(context->enums, decl);
break;
case DECL_ERROR:
TODO
break;
break;
case DECL_ENUM_CONSTANT:
case DECL_ERROR_CONSTANT:
case DECL_ARRAY_VALUE:
case DECL_IMPORT:
case DECL_MULTI_DECL:
case DECL_CT_ELSE:
case DECL_CT_ELIF:
UNREACHABLE
break;
case DECL_CT_IF:
vec_add(context->ct_ifs, decl);
return;
}
else
DEBUG_LOG("Registering symbol %s.", decl->name.string);
Decl *old = stable_set(&context->local_symbols, decl->name.string, decl);
if (!old && decl->visibility != VISIBLE_LOCAL)
{
DEBUG_LOG("Registering %s.", decl->name.string);
context->declarations = VECADD(context->declarations, decl);
old = stable_set(&context->module->symbols, decl->name.string, decl);
}
if (!old && decl->visibility == VISIBLE_PUBLIC)
{
old = stable_set(&context->module->public_symbols, decl->name.string, decl);
}
if (old != NULL)
{
sema_shadow_error(decl, old);
decl_poison(decl);
decl_poison(old);
}
}
@@ -161,16 +213,24 @@ bool context_add_import(Context *context, Token module_name, Token alias, Import
void context_print_ast(Context *context, FILE *file)
{
VECEACH(context->enums, i)
{
VECEACH(context->declarations, i)
{
fprint_decl(file, context->declarations[i]);
}
fprint_decl(file, context->enums[i]);
}
VECEACH(context->vars, i)
{
fprint_decl(file, context->vars[i]);
}
VECEACH(context->types, i)
{
fprint_decl(file, context->types[i]);
}
VECEACH(context->functions, i)
{
fprint_decl(file, context->functions[i]);
}
VECEACH(context->ct_ifs, i)
{
fprint_decl(file, context->ct_ifs[i]);
}
}
}

View File

@@ -64,7 +64,12 @@ typedef enum
ATTR_UNRESOLVED,
} AttrKind;
typedef enum
{
CASE_VALUE_INT,
CASE_VALUE_UINT,
CASE_VALUE_DEFAULT
} CaseValueType;
typedef enum
{
@@ -134,11 +139,6 @@ typedef enum
CONST_STRING,
} ConstType;
typedef enum
{
DECLEXPR_DECL,
DECLEXPR_EXPR,
} DeclExprType;
typedef enum
{
@@ -248,6 +248,7 @@ typedef enum
SCOPE_BREAK = 1 << 0,
SCOPE_CONTINUE = 1 << 1,
SCOPE_CONTROL = 1 << 2,
SCOPE_NEXT = 1 << 3,
} ScopeFlags;
typedef enum

View File

@@ -12,9 +12,22 @@ static ExprBinopAnalysis BINOP_ANALYSIS[TOKEN_EOF];
static ExprUnaryAnalysis UNARYOP_ANALYSIS[TOKEN_EOF + 1];
static ExprUnaryAnalysis POSTUNARYOP_ANALYSIS[TOKEN_EOF + 1];
static bool expr_is_ltype(Expr *expr)
{
switch (expr->expr_kind)
{
case EXPR_IDENTIFIER:
return expr->identifier_expr.decl->decl_kind == DECL_VAR && (expr->identifier_expr.decl->var.kind == VARDECL_LOCAL || expr->identifier_expr.decl->var.kind == VARDECL_GLOBAL);
case EXPR_UNARY:
return expr->unary_expr.operator == TOKEN_STAR;
default:
return false;
}
}
static inline bool sema_type_error_on_binop(const char *op, Expr *expr)
{
SEMA_ERROR(expr->loc, "Cannot perform '%s' %s '%s'.", expr->binary_expr.left->type->name_loc.string, op, expr->binary_expr.right->type->name_loc.string);
SEMA_ERROR(expr->loc, "Cannot perform '%s' %s '%s'.", type_to_error_string(expr->binary_expr.left->type), op, type_to_error_string(expr->binary_expr.right->type));
return false;
}
@@ -73,7 +86,7 @@ static inline bool sema_expr_analyse_func_call(Context *context, Expr *expr, Dec
for (unsigned i = 0; i < num_args; i++)
{
Expr *arg = args[i];
if (!sema_expr_analysis(context, arg)) return false;
if (!sema_analyse_expr(context, arg)) return false;
if (!cast(arg, func_params[i]->var.type, CAST_TYPE_IMPLICIT_ASSIGN)) return false;
}
expr->type = decl->func.function_signature.rtype;
@@ -83,7 +96,7 @@ static inline bool sema_expr_analyse_func_call(Context *context, Expr *expr, Dec
static inline bool sema_expr_analyse_call(Context *context, Expr *expr)
{
Expr *func_expr = expr->call_expr.function;
if (!sema_expr_analysis(context, func_expr)) return false;
if (!sema_analyse_expr(context, func_expr)) return false;
if (func_expr->expr_kind != EXPR_IDENTIFIER)
{
TODO
@@ -146,7 +159,7 @@ static inline bool sema_expr_analyse_cast(Context *context, Expr *expr)
{
Expr *inner = expr->expr_cast.expr;
if (!sema_resolve_type(context, expr->type)) return false;
if (!sema_expr_analysis(context, inner)) return false;
if (!sema_analyse_expr(context, inner)) return false;
if (!cast(inner, expr->type, CAST_TYPE_EXPLICIT)) return false;
@@ -295,50 +308,79 @@ static bool sema_expr_analyse_and_assign(Context *context, Expr *expr, Expr *lef
static bool sema_expr_analyse_or(Context *context, Expr *expr, Expr *left, Expr *right) { TODO }
static bool sema_expr_analyse_or_assign(Context *context, Expr *expr, Expr *left, Expr *right) { TODO }
static bool sema_expr_analyse_eq(Context *context, Expr *expr, Expr *left, Expr *right) { TODO }
static bool sema_expr_analyse_ne(Context *context, Expr *expr, Expr *left, Expr *right) { TODO }
static bool sema_expr_analyse_ge(Context *context, Expr *expr, Expr *left, Expr *right) { TODO }
static bool sema_expr_analyse_gt(Context *context, Expr *expr, Expr *left, Expr *right)
{
if (!cast_arithmetic(left, right, ">")) return false;
if (!cast_arithmetic(right, left, ">")) return false;
if (both_const(left, right))
{
switch (left->const_expr.type)
{
case CONST_FLOAT:
expr->const_expr.b = left->const_expr.f > right->const_expr.f;
break;
case CONST_BOOL:
expr->const_expr.b = left->const_expr.b > right->const_expr.b;
break;
case CONST_INT:
expr->const_expr.b = left->const_expr.i > right->const_expr.i;
break;
default:
UNREACHABLE
}
expr->const_expr.type = CONST_BOOL;
expr->expr_kind = EXPR_CONST;
}
if (!cast_to_runtime(left) || !cast_to_runtime(right)) return false;
expr->type = type_bool;
return true;
}
static bool sema_expr_analyse_le(Context *context, Expr *expr, Expr *left, Expr *right) { TODO }
static bool sema_expr_analyse_lt(Context *context, Expr *expr, Expr *left, Expr *right) { TODO }
#define SEMA_ANALYSE_CMP(op) { \
if (!cast_arithmetic(left, right, #op)) return false;\
if (!cast_arithmetic(right, left, #op)) return false;\
if (both_const(left, right)) { \
switch (left->const_expr.type) { \
case CONST_FLOAT: expr->const_expr.b = left->const_expr.f op right->const_expr.f; break; \
case CONST_BOOL: expr->const_expr.b = left->const_expr.b op right->const_expr.b; break; \
case CONST_INT: expr->const_expr.b = left->const_expr.i op right->const_expr.i; break; \
default: UNREACHABLE }\
expr->const_expr.type = CONST_BOOL;\
expr->expr_kind = EXPR_CONST;\
}\
if (!cast_to_runtime(left) || !cast_to_runtime(right)) return false;\
expr->type = type_bool;\
return true; }
static bool sema_expr_analyse_eq(Context *context, Expr *expr, Expr *left, Expr *right) SEMA_ANALYSE_CMP(==)
static bool sema_expr_analyse_ne(Context *context, Expr *expr, Expr *left, Expr *right) SEMA_ANALYSE_CMP(!=)
static bool sema_expr_analyse_ge(Context *context, Expr *expr, Expr *left, Expr *right) SEMA_ANALYSE_CMP(>=)
static bool sema_expr_analyse_gt(Context *context, Expr *expr, Expr *left, Expr *right) SEMA_ANALYSE_CMP(>)
static bool sema_expr_analyse_le(Context *context, Expr *expr, Expr *left, Expr *right) SEMA_ANALYSE_CMP(<=)
static bool sema_expr_analyse_lt(Context *context, Expr *expr, Expr *left, Expr *right) SEMA_ANALYSE_CMP(<)
static bool sema_expr_analyse_elvis(Context *context, Expr *expr, Expr *left, Expr *right) { TODO }
static bool sema_expr_analyse_deref(Context *context, Expr *expr, Expr *inner)
{
Type *canonical = inner->type->canonical;
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));
return false;
}
if (inner->expr_kind == EXPR_CONST)
{
SEMA_ERROR(inner->loc, "Dereferencing nil is not allowed.");
return false;
}
if (canonical->nullable)
{
SEMA_ERROR(inner->loc, "Dereferencing a nullable pointer is not allowed.");
return false;
}
Type *deref_type = inner->type->type_kind != TYPE_POINTER ? inner->type : canonical;
expr->type = deref_type->base;
return true;
}
static bool sema_expr_analyse_deref(Context *context, Expr *expr, Expr *inner) { TODO }
static bool sema_expr_analyse_addr(Context *context, Expr *expr, Expr *inner) { TODO }
static bool sema_expr_analyse_addr(Context *context, Expr *expr, Expr *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));
return false;
}
Type *type = type_new(TYPE_POINTER);
type->name_loc = inner->type->name_loc;
type->base = inner->type;
type->nullable = false;
type->resolve_status = RESOLVE_DONE;
type->canonical = type_get_canonical_ptr(type);
assert(type->resolve_status == RESOLVE_DONE);
assert(type->canonical->resolve_status == RESOLVE_DONE);
expr->type = type;
return true;
}
static bool sema_expr_analyse_neg(Context *context, Expr *expr, Expr *inner)
{
Type *canonical = inner->type->canonical;
if (!builtin_may_negate(canonical))
{
SEMA_ERROR(expr->loc, "Cannot negate %s.", inner->type->name_loc.string);
SEMA_ERROR(expr->loc, "Cannot negate %s.", type_to_error_string(inner->type));
return false;
}
if (inner->expr_kind != EXPR_CONST)
@@ -366,7 +408,7 @@ static bool sema_expr_analyse_bit_not(Context *context, Expr *expr, Expr *inner)
Type *canonical = inner->type->canonical;
if (!type_is_integer(canonical) && canonical != type_bool)
{
SEMA_ERROR(expr->loc, "Cannot bit negate %s.", inner->type->name_loc.string);
SEMA_ERROR(expr->loc, "Cannot bit negate %s.", type_to_error_string(inner->type));
}
if (inner->expr_kind != EXPR_CONST)
{
@@ -390,6 +432,7 @@ static bool sema_expr_analyse_bit_not(Context *context, Expr *expr, Expr *inner)
}
static bool sema_expr_analyse_not(Context *context, Expr *expr, Expr *inner)
{
expr->type = type_bool;
if (inner->expr_kind == EXPR_CONST)
{
switch (expr->const_expr.type)
@@ -411,7 +454,6 @@ static bool sema_expr_analyse_not(Context *context, Expr *expr, Expr *inner)
break;
}
expr->const_expr.type = CONST_BOOL;
expr->type = type_bool;
expr->expr_kind = EXPR_CONST;
return true;
}
@@ -443,17 +485,30 @@ static bool sema_expr_analyse_not(Context *context, Expr *expr, Expr *inner)
case TYPE_USER_DEFINED:
case TYPE_VOID:
case TYPE_STRING:
SEMA_ERROR(expr->loc, "Cannot use 'not' on %s", inner->type->name_loc.string);
SEMA_ERROR(expr->loc, "Cannot use 'not' on %s", type_to_error_string(inner->type));
return false;
}
UNREACHABLE
}
static bool sema_expr_analyse_preinc(Context *context, Expr *expr, Expr *inner) { TODO }
static bool sema_expr_analyse_predec(Context *context, Expr *expr, Expr *inner) { TODO }
static bool sema_expr_analyse_postinc(Context *context, Expr *expr, Expr *inner) { TODO }
static bool sema_expr_analyse_postdec(Context *context, Expr *expr, Expr *inner) { TODO }
static inline bool sema_expr_analyse_incdec(Context *context, Expr *expr, Expr *inner)
{
if (!expr_is_ltype(inner))
{
SEMA_ERROR(inner->loc, "Expression cannot be assigned to");
return false;
}
if (!type_is_integer(inner->type->canonical) && inner->type->canonical->type_kind == TYPE_POINTER)
{
SEMA_ERROR(inner->loc, "Expression must be an integer or pointer");
return false;
}
expr->type = inner->type;
return true;
}
static inline bool sema_expr_analyse_binary(Context *context, Expr *expr)
{
@@ -461,8 +516,8 @@ static inline bool sema_expr_analyse_binary(Context *context, Expr *expr)
Expr *left = expr->binary_expr.left;
Expr *right = expr->binary_expr.right;
if (!sema_expr_analysis(context, left)) return false;
if (!sema_expr_analysis(context, right)) return false;
if (!sema_analyse_expr(context, left)) return false;
if (!sema_analyse_expr(context, right)) return false;
return BINOP_ANALYSIS[expr->binary_expr.operator](context, expr, left, right);
}
@@ -472,7 +527,7 @@ static inline bool sema_expr_analyse_unary(Context *context, Expr *expr)
assert(expr->resolve_status == RESOLVE_RUNNING);
Expr *inner = expr->unary_expr.expr;
if (!sema_expr_analysis(context, inner)) return false;
if (!sema_analyse_expr(context, inner)) return false;
return UNARYOP_ANALYSIS[expr->unary_expr.operator](context, expr, inner);
}
@@ -482,18 +537,19 @@ static inline bool sema_expr_analyse_postunary(Context *context, Expr *expr)
assert(expr->resolve_status == RESOLVE_RUNNING);
Expr *inner = expr->post_expr.expr;
if (!sema_expr_analysis(context, inner)) return false;
if (!sema_analyse_expr(context, inner)) return false;
return POSTUNARYOP_ANALYSIS[expr->post_expr.operator](context, expr, inner);
assert(expr->post_expr.operator == TOKEN_PLUSPLUS || expr->post_expr.operator == TOKEN_MINUSMINUS);
return sema_expr_analyse_incdec(context, expr, inner);
}
static inline bool sema_expr_analyse_try(Context *context, Expr *expr)
{
if (!sema_expr_analysis(context, expr->try_expr.expr)) return false;
if (!sema_analyse_expr(context, expr->try_expr.expr)) return false;
expr->type = expr->try_expr.expr->type;
if (expr->try_expr.else_expr)
{
if (!sema_expr_analysis(context, expr->try_expr.else_expr)) return false;
if (!sema_analyse_expr(context, expr->try_expr.else_expr)) return false;
if (!cast(expr->try_expr.else_expr, expr->type, CAST_TYPE_IMPLICIT)) return false;
}
// Check errors!
@@ -550,16 +606,10 @@ static ExprUnaryAnalysis UNARYOP_ANALYSIS[TOKEN_EOF + 1] = {
[TOKEN_MINUS] = &sema_expr_analyse_neg,
[TOKEN_BIT_NOT] = &sema_expr_analyse_bit_not,
[TOKEN_NOT] = &sema_expr_analyse_not,
[TOKEN_PLUSPLUS] = &sema_expr_analyse_preinc,
[TOKEN_MINUSMINUS] = &sema_expr_analyse_predec,
[TOKEN_PLUSPLUS] = &sema_expr_analyse_incdec,
[TOKEN_MINUSMINUS] = &sema_expr_analyse_incdec,
};
static ExprUnaryAnalysis POSTUNARYOP_ANALYSIS[TOKEN_EOF + 1] = {
[TOKEN_PLUSPLUS] = &sema_expr_analyse_postinc,
[TOKEN_MINUSMINUS] = &sema_expr_analyse_postdec,
};
static ExprAnalysis EXPR_ANALYSIS[EXPR_CAST + 1] = {
[EXPR_TRY] = &sema_expr_analyse_try,
[EXPR_CONST] = NULL,
@@ -580,7 +630,7 @@ static ExprAnalysis EXPR_ANALYSIS[EXPR_CAST + 1] = {
[EXPR_CAST] = &sema_expr_analyse_cast,
};
bool sema_expr_analysis(Context *context, Expr *expr)
bool sema_analyse_expr(Context *context, Expr *expr)
{
switch (expr->resolve_status)
{

View File

@@ -394,13 +394,27 @@ static Type *parse_type_expression(void)
type = ptr_type;
}
break;
case TOKEN_AND:
advance();
{
Type *ptr_type = type_new(TYPE_POINTER);
assert(type);
ptr_type->base = type;
ptr_type->nullable = false;
type = ptr_type;
ptr_type = type_new(TYPE_POINTER);
ptr_type->base = type;
ptr_type->nullable = false;
type = ptr_type;
break;
}
case TOKEN_AMP:
advance();
{
Type *ptr_type = type_new(TYPE_POINTER);
type->base = type;
assert(type);
type->nullable = false;
ptr_type->base = type;
ptr_type->nullable = false;
type = ptr_type;
}
break;
@@ -654,7 +668,7 @@ static inline Ast* parse_if_stmt(void)
Ast *stmt = TRY_AST(parse_stmt());
if_ast->if_stmt.cond = cond;
if_ast->if_stmt.then_body = stmt;
if (stmt->ast_kind != AST_COMPOUND_STMT || next_tok.type != TOKEN_ELSE)
if (stmt->ast_kind != AST_COMPOUND_STMT || tok.type != TOKEN_ELSE)
{
if (stmt->ast_kind != AST_COMPOUND_STMT)
{
@@ -1793,8 +1807,6 @@ bool parse_struct_body(Decl *parent, Decl *visible_parent)
*/
static inline Decl *parse_struct_declaration(Visibility visibility)
{
LOG_FUNC
TokenType type = tok.type;
advance();
@@ -2345,7 +2357,7 @@ static inline bool parse_conditional_top_level(Decl ***decls)
Decl *decl = parse_top_level();
if (decl_ok(decl))
{
*decls = VECADD(*decls, decl);
vec_add(*decls, decl);
}
else
{

View File

@@ -13,31 +13,9 @@ void sema_init(File *file)
LOG_FUNC
}
/**
* Check if a type is contained in another type.
*
* @param type
* @param possible_subtype
* @return true if it is a subtype
*/
static bool canonical_type_is_subtype(Type *type, Type *possible_subtype)
{
assert(type == type->canonical && possible_subtype == possible_subtype->canonical);
if (type == possible_subtype) return true;
if (type->type_kind != possible_subtype->type_kind) return false;
if (type->type_kind != TYPE_USER_DEFINED || type->decl->decl_kind != DECL_STRUCT) return false;
if (!possible_subtype->decl->strukt.members) return false;
Decl *first_element = possible_subtype->decl->strukt.members[0];
if (first_element->decl_kind != DECL_VAR) return false;
return canonical_type_is_subtype(type, first_element->var.type->canonical);
}
static void show_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_prev_at_range(old->name.span, "The previous use of '%s' was here.", decl->name.string);
@@ -100,7 +78,7 @@ static inline void context_pop_scope(Context *context)
static bool sema_resolve_ptr_type(Context *context, Type *type)
{
if (!sema_resolve_type(context, type->base))
if (!sema_resolve_type_shallow(context, type->base))
{
type_poison(type);
return false;
@@ -121,100 +99,8 @@ static bool sema_resolve_array_type(Context *context, Type *type)
type->resolve_status = RESOLVE_DONE;
return true;
}
bool sema_resolve_type(Context *context, Type *type)
{
LOG_FUNC
if (type->resolve_status == RESOLVE_DONE) return type_ok(type);
if (type->resolve_status == RESOLVE_RUNNING)
{
SEMA_ERROR(type->name_loc, "Circular dependency resolving type '%s'.", type->name_loc);
type_poison(type);
return false;
}
type->resolve_status = RESOLVE_RUNNING;
switch (type->type_kind)
{
case TYPE_POISONED:
case TYPE_INC_ARRAY:
UNREACHABLE
case TYPE_USER_DEFINED:
break;
case TYPE_POINTER:
return sema_resolve_ptr_type(context, type);
case TYPE_ARRAY:
return sema_resolve_array_type(context, type);
default:
TODO
}
Decl *decl = stable_get(&context->local_symbols, type->name_loc.string);
if (!decl)
{
decl = module_find_symbol(context->module, type->name_loc.string);
}
if (!decl)
{
SEMA_ERROR(type->name_loc, "Unknown type '%s'.", type->name_loc.string);
type_poison(type);
return false;
}
switch (decl->decl_kind)
{
case DECL_STRUCT:
case DECL_UNION:
case DECL_ERROR:
case DECL_ENUM:
type->decl = decl;
type->canonical = decl->self_type;
type->resolve_status = RESOLVE_DONE;
DEBUG_LOG("Resolved %s.", type->name_loc.string);
return true;
case DECL_TYPEDEF:
// TODO func
if (!sema_resolve_type(context, decl->typedef_decl.type))
{
decl_poison(decl);
type_poison(type);
return false;
}
type->decl = decl;
type->canonical = decl->typedef_decl.type->canonical;
type->resolve_status = RESOLVE_DONE;
DEBUG_LOG("Resolved %s.", type->name_loc.string);
return true;
case DECL_POISONED:
type_poison(type);
return false;
case DECL_FUNC:
case DECL_VAR:
case DECL_ENUM_CONSTANT:
case DECL_ERROR_CONSTANT:
case DECL_ARRAY_VALUE:
case DECL_IMPORT:
case DECL_MACRO:
case DECL_GENERIC:
SEMA_ERROR(type->name_loc, "This is not a type.");
type_poison(type);
return false;
case DECL_MULTI_DECL:
case DECL_CT_ELSE:
case DECL_CT_IF:
case DECL_CT_ELIF:
UNREACHABLE
}
UNREACHABLE
}
static inline bool sema_analyse_struct_member(Context *context, Decl *decl)
{
LOG_FUNC
assert(decl->decl_kind == DECL_VAR);
assert(decl->var.kind == VARDECL_MEMBER);
assert(!decl->var.init_expr);
@@ -226,9 +112,8 @@ static inline bool sema_analyse_struct_member(Context *context, Decl *decl)
assert(decl->var.type->canonical);
return true;
}
static inline void sema_analyse_struct(Context *context, Decl *decl)
static inline bool sema_analyse_struct(Context *context, Decl *decl)
{
LOG_FUNC
DEBUG_LOG("Beginning analysis of %s.", decl->name.string);
assert(decl->decl_kind == DECL_STRUCT);
VECEACH(decl->strukt.members, i)
@@ -249,34 +134,11 @@ static inline void sema_analyse_struct(Context *context, Decl *decl)
decl_poison(decl);
}
}
DEBUG_LOG("Analysing complete.");
DEBUG_LOG("Analysis complete.");
return decl_ok(decl);
}
/*
static inline void add_integers(ExprConst *result, uint64_t l, bool l_is_negative, uint64_t r, bool r_is_negative)
{
if (l_is_negative == r_is_negative)
{
result->type = l_is_negative ? CONST_NEGATIVE_INT : CONST_POSITIVE_INT;
result->integer.i = l + r;
return;
}
if (l > r)
{
result->integer.i = l - r;
result->type = l_is_negative ? CONST_NEGATIVE_INT : CONST_POSITIVE_INT;
}
else
{
result->integer.i = r - l;
result->type = l_is_negative ? CONST_POSITIVE_INT : CONST_NEGATIVE_INT;
}
}
*/
static inline bool sema_analyse_function_param(Context *context, Decl *param, bool is_function)
{
@@ -295,7 +157,7 @@ static inline bool sema_analyse_function_param(Context *context, Decl *param, bo
if (param->var.init_expr)
{
Expr *expr = param->var.init_expr;
if (!sema_expr_analysis(context, expr)) return false;
if (!sema_analyse_expr(context, expr)) return false;
if (expr->expr_kind != EXPR_CONST)
{
SEMA_ERROR(expr->loc, "Only constant expressions may be used as default values.");
@@ -329,7 +191,6 @@ static inline bool sema_analyse_function_signature(Context *context, FunctionSig
static inline bool sema_analyse_compound_statement_no_scope(Context *context, Ast *compound_statement)
{
LOG_FUNC
bool all_ok = ast_ok(compound_statement);
VECEACH(compound_statement->compound_stmt.stmts, i)
{
@@ -349,7 +210,6 @@ static inline bool sema_analyse_compound_statement_no_scope(Context *context, As
static inline bool sema_analyse_return_stmt(Context *context, Ast *statement)
{
LOG_FUNC
context->current_scope->exit = EXIT_RETURN;
Type *expected_rtype = context->rtype;
Expr *return_expr = statement->return_stmt.expr;
@@ -363,12 +223,12 @@ static inline bool sema_analyse_return_stmt(Context *context, Ast *statement)
}
if (expected_rtype->canonical != type_void)
{
SEMA_ERROR(statement->token, "Expected to return a result of type %s.", expected_rtype->name_loc.string);
SEMA_ERROR(statement->token, "Expected to return a result of type %s.", type_to_error_string(expected_rtype));
return false;
}
return true;
}
if (!sema_expr_analysis(context, return_expr)) return false;
if (!sema_analyse_expr(context, return_expr)) return false;
if (!expected_rtype)
{
assert(context->evaluating_macro);
@@ -392,7 +252,7 @@ static inline bool sema_analyse_var_decl(Context *context, Decl *decl)
Decl *other = context_find_ident(context, decl->name.string);
if (other)
{
show_shadow_error(decl, other);
sema_shadow_error(decl, other);
decl_poison(decl);
decl_poison(other);
return false;
@@ -408,7 +268,7 @@ static inline bool sema_analyse_var_decl(Context *context, Decl *decl)
*vars = VECADD(*vars, decl);
if (decl->var.init_expr)
{
if (!sema_expr_analysis(context, decl->var.init_expr) ||
if (!sema_analyse_expr(context, decl->var.init_expr) ||
!cast(decl->var.init_expr, decl->var.type, CAST_TYPE_IMPLICIT_ASSIGN))
{
decl_poison(decl);
@@ -420,25 +280,8 @@ static inline bool sema_analyse_var_decl(Context *context, Decl *decl)
return true;
}
static inline bool sema_analyse_decl_expr_list(Context *context, Ast *statement)
{
switch (statement->decl_expr_list.list_type)
{
case DECLEXPR_DECL:
return sema_analyse_var_decl(context, statement->decl_expr_list.decl);
case DECLEXPR_EXPR:
return sema_expr_analysis(context, statement->decl_expr_list.expr);
}
UNREACHABLE
}
static inline bool sema_insert_decl_expr_list_in_compound_stmt(Context *context, Ast *compound_statement, Ast *decl_expr_list)
{
compound_statement->compound_stmt.stmts = VECADD(compound_statement->compound_stmt.stmts, decl_expr_list);
return true;
}
static inline Ast *convert_expr_to_ast(Expr *expr)
{
Ast *ast = new_ast(AST_EXPR_STMT, expr->loc);
@@ -566,7 +409,7 @@ static inline bool decl_or_expr_to_expr_stmt(Context *context, Ast *stmt)
return true;
}
static inline bool sema_flatten_cond(Context *context, Ast *stmt)
static inline bool sema_flatten_cond(Context *context, Ast *stmt, bool cast_to_bool)
{
assert(stmt->ast_kind == AST_STMT_LIST);
assert(vec_size(stmt->stmt_list) > 0);
@@ -575,7 +418,7 @@ static inline bool sema_flatten_cond(Context *context, Ast *stmt)
if (vec_size(stmt->stmt_list) == 1 && stmt->stmt_list[0]->ast_kind == AST_EXPR_STMT)
{
Expr *expr = stmt->stmt_list[0]->expr_stmt;
if (!cast(expr, type_bool, CAST_TYPE_IMPLICIT)) return false;
if (cast_to_bool && !cast(expr, type_bool, CAST_TYPE_IMPLICIT)) return false;
stmt->ast_kind = AST_COND_STMT;
stmt->cond_stmt.expr = expr;
stmt->cond_stmt.stmts = NULL;
@@ -589,7 +432,7 @@ static inline bool sema_flatten_cond(Context *context, Ast *stmt)
{
if (!convert_stmt_for_cond(context, stmt->stmt_list[i], &new_list, &last, last_index == i)) return false;
}
if (!cast(last, type_bool, CAST_TYPE_IMPLICIT)) return false;
if (cast_to_bool && !cast(last, type_bool, CAST_TYPE_IMPLICIT)) return false;
stmt->ast_kind = AST_COND_STMT;
stmt->cond_stmt.expr = last;
stmt->cond_stmt.stmts = new_list;
@@ -598,13 +441,12 @@ static inline bool sema_flatten_cond(Context *context, Ast *stmt)
static inline bool sema_analyse_while_stmt(Context *context, Ast *statement)
{
LOG_FUNC
Ast *cond = statement->while_stmt.cond;
Ast *body = statement->while_stmt.body;
assert(cond && cond->ast_kind == AST_STMT_LIST);
context_push_scope_with_flags(context, SCOPE_CONTROL);
bool success = sema_analyse_statement(context, cond);
sema_flatten_cond(context, cond);
success = success && sema_flatten_cond(context, cond, true);
context_push_scope_with_flags(context, SCOPE_BREAK | SCOPE_CONTINUE); // NOLINT(hicpp-signed-bitwise)
success = success && sema_analyse_statement(context, body);
context_pop_scope(context);
@@ -619,7 +461,6 @@ static inline bool sema_analyse_while_stmt(Context *context, Ast *statement)
static inline bool sema_analyse_do_stmt(Context *context, Ast *statement)
{
LOG_FUNC
Expr *expr = statement->do_stmt.expr;
Ast *body = statement->do_stmt.body;
bool success;
@@ -628,7 +469,7 @@ static inline bool sema_analyse_do_stmt(Context *context, Ast *statement)
context_pop_scope(context);
if (!success) return false;
context_push_scope_with_flags(context, SCOPE_CONTROL);
success = sema_expr_analysis(context, expr);
success = sema_analyse_expr(context, expr);
success = success && cast(expr, type_bool, CAST_TYPE_IMPLICIT);
context_pop_scope(context);
return success;
@@ -661,7 +502,7 @@ static inline bool sema_analyse_declare_stmt(Context *context, Ast *statement)
static inline bool sema_analyse_expr_stmt(Context *context, Ast *statement)
{
return sema_expr_analysis(context, statement->expr_stmt);
return sema_analyse_expr(context, statement->expr_stmt);
}
static inline bool sema_analyse_defer_stmt(Context *context, Ast *statement)
@@ -671,7 +512,8 @@ static inline bool sema_analyse_defer_stmt(Context *context, Ast *statement)
static inline bool sema_analyse_default_stmt(Context *context, Ast *statement)
{
TODO
SEMA_ERROR(statement->token, "Unexpected 'default' outside of switch");
return false;
}
bool sema_analyse_stmt_list(Context *context, Ast *statement)
@@ -699,22 +541,73 @@ static inline bool sema_analyse_for_stmt(Context *context, Ast *statement)
static inline bool sema_analyse_goto_stmt(Context *context, Ast *statement)
{
TODO
VECEACH(context->labels, i)
{
Ast *label = context->labels[i];
if (statement->token.string == label->token.string)
{
statement->goto_stmt.type = GOTO_JUMP_BACK;
label->label_stmt.is_used = true;
statement->goto_stmt.label = label;
}
}
vec_add(context->gotos, statement);
return true;
}
static inline bool sema_analyse_if_stmt(Context *context, Ast *statement)
{
TODO
context_push_scope(context);
Ast *cond = statement->if_stmt.cond;
context_push_scope_with_flags(context, SCOPE_CONTROL);
bool success = sema_analyse_statement(context, cond);
success = success && sema_flatten_cond(context, cond, true);
context_push_scope(context);
success = success && sema_analyse_statement(context, statement->if_stmt.then_body);
context_pop_scope(context);
// TODO null flowcheck
if (statement->if_stmt.else_body)
{
context_push_scope(context);
success = success && sema_analyse_statement(context, statement->if_stmt.else_body);
context_pop_scope(context);
}
context_pop_scope(context);
return success;
}
static inline bool sema_analyse_label(Context *context, Ast *statement)
{
TODO
VECEACH(context->labels, i)
{
Ast *label = context->labels[i];
if (label->token.string == statement->token.string)
{
SEMA_ERROR(tok, "This duplicate label '%s'.", statement->token.string);
sema_prev_at_range(label->token.span, "The previous declaration was here.");
ast_poison(label);
ast_poison(statement);
return false;
}
}
vec_add(context->labels, statement);
VECEACH(context->gotos, i)
{
Ast *the_goto = context->gotos[i];
if (the_goto->token.string == statement->token.string)
{
the_goto->goto_stmt.type = GOTO_JUMP_FORWARD;
the_goto->goto_stmt.label = statement;
statement->label_stmt.is_used = true;
break;
}
}
return true;
}
static inline bool sema_analyse_nop_stmt(Context *context, Ast *statement)
{
TODO
return true;
}
@@ -735,27 +628,183 @@ static bool sema_analyse_attribute(Context *context, Ast *statement)
static bool sema_analyse_break_stmt(Context *context, Ast *statement)
{
TODO
if (!(context->current_scope->flags | SCOPE_BREAK)) // NOLINT(hicpp-signed-bitwise)
{
SEMA_ERROR(statement->token, "'break' is not allowed here.");
return false;
}
return true;
}
static bool sema_analyse_case_stmt(Context *context, Ast *statement)
{
TODO
SEMA_ERROR(statement->token, "Unexpected 'case' outside of switch");
return false;
}
static bool sema_analyse_continue_stmt(Context *context, Ast *statement)
{
TODO
if (!(context->current_scope->flags | SCOPE_CONTINUE)) // NOLINT(hicpp-signed-bitwise)
{
SEMA_ERROR(statement->token, "'continue' is not allowed here.");
return false;
}
return true;
}
static inline bool sema_analyse_then_overwrite(Context *context, Ast *statement, Ast *replacement)
{
if (!sema_analyse_statement(context, replacement)) return false;
// Overwrite
*statement = *replacement;
return true;
}
static int sema_check_comp_time_bool(Context *context, Expr *expr)
{
if (!sema_analyse_expr(context, expr)) return -1;
if (expr->expr_kind != EXPR_CONST)
{
SEMA_ERROR(expr->loc, "$if requires a compile time constant value.");
return -1;
}
if (!cast(expr, type_bool, CAST_TYPE_IMPLICIT)) return -1;
return expr->const_expr.b;
}
static bool sema_analyse_ct_if_stmt(Context *context, Ast *statement)
{
TODO
int res = sema_check_comp_time_bool(context, statement->ct_if_stmt.expr);
if (res == -1) return false;
if (res)
{
return sema_analyse_then_overwrite(context, statement, statement->ct_if_stmt.then);
}
Ast *elif = statement->ct_if_stmt.elif;
while (1)
{
if (!elif)
{
// Turn into NOP!
statement->ast_kind = AST_NOP_STMT;
return true;
}
// We found else, then just replace with that.
if (elif->ast_kind == AST_CT_ELSE_STMT)
{
return sema_analyse_then_overwrite(context, statement, elif->ct_else_stmt);
}
assert(elif->ast_kind == AST_CT_ELIF_STMT);
res = sema_check_comp_time_bool(context, elif->ct_elif_stmt.expr);
if (res == -1) return false;
if (res)
{
return sema_analyse_then_overwrite(context, statement, elif->ct_elif_stmt.then);
}
elif = elif->ct_elif_stmt.elif;
}
}
static bool sema_analyse_switch_case(Context *context, Ast*** prev_cases, Ast *case_stmt, Type *switch_type, Ast **prev_case)
{
if (case_stmt->ast_kind == AST_CASE_STMT)
{
if (*prev_case)
{
context_pop_scope(context);
*prev_case = NULL;
}
Expr *case_expr = case_stmt->case_stmt.expr;
if (!sema_analyse_expr(context, case_expr)) return false;
if (!cast(case_expr, switch_type, CAST_TYPE_IMPLICIT)) return false;
if (case_expr->expr_kind != EXPR_CONST)
{
SEMA_ERROR(case_expr->loc, "This must be a constant expression.");
return false;
}
assert(case_expr->const_expr.type == CONST_INT);
case_stmt->case_stmt.value_type = type_is_signed(case_expr->type->canonical) ? CASE_VALUE_INT : CASE_VALUE_UINT;
uint64_t val = case_expr->const_expr.i;
case_stmt->case_stmt.val = val;
context_push_scope(context);
*prev_case = case_stmt;
VECEACH(*prev_cases, i)
{
if ((*prev_cases)[i]->case_stmt.val == val)
{
SEMA_ERROR(case_stmt->token, "Duplicate case value.");
sema_prev_at_range((*prev_cases)[i]->token.span, "Previous use was here.");
return false;
}
}
vec_add(*prev_cases, case_stmt);
return true;
}
if (case_stmt->ast_kind == AST_DEFAULT_STMT)
{
case_stmt->ast_kind = AST_CASE_STMT;
case_stmt->case_stmt.value_type = CASE_VALUE_DEFAULT;
case_stmt->case_stmt.block = NULL;
if (*prev_case)
{
context_pop_scope(context);
}
context_push_scope(context);
*prev_case = case_stmt;
vec_add(*prev_cases, case_stmt);
return true;
}
if (!*prev_case)
{
SEMA_ERROR(case_stmt->token, "Expected a 'case' or 'default' statement.");
return false;
}
if (case_stmt->ast_kind == AST_NEXT_STMT)
{
case_stmt->next_stmt = *prev_case;
(*prev_case)->case_stmt.has_next = true;
}
else
{
if (!sema_analyse_statement(context, case_stmt)) return false;
}
if (!(*prev_case)->case_stmt.block)
{
(*prev_case)->case_stmt.block = new_ast(AST_COMPOUND_STMT, (*prev_case)->token);
}
vec_add((*prev_case)->case_stmt.block->compound_stmt.stmts, case_stmt);
return true;
}
static bool sema_analyse_switch_stmt(Context *context, Ast *statement)
{
TODO
Ast *cond = statement->switch_stmt.cond;
context_push_scope_with_flags(context, SCOPE_CONTROL);
bool success = sema_analyse_statement(context, cond);
success = success && sema_flatten_cond(context, cond, false);
context_push_scope_with_flags(context, SCOPE_BREAK | SCOPE_NEXT); // NOLINT(hicpp-signed-bitwise)
Ast *body = statement->switch_stmt.body;
assert(body->ast_kind == AST_COMPOUND_STMT);
Type *switch_type = cond->cond_stmt.expr->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));
return false;
}
Ast *in_case = NULL;
VECEACH(body->compound_stmt.stmts, i)
{
success = success && sema_analyse_switch_case(context, &statement->switch_stmt.cases, body->compound_stmt.stmts[i], switch_type, &in_case);
}
if (in_case)
{
context_pop_scope(context);
}
context_pop_scope(context);
context_pop_scope(context);
return success;
}
static bool sema_analyse_try_stmt(Context *context, Ast *statement)
@@ -768,10 +817,6 @@ static bool sema_analyse_throw_stmt(Context *context, Ast *statement)
TODO
}
static bool sema_analyse_next_stmt(Context *context, Ast *statement)
{
TODO
}
static bool sema_analyse_volatile_stmt(Context *context, Ast *statement)
{
@@ -813,7 +858,7 @@ static AstAnalysis AST_ANALYSIS[AST_WHILE_STMT + 1] =
[AST_SWITCH_STMT] = &sema_analyse_switch_stmt,
[AST_TRY_STMT] = &sema_analyse_try_stmt,
[AST_THROW_STMT] = &sema_analyse_throw_stmt,
[AST_NEXT_STMT] = &sema_analyse_next_stmt,
[AST_NEXT_STMT] = NULL, // Never reached
[AST_VOLATILE_STMT] = &sema_analyse_volatile_stmt,
[AST_WHILE_STMT] = &sema_analyse_while_stmt,
[AST_STMT_LIST] = &sema_analyse_stmt_list
@@ -821,7 +866,6 @@ static AstAnalysis AST_ANALYSIS[AST_WHILE_STMT + 1] =
bool sema_analyse_statement(Context *context, Ast *statement)
{
LOG_FUNC
if (AST_ANALYSIS[statement->ast_kind](context, statement)) return true;
return ast_poison(statement);
}
@@ -832,6 +876,8 @@ static inline bool sema_analyse_function_body(Context *context, Decl *func)
context->rtype = func->func.function_signature.rtype;
context->current_scope = &context->scopes[0];
context->current_scope->local_decl_start = 0;
context->labels = NULL;
context->gotos = NULL;
context->last_local = &context->locals[0];
context->unique_index = 0;
context->in_volatile_section = 0;
@@ -848,6 +894,7 @@ static inline bool sema_analyse_function_body(Context *context, Decl *func)
}
static inline bool sema_analyse_func(Context *context, Decl *decl)
{
DEBUG_LOG("Analysing function %s", decl->name.string);
bool all_ok = sema_analyse_function_signature(context, &decl->func.function_signature, true);
if (decl->func.struct_parent)
{
@@ -855,6 +902,7 @@ static inline bool sema_analyse_func(Context *context, Decl *decl)
}
all_ok = all_ok && sema_analyse_function_body(context, decl);
if (!all_ok) decl_poison(decl);
DEBUG_LOG("Function analysis done.")
return all_ok;
}
@@ -872,65 +920,85 @@ static inline bool sema_analyse_macro(Context *context, Decl *decl)
return true;
}
static inline void sema_analyse_decl(Context *context, Decl *decl)
static inline bool sema_analyse_decl(Context *context, Decl *decl)
{
LOG_FUNC
if (decl->resolve_status == RESOLVE_DONE) return decl_ok(decl);
DEBUG_LOG("Analyse %s", decl->name.string);
if (decl->resolve_status == RESOLVE_RUNNING)
{
SEMA_ERROR(decl->name, "Recursive dependency on %s.", decl->name.string);
decl_poison(decl);
return false;
}
decl->resolve_status = RESOLVE_RUNNING;
switch (decl->decl_kind)
{
case DECL_IMPORT:
// TODO
break;
TODO
case DECL_STRUCT:
sema_analyse_struct(context, decl);
break;
if (!sema_analyse_struct(context, decl)) return false;
decl->resolve_status = RESOLVE_DONE;
context_add_header_decl(context, decl);
return true;
case DECL_FUNC:
sema_analyse_func(context, decl);
break;
if (!sema_analyse_func(context, decl)) return false;
decl->resolve_status = RESOLVE_DONE;
context_add_header_decl(context, decl);
return true;
case DECL_MACRO:
sema_analyse_macro(context, decl);
break;
if (!sema_analyse_macro(context, decl)) return false;
decl->resolve_status = RESOLVE_DONE;
return true;
default:
TODO
}
}
bool context_register_global(Context *context, Decl *decl)
static void append_decls(Context *context, Decl **decls)
{
Decl *old = stable_set(&context->local_symbols, decl->name.string, decl);
if (!old && decl->visibility != VISIBLE_LOCAL)
VECEACH(decls, i)
{
old = stable_set(&context->module->symbols, decl->name.string, decl);
context_register_global_decl(context, decls[i]);
}
if (!old && decl->visibility == VISIBLE_PUBLIC)
}
static inline bool sema_analyse_top_level_if(Context *context, Decl *ct_if)
{
int res = sema_check_comp_time_bool(context, ct_if->ct_if_decl.expr);
if (res == -1) return false;
if (res)
{
old = stable_set(&context->module->public_symbols, decl->name.string, decl);
append_decls(context, ct_if->ct_if_decl.then);
return true;
}
if (old != NULL)
Decl *ct_elif = ct_if->ct_if_decl.elif;
while (ct_elif)
{
show_shadow_error(decl, old);
decl_poison(decl);
return false;
if (ct_elif->decl_kind == DECL_CT_ELIF)
{
res = sema_check_comp_time_bool(context, ct_elif->ct_elif_decl.expr);
if (res == -1) return false;
if (res)
{
append_decls(context, ct_elif->ct_elif_decl.then);
return true;
}
ct_elif = ct_elif->ct_elif_decl.elif;
}
else
{
assert(ct_elif->decl_kind == DECL_CT_ELSE);
append_decls(context, ct_elif->ct_elif_decl.then);
return true;
}
}
return true;
}
static inline void sema_register_declarations(Context *context)
{
VECEACH(context->declarations, i)
{
context_register_global(context, context->declarations[i]);
}
}
static inline void sema_analyse_declarations(Context *context)
{
VECEACH(context->declarations, i)
{
sema_analyse_decl(context, context->declarations[i]);
}
}
static inline void sema_process_imports(Context *context)
{
@@ -939,8 +1007,125 @@ static inline void sema_process_imports(Context *context)
void sema_analysis(Context *context)
{
sema_process_imports(context);
sema_register_declarations(context);
// Skip the ct_if for now -> assume they passed.
sema_analyse_declarations(context);
VECEACH(context->ct_ifs, i)
{
sema_analyse_top_level_if(context, context->ct_ifs[i]);
}
VECEACH(context->enums, i)
{
sema_analyse_decl(context, context->enums[i]);
}
VECEACH(context->types, i)
{
sema_analyse_decl(context, context->types[i]);
}
VECEACH(context->vars, i)
{
sema_analyse_decl(context, context->vars[i]);
}
VECEACH(context->functions, i)
{
sema_analyse_decl(context, context->functions[i]);
}
}
bool sema_resolve_type_shallow(Context *context, Type *type)
{
if (type->resolve_status == RESOLVE_DONE) return type_ok(type);
if (type->resolve_status == RESOLVE_RUNNING)
{
SEMA_ERROR(type->name_loc, "Circular dependency resolving type '%s'.", type->name_loc);
type_poison(type);
return false;
}
type->resolve_status = RESOLVE_RUNNING;
switch (type->type_kind)
{
case TYPE_POISONED:
case TYPE_INC_ARRAY:
UNREACHABLE
case TYPE_USER_DEFINED:
break;
case TYPE_POINTER:
return sema_resolve_ptr_type(context, type);
case TYPE_ARRAY:
return sema_resolve_array_type(context, type);
default:
TODO
}
Decl *decl = stable_get(&context->local_symbols, type->name_loc.string);
if (!decl)
{
decl = module_find_symbol(context->module, type->name_loc.string);
}
if (!decl)
{
SEMA_ERROR(type->name_loc, "Unknown type '%s'.", type->name_loc.string);
type_poison(type);
return false;
}
switch (decl->decl_kind)
{
case DECL_STRUCT:
case DECL_UNION:
case DECL_ERROR:
case DECL_ENUM:
type->decl = decl;
type->canonical = decl->self_type;
type->resolve_status = RESOLVE_DONE;
DEBUG_LOG("Resolved %s.", type->name_loc.string);
return true;
case DECL_TYPEDEF:
// TODO func
if (!sema_resolve_type(context, decl->typedef_decl.type))
{
decl_poison(decl);
type_poison(type);
return false;
}
type->decl = decl;
type->canonical = decl->typedef_decl.type->canonical;
type->resolve_status = RESOLVE_DONE;
DEBUG_LOG("Resolved %s.", type->name_loc.string);
return true;
case DECL_POISONED:
type_poison(type);
return false;
case DECL_FUNC:
case DECL_VAR:
case DECL_ENUM_CONSTANT:
case DECL_ERROR_CONSTANT:
case DECL_ARRAY_VALUE:
case DECL_IMPORT:
case DECL_MACRO:
case DECL_GENERIC:
SEMA_ERROR(type->name_loc, "This is not a type.");
type_poison(type);
return false;
case DECL_MULTI_DECL:
case DECL_CT_ELSE:
case DECL_CT_IF:
case DECL_CT_ELIF:
UNREACHABLE
}
UNREACHABLE
}
bool sema_resolve_type(Context *context, Type *type)
{
if (!sema_resolve_type_shallow(context, type)) return false;
if (type->type_kind == TYPE_USER_DEFINED)
{
if (!sema_analyse_decl(context, type->decl)) return false;
}
return true;
}

View File

@@ -44,6 +44,57 @@ Type *type_unsigned_int_by_size(int bitsize)
}
}
const char *type_to_error_string(Type *type)
{
char *buffer = NULL;
switch (type->type_kind)
{
case TYPE_POISONED:
return "poisoned";
case TYPE_USER_DEFINED:
return type->name_loc.string;
case TYPE_VOID:
case TYPE_BOOL:
case TYPE_I8:
case TYPE_I16:
case TYPE_I32:
case TYPE_I64:
case TYPE_IXX:
case TYPE_U8:
case TYPE_U16:
case TYPE_U32:
case TYPE_U64:
case TYPE_UXX:
case TYPE_F32:
case TYPE_F64:
case TYPE_FXX:
return type->name_loc.string;
case TYPE_POINTER:
asprintf(&buffer, "%s%s", type_to_error_string(type->base), type->nullable ? "*" : "?");
return buffer;
case TYPE_STRING:
return "string";
case TYPE_ARRAY:
if (type->resolve_status == RESOLVE_DONE)
{
asprintf(&buffer, "%s[%zu]", type_to_error_string(type->base), type->len);
}
else
{
asprintf(&buffer, "%s[]", type_to_error_string(type->base));
}
return buffer;
case TYPE_VARARRAY:
asprintf(&buffer, "%s[]", type_to_error_string(type->base));
return buffer;
case TYPE_INC_ARRAY:
asprintf(&buffer, "%s[+]", type_to_error_string(type->base));
return buffer;
case TYPE_EXPRESSION:
return "type(...)";
}
}
Type *type_new(TypeKind type_kind)
{
Type *type = malloc_arena(sizeof(Type));
@@ -116,6 +167,8 @@ Type *type_get_canonical_ptr(Type *ptr_type)
canonical_ptr = malloc_arena(sizeof(Type));
*canonical_ptr = *ptr_type;
canonical_ptr->base = canonical_base;
canonical_ptr->canonical = canonical_ptr;
canonical_ptr->resolve_status = RESOLVE_DONE;
canonical_base->ptr_like_canonical[(int)ptr_type->nullable] = canonical_ptr;
canonical_base->resolve_status = RESOLVE_DONE;
}
@@ -231,3 +284,27 @@ create_type(#_name, &_shortname, &type_ ## _name, _type, (_bits + 7) / 8, _bits)
}
/**
* Check if a type is contained in another type.
*
* @param type canonical type
* @param possible_subtype canonical type
* @return true if it is a subtype
*/
bool type_is_subtype(Type *type, Type *possible_subtype)
{
assert(type == type->canonical && possible_subtype == possible_subtype->canonical);
if (type == possible_subtype) return true;
if (type->type_kind != possible_subtype->type_kind) return false;
if (type->type_kind != TYPE_USER_DEFINED || type->decl->decl_kind != DECL_STRUCT) return false;
if (!possible_subtype->decl->strukt.members) return false;
Decl *first_element = possible_subtype->decl->strukt.members[0];
if (first_element->decl_kind != DECL_VAR) return false;
return type_is_subtype(type, first_element->var.type->canonical);
}

View File

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