mirror of
https://github.com/c3lang/c3c.git
synced 2026-02-27 12:01:16 +00:00
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:
@@ -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()
|
||||
{
|
||||
|
||||
}
|
||||
@@ -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);
|
||||
}
|
||||
|
||||
@@ -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,13 +713,26 @@ 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]);
|
||||
}
|
||||
|
||||
|
||||
|
||||
}
|
||||
@@ -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);
|
||||
}
|
||||
|
||||
@@ -442,14 +442,25 @@ 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; }
|
||||
|
||||
@@ -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]);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -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)
|
||||
{
|
||||
|
||||
@@ -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
|
||||
{
|
||||
|
||||
@@ -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)
|
||||
{
|
||||
old = stable_set(&context->module->public_symbols, decl->name.string, decl);
|
||||
}
|
||||
if (old != NULL)
|
||||
static inline bool sema_analyse_top_level_if(Context *context, Decl *ct_if)
|
||||
{
|
||||
show_shadow_error(decl, old);
|
||||
decl_poison(decl);
|
||||
return false;
|
||||
int res = sema_check_comp_time_bool(context, ct_if->ct_if_decl.expr);
|
||||
if (res == -1) return false;
|
||||
if (res)
|
||||
{
|
||||
append_decls(context, ct_if->ct_if_decl.then);
|
||||
return true;
|
||||
}
|
||||
Decl *ct_elif = ct_if->ct_if_decl.elif;
|
||||
while (ct_elif)
|
||||
{
|
||||
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;
|
||||
}
|
||||
|
||||
@@ -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);
|
||||
}
|
||||
|
||||
|
||||
|
||||
@@ -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)
|
||||
|
||||
Reference in New Issue
Block a user