diff options
author | Leo Tenenbaum <pommicket@gmail.com> | 2019-09-28 17:59:16 -0400 |
---|---|---|
committer | Leo Tenenbaum <pommicket@gmail.com> | 2019-09-28 17:59:16 -0400 |
commit | ff9e00fc50ab9baef65157b91ed72b20618c0802 (patch) | |
tree | e277f47d7b2698eb806bd83ea0140484e8f70885 | |
parent | a4ee519c30cf2790347872eb8f78292f40e300a4 (diff) |
improved eval
-rw-r--r-- | eval.c | 346 | ||||
-rw-r--r-- | parse.c | 17 | ||||
-rw-r--r-- | test.toc | 11 | ||||
-rw-r--r-- | types.c | 21 |
4 files changed, 310 insertions, 85 deletions
@@ -1,6 +1,8 @@ typedef enum { VAL_VOID, VAL_INT, + VAL_UINT, + VAL_CHAR, VAL_FLOAT, VAL_PTR, VAL_FN, @@ -15,10 +17,12 @@ typedef struct Value { ValueKind kind; union { Integer intv; + UInteger uintv; FloatVal floatv; + bool boolv; + char charv; struct Value *points_to; FnExpr *fn; - bool boolv; }; } Value; @@ -29,6 +33,8 @@ static bool eval_truthiness(Value *v) { 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: @@ -37,11 +43,198 @@ static bool eval_truthiness(Value *v) { return v->fn != NULL; case VAL_BOOL: return v->boolv; + case VAL_CHAR: + return v->charv != 0; } assert(0); return false; } +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.points_to == b.points_to; + case VAL_CHAR: return a.charv == b.charv; + case VAL_VOID: assert(0); + } + return false; +} + +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.points_to < b.points_to; + case VAL_CHAR: return a.charv < b.charv; + case VAL_VOID: assert(0); + } + return false; +} + +static bool val_cast(Location where, Value *out, Value cast, Type *type) { + 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.points_to; break; + case VAL_CHAR: + out->uintv = (UInteger)cast.charv; break; + 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.points_to; break; + case VAL_CHAR: + out->intv = (Integer)cast.charv; break; + 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_FN: + case VAL_PTR: + /* TODO: errors at type checking */ + assert(0); + return false; + case VAL_CHAR: + out->floatv = (FloatVal)cast.charv; break; + case VAL_VOID: assert(0); + } + 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_FLOAT: + out->charv = (char)cast.floatv; break; + case VAL_BOOL: + out->charv = cast.boolv ? 1 : 0; break; + case VAL_FN: + out->charv = (char)cast.fn; break; + case VAL_PTR: + out->charv = (char)cast.points_to; break; + case VAL_CHAR: + out->charv = cast.charv; break; + 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.points_to; break; + case VAL_CHAR: + case VAL_FLOAT: + case VAL_BOOL: + assert(0); return false; + case VAL_VOID: assert(0); + } + break; + case TYPE_TUPLE: + case TYPE_ARR: + /* TODO: errors at type checking */ + assert(0); + return false; + case TYPE_UNKNOWN: + err_print(where, "Cannot cast to unknown type."); + return false; + } + return true; +} + +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; + } + +} + /* NOTE: expr must be typed before it can be evaluated */ static bool eval_expr(Expression *e, Value *v) { switch (e->kind) { @@ -50,12 +243,13 @@ static bool eval_expr(Expression *e, Value *v) { v->floatv = (FloatVal)e->floatl; return true; case EXPR_LITERAL_INT: - v->kind = VAL_INT; - if (e->intl > (UInteger)INTEGER_MAX) { /* TODO: FIXME */ - err_print(e->where, "Overflow when evaluating integer."); - return false; + if (e->intl > (UInteger)INTEGER_MAX) { + v->kind = VAL_UINT; + v->uintv = e->intl; + } else { + v->kind = VAL_INT; + v->intv = (Integer)e->intl; } - v->intv = (Integer)e->intl; return true; case EXPR_LITERAL_BOOL: v->kind = VAL_BOOL; @@ -67,7 +261,7 @@ static bool eval_expr(Expression *e, Value *v) { case UNARY_MINUS: { Value of; if (!eval_expr(of_expr, &of)) return false; - assert(e->type.kind != TYPE_BUILTIN); + assert(e->type.kind == TYPE_BUILTIN); v->kind = of.kind; if (v->kind == VAL_INT) { v->intv = -of.intv; @@ -107,98 +301,81 @@ static bool eval_expr(Expression *e, Value *v) { err_print(e->where, "Operators can only be applied to builtin types."); return false; } - bool is_int = type_builtin_is_integer(e->type.builtin); - bool is_float = type_builtin_is_floating(e->type.builtin); - bool is_bool = e->type.builtin == BUILTIN_BOOL; + 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); + } switch (e->binary.op) { case BINARY_PLUS: v->kind = lhs.kind; - if (is_int) { + 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); - return true; + break; case BINARY_MINUS: v->kind = lhs.kind; - if (is_int) { + 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); - return true; + break; case BINARY_MUL: v->kind = lhs.kind; - if (is_int) { + 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); - return true; + break; case BINARY_DIV: v->kind = lhs.kind; /* TODO(eventually): check div by 0 */ - if (is_int) { + 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); - return true; + break; case BINARY_EQ: v->kind = VAL_BOOL; - if (is_int) { - v->boolv = lhs.intv == rhs.intv; - } else if (is_float) { - v->boolv = lhs.floatv == rhs.floatv; - } else if (is_bool) { - v->boolv = lhs.boolv == rhs.boolv; - } else assert(0); - return true; + v->boolv = val_eq(lhs, rhs); + break; case BINARY_NE: v->kind = VAL_BOOL; - if (is_int) { - v->boolv = lhs.intv != rhs.intv; - } else if (is_float) { - v->boolv = lhs.floatv != rhs.floatv; - } else if (is_bool) { - v->boolv = lhs.boolv != rhs.boolv; - } else assert(0); - return true; + v->boolv = !val_eq(lhs, rhs); + break; case BINARY_GT: v->kind = VAL_BOOL; - if (is_int) { - v->boolv = lhs.intv > rhs.intv; - } else if (is_float) { - v->boolv = lhs.floatv > rhs.floatv; - } else assert(0); - return true; + v->boolv = val_lt(rhs, lhs); + break; case BINARY_GE: v->kind = VAL_BOOL; - if (is_int) { - v->boolv = lhs.intv >= rhs.intv; - } else if (is_float) { - v->boolv = lhs.floatv >= rhs.floatv; - } else assert(0); - return true; + v->boolv = val_lt(rhs, lhs) || val_eq(lhs, rhs); + break; case BINARY_LT: v->kind = VAL_BOOL; - if (is_int) { - v->boolv = lhs.intv < rhs.intv; - } else if (is_float) { - v->boolv = lhs.floatv < rhs.floatv; - } else assert(0); - return true; + v->boolv = val_lt(lhs, rhs); + break; case BINARY_LE: - v->kind = VAL_BOOL; - if (is_int) { - v->boolv = lhs.intv <= rhs.intv; - } else if (is_float) { - v->boolv = lhs.floatv <= rhs.floatv; - } else assert(0); - return true; + v->boolv = val_lt(lhs, rhs) || val_eq(lhs, rhs); + break; case BINARY_SET: v->kind = VAL_VOID; - return true; + break; case BINARY_COMMA: err_print(e->where, "tuples not supported at compile time yet."); return false; @@ -233,22 +410,42 @@ static bool eval_expr(Expression *e, Value *v) { return false; } *v = *d->val; - return true; + break; } break; case EXPR_FN: v->kind = VAL_FN; v->fn = &e->fn; - return true; - case EXPR_CAST: - case EXPR_IF: - case EXPR_WHILE: - case EXPR_CALL: + 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(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(i->next_elif, v)) return false; + } else { + v->kind = VAL_VOID; + } + break; + } case EXPR_BLOCK: - case EXPR_LITERAL_STR: + return eval_block(&e->block, v); case EXPR_LITERAL_CHAR: - case EXPR_NEW:{ - err_print(e->where, "operation not supported at compile time yet."); /* TODO */ - } break; + v->kind = VAL_CHAR; + v->charv = e->charl; + break; + case EXPR_CAST: { + Value cast_val; + if (!eval_expr(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: @@ -257,7 +454,12 @@ static bool eval_expr(Expression *e, Value *v) { case DIRECT_COUNT: assert(0); break; } break; + case EXPR_NEW: + case EXPR_WHILE: + case EXPR_CALL: + case EXPR_LITERAL_STR: + err_print(e->where, "Not implemented yet"); + return false; } - err_print(e->where, "Not implemented yet"); - return false; + return true; } @@ -277,7 +277,18 @@ static const char *binary_op_to_str(BinaryOp b) { return ""; } -static bool type_builtin_is_integer(BuiltinType b) { +static bool type_builtin_is_uint(BuiltinType b) { + switch (b) { + case BUILTIN_U8: + case BUILTIN_U16: + case BUILTIN_U32: + case BUILTIN_U64: + return true; + default: return false; + } +} + +static bool type_builtin_is_int(BuiltinType b) { switch (b) { case BUILTIN_I8: case BUILTIN_I16: @@ -292,7 +303,7 @@ static bool type_builtin_is_integer(BuiltinType b) { } } -static bool type_builtin_is_floating(BuiltinType b) { +static bool type_builtin_is_float(BuiltinType b) { switch (b) { case BUILTIN_F32: case BUILTIN_F64: @@ -302,7 +313,7 @@ static bool type_builtin_is_floating(BuiltinType b) { } static bool type_builtin_is_numerical(BuiltinType b) { - return type_builtin_is_integer(b) || type_builtin_is_floating(b); + return type_builtin_is_int(b) || type_builtin_is_float(b); } @@ -1,7 +1,14 @@ main @= fn() { - foo @= 5.3 + 6; + arr1 : ['a' as u8]int; + arr2 : [main as u64]int; + 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; + // x @= fn(i: f32) i64 { // 0 // }; - bar := foo+-foo; }; @@ -73,8 +73,8 @@ static bool type_eq(Type *a, Type *b) { if (b->flags & TYPE_FLAG_FLEXIBLE) return true; assert(a->kind == TYPE_BUILTIN); - if (type_builtin_is_floating(a->builtin)) { - return type_builtin_is_floating(b->builtin); + if (type_builtin_is_float(a->builtin)) { + return type_builtin_is_float(b->builtin); } assert(a->builtin == BUILTIN_I64); return type_builtin_is_numerical(b->builtin); @@ -255,7 +255,11 @@ static bool type_resolve(Typer *tr, Type *t) { Value val; Expression *n_expr = t->arr.n_expr; if (!types_expr(tr, n_expr)) return false; - if (n_expr->type.kind != TYPE_BUILTIN || !type_builtin_is_integer(n_expr->type.builtin)) { + if (n_expr->type.kind == TYPE_UNKNOWN) { + t->arr.n = 0; + break; + } + if (n_expr->type.kind != TYPE_BUILTIN || !type_builtin_is_int(n_expr->type.builtin)) { char *s = type_to_str(&n_expr->type); err_print(n_expr->where, "Cannot use type %s as the size of an array (it's not an integer type).", s); free(s); @@ -263,8 +267,10 @@ static bool type_resolve(Typer *tr, Type *t) { } if (!eval_expr(n_expr, &val)) return false; /* resolve N */ Integer size = val.intv; - if (size < 0) + if (size < 0) { err_print(t->arr.n_expr->where, "Negative array length (" INTEGER_FMT ")", size); + return false; + } t->arr.n = (UInteger)size; } break; case TYPE_FN: @@ -762,13 +768,12 @@ static bool types_expr(Typer *tr, Expression *e) { int rhs_is_flexible = rhs_type->flags & TYPE_FLAG_FLEXIBLE; if (lhs_is_flexible && rhs_is_flexible) { /* both flexible */ + *t = *lhs_type; if (rhs_type->builtin == BUILTIN_F32) { /* promote to float */ - lhs_type->builtin = BUILTIN_F32; + t->builtin = BUILTIN_F32; } - if (lhs_type->builtin == BUILTIN_F32) - rhs_type->builtin = BUILTIN_F32; - *t = *lhs_type; + } else if (!lhs_is_flexible) { /* lhs inflexible, rhs ? */ *t = *lhs_type; |