From dc6a7e198d2001086dd2245dd223bab3eda5670b Mon Sep 17 00:00:00 2001 From: Leo Tenenbaum Date: Sat, 23 May 2020 17:17:13 -0400 Subject: turned if, while, for, block into statements --- cgen.c | 468 +++++++++++----------- copy.c | 85 ++-- eval.c | 338 ++++++++-------- main.c | 4 +- parse.c | 451 ++++++++++----------- test.toc | 6 +- types.c | 1327 +++++++++++++++++++++++++++++++------------------------------- types.h | 93 ++--- 8 files changed, 1365 insertions(+), 1407 deletions(-) diff --git a/cgen.c b/cgen.c index dce344e..04f93c1 100644 --- a/cgen.c +++ b/cgen.c @@ -767,35 +767,10 @@ static void cgen_set_tuple(CGenerator *g, Expression *exprs, Identifier *idents, } arr_clear(underscore_ids); cgen_writeln(g, "); "); - } break; - case EXPR_IF: - case EXPR_BLOCK: { - IdentID prefix_id = to->cgen.id = ++g->ident_counter; - if (exprs) { - for (size_t i = 0; i < arr_len(to->type.tuple); ++i) { - cgen_expr_pre(g, &exprs[i]); - } - } - for (unsigned long i = 0; i < (unsigned long)arr_len(to->type.tuple); ++i) { - cgen_write(g, "("); - if (exprs) { - cgen_expr(g, &exprs[i]); - } else if (idents) { - cgen_ident(g, idents[i]); - } else { - cgen_write(g, "%s%lu", prefix, i); - } - cgen_write(g, ") = "); - cgen_ident_id(g, prefix_id); - cgen_write(g, "%lu", i); - cgen_write(g, "; "); - } } break; /* things which can never be tuples */ case EXPR_SLICE: case EXPR_IDENT: - case EXPR_WHILE: - case EXPR_FOR: case EXPR_LITERAL_INT: case EXPR_LITERAL_CHAR: case EXPR_LITERAL_BOOL: @@ -828,24 +803,6 @@ static void cgen_truthiness(CGenerator *g, Expression *e) { static void cgen_expr_pre(CGenerator *g, Expression *e) { switch (e->kind) { - case EXPR_IF: { - IfExpr *curr = e->if_; - while (1) { - if (curr->cond) { - cgen_write(g, "if ("); - cgen_truthiness(g, curr->cond); - cgen_write(g, ") "); - } - cgen_block(g, &curr->body, 0); - if (curr->next_elif) { - cgen_write(g, " else "); - curr = curr->next_elif->if_; - } else break; - } - } break; - case EXPR_BLOCK: - cgen_block(g, e->block, 0); - break; case EXPR_CALL: { cgen_expr_pre(g, e->call.fn); size_t i = 0; @@ -1026,8 +983,6 @@ static void cgen_expr_pre(CGenerator *g, Expression *e) { case EXPR_C: case EXPR_TYPE: case EXPR_NMS: - case EXPR_FOR: - case EXPR_WHILE: break; } } @@ -1246,211 +1201,6 @@ static void cgen_expr(CGenerator *g, Expression *e) { cgen_expr(g, e->unary.of); cgen_write(g, ")"); } break; - case EXPR_WHILE: { - WhileExpr *w = e->while_; - cgen_write(g, "while ("); - cgen_expr(g, w->cond); - cgen_write(g, ") "); - cgen_block(g, &w->body, 0); - } break; - case EXPR_FOR: { - ForExpr *fo = e->for_; - int is_range = fo->flags & FOR_IS_RANGE; - Declaration *header_decl = &fo->header; - Identifier val_ident = header_decl->idents[0]; - Identifier index_ident = header_decl->idents[1]; - Type *fo_type = &header_decl->type; - assert(fo_type->kind == TYPE_TUPLE && arr_len(fo_type->tuple) == 2); - Type *val_type = &fo_type->tuple[0]; - Type *index_type = &fo_type->tuple[1]; - bool has_val = !ident_eq_str(val_ident, "_"); - bool has_index = !ident_eq_str(index_ident, "_"); - - Type *of_type = NULL; - bool uses_ptr = false; - - if (is_range) { - cgen_expr_pre(g, fo->range.from); - if (fo->range.to) - cgen_expr_pre(g, fo->range.to); - } else { - cgen_expr_pre(g, fo->of); - } - cgen_write(g, "{"); - if (is_range) { - if (fo->range.to) { - /* pre generate to */ - cgen_type_pre(g, val_type); - cgen_write(g, " to_"); - cgen_type_post(g, val_type); - cgen_write(g, " = "); - cgen_expr(g, fo->range.to); - cgen_write(g, "; "); - } - - /* set value to from */ - if (has_val) { - cgen_type_pre(g, val_type); - cgen_write(g, " "); - cgen_ident(g, val_ident); - cgen_type_post(g, val_type); - cgen_write(g, "; "); - Expression val_expr = {0}; - val_expr.flags = EXPR_FOUND_TYPE; - val_expr.kind = EXPR_IDENT; - val_expr.ident = val_ident; - val_expr.type = *val_type; - cgen_set(g, &val_expr, NULL, fo->range.from, NULL); - } else { - cgen_type_pre(g, val_type); - cgen_write(g, " val_"); - cgen_type_post(g, val_type); - cgen_write(g, "; "); - cgen_set(g, NULL, "val_", fo->range.from, NULL); - } - } else { - of_type = &fo->of->type; - if (of_type->kind == TYPE_PTR) { - uses_ptr = true; - of_type = of_type->ptr; - } - - /* pre-generate of */ - switch (of_type->kind) { - case TYPE_SLICE: - cgen_type_pre(g, of_type); - cgen_write(g, " of_"); - cgen_type_post(g, of_type); - cgen_write(g, " = "); - if (uses_ptr) cgen_write(g, "*"); - cgen_expr(g, fo->of); - cgen_write(g, "; "); - break; - case TYPE_ARR: - cgen_type_pre(g, of_type->arr.of); - cgen_write(g, " (* of_)"); - cgen_type_post(g, of_type->arr.of); - cgen_write(g, " = "); - if (uses_ptr) cgen_write(g, "*"); - cgen_expr(g, fo->of); - cgen_write(g, "; "); - break; - default: assert(0); break; - } - } - - if (has_index) { - cgen_type_pre(g, index_type); - cgen_write(g, " "); - cgen_ident(g, index_ident); - cgen_type_post(g, index_type); /* not needed yet, but keeping it here to prevent potential future problems */ - cgen_write(g, " = 0; "); - } - - cgen_write(g, "for ("); - - if (!is_range) { - cgen_type_pre(g, val_type); - cgen_write(g, "(%sp_)", uses_ptr ? "" : "*"); - cgen_type_post(g, val_type); - cgen_write(g, " = "); - switch (of_type->kind) { - case TYPE_ARR: - cgen_write(g, "of_"); - break; - case TYPE_SLICE: - cgen_write(g, "of_.data"); - break; - default: assert(0); break; - } - cgen_write(g, ", (*end_) = p_ + "); - switch (of_type->kind) { - case TYPE_ARR: - cgen_write(g, U64_FMT, (U64)of_type->arr.n); - break; - case TYPE_SLICE: - cgen_write(g, "of_.len"); - break; - default: assert(0); break; - } - } - - cgen_write(g, "; "); - if (!(is_range && !fo->range.to)) { /* if it's finite */ - if (is_range) { - if (has_val) - cgen_ident(g, val_ident); - else - cgen_write(g, "val_"); - bool positive_step - = fo->range.stepval == NULL || val_is_nonnegative(*fo->range.stepval, val_type); - cgen_write(g, " %c= to_", positive_step ? '<' : '>'); - } else { - cgen_write(g, "p_ != end_"); - } - } - cgen_write(g, "; "); - if (is_range) { - if (fo->range.stepval) { - cgen_val_pre(g, fo->range.stepval, val_type); - } - if (has_val) - cgen_ident(g, val_ident); - else - cgen_write(g, "val_"); - cgen_write(g, " += "); - if (fo->range.stepval) { - cgen_val(g, fo->range.stepval, val_type); - } else { - cgen_write(g, "1"); - } - if (has_index) cgen_write(g, ", "); - } else { - cgen_write(g, "++p_"); - if (has_index) cgen_write(g, ", "); - } - if (has_index) { - cgen_write(g, "++"); - cgen_ident(g, index_ident); - } - cgen_write(g, ") {"); - cgen_nl(g); - if (has_val) { - if (!is_range) { - cgen_type_pre(g, val_type); - cgen_write(g, " "); - cgen_ident(g, val_ident); - cgen_type_post(g, val_type); - cgen_write(g, "; "); - if (uses_ptr) { - cgen_ident(g, val_ident); - cgen_write(g, " = p_;"); - cgen_nl(g); - } else { - Expression set_expr = {0}; - set_expr.kind = EXPR_IDENT; - set_expr.ident = val_ident; - set_expr.type = *val_type; - set_expr.flags = EXPR_FOUND_TYPE; - - cgen_set(g, &set_expr, NULL, NULL, "(*p_)"); - cgen_nl(g); - } - } - } - cgen_block(g, &fo->body, CGEN_BLOCK_NOBRACES); - cgen_deferred_from_block(g, &fo->body); - cgen_write(g, "}}"); - if (fo->body.c.break_lbl) { - cgen_lbl(g, fo->body.c.break_lbl); - cgen_writeln(g, ":;"); - } - } break; - case EXPR_BLOCK: - case EXPR_IF: - if (!type_is_void(&e->type)) - cgen_ident_id(g, e->cgen.id); - break; case EXPR_CALL: if (e->type.kind == TYPE_TUPLE) { /* the only situation in which this could happen is if the return value doesn't matter */ @@ -1911,6 +1661,224 @@ static void cgen_stmt(CGenerator *g, Statement *s) { arr_foreach(s->inline_block, Statement, sub) cgen_stmt(g, sub); break; + case STMT_IF: { + If *curr = s->if_; + while (1) { + if (curr->cond) { + cgen_write(g, "if ("); + cgen_truthiness(g, curr->cond); + cgen_write(g, ") "); + } + cgen_block(g, &curr->body, 0); + if (curr->next_elif) { + cgen_write(g, " else "); + curr = curr->next_elif; + } else break; + } + } break; + case STMT_WHILE: { + While *w = s->while_; + cgen_write(g, "while ("); + cgen_expr(g, w->cond); + cgen_write(g, ") "); + cgen_block(g, &w->body, 0); + } break; + case STMT_FOR: { + For *fo = s->for_; + int is_range = fo->flags & FOR_IS_RANGE; + Declaration *header_decl = &fo->header; + Identifier val_ident = header_decl->idents[0]; + Identifier index_ident = header_decl->idents[1]; + Type *fo_type = &header_decl->type; + assert(fo_type->kind == TYPE_TUPLE && arr_len(fo_type->tuple) == 2); + Type *val_type = &fo_type->tuple[0]; + Type *index_type = &fo_type->tuple[1]; + bool has_val = !ident_eq_str(val_ident, "_"); + bool has_index = !ident_eq_str(index_ident, "_"); + + Type *of_type = NULL; + bool uses_ptr = false; + + if (is_range) { + cgen_expr_pre(g, fo->range.from); + if (fo->range.to) + cgen_expr_pre(g, fo->range.to); + } else { + cgen_expr_pre(g, fo->of); + } + cgen_write(g, "{"); + if (is_range) { + if (fo->range.to) { + /* pre generate to */ + cgen_type_pre(g, val_type); + cgen_write(g, " to_"); + cgen_type_post(g, val_type); + cgen_write(g, " = "); + cgen_expr(g, fo->range.to); + cgen_write(g, "; "); + } + + /* set value to from */ + if (has_val) { + cgen_type_pre(g, val_type); + cgen_write(g, " "); + cgen_ident(g, val_ident); + cgen_type_post(g, val_type); + cgen_write(g, "; "); + Expression val_expr = {0}; + val_expr.flags = EXPR_FOUND_TYPE; + val_expr.kind = EXPR_IDENT; + val_expr.ident = val_ident; + val_expr.type = *val_type; + cgen_set(g, &val_expr, NULL, fo->range.from, NULL); + } else { + cgen_type_pre(g, val_type); + cgen_write(g, " val_"); + cgen_type_post(g, val_type); + cgen_write(g, "; "); + cgen_set(g, NULL, "val_", fo->range.from, NULL); + } + } else { + of_type = &fo->of->type; + if (of_type->kind == TYPE_PTR) { + uses_ptr = true; + of_type = of_type->ptr; + } + + /* pre-generate of */ + switch (of_type->kind) { + case TYPE_SLICE: + cgen_type_pre(g, of_type); + cgen_write(g, " of_"); + cgen_type_post(g, of_type); + cgen_write(g, " = "); + if (uses_ptr) cgen_write(g, "*"); + cgen_expr(g, fo->of); + cgen_write(g, "; "); + break; + case TYPE_ARR: + cgen_type_pre(g, of_type->arr.of); + cgen_write(g, " (* of_)"); + cgen_type_post(g, of_type->arr.of); + cgen_write(g, " = "); + if (uses_ptr) cgen_write(g, "*"); + cgen_expr(g, fo->of); + cgen_write(g, "; "); + break; + default: assert(0); break; + } + } + + if (has_index) { + cgen_type_pre(g, index_type); + cgen_write(g, " "); + cgen_ident(g, index_ident); + cgen_type_post(g, index_type); /* not needed yet, but keeping it here to prevent potential future problems */ + cgen_write(g, " = 0; "); + } + + cgen_write(g, "for ("); + + if (!is_range) { + cgen_type_pre(g, val_type); + cgen_write(g, "(%sp_)", uses_ptr ? "" : "*"); + cgen_type_post(g, val_type); + cgen_write(g, " = "); + switch (of_type->kind) { + case TYPE_ARR: + cgen_write(g, "of_"); + break; + case TYPE_SLICE: + cgen_write(g, "of_.data"); + break; + default: assert(0); break; + } + cgen_write(g, ", (*end_) = p_ + "); + switch (of_type->kind) { + case TYPE_ARR: + cgen_write(g, U64_FMT, (U64)of_type->arr.n); + break; + case TYPE_SLICE: + cgen_write(g, "of_.len"); + break; + default: assert(0); break; + } + } + + cgen_write(g, "; "); + if (!(is_range && !fo->range.to)) { /* if it's finite */ + if (is_range) { + if (has_val) + cgen_ident(g, val_ident); + else + cgen_write(g, "val_"); + bool positive_step + = fo->range.stepval == NULL || val_is_nonnegative(*fo->range.stepval, val_type); + cgen_write(g, " %c= to_", positive_step ? '<' : '>'); + } else { + cgen_write(g, "p_ != end_"); + } + } + cgen_write(g, "; "); + if (is_range) { + if (fo->range.stepval) { + cgen_val_pre(g, fo->range.stepval, val_type); + } + if (has_val) + cgen_ident(g, val_ident); + else + cgen_write(g, "val_"); + cgen_write(g, " += "); + if (fo->range.stepval) { + cgen_val(g, fo->range.stepval, val_type); + } else { + cgen_write(g, "1"); + } + if (has_index) cgen_write(g, ", "); + } else { + cgen_write(g, "++p_"); + if (has_index) cgen_write(g, ", "); + } + if (has_index) { + cgen_write(g, "++"); + cgen_ident(g, index_ident); + } + cgen_write(g, ") {"); + cgen_nl(g); + if (has_val) { + if (!is_range) { + cgen_type_pre(g, val_type); + cgen_write(g, " "); + cgen_ident(g, val_ident); + cgen_type_post(g, val_type); + cgen_write(g, "; "); + if (uses_ptr) { + cgen_ident(g, val_ident); + cgen_write(g, " = p_;"); + cgen_nl(g); + } else { + Expression set_expr = {0}; + set_expr.kind = EXPR_IDENT; + set_expr.ident = val_ident; + set_expr.type = *val_type; + set_expr.flags = EXPR_FOUND_TYPE; + + cgen_set(g, &set_expr, NULL, NULL, "(*p_)"); + cgen_nl(g); + } + } + } + cgen_block(g, &fo->body, CGEN_BLOCK_NOBRACES); + cgen_deferred_from_block(g, &fo->body); + cgen_write(g, "}}"); + if (fo->body.c.break_lbl) { + cgen_lbl(g, fo->body.c.break_lbl); + cgen_writeln(g, ":;"); + } + } break; + case STMT_BLOCK: + cgen_block(g, s->block, 0); + break; case STMT_INCLUDE: assert(0); break; diff --git a/copy.c b/copy.c index 3f352c2..b6716f5 100644 --- a/copy.c +++ b/copy.c @@ -250,41 +250,6 @@ static void copy_expr(Copier *c, Expression *out, Expression *in) { out->binary.lhs = copy_expr_(c, in->binary.lhs); out->binary.rhs = copy_expr_(c, in->binary.rhs); break; - case EXPR_IF: { - IfExpr *iin = in->if_; - IfExpr *iout = out->if_ = allocr_malloc(a, sizeof *iout); - *iout = *iin; - if (iin->cond) - iout->cond = copy_expr_(c, iin->cond); - if (iin->next_elif) - iout->next_elif = copy_expr_(c, iin->next_elif); - copy_block(c, &iout->body, &iin->body, 0); - } break; - case EXPR_WHILE: { - WhileExpr *win = in->while_; - WhileExpr *wout = out->while_ = allocr_malloc(a, sizeof *wout); - *wout = *win; - wout->cond = copy_expr_(c, win->cond); - copy_block(c, &wout->body, &win->body, 0); - } break; - case EXPR_FOR: { - ForExpr *fin = in->for_; - ForExpr *fout = out->for_ = allocr_malloc(a, sizeof *fout); - *fout = *fin; - Block *prev = c->block; - c->block = &fout->body; - idents_create(&fout->body.idents, c->allocr, &fout->body); - copy_decl(c, &fout->header, &fin->header); - if (fin->flags & FOR_IS_RANGE) { - fout->range.from = copy_expr_(c, fin->range.from); - if (fin->range.to) fout->range.to = copy_expr_(c, fin->range.to); - if (fin->range.step) fout->range.step = copy_expr_(c, fin->range.step); - } else { - fout->of = copy_expr_(c, fin->of); - } - c->block = prev; - copy_block(c, &fout->body, &fin->body, COPY_BLOCK_DONT_CREATE_IDENTS); - } break; case EXPR_FN: copy_fn_expr(c, out->fn = allocr_malloc(a, sizeof *out->fn), in->fn, 0); break; @@ -308,9 +273,6 @@ static void copy_expr(Copier *c, Expression *out, Expression *in) { copy_expr(c, &arg_out->val, &arg_in->val); } } break; - case EXPR_BLOCK: - copy_block(c, out->block = allocr_malloc(a, sizeof *out->block), in->block, 0); - break; case EXPR_TUPLE: { size_t nexprs = arr_len(in->tuple); out->tuple = NULL; @@ -413,6 +375,53 @@ static void copy_stmt(Copier *c, Statement *out, Statement *in) { *out->use = *in->use; copy_expr(c, &out->use->expr, &in->use->expr); break; + case STMT_IF: { + If *iin = in->if_; + If *iout = out->if_ = copier_malloc(c, sizeof *iout); + while (1) { + *iout = *iin; + + if (iin->cond) + iout->cond = copy_expr_(c, iin->cond); + copy_block(c, &iout->body, &iin->body, 0); + + if (iin->next_elif) { + iout->next_elif = copier_malloc(c, sizeof *iout->next_elif); + iout = iout->next_elif; + iin = iin->next_elif; + } else { + break; + } + } + } break; + case STMT_WHILE: { + While *win = in->while_; + While *wout = out->while_ = copier_malloc(c, sizeof *wout); + *wout = *win; + wout->cond = copy_expr_(c, win->cond); + copy_block(c, &wout->body, &win->body, 0); + } break; + case STMT_FOR: { + For *fin = in->for_; + For *fout = out->for_ = copier_malloc(c, sizeof *fout); + *fout = *fin; + Block *prev = c->block; + c->block = &fout->body; + idents_create(&fout->body.idents, c->allocr, &fout->body); + copy_decl(c, &fout->header, &fin->header); + if (fin->flags & FOR_IS_RANGE) { + fout->range.from = copy_expr_(c, fin->range.from); + if (fin->range.to) fout->range.to = copy_expr_(c, fin->range.to); + if (fin->range.step) fout->range.step = copy_expr_(c, fin->range.step); + } else { + fout->of = copy_expr_(c, fin->of); + } + c->block = prev; + copy_block(c, &fout->body, &fin->body, COPY_BLOCK_DONT_CREATE_IDENTS); + } break; + case STMT_BLOCK: + copy_block(c, out->block = copier_malloc(c, sizeof *out->block), in->block, 0); + break; case STMT_INLINE_BLOCK: assert(0); /* only exists after typing */ break; diff --git a/eval.c b/eval.c index 74c2e78..501f267 100644 --- a/eval.c +++ b/eval.c @@ -1028,8 +1028,9 @@ static Status eval_ident(Evaluator *ev, Identifier ident, Value *v, Location whe Block *prev_block = tr->block; /* make sure we're in the right block for typing the declaration */ tr->block = ident->idents->scope; - if (!types_decl(ev->typer, d)) return false; + bool success = types_decl(ev->typer, d); tr->block = prev_block; + if (!success) return false; assert(d->type.flags & TYPE_IS_RESOLVED); } Value *ival = ident_val(ev, ident, where); @@ -1210,167 +1211,6 @@ static Status eval_expr(Evaluator *ev, Expression *e, Value *v) { assert(0); } break; - case EXPR_IF: { - IfExpr *i = e->if_; - if (i->cond) { - Value cond; - if (i->cond->type.kind == TYPE_UNKNOWN) { - if (!i->cond->where.file->ctx->have_errored) { - err_print(i->cond->where, "Couldn't determine type of if condition, but need to evaluate it."); - return false; - } - return false; - } - if (!eval_expr(ev, i->cond, &cond)) return false; - if (val_truthiness(cond, &i->cond->type)) { - if (!eval_block(ev, &i->body)) return false; - } else if (i->next_elif && !ev->returning) { - if (!eval_expr(ev, i->next_elif, v)) return false; - } - } else { - if (!eval_block(ev, &i->body)) return false; - } - memset(v, 0, sizeof *v); - } break; - case EXPR_WHILE: { - Value cond; - WhileExpr *w = e->while_; - while (1) { - if (w->cond) { - if (w->cond->type.kind == TYPE_UNKNOWN) { - if (!w->cond->where.file->ctx->have_errored) { - err_print(w->cond->where, "Couldn't determine type of while condition, but need to evaluate it."); - return false; - } - return false; - } - if (!eval_expr(ev, w->cond, &cond)) return false; - Type *cond_type = &w->cond->type; - if (!val_truthiness(cond, cond_type)) - break; - } - if (!eval_block(ev, &w->body)) return false; - if (ev->returning) { - if (ev->returning == &w->body) { - ev->returning = NULL; - if (ev->is_break) - break; - } else break; - } - } - memset(v, 0, sizeof *v); - } break; - case EXPR_FOR: { - ForExpr *fo = e->for_; - Declaration *header = &fo->header; - Value *for_valp = err_malloc(sizeof *for_valp); - arr_add(header->val_stack, for_valp); - /* make a tuple */ - Value for_val_tuple[2]; - for_valp->tuple = for_val_tuple; - Value *value_val = &for_val_tuple[0]; - Value *index_val = &for_val_tuple[1]; - Type *value_type = &header->type.tuple[0]; - if (fo->flags & FOR_IS_RANGE) { - assert(value_type->kind == TYPE_BUILTIN); - Value from, to; - Value stepval; - i64_to_val(&stepval, value_type->builtin, 1); - if (!eval_expr(ev, fo->range.from, &from)) return false; - if (fo->range.to && !eval_expr(ev, fo->range.to, &to)) return false; - if (fo->range.stepval) - stepval = *fo->range.stepval; - Value x = from; - bool step_is_negative = fo->range.stepval && !val_is_nonnegative(stepval, value_type); - if (index_val) index_val->i64 = 0; - while (1) { - if (fo->range.to) { - /* check if loop has ended */ - Value lhs = x; - Value rhs = to; - Type boolt = {0}; - boolt.flags = TYPE_IS_RESOLVED; - boolt.kind = TYPE_BUILTIN; - boolt.builtin = BUILTIN_BOOL; - Value cont; - - eval_numerical_bin_op(lhs, value_type, step_is_negative ? BINARY_GE : BINARY_LE, rhs, &fo->range.to->type, &cont, &boolt); - if (!cont.boolv) break; - } - if (value_val) *value_val = x; - - if (!eval_block(ev, &fo->body)) return false; - - if (ev->returning) { - if (ev->returning == &fo->body) { - ev->returning = NULL; - if (ev->is_break) - break; - } else break; - } - if (index_val) { - ++index_val->i64; - } - eval_numerical_bin_op(x, value_type, BINARY_ADD, stepval, value_type, &x, value_type); - } - - } else { - Value x; - Value *index = index_val ? index_val : &x; - Value of; - if (!eval_expr(ev, fo->of, &of)) return false; - I64 len; - bool uses_ptr = false; - Type *of_type = &fo->of->type; - if (of_type->kind == TYPE_PTR) { - uses_ptr = true; - of_type = of_type->ptr; - } - switch (of_type->kind) { - case TYPE_ARR: - len = (I64)of_type->arr.n; - if (uses_ptr) { - of.arr = of.ptr; - } - - break; - case TYPE_SLICE: - if (uses_ptr) { - of.slice = *(Slice *)of.ptr; - } - len = of.slice.len; - break; - default: assert(0); return false; - } - - index->i64 = 0; - while (index->i64 < len) { - void *ptr = NULL; - if (!eval_val_ptr_at_index(e->where, &of, (U64)index->i64, of_type, &ptr, NULL)) - return false; - if (uses_ptr) - value_val->ptr = ptr; - else - eval_deref(value_val, ptr, value_type); - if (!eval_block(ev, &fo->body)) - return false; - if (ev->returning) { - if (ev->returning == &fo->body) { - ev->returning = NULL; - if (ev->is_break) - break; - } else break; - } - ++index->i64; - } - } - arr_remove_last(header->val_stack); - free(for_valp); - memset(v, 0, sizeof *v); - } break; - case EXPR_BLOCK: - if (!eval_block(ev, e->block)) return false; - break; case EXPR_LITERAL_BOOL: v->boolv = e->booll; break; @@ -1487,19 +1327,6 @@ static Status eval_expr(Evaluator *ev, Expression *e, Value *v) { ++idx; } } - - - - /* make sure function body is typed before calling it */ - /* @TODO: is this necessary? see also types_decl call in eval_ident */ - if (!(fn->body.flags & BLOCK_FOUND_TYPES)) { - Typer *tr = ev->typer; - Block *prev_block = tr->block; - tr->block = fn->declaration_block; - if (!types_block(tr, &fn->body)) - return false; - tr->block = prev_block; - } if (!eval_block(ev, &fn->body)) { return false; @@ -1704,6 +1531,166 @@ static Status eval_stmt(Evaluator *ev, Statement *stmt) { } eval_exit_stmts(stmts, last_reached); } break; + case STMT_IF: { + for (If *i = stmt->if_; i; i = i->next_elif) { + if (i->cond) { + Value cond; + if (i->cond->type.kind == TYPE_UNKNOWN) { + if (!i->cond->where.file->ctx->have_errored) { + err_print(i->cond->where, "Couldn't determine type of if condition, but need to evaluate it."); + return false; + } + return false; + } + if (!eval_expr(ev, i->cond, &cond)) return false; + if (val_truthiness(cond, &i->cond->type)) { + /* condition is true */ + if (!eval_block(ev, &i->body)) return false; + break; + } + } else { + assert(!i->next_elif); + if (!eval_block(ev, &i->body)) return false; + } + } + } break; + case STMT_WHILE: { + Value cond; + While *w = stmt->while_; + while (1) { + if (w->cond) { + if (w->cond->type.kind == TYPE_UNKNOWN) { + if (!w->cond->where.file->ctx->have_errored) { + err_print(w->cond->where, "Couldn't determine type of while condition, but need to evaluate it."); + return false; + } + return false; + } + if (!eval_expr(ev, w->cond, &cond)) return false; + Type *cond_type = &w->cond->type; + if (!val_truthiness(cond, cond_type)) + break; + } + if (!eval_block(ev, &w->body)) return false; + if (ev->returning) { + if (ev->returning == &w->body) { + ev->returning = NULL; + if (ev->is_break) + break; + } else break; + } + } + } break; + case STMT_FOR: { + For *fo = stmt->for_; + Declaration *header = &fo->header; + Value *for_valp = err_malloc(sizeof *for_valp); + arr_add(header->val_stack, for_valp); + /* make a tuple */ + Value for_val_tuple[2]; + for_valp->tuple = for_val_tuple; + Value *value_val = &for_val_tuple[0]; + Value *index_val = &for_val_tuple[1]; + Type *value_type = &header->type.tuple[0]; + if (fo->flags & FOR_IS_RANGE) { + assert(value_type->kind == TYPE_BUILTIN); + Value from, to; + Value stepval; + i64_to_val(&stepval, value_type->builtin, 1); + if (!eval_expr(ev, fo->range.from, &from)) return false; + if (fo->range.to && !eval_expr(ev, fo->range.to, &to)) return false; + if (fo->range.stepval) + stepval = *fo->range.stepval; + Value x = from; + bool step_is_negative = fo->range.stepval && !val_is_nonnegative(stepval, value_type); + if (index_val) index_val->i64 = 0; + while (1) { + if (fo->range.to) { + /* check if loop has ended */ + Value lhs = x; + Value rhs = to; + Type boolt = {0}; + boolt.flags = TYPE_IS_RESOLVED; + boolt.kind = TYPE_BUILTIN; + boolt.builtin = BUILTIN_BOOL; + Value cont; + + eval_numerical_bin_op(lhs, value_type, step_is_negative ? BINARY_GE : BINARY_LE, rhs, &fo->range.to->type, &cont, &boolt); + if (!cont.boolv) break; + } + if (value_val) *value_val = x; + + if (!eval_block(ev, &fo->body)) return false; + + if (ev->returning) { + if (ev->returning == &fo->body) { + ev->returning = NULL; + if (ev->is_break) + break; + } else break; + } + if (index_val) { + ++index_val->i64; + } + eval_numerical_bin_op(x, value_type, BINARY_ADD, stepval, value_type, &x, value_type); + } + + } else { + Value x; + Value *index = index_val ? index_val : &x; + Value of; + if (!eval_expr(ev, fo->of, &of)) return false; + I64 len; + bool uses_ptr = false; + Type *of_type = &fo->of->type; + if (of_type->kind == TYPE_PTR) { + uses_ptr = true; + of_type = of_type->ptr; + } + switch (of_type->kind) { + case TYPE_ARR: + len = (I64)of_type->arr.n; + if (uses_ptr) { + of.arr = of.ptr; + } + + break; + case TYPE_SLICE: + if (uses_ptr) { + of.slice = *(Slice *)of.ptr; + } + len = of.slice.len; + break; + default: assert(0); return false; + } + + index->i64 = 0; + while (index->i64 < len) { + void *ptr = NULL; + if (!eval_val_ptr_at_index(stmt->where, &of, (U64)index->i64, of_type, &ptr, NULL)) + return false; + if (uses_ptr) + value_val->ptr = ptr; + else + eval_deref(value_val, ptr, value_type); + if (!eval_block(ev, &fo->body)) + return false; + if (ev->returning) { + if (ev->returning == &fo->body) { + ev->returning = NULL; + if (ev->is_break) + break; + } else break; + } + ++index->i64; + } + } + arr_remove_last(header->val_stack); + free(for_valp); + } break; + case STMT_BLOCK: + if (!eval_block(ev, stmt->block)) return false; + break; case STMT_INCLUDE: assert(0); break; @@ -1712,6 +1699,7 @@ static Status eval_stmt(Evaluator *ev, Statement *stmt) { } static Status eval_block(Evaluator *ev, Block *b) { + assert(b->flags & BLOCK_FOUND_TYPES); Block *prev = ev->typer->block; ev->typer->block = b; b->deferred = NULL; diff --git a/main.c b/main.c index 48ae840..a092fce 100644 --- a/main.c +++ b/main.c @@ -8,10 +8,8 @@ /* @TODO: -get rid of blocks returning values -turn if, while, for, block into statements +fix expr_find_end see if you can get rid of Expression.cgen.id--would mean that kind doesn't have to be a bitfield anymore -make sure functions which should return things do check return #C("3"); initialization statements (maybe #init(-50), where -50 is the priority and <0 is reserved for standard library) if we do #include "foo.toc", bar; and foo.toc fails, bar should be declared as TYPE_UNKNOWN (right now it's undeclared) diff --git a/parse.c b/parse.c index 8a941cf..7b8c76a 100644 --- a/parse.c +++ b/parse.c @@ -42,9 +42,6 @@ static const char *expr_kind_to_str(ExprKind k) { case EXPR_LITERAL_STR: return "string literal"; case EXPR_LITERAL_BOOL: return "boolean literal"; case EXPR_LITERAL_CHAR: return "character literal"; - case EXPR_IF: return "if expression"; - case EXPR_WHILE: return "while expression"; - case EXPR_FOR: return "for expression"; case EXPR_CALL: return "function call"; case EXPR_C: return "C code"; case EXPR_BUILTIN: return "#builtin value"; @@ -53,7 +50,6 @@ static const char *expr_kind_to_str(ExprKind k) { case EXPR_BINARY_OP: return "binary operator"; case EXPR_FN: return "function expression"; case EXPR_TUPLE: return "tuple"; - case EXPR_BLOCK: return "block"; case EXPR_IDENT: return "identifier"; case EXPR_SLICE: return "slice"; case EXPR_TYPE: return "type"; @@ -867,6 +863,11 @@ static Status parse_block(Parser *p, Block *b, U8 flags) { parser_put_end(p, &b->where); end: p->block = prev_block; + if (!ret) { + /* @TODO: better way of skipping to end of block */ + while (t->token->kind != TOKEN_EOF && !token_is_kw(t->token, KW_RBRACE)) + ++t->token; + } return ret; } @@ -1315,9 +1316,6 @@ static Status parse_expr(Parser *p, Expression *e, Token *end) { Token *start = t->token; - if (token_is_direct(t->token, DIRECT_IF)) { - goto if_expr; - } if (t->token->kind == TOKEN_KW) switch (t->token->kw) { case KW_FN: { /* this is a function */ @@ -1345,157 +1343,6 @@ static Status parse_expr(Parser *p, Expression *e, Token *end) { n->body.kind = BLOCK_NMS; goto success; } - case KW_IF: - if_expr: { - IfExpr *i = e->if_ = parser_malloc(p, sizeof *i); - i->flags = 0; - if (t->token->kind == TOKEN_DIRECT) { - i->flags |= IF_STATIC; - } - e->kind = EXPR_IF; - ++t->token; - Token *cond_end = expr_find_end(p, EXPR_CAN_END_WITH_LBRACE); - if (!cond_end) return false; - if (!token_is_kw(cond_end, KW_LBRACE)) { - t->token = cond_end; - tokr_err(t, "Expected { to open if body."); - return false; - } - i->cond = parser_new_expr(p); - if (!parse_expr(p, i->cond, cond_end)) return false; - if (!parse_block(p, &i->body, 0)) return false; - IfExpr *curr = i; - while (1) { - bool is_else = token_is_kw(t->token, KW_ELSE); - bool is_elif = token_is_kw(t->token, KW_ELIF); - if (!is_else && !is_elif) { - curr->next_elif = NULL; - break; - } - if (curr->cond == NULL) { - tokr_err(t, "You can't have more elif/elses after an else."); - return false; - } - Expression *next = parser_new_expr(p); - next->flags = 0; - next->kind = EXPR_IF; - next->where = parser_mk_loc(p); - curr->next_elif = next; - IfExpr *nexti = next->if_ = parser_malloc(p, sizeof *nexti); - nexti->flags = 0; - if (is_else) { - ++t->token; - nexti->cond = NULL; - if (!parse_block(p, &nexti->body, 0)) return false; - } else { - /* elif */ - ++t->token; - cond_end = expr_find_end(p, EXPR_CAN_END_WITH_LBRACE); - if (!cond_end) return false; - if (!token_is_kw(cond_end, KW_LBRACE)) { - t->token = cond_end; - tokr_err(t, "Expected { to open elif body."); - return false; - } - Expression *cond = parser_new_expr(p); - if (!parse_expr(p, cond, cond_end)) - return false; - nexti->cond = cond; - if (!parse_block(p, &nexti->body, 0)) return false; - } - parser_put_end(p, &next->where); - curr = nexti; - } - goto success; - } - case KW_WHILE: { - e->kind = EXPR_WHILE; - WhileExpr *w = e->while_ = parser_malloc(p, sizeof *w); - ++t->token; - Token *cond_end = expr_find_end(p, EXPR_CAN_END_WITH_LBRACE); - if (!cond_end) return false; - if (!token_is_kw(cond_end, KW_LBRACE)) { - t->token = cond_end; - tokr_err(t, "Expected { to open while body."); - return false; - } - Expression *cond = parser_new_expr(p); - w->cond = cond; - - if (!parse_expr(p, cond, cond_end)) - return false; - if (!parse_block(p, &w->body, 0)) return false; - w->body.kind = BLOCK_WHILE; - goto success; - } - case KW_FOR: { - e->kind = EXPR_FOR; - ForExpr *fo = e->for_ = parser_malloc(p, sizeof *fo); - fo->flags = 0; - Block *prev_block = p->block; - fo->body.parent = p->block; - p->block = &fo->body; - Declaration *header_decl = &fo->header; - idents_create(&p->block->idents, p->allocr, p->block); - ++t->token; - if (!parse_decl(p, header_decl, PARSE_DECL_IGNORE_EXPR | DECL_CAN_END_WITH_LBRACE)) - goto for_fail; - - if (!token_is_kw(t->token, KW_EQ)) { - tokr_err(t, "Expected = to follow for declaration."); - goto for_fail; - } - ++t->token; - Token *first_end; first_end = expr_find_end(p, EXPR_CAN_END_WITH_COMMA|EXPR_CAN_END_WITH_DOTDOT|EXPR_CAN_END_WITH_LBRACE); - Expression *first; first = parser_new_expr(p); - if (!parse_expr(p, first, first_end)) - goto for_fail; - if (token_is_kw(first_end, KW_LBRACE)) { - fo->of = first; - } else if (token_is_kw(first_end, KW_DOTDOT) || token_is_kw(first_end, KW_COMMA)) { - fo->flags |= FOR_IS_RANGE; - fo->range.from = first; - if (token_is_kw(first_end, KW_COMMA)) { - /* step */ - ++t->token; - fo->range.step = parser_new_expr(p); - Token *step_end = expr_find_end(p, EXPR_CAN_END_WITH_LBRACE|EXPR_CAN_END_WITH_DOTDOT); - if (!parse_expr(p, fo->range.step, step_end)) - goto for_fail; - if (!token_is_kw(step_end, KW_DOTDOT)) { - err_print(token_location(p->file, step_end), "Expected .. to follow step in for statement."); - goto for_fail; - } - } else { - fo->range.step = NULL; - } - ++t->token; /* move past .. */ - if (token_is_kw(t->token, KW_LBRACE)) { - fo->range.to = NULL; /* infinite loop! */ - } else { - fo->range.to = parser_new_expr(p); - Token *to_end = expr_find_end(p, EXPR_CAN_END_WITH_LBRACE); - if (!parse_expr(p, fo->range.to, to_end)) - goto for_fail; - if (!token_is_kw(t->token, KW_LBRACE)) { - tokr_err(t, "Expected { to open body of for statement."); - goto for_fail; - } - } - } else { - err_print(token_location(p->file, first_end), "Expected { or .. to follow expression in for statement."); - goto for_fail; - } - parser_put_end(p, &fo->header.where); - p->block = prev_block; - if (!parse_block(p, &fo->body, PARSE_BLOCK_DONT_CREATE_IDENTS)) - goto for_fail; - fo->body.kind = BLOCK_FOR; - goto success; - for_fail: - p->block = prev_block; - return false; - } default: break; } if (token_is_direct(t->token, DIRECT_FOREIGN)) { @@ -2090,17 +1937,6 @@ static Status parse_expr(Parser *p, Expression *e, Token *end) { } } - if (token_is_kw(t->token, KW_LBRACE)) { - /* it's a block */ - e->kind = EXPR_BLOCK; - if (!parse_block(p, e->block = parser_malloc(p, sizeof *e->block), 0)) return false; - if (t->token != end) { - tokr_err(t, "Expression continues after end of block."); /* @TODO: improve this err message */ - return false; - } - goto success; - } - if (dot) { e->kind = EXPR_BINARY_OP; e->binary.lhs = parser_new_expr(p); @@ -2378,6 +2214,11 @@ static Status parse_stmt(Parser *p, Statement *s, bool *was_a_statement) { *was_a_statement = false; ++t->token; break; + case KW_LBRACE: + /* it's a block */ + s->kind = STMT_BLOCK; + if (!parse_block(p, s->block = parser_malloc(p, sizeof *s->block), 0)) return false; + break; case KW_RETURN: { s->kind = STMT_RET; ++t->token; @@ -2402,8 +2243,7 @@ static Status parse_stmt(Parser *p, Statement *s, bool *was_a_statement) { bool parsed = parse_expr(p, &r->expr, end); t->token = end + 1; if (!parsed) return false; - break; - } + } break; case KW_BREAK: s->kind = STMT_BREAK; ++t->token; @@ -2443,6 +2283,168 @@ static Status parse_stmt(Parser *p, Statement *s, bool *was_a_statement) { return false; break; } + case KW_IF: + if_stmt: { + If *i = s->if_ = parser_malloc(p, sizeof *i); + i->flags = 0; + if (t->token->kind == TOKEN_DIRECT) { + i->flags |= IF_STATIC; + } + s->kind = STMT_IF; + ++t->token; + Token *cond_end = expr_find_end(p, EXPR_CAN_END_WITH_LBRACE); + if (!cond_end) { + tokr_skip_to_eof(t); + return false; + } + if (!token_is_kw(cond_end, KW_LBRACE)) { + t->token = cond_end; + tokr_err(t, "Expected { to open if body."); + tokr_skip_to_eof(t); + return false; + } + i->cond = parser_new_expr(p); + bool cond_success = parse_expr(p, i->cond, cond_end); + t->token = cond_end; + if (!parse_block(p, &i->body, 0)) return false; + if (!cond_success) return false; + If *curr = i; + while (1) { + bool is_else = token_is_kw(t->token, KW_ELSE); + bool is_elif = token_is_kw(t->token, KW_ELIF); + if (!is_else && !is_elif) { + curr->next_elif = NULL; + break; + } + if (curr->cond == NULL) { + tokr_err(t, "You can't have more elif/elses after an else."); + tokr_skip_to_eof(t); + return false; + } + If *next = parser_calloc(p, 1, sizeof *next); + curr->next_elif = next; + if (is_else) { + ++t->token; + next->cond = NULL; + if (!parse_block(p, &next->body, 0)) return false; + } else { + /* elif */ + ++t->token; + cond_end = expr_find_end(p, EXPR_CAN_END_WITH_LBRACE); + if (!cond_end) { + tokr_skip_to_eof(t); + return false; + } + if (!token_is_kw(cond_end, KW_LBRACE)) { + t->token = cond_end; + tokr_err(t, "Expected { to open elif body."); + tokr_skip_to_eof(t); + return false; + } + Expression *cond = next->cond = parser_new_expr(p); + cond_success = parse_expr(p, cond, cond_end); + t->token = cond_end; + if (!parse_block(p, &next->body, 0)) return false; + if (!cond_success) return false; + } + curr = next; + } + } break; + case KW_WHILE: { + s->kind = STMT_WHILE; + While *w = s->while_ = parser_malloc(p, sizeof *w); + ++t->token; + Token *cond_end = expr_find_end(p, EXPR_CAN_END_WITH_LBRACE); + if (!cond_end) return false; + if (!token_is_kw(cond_end, KW_LBRACE)) { + t->token = cond_end; + tokr_err(t, "Expected { to open while body."); + tokr_skip_to_eof(t); + return false; + } + Expression *cond = parser_new_expr(p); + w->cond = cond; + /* parse the body even if the condition fails */ + bool cond_success = parse_expr(p, cond, cond_end); + t->token = cond_end; + if (!parse_block(p, &w->body, 0)) return false; + if (!cond_success) return false; + w->body.kind = BLOCK_WHILE; + } break; + case KW_FOR: { + s->kind = STMT_FOR; + For *fo = s->for_ = parser_malloc(p, sizeof *fo); + fo->flags = 0; + Block *prev_block = p->block; + fo->body.parent = p->block; + p->block = &fo->body; + Declaration *header_decl = &fo->header; + idents_create(&p->block->idents, p->allocr, p->block); + ++t->token; + if (!parse_decl(p, header_decl, PARSE_DECL_IGNORE_EXPR | DECL_CAN_END_WITH_LBRACE)) { + tokr_skip_to_eof(t); + goto for_fail; + } + + if (!token_is_kw(t->token, KW_EQ)) { + tokr_err(t, "Expected = to follow for declaration."); + tokr_skip_to_eof(t); + goto for_fail; + } + ++t->token; + Token *first_end; first_end = expr_find_end(p, EXPR_CAN_END_WITH_COMMA|EXPR_CAN_END_WITH_DOTDOT|EXPR_CAN_END_WITH_LBRACE); + Expression *first; first = parser_new_expr(p); + if (!parse_expr(p, first, first_end)) + goto for_fail; + if (token_is_kw(first_end, KW_LBRACE)) { + fo->of = first; + } else if (token_is_kw(first_end, KW_DOTDOT) || token_is_kw(first_end, KW_COMMA)) { + fo->flags |= FOR_IS_RANGE; + fo->range.from = first; + if (token_is_kw(first_end, KW_COMMA)) { + /* step */ + ++t->token; + fo->range.step = parser_new_expr(p); + Token *step_end = expr_find_end(p, EXPR_CAN_END_WITH_LBRACE|EXPR_CAN_END_WITH_DOTDOT); + if (!parse_expr(p, fo->range.step, step_end)) + goto for_fail; + if (!token_is_kw(step_end, KW_DOTDOT)) { + err_print(token_location(p->file, step_end), "Expected .. to follow step in for statement."); + tokr_skip_to_eof(t); + goto for_fail; + } + } else { + fo->range.step = NULL; + } + ++t->token; /* move past .. */ + if (token_is_kw(t->token, KW_LBRACE)) { + fo->range.to = NULL; /* infinite loop! */ + } else { + fo->range.to = parser_new_expr(p); + Token *to_end = expr_find_end(p, EXPR_CAN_END_WITH_LBRACE); + if (!parse_expr(p, fo->range.to, to_end)) + goto for_fail; + if (!token_is_kw(t->token, KW_LBRACE)) { + tokr_err(t, "Expected { to open body of for statement."); + tokr_skip_to_eof(t); + goto for_fail; + } + } + } else { + err_print(token_location(p->file, first_end), "Expected { or .. to follow expression in for statement."); + tokr_skip_to_eof(t); + goto for_fail; + } + parser_put_end(p, &fo->header.where); + p->block = prev_block; + if (!parse_block(p, &fo->body, PARSE_BLOCK_DONT_CREATE_IDENTS)) + goto for_fail; + fo->body.kind = BLOCK_FOR; + break; + for_fail: + p->block = prev_block; + return false; + } default: goto stmt_expr; } } else if (t->token->kind == TOKEN_DIRECT) { @@ -2478,6 +2480,8 @@ static Status parse_stmt(Parser *p, Statement *s, bool *was_a_statement) { } ++t->token; } break; + case DIRECT_IF: + goto if_stmt; case DIRECT_ERROR: case DIRECT_WARN: case DIRECT_INFO: { @@ -2733,52 +2737,6 @@ static void fprint_expr(FILE *out, Expression *e) { fprint_type(out, &e->cast.type); fprintf(out, ")"); break; - case EXPR_IF: { - IfExpr *i = e->if_; - if (i->cond) { - fprintf(out, "(else)? if "); - fprint_expr(out, i->cond); - } else { - fprintf(out, "else"); - } - fprint_block(out, &i->body); - if (i->next_elif) - fprint_expr(out, i->next_elif); - } break; - case EXPR_WHILE: { - WhileExpr *w = e->while_; - fprintf(out, "while "); - fprint_expr(out, w->cond); - fprint_block(out, &w->body); - } break; - case EXPR_FOR: { - ForExpr *fo = e->for_; - fprintf(out, "for "); - fprint_decl(out, &fo->header); - fprintf(out, "= "); - if (fo->flags & FOR_IS_RANGE) { - fprint_expr(out, fo->range.from); - if (found_type) { - if (fo->range.stepval) { - fprintf(out, ","); - fprint_val(out, *fo->range.stepval, &fo->header.type.tuple[0]); - } - } else { - if (fo->range.step) { - fprintf(out, ","); - fprint_expr(out, fo->range.step); - } - } - fprintf(out, ".."); - if (fo->range.to) { - fprint_expr(out, fo->range.to); - } - fprintf(out, " "); - } else { - fprint_expr(out, fo->of); - } - fprint_block(out, &fo->body); - } break; case EXPR_CALL: fprint_expr(out, e->call.fn); if (found_type) { @@ -2787,9 +2745,6 @@ static void fprint_expr(FILE *out, Expression *e) { fprint_args(out, e->call.args); } break; - case EXPR_BLOCK: - fprint_block(out, e->block); - break; case EXPR_TUPLE: fprintf(out, "("); arr_foreach(e->tuple, Expression, x) { @@ -2876,6 +2831,7 @@ static void print_decl(Declaration *d) { static void fprint_stmt(FILE *out, Statement *s) { PARSE_PRINT_LOCATION(s->where); + bool typed = (s->flags & STMT_TYPED) != 0; switch (s->kind) { case STMT_DECL: fprint_decl(out, s->decl); @@ -2929,6 +2885,57 @@ static void fprint_stmt(FILE *out, Statement *s) { fprint_expr(out, &s->use->expr); fprintf(out, ";\n"); break; + case STMT_IF: { + If *i = s->if_; + bool first = true; + while (i) { + if (i->cond) { + fprintf(out, "%sif ", first ? "" : "el"); + fprint_expr(out, i->cond); + } else { + fprintf(out, "else"); + } + fprint_block(out, &i->body); + first = false; + } + } break; + case STMT_WHILE: { + While *w = s->while_; + fprintf(out, "while "); + fprint_expr(out, w->cond); + fprint_block(out, &w->body); + } break; + case STMT_FOR: { + For *fo = s->for_; + fprintf(out, "for "); + fprint_decl(out, &fo->header); + fprintf(out, "= "); + if (fo->flags & FOR_IS_RANGE) { + fprint_expr(out, fo->range.from); + if (typed) { + if (fo->range.stepval) { + fprintf(out, ","); + fprint_val(out, *fo->range.stepval, &fo->header.type.tuple[0]); + } + } else { + if (fo->range.step) { + fprintf(out, ","); + fprint_expr(out, fo->range.step); + } + } + fprintf(out, ".."); + if (fo->range.to) { + fprint_expr(out, fo->range.to); + } + fprintf(out, " "); + } else { + fprint_expr(out, fo->of); + } + fprint_block(out, &fo->body); + } break; + case STMT_BLOCK: + fprint_block(out, s->block); + break; case STMT_INLINE_BLOCK: arr_foreach(s->inline_block, Statement, sub) fprint_stmt(out, sub); @@ -3002,15 +3009,11 @@ static bool expr_is_definitely_const(Expression *e) { case EXPR_VAL: case EXPR_NMS: return true; - case EXPR_IF: - case EXPR_WHILE: case EXPR_C: case EXPR_BUILTIN: case EXPR_CAST: case EXPR_CALL: - case EXPR_BLOCK: case EXPR_TUPLE: - case EXPR_FOR: case EXPR_FN: return false; case EXPR_UNARY_OP: diff --git a/test.toc b/test.toc index 9f27d1c..d596c68 100644 --- a/test.toc +++ b/test.toc @@ -5,6 +5,10 @@ main ::= fn() { } foo ::= fn(x: int) int { - return 3*x; + if x == 3 { + return 7; + } else { + return 3*x; + } } diff --git a/types.c b/types.c index 198de00..8815ddb 100644 --- a/types.c +++ b/types.c @@ -1152,6 +1152,26 @@ static bool arg_is_const(Expression *arg, Constness constness) { return false; } +/* does this statement no matter what result in a return? */ +static Status definitely_returns(Statement *s) { + if (s->kind == STMT_RET) return true; /* of course */ + if (s->kind == STMT_IF) { + /* if foo { return 5; } else { return 6; } */ + bool has_else = false; + for (If *i = s->if_; i; i = i->next_elif) { + Statement *last_stmt = arr_last_ptr(i->body.stmts); + if (!definitely_returns(last_stmt)) + return false; + if (!i->cond) has_else = true; + } + return has_else; + } else if (s->kind == STMT_BLOCK) { + /* { return 7; } */ + Statement *last_stmt = arr_last_ptr(s->block->stmts); + return definitely_returns(last_stmt); + } + return false; +} /* pass NULL for instance if this isn't an instance */ static Status types_fn(Typer *tr, FnExpr *f, Type *t, Instance *instance) { @@ -1186,19 +1206,13 @@ static Status types_fn(Typer *tr, FnExpr *f, Type *t, Instance *instance) { if (!type_is_builtin(ret_type, BUILTIN_VOID) && !has_named_ret_vals) { Statement *stmts = f->body.stmts; if (arr_len(stmts)) { - Statement *last_stmt = (Statement *)stmts + (arr_len(stmts) - 1); - if (last_stmt->kind == STMT_RET) { - /* - last statement is a return, so it doesn't matter that the function has no return value - ideally this would handle if foo { return 5; } else { return 6; } - */ - success = true; + Statement *last_stmt = arr_last_ptr(stmts); + if (definitely_returns(last_stmt)) goto ret; - } } char *expected = type_to_str(ret_type); err_print(token_location(f->body.where.file, &f->body.where.file->tokens[f->body.where.end-1]), - "No return value in function which returns %s.", expected); + "Function which should return %s is missing a return statement (or it does not clearly always return).", expected); free(expected); info_print(f->where, "Function was declared here:"); success = false; @@ -1640,576 +1654,188 @@ static Status types_expr(Typer *tr, Expression *e) { t->kind = TYPE_BUILTIN; t->builtin = BUILTIN_CHAR; break; - case EXPR_FOR: { - bool in_header = true;{ /* additional block because c++ */ - ForExpr *fo = e->for_; - Declaration *header = &fo->header; - U32 is_range = fo->flags & FOR_IS_RANGE; - typer_arr_add(tr, tr->in_decls, header); - fo->body.uses = NULL; - typer_block_enter(tr, &fo->body); - bool annotated_index = true; - { - size_t nidents = arr_len(header->idents); - if (nidents > 2) { - err_print(header->where, "Expected at most 2 identifiers in for declaration (index and value) but got %lu.", - (unsigned long)nidents); - goto for_fail; - } - if (nidents < 2) { - annotated_index = false; - assert(nidents == 1); - /* turn value := arr to value, _ := arr to simplify things */ - typer_arr_add(tr, header->idents, ident_insert_with_len(typer_get_idents(tr), "_", 1)); - } + case EXPR_IDENT: { + Block *b = tr->block; + String i = e->ident_str; + char *i_str = i.str; + size_t i_len = i.len; + if (str_eq_cstr(i, "_")) { + err_print(e->where, "You cannot use _ as a variable. It is used for ignoring results of function calls, e.g. _, y := function_which_returns_two_things();"); + return false; } - - Type *fo_type_tuple = NULL; - /* fo_type is (val_type, index_type) */ - arr_set_lena(fo_type_tuple, 2, tr->allocr); - memset(fo_type_tuple, 0, 2*sizeof *fo_type_tuple); - Type *val_type = &fo_type_tuple[0]; - Type *index_type = &fo_type_tuple[1]; + Identifier final_ident = NULL; + bool undeclared = true; + while (1) { /* for each block we are inside... */ + /* @OPTIM: only hash once */ + Identifier translated = ident_get_with_len(b ? &b->idents : tr->globals, i_str, i_len); + if (translated) { +#if 0 + printf("translated %s from\n", ident_to_str(i)); + print_block_location(i->idents->body); + printf(" to \n"); + print_block_location(translated->idents->body); +#endif + final_ident = translated; + undeclared = false; + } + Use **uses = b ? b->uses : tr->uses; - if (header->flags & DECL_ANNOTATES_TYPE) { - Type *header_type = &header->type; - if (!type_resolve(tr, header_type, header->where)) - goto for_fail; - if (annotated_index) { - if (header_type->kind != TYPE_TUPLE || arr_len(header_type->tuple) != 2) { - char *s = type_to_str(header_type); - err_print(header->where, "Expected annotated for loop type to be (val_type, index_type), but got %s instead.", s); - free(s); - goto for_fail; + Use *previous_use_which_uses_i = NULL; + arr_foreach(uses, UsePtr, usep) { + Use *use = *usep; + Expression *used = &use->expr; + Identifier translated_use; + bool was_a_struct = false; + if (type_is_builtin(&used->type, BUILTIN_NMS)) { + Value val; + if (!eval_expr(tr->evalr, used, &val)) + return 0; + Namespace *nms = val.nms; + Block *body = &nms->body; + /* look up identifier in namespace */ + translated_use = ident_get_with_len(&body->idents, i_str, i_len); + } else { + /* it's a struct */ + was_a_struct = true; + Type *struct_type = &used->type; + if (struct_type->kind == TYPE_PTR) + struct_type = struct_type->ptr; + assert(struct_type->kind == TYPE_STRUCT); + StructDef *struc = struct_type->struc; + translated_use = ident_get_with_len(&struc->body.idents, i_str, i_len); } - fo_type_tuple = header_type->tuple; - val_type = &fo_type_tuple[0]; - index_type = &fo_type_tuple[1]; - assert(val_type->flags & TYPE_IS_RESOLVED); - assert(index_type->flags & TYPE_IS_RESOLVED); - if (!type_is_int(index_type)) { - char *s = type_to_str(index_type); - err_print(header->where, "Expected index type of for loop to be a builtin integer type, but it's %s.", s); - free(s); - goto for_fail; + if (translated_use) { + if (undeclared) { + previous_use_which_uses_i = use; + undeclared = false; + final_ident = translated_use; + } else { + char *s = cstr(i_str, i_len); + err_print(e->where, "Conflicting declarations for identifier %s.", s); + char *also = ""; + if (previous_use_which_uses_i) { + /* i was use'd twice */ + info_print(previous_use_which_uses_i->expr.where, "%s was imported by this use statement.", s); + also = "also "; + } else { + /* i was declared then used. */ + info_print(ident_decl_location(translated), "%s was declared here.", s); + } + free(s); + info_print(use->expr.where, "...and %simported by this use statement.", also); + return false; + } + if (was_a_struct) { + /* change to BINARY_DOT */ + e->kind = EXPR_BINARY_OP; + e->flags = 0; + e->binary.op = BINARY_DOT; + e->binary.lhs = used; + e->binary.rhs = typer_calloc(tr, 1, sizeof *e->binary.rhs); + e->binary.rhs->kind = EXPR_IDENT; + e->binary.rhs->flags = 0; + e->binary.rhs->ident_str.str = i_str; + e->binary.rhs->ident_str.len = i_len; + /* re-type */ + if (!types_expr(tr, e)) + return false; + return true; + } } + } + if (!undeclared) break; + if (b) { + b = b->parent; } else { - *val_type = header->type; + break; } } - Type *fo_type = &header->type; - fo_type->flags = TYPE_IS_RESOLVED; - fo_type->kind = TYPE_TUPLE; - fo_type->tuple = fo_type_tuple; - - assert(fo_type->flags & TYPE_IS_RESOLVED); - - if (!index_type->flags) { - construct_resolved_builtin_type(index_type, BUILTIN_I64); + if (undeclared) { + char *s = cstr(e->ident_str.str, e->ident_str.len); + err_print(e->where, "Undeclared identifier '%s'.", s); + free(s); + return false; } - - if (is_range) { - if (!types_expr(tr, fo->range.from)) goto for_fail; - { - Type *ft = &fo->range.from->type; - - if (ft->kind != TYPE_BUILTIN || !type_builtin_is_numerical(ft->builtin)) { - char *s = type_to_str(ft); - err_print(e->where, "from expression of for loop must be a builtin numerical type, not %s", s); - free(s); - goto for_fail; - } + if (b && b->kind == BLOCK_STRUCT) { + /* this is really necessary if you're trying to access a struct constant from inside a function in the same struct */ + e->kind = EXPR_VAL; + Declaration *decl = final_ident->decl; + if (!(decl->flags & DECL_IS_CONST)) { + /* not sure if this can even happen right now, but might as well have this check here */ + err_print(e->where, "Trying to access non-constant struct member from inside of it. This is not allowed."); + return false; } - if (fo->range.step) { - if (!types_expr(tr, fo->range.step)) goto for_fail; - Type *st = &fo->range.step->type; - if (st->kind != TYPE_BUILTIN || !type_builtin_is_numerical(st->builtin)) { - char *s = type_to_str(st); - err_print(e->where, "step expression of for loop must be a builtin numerical type, not %s", s); - free(s); - goto for_fail; + assert(decl->flags & DECL_FOUND_VAL); + int idx = decl_ident_index(decl, final_ident); + e->val = *decl_val_at_index(decl, idx); + e->type = *decl_type_at_index(decl, idx); + break; + } + e->ident = final_ident; + if (!type_of_ident(tr, e->where, e->ident, t)) { + return false; + } + } break; + case EXPR_CAST: { + CastExpr *c = &e->cast; + if (!types_expr(tr, c->expr)) + return false; + if (!type_resolve(tr, &c->type, e->where)) + return false; + CastStatus status = type_cast_status(&c->expr->type, &c->type); + if (status != CAST_STATUS_NONE) { + char *from = type_to_str(&c->expr->type); + char *to = type_to_str(&c->type); + if (status == CAST_STATUS_ERR) + + err_print(e->where, "Cannot cast from type %s to %s.", from, to); + else + warn_print(e->where, "Casting from type %s to %s.", from, to); + free(from); + free(to); + if (status == CAST_STATUS_ERR) + return false; + } + *t = c->type; + } break; + case EXPR_CALL: { + CallExpr *c = &e->call; + c->instance = NULL; + Expression *f = c->fn; + FnExpr *fn_decl = NULL; + if (!types_expr(tr, f)) return false; + arr_foreach(c->args, Argument, arg) { + if (!types_expr(tr, &arg->val)) + return false; + } + if (f->type.kind == TYPE_UNKNOWN) { + e->type.kind = TYPE_UNKNOWN; + return true; + } + if (type_is_builtin(&f->type, BUILTIN_TYPE)) { + /* maybe it's a parameterized type */ + } else if (f->type.kind != TYPE_FN) { + char *type = type_to_str(&f->type); + err_print(e->where, "Calling non-function (type %s).", type); + return false; + } + bool has_varargs = f->type.kind == TYPE_FN && fn_type_has_varargs(&f->type.fn); + + if (expr_is_definitely_const(f) || type_is_builtin(&f->type, BUILTIN_TYPE) || has_varargs) { + Value val; + + if (!eval_expr(tr->evalr, f, &val)) + return false; + if (type_is_builtin(&f->type, BUILTIN_TYPE)) { + Type *base = val.type; + if (base->kind != TYPE_STRUCT) { + err_print(e->where, "Cannot pass arguments to non-struct type."); + return false; } - } - if (fo->range.to) { - if (!types_expr(tr, fo->range.to)) goto for_fail; - Type *tt = &fo->range.to->type; - if (tt->kind != TYPE_BUILTIN || !type_builtin_is_numerical(tt->builtin)) { - char *s = type_to_str(tt); - err_print(e->where, "to expression of for loop must be a builtin numerical type, not %s", s); - free(s); - goto for_fail; - } - } - - if (val_type->flags) { - if (type_eq_implicit(&fo->range.from->type, val_type)) { - *val_type = *overriding_type(&fo->range.from->type, val_type); - } else { - char *exp = type_to_str(val_type); - char *got = type_to_str(&fo->range.from->type); - err_print(e->where, "Type of from expression does not match type of for loop. Expected %s, but got %s.", exp, got); - free(exp); free(got); - goto for_fail; - } - } else { - *val_type = fo->range.from->type; - } - - if (fo->range.step) { - if (type_eq_implicit(&fo->range.step->type, val_type)) { - *val_type = *overriding_type(&fo->range.step->type, val_type); - } else { - char *exp = type_to_str(val_type); - char *got = type_to_str(&fo->range.step->type); - err_print(e->where, "Type of step expression does not match type of for loop. Expected %s, but got %s.", exp, got); - free(exp); free(got); - goto for_fail; - } - } - - if (fo->range.to) { - if (type_eq_implicit(&fo->range.to->type, val_type)) { - *val_type = *overriding_type(&fo->range.to->type, val_type); - } else { - char *exp = type_to_str(val_type); - char *got = type_to_str(&fo->range.to->type); - err_print(e->where, "Type of to expression does not match type of for loop. Expected %s, but got %s.", exp, got); - free(exp); free(got); - goto for_fail; - } - } - - val_type->flags &= (TypeFlags)~(TypeFlags)TYPE_IS_FLEXIBLE; - - if (fo->range.step) { - /* we can't put this above because *val_type might have changed. */ - Value *stepval = typer_malloc(tr, sizeof *fo->range.stepval); - if (!eval_expr(tr->evalr, fo->range.step, stepval)) { - info_print(fo->range.step->where, "Note that the step of a for loop must be a compile-time constant."); - goto for_fail; - } - val_cast(stepval, &fo->range.step->type, stepval, val_type); - fo->range.stepval = stepval; - } - } else { - if (!types_expr(tr, fo->of)) - goto for_fail; - - Type *iter_type = &fo->of->type; - - bool uses_ptr = false; - if (iter_type->kind == TYPE_PTR) { - uses_ptr = true; - iter_type = iter_type->ptr; - } - switch (iter_type->kind) { - case TYPE_SLICE: - iter_type = iter_type->slice; - break; - case TYPE_ARR: - iter_type = iter_type->arr.of; - break; - case TYPE_BUILTIN: - switch (iter_type->builtin) { - case BUILTIN_VARARGS: { - /* exit for body */ - typer_block_exit(tr); - arr_remove_lasta(tr->in_decls, tr->allocr); - /* create one block, containing a block for each vararg */ - /* e.g. for x := varargs { total += x; } => { { x := varargs[0]; total += x; } { x := varargs[0]; total += x; } } */ - assert(fo->of->kind == EXPR_IDENT); - Identifier varargs_ident = fo->of->ident; - Declaration *idecl = varargs_ident->decl; - VarArg *varargs = idecl->val.varargs; - size_t nvarargs = arr_len(varargs); - /* create surrounding block */ - e->kind = EXPR_BLOCK; - Block *b = e->block = typer_calloc(tr, 1, sizeof *e->block); - idents_create(&b->idents, tr->allocr, b); - b->stmts = NULL; - b->parent = tr->block; - b->where = e->where; - arr_set_lena(b->stmts, nvarargs, tr->allocr); - Statement *stmt = b->stmts; - size_t nstmts = arr_len(fo->body.stmts); - Declaration *header_decl = &fo->header; - - assert(arr_len(header_decl->idents) == 2); - Identifier val_ident = header_decl->idents[0]; - Identifier index_ident = header_decl->idents[1]; - bool has_val = !ident_eq_str(val_ident, "_"); - bool has_index = !ident_eq_str(index_ident, "_"); - - for (size_t i = 0; i < nvarargs; ++i, ++stmt) { - /* create sub-block #i */ - memset(stmt, 0, sizeof *stmt); - stmt->kind = STMT_EXPR; - stmt->expr = typer_calloc(tr, 1, sizeof *stmt->expr); - stmt->expr->kind = EXPR_BLOCK; - Block *sub = stmt->expr->block = typer_calloc(tr, 1, sizeof *sub); - sub->parent = b; - idents_create(&sub->idents, tr->allocr, sub); - sub->stmts = NULL; - sub->where = e->where; - size_t total_nstmts = nstmts + has_val + has_index; - arr_set_lena(sub->stmts, total_nstmts, tr->allocr); - Copier copier = copier_create(tr->allocr, sub); - if (has_val) { - /* @TODO(eventually): don't put a decl in each block, just put one at the start */ - Statement *s = &sub->stmts[0]; - s->flags = 0; - s->kind = STMT_DECL; - s->where = e->where; - - /* declare value */ - Declaration *decl = s->decl = typer_calloc(tr, 1, sizeof *decl); - decl->where = fo->of->where; - Identifier ident = ident_translate_forced(val_ident, &sub->idents); - typer_arr_add(tr, decl->idents, ident); - ident->decl = decl; - - decl->flags |= DECL_HAS_EXPR; - decl->expr.kind = EXPR_BINARY_OP; - decl->expr.binary.op = BINARY_AT_INDEX; - decl->expr.binary.lhs = fo->of; - decl->expr.where = fo->of->where; - Expression *index = decl->expr.binary.rhs = typer_calloc(tr, 1, sizeof *decl->expr.binary.rhs); - index->kind = EXPR_LITERAL_INT; - index->intl = (U64)i; - index->where = fo->of->where; - } - if (has_index) { - /* @TODO(eventually): don't put a decl in each block, just put one at the start */ - Statement *s = &sub->stmts[has_val]; - s->flags = 0; - s->kind = STMT_DECL; - s->where = e->where; - - /* declare value */ - Declaration *decl = s->decl = typer_calloc(tr, 1, sizeof *decl); - decl->where = fo->of->where; - Identifier ident = ident_translate_forced(index_ident, &sub->idents); - typer_arr_add(tr, decl->idents, ident); - ident->decl = decl; - - decl->flags |= DECL_HAS_EXPR; - decl->expr.kind = EXPR_LITERAL_INT; - decl->expr.intl = (U64)i; - decl->expr.where = fo->of->where; - } - - size_t start = total_nstmts - nstmts; - for (size_t s = start; s < total_nstmts; ++s) { - copy_stmt(&copier, &sub->stmts[s], &fo->body.stmts[s-start]); - } - } - e->flags &= (ExprFlags)~(ExprFlags)EXPR_FOUND_TYPE; - /* type this new big block */ - if (!types_expr(tr, e)) - return false; - return true; - } - default: break; - } - /* fallthrough */ - default: { - if (fo->of->type.kind == TYPE_UNKNOWN && tr->err_ctx->have_errored) { - /* silently fail */ - goto for_fail; - } - char *s = type_to_str(&fo->of->type); - err_print(e->where, "Cannot iterate over non-array non-slice type %s.", s); - free(s); - goto for_fail; - } - } - Type *ptr_type = typer_calloc(tr, 1, sizeof *ptr_type); - if (uses_ptr) { - ptr_type->flags = TYPE_IS_RESOLVED; - ptr_type->kind = TYPE_PTR; - ptr_type->ptr = iter_type; - iter_type = ptr_type; - } - if (header->flags & DECL_ANNOTATES_TYPE) { - if (type_eq_implicit(iter_type, val_type)) { - *val_type = *overriding_type(iter_type, val_type); - } else { - char *exp = type_to_str(iter_type); - char *got = type_to_str(val_type); - err_print(e->where, "Expected to iterate over type %s, but it was annotated as iterating over type %s.", exp, got); - free(exp); free(got); - goto for_fail; - } - } else *val_type = *iter_type; - } - - arr_remove_lasta(tr->in_decls, tr->allocr); - in_header = false; - - assert(header->type.flags & TYPE_IS_RESOLVED); - assert(index_type->flags & TYPE_IS_RESOLVED); - assert(val_type->flags & TYPE_IS_RESOLVED); - - header->flags |= DECL_FOUND_TYPE; - - if (header->flags & DECL_USE) { - if (ident_eq_str(header->idents[0], "_")) { - err_print(header->where, "You have to name your for loop variable in order to use it (sorry)."); - return false; - } - if (!use_ident(tr, header->idents[0], val_type, header->where)) { - return false; - } - } - - if (!types_block(tr, &fo->body)) goto for_fail; - - t->kind = TYPE_BUILTIN; - t->builtin = BUILTIN_VOID; - - typer_block_exit(tr); - } break; - for_fail: - if (in_header) - arr_remove_lasta(tr->in_decls, tr->allocr); - typer_block_exit(tr); - return false; - } - case EXPR_IDENT: { - Block *b = tr->block; - String i = e->ident_str; - char *i_str = i.str; - size_t i_len = i.len; - if (str_eq_cstr(i, "_")) { - err_print(e->where, "You cannot use _ as a variable. It is used for ignoring results of function calls, e.g. _, y := function_which_returns_two_things();"); - return false; - } - Identifier final_ident = NULL; - bool undeclared = true; - while (1) { /* for each block we are inside... */ - /* @OPTIM: only hash once */ - Identifier translated = ident_get_with_len(b ? &b->idents : tr->globals, i_str, i_len); - if (translated) { -#if 0 - printf("translated %s from\n", ident_to_str(i)); - print_block_location(i->idents->body); - printf(" to \n"); - print_block_location(translated->idents->body); -#endif - final_ident = translated; - undeclared = false; - } - Use **uses = b ? b->uses : tr->uses; - - Use *previous_use_which_uses_i = NULL; - arr_foreach(uses, UsePtr, usep) { - Use *use = *usep; - Expression *used = &use->expr; - Identifier translated_use; - bool was_a_struct = false; - if (type_is_builtin(&used->type, BUILTIN_NMS)) { - Value val; - if (!eval_expr(tr->evalr, used, &val)) - return 0; - Namespace *nms = val.nms; - Block *body = &nms->body; - /* look up identifier in namespace */ - translated_use = ident_get_with_len(&body->idents, i_str, i_len); - } else { - /* it's a struct */ - was_a_struct = true; - Type *struct_type = &used->type; - if (struct_type->kind == TYPE_PTR) - struct_type = struct_type->ptr; - assert(struct_type->kind == TYPE_STRUCT); - StructDef *struc = struct_type->struc; - translated_use = ident_get_with_len(&struc->body.idents, i_str, i_len); - } - if (translated_use) { - if (undeclared) { - previous_use_which_uses_i = use; - undeclared = false; - final_ident = translated_use; - } else { - char *s = cstr(i_str, i_len); - err_print(e->where, "Conflicting declarations for identifier %s.", s); - char *also = ""; - if (previous_use_which_uses_i) { - /* i was use'd twice */ - info_print(previous_use_which_uses_i->expr.where, "%s was imported by this use statement.", s); - also = "also "; - } else { - /* i was declared then used. */ - info_print(ident_decl_location(translated), "%s was declared here.", s); - } - free(s); - info_print(use->expr.where, "...and %simported by this use statement.", also); - return false; - } - if (was_a_struct) { - /* change to BINARY_DOT */ - e->kind = EXPR_BINARY_OP; - e->flags = 0; - e->binary.op = BINARY_DOT; - e->binary.lhs = used; - e->binary.rhs = typer_calloc(tr, 1, sizeof *e->binary.rhs); - e->binary.rhs->kind = EXPR_IDENT; - e->binary.rhs->flags = 0; - e->binary.rhs->ident_str.str = i_str; - e->binary.rhs->ident_str.len = i_len; - /* re-type */ - if (!types_expr(tr, e)) - return false; - return true; - } - } - } - if (!undeclared) break; - if (b) { - b = b->parent; - } else { - break; - } - } - if (undeclared) { - char *s = cstr(e->ident_str.str, e->ident_str.len); - err_print(e->where, "Undeclared identifier '%s'.", s); - free(s); - return false; - } - if (b && b->kind == BLOCK_STRUCT) { - /* this is really necessary if you're trying to access a struct constant from inside a function in the same struct */ - e->kind = EXPR_VAL; - Declaration *decl = final_ident->decl; - if (!(decl->flags & DECL_IS_CONST)) { - /* not sure if this can even happen right now, but might as well have this check here */ - err_print(e->where, "Trying to access non-constant struct member from inside of it. This is not allowed."); - return false; - } - assert(decl->flags & DECL_FOUND_VAL); - int idx = decl_ident_index(decl, final_ident); - e->val = *decl_val_at_index(decl, idx); - e->type = *decl_type_at_index(decl, idx); - break; - } - e->ident = final_ident; - if (!type_of_ident(tr, e->where, e->ident, t)) { - return false; - } - } break; - case EXPR_CAST: { - CastExpr *c = &e->cast; - if (!types_expr(tr, c->expr)) - return false; - if (!type_resolve(tr, &c->type, e->where)) - return false; - CastStatus status = type_cast_status(&c->expr->type, &c->type); - if (status != CAST_STATUS_NONE) { - char *from = type_to_str(&c->expr->type); - char *to = type_to_str(&c->type); - if (status == CAST_STATUS_ERR) - - err_print(e->where, "Cannot cast from type %s to %s.", from, to); - else - warn_print(e->where, "Casting from type %s to %s.", from, to); - free(from); - free(to); - if (status == CAST_STATUS_ERR) - return false; - } - *t = c->type; - } break; - case EXPR_IF: { - IfExpr *i = e->if_; - IfExpr *curr = i; - if (curr->flags & IF_STATIC) { - /* handled in types_stmt unless there's a problem */ - err_print(e->where, "You can't use #if in this way. It has to be a statement on its own, and can't return a value."); - return false; - } - if (!types_block(tr, &curr->body)) - return false; - { - t->kind = TYPE_BUILTIN; t->builtin = BUILTIN_VOID; - t->flags |= TYPE_IS_RESOLVED; - } - while (1) { - if (curr->cond) { - if (!types_expr(tr, curr->cond)) - return false; - if (!type_can_be_truthy(&curr->cond->type)) { - char *s = type_to_str(&curr->cond->type); - err_print(curr->cond->where, "Type %s cannot be the condition of an if statement.", s); - free(s); - return false; - } - } - if (curr->next_elif) { - IfExpr *nexti = curr->next_elif->if_; - Type *next_type = &curr->next_elif->type; - curr->next_elif->flags |= EXPR_FOUND_TYPE; - if (!types_block(tr, &nexti->body)) { - return false; - } - { - next_type->kind = TYPE_BUILTIN; next_type->builtin = BUILTIN_VOID; - next_type->flags = TYPE_IS_RESOLVED; - } - curr = nexti; - } else { - break; - } - } - } break; - case EXPR_WHILE: { - WhileExpr *w = e->while_; - bool ret = true; - if (!types_expr(tr, w->cond)) - ret = false; - if (!types_block(tr, &w->body)) - ret = false; - if (!ret) return false; - t->kind = TYPE_BUILTIN; - t->builtin = BUILTIN_VOID; - } break; - case EXPR_CALL: { - CallExpr *c = &e->call; - c->instance = NULL; - Expression *f = c->fn; - FnExpr *fn_decl = NULL; - if (!types_expr(tr, f)) return false; - arr_foreach(c->args, Argument, arg) { - if (!types_expr(tr, &arg->val)) - return false; - } - if (f->type.kind == TYPE_UNKNOWN) { - e->type.kind = TYPE_UNKNOWN; - return true; - } - if (type_is_builtin(&f->type, BUILTIN_TYPE)) { - /* maybe it's a parameterized type */ - } else if (f->type.kind != TYPE_FN) { - char *type = type_to_str(&f->type); - err_print(e->where, "Calling non-function (type %s).", type); - return false; - } - bool has_varargs = f->type.kind == TYPE_FN && fn_type_has_varargs(&f->type.fn); - - if (expr_is_definitely_const(f) || type_is_builtin(&f->type, BUILTIN_TYPE) || has_varargs) { - Value val; - - if (!eval_expr(tr->evalr, f, &val)) - return false; - if (type_is_builtin(&f->type, BUILTIN_TYPE)) { - Type *base = val.type; - if (base->kind != TYPE_STRUCT) { - err_print(e->where, "Cannot pass arguments to non-struct type."); - return false; - } - if (!base->struc->params) { - err_print(e->where, "Passing arguments to struct, but it doesn't take any."); - info_print(base->struc->where, "struct was declared here."); - return false; + if (!base->struc->params) { + err_print(e->where, "Passing arguments to struct, but it doesn't take any."); + info_print(base->struc->where, "struct was declared here."); + return false; } Copier cop = copier_create(tr->allocr, base->struc->body.parent); HashTable *table = &base->struc->instances; @@ -2759,13 +2385,6 @@ static Status types_expr(Typer *tr, Expression *e) { free(order); *t = *ret_type; } break; - case EXPR_BLOCK: { - Block *b = e->block; - if (!types_block(tr, b)) - return false; - t->kind = TYPE_BUILTIN; - t->builtin = BUILTIN_VOID; - } break; case EXPR_C: { Expression *code = e->c.code; if (!types_expr(tr, code)) @@ -3546,94 +3165,448 @@ static Status types_decl(Typer *tr, Declaration *d) { return false; } - if (tr->nms && tr->block == &tr->nms->body) { - arr_foreach(d->idents, Identifier, ident) { - (*ident)->nms = tr->nms; - } - } + if (tr->nms && tr->block == &tr->nms->body) { + arr_foreach(d->idents, Identifier, ident) { + (*ident)->nms = tr->nms; + } + } + + if (d->flags & DECL_EXPORT) { + if (d->expr.kind == EXPR_FN) + d->expr.fn->flags |= FN_EXPR_EXPORT; + } + + if (is_at_top_level(tr)) { + DeclWithCtx dctx = {d, tr->nms, tr->block}; + typer_arr_add(tr, tr->all_globals, dctx); + } + + ret: + /* pretend we found the type even if we didn't to prevent too many errors */ + d->flags |= DECL_FOUND_TYPE; + if (!success) { + /* use unknown type if we didn't get the type */ + dtype->flags = TYPE_IS_RESOLVED; + dtype->kind = TYPE_UNKNOWN; + } + arr_remove_lasta(tr->in_decls, tr->allocr); + return success; +} + +static Status fix_ident_decls_inline_block(Typer *tr, Statement *stmts) { + Identifiers *idents = typer_get_idents(tr); + arr_foreach(stmts, Statement, s) { + assert(!(s->flags & STMT_TYPED)); + if (s->kind == STMT_DECL) { + Declaration *d = s->decl; + arr_foreach(d->idents, Identifier, ident) { + Identifier i = *ident = ident_translate_forced(*ident, idents); + if (i->decl) { + char *istr = ident_to_str(i); + err_print(d->where, "Redeclaration of identifier %s.", istr); + info_print(i->decl->where, "%s was also declared here.", istr); + free(istr); + return false; + } + i->decl = d; + } + } + } + return true; +} + +/* introduce identifiers from stmts into current scope, setting their "nms" field to nms */ +static Status include_stmts_link_to_nms(Typer *tr, Namespace *nms, Statement *stmts) { + Identifiers *idents = typer_get_idents(tr); + arr_foreach(stmts, Statement, s) { + if (s->kind == STMT_INLINE_BLOCK) { + if (!include_stmts_link_to_nms(tr, nms, s->inline_block)) + return false; + } else if (s->kind == STMT_DECL) { + Declaration *d = s->decl; + arr_foreach(d->idents, Identifier, ident) { + /* @OPTIM: only hash once */ + Identifier preexisting = ident_translate(*ident, idents); + if (preexisting && preexisting->decl != d) { + char *istr = ident_to_str(preexisting); + err_print(d->where, "Redeclaration of identifier %s.", istr); + info_print(preexisting->decl->where, "%s was first declared here.", istr); + free(istr); + } + Identifier i = ident_translate_forced(*ident, idents); + i->nms = nms; + i->decl = d; + } + } + } + return true; +} + +static Status types_stmt(Typer *tr, Statement *s) { +top: + if (s->flags & STMT_TYPED) return true; + switch (s->kind) { + case STMT_EXPR: { + Expression *e = s->expr; + if (!types_expr(tr, e)) { + return false; + } + + { + if (e->kind == EXPR_TUPLE) { + err_print(s->where, "Statement of a tuple is not allowed. Use a semicolon instead of a comma here."); + return false; + } + Type *t = &e->type; + if (type_is_compileonly(t)) { + char *str = type_to_str(t); + warn_print(s->where, "This expression has a compile-only type (%s), so this statement will not actually be outputted in C code.", str); + free(str); + } + } + if (tr->block == NULL) { + /* evaluate expression statements at global scope */ + if (e->kind != EXPR_C) { + if (!eval_stmt(tr->evalr, s)) + return false; + } + } + } break; + + case STMT_FOR: { + bool in_header = true;{ /* additional block because c++ */ + For *fo = s->for_; + Declaration *header = &fo->header; + U32 is_range = fo->flags & FOR_IS_RANGE; + typer_arr_add(tr, tr->in_decls, header); + fo->body.uses = NULL; + typer_block_enter(tr, &fo->body); + bool annotated_index = true; + { + size_t nidents = arr_len(header->idents); + if (nidents > 2) { + err_print(header->where, "Expected at most 2 identifiers in for declaration (index and value) but got %lu.", + (unsigned long)nidents); + goto for_fail; + } + if (nidents < 2) { + annotated_index = false; + assert(nidents == 1); + /* turn value := arr to value, _ := arr to simplify things */ + typer_arr_add(tr, header->idents, ident_insert_with_len(typer_get_idents(tr), "_", 1)); + } + } + + Type *fo_type_tuple = NULL; + /* fo_type is (val_type, index_type) */ + arr_set_lena(fo_type_tuple, 2, tr->allocr); + memset(fo_type_tuple, 0, 2*sizeof *fo_type_tuple); + Type *val_type = &fo_type_tuple[0]; + Type *index_type = &fo_type_tuple[1]; + + if (header->flags & DECL_ANNOTATES_TYPE) { + Type *header_type = &header->type; + if (!type_resolve(tr, header_type, header->where)) + goto for_fail; + if (annotated_index) { + if (header_type->kind != TYPE_TUPLE || arr_len(header_type->tuple) != 2) { + char *str = type_to_str(header_type); + err_print(header->where, "Expected annotated for loop type to be (val_type, index_type), but got %s instead.", str); + free(str); + goto for_fail; + } + fo_type_tuple = header_type->tuple; + val_type = &fo_type_tuple[0]; + index_type = &fo_type_tuple[1]; + assert(val_type->flags & TYPE_IS_RESOLVED); + assert(index_type->flags & TYPE_IS_RESOLVED); + if (!type_is_int(index_type)) { + char *str = type_to_str(index_type); + err_print(header->where, "Expected index type of for loop to be a builtin integer type, but it's %s.", str); + free(s); + goto for_fail; + } + } else { + *val_type = header->type; + } + } + Type *fo_type = &header->type; + fo_type->flags = TYPE_IS_RESOLVED; + fo_type->kind = TYPE_TUPLE; + fo_type->tuple = fo_type_tuple; + + assert(fo_type->flags & TYPE_IS_RESOLVED); + + if (!index_type->flags) { + construct_resolved_builtin_type(index_type, BUILTIN_I64); + } + + if (is_range) { + if (!types_expr(tr, fo->range.from)) goto for_fail; + { + Type *ft = &fo->range.from->type; + + if (ft->kind != TYPE_BUILTIN || !type_builtin_is_numerical(ft->builtin)) { + char *str = type_to_str(ft); + err_print(s->where, "from expression of for loop must be a builtin numerical type, not %s", str); + free(str); + goto for_fail; + } + } + if (fo->range.step) { + if (!types_expr(tr, fo->range.step)) goto for_fail; + Type *st = &fo->range.step->type; + if (st->kind != TYPE_BUILTIN || !type_builtin_is_numerical(st->builtin)) { + char *str = type_to_str(st); + err_print(s->where, "step expression of for loop must be a builtin numerical type, not %s", str); + free(str); + goto for_fail; + } + } + if (fo->range.to) { + if (!types_expr(tr, fo->range.to)) goto for_fail; + Type *tt = &fo->range.to->type; + if (tt->kind != TYPE_BUILTIN || !type_builtin_is_numerical(tt->builtin)) { + char *str = type_to_str(tt); + err_print(s->where, "to expression of for loop must be a builtin numerical type, not %s", str); + free(str); + goto for_fail; + } + } + + if (val_type->flags) { + if (type_eq_implicit(&fo->range.from->type, val_type)) { + *val_type = *overriding_type(&fo->range.from->type, val_type); + } else { + char *exp = type_to_str(val_type); + char *got = type_to_str(&fo->range.from->type); + err_print(s->where, "Type of from expression does not match type of for loop. Expected %s, but got %s.", exp, got); + free(exp); free(got); + goto for_fail; + } + } else { + *val_type = fo->range.from->type; + } + + if (fo->range.step) { + if (type_eq_implicit(&fo->range.step->type, val_type)) { + *val_type = *overriding_type(&fo->range.step->type, val_type); + } else { + char *exp = type_to_str(val_type); + char *got = type_to_str(&fo->range.step->type); + err_print(s->where, "Type of step expression does not match type of for loop. Expected %s, but got %s.", exp, got); + free(exp); free(got); + goto for_fail; + } + } + + if (fo->range.to) { + if (type_eq_implicit(&fo->range.to->type, val_type)) { + *val_type = *overriding_type(&fo->range.to->type, val_type); + } else { + char *exp = type_to_str(val_type); + char *got = type_to_str(&fo->range.to->type); + err_print(s->where, "Type of to expression does not match type of for loop. Expected %s, but got %s.", exp, got); + free(exp); free(got); + goto for_fail; + } + } + + val_type->flags &= (TypeFlags)~(TypeFlags)TYPE_IS_FLEXIBLE; + + if (fo->range.step) { + /* we can't put this above because *val_type might have changed. */ + Value *stepval = typer_malloc(tr, sizeof *fo->range.stepval); + if (!eval_expr(tr->evalr, fo->range.step, stepval)) { + info_print(fo->range.step->where, "Note that the step of a for loop must be a compile-time constant."); + goto for_fail; + } + val_cast(stepval, &fo->range.step->type, stepval, val_type); + fo->range.stepval = stepval; + } + } else { + if (!types_expr(tr, fo->of)) + goto for_fail; + + Type *iter_type = &fo->of->type; - if (d->flags & DECL_EXPORT) { - if (d->expr.kind == EXPR_FN) - d->expr.fn->flags |= FN_EXPR_EXPORT; - } + bool uses_ptr = false; + if (iter_type->kind == TYPE_PTR) { + uses_ptr = true; + iter_type = iter_type->ptr; + } + switch (iter_type->kind) { + case TYPE_SLICE: + iter_type = iter_type->slice; + break; + case TYPE_ARR: + iter_type = iter_type->arr.of; + break; + case TYPE_BUILTIN: + switch (iter_type->builtin) { + case BUILTIN_VARARGS: { + /* exit for body */ + typer_block_exit(tr); + arr_remove_lasta(tr->in_decls, tr->allocr); + /* create one block, containing a block for each vararg */ + /* e.g. for x := varargs { total += x; } => { { x := varargs[0]; total += x; } { x := varargs[0]; total += x; } } */ + assert(fo->of->kind == EXPR_IDENT); + Identifier varargs_ident = fo->of->ident; + Declaration *idecl = varargs_ident->decl; + VarArg *varargs = idecl->val.varargs; + size_t nvarargs = arr_len(varargs); + /* create surrounding block */ + s->kind = STMT_BLOCK; + Block *b = s->block = typer_calloc(tr, 1, sizeof *s->block); + idents_create(&b->idents, tr->allocr, b); + b->stmts = NULL; + b->parent = tr->block; + b->where = s->where; + arr_set_lena(b->stmts, nvarargs, tr->allocr); + Statement *stmt = b->stmts; + size_t nstmts = arr_len(fo->body.stmts); + Declaration *header_decl = &fo->header; + + assert(arr_len(header_decl->idents) == 2); + Identifier val_ident = header_decl->idents[0]; + Identifier index_ident = header_decl->idents[1]; + bool has_val = !ident_eq_str(val_ident, "_"); + bool has_index = !ident_eq_str(index_ident, "_"); + + for (size_t i = 0; i < nvarargs; ++i, ++stmt) { + /* create sub-block #i */ + memset(stmt, 0, sizeof *stmt); + stmt->kind = STMT_BLOCK; + Block *sub = stmt->block = typer_calloc(tr, 1, sizeof *sub); + sub->parent = b; + idents_create(&sub->idents, tr->allocr, sub); + sub->stmts = NULL; + sub->where = s->where; + size_t total_nstmts = nstmts + has_val + has_index; + arr_set_lena(sub->stmts, total_nstmts, tr->allocr); + Copier copier = copier_create(tr->allocr, sub); + if (has_val) { + /* @TODO(eventually): don't put a decl in each block, just put one at the start */ + Statement *decl_stmt = &sub->stmts[0]; + decl_stmt->flags = 0; + decl_stmt->kind = STMT_DECL; + decl_stmt->where = s->where; - if (is_at_top_level(tr)) { - DeclWithCtx dctx = {d, tr->nms, tr->block}; - typer_arr_add(tr, tr->all_globals, dctx); - } - - ret: - /* pretend we found the type even if we didn't to prevent too many errors */ - d->flags |= DECL_FOUND_TYPE; - if (!success) { - /* use unknown type if we didn't get the type */ - dtype->flags = TYPE_IS_RESOLVED; - dtype->kind = TYPE_UNKNOWN; - } - arr_remove_lasta(tr->in_decls, tr->allocr); - return success; -} + /* declare value */ + Declaration *decl = decl_stmt->decl = typer_calloc(tr, 1, sizeof *decl); + decl->where = fo->of->where; + Identifier ident = ident_translate_forced(val_ident, &sub->idents); + typer_arr_add(tr, decl->idents, ident); + ident->decl = decl; + + decl->flags |= DECL_HAS_EXPR; + decl->expr.kind = EXPR_BINARY_OP; + decl->expr.binary.op = BINARY_AT_INDEX; + decl->expr.binary.lhs = fo->of; + decl->expr.where = fo->of->where; + Expression *index = decl->expr.binary.rhs = typer_calloc(tr, 1, sizeof *decl->expr.binary.rhs); + index->kind = EXPR_LITERAL_INT; + index->intl = (U64)i; + index->where = fo->of->where; + } + if (has_index) { + /* @TODO(eventually): don't put a decl in each block, just put one at the start */ + Statement *decl_stmt = &sub->stmts[has_val]; + decl_stmt->flags = 0; + decl_stmt->kind = STMT_DECL; + decl_stmt->where = s->where; -static Status fix_ident_decls_inline_block(Typer *tr, Statement *stmts) { - Identifiers *idents = typer_get_idents(tr); - arr_foreach(stmts, Statement, s) { - assert(!(s->flags & STMT_TYPED)); - if (s->kind == STMT_DECL) { - Declaration *d = s->decl; - arr_foreach(d->idents, Identifier, ident) { - Identifier i = *ident = ident_translate_forced(*ident, idents); - if (i->decl) { - char *istr = ident_to_str(i); - err_print(d->where, "Redeclaration of identifier %s.", istr); - info_print(i->decl->where, "%s was also declared here.", istr); - free(istr); - return false; + /* declare value */ + Declaration *decl = decl_stmt->decl = typer_calloc(tr, 1, sizeof *decl); + decl->where = fo->of->where; + Identifier ident = ident_translate_forced(index_ident, &sub->idents); + typer_arr_add(tr, decl->idents, ident); + ident->decl = decl; + + decl->flags |= DECL_HAS_EXPR; + decl->expr.kind = EXPR_LITERAL_INT; + decl->expr.intl = (U64)i; + decl->expr.where = fo->of->where; + } + + size_t start = total_nstmts - nstmts; + for (size_t idx = start; idx < total_nstmts; ++idx) { + copy_stmt(&copier, &sub->stmts[idx], &fo->body.stmts[idx-start]); + } + } + goto top; } - i->decl = d; + default: break; + } + /* fallthrough */ + default: { + if (fo->of->type.kind == TYPE_UNKNOWN && tr->err_ctx->have_errored) { + /* silently fail */ + goto for_fail; + } + char *str = type_to_str(&fo->of->type); + err_print(s->where, "Cannot iterate over non-array non-slice type %s.", str); + free(str); + goto for_fail; + } + } + Type *ptr_type = typer_calloc(tr, 1, sizeof *ptr_type); + if (uses_ptr) { + ptr_type->flags = TYPE_IS_RESOLVED; + ptr_type->kind = TYPE_PTR; + ptr_type->ptr = iter_type; + iter_type = ptr_type; } + if (header->flags & DECL_ANNOTATES_TYPE) { + if (type_eq_implicit(iter_type, val_type)) { + *val_type = *overriding_type(iter_type, val_type); + } else { + char *exp = type_to_str(iter_type); + char *got = type_to_str(val_type); + err_print(s->where, "Expected to iterate over type %s, but it was annotated as iterating over type %s.", exp, got); + free(exp); free(got); + goto for_fail; + } + } else *val_type = *iter_type; } - } - return true; -} + + arr_remove_lasta(tr->in_decls, tr->allocr); + in_header = false; + + assert(header->type.flags & TYPE_IS_RESOLVED); + assert(index_type->flags & TYPE_IS_RESOLVED); + assert(val_type->flags & TYPE_IS_RESOLVED); -/* introduce identifiers from stmts into current scope, setting their "nms" field to nms */ -static Status include_stmts_link_to_nms(Typer *tr, Namespace *nms, Statement *stmts) { - Identifiers *idents = typer_get_idents(tr); - arr_foreach(stmts, Statement, s) { - if (s->kind == STMT_INLINE_BLOCK) { - if (!include_stmts_link_to_nms(tr, nms, s->inline_block)) + header->flags |= DECL_FOUND_TYPE; + + if (header->flags & DECL_USE) { + if (ident_eq_str(header->idents[0], "_")) { + err_print(header->where, "You have to name your for loop variable in order to use it (sorry)."); + return false; + } + if (!use_ident(tr, header->idents[0], val_type, header->where)) { return false; - } else if (s->kind == STMT_DECL) { - Declaration *d = s->decl; - arr_foreach(d->idents, Identifier, ident) { - /* @OPTIM: only hash once */ - Identifier preexisting = ident_translate(*ident, idents); - if (preexisting && preexisting->decl != d) { - char *istr = ident_to_str(preexisting); - err_print(d->where, "Redeclaration of identifier %s.", istr); - info_print(preexisting->decl->where, "%s was first declared here.", istr); - free(istr); - } - Identifier i = ident_translate_forced(*ident, idents); - i->nms = nms; - i->decl = d; } } - } - return true; -} -static Status types_stmt(Typer *tr, Statement *s) { - if (s->flags & STMT_TYPED) return true; - switch (s->kind) { - case STMT_EXPR: { - Expression *e = s->expr; - if (e->kind == EXPR_IF && (e->if_->flags & IF_STATIC)) { + if (!types_block(tr, &fo->body)) goto for_fail; + + typer_block_exit(tr); + } break; + for_fail: + if (in_header) + arr_remove_lasta(tr->in_decls, tr->allocr); + typer_block_exit(tr); + return false; + } + case STMT_IF: { + If *i = s->if_; + If *curr = i; + if (curr->flags & IF_STATIC) { /* handle #if */ - IfExpr *curr = e->if_; while (1) { Expression *cond = curr->cond; - Expression *next = curr->next_elif; + If *next = curr->next_elif; Value v; if (cond) { if (!types_expr(tr, cond)) @@ -3663,9 +3636,9 @@ static Status types_stmt(Typer *tr, Statement *s) { goto success; } if (!next) break; - curr = next->if_; + curr = next; } - if (e->kind == EXPR_IF) { + if (s->kind == STMT_IF) { /* all conds were false */ /* empty inline block */ s->kind = STMT_INLINE_BLOCK; @@ -3674,31 +3647,45 @@ static Status types_stmt(Typer *tr, Statement *s) { break; } - if (!types_expr(tr, e)) { + if (!types_block(tr, &curr->body)) return false; - } - { - if (e->kind == EXPR_TUPLE) { - err_print(s->where, "Statement of a tuple is not allowed. Use a semicolon instead of a comma here."); - return false; - } - Type *t = &e->type; - if (type_is_compileonly(t)) { - char *str = type_to_str(t); - warn_print(s->where, "This expression has a compile-only type (%s), so this statement will not actually be outputted in C code.", str); - free(str); + while (1) { + if (curr->cond) { + if (!types_expr(tr, curr->cond)) + return false; + if (!type_can_be_truthy(&curr->cond->type)) { + char *str = type_to_str(&curr->cond->type); + err_print(curr->cond->where, "Type %s cannot be the condition of an if statement.", str); + free(str); + return false; + } } - } - - if (tr->block == NULL) { - /* evaluate expression statements at global scope */ - if (e->kind != EXPR_C) { - if (!eval_stmt(tr->evalr, s)) + if (curr->next_elif) { + If *nexti = curr->next_elif; + if (!types_block(tr, &nexti->body)) { return false; + } + curr = nexti; + } else { + break; } } } break; + case STMT_BLOCK: { + Block *b = s->block; + if (!types_block(tr, b)) + return false; + } break; + case STMT_WHILE: { + While *w = s->while_; + bool ret = true; + if (!types_expr(tr, w->cond)) + ret = false; + if (!types_block(tr, &w->body)) + ret = false; + if (!ret) return false; + } break; case STMT_DECL: if (!types_decl(tr, s->decl)) { return false; diff --git a/types.h b/types.h index 9fcea1a..ceedcea 100644 --- a/types.h +++ b/types.h @@ -523,6 +523,7 @@ typedef struct Block { struct Statement **deferred; /* deferred stuff from this block; used by both eval and cgen */ struct Use **uses; /* use statements (for types.c) */ } Block; + typedef Block *BlockPtr; enum { @@ -569,13 +570,9 @@ typedef enum { EXPR_IDENT, /* variable or constant */ EXPR_BINARY_OP, EXPR_UNARY_OP, - EXPR_IF, - EXPR_WHILE, - EXPR_FOR, EXPR_FN, EXPR_CAST, EXPR_CALL, - EXPR_BLOCK, EXPR_TUPLE, EXPR_C, EXPR_BUILTIN, @@ -635,22 +632,6 @@ typedef struct CallExpr { struct Instance *instance; /* NULL = ordinary function, no compile time args */ } CallExpr; -enum { - IF_STATIC = 0x01 -}; - -typedef struct IfExpr { - U8 flags; - struct Expression *cond; /* NULL = this is an else */ - struct Expression *next_elif; /* next elif/else of this statement */ - Block body; -} IfExpr; - -typedef struct WhileExpr { - struct Expression *cond; - Block body; -} WhileExpr; - typedef enum { CTYPE_NONE = 0x00, @@ -678,6 +659,11 @@ typedef struct { char *points_to; /* if kind == CTYPE_PTR, ident string of C type which it points to */ } CType; +enum { + FN_EXPR_FOREIGN = 0x01, + FN_EXPR_EXPORT = 0x02, /* set during typing */ + FN_EXPR_HAS_VARARGS = 0x04 +}; typedef struct FnExpr { Location where; Block *declaration_block; /* block wherein this function is declared */ @@ -824,9 +810,6 @@ typedef struct Expression { struct { Type type; } del; - IfExpr *if_; - WhileExpr *while_; - struct ForExpr *for_; FnExpr *fn; CastExpr cast; SliceExpr slice; @@ -892,44 +875,42 @@ typedef struct Declaration { typedef Declaration *DeclarationPtr; enum { - FOR_IS_RANGE = 0x01 + IF_STATIC = 0x01 }; + +typedef struct If { + U8 flags; + Expression *cond; /* NULL = this is an else */ + struct If *next_elif; /* next elif/else of this statement */ + Block body; +} If; + +typedef struct While { + Expression *cond; + Block body; +} While; + enum { - FN_EXPR_FOREIGN = 0x01, - FN_EXPR_EXPORT = 0x02, /* set during typing */ - FN_EXPR_HAS_VARARGS = 0x04 + FOR_IS_RANGE = 0x01 }; -typedef struct ForExpr { +typedef struct For { U8 flags; Declaration header; Block body; union { struct { - struct Expression *from; /* can't be null */ - struct Expression *to; /* can be null */ + Expression *from; /* can't be null */ + Expression *to; /* can be null */ union { /* (either) can be null */ - struct Expression *step; /* before typing */ + Expression *step; /* before typing */ Value *stepval; /* after typing. the type of this is header.type.tuple[0] (i.e. the value type for this for loop), NOTE: this might be different from the original ForExpr.step.type, because of implicit type conversions. */ }; } range; - struct Expression *of; + Expression *of; }; -} ForExpr; - -typedef enum { - STMT_DECL, - STMT_EXPR, - STMT_RET, - STMT_BREAK, - STMT_CONT, - STMT_INCLUDE, /* turns into STMT_INLINE_BLOCK after typing */ - STMT_MESSAGE, - STMT_DEFER, - STMT_USE, - STMT_INLINE_BLOCK /* a group of statements acting as one statement */ -} StatementKind; +} For; enum { RET_HAS_EXPR = 0x01 @@ -981,6 +962,22 @@ typedef struct Use { } Use; typedef Use *UsePtr; +typedef enum { + STMT_DECL, + STMT_EXPR, + STMT_RET, + STMT_BREAK, + STMT_CONT, + STMT_INCLUDE, /* turns into STMT_INLINE_BLOCK after typing */ + STMT_MESSAGE, + STMT_DEFER, + STMT_USE, + STMT_IF, + STMT_FOR, + STMT_WHILE, + STMT_BLOCK, + STMT_INLINE_BLOCK /* a group of statements acting as one statement, e.g. all the statements from a #include */ +} StatementKind; enum { STMT_TYPED = 0x01 }; @@ -998,6 +995,10 @@ typedef struct Statement { struct Statement *defer; struct Statement *inline_block; /* statements in an inline block (dynamic array) */ Use *use; + If *if_; + While *while_; + For *for_; + Block *block; }; } Statement; -- cgit v1.2.3