Major type check rewrite. Fixed params to be writable. Conditionals work. Lots of assign operators fixed. Struct access works.

This commit is contained in:
Christoffer Lerno
2019-11-29 23:23:30 +01:00
parent acf7efded4
commit fc3bd57ecf
12 changed files with 1256 additions and 459 deletions

View File

@@ -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;
}

View File

@@ -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:

View File

@@ -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);
}

View File

@@ -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; }

View File

@@ -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

View File

@@ -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:

View File

@@ -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);

View File

@@ -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;
}

View File

@@ -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);
}

View File

@@ -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;
}
}
}

View File

@@ -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)