summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorLeo Tenenbaum <pommicket@gmail.com>2019-10-02 20:32:03 -0400
committerLeo Tenenbaum <pommicket@gmail.com>2019-10-02 20:32:03 -0400
commitf2ca07e37241e492c271f79633505c78b49f44a2 (patch)
treee2a8f4d710def32ae957937e4f9ad39345c22fb7
parentc5e01140d570f2712a6ad77028477ed789ffb0b6 (diff)
eval casting
-rwxr-xr-xbuild.sh7
-rw-r--r--eval.c153
-rw-r--r--identifiers.c2
-rw-r--r--location.c2
-rw-r--r--test.toc2
-rw-r--r--toc.c10
-rw-r--r--tokenizer.c2
-rw-r--r--types.c1
8 files changed, 151 insertions, 28 deletions
diff --git a/build.sh b/build.sh
index d284567..b6cd04f 100755
--- a/build.sh
+++ b/build.sh
@@ -9,7 +9,12 @@ CC=clang
ADDITIONAL_FLAGS='-Wno-unused-function -Wno-unneeded-internal-declaration'
-WARNINGS='-Wall -Wextra -Wpedantic -Wconversion -Wshadow'
+if [[ $CC == "clang" ]]; then
+ WARNINGS='-Wall -Wextra -Wpedantic -Wshadow -Wimplicit-fallthrough'
+else
+ WARNINGS='-Wall -Wextra -Wpedantic -Wshadow'
+fi
+
DEBUG_FLAGS="-O0 -g3 $WARNINGS -std=c11 -DTOC_DEBUG"
RELEASE_FLAGS="-O3 -s -DNDEBUG $WARNINGS -std=c11"
diff --git a/eval.c b/eval.c
index 0348fa2..56c183c 100644
--- a/eval.c
+++ b/eval.c
@@ -32,32 +32,36 @@ typedef union Value {
void *ptr;
} Value;
+static bool builtin_truthiness(Value *v, BuiltinType b) {
+ switch (b) {
+ case BUILTIN_I8: return v->i8 != 0;
+ case BUILTIN_I16: return v->i16 != 0;
+ case BUILTIN_I32: return v->i32 != 0;
+ case BUILTIN_I64: return v->i64 != 0;
+ case BUILTIN_U8: return v->u8 != 0;
+ case BUILTIN_U16: return v->u16 != 0;
+ case BUILTIN_U32: return v->u32 != 0;
+ case BUILTIN_U64: return v->u64 != 0;
+ case BUILTIN_F32: return v->f32 != 0;
+ case BUILTIN_F64: return v->f64 != 0;
+ case BUILTIN_BOOL: return v->boolv;
+ case BUILTIN_CHAR: return v->charv != 0;
+ case BUILTIN_TYPE_COUNT: assert(0); return false;
+ }
+}
+
static bool val_truthiness(Value *v, Type *t) {
switch (t->kind) {
case TYPE_VOID: return false;
case TYPE_UNKNOWN: assert(0); return false;
- case TYPE_BUILTIN:
- switch (t->builtin) {
- case BUILTIN_I8: return v->i8 != 0;
- case BUILTIN_I16: return v->i16 != 0;
- case BUILTIN_I32: return v->i32 != 0;
- case BUILTIN_I64: return v->i64 != 0;
- case BUILTIN_U8: return v->u8 != 0;
- case BUILTIN_U16: return v->u16 != 0;
- case BUILTIN_U32: return v->u32 != 0;
- case BUILTIN_U64: return v->u64 != 0;
- case BUILTIN_F32: return v->f32 != 0;
- case BUILTIN_F64: return v->f64 != 0;
- case BUILTIN_BOOL: return v->boolv;
- case BUILTIN_CHAR: return v->charv != 0;
- case BUILTIN_TYPE_COUNT: assert(0); return false;
- }
- break;
+ case TYPE_BUILTIN: return builtin_truthiness(v, t->builtin);
case TYPE_PTR: return v->ptr != NULL;
case TYPE_FN: return v->fn != NULL;
case TYPE_ARR: return t->arr.n > 0;
- case TYPE_TUPLE: assert(0); return false;
+ case TYPE_TUPLE: break;
}
+ assert(0);
+ return false;
}
static I64 val_to_i64(Value *v, BuiltinType v_type) {
@@ -110,7 +114,99 @@ static void u64_to_val(Value *v, BuiltinType v_type, U64 x) {
i64_to_val(v, v_type, (I64)x);
}
+#define builtin_casts_to_int(x) \
+ case BUILTIN_I8: \
+ vout->i8 = (I8)vin->x; break; \
+ case BUILTIN_I16: \
+ vout->i16 = (I16)vin->x; break; \
+ case BUILTIN_I32: \
+ vout->i32 = (I32)vin->x; break; \
+ case BUILTIN_I64: \
+ vout->i64 = (I64)vin->x; break; \
+ case BUILTIN_U8: \
+ vout->u8 = (U8)vin->x; break; \
+ case BUILTIN_U16: \
+ vout->u16 = (U16)vin->x; break; \
+ case BUILTIN_U32: \
+ vout->u32 = (U32)vin->x; break; \
+ case BUILTIN_U64: \
+ vout->u64 = (U64)vin->x; break
+
+#define builtin_casts_to_num(x) \
+ builtin_casts_to_int(x); \
+ case BUILTIN_F32: \
+ vout->f32 = (F32)vin->x; break; \
+ case BUILTIN_F64: \
+ vout->f64 = (F64)vin->x; break
+#define builtin_int_casts(low, up) \
+ case BUILTIN_##up: \
+ switch (to) { \
+ builtin_casts_to_num(low); \
+ case BUILTIN_CHAR: vout->charv = (char)vin->low; break; \
+ case BUILTIN_BOOL: vout->boolv = vin->low != 0; break; \
+ case BUILTIN_TYPE_COUNT: assert(0); break; \
+ } break
+
+#define builtin_float_casts(low, up) \
+ case BUILTIN_##up: \
+ switch (to) { \
+ builtin_casts_to_num(low); \
+ case BUILTIN_BOOL: vout->boolv = vin->low != 0.0f; break; \
+ case BUILTIN_CHAR: \
+ case BUILTIN_TYPE_COUNT: assert(0); break; \
+ } break
+
+static void val_builtin_cast(Value *vin, BuiltinType from, Value *vout, BuiltinType to) {
+ if (from == to) {
+ *vout = *vin;
+ return;
+ }
+ switch (from) {
+ builtin_int_casts(i8, I8);
+ builtin_int_casts(i16, I16);
+ builtin_int_casts(i32, I32);
+ builtin_int_casts(i64, I64);
+ builtin_int_casts(u8, U8);
+ builtin_int_casts(u16, U16);
+ builtin_int_casts(u32, U32);
+ builtin_int_casts(u64, U64);
+ builtin_float_casts(f32, F32);
+ builtin_float_casts(f64, F64);
+
+ case BUILTIN_BOOL: vout->boolv = builtin_truthiness(vin, from);
+ case BUILTIN_CHAR:
+ switch (to) {
+ builtin_casts_to_int(charv);
+ case BUILTIN_CHAR: /* handled at top of func */
+ case BUILTIN_F32:
+ case BUILTIN_F64:
+ case BUILTIN_BOOL:
+ case BUILTIN_TYPE_COUNT:
+ assert(0); break;
+ }
+ break;
+ case BUILTIN_TYPE_COUNT: assert(0); break;
+ }
+}
+
+static void val_cast(Value *vin, Type *from, Value *vout, Type *to) {
+ switch (from->kind) {
+ case TYPE_VOID: assert(0); break;
+ case TYPE_UNKNOWN: assert(0); break;
+ case TYPE_TUPLE: assert(0); break;
+
+ case TYPE_BUILTIN:
+ switch (to->kind) {
+ case TYPE_VOID: assert(0); break;
+ case TYPE_UNKNOWN: assert(0); break;
+ case TYPE_TUPLE: assert(0); break;
+ case TYPE_BUILTIN:
+ val_builtin_cast(vin, from->builtin, vout, to->builtin);
+ break;
+ }
+ }
+}
static void eval_expr(Evaluator *ev, Expression *e, Value *v) {
/* WARNING: macros ahead */
@@ -137,7 +233,8 @@ static void eval_expr(Evaluator *ev, Expression *e, Value *v) {
#define eval_binary_op_one(low, up, op) \
case BUILTIN_##up: \
- v->low = lhs.low op rhs.low; break
+ v->low = lhs.low op rhs.low; break
+
#define eval_binary_op_nums(builtin, op) \
eval_binary_op_one(i8, I8, op); \
eval_binary_op_one(i16, I16, op); \
@@ -201,6 +298,9 @@ static void eval_expr(Evaluator *ev, Expression *e, Value *v) {
/* TODO(eventually): short-circuiting */
eval_expr(ev, e->binary.lhs, &lhs);
eval_expr(ev, e->binary.rhs, &rhs);
+ /* OPTIM: this is not ideal, but 5+3.7 will be 5:int+3.7:f32 right now */
+ val_cast(&lhs, &e->binary.lhs->type, &lhs, &e->type);
+ val_cast(&rhs, &e->binary.rhs->type, &rhs, &e->type);
BuiltinType builtin = e->type.builtin;
assert(e->type.kind == TYPE_BUILTIN);
switch (e->binary.op) {
@@ -239,5 +339,20 @@ static void eval_expr(Evaluator *ev, Expression *e, Value *v) {
} else {
assert(0);
}
+ break;
+ case EXPR_LITERAL_BOOL:
+ v->boolv = e->booll;
+ break;
+ case EXPR_LITERAL_CHAR:
+ v->charv = e->charl;
+ break;
+ case EXPR_LITERAL_STR:
+ v->arr = e->strl.str;
+ break;
+ case EXPR_CAST: {
+ Value casted;
+ eval_expr(ev, e->cast.expr, &casted);
+ val_cast(&casted, &e->cast.expr->type, v, &e->cast.type);
+ } break;
}
}
diff --git a/identifiers.c b/identifiers.c
index 60c1460..1ff225c 100644
--- a/identifiers.c
+++ b/identifiers.c
@@ -63,7 +63,7 @@ static Identifier ident_new(Identifiers *ids, Identifier parent, unsigned char i
#endif
tree->parent = parent;
if (parent)
- tree->depth = parent->depth + 1;
+ tree->depth = (uint16_t)(parent->depth + 1);
tree->index_in_parent = index_in_parent;
return tree;
}
diff --git a/location.c b/location.c
index 4b450ce..8e68ca3 100644
--- a/location.c
+++ b/location.c
@@ -5,6 +5,6 @@ typedef struct {
const char *filename;
} Location;
-bool location_after(Location a, Location b) { /* a is after b? */
+static bool location_after(Location a, Location b) { /* a is after b? */
return a.code > b.code;
}
diff --git a/test.toc b/test.toc
index 50e77d5..ae758b0 100644
--- a/test.toc
+++ b/test.toc
@@ -1,5 +1,5 @@
main @= fn() {
- a : [3 + 7 - 8 / 9 * 8]int;
+ a : [('a' as u8 as f32) / 2 + 0.5 as i8]int;
// arr1 : ['a' as u8]int;
// arr2 : [main as u64]int;
// arr3 : [main as i64]int;
diff --git a/toc.c b/toc.c
index 8bc8c06..dc8204d 100644
--- a/toc.c
+++ b/toc.c
@@ -10,10 +10,15 @@
#include <inttypes.h>
#include <stdbool.h>
-typedef uint64_t UInteger;
typedef int64_t Integer;
+typedef uint64_t UInteger;
typedef long double Floating; /* OPTIM: Switch to double, but make sure floating-point literals are right */
+#define INTEGER_MAX INT64_MAX
+#define UINTEGER_MAX UINT64_MAX
+#define INTEGER_FMT "%"PRId64
+#define UINTEGER_FMT "%"PRIu64
+
typedef uint8_t U8;
typedef uint16_t U16;
typedef uint32_t U32;
@@ -27,9 +32,6 @@ typedef int64_t I64;
typedef float F32;
typedef double F64;
-#define INTEGER_MAX INT64_MAX
-#define UINTEGER_FMT "%"PRIu64
-#define INTEGER_FMT "%"PRId64
#include "location.c"
#include "err.c"
diff --git a/tokenizer.c b/tokenizer.c
index 8807b33..520edd0 100644
--- a/tokenizer.c
+++ b/tokenizer.c
@@ -484,7 +484,7 @@ static bool tokenize_string(Tokenizer *t, char *str) {
}
switch (n.kind) {
case NUM_LITERAL_INT:
- if (n.intval > ULLONG_MAX / (UInteger)base ||
+ if (n.intval > UINTEGER_MAX / (UInteger)base ||
n.intval * (UInteger)base > ULLONG_MAX - (UInteger)digit) {
/* too big! */
tokenization_err(t, "Number too big to fit in a numeric literal.");
diff --git a/types.c b/types.c
index 150a994..8851693 100644
--- a/types.c
+++ b/types.c
@@ -374,6 +374,7 @@ static Status type_cast_status(Type *from, Type *to) {
case TYPE_FN: return STATUS_WARN;
case TYPE_TUPLE: return STATUS_ERR;
}
+ break;
case BUILTIN_F32:
case BUILTIN_F64:
if (to->kind == TYPE_BUILTIN && to->builtin != BUILTIN_CHAR)