diff --git a/resources/testfragments/super_simple.c3 b/resources/testfragments/super_simple.c3 index 11cdd573c..de38edbd6 100644 --- a/resources/testfragments/super_simple.c3 +++ b/resources/testfragments/super_simple.c3 @@ -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; } \ No newline at end of file diff --git a/src/compiler/ast.c b/src/compiler/ast.c index 8569d28d5..19d37a08a 100644 --- a/src/compiler/ast.c +++ b/src/compiler/ast.c @@ -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: diff --git a/src/compiler/casts.c b/src/compiler/casts.c index 17d773b78..5c2e6b1ac 100644 --- a/src/compiler/casts.c +++ b/src/compiler/casts.c @@ -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); } diff --git a/src/compiler/compiler_internal.h b/src/compiler/compiler_internal.h index 7e915d84d..b666b94a1 100644 --- a/src/compiler/compiler_internal.h +++ b/src/compiler/compiler_internal.h @@ -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; } diff --git a/src/compiler/enums.h b/src/compiler/enums.h index 7b7ea4459..085a9beb7 100644 --- a/src/compiler/enums.h +++ b/src/compiler/enums.h @@ -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, diff --git a/src/compiler/expr_analysis.c b/src/compiler/expr_analysis.c index 65ba60bf2..801d60b2e 100644 --- a/src/compiler/expr_analysis.c +++ b/src/compiler/expr_analysis.c @@ -4,20 +4,25 @@ #include "compiler_internal.h" -typedef bool(*ExprAnalysis)(Context *, Expr*); -typedef bool(*ExprBinopAnalysis)(Context *, Expr*, Expr*, Expr*); -typedef bool(*ExprUnaryAnalysis)(Context *, Expr*, Expr*); -static ExprBinopAnalysis BINOP_ANALYSIS[TOKEN_EOF]; -static ExprUnaryAnalysis UNARYOP_ANALYSIS[TOKEN_EOF + 1]; -static ExprUnaryAnalysis POSTUNARYOP_ANALYSIS[TOKEN_EOF + 1]; +#define CONST_PROCESS(_op) \ +if (both_const(left, right)) { \ +switch (left->const_expr.type) { \ +case CONST_INT: expr->const_expr.i = left->const_expr.i _op right->const_expr.i; break; \ +case CONST_FLOAT: expr->const_expr.f = left->const_expr.f _op right->const_expr.f; break; \ +default: UNREACHABLE } \ +expr->expr_kind = EXPR_CONST; \ +expr->const_expr.type = left->const_expr.type; \ +} 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); + 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 + || expr->identifier_expr.decl->var.kind == VARDECL_PARAM); case EXPR_UNARY: return expr->unary_expr.operator == TOKEN_STAR; case EXPR_ACCESS: @@ -29,17 +34,40 @@ static bool expr_is_ltype(Expr *expr) static inline bool sema_type_error_on_binop(const char *op, Expr *expr) { - 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)); + 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; } -static inline bool sema_expr_analyse_conditional(Context *context, Expr *expr) +static inline bool sema_expr_analyse_conditional(Context *context, Type *to, Expr *expr) { - TODO + if (!sema_analyse_expr(context, type_bool, expr->conditional_expr.cond)) return expr_poison(expr); + Expr *left = expr->conditional_expr.then_expr; + Expr *right = expr->conditional_expr.else_expr; + if (!sema_analyse_expr(context, to, left)) return expr_poison(expr); + if (!sema_analyse_expr(context, to, right)) return expr_poison(expr); + + Type *left_canonical = left->type->canonical; + Type *right_canonical = right->type->canonical; + if (left_canonical != right_canonical) + { + Type *max = type_find_max_type(left_canonical, right_canonical); + if (!max) + { + SEMA_ERROR(expr->loc, "Cannot find a common parent type of '%s' and '%s'", + type_to_error_string(left_canonical), type_to_error_string(right_canonical)); + return false; + } + if (!cast_implicit(left, max) || !cast_implicit(right, max)) return false; + } + + expr->type = left->type; + + return true; } -static inline bool sema_expr_analyse_identifier(Context *context, Expr *expr) +static inline bool sema_expr_analyse_identifier(Context *context, Type *to, Expr *expr) { // TODO what about struct functions if (expr->identifier_expr.path) @@ -64,8 +92,13 @@ static inline bool sema_expr_analyse_identifier(Context *context, Expr *expr) return true; } -static inline bool sema_expr_analyse_var_call(Context *context, Expr *expr) { TODO } -static inline bool sema_expr_analyse_macro_call(Context *context, Expr *expr, Decl *macro) +static inline bool sema_expr_analyse_binary_sub_expr(Context *context, Expr *left, Expr *right) +{ + return sema_analyse_expr(context, NULL, left) & sema_analyse_expr(context, NULL, right); +} + +static inline bool sema_expr_analyse_var_call(Context *context, Type *to, Expr *expr) { TODO } +static inline bool sema_expr_analyse_macro_call(Context *context, Type *to, Expr *expr, Decl *macro) { Ast *macro_parent; // TODO handle loops @@ -82,11 +115,10 @@ static inline bool sema_expr_analyse_macro_call(Context *context, Expr *expr, De TODO return success; }; -static inline bool sema_expr_analyse_generic_call(Context *context, Expr *expr) { TODO }; +static inline bool sema_expr_analyse_generic_call(Context *context, Type *to, Expr *expr) { TODO }; -static inline bool sema_expr_analyse_func_call(Context *context, Expr *expr, Decl *decl) +static inline bool sema_expr_analyse_func_call(Context *context, Type *to, Expr *expr, Decl *decl) { - if (decl->func.function_signature.throws != NULL) TODO Expr **args =expr->call_expr.arguments; Decl **func_params = decl->func.function_signature.params; unsigned num_args = vec_size(args); @@ -95,17 +127,17 @@ 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_analyse_expr(context, arg)) return false; - if (!cast(arg, func_params[i]->type, CAST_TYPE_IMPLICIT_ASSIGN)) return false; + if (!sema_analyse_expr(context, func_params[i]->type, arg)) return false; } expr->type = decl->func.function_signature.rtype->type; return true; } -static inline bool sema_expr_analyse_call(Context *context, Expr *expr) +static inline bool sema_expr_analyse_call(Context *context, Type *to, Expr *expr) { + // TODO Expr *func_expr = expr->call_expr.function; - if (!sema_analyse_expr(context, func_expr)) return false; + if (!sema_analyse_expr(context, to, func_expr)) return false; Decl *decl; switch (func_expr->expr_kind) { @@ -121,13 +153,13 @@ static inline bool sema_expr_analyse_call(Context *context, Expr *expr) switch (decl->decl_kind) { case DECL_VAR: - return sema_expr_analyse_var_call(context, expr); + return sema_expr_analyse_var_call(context, to, expr); case DECL_FUNC: - return sema_expr_analyse_func_call(context, expr, decl); + return sema_expr_analyse_func_call(context, to, expr, decl); case DECL_MACRO: - return sema_expr_analyse_macro_call(context, expr, decl); + return sema_expr_analyse_macro_call(context, to, expr, decl); case DECL_GENERIC: - return sema_expr_analyse_generic_call(context, expr); + return sema_expr_analyse_generic_call(context, to, expr); default: SEMA_ERROR(expr->loc, "The expression cannot be called."); return false; @@ -135,17 +167,17 @@ static inline bool sema_expr_analyse_call(Context *context, Expr *expr) } } -static inline bool sema_expr_analyse_struct_value(Context *context, Expr *expr) +static inline bool sema_expr_analyse_struct_value(Context *context, Type *to, Expr *expr) { TODO } -static inline bool sema_expr_analyse_struct_init_values(Context *context, Expr *expr) +static inline bool sema_expr_analyse_struct_init_values(Context *context, Type *to, Expr *expr) { TODO } -static inline bool sema_expr_analyse_subscript(Context *context, Expr *expr) +static inline bool sema_expr_analyse_subscript(Context *context, Type *to, Expr *expr) { TODO } @@ -219,9 +251,9 @@ static Decl *strukt_recursive_search_member(Decl *strukt, const char *name, int return NULL; } -static inline bool sema_expr_analyse_access(Context *context, Expr *expr) +static inline bool sema_expr_analyse_access(Context *context, Type *to, Expr *expr) { - if (!sema_analyse_expr(context, expr->access_expr.parent)) return false; + if (!sema_analyse_expr(context, NULL, expr->access_expr.parent)) return false; Type *parent_type = expr->access_expr.parent->type; Type *type = parent_type->canonical; @@ -268,7 +300,7 @@ static inline bool sema_expr_analyse_access(Context *context, Expr *expr) return true; } -static inline bool sema_expr_analyse_type_access(Context *context, Expr *expr) +static inline bool sema_expr_analyse_type_access(Context *context, Type *to, Expr *expr) { TypeInfo *type_info = expr->type_access.type; if (!sema_resolve_type_info(context, type_info)) return false; @@ -359,10 +391,10 @@ static inline bool sema_expr_analyse_struct_initializer_list(Context *context, T expr->type = assigned; return true; } -static inline bool sema_expr_analyse_initializer_list(Context *context, Expr *expr) +static inline bool sema_expr_analyse_initializer_list(Context *context, Type *to, Expr *expr) { - assert(context->left_type_in_assignment); - Type *assigned = context->left_type_in_assignment->canonical; + assert(to); + Type *assigned = to->canonical; assert(assigned); switch (assigned->type_kind) { @@ -377,23 +409,33 @@ static inline bool sema_expr_analyse_initializer_list(Context *context, Expr *ex default: break; } - SEMA_ERROR(expr->loc, "Cannot assign expression to '%s'.", type_to_error_string(context->left_type_in_assignment)); + SEMA_ERROR(expr->loc, "Cannot assign expression to '%s'.", type_to_error_string(to)); return false; } -static inline bool sema_expr_analyse_sizeof(Context *context, Expr *expr) +static inline bool sema_expr_analyse_sizeof(Context *context, Type *to, Expr *expr) { TODO } - -static inline bool sema_expr_analyse_cast(Context *context, Expr *expr) +static inline bool sema_expr_analyse_expr_list(Context *context, Type *to, Expr *expr) { - Expr *inner = expr->expr_cast.expr; - if (!sema_resolve_type_info(context, expr->expr_cast.type_info)) return false; - if (!sema_analyse_expr(context, inner)) return false; + bool success = true; + size_t last = vec_size(expr->expression_list) - 1; + VECEACH(expr->expression_list, i) + { + success &= sema_analyse_expr(context, i == last ? to : NULL, expr); + } + return success; +} - if (!cast(inner, expr->expr_cast.type_info->type, CAST_TYPE_EXPLICIT)) return false; +static inline bool sema_expr_analyse_cast(Context *context, Type *to, Expr *expr) +{ + Expr *inner = expr->cast_expr.expr; + if (!sema_resolve_type_info(context, expr->cast_expr.type_info)) return false; + if (!sema_analyse_expr(context, NULL, inner)) return false; + + if (!cast(inner, expr->cast_expr.type_info->type, CAST_TYPE_EXPLICIT)) return false; // TODO above is probably not right, cast type not set. // Overwrite cast. @@ -405,27 +447,17 @@ static inline bool sema_expr_analyse_cast(Context *context, Expr *expr) } -static bool sema_expr_analyse_assign(Context *context, Expr *expr, Expr *left, Expr *right) +static bool sema_expr_analyse_assign(Context *context, Type *to, Expr *expr, Expr *left, Expr *right) { - if (!sema_analyse_expr(context, left)) return false; + if (!sema_analyse_expr(context, NULL, left)) return false; if (!expr_is_ltype(left)) { SEMA_ERROR(left->loc, "Expression is not assignable."); return false; } - - Type *prev_type = context->left_type_in_assignment; - context->left_type_in_assignment = left->type; - - bool success = sema_analyse_expr(context, right); - - context->left_type_in_assignment = prev_type; - - if (!success) return false; - - if (!cast(right, left->type, CAST_TYPE_IMPLICIT_ASSIGN)) return false; - + if (!sema_analyse_expr(context, left->type, right)) return false; + expr->type = right->type; return true; } @@ -434,196 +466,343 @@ static inline bool both_const(Expr *left, Expr *right) return left->expr_kind == EXPR_CONST && right->expr_kind == EXPR_CONST; } -static bool sema_expr_analyse_bit_and_assign(Context *context, Expr *expr, Expr *left, Expr *right) { TODO } -static bool sema_expr_analyse_bit_or_assign(Context *context, Expr *expr, Expr *left, Expr *right) { TODO } -static bool sema_expr_analyse_bit_xor_assign(Context *context, Expr *expr, Expr *left, Expr *right) { TODO } -static bool sema_expr_analyse_div_assign(Context *context, Expr *expr, Expr *left, Expr *right) { TODO } -static bool sema_expr_analyse_add_assign(Context *context, Expr *expr, Expr *left, Expr *right) { TODO } -static bool sema_expr_analyse_sub_assign(Context *context, Expr *expr, Expr *left, Expr *right) { TODO } -static bool sema_expr_analyse_mult_assign(Context *context, Expr *expr, Expr *left, Expr *right) { TODO } - -static bool sema_expr_analyse_add(Context *context, Expr *expr, Expr *left, Expr *right) +static bool sema_expr_analyse_bit_and_assign(Context *context, Type *to, Expr *expr, Expr *left, Expr *right) { - Type *left_type = left->type->canonical; - Type *right_type = right->type->canonical; - if (left_type->type_kind == TYPE_POINTER) - { - if (!cast_arithmetic(right, left, "+")) return false; - expr->type = left_type; - return true; - } - if (right_type->type_kind == TYPE_POINTER) - { - if (!cast_arithmetic(left, right, "+")) return false; - expr->type = right_type; - return true; - } - if (!cast_arithmetic(left, right, "+")) return false; - if (!cast_arithmetic(right, left, "+")) return false; + if (!sema_analyse_expr(context, NULL, left)) return false; - Type *canonical = left->type->canonical; - if (!type_is_number(canonical)) + if (!type_is_number(left->type)) { - SEMA_ERROR(expr->loc, "Add is not allowed"); + SEMA_ERROR(left->loc, "Expected a numeric type here."); return false; } - if (both_const(left, right)) + + if (!sema_analyse_expr(context, left->type->canonical, right)) return false; + + if (!type_is_number(right->type)) { - switch (left->const_expr.type) - { - case CONST_INT: - expr->const_expr.i = left->const_expr.i + right->const_expr.i; - break; - case CONST_FLOAT: - expr->const_expr.f = left->const_expr.f + right->const_expr.f; - break; - default: - UNREACHABLE - } - expr->expr_kind = EXPR_CONST; - expr->const_expr.type = left->const_expr.type; + SEMA_ERROR(right->loc, "Expected a numeric type here."); + return false; } + expr->type = left->type; - return true; + return cast(right, left->type, CAST_TYPE_IMPLICIT_ASSIGN_ADD); } -static bool sema_expr_analyse_sub(Context *context, Expr *expr, Expr *left, Expr *right) +static bool sema_expr_analyse_bit_or_assign(Context *context, Type *to, Expr *expr, Expr *left, Expr *right) { + if (!sema_analyse_expr(context, NULL, left)) return false; + + if (!type_is_number(left->type)) + { + SEMA_ERROR(left->loc, "Expected a numeric type here."); + return false; + } + + if (!sema_analyse_expr(context, left->type->canonical, right)) return false; + + if (!type_is_number(right->type)) + { + SEMA_ERROR(right->loc, "Expected a numeric type here."); + return false; + } + + expr->type = left->type; + return cast(right, left->type, CAST_TYPE_IMPLICIT_ASSIGN_ADD); +} + +static bool sema_expr_analyse_bit_xor_assign(Context *context, Type *to, Expr *expr, Expr *left, Expr *right) +{ + if (!sema_analyse_expr(context, NULL, left)) return false; + + if (!type_is_number(left->type)) + { + SEMA_ERROR(left->loc, "Expected a numeric type here."); + return false; + } + + if (!sema_analyse_expr(context, left->type->canonical, right)) return false; + + if (!type_is_number(right->type)) + { + SEMA_ERROR(right->loc, "Expected a numeric type here."); + return false; + } + + expr->type = left->type; + return cast(right, left->type, CAST_TYPE_IMPLICIT_ASSIGN_ADD); + +} + +static bool sema_expr_analyse_div_assign(Context *context, Type *to, Expr *expr, Expr *left, Expr *right) +{ + if (!sema_analyse_expr(context, NULL, left)) return false; + + if (!type_is_number(left->type)) + { + SEMA_ERROR(left->loc, "Expected a numeric type here."); + return false; + } + + if (!sema_analyse_expr(context, left->type->canonical, right)) return false; + + if (!type_is_number(right->type)) + { + SEMA_ERROR(right->loc, "Expected a numeric type here."); + return false; + } + + expr->type = left->type; + return cast(right, left->type, CAST_TYPE_IMPLICIT_ASSIGN_ADD); +} + +static bool sema_expr_analyse_mult_assign(Context *context, Type *to, Expr *expr, Expr *left, Expr *right) +{ + if (!sema_analyse_expr(context, NULL, left)) return false; + + if (!type_is_number(left->type)) + { + SEMA_ERROR(left->loc, "Expected a numeric type here."); + return false; + } + + if (!sema_analyse_expr(context, left->type->canonical, right)) return false; + + if (!type_is_number(right->type)) + { + SEMA_ERROR(right->loc, "Expected a numeric type here."); + return false; + } + + expr->type = left->type; + return cast(right, left->type, CAST_TYPE_IMPLICIT_ASSIGN_ADD); +} + + +static bool sema_expr_analyse_sub_assign(Context *context, Type *to, Expr *expr, Expr *left, Expr *right) +{ + if (!sema_analyse_expr(context, NULL, left)) return false; + + Type *left_type_canonical = left->type->canonical; + + if (left_type_canonical->type_kind == TYPE_POINTER) + { + if (!sema_analyse_expr(context, NULL, right)) return false; + // Improve check if this should be usize. + if (!cast_to_runtime(right)) return false; + Type *right_type = right->type->canonical; + if (!type_is_integer(right_type)) + { + SEMA_ERROR(right->loc, "Expected an integer type instead."); + return false; + } + expr->type = left->type; + return true; + } + + if (!sema_analyse_expr(context, left->type->canonical, right)) return false; + + if (!type_is_number(left->type)) + { + SEMA_ERROR(left->loc, "Expected a numeric type here."); + return false; + } + + if (!type_is_number(right->type)) + { + SEMA_ERROR(right->loc, "Expected a numeric type here."); + return false; + } + + expr->type = left->type; + + return cast(right, left->type, CAST_TYPE_IMPLICIT_ASSIGN_ADD); +} + +static bool sema_expr_analyse_add_assign(Context *context, Type *to, Expr *expr, Expr *left, Expr *right) +{ + if (!sema_analyse_expr(context, NULL, left)) return false; + + Type *left_type_canonical = left->type->canonical; + + if (left_type_canonical->type_kind == TYPE_POINTER) + { + if (!sema_analyse_expr(context, NULL, right)) return false; + // Improve check if this should be usize. + if (!cast_to_runtime(right)) return false; + Type *right_type = right->type->canonical; + if (!type_is_integer(right_type)) + { + SEMA_ERROR(right->loc, "Expected an integer type instead."); + return false; + } + expr->type = left->type; + return true; + } + + if (!sema_analyse_expr(context, left->type->canonical, right)) return false; + + if (!type_is_number(left->type)) + { + SEMA_ERROR(left->loc, "Expected a numeric type here."); + return false; + } + + if (!type_is_number(right->type)) + { + SEMA_ERROR(right->loc, "Expected a numeric type here."); + return false; + } + + expr->type = left->type; + + return cast(right, left->type, CAST_TYPE_IMPLICIT_ASSIGN_ADD); +} + +static bool binary_arithmetic_promotion(Expr *left, Expr *right, Type *left_type, Type *right_type) +{ + Type *max = type_find_max_type(left_type, right_type); + return max && type_is_number(max) && cast_implicit(left, max) && cast_implicit(right, max); +} + +static bool sema_expr_analyse_sub(Context *context, Type *to, Expr *expr, Expr *left, Expr *right) +{ + if (!sema_expr_analyse_binary_sub_expr(context, left, right)) return false; + Type *left_type = left->type->canonical; Type *right_type = right->type->canonical; + if (left_type->type_kind == TYPE_POINTER) { if (right_type->type_kind == TYPE_POINTER) { - if (!cast(right, left_type, CAST_TYPE_IMPLICIT)) return false; + Type *max = type_find_max_type(left_type, right_type); + bool success = max && cast_implicit(left, max) && cast_implicit(right, max); + if (!success) goto ERR; expr->type = type_isize; return true; } - if (!cast_arithmetic(right, left, "-")) return false; + // No need to cast this, we just ensure it is an integer. + if (!type_is_integer(right_type) || !cast_to_runtime(right)) goto ERR; expr->type = left->type; return true; } - if (!cast_arithmetic(left, right, "-")) return false; - if (!cast_arithmetic(right, left, "-")) return false; - Type *canonical = left->type->canonical; - if (!type_is_number(canonical)) + if (!binary_arithmetic_promotion(left, right, left_type, right_type)) goto ERR; + + CONST_PROCESS(-); + + expr->type = left->type; + return true; + + ERR: + SEMA_ERROR(expr->loc, "Cannot subtract '%s' from '%s'", type_to_error_string(left_type), type_to_error_string(right_type)); + return false; +} + +static bool sema_expr_analyse_add(Context *context, Type *to, Expr *expr, Expr *left, Expr *right) +{ + if (!sema_expr_analyse_binary_sub_expr(context, left, right)) return false; + + Type *left_type = left->type->canonical; + Type *right_type = right->type->canonical; + + // Reorder if needed + if (right_type->type_kind == TYPE_POINTER && left_type->type_kind != TYPE_POINTER) { - SEMA_ERROR(expr->loc, "- is not allowed"); - return false; + Expr *temp = right; + right = left; + left = temp; + right_type = left_type; + left_type = left->type->canonical; } - if (both_const(left, right)) + + if (left_type->type_kind == TYPE_POINTER) { - switch (left->const_expr.type) + // No need to cast this, we just ensure it is an integer. + if (!type_is_integer(right_type) || !cast_to_runtime(right)) goto ERR; + expr->type = left->type; + return true; + } + + if (!binary_arithmetic_promotion(left, right, left_type, right_type)) goto ERR; + + CONST_PROCESS(+); + + expr->type = left->type; + return true; + + ERR: + SEMA_ERROR(expr->loc, "Cannot add '%s' to '%s'", type_to_error_string(left_type), type_to_error_string(right_type)); + return false; +} + +static bool sema_expr_analyse_mult(Context *context, Type *to, Expr *expr, Expr *left, Expr *right) +{ + if (!sema_expr_analyse_binary_sub_expr(context, left, right)) return false; + + Type *left_type = left->type->canonical; + Type *right_type = right->type->canonical; + + if (!binary_arithmetic_promotion(left, right, left_type, right_type)) goto ERR; + + CONST_PROCESS(*) + + expr->type = left->type; + return true; + + ERR: + SEMA_ERROR(expr->loc, "Cannot multiply '%s' and '%s'", type_to_error_string(left_type), type_to_error_string(right_type)); + return false; +} + +static bool sema_expr_analyse_div(Context *context, Type *to, Expr *expr, Expr *left, Expr *right) +{ + if (!sema_expr_analyse_binary_sub_expr(context, left, right)) return false; + + Type *left_type = left->type->canonical; + Type *right_type = right->type->canonical; + + if (!binary_arithmetic_promotion(left, right, left_type, right_type)) goto ERR; + + // Check null + if (right->expr_kind == EXPR_CONST) + { + switch (right->const_expr.type) { case CONST_INT: - expr->const_expr.i = left->const_expr.i - right->const_expr.i; + if (right->const_expr.i == 0) + { + SEMA_ERROR(right->loc, "Division by zero not allowed."); + return false; + } break; case CONST_FLOAT: - expr->const_expr.f = left->const_expr.f - right->const_expr.f; + if (right->const_expr.f == 0) + { + SEMA_ERROR(right->loc, "Division by zero not allowed."); + return false; + } break; default: UNREACHABLE } - expr->expr_kind = EXPR_CONST; - expr->const_expr.type = left->const_expr.type; } + + CONST_PROCESS(/) + expr->type = left->type; return true; + + ERR: + SEMA_ERROR(expr->loc, "Cannot divide '%s' by '%s'", type_to_error_string(left_type), type_to_error_string(right_type)); + return false; + } -static bool sema_expr_analyse_mult(Context *context, Expr *expr, Expr *left, Expr *right) +static bool sema_expr_analyse_mod(Context *context, Type *to, Expr *expr, Expr *left, Expr *right) { - if (!cast_arithmetic(left, right, "*")) return false; - if (!cast_arithmetic(right, left, "*")) return false; + if (!sema_expr_analyse_binary_sub_expr(context, left, right)) return false; - Type *canonical = left->type->canonical; - if (!type_is_number(canonical)) - { - SEMA_ERROR(expr->loc, "* is not allowed"); - return false; - } - if (both_const(left, right)) - { - switch (left->const_expr.type) - { - case CONST_INT: - expr->const_expr.i = left->const_expr.i * right->const_expr.i; - break; - case CONST_FLOAT: - expr->const_expr.f = left->const_expr.f * right->const_expr.f; - break; - default: - UNREACHABLE - } - expr->expr_kind = EXPR_CONST; - expr->const_expr.type = left->const_expr.type; - } - expr->type = left->type; - return true; -} - -static bool sema_expr_analyse_div(Context *context, Expr *expr, Expr *left, Expr *right) -{ - if (!cast_arithmetic(left, right, "/")) return false; - if (!cast_arithmetic(right, left, "/")) return false; - - Type *canonical = left->type->canonical; - if (!type_is_number(canonical)) - { - SEMA_ERROR(expr->loc, "/ is not allowed"); - return false; - } - if (both_const(left, right)) - { - switch (left->const_expr.type) - { - case CONST_INT: - expr->const_expr.i = left->const_expr.i / right->const_expr.i; - break; - case CONST_FLOAT: - expr->const_expr.f = left->const_expr.f / right->const_expr.f; - break; - default: - UNREACHABLE - } - expr->expr_kind = EXPR_CONST; - expr->const_expr.type = left->const_expr.type; - } - expr->type = left->type; - return true; -} - - - /* - switch (left->type) - { - case CONST_NIL: - case CONST_BOOL: - case CONST_STRING: - UNREACHABLE; - case CONST_INT: - if (right->i == 0) - { - SEMA_ERROR(expr->binary_expr.right->loc, "Division by zero not allowed."); - return false; - } - result->i = left->i / right->i; - break; - case CONST_FLOAT: - if (right->f == 0) - { - SEMA_ERROR(expr->binary_expr.right->loc, "Division by zero not allowed."); - return false; - } - expr->const_expr.f = left->f / right->f; - expr->const_expr.type = CONST_FLOAT; - break; - }*/ - -static bool sema_expr_analyse_mod(Context *context, Expr *expr, Expr *left, Expr *right) -{ - if (!cast_arithmetic(left, right, "%") || !cast_arithmetic(right, left, "%")) return false; if (!type_is_integer(right->type->canonical) || !type_is_integer(left->type->canonical)) return sema_type_error_on_binop("%", expr); if (right->expr_kind == EXPR_CONST && right->const_expr.i == 0) @@ -631,48 +810,83 @@ static bool sema_expr_analyse_mod(Context *context, Expr *expr, Expr *left, Expr SEMA_ERROR(expr->binary_expr.right->loc, "Cannot perform mod by zero."); return false; } + // TODO Insert trap on negative right. if (left->expr_kind == EXPR_CONST && right->expr_kind == EXPR_CONST) { // TODO negative expr_replace(expr, left); expr->const_expr.i %= right->const_expr.i; - return true; + return expr; + } + + if (!cast_implicit(left, to)) return false; + + if (!cast_to_runtime(left) || !cast_to_runtime(right)) return false; + + expr->type = left->type; + + return true; +} + +static bool sema_expr_analyse_mod_assign(Context *context, Type *to, Expr *expr, Expr *left, Expr *right) +{ + + TODO } + + +static bool sema_expr_analyse_bit(Context *context, Type *to, Expr *expr, Expr *left, Expr *right) +{ + if (!sema_expr_analyse_binary_sub_expr(context, left, right)) return false; + + if (!type_is_integer(right->type->canonical) || !type_is_integer(left->type->canonical)) goto ERR; + + Type *left_type = left->type->canonical; + Type *right_type = right->type->canonical; + + if (!binary_arithmetic_promotion(left, right, left_type, right_type)) goto ERR; + + if (left->expr_kind == EXPR_CONST && right->expr_kind == EXPR_CONST) + { + expr_replace(expr, left); + switch (expr->binary_expr.operator) + { + case TOKEN_AMP: + expr->const_expr.i &= right->const_expr.i; + break; + case TOKEN_BIT_XOR: + expr->const_expr.i ^= right->const_expr.i; + break; + case TOKEN_BIT_OR: + expr->const_expr.i |= right->const_expr.i; + break; + default: + UNREACHABLE; + } + return expr; } expr->type = left->type; return true; + + ERR: + return sema_type_error_on_binop(token_type_to_string(expr->binary_expr.operator), expr); + } -static bool sema_expr_analyse_mod_assign(Context *context, Expr *expr, Expr *left, Expr *right) { TODO } -#define SEMA_ANALYSE_BIT(op) \ -{ if (!cast_arithmetic(left, right, #op) || !cast_arithmetic(right, left, #op)) return false; \ -if (left->type->canonical->type_kind != TYPE_BOOL && !type_is_integer(left->type)) sema_type_error_on_binop(#op, expr); \ -if (left->expr_kind == EXPR_CONST && right->expr_kind == EXPR_CONST)\ -{ expr_replace(expr, left); \ -if (left->const_expr.type == CONST_BOOL) \ -{ expr->const_expr.b |= right->const_expr.b; } \ -else { expr->const_expr.i |= expr->const_expr.i; } \ -return true; } \ -expr->type = left->type; \ -return true; } - -static bool sema_expr_analyse_bit_or(Context *context, Expr *expr, Expr *left, Expr *right) SEMA_ANALYSE_BIT(|) -static bool sema_expr_analyse_bit_xor(Context *context, Expr *expr, Expr *left, Expr *right) SEMA_ANALYSE_BIT(^) -static bool sema_expr_analyse_bit_and(Context *context, Expr *expr, Expr *left, Expr *right) SEMA_ANALYSE_BIT(&) - -static bool sema_expr_analyse_shr(Context *context, Expr *expr, Expr *left, Expr *right) +static bool sema_expr_analyse_shr(Context *context, Type *to, Expr *expr, Expr *left, Expr *right) { - // Todo: proper handling of signed / unsigned. Proper reduction of constants. - if (!type_is_integer(left->type) || !type_is_integer(right->type)) return sema_type_error_on_binop(">>", expr); - if (type_is_signed(right->type->canonical)) - { - cast(right, type_long, CAST_TYPE_IMPLICIT); - } - else - { - cast(left, type_ulong, CAST_TYPE_IMPLICIT); - } + + if (!sema_expr_analyse_binary_sub_expr(context, left, right)) return false; + + if (!type_is_integer(right->type->canonical) || !type_is_integer(left->type->canonical)) goto ERR; + + // First, try to do assign type promotion. + if (!cast_implicit(left, to)) goto ERR; + + // Next, cast to runtime types, this might be needed for runtime constants, e.g. x >> 2 + if (!cast_to_runtime(left) || !cast_to_runtime(right)) goto ERR; + if (right->expr_kind == EXPR_CONST) { if (right->const_expr.i > left->type->canonical->builtin.bitsize) @@ -687,22 +901,53 @@ static bool sema_expr_analyse_shr(Context *context, Expr *expr, Expr *left, Expr return true; } } + + expr->type = left->type; + return true; + + ERR: + return sema_type_error_on_binop(">>", expr); +} + +static bool sema_expr_analyse_shr_assign(Context *context, Type *to, Expr *expr, Expr *left, Expr *right) +{ + if (!sema_expr_analyse_binary_sub_expr(context, left, right)) return false; + + if (!expr_is_ltype(left)) + { + SEMA_ERROR(left->loc, "Expression is not assignable."); + return false; + } + + // Check that right side is integer and cast to a runtime type if needed. + if (!type_is_integer(right->type->canonical) || !cast_to_runtime(right)) return false; + + if (right->expr_kind == EXPR_CONST) + { + if (right->const_expr.i > left->type->canonical->builtin.bitsize) + { + SEMA_ERROR(right->loc, "Rightshift exceeds bitsize of '%s'", type_to_error_string(left->type)); + return false; + } + } + expr->type = left->type; return true; } -static bool sema_expr_analyse_shl(Context *context, Expr *expr, Expr *left, Expr *right) +static bool sema_expr_analyse_shl(Context *context, Type *to, Expr *expr, Expr *left, Expr *right) { - // Todo: proper handling of signed / unsigned. Proper reduction of constants. - if (!type_is_integer(left->type) || !type_is_integer(right->type)) return sema_type_error_on_binop("<<", expr); - if (type_is_signed(right->type->canonical)) - { - cast(right, type_long, CAST_TYPE_IMPLICIT); - } - else - { - cast(left, type_ulong, CAST_TYPE_IMPLICIT); - } + + if (!sema_expr_analyse_binary_sub_expr(context, left, right)) return false; + + if (!type_is_integer(right->type->canonical) || !type_is_integer(left->type->canonical)) goto ERR; + + // First, try to do assign type promotion. + if (!cast_implicit(left, to)) goto ERR; + + // Next, cast to runtime types, this might be needed for runtime constants, e.g. x << 2 + if (!cast_to_runtime(left) || !cast_to_runtime(right)) return false; + if (right->expr_kind == EXPR_CONST) { if (right->const_expr.i > left->type->canonical->builtin.bitsize) @@ -717,18 +962,49 @@ static bool sema_expr_analyse_shl(Context *context, Expr *expr, Expr *left, Expr return true; } } + + expr->type = left->type; + return true; + + ERR: + return sema_type_error_on_binop("<<", expr); +} + +static bool sema_expr_analyse_shl_assign(Context *context, Type *to, Expr *expr, Expr *left, Expr *right) +{ + if (!sema_expr_analyse_binary_sub_expr(context, left, right)) return false; + + if (!expr_is_ltype(left)) + { + SEMA_ERROR(left->loc, "Expression is not assignable."); + return false; + } + + // Check that right side is integer and cast to a runtime type if needed. + if (!type_is_integer(right->type->canonical)) return sema_type_error_on_binop("<<=", expr); + + if (!cast_to_runtime(right)) return false; + + if (right->expr_kind == EXPR_CONST) + { + if (right->const_expr.i > left->type->canonical->builtin.bitsize) + { + SEMA_ERROR(right->loc, "Leftshift exceeds bitsize of '%s'", type_to_error_string(left->type)); + return false; + } + } + expr->type = left->type; return true; } -static bool sema_expr_analyse_shr_assign(Context *context, Expr *expr, Expr *left, Expr *right) { TODO } -static bool sema_expr_analyse_shl_assign(Context *context, Expr *expr, Expr *left, Expr *right) { TODO } -static bool sema_expr_analyse_and(Context *context, Expr *expr, Expr *left, Expr *right) +static bool sema_expr_analyse_and(Context *context, Type *to, Expr *expr, Expr *left, Expr *right) { + if (!sema_expr_analyse_binary_sub_expr(context, left, right)) return false; + if (!cast_implicit(left, type_bool) || !cast_implicit(right, type_bool)) return false; + expr->type = type_bool; - if (!cast(left, type_bool, CAST_TYPE_IMPLICIT)) return false; - if (!cast(right, type_bool, CAST_TYPE_IMPLICIT)) return false; if (both_const(left, right)) { expr_replace(expr, left); @@ -737,10 +1013,11 @@ static bool sema_expr_analyse_and(Context *context, Expr *expr, Expr *left, Expr return true; } -static bool sema_expr_analyse_or(Context *context, Expr *expr, Expr *left, Expr *right) +static bool sema_expr_analyse_or(Context *context, Type *to, Expr *expr, Expr *left, Expr *right) { - if (!cast(left, type_bool, CAST_TYPE_IMPLICIT)) return false; - if (!cast(right, type_bool, CAST_TYPE_IMPLICIT)) return false; + if (!sema_expr_analyse_binary_sub_expr(context, left, right)) return false; + if (!cast_implicit(left, type_bool) || !cast_implicit(right, type_bool)) return false; + if (both_const(left, right)) { expr_replace(expr, left); @@ -750,8 +1027,56 @@ static bool sema_expr_analyse_or(Context *context, Expr *expr, Expr *left, Expr return true; } -static bool sema_expr_analyse_and_assign(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_and_assign(Context *context, Type *to, Expr *expr, Expr *left, Expr *right) { TODO } +static bool sema_expr_analyse_or_assign(Context *context, Type *to, Expr *expr, Expr *left, Expr *right) { TODO } + + +static bool sema_expr_analyse_comp(Context *context, Type *to, Expr *expr, Expr *left, Expr *right) +{ + if (!sema_expr_analyse_binary_sub_expr(context, left, right)) return false; + Type *left_type = left->type->canonical; + Type *right_type = right->type->canonical; + Type *max = type_find_max_type(left_type, right_type); + bool success = max && cast_implicit(left, max) && cast_implicit(right, max); + if (!success) + { + SEMA_ERROR(expr->loc, "Cannot implicitly convert types to evaluate '%s' %s '%s'", type_to_error_string(left_type), token_type_to_string(expr->binary_expr.operator), type_to_error_string(right_type)); + return false; + } + if (both_const(left, right)) + { +#define COMP(_op_) \ +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 } break; + switch (expr->binary_expr.operator) + { + case TOKEN_GREATER: + COMP(>) + case TOKEN_GREATER_EQ: + COMP(>=) + case TOKEN_LESS: + COMP(<) + case TOKEN_LESS_EQ: + COMP(<=) + case TOKEN_EQEQ: + // TODO elsewhere + COMP(==) + case TOKEN_NOT_EQUAL: + // TODO elsewhere + COMP(!=) + default: + UNREACHABLE + } +#undef COMP + expr->const_expr.type = CONST_BOOL; + expr->expr_kind = EXPR_CONST; + } + expr->type = type_bool; + return true; +} #define SEMA_ANALYSE_CMP(op) { \ if (!cast_arithmetic(left, right, #op)) return false;\ @@ -769,16 +1094,10 @@ 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_elvis(Context *context, Type *to, Expr *expr, Expr *left, Expr *right) { TODO } -static bool sema_expr_analyse_deref(Context *context, Expr *expr, Expr *inner) +static bool sema_expr_analyse_deref(Context *context, Type *to, Expr *expr, Expr *inner) { Type *canonical = inner->type->canonical; if (canonical->type_kind != TYPE_POINTER) @@ -796,7 +1115,7 @@ static bool sema_expr_analyse_deref(Context *context, Expr *expr, Expr *inner) return true; } -static bool sema_expr_analyse_addr(Context *context, Expr *expr, Expr *inner) +static bool sema_expr_analyse_addr(Context *context, Type *to, Expr *expr, Expr *inner) { if (!expr_is_ltype(inner)) { @@ -807,7 +1126,7 @@ static bool sema_expr_analyse_addr(Context *context, Expr *expr, Expr *inner) return true; } -static bool sema_expr_analyse_neg(Context *context, Expr *expr, Expr *inner) +static bool sema_expr_analyse_neg(Context *context, Type *to, Expr *expr, Expr *inner) { Type *canonical = inner->type->canonical; if (!builtin_may_negate(canonical)) @@ -835,7 +1154,7 @@ static bool sema_expr_analyse_neg(Context *context, Expr *expr, Expr *inner) } return true; } -static bool sema_expr_analyse_bit_not(Context *context, Expr *expr, Expr *inner) +static bool sema_expr_analyse_bit_not(Context *context, Type *to, Expr *expr, Expr *inner) { Type *canonical = inner->type->canonical; if (!type_is_integer(canonical) && canonical != type_bool) @@ -862,7 +1181,7 @@ static bool sema_expr_analyse_bit_not(Context *context, Expr *expr, Expr *inner) } return true; } -static bool sema_expr_analyse_not(Context *context, Expr *expr, Expr *inner) +static bool sema_expr_analyse_not(Context *context, Type *to, Expr *expr, Expr *inner) { expr->type = type_bool; if (inner->expr_kind == EXPR_CONST) @@ -928,9 +1247,7 @@ static bool sema_expr_analyse_not(Context *context, Expr *expr, Expr *inner) UNREACHABLE } - - -static inline bool sema_expr_analyse_incdec(Context *context, Expr *expr, Expr *inner) +static inline bool sema_expr_analyse_incdec(Context *context, Type *to, Expr *expr, Expr *inner) { if (!expr_is_ltype(inner)) { @@ -946,136 +1263,189 @@ static inline bool sema_expr_analyse_incdec(Context *context, Expr *expr, Expr * return true; } - -static inline bool sema_expr_analyse_binary(Context *context, Expr *expr) +static inline bool sema_expr_analyse_binary(Context *context, Type *to, Expr *expr) { assert(expr->resolve_status == RESOLVE_RUNNING); Expr *left = expr->binary_expr.left; Expr *right = expr->binary_expr.right; - - // Special handling due to initalizer lists - if (expr->binary_expr.operator == TOKEN_EQ) + switch (expr->binary_expr.operator) { - return sema_expr_analyse_assign(context, expr, left, right); + case TOKEN_EQ: + return sema_expr_analyse_assign(context, to, expr, left, right); + case TOKEN_STAR: + return sema_expr_analyse_mult(context, to, expr, left, right); + case TOKEN_MULT_ASSIGN: + return sema_expr_analyse_mult_assign(context, to, expr, left, right); + case TOKEN_PLUS: + return sema_expr_analyse_add(context, to, expr, left, right); + case TOKEN_PLUS_ASSIGN: + return sema_expr_analyse_add_assign(context, to, expr, left, right); + case TOKEN_MINUS: + return sema_expr_analyse_sub(context, to, expr, left, right); + case TOKEN_MINUS_ASSIGN: + return sema_expr_analyse_sub_assign(context, to, expr, left, right); + case TOKEN_DIV: + return sema_expr_analyse_div(context, to, expr, left, right); + case TOKEN_DIV_ASSIGN: + return sema_expr_analyse_div_assign(context, to, expr, left, right); + case TOKEN_MOD: + return sema_expr_analyse_mod(context, to, expr, left, right); + case TOKEN_MOD_ASSIGN: + return sema_expr_analyse_mod_assign(context, to, expr, left, right); + case TOKEN_AND: + return sema_expr_analyse_and(context, to, expr, left, right); + case TOKEN_AND_ASSIGN: + return sema_expr_analyse_and_assign(context, to, expr, left, right); + case TOKEN_OR: + return sema_expr_analyse_or(context, to, expr, left, right); + case TOKEN_OR_ASSIGN: + return sema_expr_analyse_or_assign(context, to, expr, left, right); + case TOKEN_BIT_AND_ASSIGN: + return sema_expr_analyse_bit_and_assign(context, to, expr, left, right); + case TOKEN_BIT_OR: + case TOKEN_BIT_XOR: + case TOKEN_AMP: + return sema_expr_analyse_bit(context, to, expr, left, right); + case TOKEN_BIT_OR_ASSIGN: + return sema_expr_analyse_bit_or_assign(context, to, expr, left, right); + case TOKEN_BIT_XOR_ASSIGN: + return sema_expr_analyse_bit_xor_assign(context, to, expr, left, right); + case TOKEN_NOT_EQUAL: + // TODO special handling + return sema_expr_analyse_comp(context, to, expr, left, right); + case TOKEN_EQEQ: + // TODO special handling + return sema_expr_analyse_comp(context, to, expr, left, right); + case TOKEN_GREATER_EQ: + case TOKEN_GREATER: + case TOKEN_LESS_EQ: + case TOKEN_LESS: + return sema_expr_analyse_comp(context, to, expr, left, right); + case TOKEN_SHR: + return sema_expr_analyse_shr(context, to, expr, left, right); + case TOKEN_SHR_ASSIGN: + return sema_expr_analyse_shr_assign(context, to, expr, left, right); + case TOKEN_SHL: + return sema_expr_analyse_shl(context, to, expr, left, right); + case TOKEN_SHL_ASSIGN: + return sema_expr_analyse_shl_assign(context, to, expr, left, right); + case TOKEN_ELVIS: + return sema_expr_analyse_elvis(context, to, expr, left, right); + default: + UNREACHABLE } - - if (!sema_analyse_expr(context, left)) return false; - if (!sema_analyse_expr(context, right)) return false; - - assert(left->type); - assert(right->type); - return BINOP_ANALYSIS[expr->binary_expr.operator](context, expr, left, right); } -static inline bool sema_expr_analyse_unary(Context *context, Expr *expr) +static inline bool sema_expr_analyse_unary(Context *context, Type *to, Expr *expr) { assert(expr->resolve_status == RESOLVE_RUNNING); Expr *inner = expr->unary_expr.expr; - if (!sema_analyse_expr(context, inner)) return false; + if (!sema_analyse_expr(context, NULL, inner)) return false; - return UNARYOP_ANALYSIS[expr->unary_expr.operator](context, expr, inner); + switch (expr->unary_expr.operator) + { + case TOKEN_STAR: + return sema_expr_analyse_deref(context, to, expr, inner); + case TOKEN_AMP: + return sema_expr_analyse_addr(context, to, expr, inner); + case TOKEN_MINUS: + return sema_expr_analyse_neg(context, to, expr, inner); + case TOKEN_BIT_NOT: + return sema_expr_analyse_bit_not(context, to, expr, inner); + case TOKEN_NOT: + return sema_expr_analyse_not(context, to, expr, inner); + case TOKEN_PLUSPLUS: + case TOKEN_MINUSMINUS: + return sema_expr_analyse_incdec(context, to, expr, inner); + default: + UNREACHABLE + } } -static inline bool sema_expr_analyse_postunary(Context *context, Expr *expr) +static inline bool sema_expr_analyse_post_unary(Context *context, Type *to, Expr *expr) { assert(expr->resolve_status == RESOLVE_RUNNING); Expr *inner = expr->post_expr.expr; - if (!sema_analyse_expr(context, inner)) return false; + if (!sema_analyse_expr(context, NULL, inner)) return false; assert(expr->post_expr.operator == TOKEN_PLUSPLUS || expr->post_expr.operator == TOKEN_MINUSMINUS); - return sema_expr_analyse_incdec(context, expr, inner); + + return sema_expr_analyse_incdec(context, to, expr, inner); } -static inline bool sema_expr_analyse_try(Context *context, Expr *expr) + +static inline bool sema_expr_analyse_try(Context *context, Type *to, Expr *expr) { - if (!sema_analyse_expr(context, expr->try_expr.expr)) return false; + if (!sema_analyse_expr(context, to, expr->try_expr.expr)) return false; expr->type = expr->try_expr.expr->type; if (expr->try_expr.else_expr) { - 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; + if (!sema_analyse_expr(context, to, expr->try_expr.else_expr)) return false; } // Check errors! TODO return true; } -static inline bool sema_expr_analyse_type(Context *context, Expr *expr) +static inline bool sema_expr_analyse_type(Context *context, Type *to, Expr *expr) { TODO return true; } -static ExprBinopAnalysis BINOP_ANALYSIS[TOKEN_EOF] = { - [TOKEN_EQ] = NULL, // Explicitly dispatched - [TOKEN_STAR] = &sema_expr_analyse_mult, - [TOKEN_MULT_ASSIGN] = &sema_expr_analyse_mult_assign, - [TOKEN_PLUS] = &sema_expr_analyse_add, - [TOKEN_PLUS_ASSIGN] = &sema_expr_analyse_add_assign, - [TOKEN_MINUS] = &sema_expr_analyse_sub, - [TOKEN_MINUS_ASSIGN] = &sema_expr_analyse_sub_assign, - [TOKEN_DIV] = &sema_expr_analyse_div, - [TOKEN_DIV_ASSIGN] = &sema_expr_analyse_div_assign, - [TOKEN_MOD] = &sema_expr_analyse_mod, - [TOKEN_MOD_ASSIGN] = &sema_expr_analyse_mod_assign, - [TOKEN_AND] = &sema_expr_analyse_and, - [TOKEN_AND_ASSIGN] = &sema_expr_analyse_and_assign, - [TOKEN_OR] = &sema_expr_analyse_or, - [TOKEN_OR_ASSIGN] = &sema_expr_analyse_or_assign, - [TOKEN_AMP] = &sema_expr_analyse_bit_and, - [TOKEN_BIT_AND_ASSIGN] = &sema_expr_analyse_bit_and_assign, - [TOKEN_BIT_OR] = &sema_expr_analyse_bit_or, - [TOKEN_BIT_OR_ASSIGN] = &sema_expr_analyse_bit_or_assign, - [TOKEN_BIT_XOR] = &sema_expr_analyse_bit_xor, - [TOKEN_BIT_XOR_ASSIGN] = &sema_expr_analyse_bit_xor_assign, - [TOKEN_NOT_EQUAL] = &sema_expr_analyse_ne, - [TOKEN_EQEQ] = &sema_expr_analyse_eq, - [TOKEN_GREATER_EQ] = &sema_expr_analyse_ge, - [TOKEN_GREATER] = &sema_expr_analyse_gt, - [TOKEN_LESS_EQ] = &sema_expr_analyse_le, - [TOKEN_LESS] = &sema_expr_analyse_lt, - [TOKEN_SHR] = &sema_expr_analyse_shr, - [TOKEN_SHR_ASSIGN] = &sema_expr_analyse_shr_assign, - [TOKEN_SHL] = &sema_expr_analyse_shl, - [TOKEN_SHL_ASSIGN] = &sema_expr_analyse_shl_assign, - [TOKEN_ELVIS] = &sema_expr_analyse_elvis, -}; -static ExprUnaryAnalysis UNARYOP_ANALYSIS[TOKEN_EOF + 1] = { - [TOKEN_STAR] = &sema_expr_analyse_deref, - [TOKEN_AMP] = &sema_expr_analyse_addr, - [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_incdec, - [TOKEN_MINUSMINUS] = &sema_expr_analyse_incdec, -}; -static ExprAnalysis EXPR_ANALYSIS[EXPR_CAST + 1] = { - [EXPR_TRY] = &sema_expr_analyse_try, - [EXPR_CONST] = NULL, - [EXPR_BINARY] = &sema_expr_analyse_binary, - [EXPR_CONDITIONAL] = &sema_expr_analyse_conditional, - [EXPR_UNARY] = &sema_expr_analyse_unary, - [EXPR_POST_UNARY] = &sema_expr_analyse_postunary, - [EXPR_TYPE] = &sema_expr_analyse_type, - [EXPR_IDENTIFIER] = &sema_expr_analyse_identifier, - [EXPR_TYPE_ACCESS] = &sema_expr_analyse_type_access, - [EXPR_CALL] = &sema_expr_analyse_call, - [EXPR_SIZEOF] = &sema_expr_analyse_sizeof, - [EXPR_SUBSCRIPT] = &sema_expr_analyse_subscript, - [EXPR_ACCESS] = &sema_expr_analyse_access, - [EXPR_STRUCT_VALUE] = &sema_expr_analyse_struct_value, - [EXPR_STRUCT_INIT_VALUES] = &sema_expr_analyse_struct_init_values, - [EXPR_INITIALIZER_LIST] = &sema_expr_analyse_initializer_list, - [EXPR_CAST] = &sema_expr_analyse_cast, -}; -bool sema_analyse_expr(Context *context, Expr *expr) +static inline bool sema_analyse_expr_dispatch(Context *context, Type *to, Expr *expr) +{ + switch (expr->expr_kind) + { + case EXPR_POISONED: + return false; + case EXPR_TRY: + return sema_expr_analyse_try(context, to, expr); + case EXPR_CONST: + return true; + case EXPR_BINARY: + return sema_expr_analyse_binary(context, to, expr); + case EXPR_CONDITIONAL: + return sema_expr_analyse_conditional(context, to, expr); + case EXPR_UNARY: + return sema_expr_analyse_unary(context, to, expr); + case EXPR_POST_UNARY: + return sema_expr_analyse_post_unary(context, to, expr); + case EXPR_TYPE: + return sema_expr_analyse_type(context, to, expr); + case EXPR_IDENTIFIER: + return sema_expr_analyse_identifier(context, to, expr); + case EXPR_TYPE_ACCESS: + return sema_expr_analyse_type_access(context, to, expr); + case EXPR_CALL: + return sema_expr_analyse_call(context, to, expr); + case EXPR_SIZEOF: + return sema_expr_analyse_sizeof(context, to, expr); + case EXPR_SUBSCRIPT: + return sema_expr_analyse_subscript(context, to, expr); + case EXPR_ACCESS: + return sema_expr_analyse_access(context, to, expr); + case EXPR_STRUCT_VALUE: + return sema_expr_analyse_struct_value(context, to, expr); + case EXPR_STRUCT_INIT_VALUES: + return sema_expr_analyse_struct_init_values(context, to, expr); + case EXPR_INITIALIZER_LIST: + return sema_expr_analyse_initializer_list(context, to, expr); + case EXPR_CAST: + return sema_expr_analyse_cast(context, to, expr); + case EXPR_EXPRESSION_LIST: + return sema_expr_analyse_expr_list(context, to, expr); + } + UNREACHABLE +} +bool sema_analyse_expr(Context *context, Type *to, Expr *expr) { switch (expr->resolve_status) { @@ -1088,7 +1458,7 @@ bool sema_analyse_expr(Context *context, Expr *expr) case RESOLVE_DONE: return expr_ok(expr); } - if (!EXPR_ANALYSIS[expr->expr_kind](context, expr)) return expr_poison(expr); + if (!sema_analyse_expr_dispatch(context, to, expr)) return expr_poison(expr); expr->resolve_status = RESOLVE_DONE; - return true; + return cast_implicit(expr, to); } \ No newline at end of file diff --git a/src/compiler/llvm_codegen_expr.c b/src/compiler/llvm_codegen_expr.c index c2e6653d2..c03dfd79b 100644 --- a/src/compiler/llvm_codegen_expr.c +++ b/src/compiler/llvm_codegen_expr.c @@ -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: diff --git a/src/compiler/llvm_codegen_function.c b/src/compiler/llvm_codegen_function.c index 9eff9b7ce..6cecc4e84 100644 --- a/src/compiler/llvm_codegen_function.c +++ b/src/compiler/llvm_codegen_function.c @@ -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); diff --git a/src/compiler/parser.c b/src/compiler/parser.c index 2549e6324..1e9092cc2 100644 --- a/src/compiler/parser.c +++ b/src/compiler/parser.c @@ -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; } diff --git a/src/compiler/semantic_analyser.c b/src/compiler/semantic_analyser.c index a8b82da20..137c24cd6 100644 --- a/src/compiler/semantic_analyser.c +++ b/src/compiler/semantic_analyser.c @@ -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); } diff --git a/src/compiler/types.c b/src/compiler/types.c index 221bc052b..42e85ec19 100644 --- a/src/compiler/types.c +++ b/src/compiler/types.c @@ -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); } } @@ -396,4 +396,241 @@ bool type_may_have_method_functions(Type *type) default: 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; + } + } } \ No newline at end of file diff --git a/src/utils/lib.h b/src/utils/lib.h index d11b48c3a..8fc6586d4 100644 --- a/src/utils/lib.h +++ b/src/utils/lib.h @@ -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)