mirror of
https://github.com/c3lang/c3c.git
synced 2026-02-27 12:01:16 +00:00
Major type check rewrite. Fixed params to be writable. Conditionals work. Lots of assign operators fixed. Struct access works.
This commit is contained in:
@@ -23,6 +23,9 @@ union Test3
|
||||
|
||||
func int boba(int y, int j)
|
||||
{
|
||||
Test2 bar;
|
||||
bar.b = 1;
|
||||
//int w = y ? y : j;
|
||||
int x = y * 2;
|
||||
int z = j;
|
||||
while (j > 10)
|
||||
@@ -64,9 +67,10 @@ func int test3()
|
||||
if (test() < 0) return -1;
|
||||
return 5;
|
||||
}
|
||||
|
||||
|
||||
typedef func void(int) as Foo;
|
||||
//typedef int as Foo;
|
||||
|
||||
func void printf(char *hello);
|
||||
|
||||
macro @hello()
|
||||
@@ -74,17 +78,37 @@ macro @hello()
|
||||
printf("Hello world!\n");
|
||||
}
|
||||
|
||||
func void bob()
|
||||
{
|
||||
byte a = 2;
|
||||
short b = 3;
|
||||
int c = 4;
|
||||
bool eok = true;
|
||||
long deee = (eok ? a : b) + c;
|
||||
}
|
||||
|
||||
func int main(int x)
|
||||
{
|
||||
Test2 efe;
|
||||
efe.t.a = 3;
|
||||
if (efe.t.a > 2) printf("Works!\n");
|
||||
/*
|
||||
byte a = 2;
|
||||
short b = 3;
|
||||
int c = 4;
|
||||
bool eok = true;
|
||||
long deee = (eok ? a : b) + (eok ? b : c);*/
|
||||
int i = 0;
|
||||
JUMP:
|
||||
i = i + 1;
|
||||
//@hello();
|
||||
printf("Hello worldABC" "D" "E\u2701\n");
|
||||
if (i < 10) goto JUMP;
|
||||
float f = 10.0;
|
||||
float* pf = &f;
|
||||
if (*pf > i) goto JUMP;
|
||||
goto EX;
|
||||
YEF:
|
||||
return 4 * test3();
|
||||
return 4;
|
||||
EX:
|
||||
printf("EX\n");
|
||||
goto YEF;
|
||||
@@ -92,6 +116,34 @@ JUMP:
|
||||
|
||||
func void test2(int* x, int y, int z)
|
||||
{
|
||||
z = 0;
|
||||
z ? y : z;
|
||||
x += 1;
|
||||
y += z;
|
||||
x -= 1;
|
||||
y -= z;
|
||||
y *= 2;
|
||||
y /= 2;
|
||||
y /= *x;
|
||||
y |= 2;
|
||||
y ^= 2;
|
||||
y &= 2;
|
||||
z ^ y;
|
||||
z | y;
|
||||
int g = z & y;
|
||||
g <<= 2;
|
||||
g <<= z;
|
||||
g >>= 2;
|
||||
g >>= z;
|
||||
int fz = 100;
|
||||
y && z;
|
||||
y || z;
|
||||
y >> z;
|
||||
z << y;
|
||||
~z;
|
||||
!z;
|
||||
-z;
|
||||
|
||||
int i = 3;
|
||||
uint ui = 2;
|
||||
int j = 129;
|
||||
@@ -108,5 +160,6 @@ func void test2(int* x, int y, int z)
|
||||
ui = ui + 1;
|
||||
i = i - 1;
|
||||
ui = ui - 1;
|
||||
x + 1;
|
||||
// TODO x + 1;
|
||||
}
|
||||
@@ -206,7 +206,7 @@ static BinaryOp assign_binop[256] = {
|
||||
|
||||
BinaryOp binaryop_assign_base_op(BinaryOp assign_binary_op)
|
||||
{
|
||||
return assign_binop[(int)binary_op];
|
||||
return assign_binop[(int)assign_binary_op];
|
||||
}
|
||||
|
||||
AssignOp assign_op[256] = {
|
||||
@@ -451,73 +451,100 @@ void fprint_type_info_recursive(FILE *file, TypeInfo *type_info, int indent)
|
||||
}
|
||||
fprint_endparen(file, indent);
|
||||
}
|
||||
|
||||
void fprint_expr_common(FILE *file, Expr *expr, int indent)
|
||||
{
|
||||
switch (expr->resolve_status)
|
||||
{
|
||||
case RESOLVE_NOT_DONE:
|
||||
fprintf_indented(file, indent, "(unresolved)\n");
|
||||
break;
|
||||
case RESOLVE_RUNNING:
|
||||
fprintf_indented(file, indent, "(resolving)\n");
|
||||
break;
|
||||
case RESOLVE_DONE:
|
||||
fprint_type_recursive(file, expr->type, indent);
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
void fprint_expr_recursive(FILE *file, Expr *expr, int indent)
|
||||
{
|
||||
switch (expr->expr_kind)
|
||||
{
|
||||
case EXPR_IDENTIFIER:
|
||||
fprintf_indented(file, indent, "(ident %s)\n", expr->identifier_expr.identifier.string);
|
||||
return;
|
||||
fprintf_indented(file, indent, "(ident %s\n", expr->identifier_expr.identifier.string);
|
||||
fprint_expr_common(file, expr, indent + 1);
|
||||
break;
|
||||
case EXPR_CONST:
|
||||
fprintf_indented(file, indent, "(const ");
|
||||
switch (expr->const_expr.type)
|
||||
{
|
||||
case CONST_NIL:
|
||||
fprintf(file, "nil)\n");
|
||||
fprintf(file, "nil\n");
|
||||
break;
|
||||
case CONST_BOOL:
|
||||
fprintf(file, expr->const_expr.b ? "true" : "false");
|
||||
fprintf(file, expr->const_expr.b ? "true\n" : "false\n");
|
||||
break;
|
||||
case CONST_INT:
|
||||
if (expr->type->type_kind >= TYPE_U8 && expr->type->type_kind <= TYPE_UXX)
|
||||
{
|
||||
fprintf(file, "%llu)\n", expr->const_expr.i);
|
||||
fprintf(file, "%llu\n", expr->const_expr.i);
|
||||
}
|
||||
else
|
||||
{
|
||||
fprintf(file, "%lld)\n", (int64_t)expr->const_expr.i);
|
||||
fprintf(file, "%lld\n", (int64_t)expr->const_expr.i);
|
||||
}
|
||||
break;
|
||||
case CONST_FLOAT:
|
||||
fprintf(file, "%Lf)\n", expr->const_expr.f);
|
||||
fprintf(file, "%Lf\n", expr->const_expr.f);
|
||||
break;
|
||||
case CONST_STRING:
|
||||
fprintf(file, "%s)\n", expr->const_expr.string.chars);
|
||||
fprintf(file, "%s\n", expr->const_expr.string.chars);
|
||||
break;
|
||||
}
|
||||
return;
|
||||
fprint_expr_common(file, expr, indent + 1);
|
||||
break;
|
||||
case EXPR_BINARY:
|
||||
fprintf_indented(file, indent, "(binary %s\n", token_type_to_string(expr->binary_expr.operator));
|
||||
fprint_expr_common(file, expr, indent + 1);
|
||||
fprint_expr_recursive(file, expr->binary_expr.left, indent + 1);
|
||||
fprint_expr_recursive(file, expr->binary_expr.right, indent + 1);
|
||||
break;
|
||||
case EXPR_UNARY:
|
||||
fprintf_indented(file, indent, "(unary %s\n", token_type_to_string(expr->unary_expr.operator));
|
||||
fprint_expr_common(file, expr, indent + 1);
|
||||
fprint_expr_recursive(file, expr->unary_expr.expr, indent + 1);
|
||||
break;
|
||||
case EXPR_POST_UNARY:
|
||||
fprintf_indented(file, indent, "(postunary %s\n", token_type_to_string(expr->post_expr.operator));
|
||||
fprint_expr_common(file, expr, indent + 1);
|
||||
fprint_expr_recursive(file, expr->post_expr.expr, indent + 1);
|
||||
break;
|
||||
case EXPR_TYPE_ACCESS:
|
||||
fprintf_indented(file, indent, "(typeaccess .%s\n", expr->type_access.name.string);
|
||||
fprint_expr_common(file, expr, indent + 1);
|
||||
fprint_type_info_recursive(file, expr->type_access.type, indent + 1);
|
||||
break;
|
||||
case EXPR_STRUCT_VALUE:
|
||||
fprintf_indented(file, indent, "(structvalue\n");
|
||||
fprint_expr_common(file, expr, indent + 1);
|
||||
fprint_type_info_recursive(file, expr->struct_value_expr.type, indent + 1);
|
||||
fprint_expr_recursive(file, expr->struct_value_expr.init_expr, indent + 1);
|
||||
break;
|
||||
case EXPR_ACCESS:
|
||||
fprintf_indented(file, indent, "(access .%s\n", expr->access_expr.sub_element.string);
|
||||
fprint_expr_common(file, expr, indent + 1);
|
||||
fprint_expr_recursive(file, expr->access_expr.parent, indent + 1);
|
||||
break;
|
||||
case EXPR_TYPE:
|
||||
fprintf_indented(file, indent, "(type\n");
|
||||
fprint_expr_common(file, expr, indent + 1);
|
||||
fprint_type_info_recursive(file, expr->type_expr.type, indent + 1);
|
||||
break;
|
||||
case EXPR_CALL:
|
||||
fprintf_indented(file, indent, "(call\n");
|
||||
fprint_expr_common(file, expr, indent + 1);
|
||||
fprint_expr_recursive(file, expr->call_expr.function, indent + 1);
|
||||
{
|
||||
VECEACH(expr->call_expr.arguments, i)
|
||||
@@ -530,11 +557,13 @@ void fprint_expr_recursive(FILE *file, Expr *expr, int indent)
|
||||
if (!expr->conditional_expr.then_expr)
|
||||
{
|
||||
fprintf_indented(file, indent, "(elvis\n");
|
||||
fprint_expr_common(file, expr, indent + 1);
|
||||
fprint_expr_recursive(file, expr->conditional_expr.cond, indent + 1);
|
||||
}
|
||||
else
|
||||
{
|
||||
fprintf_indented(file, indent, "(cond\n");
|
||||
fprint_expr_common(file, expr, indent + 1);
|
||||
fprint_expr_recursive(file, expr->conditional_expr.cond, indent + 1);
|
||||
fprint_expr_recursive(file, expr->conditional_expr.then_expr, indent + 1);
|
||||
}
|
||||
@@ -542,6 +571,7 @@ void fprint_expr_recursive(FILE *file, Expr *expr, int indent)
|
||||
break;
|
||||
case EXPR_INITIALIZER_LIST:
|
||||
fprintf_indented(file, indent, "(initializerlist\n");
|
||||
fprint_expr_common(file, expr, indent + 1);
|
||||
{
|
||||
VECEACH(expr->initializer_expr, i)
|
||||
{
|
||||
@@ -551,6 +581,7 @@ void fprint_expr_recursive(FILE *file, Expr *expr, int indent)
|
||||
break;
|
||||
case EXPR_SUBSCRIPT:
|
||||
fprintf_indented(file, indent, "(subscript\n");
|
||||
fprint_expr_common(file, expr, indent + 1);
|
||||
fprint_expr_recursive(file, expr->subscript_expr.expr, indent + 1);
|
||||
fprint_expr_recursive(file, expr->subscript_expr.index, indent + 1);
|
||||
break;
|
||||
@@ -558,15 +589,23 @@ void fprint_expr_recursive(FILE *file, Expr *expr, int indent)
|
||||
if (!expr->try_expr.else_expr)
|
||||
{
|
||||
fprintf_indented(file, indent, "(try\n");
|
||||
fprint_expr_common(file, expr, indent + 1);
|
||||
fprint_expr_recursive(file, expr->try_expr.expr, indent + 1);
|
||||
}
|
||||
else
|
||||
{
|
||||
fprintf_indented(file, indent, "(try-else\n");
|
||||
fprint_expr_common(file, expr, indent + 1);
|
||||
fprint_expr_recursive(file, expr->try_expr.expr, indent + 1);
|
||||
fprint_expr_recursive(file, expr->try_expr.else_expr, indent + 1);
|
||||
}
|
||||
break;
|
||||
case EXPR_CAST:
|
||||
fprintf_indented(file, indent, "cast\n");
|
||||
fprint_expr_common(file, expr, indent + 1);
|
||||
fprint_type_info_recursive(file, expr->cast_expr.type_info, indent + 1);
|
||||
fprint_expr_recursive(file, expr->cast_expr.expr, indent + 1);
|
||||
break;
|
||||
default:
|
||||
fprintf_indented(file, indent, "(TODOEXPR)\n");
|
||||
return;
|
||||
@@ -631,7 +670,7 @@ void fprint_decl_recursive(FILE *file, Decl *decl, int indent)
|
||||
fprintf(file, ")\n");
|
||||
}
|
||||
fprint_func_signature(file, &decl->func.function_signature, indent + 1);
|
||||
fprint_ast_recursive(file, decl->func.body, indent + 1);
|
||||
if (decl->func.body) fprint_ast_recursive(file, decl->func.body, indent + 1);
|
||||
fprint_endparen(file, indent);
|
||||
break;
|
||||
case DECL_STRUCT:
|
||||
|
||||
@@ -15,9 +15,9 @@ static inline void insert_cast(Expr *expr, CastKind kind, Type *canonical)
|
||||
assert(canonical->canonical == canonical);
|
||||
*inner = *expr;
|
||||
expr->expr_kind = EXPR_CAST;
|
||||
expr->expr_cast.kind = kind;
|
||||
expr->expr_cast.expr = inner;
|
||||
expr->expr_cast.type_info = NULL;
|
||||
expr->cast_expr.kind = kind;
|
||||
expr->cast_expr.expr = inner;
|
||||
expr->cast_expr.type_info = NULL;
|
||||
expr->type = canonical;
|
||||
}
|
||||
|
||||
@@ -560,6 +560,7 @@ CastFunc conversion(TypeKind from, Type *to)
|
||||
if (type_is_unsigned_integer(to)) return &siui;
|
||||
if (type_is_signed_integer(to)) return &sisi;
|
||||
if (type_is_float(to)) return &sifp;
|
||||
if (to == type_bool) return &xibo;
|
||||
if (to->type_kind == TYPE_POINTER) return &ptxi;
|
||||
return &erro;
|
||||
case TYPE_U8:
|
||||
@@ -570,6 +571,7 @@ CastFunc conversion(TypeKind from, Type *to)
|
||||
if (type_is_unsigned_integer(to)) return &uiui;
|
||||
if (type_is_signed_integer(to)) return &uisi;
|
||||
if (type_is_float(to)) return &uifp;
|
||||
if (to == type_bool) return &xibo;
|
||||
if (to->type_kind == TYPE_POINTER) return &ptxi;
|
||||
return &erro;
|
||||
case TYPE_F32:
|
||||
@@ -577,6 +579,7 @@ CastFunc conversion(TypeKind from, Type *to)
|
||||
case TYPE_FXX:
|
||||
if (type_is_unsigned_integer(to)) return &fpui;
|
||||
if (type_is_signed_integer(to)) return &fpsi;
|
||||
if (to == type_bool) return &fpbo;
|
||||
if (type_is_float(to)) return &fpfp;
|
||||
return &erro;
|
||||
case TYPE_POINTER:
|
||||
@@ -655,21 +658,6 @@ static inline bool cannot_convert(TypeKind type_kind)
|
||||
return type_kind <= TYPE_VOID || type_kind > TYPE_ARRAY;
|
||||
}
|
||||
|
||||
bool cast_arithmetic(Expr *expr, Expr *other, const char *action)
|
||||
{
|
||||
Type *canonical = expr->type->canonical;
|
||||
Type *canonical_to = other->type->canonical;
|
||||
if (cannot_convert(canonical->type_kind) || cannot_convert(canonical_to->type_kind)) goto ERR;
|
||||
Type *preferred_type = ARITHMETIC_PROMOTION[canonical->type_kind - TYPE_BOOL][canonical_to->type_kind - TYPE_BOOL];
|
||||
if (preferred_type == &t_err) goto ERR;
|
||||
if (preferred_type == &t_cpy || preferred_type == canonical) return true;
|
||||
return cast(expr, preferred_type, CAST_TYPE_IMPLICIT);
|
||||
|
||||
ERR:
|
||||
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;
|
||||
|
||||
}
|
||||
|
||||
bool cast_to_runtime(Expr *expr)
|
||||
{
|
||||
@@ -687,19 +675,99 @@ bool cast_to_runtime(Expr *expr)
|
||||
}
|
||||
}
|
||||
|
||||
bool cast_implicit(Expr *expr, Type *to_type)
|
||||
{
|
||||
if (!to_type) return true;
|
||||
return cast(expr, to_type, CAST_TYPE_IMPLICIT);
|
||||
}
|
||||
|
||||
bool cast(Expr *expr, Type *to_type, CastType cast_type)
|
||||
{
|
||||
Type *from_type = expr->type->canonical;
|
||||
Type *canonical = to_type->canonical;
|
||||
if (from_type == canonical) return true;
|
||||
TypeKind from_kind = from_type->type_kind;
|
||||
TypeKind to_kind = canonical->type_kind;
|
||||
|
||||
if (cannot_convert(from_kind) || cannot_convert(to_kind))
|
||||
switch (from_type->type_kind)
|
||||
{
|
||||
sema_type_mismatch(expr, to_type, cast_type);
|
||||
return false;
|
||||
case TYPE_POISONED:
|
||||
case TYPE_VOID:
|
||||
break;
|
||||
case TYPE_BOOL:
|
||||
if (type_is_integer(canonical)) return boxi(expr, from_type, canonical, to_type, cast_type);
|
||||
if (type_is_float(canonical)) return bofp(expr, from_type, canonical, to_type, cast_type);
|
||||
break;
|
||||
case TYPE_ERROR_UNION:
|
||||
TODO
|
||||
case TYPE_I8:
|
||||
case TYPE_I16:
|
||||
case TYPE_I32:
|
||||
case TYPE_I64:
|
||||
case TYPE_IXX:
|
||||
if (type_is_unsigned_integer(canonical)) return siui(expr, from_type, canonical, to_type, cast_type);
|
||||
if (type_is_signed_integer(canonical)) return sisi(expr, from_type, canonical, to_type, cast_type);
|
||||
if (type_is_float(canonical)) return sifp(expr, from_type, canonical, to_type, cast_type);
|
||||
if (canonical == type_bool) return xibo(expr, from_type, canonical, to_type, cast_type);
|
||||
if (canonical->type_kind == TYPE_POINTER) return ptxi(expr, from_type, canonical, to_type, cast_type);
|
||||
break;
|
||||
case TYPE_U8:
|
||||
case TYPE_U16:
|
||||
case TYPE_U32:
|
||||
case TYPE_U64:
|
||||
case TYPE_UXX:
|
||||
if (type_is_unsigned_integer(canonical)) return uiui(expr, from_type, canonical, to_type, cast_type);
|
||||
if (type_is_signed_integer(canonical)) return uisi(expr, from_type, canonical, to_type, cast_type);
|
||||
if (type_is_float(canonical)) return uifp(expr, from_type, canonical, to_type, cast_type);
|
||||
if (canonical == type_bool) return xibo(expr, from_type, canonical, to_type, cast_type);
|
||||
if (canonical->type_kind == TYPE_POINTER) return ptxi(expr, from_type, canonical, to_type, cast_type);
|
||||
break;
|
||||
case TYPE_F32:
|
||||
case TYPE_F64:
|
||||
case TYPE_FXX:
|
||||
if (type_is_unsigned_integer(canonical)) return fpui(expr, from_type, canonical, to_type, cast_type);
|
||||
if (type_is_signed_integer(canonical)) return fpsi(expr, from_type, canonical, to_type, cast_type);
|
||||
if (canonical == type_bool) return fpbo(expr, from_type, canonical, to_type, cast_type);
|
||||
if (type_is_float(canonical)) return fpfp(expr, from_type, canonical, to_type, cast_type);
|
||||
break;
|
||||
case TYPE_POINTER:
|
||||
if (type_is_integer(canonical)) return ptxi(expr, from_type, canonical, to_type, cast_type);
|
||||
if (canonical->type_kind == TYPE_BOOL) return ptbo(expr, from_type, canonical, to_type, cast_type);
|
||||
if (canonical->type_kind == TYPE_POINTER) return ptpt(expr, from_type, canonical, to_type, cast_type);
|
||||
if (canonical->type_kind == TYPE_FUNC) return ptfu(expr, from_type, canonical, to_type, cast_type);
|
||||
if (canonical->type_kind == TYPE_VARARRAY) return ptva(expr, from_type, canonical, to_type, cast_type);
|
||||
break;
|
||||
case TYPE_ENUM:
|
||||
if (type_is_integer(canonical)) return enxi(expr, from_type, canonical, to_type, cast_type);
|
||||
break;
|
||||
case TYPE_ERROR:
|
||||
if (type_is_integer(canonical)) return erxi(expr, from_type, canonical, to_type, cast_type);
|
||||
break;
|
||||
case TYPE_FUNC:
|
||||
if (type_is_integer(canonical)) return ptxi(expr, from_type, canonical, to_type, cast_type);
|
||||
if (canonical->type_kind == TYPE_POINTER) return fupt(expr, from_type, canonical, to_type, cast_type);
|
||||
break;
|
||||
case TYPE_STRUCT:
|
||||
if (canonical->type_kind == TYPE_STRUCT) return stst(expr, from_type, canonical, to_type, cast_type);
|
||||
if (canonical->type_kind == TYPE_UNION) return stun(expr, from_type, canonical, to_type, cast_type);
|
||||
break;
|
||||
case TYPE_UNION:
|
||||
if (canonical->type_kind == TYPE_STRUCT) return unst(expr, from_type, canonical, to_type, cast_type);
|
||||
if (canonical->type_kind == TYPE_UNION) return unun(expr, from_type, canonical, to_type, cast_type);
|
||||
break;
|
||||
case TYPE_TYPEDEF:
|
||||
UNREACHABLE
|
||||
case TYPE_STRING:
|
||||
if (canonical->type_kind == TYPE_POINTER) return strpt(expr, from_type, canonical, to_type, cast_type);
|
||||
break;
|
||||
case TYPE_ARRAY:
|
||||
// There is no valid cast from array to anything else.
|
||||
break;
|
||||
case TYPE_VARARRAY:
|
||||
if (canonical->type_kind == TYPE_SUBARRAY) return vasa(expr, from_type, canonical, to_type, cast_type);
|
||||
if (canonical->type_kind == TYPE_VARARRAY) return vava(expr, from_type, canonical, to_type, cast_type);
|
||||
if (canonical->type_kind == TYPE_POINTER) return vapt(expr, from_type, canonical, to_type, cast_type);
|
||||
break;
|
||||
case TYPE_SUBARRAY:
|
||||
if (canonical->type_kind == TYPE_POINTER) return sapt(expr, from_type, canonical, to_type, cast_type);
|
||||
break;
|
||||
}
|
||||
CastFunc func = conversion(from_type->type_kind, canonical);
|
||||
return func(expr, from_type, canonical, to_type, cast_type);
|
||||
return sema_type_mismatch(expr, canonical, cast_type);
|
||||
}
|
||||
|
||||
@@ -451,7 +451,7 @@ struct _Expr
|
||||
Token loc;
|
||||
Type *type;
|
||||
union {
|
||||
ExprCast expr_cast;
|
||||
ExprCast cast_expr;
|
||||
ExprConst const_expr;
|
||||
ExprStructValue struct_value_expr;
|
||||
ExprTypeRef type_access;
|
||||
@@ -710,7 +710,6 @@ typedef struct _Context
|
||||
Decl **ct_ifs;
|
||||
Ast **defers;
|
||||
Decl *active_function_for_analysis;
|
||||
Type *left_type_in_assignment;
|
||||
Decl **last_local;
|
||||
Ast **labels;
|
||||
Ast **gotos;
|
||||
@@ -824,14 +823,16 @@ static inline ConstType sign_from_type(Type *type)
|
||||
return (type->type_kind >= TYPE_I8 && type->type_kind <= TYPE_IXX) ? CONST_INT : CONST_INT;
|
||||
}
|
||||
|
||||
bool cast_implicit(Expr *expr, Type *to_type);
|
||||
bool cast(Expr *expr, Type *to_type, CastType cast_type);
|
||||
bool cast_arithmetic(Expr *expr, Expr *other, const char *action);
|
||||
bool cast_binary_arithmetic(Expr *left, Expr *right, const char *action);
|
||||
|
||||
bool cast_to_runtime(Expr *expr);
|
||||
|
||||
void llvm_codegen(Context *context);
|
||||
void codegen(Context *context);
|
||||
|
||||
bool sema_analyse_expr(Context *context, Expr *expr);
|
||||
bool sema_analyse_expr(Context *context, Type *to, Expr *expr);
|
||||
bool sema_analyse_decl(Context *context, Decl *decl);
|
||||
|
||||
void compiler_add_type(Type *type);
|
||||
@@ -968,12 +969,14 @@ static inline Token wrap(const char *string)
|
||||
|
||||
Type *type_get_ptr(Type *ptr_type);
|
||||
Type *type_get_array(Type *arr_type, uint64_t len);
|
||||
Type *type_signed_int_by_size(int bitsize);
|
||||
Type *type_unsigned_int_by_size(int bitsize);
|
||||
Type *type_signed_int_by_size(int bytesize);
|
||||
Type *type_unsigned_int_by_size(int bytesize);
|
||||
bool type_is_subtype(Type *type, Type *possible_subtype);
|
||||
Type *type_find_common_ancestor(Type *left, Type *right);
|
||||
const char *type_to_error_string(Type *type);
|
||||
size_t type_size(Type *canonical);
|
||||
void type_append_signature_name(Type *type, char *dst, size_t *offset);
|
||||
Type *type_find_max_type(Type *type, Type *other);
|
||||
|
||||
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; }
|
||||
|
||||
@@ -496,6 +496,10 @@ typedef enum
|
||||
} TokenType;
|
||||
|
||||
|
||||
// Note that ordering matters here. If ordering is changed,
|
||||
// So must type_find_max_type and friends.
|
||||
// The reason is that for binary expressions we can simplify
|
||||
// by knowing the type_kind of left <= type kind of right
|
||||
typedef enum
|
||||
{
|
||||
TYPE_POISONED,
|
||||
@@ -528,6 +532,8 @@ typedef enum
|
||||
TYPE_SUBARRAY,
|
||||
} TypeKind;
|
||||
|
||||
#define TYPE_KINDS (TYPE_SUBARRAY + 1)
|
||||
|
||||
typedef enum
|
||||
{
|
||||
UNARYOP_ERROR,
|
||||
|
||||
File diff suppressed because it is too large
Load Diff
@@ -21,10 +21,9 @@ LLVMValueRef gencontext_emit_address(GenContext *context, Expr *expr)
|
||||
return gencontext_emit_expr(context, expr->unary_expr.expr);
|
||||
}
|
||||
case EXPR_ACCESS:
|
||||
TODO;
|
||||
{
|
||||
// LLVMValueRef value = gencontext_emit_address(context, expr->access_expr.parent);
|
||||
// LLVMBuildExtractValue(context->builder, value, (unsigned)expr->access_expr.index, expr->access_expr.ref->name.string);
|
||||
LLVMValueRef value = gencontext_emit_address(context, expr->access_expr.parent);
|
||||
return LLVMBuildStructGEP(context->builder, value, (unsigned)expr->access_expr.index, "");
|
||||
}
|
||||
case EXPR_POISONED:
|
||||
case EXPR_TRY:
|
||||
@@ -58,8 +57,8 @@ LLVMValueRef gencontext_emit_address(GenContext *context, Expr *expr)
|
||||
|
||||
static inline LLVMValueRef gencontext_emit_cast_expr(GenContext *context, Expr *expr)
|
||||
{
|
||||
LLVMValueRef rhs = gencontext_emit_expr(context, expr->expr_cast.expr);
|
||||
switch (expr->expr_cast.kind)
|
||||
LLVMValueRef rhs = gencontext_emit_expr(context, expr->cast_expr.expr);
|
||||
switch (expr->cast_expr.kind)
|
||||
{
|
||||
case CAST_ERROR:
|
||||
UNREACHABLE
|
||||
@@ -84,7 +83,7 @@ static inline LLVMValueRef gencontext_emit_cast_expr(GenContext *context, Expr *
|
||||
case CAST_INTBOOL:
|
||||
return LLVMBuildICmp(context->builder, LLVMIntNE, rhs, LLVMConstNull(LLVMTypeOf(rhs)), "intbool");
|
||||
case CAST_FPFP:
|
||||
return type_convert_will_trunc(expr->type, expr->expr_cast.expr->type)
|
||||
return type_convert_will_trunc(expr->type, expr->cast_expr.expr->type)
|
||||
? LLVMBuildFPTrunc(context->builder, rhs, BACKEND_TYPE(expr->type), "fpfptrunc")
|
||||
: LLVMBuildFPExt(context->builder, rhs, BACKEND_TYPE(expr->type), "fpfpext");
|
||||
case CAST_FPSI:
|
||||
@@ -92,11 +91,11 @@ static inline LLVMValueRef gencontext_emit_cast_expr(GenContext *context, Expr *
|
||||
case CAST_FPUI:
|
||||
return LLVMBuildFPToUI(context->builder, rhs, BACKEND_TYPE(expr->type), "fpui");
|
||||
case CAST_SISI:
|
||||
return type_convert_will_trunc(expr->type, expr->expr_cast.expr->type)
|
||||
return type_convert_will_trunc(expr->type, expr->cast_expr.expr->type)
|
||||
? LLVMBuildTrunc(context->builder, rhs, BACKEND_TYPE(expr->type), "sisitrunc")
|
||||
: LLVMBuildSExt(context->builder, rhs, BACKEND_TYPE(expr->type), "sisiext");
|
||||
case CAST_SIUI:
|
||||
return type_convert_will_trunc(expr->type, expr->expr_cast.expr->type)
|
||||
return type_convert_will_trunc(expr->type, expr->cast_expr.expr->type)
|
||||
? LLVMBuildTrunc(context->builder, rhs, BACKEND_TYPE(expr->type), "siuitrunc")
|
||||
: LLVMBuildZExt(context->builder, rhs, BACKEND_TYPE(expr->type), "siuiext");
|
||||
break;
|
||||
@@ -105,11 +104,11 @@ static inline LLVMValueRef gencontext_emit_cast_expr(GenContext *context, Expr *
|
||||
case CAST_XIPTR:
|
||||
return LLVMBuildIntToPtr(context->builder, rhs, BACKEND_TYPE(expr->type), "xiptr");
|
||||
case CAST_UISI:
|
||||
return type_convert_will_trunc(expr->type, expr->expr_cast.expr->type)
|
||||
return type_convert_will_trunc(expr->type, expr->cast_expr.expr->type)
|
||||
? LLVMBuildTrunc(context->builder, rhs, BACKEND_TYPE(expr->type), "uisitrunc")
|
||||
: LLVMBuildZExt(context->builder, rhs, BACKEND_TYPE(expr->type), "uisiext");
|
||||
case CAST_UIUI:
|
||||
return type_convert_will_trunc(expr->type, expr->expr_cast.expr->type)
|
||||
return type_convert_will_trunc(expr->type, expr->cast_expr.expr->type)
|
||||
? LLVMBuildTrunc(context->builder, rhs, BACKEND_TYPE(expr->type), "uiuitrunc")
|
||||
: LLVMBuildZExt(context->builder, rhs, BACKEND_TYPE(expr->type), "uiuiext");
|
||||
case CAST_UIFP:
|
||||
@@ -239,7 +238,7 @@ static LLVMValueRef gencontext_emit_binary(GenContext *context, Expr *expr, bool
|
||||
case BINARYOP_ADD:
|
||||
if (lhs->type->canonical->type_kind == TYPE_POINTER)
|
||||
{
|
||||
assert(type_is_integer(lhs->type->canonical));
|
||||
assert(type_is_integer(rhs->type->canonical));
|
||||
return LLVMBuildGEP2(context->builder, BACKEND_TYPE(lhs->type), lhs_value, &rhs_value, 1, "ptradd");
|
||||
}
|
||||
if (is_float) return LLVMBuildFAdd(context->builder, lhs_value, rhs_value, "fadd");
|
||||
@@ -259,7 +258,7 @@ static LLVMValueRef gencontext_emit_binary(GenContext *context, Expr *expr, bool
|
||||
? LLVMBuildLShr(context->builder, lhs_value, rhs_value, "lshr")
|
||||
: LLVMBuildAShr(context->builder, lhs_value, rhs_value, "ashr");
|
||||
case BINARYOP_SHL:
|
||||
return LLVMBuildShl(context->builder, lhs_value, rhs_value, "shr");
|
||||
return LLVMBuildShl(context->builder, lhs_value, rhs_value, "shl");
|
||||
case BINARYOP_BIT_AND:
|
||||
return LLVMBuildAnd(context->builder, lhs_value, rhs_value, "and");
|
||||
case BINARYOP_BIT_OR:
|
||||
@@ -364,6 +363,37 @@ static LLVMValueRef gencontext_emit_binary_expr(GenContext *context, Expr *expr)
|
||||
return gencontext_emit_binary(context, expr, false, binary_op);
|
||||
}
|
||||
|
||||
LLVMValueRef gencontext_emit_conditional_expr(GenContext *context, Expr *expr)
|
||||
{
|
||||
// Set up basic blocks, following Cone
|
||||
LLVMBasicBlockRef phi_block = LLVMCreateBasicBlockInContext(context->context, "cond.phi");
|
||||
LLVMBasicBlockRef lhs_block = LLVMCreateBasicBlockInContext(context->context, "cond.lhs");
|
||||
LLVMBasicBlockRef rhs_block = LLVMCreateBasicBlockInContext(context->context, "cond.rhs");
|
||||
|
||||
// Generate condition and conditional branch
|
||||
LLVMValueRef cond = gencontext_emit_expr(context, expr->conditional_expr.cond);
|
||||
|
||||
gencontext_emit_cond_br(context, cond, lhs_block, rhs_block);
|
||||
|
||||
gencontext_emit_block(context, lhs_block);
|
||||
LLVMValueRef lhs = gencontext_emit_expr(context, expr->conditional_expr.then_expr);
|
||||
gencontext_emit_br(context, phi_block);
|
||||
|
||||
gencontext_emit_block(context, rhs_block);
|
||||
LLVMValueRef rhs = gencontext_emit_expr(context, expr->conditional_expr.else_expr);
|
||||
gencontext_emit_br(context, phi_block);
|
||||
|
||||
// Generate phi
|
||||
gencontext_emit_block(context, phi_block);
|
||||
LLVMValueRef phi = LLVMBuildPhi(context->builder, expr->type->backend_type, "val");
|
||||
|
||||
LLVMValueRef logicValues[2] = { lhs, rhs };
|
||||
LLVMBasicBlockRef blocks[2] = { lhs_block, rhs_block };
|
||||
LLVMAddIncoming(phi, logicValues, blocks, 2);
|
||||
|
||||
return phi;
|
||||
}
|
||||
|
||||
static LLVMValueRef gencontext_emit_identifier_expr(GenContext *context, Expr *expr)
|
||||
{
|
||||
return LLVMBuildLoad2(context->builder, expr->identifier_expr.decl->type->canonical->backend_type,
|
||||
@@ -429,7 +459,7 @@ LLVMValueRef gencontext_emit_expr(GenContext *context, Expr *expr)
|
||||
case EXPR_BINARY:
|
||||
return gencontext_emit_binary_expr(context, expr);
|
||||
case EXPR_CONDITIONAL:
|
||||
break;
|
||||
return gencontext_emit_conditional_expr(context, expr);
|
||||
case EXPR_POST_UNARY:
|
||||
return gencontext_emit_post_unary_expr(context, expr);
|
||||
case EXPR_TYPE:
|
||||
@@ -445,7 +475,11 @@ LLVMValueRef gencontext_emit_expr(GenContext *context, Expr *expr)
|
||||
case EXPR_SUBSCRIPT:
|
||||
break;
|
||||
case EXPR_ACCESS:
|
||||
break;
|
||||
{
|
||||
LLVMValueRef value = gencontext_emit_address(context, expr->access_expr.parent);
|
||||
LLVMValueRef val = LLVMBuildStructGEP(context->builder, value, (unsigned)expr->access_expr.index, "");
|
||||
return LLVMBuildLoad2(context->builder, gencontext_get_llvm_type(context, expr->type), val, "");
|
||||
}
|
||||
case EXPR_STRUCT_VALUE:
|
||||
break;
|
||||
case EXPR_STRUCT_INIT_VALUES:
|
||||
|
||||
@@ -117,6 +117,7 @@ void gencontext_emit_function_body(GenContext *context, Decl *decl)
|
||||
|
||||
gencontext_emit_compound_stmt(context, decl->func.body);
|
||||
|
||||
|
||||
if (!LLVMGetFirstInstruction(context->current_block) && !LLVMGetFirstUse(LLVMBasicBlockAsValue(context->current_block)))
|
||||
{
|
||||
LLVMBasicBlockRef prev_block = LLVMGetPreviousBasicBlock(context->current_block);
|
||||
|
||||
@@ -3087,7 +3087,6 @@ static Expr *parse_integer(Expr *left)
|
||||
expr_int->const_expr.i = i;
|
||||
expr_int->const_expr.type = CONST_INT;
|
||||
expr_int->type = i > INT64_MAX ? type_compuint : type_compint;
|
||||
expr_int->resolve_status = RESOLVE_DONE;
|
||||
advance();
|
||||
return expr_int;
|
||||
}
|
||||
@@ -3109,7 +3108,6 @@ static Expr *parse_double(Expr *left)
|
||||
number->const_expr.f = fval;
|
||||
number->type = type_compfloat;
|
||||
number->const_expr.type = CONST_FLOAT;
|
||||
number->resolve_status = RESOLVE_DONE;
|
||||
return number;
|
||||
}
|
||||
|
||||
@@ -3130,7 +3128,6 @@ static Expr *parse_nil(Expr *left)
|
||||
Expr *number = EXPR_NEW_TOKEN(EXPR_CONST, tok);
|
||||
number->const_expr.type = CONST_NIL;
|
||||
number->type = type_voidptr;
|
||||
number->resolve_status = RESOLVE_DONE;
|
||||
advance();
|
||||
return number;
|
||||
}
|
||||
@@ -3293,9 +3290,9 @@ static Expr *parse_cast_expr(Expr *left)
|
||||
Expr *expr = EXPR_NEW_TOKEN(EXPR_CAST, tok);
|
||||
advance_and_verify(TOKEN_CAST);
|
||||
CONSUME_OR(TOKEN_LPAREN, &poisoned_expr);
|
||||
expr->expr_cast.type_info = TRY_TYPE_OR(parse_type_expression(), &poisoned_expr);
|
||||
expr->cast_expr.type_info = TRY_TYPE_OR(parse_type_expression(), &poisoned_expr);
|
||||
CONSUME_OR(TOKEN_COMMA, &poisoned_expr);
|
||||
expr->expr_cast.expr = TRY_EXPR_OR(parse_expr(), &poisoned_expr);
|
||||
expr->cast_expr.expr = TRY_EXPR_OR(parse_expr(), &poisoned_expr);
|
||||
CONSUME_OR(TOKEN_RPAREN, &poisoned_expr);
|
||||
return expr;
|
||||
}
|
||||
|
||||
@@ -114,9 +114,12 @@ static bool sema_resolve_array_type(Context *context, TypeInfo *type)
|
||||
}
|
||||
if (type->array.len)
|
||||
{
|
||||
if (!sema_analyse_expr(context, type->array.len)) return type_info_poison(type);
|
||||
// Sema error on non const non positive integer.
|
||||
TODO
|
||||
if (!sema_analyse_expr(context, type_usize, type->array.len)) return type_info_poison(type);
|
||||
if (type->array.len->expr_kind != EXPR_CONST)
|
||||
{
|
||||
SEMA_ERROR(type->array.len->loc, "Expected a constant value as array size.");
|
||||
return type_info_poison(type);
|
||||
}
|
||||
}
|
||||
assert(!type->array.len || type->array.len->expr_kind == EXPR_CONST);
|
||||
type->type = type_get_array(type->array.base->type, type->array.len ? type->array.len->const_expr.i : 0);
|
||||
@@ -208,13 +211,12 @@ 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_analyse_expr(context, expr)) return false;
|
||||
if (!sema_analyse_expr(context, param->type, expr)) return false;
|
||||
if (expr->expr_kind != EXPR_CONST)
|
||||
{
|
||||
SEMA_ERROR(expr->loc, "Only constant expressions may be used as default values.");
|
||||
return false;
|
||||
}
|
||||
if (!cast(expr, param->type, CAST_TYPE_IMPLICIT_ASSIGN)) return false;
|
||||
}
|
||||
return true;
|
||||
}
|
||||
@@ -320,7 +322,7 @@ static inline bool sema_analyse_return_stmt(Context *context, Ast *statement)
|
||||
}
|
||||
return true;
|
||||
}
|
||||
if (!sema_analyse_expr(context, return_expr)) return false;
|
||||
if (!sema_analyse_expr(context, expected_rtype, return_expr)) return false;
|
||||
if (!expected_rtype)
|
||||
{
|
||||
assert(context->evaluating_macro);
|
||||
@@ -340,26 +342,16 @@ static inline bool sema_analyse_return_stmt(Context *context, Ast *statement)
|
||||
static inline bool sema_analyse_var_decl(Context *context, Decl *decl)
|
||||
{
|
||||
assert(decl->decl_kind == DECL_VAR);
|
||||
if (!sema_resolve_type_info(context, decl->var.type_info)) return false;
|
||||
if (!sema_resolve_type_info(context, decl->var.type_info)) return decl_poison(decl);
|
||||
decl->type = decl->var.type_info->type;
|
||||
if (decl->var.init_expr)
|
||||
{
|
||||
Type *prev_type = context->left_type_in_assignment;
|
||||
context->left_type_in_assignment = decl->var.type_info->type;
|
||||
bool success = sema_analyse_expr(context, decl->var.init_expr) && cast(decl->var.init_expr, decl->var.type_info->type, CAST_TYPE_IMPLICIT_ASSIGN);
|
||||
context->left_type_in_assignment = prev_type;
|
||||
if (!success)
|
||||
{
|
||||
decl_poison(decl);
|
||||
return false;
|
||||
}
|
||||
if (!sema_analyse_expr(context, decl->type, decl->var.init_expr)) return decl_poison(decl);
|
||||
}
|
||||
if (!context_add_local(context, decl)) return false;
|
||||
if (!context_add_local(context, decl)) return decl_poison(decl);
|
||||
return true;
|
||||
}
|
||||
|
||||
|
||||
|
||||
static inline Ast *convert_expr_to_ast(Expr *expr)
|
||||
{
|
||||
Ast *ast = new_ast(AST_EXPR_STMT, expr->loc);
|
||||
@@ -548,8 +540,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_analyse_expr(context, expr);
|
||||
success = success && cast(expr, type_bool, CAST_TYPE_IMPLICIT);
|
||||
success = sema_analyse_expr(context, type_bool, expr);
|
||||
context_pop_scope(context);
|
||||
return success;
|
||||
}
|
||||
@@ -581,7 +572,8 @@ static inline bool sema_analyse_declare_stmt(Context *context, Ast *statement)
|
||||
|
||||
static inline bool sema_analyse_expr_stmt(Context *context, Ast *statement)
|
||||
{
|
||||
return sema_analyse_expr(context, statement->expr_stmt);
|
||||
if (!sema_analyse_expr(context, NULL, statement->expr_stmt)) return false;
|
||||
return true;
|
||||
}
|
||||
|
||||
static inline bool sema_analyse_defer_stmt(Context *context, Ast *statement)
|
||||
@@ -686,7 +678,7 @@ static inline bool sema_analyse_label(Context *context, Ast *statement)
|
||||
return false;
|
||||
}
|
||||
}
|
||||
VECADD(context->labels, statement);
|
||||
vec_add(context->labels, statement);
|
||||
VECEACH(context->gotos, i)
|
||||
{
|
||||
Ast *the_goto = context->gotos[i];
|
||||
@@ -755,13 +747,12 @@ static inline bool sema_analyse_then_overwrite(Context *context, Ast *statement,
|
||||
|
||||
static int sema_check_comp_time_bool(Context *context, Expr *expr)
|
||||
{
|
||||
if (!sema_analyse_expr(context, expr)) return -1;
|
||||
if (!sema_analyse_expr(context, type_bool, 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;
|
||||
}
|
||||
|
||||
@@ -811,8 +802,7 @@ static bool sema_analyse_switch_case(Context *context, Ast*** prev_cases, Ast *c
|
||||
*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 (!sema_analyse_expr(context, switch_type, case_expr)) return false;
|
||||
if (case_expr->expr_kind != EXPR_CONST)
|
||||
{
|
||||
SEMA_ERROR(case_expr->loc, "This must be a constant expression.");
|
||||
@@ -1056,8 +1046,7 @@ static inline bool sema_analyse_global(Context *context, Decl *decl)
|
||||
if (!sema_resolve_type_info(context, decl->var.type_info)) return false;
|
||||
if (decl->var.init_expr)
|
||||
{
|
||||
if (!sema_analyse_expr(context, decl->var.init_expr)) return false;
|
||||
if (!cast(decl->var.init_expr, decl->var.type_info->type, CAST_TYPE_IMPLICIT_ASSIGN)) return false;
|
||||
if (!sema_analyse_expr(context, decl->type, decl->var.init_expr)) return false;
|
||||
if (decl->var.init_expr->expr_kind != EXPR_CONST)
|
||||
{
|
||||
SEMA_ERROR(decl->var.init_expr->loc, "The expression must be a constant value.");
|
||||
@@ -1344,7 +1333,7 @@ bool sema_resolve_type_shallow(Context *context, TypeInfo *type_info)
|
||||
case TYPE_INFO_IDENTIFIER:
|
||||
return sema_resolve_type_identifier(context, type_info);
|
||||
case TYPE_INFO_EXPRESSION:
|
||||
if (!sema_analyse_expr(context, type_info->unresolved_type_expr))
|
||||
if (!sema_analyse_expr(context, NULL, type_info->unresolved_type_expr))
|
||||
{
|
||||
return type_info_poison(type_info);
|
||||
}
|
||||
|
||||
@@ -21,26 +21,26 @@ Type t_cus, t_cui, t_cul, t_cull;
|
||||
Type t_cs, t_ci, t_cl, t_cll;
|
||||
Type t_voidstar;
|
||||
|
||||
Type *type_signed_int_by_size(int bitsize)
|
||||
Type *type_signed_int_by_size(int bytesize)
|
||||
{
|
||||
switch (bitsize)
|
||||
switch (bytesize)
|
||||
{
|
||||
case 1: return type_char;
|
||||
case 2: return type_short;
|
||||
case 4: return type_int;
|
||||
case 8: return type_long;
|
||||
default: FATAL_ERROR("Illegal bitsize %d", bitsize);
|
||||
default: FATAL_ERROR("Illegal bytesize %d", bytesize);
|
||||
}
|
||||
}
|
||||
Type *type_unsigned_int_by_size(int bitsize)
|
||||
Type *type_unsigned_int_by_size(int bytesize)
|
||||
{
|
||||
switch (bitsize)
|
||||
switch (bytesize)
|
||||
{
|
||||
case 1: return type_byte;
|
||||
case 2: return type_ushort;
|
||||
case 4: return type_uint;
|
||||
case 8: return type_ulong;
|
||||
default: FATAL_ERROR("Illegal bitsize %d", bitsize);
|
||||
default: FATAL_ERROR("Illegal bytesize %d", bytesize);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -397,3 +397,240 @@ bool type_may_have_method_functions(Type *type)
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
typedef enum
|
||||
{
|
||||
L,
|
||||
LS,
|
||||
R,
|
||||
RS,
|
||||
FL,
|
||||
} MaxType;
|
||||
|
||||
Type *type_find_max_num_type(Type *num_type, Type *other_num)
|
||||
{
|
||||
if (other_num->type_kind < TYPE_BOOL || other_num->type_kind > TYPE_FXX) return NULL;
|
||||
assert(num_type->type_kind >= TYPE_BOOL && num_type->type_kind <= TYPE_FXX);
|
||||
static MaxType max_conv[TYPE_FXX - TYPE_BOOL + 1][TYPE_FXX - TYPE_BOOL + 1] = {
|
||||
//Bool I8 I16 I32 I64 IXX U8 U16 U32 U64 UXX F32 F64 FXX
|
||||
{ L, R, R, R, R, L, R, R, R, R, L, R, R, FL }, // Bool
|
||||
{ L, L, R, R, R, L, L, RS, RS, RS, L, R, R, FL }, // I8
|
||||
{ L, L, L, R, R, L, L, L, RS, RS, L, R, R, FL }, // I16
|
||||
{ L, L, L, L, R, L, L, L, L, RS, L, R, R, FL }, // I32
|
||||
{ L, L, L, L, L, L, L, L, L, L, L, R, R, FL }, // I64
|
||||
{ R, R, R, R, R, L, RS, RS, RS, RS, L, R, R, R }, // IXX
|
||||
{ L, R, R, R, R, LS, L, R, R, R, L, R, R, FL }, // U8
|
||||
{ L, LS, R, R, R, LS, L, L, R, R, L, R, R, FL }, // U16
|
||||
{ L, LS, LS, R, R, L, L, L, L, R, L, R, R, FL }, // U32
|
||||
{ L, LS, LS, LS, R, L, L, L, L, L, L, R, R, FL }, // U64
|
||||
{ R, R, R, R, R, R, R, R, R, R, L, R, R, R }, // UXX
|
||||
{ L, L, L, L, L, L, L, L, L, L, L, L, R, L }, // F32
|
||||
{ L, L, L, L, L, L, L, L, L, L, L, L, L, L }, // F32
|
||||
{ FL, FL, FL, FL, FL, FL, FL, FL, FL, FL, L, R, R, L }, // FXX
|
||||
};
|
||||
MaxType conversion = max_conv[num_type->type_kind - TYPE_BOOL][other_num->type_kind - TYPE_BOOL];
|
||||
switch (conversion)
|
||||
{
|
||||
case L:
|
||||
assert (num_type->type_kind != TYPE_FXX);
|
||||
return num_type;
|
||||
case R:
|
||||
assert (other_num->type_kind != TYPE_FXX);
|
||||
return other_num;
|
||||
case LS:
|
||||
return type_signed_int_by_size(num_type->builtin.bytesize);
|
||||
case RS:
|
||||
return type_signed_int_by_size(other_num->builtin.bytesize);
|
||||
case FL:
|
||||
return type_double;
|
||||
default:
|
||||
UNREACHABLE
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* max(Foo[:], Bar*) -> max(Foo*, Bar*)
|
||||
* max(Foo[], Bar*) -> max(Foo*, Bar*)
|
||||
* max(Foo[n]*, Bar*) -> max(Foo*, Bar*)
|
||||
* max(void*, Foo*) -> void*
|
||||
* max(Foo*, Bar*) -> max(Foo, Bar)*
|
||||
* max(other, Foo*) -> NULL
|
||||
*
|
||||
* @param type
|
||||
* @param other
|
||||
* @return the max pointer type or NULL if none can be found.
|
||||
*/
|
||||
static inline Type *type_find_max_ptr_type(Type *type, Type *other)
|
||||
{
|
||||
// Subarray and vararray can implicitly convert to a pointer.
|
||||
if (other->type_kind == TYPE_SUBARRAY || other->type_kind == TYPE_VARARRAY)
|
||||
{
|
||||
Type *max_type = type_find_max_type(type->pointer, other->pointer);
|
||||
if (!max_type) return NULL;
|
||||
return type_get_ptr(max_type);
|
||||
}
|
||||
|
||||
// Neither subarray, vararray or pointer? Then no max
|
||||
if (other->type_kind != TYPE_POINTER) return NULL;
|
||||
|
||||
Type* other_pointer_type = other->pointer;
|
||||
Type* pointer_type = type->pointer;
|
||||
|
||||
// Reorder if needed
|
||||
if (other_pointer_type->type_kind < pointer_type->type_kind)
|
||||
{
|
||||
pointer_type = other_pointer_type;
|
||||
other_pointer_type = type->pointer;
|
||||
}
|
||||
|
||||
// void * is always max.
|
||||
if (pointer_type->type_kind == TYPE_VOID) return type_voidptr;
|
||||
|
||||
if (pointer_type->type_kind == TYPE_POINTER && other_pointer_type->type_kind == TYPE_ARRAY)
|
||||
{
|
||||
// Decay foo[n]* to foo*
|
||||
other_pointer_type = type_get_ptr(other_pointer_type->array.base);
|
||||
}
|
||||
|
||||
Type *max_type = type_find_max_type(pointer_type, other_pointer_type);
|
||||
if (!max_type) return NULL;
|
||||
return type_get_ptr(max_type);
|
||||
}
|
||||
|
||||
/**
|
||||
* Find the maximum vararray type. Due to ordering the other type fullfils
|
||||
* other->type_kind >= TYPE_VARARRAY
|
||||
*
|
||||
* @param type
|
||||
* @param other
|
||||
* @return maximum type or NULL if none is found.
|
||||
*/
|
||||
static inline Type *type_find_max_vararray_type(Type *type, Type *other)
|
||||
{
|
||||
assert(other->canonical != type->canonical && "Expected different types");
|
||||
assert(other->type_kind >= type->type_kind && "Expected sorted types");
|
||||
switch (other->type_kind)
|
||||
{
|
||||
case TYPE_VARARRAY:
|
||||
// Because of the stride being different, it's not safe to implictly
|
||||
// convert one vararray to another. However, it is fine if they are both pointers
|
||||
// since the stride is the same.
|
||||
if (type->array.base->type_kind == TYPE_POINTER && other->array.base->type_kind == TYPE_POINTER)
|
||||
{
|
||||
// Jolly nice. Let's create the max from these:
|
||||
Type *max_type = type_find_max_ptr_type(type->array.base, other->array.base);
|
||||
if (max_type == NULL) return NULL;
|
||||
return type_get_array(max_type, 0);
|
||||
}
|
||||
// If it's not a pointer then there's no real way of converting them.
|
||||
return NULL;
|
||||
case TYPE_SUBARRAY:
|
||||
TODO; // Will return the subarray
|
||||
default:
|
||||
UNREACHABLE
|
||||
}
|
||||
}
|
||||
|
||||
Type *type_find_max_type(Type *type, Type *other)
|
||||
{
|
||||
assert(type->canonical == type);
|
||||
assert(other->canonical == other);
|
||||
if (type == other) return type;
|
||||
|
||||
// Sort types
|
||||
if (type->type_kind > other->type_kind)
|
||||
{
|
||||
Type *temp = type;
|
||||
type = other;
|
||||
other = temp;
|
||||
}
|
||||
|
||||
switch (type->type_kind)
|
||||
{
|
||||
case TYPE_POISONED:
|
||||
case TYPE_VOID:
|
||||
return NULL;
|
||||
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_find_max_num_type(type, other);
|
||||
case TYPE_POINTER:
|
||||
return type_find_max_ptr_type(type, other);
|
||||
case TYPE_ENUM:
|
||||
// IMPROVE: should there be implicit conversion between one enum and the other in
|
||||
// some way?
|
||||
return NULL;
|
||||
case TYPE_ERROR:
|
||||
TODO
|
||||
case TYPE_FUNC:
|
||||
case TYPE_UNION:
|
||||
case TYPE_ERROR_UNION:
|
||||
return NULL;
|
||||
case TYPE_STRUCT:
|
||||
TODO
|
||||
case TYPE_TYPEDEF:
|
||||
UNREACHABLE
|
||||
case TYPE_STRING:
|
||||
TODO
|
||||
case TYPE_ARRAY:
|
||||
return NULL;
|
||||
case TYPE_VARARRAY:
|
||||
return type_find_max_vararray_type(type, other);
|
||||
case TYPE_SUBARRAY:
|
||||
TODO
|
||||
}
|
||||
}
|
||||
|
||||
Type *type_find_common_ancestor(Type *left, Type *right)
|
||||
{
|
||||
if (left == right) return left;
|
||||
left = left->canonical;
|
||||
right = right->canonical;
|
||||
if (left == right) return left;
|
||||
if (left->type_kind != right->type_kind) return NULL;
|
||||
if (left->type_kind == TYPE_POINTER)
|
||||
{
|
||||
Type *common = type_find_common_ancestor(left->pointer, right->pointer);
|
||||
return common ? type_generate_ptr(common, true) : NULL;
|
||||
}
|
||||
if (left->type_kind != TYPE_STRUCT) return NULL;
|
||||
|
||||
static const int MAX_SEARCH_DEPTH = 512;
|
||||
static Type *left_types[MAX_SEARCH_DEPTH];
|
||||
int depth = 0;
|
||||
while (depth < MAX_SEARCH_DEPTH)
|
||||
{
|
||||
if (!left->decl->strukt.members) break;
|
||||
Decl *first_element = left->decl->strukt.members[0];
|
||||
if (first_element->decl_kind != DECL_VAR) break;
|
||||
if (first_element->type->canonical == right) return right;
|
||||
left = first_element->type->canonical;
|
||||
left_types[depth++] = left;
|
||||
}
|
||||
if (depth == MAX_SEARCH_DEPTH)
|
||||
{
|
||||
error_exit("Struct type depth %d exceeded.", MAX_SEARCH_DEPTH);
|
||||
}
|
||||
while (true)
|
||||
{
|
||||
if (!right->decl->strukt.members) return NULL;
|
||||
Decl *first_element = right->decl->strukt.members[0];
|
||||
if (first_element->decl_kind != DECL_VAR) return NULL;
|
||||
right = first_element->type->canonical;
|
||||
for (int i = 0; i < depth; i++)
|
||||
{
|
||||
if (right == left_types[i]) return right;
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -266,7 +266,7 @@ static inline void* _expand(void *vec, size_t element_size)
|
||||
#define VECNEW(_type, _capacity) ((_type *)(_vec_new(sizeof(_type), _capacity) + 1))
|
||||
#define VECADD(_vec, _value) \
|
||||
({ \
|
||||
typeof(_vec) __temp = (typeof(_vec))_expand((_vec), sizeof((_vec)[0])); \
|
||||
typeof(_vec) __temp = (typeof(_vec))_expand((_vec), sizeof(typeof(*(_vec)))); \
|
||||
__temp[vec_size(__temp) - 1] = _value; \
|
||||
_vec = __temp; })
|
||||
#define vec_add(_vec, _value) do { (_vec) = VECADD((_vec), _value); } while (0)
|
||||
|
||||
Reference in New Issue
Block a user