harec

Unnamed repository; edit this file 'description' to name the repository.
Log | Files | Refs | README | LICENSE

commit aebcb0e52f522914627ad81d823c684c8a62aa6e
parent c41b2f8bbfe4bad1adc311cdfe566b3c94aadf11
Author: Drew DeVault <sir@cmpwn.com>
Date:   Wed, 30 Dec 2020 15:47:07 -0500

check: implement casts

Diffstat:
Minclude/expr.h | 1-
Minclude/type_store.h | 1+
Msrc/check.c | 17++++++++++++++++-
Msrc/type_store.c | 63+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
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) {