summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--parse.c1
-rw-r--r--test.toc18
-rw-r--r--types.c49
3 files changed, 49 insertions, 19 deletions
diff --git a/parse.c b/parse.c
index 49b13e8..a753bda 100644
--- a/parse.c
+++ b/parse.c
@@ -1007,6 +1007,7 @@ static bool 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)) return false;
if (t->token != end) {
tokr_err(t, "Expression continues after end of block."); /* TODO: improve this err message */
diff --git a/test.toc b/test.toc
index 788cdcd..94e8ff7 100644
--- a/test.toc
+++ b/test.toc
@@ -1,13 +1,11 @@
main @= fn() {
- //x := 1;
- /*foo := if x {
- 9
- } elif 7-3 {
- 5
- } elif main {
- 3
- } else {7 };*/
-
- bar := if 1 { 9 };
+ {
+ i := 0;
+ asdf := if (fn(i: i64) i64 { i - 1024 })(i) {
+ i = i * 2;
+ i
+ } else { 0 };
+ }
+ (fn(){})();
};
diff --git a/types.c b/types.c
index 8c42d7e..7e9e929 100644
--- a/types.c
+++ b/types.c
@@ -374,8 +374,8 @@ static bool type_of_expr(Typer *tr, Expression *e) {
}
}
- if (!has_else && t->kind == TYPE_VOID) {
- err_print(e->where, "non-void if block with no else");
+ if (!has_else && t->kind != TYPE_VOID) {
+ err_print(e->where, "Non-void if block with no else.");
return false;
}
} break;
@@ -583,26 +583,46 @@ static bool type_of_expr(Typer *tr, Expression *e) {
}
static bool types_block(Typer *tr, Block *b) {
- bool ret = true;
+ bool success = true;
Block *prev_block = tr->block;
tr->block = b;
if (!block_enter(b, &b->stmts)) return false;
arr_foreach(&b->stmts, Statement, s) {
- if (!types_stmt(tr, s)) ret = false;
+ if (!types_stmt(tr, s)) success = false;
}
- if (b->ret_expr)
+ if (!success) return false;
+ if (b->ret_expr) {
if (!types_expr(tr, b->ret_expr))
- ret = false;
+ return false;
+ if (b->ret_expr->type.kind == TYPE_VOID) {
+ err_print(b->ret_expr->where, "Cannot return void value.");
+ return false;
+ }
+ }
+
block_exit(b, &b->stmts);
tr->block = prev_block;
- return ret;
+ return true;
}
-/* does descend into blocks, unlike type_of_expr. */
+/* does descend into functions, unlike type_of_expr. */
/* TODO: you still need to descend into other things */
static bool types_expr(Typer *tr, Expression *e) {
if (!type_of_expr(tr, e)) return false;
switch (e->kind) {
+ case EXPR_UNARY_OP:
+ if (!types_expr(tr, e->unary.of)) return false;
+ break;
+ case EXPR_BINARY_OP:
+ if (!types_expr(tr, e->binary.lhs)) return false;
+ if (!types_expr(tr, e->binary.rhs)) return false;
+ break;
+ case EXPR_CALL:
+ if (!types_expr(tr, e->call.fn)) return false;
+ arr_foreach(&e->call.args, Expression, arg) {
+ if (!types_expr(tr, arg)) return false;
+ }
+ break;
case EXPR_FN: {
assert(e->type.kind == TYPE_FN);
FnExpr *f = e->fn;
@@ -631,7 +651,18 @@ static bool types_expr(Typer *tr, Expression *e) {
return false;
}
} break;
- default: break;
+ case EXPR_IF: {
+ IfExpr *i = &e->if_;
+ if (i->cond && !types_expr(tr, i->cond)) return false;
+
+ } break;
+ case EXPR_DIRECT:
+ case EXPR_BLOCK:
+ case EXPR_IDENT:
+ case EXPR_LITERAL_INT:
+ case EXPR_LITERAL_FLOAT:
+ case EXPR_LITERAL_STR:
+ break;
}
return true;
}