summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--#test.toc#17
-rwxr-xr-xbuild.sh2
-rw-r--r--eval.c774
-rw-r--r--identifiers.c1
-rw-r--r--parse.c24
-rw-r--r--test.toc29
-rw-r--r--toc.c16
-rw-r--r--types.c31
8 files changed, 209 insertions, 685 deletions
diff --git a/#test.toc# b/#test.toc#
deleted file mode 100644
index 112e4e3..0000000
--- a/#test.toc#
+++ /dev/null
@@ -1,17 +0,0 @@
-main @= fn() {
- arr1 : ['a' as u8]int;
- arr2 : [main as u64]int;
-1 arr3 : [main as i64]int;
- N @= (-10 + (97 as char as f32)) as u32;
- arr4 : [N]int;
- arr5 : [main as u64]int;
- // arr6 : [main as u64 as fn() as u64]int;FIXME
- arr7 : [main as u64 as fn() int as u64]int;
-
- str @= "foo";
- arr8 : [(str[0] as u32) + (str[1] as u32) + (str[2] as u32)]int;
- asdf @= new int;
- arr9 : [asdf as u64]int;
- arr10 : [main as &i32 as u64]int;
- arr11 : [((main as &u64) as [4]u64)[3]]int;
-};
diff --git a/build.sh b/build.sh
index 0a7e7ce..d284567 100755
--- a/build.sh
+++ b/build.sh
@@ -11,7 +11,7 @@ ADDITIONAL_FLAGS='-Wno-unused-function -Wno-unneeded-internal-declaration'
WARNINGS='-Wall -Wextra -Wpedantic -Wconversion -Wshadow'
DEBUG_FLAGS="-O0 -g3 $WARNINGS -std=c11 -DTOC_DEBUG"
-RELEASE_FLAGS="-O3 -DNDEBUG $WARNINGS -std=c11"
+RELEASE_FLAGS="-O3 -s -DNDEBUG $WARNINGS -std=c11"
COMMAND="$CC $DEBUG_FLAGS $ADDITIONAL_FLAGS -o toc main.c"
echo $COMMAND
diff --git a/eval.c b/eval.c
index 66f9b67..3d4404a 100644
--- a/eval.c
+++ b/eval.c
@@ -1,22 +1,3 @@
-/*
-TODO: this situation isn't ideal: 8x as much space as should be used
-will be used for u8's (and this might have problems with pointer arithmetic,
-calling c, etc.). maybe macros will make this easier.
-*/
-typedef enum {
- VAL_VOID,
- VAL_INT,
- VAL_UINT,
- VAL_CHAR,
- VAL_FLOAT,
- VAL_PTR,
- VAL_FN,
- VAL_BOOL,
- VAL_ARR
-} ValueKind;
-
-#define VAL_FLAG_FN_NULL 0x01 /* is this function null? */
-
typedef struct {
Allocator allocr;
} Evaluator;
@@ -33,656 +14,193 @@ static inline void *evalr_malloc(Evaluator *ev, size_t bytes) {
return allocr_malloc(&ev->allocr, bytes);
}
-typedef double FloatVal;
-
-typedef struct {
- void *data;
- UInteger n;
-} ArrVal;
-
-typedef struct Value {
- ValueKind kind;
- union {
- ValueKind arr_kind;
- ValueKind ptr_kind;
- };
- union {
- Integer intv;
- UInteger uintv;
- FloatVal floatv;
- bool boolv;
- char charv;
- void *ptr;
- FnExpr *fn;
- ArrVal arr;
- };
+typedef union Value {
+ U8 u8;
+ U16 u16;
+ U32 u32;
+ U64 u64;
+ I8 i8;
+ I16 i16;
+ I32 i32;
+ I64 i64;
+ bool boolv;
+ char charv;
+ float f32;
+ double f64;
+ FnExpr *fn;
+ void *arr;
+ void *ptr;
} Value;
-size_t sizeof_val_kind(ValueKind k) {
- Value v;
- switch (k) {
- case VAL_VOID:
- return 0;
- case VAL_INT: return sizeof v.intv;
- case VAL_UINT: return sizeof v.uintv;
- case VAL_FLOAT: return sizeof v.floatv;
- case VAL_BOOL: return sizeof v.boolv;
- case VAL_CHAR: return sizeof v.charv;
- case VAL_PTR: return sizeof v.ptr;
- case VAL_FN: return sizeof v.fn;
- case VAL_ARR: return sizeof v.arr;
- }
- assert(0);
- return 0;
-}
-
-static ValueKind type_to_val_kind(Type *t) {
+static bool val_truthiness(Value *v, Type *t) {
switch (t->kind) {
- case TYPE_VOID: return VAL_VOID;
- case TYPE_FN: return VAL_FN;
- case TYPE_PTR: return VAL_PTR;
- case TYPE_ARR: return VAL_ARR;
+ case TYPE_VOID: return false;
+ case TYPE_UNKNOWN: assert(0); return false;
case TYPE_BUILTIN:
switch (t->builtin) {
- case BUILTIN_I8:
- case BUILTIN_I16:
- case BUILTIN_I32:
- case BUILTIN_I64:
- return VAL_INT;
- case BUILTIN_U8:
- case BUILTIN_U16:
- case BUILTIN_U32:
- case BUILTIN_U64:
- return VAL_UINT;
- case BUILTIN_F32:
- case BUILTIN_F64:
- return VAL_FLOAT;
- case BUILTIN_CHAR:
- return VAL_CHAR;
- case BUILTIN_BOOL:
- return VAL_BOOL;
- case BUILTIN_TYPE_COUNT: break;
+ 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_TUPLE: /* TODO */
- case TYPE_UNKNOWN:
- break;
+ 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;
}
- assert(0);
- return VAL_VOID;
}
-static bool eval_truthiness(Value *v) {
- switch (v->kind) {
- case VAL_VOID:
- assert(0);
- return false;
- case VAL_INT:
- return v->intv != 0;
- case VAL_UINT:
- return v->uintv != 0;
- case VAL_FLOAT:
- return v->floatv != 0;
- case VAL_PTR:
- return v->ptr != NULL;
- case VAL_FN:
- return v->fn != NULL;
- case VAL_BOOL:
- return v->boolv;
- case VAL_CHAR:
- return v->charv != 0;
- case VAL_ARR:
- return v->arr.n != 0;
+static I64 val_to_i64(Value *v, BuiltinType v_type) {
+ switch (v_type) {
+ case BUILTIN_I8: return (I64)v->i8;
+ case BUILTIN_I16: return (I64)v->i16;
+ case BUILTIN_I32: return (I64)v->i32;
+ case BUILTIN_I64: return (I64)v->i64;
+ case BUILTIN_U8: return (I64)v->u8;
+ case BUILTIN_U16: return (I64)v->u16;
+ case BUILTIN_U32: return (I64)v->u32;
+ case BUILTIN_U64: return (I64)v->u64;
+ default: break;
}
assert(0);
- return false;
+ return 0;
}
-static inline bool val_eq(Value a, Value b) {
- if (a.kind != b.kind) return false;
- switch (a.kind) {
- case VAL_UINT: return a.uintv == b.uintv;
- case VAL_INT: return a.intv == b.intv;
- case VAL_FLOAT: return a.floatv == b.floatv;
- case VAL_BOOL: return a.boolv == b.boolv;
- case VAL_FN: return a.fn == b.fn;
- case VAL_PTR: return a.ptr == b.ptr;
- case VAL_CHAR: return a.charv == b.charv;
- case VAL_ARR:
- case VAL_VOID: assert(0);
- }
- return false;
+static U64 val_to_u64(Value *v, BuiltinType v_type) {
+ if (v_type == BUILTIN_U64) return v->u64;
+ return (U64)val_to_i64(v, v_type);
}
-static inline bool val_lt(Value a, Value b) {
- if (a.kind != b.kind) return false;
- switch (a.kind) {
- case VAL_UINT: return a.uintv < b.uintv;
- case VAL_INT: return a.intv < b.intv;
- case VAL_FLOAT: return a.floatv < b.floatv;
- case VAL_BOOL: return a.boolv < b.boolv;
- case VAL_FN: return a.fn < b.fn;
- case VAL_PTR: return a.ptr < b.ptr;
- case VAL_CHAR: return a.charv < b.charv;
- case VAL_ARR:
- case VAL_VOID: assert(0);
+static void i64_to_val(Value *v, BuiltinType v_type, I64 x) {
+ switch (v_type) {
+ case BUILTIN_I8:
+ v->i8 = (I8)x; break;
+ case BUILTIN_I16:
+ v->i16 = (I16)x; break;
+ case BUILTIN_I32:
+ v->i32 = (I32)x; break;
+ case BUILTIN_I64:
+ v->i64 = (I64)x; break;
+ case BUILTIN_U8:
+ v->u8 = (U8)x; break;
+ case BUILTIN_U16:
+ v->u16 = (U16)x; break;
+ case BUILTIN_U32:
+ v->u32 = (U32)x; break;
+ case BUILTIN_U64:
+ v->u64 = (U64)x; break;
+ default: assert(0); break;
}
- return false;
}
-static bool val_cast(Location where, Value *out, Value cast, Type *type) {
- /* TODO: errors at type checking */
- switch (type->kind) {
- case TYPE_VOID:
- out->kind = VAL_VOID;
- return true;
- case TYPE_BUILTIN:
- switch (type->builtin) {
- case BUILTIN_U8:
- case BUILTIN_U16:
- case BUILTIN_U32:
- case BUILTIN_U64:
- out->kind = VAL_UINT;
- switch (cast.kind) {
- case VAL_UINT:
- out->uintv = cast.uintv; break;
- case VAL_INT:
- out->uintv = (UInteger)cast.intv; break;
- case VAL_FLOAT:
- out->uintv = (UInteger)cast.floatv; break;
- case VAL_BOOL:
- out->uintv = cast.boolv ? 1 : 0; break;
- case VAL_FN:
- out->uintv = (UInteger)cast.fn; break;
- case VAL_PTR:
- out->uintv = (UInteger)cast.ptr; break;
- case VAL_CHAR:
- out->uintv = (UInteger)cast.charv; break;
- case VAL_ARR:
- case VAL_VOID: assert(0);
- }
- break;
- case BUILTIN_I8:
- case BUILTIN_I16:
- case BUILTIN_I32:
- case BUILTIN_I64:
- out->kind = VAL_INT;
- switch (cast.kind) {
- case VAL_UINT:
- out->intv = (Integer)cast.uintv; break;
- case VAL_INT:
- out->intv = cast.intv; break;
- case VAL_FLOAT:
- out->intv = (Integer)cast.floatv; break;
- case VAL_BOOL:
- out->intv = cast.boolv ? 1 : 0; break;
- case VAL_FN:
- out->intv = (Integer)cast.fn; break;
- case VAL_PTR:
- out->intv = (Integer)cast.ptr; break;
- case VAL_CHAR:
- out->intv = (Integer)cast.charv; break;
- case VAL_ARR:
- case VAL_VOID: assert(0);
- }
- break;
- case BUILTIN_F32:
- case BUILTIN_F64:
- out->kind = VAL_FLOAT;
- switch (cast.kind) {
- case VAL_UINT:
- out->floatv = (FloatVal)cast.uintv; break;
- case VAL_INT:
- out->floatv = (FloatVal)cast.intv; break;
- case VAL_FLOAT:
- out->floatv = cast.floatv; break;
- case VAL_BOOL:
- out->floatv = cast.boolv ? 1.0 : 0.0; break;
- case VAL_CHAR:
- case VAL_VOID:
- case VAL_FN:
- case VAL_ARR:
- case VAL_PTR:
- assert(0);
- return false;
- }
- break;
- case BUILTIN_BOOL:
- out->kind = VAL_BOOL;
- out->boolv = eval_truthiness(&cast);
- break;
- case BUILTIN_CHAR:
- out->kind = VAL_CHAR;
- switch (cast.kind) {
- case VAL_UINT:
- out->charv = (char)cast.uintv; break;
- case VAL_INT:
- out->charv = (char)cast.intv; break;
- case VAL_BOOL:
- out->charv = cast.boolv ? 1 : 0; break;
- case VAL_CHAR:
- out->charv = cast.charv; break;
- case VAL_FLOAT:
- case VAL_FN:
- case VAL_PTR:
- case VAL_ARR:
- case VAL_VOID: assert(0);
- }
- break;
- case BUILTIN_TYPE_COUNT: assert(0); return false;
- }
- break;
- case TYPE_FN:
- out->kind = VAL_FN;
- switch (cast.kind) {
- case VAL_UINT:
- out->fn = (FnExpr *)cast.uintv; break;
- case VAL_INT:
- out->fn = (FnExpr *)cast.intv; break;
- case VAL_FN:
- out->fn = cast.fn; break;
- case VAL_PTR:
- out->fn = (FnExpr *)cast.ptr; break;
- case VAL_CHAR:
- case VAL_FLOAT:
- case VAL_BOOL:
- case VAL_ARR:
- case VAL_VOID:
- assert(0); return false;
- }
- break;
- case TYPE_PTR:
- out->kind = VAL_PTR;
- out->ptr_kind = type_to_val_kind(type->ptr.of);
- switch (cast.kind) {
- case VAL_INT:
- out->ptr = (void *)cast.intv; break;
- case VAL_UINT:
- out->ptr = (void *)cast.uintv; break;
- case VAL_FN:
- out->ptr = (void *)cast.fn; break;
- case VAL_PTR:
- out->ptr = cast.ptr; break;
- case VAL_ARR:
- out->ptr = cast.arr.data; break;
- case VAL_CHAR:
- case VAL_VOID:
- case VAL_FLOAT:
- case VAL_BOOL:
- assert(0); return false;
- }
- return true;
- case TYPE_ARR:
- out->kind = VAL_ARR;
- out->arr_kind = type_to_val_kind(type->arr.of);
- out->arr.n = type->arr.n;
- switch (cast.kind) {
- case VAL_PTR:
- out->arr.data = cast.ptr;
- break;
- case VAL_ARR:
- out->arr.data = cast.arr.data;
- break;
- case VAL_FN:
- case VAL_INT:
- case VAL_UINT:
- case VAL_CHAR:
- case VAL_VOID:
- case VAL_FLOAT:
- case VAL_BOOL:
- assert(0); return false;
- }
- return true;
- case TYPE_TUPLE:
- /* TODO: error at type checking */
- assert(0);
- return false;
- case TYPE_UNKNOWN:
- err_print(where, "Cannot cast to unknown type.");
- return false;
- }
- return true;
+static void u64_to_val(Value *v, BuiltinType v_type, U64 x) {
+ if (v_type == BUILTIN_U64)
+ v->u64 = x;
+ else
+ i64_to_val(v, v_type, (I64)x);
}
-static bool eval_block(Block *b, Value *v) {
- v->kind = VAL_UINT;
- v->uintv = (UInteger)b;
- (void)b,(void)v;
- return true;
-}
-static inline void val_promote_to_float(Value *v) {
- switch (v->kind) {
- case VAL_INT:
- v->kind = VAL_FLOAT;
- v->floatv = (FloatVal)v->intv;
- break;
- case VAL_UINT:
- v->kind = VAL_FLOAT;
- v->floatv = (FloatVal)v->uintv;
- break;
- case VAL_FLOAT: break;
- default: assert(0); break;
+
+static void eval_expr(Evaluator *ev, Expression *e, Value *v) {
+ /* WARNING: macros ahead */
+#define eval_unary_op_one(low, up, op) \
+ case BUILTIN_##up: \
+ v->low = op of.low; break
+#define eval_unary_op_nums(builtin, op) \
+ eval_unary_op_one(i8, I8, op); \
+ eval_unary_op_one(i16, I16, op); \
+ eval_unary_op_one(i32, I32, op); \
+ eval_unary_op_one(i64, I64, op); \
+ eval_unary_op_one(u8, U8, op); \
+ eval_unary_op_one(u16, U16, op); \
+ eval_unary_op_one(u32, U32, op); \
+ eval_unary_op_one(u64, U64, op); \
+ eval_unary_op_one(f32, F32, op); \
+ eval_unary_op_one(f64, F64, op);
+
+#define eval_unary_op_nums_only(op) \
+ switch (builtin) { \
+ eval_unary_op_nums(builtin, op); \
+ default: assert(0); break; \
}
-
-}
-/* NOTE: expr must be typed before it can be evaluated */
-static bool 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
+#define eval_binary_op_nums(builtin, op) \
+ eval_binary_op_one(i8, I8, op); \
+ eval_binary_op_one(i16, I16, op); \
+ eval_binary_op_one(i32, I32, op); \
+ eval_binary_op_one(i64, I64, op); \
+ eval_binary_op_one(u8, U8, op); \
+ eval_binary_op_one(u16, U16, op); \
+ eval_binary_op_one(u32, U32, op); \
+ eval_binary_op_one(u64, U64, op); \
+ eval_binary_op_one(f32, F32, op); \
+ eval_binary_op_one(f64, F64, op)
+
+#define eval_binary_op_nums_only(op) \
+ switch (builtin) { \
+ eval_binary_op_nums(builtin, op); \
+ default: assert(0); break; \
+ }
+
switch (e->kind) {
- case EXPR_LITERAL_FLOAT:
- v->kind = VAL_FLOAT;
- v->floatv = (FloatVal)e->floatl;
- return true;
- case EXPR_LITERAL_INT:
- if (e->intl > (UInteger)INTEGER_MAX) {
- v->kind = VAL_UINT;
- v->uintv = e->intl;
- } else {
- v->kind = VAL_INT;
- v->intv = (Integer)e->intl;
- }
- break;
- case EXPR_LITERAL_BOOL:
- v->kind = VAL_BOOL;
- v->boolv = e->booll;
- break;
- case EXPR_LITERAL_CHAR:
- v->kind = VAL_CHAR;
- v->charv = e->charl;
- break;
- case EXPR_LITERAL_STR:
- v->kind = VAL_ARR;
- v->arr_kind = VAL_CHAR;
- v->arr.n = e->strl.len;
- v->arr.data = e->strl.str;
- break;
case EXPR_UNARY_OP: {
- Expression *of_expr = e->unary.of;
Value of;
- if (!eval_expr(ev, of_expr, &of)) return false;
+ eval_expr(ev, e->unary.of, &of);
switch (e->unary.op) {
case UNARY_MINUS: {
- assert(e->type.kind == TYPE_BUILTIN);
- v->kind = of.kind;
- if (v->kind == VAL_INT) {
- v->intv = -of.intv;
- } else if (v->kind == VAL_FLOAT) {
- v->floatv = -of.floatv;
- } else {
- assert(0);
- return false;
- }
- break;
- }
- case UNARY_NOT:
- v->kind = VAL_BOOL;
- v->boolv = !eval_truthiness(&of);
- return true;
- case UNARY_ADDRESS: {
- v->kind = VAL_PTR;
- get_ptr:
- switch (of_expr->kind) {
- case EXPR_UNARY_OP:
- switch (of_expr->unary.op) {
- case UNARY_DEREF:
- /* &*x */
- of_expr = of_expr->unary.of;
- goto get_ptr;
- default: assert(0); return false;
- }
- break;
- case EXPR_IDENT:
- err_print(e->where, "Cannot get address of identifiers at compile time yet.");
- return false;
- case EXPR_BINARY_OP:
- switch (of_expr->binary.op) {
- case BINARY_AT_INDEX: {
- Expression *lhs_expr = of_expr->binary.lhs;
- Expression *rhs_expr = of_expr->binary.rhs;
- Value lhs, rhs;
- if (!eval_expr(ev, lhs_expr, &lhs)
- || !eval_expr(ev, rhs_expr, &rhs))
- return false;
- assert(lhs.kind == VAL_ARR && (rhs.kind == VAL_INT || rhs.kind == VAL_UINT));
- v->ptr = (char *)lhs.arr.data + (Integer)sizeof_val_kind(lhs.arr_kind)
- * (rhs.kind == VAL_INT ? rhs.intv : (Integer)rhs.uintv);
- } break;
- default: assert(0); return false;
- }
- break;
-
- default: assert(0); return false;
- }
+ BuiltinType builtin = e->type.builtin;
+ assert(e->type.kind == TYPE_BUILTIN);
+ eval_unary_op_nums_only(-);
} break;
- case UNARY_DEREF: {
- v->kind = type_to_val_kind(&e->type);
- switch (v->kind) {
- case VAL_INT:
- v->intv = *(Integer *)of.ptr; break;
- case VAL_UINT:
- v->uintv = *(UInteger *)of.ptr; break;
- case VAL_FLOAT:
- v->floatv = *(FloatVal *)of.ptr; break;
- case VAL_BOOL:
- v->boolv = *(bool *)of.ptr; break;
- case VAL_CHAR:
- v->charv = *(char *)of.ptr; break;
- case VAL_ARR:
- v->arr = *(ArrVal *)of.ptr; break;
- case VAL_PTR:
- v->ptr = *(void **)of.ptr; break;
- case VAL_FN:
- v->fn = *(FnExpr **)of.ptr; break;
- case VAL_VOID:
- assert(0); return false;
- /* case VAL_INT: */
- /* v->intv = *(Integer *)of.ptr; */
- /* break; */
-
- }
- break;
- } break;
- case UNARY_DEL: /* TODO */
- assert(0);
+ case UNARY_NOT:
+ v->boolv = !val_truthiness(v, &e->unary.of->type);
break;
}
} break;
case EXPR_BINARY_OP: {
Value lhs, rhs;
- /* NOTE: this will need to change for short-circuiting */
- if (!eval_expr(ev, e->binary.lhs, &lhs)) return false;
- if (!eval_expr(ev, e->binary.rhs, &rhs)) return false;
- if (e->type.kind != TYPE_BUILTIN) {
- err_print(e->where, "Operators can only be applied to builtin types.");
- return false;
- }
- bool is_uint = type_builtin_is_uint(e->type.builtin);
- bool is_int = type_builtin_is_int(e->type.builtin);
- bool is_float = type_builtin_is_float(e->type.builtin);
- if (is_float) {
- val_promote_to_float(&lhs);
- val_promote_to_float(&rhs);
- }
+ /* TODO(eventually): short-circuiting */
+ eval_expr(ev, e->binary.lhs, &lhs);
+ eval_expr(ev, e->binary.rhs, &rhs);
+ BuiltinType builtin = e->type.builtin;
+ assert(e->type.kind == TYPE_BUILTIN);
switch (e->binary.op) {
- case BINARY_PLUS:
- v->kind = lhs.kind;
- if (is_uint) {
- v->uintv = lhs.uintv + rhs.uintv;
- } else if (is_int) {
- v->intv = lhs.intv + rhs.intv;
- } else if (is_float) {
- v->floatv = lhs.floatv + rhs.floatv;
- } else assert(0);
- break;
- case BINARY_MINUS:
- v->kind = lhs.kind;
- if (is_uint) {
- v->uintv = lhs.uintv - rhs.uintv; /* TODO: will u64 - u64 => i64 be possible? */
- } else if (is_int) {
- v->intv = lhs.intv - rhs.intv;
- } else if (is_float) {
- v->floatv = lhs.floatv - rhs.floatv;
- } else assert(0);
- break;
+ case BINARY_ADD:
+ eval_binary_op_nums_only(+); break;
+ case BINARY_SUB:
+ eval_binary_op_nums_only(-); break;
case BINARY_MUL:
- v->kind = lhs.kind;
- if (is_uint) {
- v->uintv = lhs.uintv * rhs.uintv;
- } else if (is_int) {
- v->intv = lhs.intv * rhs.intv;
- } else if (is_float) {
- v->floatv = lhs.floatv * rhs.floatv;
- } else assert(0);
- break;
+ eval_binary_op_nums_only(*); break;
case BINARY_DIV:
- v->kind = lhs.kind;
- /* TODO(eventually): check div by 0 */
- if (is_uint) {
- v->uintv = lhs.uintv / rhs.uintv;
- } else if (is_int) {
- v->intv = lhs.intv / rhs.intv;
- } else if (is_float) {
- v->floatv = lhs.floatv / rhs.floatv;
- } else assert(0);
- break;
- case BINARY_EQ:
- v->kind = VAL_BOOL;
- v->boolv = val_eq(lhs, rhs);
- break;
- case BINARY_NE:
- v->kind = VAL_BOOL;
- v->boolv = !val_eq(lhs, rhs);
- break;
- case BINARY_GT:
- v->kind = VAL_BOOL;
- v->boolv = val_lt(rhs, lhs);
- break;
- case BINARY_GE:
- v->kind = VAL_BOOL;
- v->boolv = val_lt(rhs, lhs) || val_eq(lhs, rhs);
- break;
- case BINARY_LT:
- v->kind = VAL_BOOL;
- v->boolv = val_lt(lhs, rhs);
- break;
- case BINARY_LE:
- v->boolv = val_lt(lhs, rhs) || val_eq(lhs, rhs);
- break;
- case BINARY_SET:
- v->kind = VAL_VOID;
- break;
- case BINARY_COMMA:
- err_print(e->where, "tuples not supported at compile time yet.");
- return false;
- case BINARY_AT_INDEX: {
- assert(lhs.kind == VAL_ARR);
- assert(rhs.kind == VAL_INT || rhs.kind == VAL_UINT);
- /* TODO: optional bounds checking */
- UInteger index = rhs.kind == VAL_INT ? (UInteger)rhs.intv : rhs.uintv;
- void *arr = lhs.arr.data;
- v->kind = lhs.arr_kind;
- switch (lhs.arr_kind) {
- case VAL_INT:
- v->intv = ((Integer *)arr)[index]; break;
- case VAL_UINT:
- v->uintv = ((UInteger *)arr)[index]; break;
- case VAL_FLOAT:
- v->floatv = ((FloatVal *)arr)[index]; break;
- case VAL_CHAR:
- v->charv = ((char *)arr)[index]; break;
- case VAL_BOOL:
- v->boolv = ((bool *)arr)[index]; break;
- case VAL_PTR:
- v->ptr = ((Value **)arr)[index]; break;
- case VAL_ARR:
- v->arr = ((ArrVal *)arr)[index]; break;
- case VAL_FN:
- v->fn = ((FnExpr **)arr)[index]; break;
- case VAL_VOID:
- assert(0);
- return false;
- }
- break;
- }
- }
+ eval_binary_op_nums_only(/); break;
+ }
} break;
- case EXPR_IDENT: {
- Identifier id = e->ident;
- IdentDecl *id_decl = ident_decl(id);
- if (!id_decl) {
- char *id_str = ident_to_str(id);
- err_print(e->where, "Undeclared identifier: %s", id_str);
- free(id_str);
- return false;
- }
- Declaration *d = id_decl->decl;
- if (location_after(d->where, e->where)) {
- err_print(e->where, "Use of constant before its declaration.");
- info_print(d->where, "Declaration will be here.");
- return false;
- }
- if (!(d->flags & DECL_FLAG_CONST)) {
- err_print(e->where, "Use of non-constant identifier in a constant expression.");
- info_print(d->where, "Declaration was here.");
- return false;
- }
- if (!d->val) {
- d->val = evalr_malloc(ev, sizeof *d->val); /* OPTIM */
- if (!eval_expr(ev, &d->expr, d->val))
- return false;
- }
- *v = *d->val;
- break;
- } break;
- case EXPR_FN:
- v->kind = VAL_FN;
- v->fn = &e->fn;
+ case EXPR_LITERAL_INT:
+ assert(e->type.kind == TYPE_BUILTIN);
+ u64_to_val(v, e->type.builtin, e->intl);
break;
- case EXPR_IF: {
- IfExpr *i = &e->if_;
- if (!i->cond) {
- if (!eval_block(&i->body, v)) return false;
- break;
- }
- Value cond;
- if (!eval_expr(ev, i->cond, &cond))
- return false;
- if (eval_truthiness(&cond)) {
- if (!eval_block(&i->body, v)) return false;
- } else if (i->next_elif) {
- if (!eval_expr(ev, i->next_elif, v)) return false;
+ case EXPR_LITERAL_FLOAT:
+ assert(e->type.kind == TYPE_BUILTIN);
+ if (e->type.builtin == BUILTIN_F32) {
+ v->f32 = (F32)e->floatl;
+ } else if (e->type.builtin == BUILTIN_F64) {
+ v->f64 = (F64)e->floatl;
} else {
- v->kind = VAL_VOID;
- }
- break;
- }
- case EXPR_BLOCK:
- return eval_block(&e->block, v);
- case EXPR_CAST: {
- Value cast_val;
- if (!eval_expr(ev, e->cast.expr, &cast_val)) return false;
- if (!val_cast(e->where, v, cast_val, &e->cast.type)) return false;
- break;
- }
- case EXPR_DIRECT:
- switch (e->direct.which) {
- case DIRECT_C:
- err_print(e->where, "Can't run C code at compile time.");
- return false;
- case DIRECT_COUNT: assert(0); break;
+ assert(0);
}
- break;
- case EXPR_NEW:
- v->kind = VAL_PTR;
- v->ptr_kind = type_to_val_kind(&e->new.type);
- v->ptr = err_calloc(1, sizeof_val_kind(v->ptr_kind)); /* TODO(eventually): get this to work even if NULL ptrs aren't 0 */
- break;
- case EXPR_WHILE:
- case EXPR_CALL:
- err_print(e->where, "Not implemented yet");
- return false;
}
- return true;
}
-
diff --git a/identifiers.c b/identifiers.c
index 08a205c..60c1460 100644
--- a/identifiers.c
+++ b/identifiers.c
@@ -18,7 +18,6 @@ typedef struct IdentTree {
struct IdentTree *parent;
struct IdentTree *children[TREE_NCHILDREN];
Array decls; /* array of declarations of this identifier */
- unsigned long c_fn_reps; /* number of repetitions of this identifier in the C output--only used for functions */
} IdentTree;
typedef IdentTree *Identifier;
diff --git a/parse.c b/parse.c
index 6c28b7e..a52ac83 100644
--- a/parse.c
+++ b/parse.c
@@ -91,8 +91,8 @@ typedef enum {
typedef enum {
BINARY_SET, /* e.g. x = y */
- BINARY_PLUS,
- BINARY_MINUS,
+ BINARY_ADD,
+ BINARY_SUB,
BINARY_MUL,
BINARY_DIV,
BINARY_COMMA,
@@ -197,7 +197,7 @@ typedef struct Declaration {
Type type;
uint16_t flags;
Expression expr;
- struct Value *val; /* only for constant decls. set to NULL here, and to actual value by types.c. */
+ union Value *val; /* only for constant decls. set to NULL here, and to actual value by types.c. */
} Declaration;
typedef enum {
@@ -259,8 +259,8 @@ static const char *unary_op_to_str(UnaryOp u) {
static const char *binary_op_to_str(BinaryOp b) {
switch (b) {
- case BINARY_PLUS: return "+";
- case BINARY_MINUS: return "-";
+ case BINARY_ADD: return "+";
+ case BINARY_SUB: return "-";
case BINARY_MUL: return "*";
case BINARY_DIV: return "/";
case BINARY_SET: return "=";
@@ -277,12 +277,12 @@ static const char *binary_op_to_str(BinaryOp b) {
return "";
}
-static bool type_builtin_is_uint(BuiltinType b) {
+static bool type_builtin_is_signed(BuiltinType b) {
switch (b) {
- case BUILTIN_U8:
- case BUILTIN_U16:
- case BUILTIN_U32:
- case BUILTIN_U64:
+ case BUILTIN_I8:
+ case BUILTIN_I16:
+ case BUILTIN_I32:
+ case BUILTIN_I64:
return true;
default: return false;
}
@@ -1167,10 +1167,10 @@ static bool parse_expr(Parser *p, Expression *e, Token *end) {
BinaryOp op;
switch (lowest_precedence_op->kw) {
case KW_PLUS:
- op = BINARY_PLUS;
+ op = BINARY_ADD;
break;
case KW_MINUS:
- op = BINARY_MINUS;
+ op = BINARY_SUB;
break;
case KW_EQEQ:
op = BINARY_EQ;
diff --git a/test.toc b/test.toc
index e22bcbd..50e77d5 100644
--- a/test.toc
+++ b/test.toc
@@ -1,17 +1,18 @@
main @= fn() {
- arr1 : ['a' as u8]int;
- arr2 : [main as u64]int;
- arr3 : [main as i64]int;
- 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;
- arr7 : [main as u64 as fn() int as u64]int;
+ a : [3 + 7 - 8 / 9 * 8]int;
+ // arr1 : ['a' as u8]int;
+ // arr2 : [main as u64]int;
+ // arr3 : [main as i64]int;
+ // 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;
+ // arr7 : [main as u64 as fn() int as u64]int;
- str @= "foo";
- arr8 : [(str[0] as u32) + (str[1] as u32) + (str[2] as u32)]int;
- asdf @= new int;
- arr9 : [asdf as u64]int;
- arr10 : [main as &i32 as u64]int;
- arr11 : [((main as &u64) as [4]u64)[3]]int;
+ // str @= "foo";
+ // arr8 : [(str[0] as u32) + (str[1] as u32) + (str[2] as u32)]int;
+ // asdf @= new int;
+ // arr9 : [asdf as u64]int;
+ // arr10 : [main as &i32 as u64]int;
+ // arr11 : [((main as &u64) as [4]u64)[3]]int;
};
diff --git a/toc.c b/toc.c
index a4b6ce3..e36bbd0 100644
--- a/toc.c
+++ b/toc.c
@@ -12,7 +12,21 @@
typedef unsigned long long UInteger;
typedef long long Integer;
-typedef long double Floating; /* OPTIM: Switch to double */
+typedef long double Floating; /* OPTIM: Switch to double, but make sure floating-point literals are right */
+
+typedef uint8_t U8;
+typedef uint16_t U16;
+typedef uint32_t U32;
+typedef uint64_t U64;
+
+typedef int8_t I8;
+typedef int16_t I16;
+typedef int32_t I32;
+typedef int64_t I64;
+
+typedef float F32;
+typedef double F64;
+
#define INTEGER_MAX INT64_MAX
#define UINTEGER_FMT "%llu"
#define INTEGER_FMT "%lld"
diff --git a/types.c b/types.c
index 0a861cf..150a994 100644
--- a/types.c
+++ b/types.c
@@ -281,11 +281,18 @@ static bool type_resolve(Typer *tr, Type *t) {
free(s);
return false;
}
- if (!eval_expr(tr->evalr, n_expr, &val)) return false; /* resolve N */
- Integer size = val.intv;
- if (size < 0) {
- err_print(t->arr.n_expr->where, "Negative array length (" INTEGER_FMT ")", size);
- return false;
+ eval_expr(tr->evalr, n_expr, &val);
+
+ U64 size;
+ if (type_builtin_is_signed(n_expr->type.builtin)) {
+ I64 ssize = val_to_i64(&val, n_expr->type.builtin);
+ if (ssize < 0) {
+ err_print(t->arr.n_expr->where, "Negative array length (" INTEGER_FMT ")", ssize);
+ return false;
+ }
+ size = (U64)ssize;
+ } else {
+ size = val_to_u64(&val, n_expr->type.builtin);
}
t->arr.n = (UInteger)size;
} break;
@@ -773,6 +780,11 @@ static bool types_expr(Typer *tr, Expression *e) {
free(s);
return false;
}
+ if (!type_builtin_is_signed(of_type->builtin)) {
+ char *s = type_to_str(of_type);
+ warn_print(e->where, "Applying unary - to unsigned type %s may cause overflow.", s);
+ free(s);
+ }
*t = *of_type;
break;
case UNARY_ADDRESS:
@@ -833,8 +845,8 @@ static bool types_expr(Typer *tr, Expression *e) {
return false;
}
/* fallthrough */
- case BINARY_PLUS:
- case BINARY_MINUS:
+ case BINARY_ADD:
+ case BINARY_SUB:
case BINARY_MUL:
case BINARY_DIV:
case BINARY_LT:
@@ -1000,10 +1012,7 @@ static bool types_decl(Typer *tr, Declaration *d) {
if (d->flags & DECL_FLAG_CONST) {
if (!d->val) {
d->val = typer_malloc(tr, sizeof *d->val); /* OPTIM */
- if (!eval_expr(tr->evalr, &d->expr, d->val)) {
- success = false;
- goto ret;
- }
+ eval_expr(tr->evalr, &d->expr, d->val);
}
}
}