summaryrefslogtreecommitdiff
path: root/eval.c
diff options
context:
space:
mode:
Diffstat (limited to 'eval.c')
-rw-r--r--eval.c346
1 files changed, 274 insertions, 72 deletions
diff --git a/eval.c b/eval.c
index 7fbb37c..aca2a5c 100644
--- a/eval.c
+++ b/eval.c
@@ -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;
}