diff --git a/resources/testfragments/compiletest.c3 b/resources/testfragments/compiletest.c3 index 9832dd24d..71e3ee439 100644 --- a/resources/testfragments/compiletest.c3 +++ b/resources/testfragments/compiletest.c3 @@ -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() +{ + +} \ No newline at end of file diff --git a/src/compiler/casts.c b/src/compiler/casts.c index a0c3e5d6e..45ac4a78e 100644 --- a/src/compiler/casts.c +++ b/src/compiler/casts.c @@ -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); } diff --git a/src/compiler/codegen.c b/src/compiler/codegen.c index 6735265f0..eaf1506b4 100644 --- a/src/compiler/codegen.c +++ b/src/compiler/codegen.c @@ -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); - PRINTF(" %s__%s()", decl->module->name, decl->name.string); + 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]); } + + } \ No newline at end of file diff --git a/src/compiler/compiler.c b/src/compiler/compiler.c index 50efe2dd6..f77f5bc51 100644 --- a/src/compiler/compiler.c +++ b/src/compiler/compiler.c @@ -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 \n#include \n"); + current_context->codegen_output = f; codegen(current_context); + fclose(f); + system("cc test.c && ./a.out"); + } exit(EXIT_SUCCESS); } diff --git a/src/compiler/compiler_internal.h b/src/compiler/compiler_internal.h index d6badcb00..c5b1e6972 100644 --- a/src/compiler/compiler_internal.h +++ b/src/compiler/compiler_internal.h @@ -443,13 +443,24 @@ typedef struct typedef struct { - Expr *expr; + 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; } diff --git a/src/compiler/context.c b/src/compiler/context.c index d55103798..7663a20cc 100644 --- a/src/compiler/context.c +++ b/src/compiler/context.c @@ -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) { - VECEACH(context->ct_ifs, i) - { - fprint_decl(file, context->ct_ifs[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]); } } diff --git a/src/compiler/enums.h b/src/compiler/enums.h index 8bfa3c9f7..d61030ec9 100644 --- a/src/compiler/enums.h +++ b/src/compiler/enums.h @@ -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 diff --git a/src/compiler/expr_analysis.c b/src/compiler/expr_analysis.c index a850ac018..fd2ab375f 100644 --- a/src/compiler/expr_analysis.c +++ b/src/compiler/expr_analysis.c @@ -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) { diff --git a/src/compiler/parser.c b/src/compiler/parser.c index 34b6bcda0..4fecff458 100644 --- a/src/compiler/parser.c +++ b/src/compiler/parser.c @@ -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 { diff --git a/src/compiler/semantic_analyser.c b/src/compiler/semantic_analyser.c index 8cb99a116..c7498fd7b 100644 --- a/src/compiler/semantic_analyser.c +++ b/src/compiler/semantic_analyser.c @@ -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,8 +268,8 @@ 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) || - !cast(decl->var.init_expr, decl->var.type, CAST_TYPE_IMPLICIT_ASSIGN)) + if (!sema_analyse_expr(context, decl->var.init_expr) || + !cast(decl->var.init_expr, decl->var.type, CAST_TYPE_IMPLICIT_ASSIGN)) { decl_poison(decl); return false; @@ -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; +} diff --git a/src/compiler/types.c b/src/compiler/types.c index 448d49cbf..f73117c5a 100644 --- a/src/compiler/types.c +++ b/src/compiler/types.c @@ -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); +} + + diff --git a/src/utils/lib.h b/src/utils/lib.h index e509ec332..84a678588 100644 --- a/src/utils/lib.h +++ b/src/utils/lib.h @@ -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)