summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorLeo Tenenbaum <pommicket@gmail.com>2019-09-28 17:59:16 -0400
committerLeo Tenenbaum <pommicket@gmail.com>2019-09-28 17:59:16 -0400
commitff9e00fc50ab9baef65157b91ed72b20618c0802 (patch)
treee277f47d7b2698eb806bd83ea0140484e8f70885
parenta4ee519c30cf2790347872eb8f78292f40e300a4 (diff)
improved eval
-rw-r--r--eval.c346
-rw-r--r--parse.c17
-rw-r--r--test.toc11
-rw-r--r--types.c21
4 files changed, 310 insertions, 85 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;
}
diff --git a/parse.c b/parse.c
index 2d5e3d9..9f7b401 100644
--- a/parse.c
+++ b/parse.c
@@ -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);
}
diff --git a/test.toc b/test.toc
index 1812bb4..d1c2fa8 100644
--- a/test.toc
+++ b/test.toc
@@ -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;
};
diff --git a/types.c b/types.c
index dcfa7aa..c8d2159 100644
--- a/types.c
+++ b/types.c
@@ -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;