diff options
-rwxr-xr-x | build.sh | 7 | ||||
-rw-r--r-- | eval.c | 153 | ||||
-rw-r--r-- | identifiers.c | 2 | ||||
-rw-r--r-- | location.c | 2 | ||||
-rw-r--r-- | test.toc | 2 | ||||
-rw-r--r-- | toc.c | 10 | ||||
-rw-r--r-- | tokenizer.c | 2 | ||||
-rw-r--r-- | types.c | 1 |
8 files changed, 151 insertions, 28 deletions
@@ -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" @@ -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; } @@ -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; } @@ -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; @@ -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."); @@ -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) |