commit aebcb0e52f522914627ad81d823c684c8a62aa6e
parent c41b2f8bbfe4bad1adc311cdfe566b3c94aadf11
Author: Drew DeVault <sir@cmpwn.com>
Date: Wed, 30 Dec 2020 15:47:07 -0500
check: implement casts
Diffstat:
4 files changed, 80 insertions(+), 2 deletions(-)
diff --git a/include/expr.h b/include/expr.h
@@ -101,7 +101,6 @@ enum cast_kind {
struct expression_cast {
enum cast_kind kind;
struct expression *value;
- const struct type *type;
};
struct call_argument {
diff --git a/include/type_store.h b/include/type_store.h
@@ -19,6 +19,7 @@ struct type_store {
bool type_is_assignable(struct type_store *store,
const struct type *to, const struct type *from);
+bool type_is_castable(const struct type *to, const struct type *from);
const struct type *type_store_lookup_atype(
struct type_store *store, const struct ast_type *atype);
diff --git a/src/check.c b/src/check.c
@@ -299,6 +299,20 @@ check_expr_call(struct context *ctx,
}
static void
+check_expr_cast(struct context *ctx,
+ const struct ast_expression *aexpr,
+ struct expression *expr)
+{
+ trace(TR_CHECK, "cast");
+ expr->type = EXPR_CAST;
+ expr->cast.kind = aexpr->cast.kind;
+ expr->cast.value = xcalloc(1, sizeof(struct expression));
+ check_expression(ctx, aexpr->cast.value, expr->cast.value);
+ expr->result = type_store_lookup_atype(&ctx->store, aexpr->cast.type);
+ expect(type_is_castable(expr->result, expr->cast.value->result), "Invalid cast");
+}
+
+static void
check_expr_array(struct context *ctx,
const struct ast_expression *aexpr,
struct expression *expr)
@@ -640,7 +654,8 @@ check_expression(struct context *ctx,
check_expr_call(ctx, aexpr, expr);
break;
case EXPR_CAST:
- assert(0); // TODO
+ check_expr_cast(ctx, aexpr, expr);
+ break;
case EXPR_CONSTANT:
check_expr_constant(ctx, aexpr, expr);
break;
diff --git a/src/type_store.c b/src/type_store.c
@@ -111,6 +111,69 @@ type_is_assignable(struct type_store *store,
assert(0); // Unreachable
}
+bool
+type_is_castable(const struct type *to,
+ const struct type *from)
+{
+ switch (from->storage) {
+ case TYPE_STORAGE_CHAR:
+ return to->storage == TYPE_STORAGE_U8;
+ case TYPE_STORAGE_ENUM:
+ return to->storage == TYPE_STORAGE_ENUM || type_is_integer(to);
+ case TYPE_STORAGE_F32:
+ case TYPE_STORAGE_F64:
+ return type_is_numeric(to);
+ case TYPE_STORAGE_U8:
+ if (to->storage == TYPE_STORAGE_CHAR) {
+ return true;
+ }
+ // Fallthrough
+ case TYPE_STORAGE_U32:
+ if (to->storage == TYPE_STORAGE_RUNE
+ && from->storage == TYPE_STORAGE_U32) {
+ return true;
+ }
+ // Fallthrough
+ case TYPE_STORAGE_I16:
+ case TYPE_STORAGE_I32:
+ case TYPE_STORAGE_I64:
+ case TYPE_STORAGE_I8:
+ case TYPE_STORAGE_INT:
+ case TYPE_STORAGE_SIZE:
+ case TYPE_STORAGE_U16:
+ case TYPE_STORAGE_U64:
+ case TYPE_STORAGE_UINT:
+ return to->storage == TYPE_STORAGE_ENUM || type_is_numeric(to);
+ case TYPE_STORAGE_UINTPTR:
+ return to->storage == TYPE_STORAGE_POINTER
+ || to->storage == TYPE_STORAGE_NULL
+ || type_is_numeric(to);
+ case TYPE_STORAGE_POINTER:
+ case TYPE_STORAGE_NULL:
+ return to->storage == TYPE_STORAGE_POINTER
+ || to->storage == TYPE_STORAGE_NULL
+ || to->storage == TYPE_STORAGE_UINTPTR;
+ case TYPE_STORAGE_STRING:
+ return to == &builtin_type_const_ptr_char;
+ case TYPE_STORAGE_SLICE:
+ case TYPE_STORAGE_ARRAY:
+ case TYPE_STORAGE_ALIAS:
+ case TYPE_STORAGE_TAGGED_UNION:
+ assert(0); // TODO
+ case TYPE_STORAGE_RUNE:
+ return to->storage == TYPE_STORAGE_U32;
+ // Cannot be cast:
+ case TYPE_STORAGE_BOOL:
+ case TYPE_STORAGE_VOID:
+ case TYPE_STORAGE_FUNCTION:
+ case TYPE_STORAGE_STRUCT:
+ case TYPE_STORAGE_UNION:
+ return false;
+ }
+
+ assert(0); // Unreachable
+}
+
const struct type *
builtin_type_for_storage(enum type_storage storage, bool is_const)
{