summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorLeo Tenenbaum <pommicket@gmail.com>2020-05-23 17:17:13 -0400
committerLeo Tenenbaum <pommicket@gmail.com>2020-05-23 17:17:13 -0400
commitdc6a7e198d2001086dd2245dd223bab3eda5670b (patch)
treedfd1ec9ae7ecad4a44cb42deb025288707e85ed8
parent38da18a86693f4ee46952b49601438f8c73ef34c (diff)
turned if, while, for, block into statements
-rw-r--r--cgen.c468
-rw-r--r--copy.c85
-rw-r--r--eval.c338
-rw-r--r--main.c4
-rw-r--r--parse.c451
-rw-r--r--test.toc6
-rw-r--r--types.c841
-rw-r--r--types.h93
8 files changed, 1122 insertions, 1164 deletions
diff --git a/cgen.c b/cgen.c
index dce344e..04f93c1 100644
--- a/cgen.c
+++ b/cgen.c
@@ -768,34 +768,9 @@ 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,341 +1654,6 @@ 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));
- }
- }
-
- 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 *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;
- }
- 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;
- }
- } 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 *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 (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;
- }
- }
- 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;
@@ -2119,59 +1798,6 @@ static Status types_expr(Typer *tr, Expression *e) {
}
*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;
@@ -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))
@@ -3624,16 +3243,370 @@ static Status include_stmts_link_to_nms(Typer *tr, Namespace *nms, Statement *st
}
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 (e->kind == EXPR_IF && (e->if_->flags & IF_STATIC)) {
+ 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;
+
+ 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;
+
+ /* 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;
+
+ /* 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;
+ }
+ 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;
+ }
+
+ 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;
+
+ 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;