summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorLeo Tenenbaum <pommicket@gmail.com>2019-09-30 13:18:15 -0400
committerLeo Tenenbaum <pommicket@gmail.com>2019-09-30 13:18:15 -0400
commit6cebb40221d0fce80fedb4c644ca9278054a4f49 (patch)
treecd685aae30d82d7a5e077e456064831764959d7c
parentc8e6972ee18a95db544980513f619567a3bc171e (diff)
warnings and errors when casting
-rw-r--r--eval.c1
-rw-r--r--main.c1
-rw-r--r--test.toc2
-rw-r--r--types.c89
4 files changed, 89 insertions, 4 deletions
diff --git a/eval.c b/eval.c
index 9dd2f62..2a8edf1 100644
--- a/eval.c
+++ b/eval.c
@@ -234,7 +234,6 @@ static bool val_cast(Location where, Value *out, Value cast, Type *type) {
case VAL_BOOL:
out->floatv = cast.boolv ? 1.0 : 0.0; break;
case VAL_CHAR:
- out->floatv = (FloatVal)cast.charv; break;
case VAL_VOID:
case VAL_FN:
case VAL_ARR:
diff --git a/main.c b/main.c
index 6faeb9d..4e69993 100644
--- a/main.c
+++ b/main.c
@@ -1,6 +1,5 @@
/*
TODO:
-allocator
casting errors
call fns at compile time
finish evaluator
diff --git a/test.toc b/test.toc
index 689e554..7d77550 100644
--- a/test.toc
+++ b/test.toc
@@ -2,7 +2,7 @@ main @= fn() {
arr1 : ['a' as u8]int;
arr2 : [main as u64]int;
arr3 : [main as i64]int;
- N @= (-10 + (97 as char as f32)) as u32;
+ N @= (-10 + (97 as char as u8 as f32)) as u32;
arr4 : [N]int;
arr5 : [main as u64]int;
// arr6 : [main as u64 as fn() as u64]int;FIXME
diff --git a/types.c b/types.c
index d6f62b5..0a861cf 100644
--- a/types.c
+++ b/types.c
@@ -336,6 +336,79 @@ static bool type_can_be_truthy(Type *t) {
return false;
}
+typedef enum {
+ STATUS_NONE,
+ STATUS_WARN,
+ STATUS_ERR
+} Status;
+
+static Status type_cast_status(Type *from, Type *to) {
+ if (to->kind == TYPE_UNKNOWN)
+ return STATUS_NONE;
+ switch (from->kind) {
+ case TYPE_UNKNOWN: return STATUS_NONE;
+ case TYPE_VOID: return STATUS_ERR;
+ case TYPE_BUILTIN:
+ switch (from->builtin) {
+ case BUILTIN_I8:
+ case BUILTIN_U8:
+ case BUILTIN_I16:
+ case BUILTIN_U16:
+ case BUILTIN_I32:
+ case BUILTIN_U32:
+ case BUILTIN_I64:
+ case BUILTIN_U64:
+ switch (to->kind) {
+ case TYPE_UNKNOWN: return STATUS_NONE;
+ case TYPE_VOID: return STATUS_ERR;
+ case TYPE_BUILTIN: return STATUS_NONE;
+ case TYPE_ARR: return STATUS_ERR;
+ case TYPE_PTR: return STATUS_WARN;
+ case TYPE_FN: return STATUS_WARN;
+ case TYPE_TUPLE: return STATUS_ERR;
+ }
+ case BUILTIN_F32:
+ case BUILTIN_F64:
+ if (to->kind == TYPE_BUILTIN && to->builtin != BUILTIN_CHAR)
+ return STATUS_NONE;
+ return STATUS_ERR;
+ case BUILTIN_CHAR:
+ if (to->kind == TYPE_BUILTIN && type_builtin_is_int(to->builtin))
+ return STATUS_NONE;
+ return STATUS_ERR;
+ case BUILTIN_BOOL:
+ return type_can_be_truthy(to);
+ case BUILTIN_TYPE_COUNT: assert(0); break;
+ }
+ break;
+ case TYPE_TUPLE: return STATUS_ERR;
+ case TYPE_FN:
+ if (to->kind == TYPE_BUILTIN && type_builtin_is_int(to->builtin))
+ return STATUS_WARN;
+ if (to->kind == TYPE_PTR || to->kind == TYPE_FN)
+ return STATUS_WARN;
+ return STATUS_ERR;
+ case TYPE_PTR:
+ if (to->kind == TYPE_BUILTIN && type_builtin_is_int(to->builtin))
+ return STATUS_WARN;
+ if (to->kind == TYPE_PTR)
+ return STATUS_NONE;
+ if (to->kind == TYPE_ARR && type_eq(to->arr.of, from->ptr.of))
+ return STATUS_NONE;
+ if (to->kind == TYPE_FN)
+ return STATUS_WARN;
+ return STATUS_ERR;
+ case TYPE_ARR:
+ if (to->kind == TYPE_PTR && type_eq(to->ptr.of, from->arr.of))
+ return STATUS_NONE;
+ if (to->kind == TYPE_ARR && !type_eq(to, from))
+ return STATUS_WARN;
+ return STATUS_ERR;
+ }
+ assert(0);
+ return STATUS_ERR;
+}
+
static bool types_expr(Typer *tr, Expression *e) {
if (e->flags & EXPR_FLAG_FOUND_TYPE) return true;
Type *t = &e->type;
@@ -448,10 +521,24 @@ static bool types_expr(Typer *tr, Expression *e) {
if (!type_of_ident(tr, e->where, e->ident, t)) return false;
} break;
case EXPR_CAST: {
- /* TODO: forbid/warn certain casts */
CastExpr *c = &e->cast;
if (!types_expr(tr, c->expr))
return false;
+ if (!type_resolve(tr, &c->type))
+ return false;
+ Status status = type_cast_status(&c->expr->type, &c->type);
+ if (status != STATUS_NONE) {
+ char *from = type_to_str(&c->expr->type);
+ char *to = type_to_str(&c->type);
+ if (status == STATUS_ERR)
+ err_print(e->where, "Cannot cast from type %s to %s.", from, to);
+ else
+ warn_print(e->where, "Casting from type %s to %s.", from, to);
+ free(from);
+ free(to);
+ if (status == STATUS_ERR)
+ return false;
+ }
*t = c->type;
} break;
case EXPR_NEW: