diff options
author | Leo Tenenbaum <pommicket@gmail.com> | 2019-11-06 09:51:41 -0500 |
---|---|---|
committer | Leo Tenenbaum <pommicket@gmail.com> | 2019-11-06 09:51:41 -0500 |
commit | 5325c62fbde0e6dfed9d9ba69c7acb6fba730ae1 (patch) | |
tree | 96b7e27d6f449b7d539ed3edd2d3e16e51c73610 | |
parent | d0af7aafd22c319ad2517dda92d0899d74262832 (diff) |
compile time range each
-rw-r--r-- | eval.c | 216 | ||||
-rw-r--r-- | main.c | 1 | ||||
-rw-r--r-- | test.toc | 91 |
3 files changed, 207 insertions, 101 deletions
@@ -233,21 +233,6 @@ static void u64_to_val(Value *v, BuiltinType v_type, U64 x) { i64_to_val(v, v_type, (I64)x); } - -static bool val_is_nonnegative(Value *v, Type *t) { - assert(t->kind == TYPE_BUILTIN); - switch (t->builtin) { - case BUILTIN_BOOL: assert(0); return false; - case BUILTIN_CHAR: return v->charv >= 0; - case BUILTIN_F32: return v->f32 >= 0; - case BUILTIN_F64: return v->f64 >= 0; - default: break; - } - if (!type_builtin_is_signed(t->builtin)) - return true; - return val_to_i64(v, t->builtin) >= 0; -} - static void fprint_val_ptr(FILE *f, void *p, Type *t) { switch (t->kind) { case TYPE_VOID: @@ -909,23 +894,8 @@ static bool eval_set(Evaluator *ev, Expression *set, Value *to) { return true; } -static bool eval_expr(Evaluator *ev, Expression *e, Value *v) { - if (!ev->enabled) return false; /* silently fail */ - /* WARNING: macros ahead */ -#define eval_unary_op_one(low, up, op) \ - case BUILTIN_##up: \ - v->low = (up)(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); +static void eval_numerical_bin_op(Value lhs, Type *lhs_type, BinaryOp op, Value rhs, Type *rhs_type, Value *out, Type *out_type) { + /* WARNING: macros ahead */ #define eval_unary_op_nums_only(op) \ switch (builtin) { \ @@ -935,7 +905,7 @@ static bool eval_expr(Evaluator *ev, Expression *e, Value *v) { #define eval_binary_op_one(low, up, op) \ case BUILTIN_##up: \ - v->low = (up)(lhs.low op rhs.low); break + out->low = (up)(lhs.low op rhs.low); break #define eval_binary_op_nums(builtin, op) \ eval_binary_op_one(i8, I8, op); \ @@ -951,9 +921,9 @@ static bool eval_expr(Evaluator *ev, Expression *e, Value *v) { #define eval_binary_op_nums_only(op) \ - val_cast(&lhs, &e->binary.lhs->type, &lhs, &e->type); \ - val_cast(&rhs, &e->binary.rhs->type, &rhs, &e->type); \ - assert(e->type.kind == TYPE_BUILTIN); \ + val_cast(&lhs, lhs_type, &lhs, out_type); \ + val_cast(&rhs, rhs_type, &rhs, out_type); \ + assert(out_type->kind == TYPE_BUILTIN); \ switch (builtin) { \ eval_binary_op_nums(builtin, op); \ default: assert(0); break; \ @@ -962,7 +932,7 @@ static bool eval_expr(Evaluator *ev, Expression *e, Value *v) { #define eval_binary_bool_op_one(low, up, op) \ case BUILTIN_##up: \ - v->boolv = lhs.low op rhs.low; break + out->boolv = lhs.low op rhs.low; break #define eval_binary_bool_op_nums(builtin, op) \ eval_binary_bool_op_one(i8, I8, op); \ @@ -978,25 +948,82 @@ static bool eval_expr(Evaluator *ev, Expression *e, Value *v) { eval_binary_bool_op_one(boolv, BOOL, op); \ eval_binary_bool_op_one(charv, CHAR, op); -#define eval_binary_bool_op_nums_only(op) \ - {Type *ltype=&e->binary.lhs->type, \ - *rtype=&e->binary.rhs->type; \ - Type *cast_to = ltype->flags & TYPE_FLAG_FLEXIBLE ? \ - rtype : ltype; \ - val_cast(&lhs, ltype, &lhs, cast_to); \ - val_cast(&rhs, rtype, &rhs, cast_to); \ - assert(e->binary.lhs->type.kind == TYPE_BUILTIN); \ - switch (builtin) { \ - eval_binary_bool_op_nums(builtin, op); \ - default: \ - assert(!("Invalid builtin to "#op)[0]); break; \ - }} +#define eval_binary_bool_op_nums_only(op) \ + {Type *cast_to = lhs_type->flags & TYPE_FLAG_FLEXIBLE ? \ + rhs_type : lhs_type; \ + val_cast(&lhs, lhs_type, &lhs, cast_to); \ + val_cast(&rhs, rhs_type, &rhs, cast_to); \ + assert(lhs_type->kind == TYPE_BUILTIN); \ + switch (builtin) { \ + eval_binary_bool_op_nums(builtin, op); \ + default: \ + assert(!("Invalid builtin to "#op)[0]); break; \ + }} #define eval_binary_bool_op(op) \ - if (e->binary.lhs->type.kind == TYPE_PTR) \ - v->boolv = lhs.ptr op rhs.ptr; \ + if (lhs_type->kind == TYPE_PTR) \ + out->boolv = lhs.ptr op rhs.ptr; \ else { eval_binary_bool_op_nums_only(op); } + assert(out_type->kind == TYPE_BUILTIN); + BuiltinType builtin = out_type->builtin; + switch (op) { + case BINARY_ADD: + eval_binary_op_nums_only(+); break; + case BINARY_SUB: + eval_binary_op_nums_only(-); break; + case BINARY_MUL: + eval_binary_op_nums_only(*); break; + case BINARY_DIV: + eval_binary_op_nums_only(/); break; + case BINARY_LT: + eval_binary_bool_op(<); break; + case BINARY_LE: + eval_binary_bool_op(<=); break; + case BINARY_GT: + eval_binary_bool_op(>); break; + case BINARY_GE: + eval_binary_bool_op(>=); break; + case BINARY_EQ: + eval_binary_bool_op(==); break; + case BINARY_NE: + eval_binary_bool_op(!=); break; + default: assert(0); break; + } +} + + +static bool val_is_nonnegative(Value *v, Type *t) { + switch (t->builtin) { + case BUILTIN_BOOL: assert(0); return false; + case BUILTIN_CHAR: return v->charv >= 0; + case BUILTIN_F32: return v->f32 >= 0; + case BUILTIN_F64: return v->f64 >= 0; + default: break; + } + if (!type_builtin_is_signed(t->builtin)) + return true; + return val_to_i64(v, t->builtin) >= 0; +} + +static bool eval_expr(Evaluator *ev, Expression *e, Value *v) { + +#define eval_unary_op_one(low, up, op) \ + case BUILTIN_##up: \ + v->low = (up)(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); + + if (!ev->enabled) return false; /* silently fail */ switch (e->kind) { case EXPR_UNARY_OP: { Value of; @@ -1063,7 +1090,6 @@ static bool eval_expr(Evaluator *ev, Expression *e, Value *v) { if (!eval_expr(ev, lhs_expr, &lhs)) return false; if (e->binary.op != BINARY_DOT) if (!eval_expr(ev, rhs_expr, &rhs)) return false; - BuiltinType builtin = e->binary.lhs->type.builtin; switch (e->binary.op) { case BINARY_DOT: { void *ptr = eval_ptr_to_struct_field(ev, e); @@ -1075,7 +1101,7 @@ static bool eval_expr(Evaluator *ev, Expression *e, Value *v) { v->ptr = (char *)lhs.ptr + val_to_i64(&rhs, e->binary.rhs->type.builtin) * (I64)compiler_sizeof(e->binary.lhs->type.ptr); } else { - eval_binary_op_nums_only(+); + eval_numerical_bin_op(lhs, &e->binary.lhs->type, BINARY_ADD, rhs, &e->binary.rhs->type, v, &e->type); } break; case BINARY_SUB: @@ -1083,25 +1109,19 @@ static bool eval_expr(Evaluator *ev, Expression *e, Value *v) { v->ptr = (char *)lhs.ptr - val_to_i64(&rhs, e->binary.rhs->type.builtin) * (I64)compiler_sizeof(e->binary.lhs->type.ptr); } else { - eval_binary_op_nums_only(-); + eval_numerical_bin_op(lhs, &e->binary.lhs->type, BINARY_SUB, rhs, &e->binary.rhs->type, v, &e->type); } break; case BINARY_MUL: - eval_binary_op_nums_only(*); break; case BINARY_DIV: - eval_binary_op_nums_only(/); break; case BINARY_LT: - eval_binary_bool_op(<); break; case BINARY_LE: - eval_binary_bool_op(<=); break; case BINARY_GT: - eval_binary_bool_op(>); break; case BINARY_GE: - eval_binary_bool_op(>=); break; case BINARY_EQ: - eval_binary_bool_op(==); break; case BINARY_NE: - eval_binary_bool_op(!=); break; + eval_numerical_bin_op(lhs, &e->binary.lhs->type, e->binary.op, rhs, &e->binary.rhs->type, v, &e->type); + break; case BINARY_SET: if (!eval_set(ev, e->binary.lhs, &rhs)) return false; break; @@ -1156,11 +1176,65 @@ static bool eval_expr(Evaluator *ev, Expression *e, Value *v) { } break; case EXPR_EACH: { EachExpr *ea = &e->each; - /* TODO: ASDF */ + if (!each_enter(e, 0)) return false; if (ea->flags & EACH_IS_RANGE) { - + Value from, to; + Value stepval; + stepval.i64 = 1; + Type i64t; + i64t.flags = TYPE_FLAG_RESOLVED; + i64t.kind = TYPE_BUILTIN; + i64t.builtin = BUILTIN_I64; + if (!eval_expr(ev, ea->range.from, &from)) return false; + if (ea->range.to && !eval_expr(ev, ea->range.to, &to)) return false; + if (ea->range.stepval) + stepval = *ea->range.stepval; + Value x = from; + Value *index_val; + Value *value_val; + if (ea->index) { + IdentDecl *idecl = ident_decl(ea->index); + idecl->flags |= IDECL_HAS_VAL; + index_val = &idecl->val; + } else { + index_val = NULL; + } + if (ea->value) { + IdentDecl *idecl = ident_decl(ea->value); + idecl->flags |= IDECL_HAS_VAL; + value_val = &idecl->val; + } else { + value_val = NULL; + } + bool step_is_negative = ea->range.stepval && !val_is_nonnegative(&stepval, &ea->type); + index_val->i64 = 0; + while (1) { + if (ea->range.to) { + /* check if loop has ended */ + Value lhs = x; + Value rhs = to; + assert(ea->type.kind == TYPE_BUILTIN); + Type boolt; + boolt.flags = TYPE_FLAG_RESOLVED; + boolt.kind = TYPE_BUILTIN; + boolt.builtin = BUILTIN_BOOL; + eval_numerical_bin_op(lhs, &ea->type, step_is_negative ? BINARY_GE : BINARY_LE, rhs, &ea->range.to->type, v, &boolt); + + if (!v->boolv) break; + } + if (value_val) *value_val = x; + + if (!eval_block(ev, &ea->body, &e->type, v)) return false; + + if (index_val) { + index_val->i64++; + } + eval_numerical_bin_op(x, &ea->type, BINARY_ADD, stepval, ea->range.stepval ? &ea->type : &i64t, &x, &ea->type); + } } else { + assert(!*"Not implemented yet"); } + each_exit(e); } break; case EXPR_BLOCK: if (!eval_block(ev, &e->block, &e->type, v)) return false; @@ -1185,12 +1259,16 @@ static bool eval_expr(Evaluator *ev, Expression *e, Value *v) { break; case EXPR_IDENT: { IdentDecl *idecl = ident_decl(e->ident); - Declaration *d = idecl->decl; - if (!types_decl(ev->typer, d)) return false; - assert(d->type.flags & TYPE_FLAG_RESOLVED); + bool is_decl = idecl->kind == IDECL_DECL; + Declaration *d; + if (is_decl) { + d = idecl->decl; + if (!types_decl(ev->typer, d)) return false; + assert(d->type.flags & TYPE_FLAG_RESOLVED); + } if (idecl->flags & IDECL_HAS_VAL) { *v = idecl->val; - } else if (d->flags & DECL_FLAG_CONST) { + } else if (is_decl && (d->flags & DECL_FLAG_CONST)) { if (!(d->flags & DECL_FLAG_FOUND_VAL)) { if (!eval_expr(ev, &d->expr, &d->val)) return false; d->flags |= DECL_FLAG_FOUND_VAL; @@ -1,6 +1,5 @@ /* TODO: -each compile-time each allow just each arr { ... } each pointer @@ -9,37 +9,66 @@ putf @= fn(x: float) { "); }; +// f @= fn() { + +// each i := 1..4 { +// puti(i); +// } +// each i := 4,-1..1 { +// puti(i); +// } +// each i := 1.0..4.0 { +// putf(i); +// } +// each i := 7.0,-1..4.0 { +// putf(i); +// } +// // each i := 0.0,-3.0.. { putf(i); } +// foo := new(int, 3); +// each _, i := foo { +// foo[i] = i; +// }; +// each x := foo { +// puti(x); +// } +// each _ := foo { +// #C("puts(\"Hello!\")"); +// } +// bar : [3]int; +// each _, i := bar { +// bar[i] = i*i*i; +// }; +// each x := bar { +// puti(x); +// } + +// }; + +g @= fn() int { + // foo := new(int, 10); + // each _, i := foo { + // foo[i] = i; + // }; + // total := 0; + // each x := foo { + // total = total + x; + // } + // total + + // total := 0; + // each i := 1..10 { + // total = total + i; + // total + // } + total := 0; + each i, j := 1..10 { + total = total + i * j; + } + total +}; main @= fn() { - each i := 1..4 { - puti(i); - } - each i := 4,-1..1 { - puti(i); - } - each i := 1.0..4.0 { - putf(i); - } - each i := 7.0,-1..4.0 { - putf(i); - } - // each i := 0.0,-3.0.. { putf(i); } - foo := new(int, 10); - each _, i := foo { - foo[i] = i; - }; - each x := foo { - puti(x); - } - each _ := foo { - #C("puts(\"Hello!\")"); - } - bar : [10]int; - each _, i := foo { - bar[i] = i*i*i; - }; - each x := bar { - puti(x); - } - + puti(g()); + X @= g(); + puti(X); }; |