diff options
-rw-r--r-- | #test.toc# | 17 | ||||
-rwxr-xr-x | build.sh | 2 | ||||
-rw-r--r-- | eval.c | 774 | ||||
-rw-r--r-- | identifiers.c | 1 | ||||
-rw-r--r-- | parse.c | 24 | ||||
-rw-r--r-- | test.toc | 29 | ||||
-rw-r--r-- | toc.c | 16 | ||||
-rw-r--r-- | types.c | 31 |
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; -}; @@ -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 @@ -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; @@ -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; @@ -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; }; @@ -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" @@ -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); } } } |