summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--cgen.c66
-rw-r--r--copy.c2
-rw-r--r--eval.c66
-rw-r--r--main.c4
-rw-r--r--parse.c17
-rw-r--r--test.toc12
-rw-r--r--types.c147
-rw-r--r--types.h8
8 files changed, 83 insertions, 239 deletions
diff --git a/cgen.c b/cgen.c
index 3dbeaf4..dce344e 100644
--- a/cgen.c
+++ b/cgen.c
@@ -19,7 +19,7 @@ static void cgen_stmt(CGenerator *g, Statement *s);
enum {
CGEN_BLOCK_NOBRACES = 0x01 /* should it use braces? */
};
-static void cgen_block(CGenerator *g, Block *b, const char *ret_name, uint16_t flags);
+static void cgen_block(CGenerator *g, Block *b, uint16_t flags);
static void cgen_expr_pre(CGenerator *g, Expression *e);
static void cgen_expr(CGenerator *g, Expression *e);
static void cgen_set(CGenerator *g, Expression *set_expr, const char *set_str, Expression *to_expr,
@@ -827,50 +827,16 @@ static void cgen_truthiness(CGenerator *g, Expression *e) {
}
static void cgen_expr_pre(CGenerator *g, Expression *e) {
- IdentID id = 0;
- char ret_name[CGEN_IDENT_ID_STR_SIZE+20];
- switch (e->kind) {
- case EXPR_IF:
- case EXPR_BLOCK: {
- id = ++g->ident_counter;
-
- cgen_ident_id_to_str(ret_name, id);
- char *p = ret_name + strlen(ret_name);
- if (!type_is_void(&e->type)) {
- if (e->type.kind == TYPE_TUPLE) {
- for (unsigned long i = 0; i < arr_len(e->type.tuple); ++i) {
- sprintf(p, "%lu", i);
- cgen_type_pre(g, &e->type.tuple[i]);
- cgen_write(g, " %s", ret_name);
- cgen_type_post(g, &e->type.tuple[i]);
- cgen_write(g, "; ");
- }
-
- } else {
- cgen_type_pre(g, &e->type);
- cgen_write(g, " %s", ret_name);
- cgen_type_post(g, &e->type);
- cgen_write(g, ";");
- cgen_nl(g);
- }
- }
- *p = 0; /* clear tuple suffixes */
-
- } break;
- default: break;
- }
-
switch (e->kind) {
case EXPR_IF: {
IfExpr *curr = e->if_;
- e->cgen.id = id;
while (1) {
if (curr->cond) {
cgen_write(g, "if (");
cgen_truthiness(g, curr->cond);
cgen_write(g, ") ");
}
- cgen_block(g, &curr->body, ret_name, 0);
+ cgen_block(g, &curr->body, 0);
if (curr->next_elif) {
cgen_write(g, " else ");
curr = curr->next_elif->if_;
@@ -878,8 +844,7 @@ static void cgen_expr_pre(CGenerator *g, Expression *e) {
}
} break;
case EXPR_BLOCK:
- e->cgen.id = id;
- cgen_block(g, e->block, ret_name, 0);
+ cgen_block(g, e->block, 0);
break;
case EXPR_CALL: {
cgen_expr_pre(g, e->call.fn);
@@ -925,7 +890,7 @@ static void cgen_expr_pre(CGenerator *g, Expression *e) {
}
cgen_write(g, ");");
} else if (cgen_uses_ptr(&e->type)) {
- e->cgen.id = id = ++g->ident_counter;
+ IdentID id = e->cgen.id = ++g->ident_counter;
cgen_type_pre(g, &e->type);
cgen_write(g, " ");
cgen_ident_id(g, id);
@@ -1286,7 +1251,7 @@ static void cgen_expr(CGenerator *g, Expression *e) {
cgen_write(g, "while (");
cgen_expr(g, w->cond);
cgen_write(g, ") ");
- cgen_block(g, &w->body, NULL, 0);
+ cgen_block(g, &w->body, 0);
} break;
case EXPR_FOR: {
ForExpr *fo = e->for_;
@@ -1473,7 +1438,7 @@ static void cgen_expr(CGenerator *g, Expression *e) {
}
}
}
- cgen_block(g, &fo->body, NULL, CGEN_BLOCK_NOBRACES);
+ cgen_block(g, &fo->body, CGEN_BLOCK_NOBRACES);
cgen_deferred_from_block(g, &fo->body);
cgen_write(g, "}}");
if (fo->body.c.break_lbl) {
@@ -1587,12 +1552,7 @@ static void cgen_expr(CGenerator *g, Expression *e) {
}
}
-/*
- ret_name = variable to store block return value in; NULL for none. NOTE:
- functions always call with NULL as ret_name, even if they use out params, for now
- at least.
-*/
-static void cgen_block(CGenerator *g, Block *b, const char *ret_name, U16 flags) {
+static void cgen_block(CGenerator *g, Block *b, U16 flags) {
Block *prev_block = g->block;
g->block = b;
b->deferred = NULL;
@@ -1605,15 +1565,6 @@ static void cgen_block(CGenerator *g, Block *b, const char *ret_name, U16 flags)
arr_foreach(b->stmts, Statement, s)
cgen_stmt(g, s);
- if (b->ret_expr && ret_name) {
- cgen_expr_pre(g, b->ret_expr);
- if (b->ret_expr->type.kind == TYPE_TUPLE) {
- cgen_set_tuple(g, NULL, NULL, ret_name, b->ret_expr);
- } else {
- cgen_set(g, NULL, ret_name, b->ret_expr, NULL);
- }
- cgen_nl(g);
- }
if (b->c.cont_lbl) {
cgen_lbl(g, b->c.cont_lbl);
cgen_writeln(g, ":;");
@@ -1720,8 +1671,7 @@ static void cgen_fn(CGenerator *g, FnExpr *f) {
cgen_decl(g, d);
}
- cgen_block(g, &f->body, NULL, CGEN_BLOCK_NOBRACES);
- cgen_ret(g, &f->body, f->body.ret_expr);
+ cgen_block(g, &f->body, CGEN_BLOCK_NOBRACES);
cgen_writeln(g, "}");
g->block = prev_block;
g->fn = prev_fn;
diff --git a/copy.c b/copy.c
index 2c85043..3f352c2 100644
--- a/copy.c
+++ b/copy.c
@@ -430,8 +430,6 @@ static void copy_block(Copier *c, Block *out, Block *in, U8 flags) {
out->stmts = NULL;
Block *prev = c->block;
c->block = out;
- if (in->ret_expr)
- out->ret_expr = copy_expr_(c, in->ret_expr);
if (!(flags & COPY_BLOCK_DONT_CREATE_IDENTS))
idents_create(&out->idents, c->allocr, out);
arr_set_lena(out->stmts, nstmts, c->allocr);
diff --git a/eval.c b/eval.c
index 8c4b7d0..74c2e78 100644
--- a/eval.c
+++ b/eval.c
@@ -4,7 +4,7 @@
You should have received a copy of the GNU General Public License along with toc. If not, see <https://www.gnu.org/licenses/>.
*/
-static Status eval_block(Evaluator *ev, Block *b, Value *v);
+static Status eval_block(Evaluator *ev, Block *b);
static Status eval_address_of(Evaluator *ev, Expression *e, void **ptr);
static Value get_builtin_val(BuiltinVal val);
@@ -22,7 +22,7 @@ static inline void *evalr_calloc(Evaluator *ev, size_t n, size_t bytes) {
return allocr_calloc(ev->allocr, n, bytes);
}
-static bool builtin_truthiness(Value v, BuiltinType b) {
+static inline bool builtin_truthiness(Value v, BuiltinType b) {
switch (b) {
case BUILTIN_I8: return v.i8 != 0;
case BUILTIN_I16: return v.i16 != 0;
@@ -45,7 +45,7 @@ static bool builtin_truthiness(Value v, BuiltinType b) {
assert(0); return false;
}
-static bool val_truthiness(Value v, Type *t) {
+static inline bool val_truthiness(Value v, Type *t) {
assert(t->flags & TYPE_IS_RESOLVED);
switch (t->kind) {
case TYPE_UNKNOWN: assert(0); return false;
@@ -1024,7 +1024,12 @@ static Status eval_ident(Evaluator *ev, Identifier ident, Value *v, Location whe
v->type->struc = d->expr.typeval->struc;
return true;
} else {
+ Typer *tr = ev->typer;
+ 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;
+ tr->block = prev_block;
assert(d->type.flags & TYPE_IS_RESOLVED);
}
Value *ival = ident_val(ev, ident, where);
@@ -1218,13 +1223,14 @@ static Status eval_expr(Evaluator *ev, Expression *e, Value *v) {
}
if (!eval_expr(ev, i->cond, &cond)) return false;
if (val_truthiness(cond, &i->cond->type)) {
- if (!eval_block(ev, &i->body, v)) return false;
+ 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, v)) return false;
+ if (!eval_block(ev, &i->body)) return false;
}
+ memset(v, 0, sizeof *v);
} break;
case EXPR_WHILE: {
Value cond;
@@ -1243,7 +1249,7 @@ static Status eval_expr(Evaluator *ev, Expression *e, Value *v) {
if (!val_truthiness(cond, cond_type))
break;
}
- if (!eval_block(ev, &w->body, v)) return false;
+ if (!eval_block(ev, &w->body)) return false;
if (ev->returning) {
if (ev->returning == &w->body) {
ev->returning = NULL;
@@ -1252,6 +1258,7 @@ static Status eval_expr(Evaluator *ev, Expression *e, Value *v) {
} else break;
}
}
+ memset(v, 0, sizeof *v);
} break;
case EXPR_FOR: {
ForExpr *fo = e->for_;
@@ -1292,7 +1299,7 @@ static Status eval_expr(Evaluator *ev, Expression *e, Value *v) {
}
if (value_val) *value_val = x;
- if (!eval_block(ev, &fo->body, v)) return false;
+ if (!eval_block(ev, &fo->body)) return false;
if (ev->returning) {
if (ev->returning == &fo->body) {
@@ -1345,7 +1352,7 @@ static Status eval_expr(Evaluator *ev, Expression *e, Value *v) {
value_val->ptr = ptr;
else
eval_deref(value_val, ptr, value_type);
- if (!eval_block(ev, &fo->body, v))
+ if (!eval_block(ev, &fo->body))
return false;
if (ev->returning) {
if (ev->returning == &fo->body) {
@@ -1359,9 +1366,10 @@ static Status eval_expr(Evaluator *ev, Expression *e, Value *v) {
}
arr_remove_last(header->val_stack);
free(for_valp);
+ memset(v, 0, sizeof *v);
} break;
case EXPR_BLOCK:
- if (!eval_block(ev, e->block, v)) return false;
+ if (!eval_block(ev, e->block)) return false;
break;
case EXPR_LITERAL_BOOL:
v->boolv = e->booll;
@@ -1480,11 +1488,20 @@ static Status eval_expr(Evaluator *ev, Expression *e, Value *v) {
}
}
+
+
/* make sure function body is typed before calling it */
- if (!types_block(ev->typer, &fn->body))
- return false;
-
- if (!eval_block(ev, &fn->body, v)) {
+ /* @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;
}
if (fn->ret_decls) {
@@ -1694,7 +1711,7 @@ static Status eval_stmt(Evaluator *ev, Statement *stmt) {
return true;
}
-static Status eval_block(Evaluator *ev, Block *b, Value *v) {
+static Status eval_block(Evaluator *ev, Block *b) {
Block *prev = ev->typer->block;
ev->typer->block = b;
b->deferred = NULL;
@@ -1710,27 +1727,6 @@ static Status eval_block(Evaluator *ev, Block *b, Value *v) {
break;
}
}
- if (b->ret_expr) {
- if (ev->returning) {
- /* return 0 from this block */
- *v = val_zero(&b->ret_expr->type);
- } else {
- Value r;
- if (!eval_expr(ev, b->ret_expr, &r)) {
- success = false;
- goto ret;
- }
- if (!type_is_builtin(&b->ret_expr->type, BUILTIN_TYPE)) {
- /* make a copy so that r's data isn't freed when we exit the block */
- copy_val(NULL, v, r, &b->ret_expr->type);
- if (b->ret_expr->kind == EXPR_TUPLE)
- free(r.tuple);
- } else {
- *v = r;
- }
- }
-
- }
{
/* deal with deferred stmts */
/* these could overwrite ev->returning, ev->ret_val, so we should save them */
diff --git a/main.c b/main.c
index 3299df4..48ae840 100644
--- a/main.c
+++ b/main.c
@@ -9,6 +9,10 @@
/*
@TODO:
get rid of blocks returning values
+turn if, while, for, block into statements
+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)
improve type_to_str:
diff --git a/parse.c b/parse.c
index 3cb453f..8a941cf 100644
--- a/parse.c
+++ b/parse.c
@@ -823,7 +823,6 @@ static Status parse_block(Parser *p, Block *b, U8 flags) {
b->flags = 0;
b->kind = BLOCK_OTHER;
b->uses = NULL;
- b->ret_expr = NULL;
assert(p->block != b);
b->parent = p->block;
p->block = b;
@@ -2295,7 +2294,8 @@ static Status parse_decl(Parser *p, Declaration *d, U16 flags) {
tokr_err(t, "Expected %s at end of declaration.", end_str);
goto ret_false;
}
- if (!parse_expr(p, &d->expr, end)) {
+ Expression *e = &d->expr;
+ if (!parse_expr(p, e, end)) {
t->token = end; /* move to ; */
goto ret_false;
}
@@ -2322,6 +2322,7 @@ static Status parse_decl(Parser *p, Declaration *d, U16 flags) {
tokr_err(t, "You must have an expression at the end of this constant declaration.");
goto ret_false;
}
+
parser_put_end(p, &d->where);
if (!token_is_kw(t->token, KW_SEMICOLON))
@@ -2548,12 +2549,7 @@ static Status parse_stmt(Parser *p, Statement *s, bool *was_a_statement) {
bool valid = parse_expr(p, s->expr = parser_malloc(p, sizeof *s->expr), end);
/* go past end of expr regardless of whether successful or not */
- if (token_is_kw(end, KW_SEMICOLON)) {
- t->token = end + 1; /* skip ; */
- } else {
- s->flags |= STMT_EXPR_NO_SEMICOLON;
- t->token = end;
- }
+ t->token = end + 1; /* skip ; */
if (!valid) return false;
}
@@ -2616,11 +2612,6 @@ static void fprint_block(FILE *out, Block *b) {
fprint_stmt(out, stmt);
}
fprintf(out, "}");
- if (b->ret_expr) {
- fprintf(out, " returns ");
- fprint_expr(out, b->ret_expr);
- }
-
}
static void print_block(Block *b) {
diff --git a/test.toc b/test.toc
index e7f8ecd..9f27d1c 100644
--- a/test.toc
+++ b/test.toc
@@ -1,14 +1,10 @@
main ::= fn() {
- nums : []int;
- l := slice_to_ll(nums);
+ a ::= foo(3);
+ b := foo(5);
}
-slice_to_ll ::= fn(t::=, slice: []t) use ll: LinkedList(t) {
-}
-
-LinkedList ::= struct (of :: Type) {
- head: of;
- tail: &LinkedList(of);
+foo ::= fn(x: int) int {
+ return 3*x;
}
diff --git a/types.c b/types.c
index d09b3ec..198de00 100644
--- a/types.c
+++ b/types.c
@@ -33,13 +33,11 @@ static inline void *typer_calloc(Typer *tr, size_t n, size_t sz) {
#define typer_arr_add_ptr(tr, a) arr_adda_ptr(a, tr->allocr)
static inline void typer_block_enter(Typer *tr, Block *b) {
- typer_arr_add(tr, tr->blocks, b);
tr->block = b;
}
static inline void typer_block_exit(Typer *tr) {
- arr_remove_lasta(tr->blocks, tr->allocr);
- tr->block = arr_last(tr->blocks);
+ tr->block = tr->block->parent;
}
static size_t compiler_sizeof_builtin(BuiltinType b) {
@@ -628,7 +626,8 @@ static Status type_of_fn(Typer *tr, FnExpr *f, Type *t, U16 flags) {
/* reserve space for return type */
typer_arr_add_ptr(tr, t->fn.types);
tr->fn = f;
- typer_block_enter(tr, &f->body);
+ Block *prev_block = tr->block;
+ tr->block = &f->body;
f->body.uses = NULL;
size_t nparams = arr_len(f->params);
entered_fn = true;
@@ -760,7 +759,7 @@ static Status type_of_fn(Typer *tr, FnExpr *f, Type *t, U16 flags) {
ret:
/* cleanup */
- typer_block_exit(tr);
+ tr->block = prev_block;
if (entered_fn) {
tr->fn = prev_fn;
}
@@ -779,9 +778,9 @@ top:;
if (decl_scope && decl_scope->kind != BLOCK_NMS) {
if (decl_scope->kind != BLOCK_NMS) {
/* go back through scopes */
- arr_foreach_reversed(tr->blocks, BlockPtr, block) {
- if (*block == NULL || *block == decl_scope) break;
- if ((*block)->kind == BLOCK_FN) {
+ for (Block *block = tr->block; block; block = block->parent) {
+ if (block == decl_scope) break;
+ if (block->kind == BLOCK_FN) {
captured = true;
break;
}
@@ -1156,6 +1155,7 @@ static bool arg_is_const(Expression *arg, Constness constness) {
/* pass NULL for instance if this isn't an instance */
static Status types_fn(Typer *tr, FnExpr *f, Type *t, Instance *instance) {
+ f->declaration_block = tr->block;
if (f->flags & FN_EXPR_FOREIGN) {
FnWithCtx fn_ctx = {f, tr->nms, tr->block};
typer_arr_add(tr, tr->all_fns, fn_ctx);
@@ -1163,7 +1163,6 @@ static Status types_fn(Typer *tr, FnExpr *f, Type *t, Instance *instance) {
}
FnExpr *prev_fn = tr->fn;
bool success = true;
- Expression *ret_expr;
Type *ret_type;
bool has_named_ret_vals;
assert(t->kind == TYPE_FN);
@@ -1182,30 +1181,9 @@ static Status types_fn(Typer *tr, FnExpr *f, Type *t, Instance *instance) {
success = false;
goto ret;
}
- ret_expr = f->body.ret_expr;
ret_type = t->fn.types;
has_named_ret_vals = f->ret_decls != NULL;
- if (ret_expr) {
- if (ret_expr->type.kind == TYPE_UNKNOWN) {
- if (ret_type->kind == TYPE_UNKNOWN) {
- err_print(ret_expr->where, "Can't determine type of return value. Try assigning it to a variable before returning it.");
- return false;
- }
- if (!tr->err_ctx->have_errored) /* if we've had an error, this could be a placeholder because something failed earlier */
- ret_expr->type = *ret_type;
- } else if (!type_eq_implicit(&ret_expr->type, ret_type)) {
- char *got = type_to_str(&ret_expr->type);
- char *expected = type_to_str(ret_type);
- err_print(ret_expr->where, "Returning type %s, but function returns type %s.", got, expected);
- if (!instance) /* where will only actually be at the function declaration if it isn't
- an instance. otherwise, where will be at the calling site, which will already be
- printed */
- info_print(f->where, "Function declaration is here.");
- free(got); free(expected);
- success = false;
- goto ret;
- }
- } else if (!type_is_builtin(ret_type, BUILTIN_VOID) && !has_named_ret_vals) {
+ 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);
@@ -1985,16 +1963,12 @@ static Status types_expr(Typer *tr, Expression *e) {
}
if (!types_block(tr, &fo->body)) goto for_fail;
- if (fo->body.ret_expr) {
- err_print(fo->body.ret_expr->where, "for loops can't return values -- you're missing a semicolon (;).");
- goto for_fail;
- }
t->kind = TYPE_BUILTIN;
t->builtin = BUILTIN_VOID;
typer_block_exit(tr);
- }break;
+ } break;
for_fail:
if (in_header)
arr_remove_lasta(tr->in_decls, tr->allocr);
@@ -2153,13 +2127,9 @@ static Status types_expr(Typer *tr, Expression *e) {
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;
}
- Type *curr_type = t;
- bool has_else = false;
if (!types_block(tr, &curr->body))
return false;
- if (curr->body.ret_expr) {
- *t = curr->body.ret_expr->type;
- } else {
+ {
t->kind = TYPE_BUILTIN; t->builtin = BUILTIN_VOID;
t->flags |= TYPE_IS_RESOLVED;
}
@@ -2173,8 +2143,6 @@ static Status types_expr(Typer *tr, Expression *e) {
free(s);
return false;
}
- } else {
- has_else = true;
}
if (curr->next_elif) {
IfExpr *nexti = curr->next_elif->if_;
@@ -2183,31 +2151,15 @@ static Status types_expr(Typer *tr, Expression *e) {
if (!types_block(tr, &nexti->body)) {
return false;
}
- if (nexti->body.ret_expr) {
- *next_type = nexti->body.ret_expr->type;
- } else {
+ {
next_type->kind = TYPE_BUILTIN; next_type->builtin = BUILTIN_VOID;
next_type->flags = TYPE_IS_RESOLVED;
}
- if (!type_eq_implicit(next_type, curr_type)) {
- char *currstr = type_to_str(curr_type);
- char *nextstr = type_to_str(next_type);
- err_print(curr->next_elif->where, "Mismatched types in if/elif/else chain. Previous block was of type %s, but this one is of type %s.", currstr, nextstr);
- free(currstr);
- free(nextstr);
- return false;
- }
curr = nexti;
-
} else {
break;
}
}
-
- if (!has_else && !type_is_builtin(t, BUILTIN_VOID)) {
- err_print(e->where, "Non-void if block with no else.");
- return false;
- }
} break;
case EXPR_WHILE: {
WhileExpr *w = e->while_;
@@ -2217,11 +2169,6 @@ static Status types_expr(Typer *tr, Expression *e) {
if (!types_block(tr, &w->body))
ret = false;
if (!ret) return false;
-
- if (w->body.ret_expr) {
- err_print(w->body.ret_expr->where, "while loops can't return values -- you're missing a semicolon (;)");
- return false;
- }
t->kind = TYPE_BUILTIN;
t->builtin = BUILTIN_VOID;
} break;
@@ -2816,12 +2763,8 @@ static Status types_expr(Typer *tr, Expression *e) {
Block *b = e->block;
if (!types_block(tr, b))
return false;
- if (b->ret_expr) {
- *t = b->ret_expr->type;
- } else {
- t->kind = TYPE_BUILTIN;
- t->builtin = BUILTIN_VOID;
- }
+ t->kind = TYPE_BUILTIN;
+ t->builtin = BUILTIN_VOID;
} break;
case EXPR_C: {
Expression *code = e->c.code;
@@ -3400,32 +3343,8 @@ static Status types_block(Typer *tr, Block *b) {
}
continue;
}
- if (s->kind == STMT_EXPR && (s->flags & STMT_EXPR_NO_SEMICOLON)) {
- /* not voided */
- Expression *e = s->expr;
- if (type_is_builtin(&e->type, BUILTIN_VOID)) {
- if (!(e->kind == EXPR_BLOCK
- || e->kind == EXPR_IF
- || e->kind == EXPR_WHILE
- || e->kind == EXPR_FOR)) {
- err_print(e->where, "void expression must be followed by ;");
- success = false;
- goto ret;
- }
- } else {
- if (s != (Statement *)arr_last_ptr(b->stmts)) {
- err_print(e->where, "Return value must be the last statement in a block.");
- success = false;
- goto ret;
- }
- b->ret_expr = typer_malloc(tr, sizeof *b->ret_expr);
- *b->ret_expr = *e;
- arr_remove_lasta(b->stmts, tr->allocr);
- }
- }
-
}
- ret:
+ assert(tr->block == b);
typer_block_exit(tr);
b->flags |= BLOCK_FOUND_TYPES;
b->flags &= (BlockFlags)~(BlockFlags)BLOCK_FINDING_TYPES;
@@ -3434,8 +3353,8 @@ static Status types_block(Typer *tr, Block *b) {
}
static bool is_at_top_level(Typer *tr) {
- arr_foreach(tr->blocks, BlockPtr, b) {
- if (*b && (*b)->kind != BLOCK_NMS) {
+ for (Block *b = tr->block; b; b = b->parent) {
+ if (b && b->kind != BLOCK_NMS) {
return false;
}
}
@@ -3465,21 +3384,22 @@ static Status types_decl(Typer *tr, Declaration *d) {
size_t n_idents; n_idents = arr_len(d->idents);
if (e) {
- if (e->kind == EXPR_FN && tr->block && tr->block->kind == BLOCK_STRUCT && !tr->in_decls /* don't include params */) {
- warn_print(d->where, "This function is in the body of a struct. Are you trying to declare a method, because they don't exist in this language.\n"
+ if (e->kind == EXPR_FN) {
+ if (tr->block == NULL || tr->block->kind == BLOCK_NMS) {
+ e->fn->c.name = d->idents[0];
+ } else if (tr->block->kind == BLOCK_STRUCT && !tr->in_decls /* don't include params */) {
+ warn_print(d->where, "This function is in the body of a struct. Are you trying to declare a method, because they don't exist in this language.\n"
"Try moving the function outside of the struct, otherwise you might run into problems.");
- }
- if (e->kind == EXPR_TYPE
+ }
+ } else if (e->kind == EXPR_NMS) {
+ if (is_at_top_level(tr))
+ e->nms->associated_ident = d->idents[0];
+ } else if (e->kind == EXPR_TYPE
&& e->typeval->kind == TYPE_STRUCT
&& tr->fn == NULL) {
e->typeval->struc->name = d->idents[0];
}
- if (e->kind == EXPR_NMS) {
- if (is_at_top_level(tr))
- e->nms->associated_ident = d->idents[0];
- }
-
if (!types_expr(tr, e)) {
success = false;
goto ret;
@@ -3533,9 +3453,6 @@ static Status types_decl(Typer *tr, Declaration *d) {
typer_arr_add(tr, d->val_stack, copy);
}
}
- if ((tr->block == NULL || tr->block->kind == BLOCK_NMS) && e->kind == EXPR_FN && n_idents == 1) {
- e->fn->c.name = d->idents[0];
- }
}
} else if (!tr->block || tr->block->kind == BLOCK_NMS) {
/* give global variables without initializers a value stack */
@@ -3726,11 +3643,6 @@ static Status types_stmt(Typer *tr, Statement *s) {
}
if (!cond || val_truthiness(v, &cond->type)) {
Block *true_block = &curr->body;
- Statement *last = arr_last_ptr(true_block->stmts);
- if (last && last->kind == STMT_EXPR && (last->flags & STMT_EXPR_NO_SEMICOLON)) {
- err_print(last->where, "#ifs can't return values.");
- return false;
- }
s->kind = STMT_INLINE_BLOCK;
s->inline_block = true_block->stmts;
if (!fix_ident_decls_inline_block(tr, s->inline_block))
@@ -3766,7 +3678,7 @@ static Status types_stmt(Typer *tr, Statement *s) {
return false;
}
- if (!(s->flags & STMT_EXPR_NO_SEMICOLON)) {
+ {
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;
@@ -3778,6 +3690,7 @@ static Status types_stmt(Typer *tr, Statement *s) {
free(str);
}
}
+
if (tr->block == NULL) {
/* evaluate expression statements at global scope */
if (e->kind != EXPR_C) {
@@ -4041,7 +3954,6 @@ static void typer_create(Typer *tr, Evaluator *ev, ErrCtx *err_ctx, Allocator *a
tr->err_ctx = err_ctx;
tr->allocr = allocr;
tr->globals = idents;
- typer_arr_add(tr, tr->blocks, NULL);
str_hash_table_create(&tr->included_files, sizeof(IncludedFile), tr->allocr);
}
@@ -4059,7 +3971,6 @@ static Status types_file(Typer *tr, ParsedFile *f) {
}
}
assert(tr->block == NULL);
- assert(arr_len(tr->blocks) && tr->blocks[0] == NULL);
return ret;
}
diff --git a/types.h b/types.h
index cd52028..9fcea1a 100644
--- a/types.h
+++ b/types.h
@@ -519,7 +519,6 @@ typedef struct Block {
Location where;
Identifiers idents;
struct Statement *stmts;
- struct Expression *ret_expr; /* the return expression of this block, e.g. {foo(); 3} => 3 NULL for no expression. */
struct Block *parent;
struct Statement **deferred; /* deferred stuff from this block; used by both eval and cgen */
struct Use **uses; /* use statements (for types.c) */
@@ -681,6 +680,7 @@ typedef struct {
typedef struct FnExpr {
Location where;
+ Block *declaration_block; /* block wherein this function is declared */
union {
struct {
struct Declaration *params; /* declarations of the parameters to this function */
@@ -713,7 +713,7 @@ typedef struct FnExpr {
IdentID id;
} c;
U8 flags;
-} FnExpr; /* an expression such as fn(x: int) int { 2 * x } */
+} FnExpr; /* an expression such as fn(x: int) int { return 2 * x; } */
typedef FnExpr *FnExprPtr;
typedef struct Instance {
@@ -982,8 +982,7 @@ typedef struct Use {
typedef Use *UsePtr;
enum {
- STMT_EXPR_NO_SEMICOLON = 0x01,
- STMT_TYPED = 0x02
+ STMT_TYPED = 0x01
};
typedef struct Statement {
Location where;
@@ -1072,7 +1071,6 @@ typedef struct Typer {
Use **uses; /* global used things */
Declaration **in_decls; /* array of declarations we are currently inside */
Block *block;
- Block **blocks; /* dyn array of all the block's we're in ([0] = NULL for global scope) */
FnExpr *fn; /* the function we're currently parsing. */
ErrCtx *err_ctx;
ParsedFile *parsed_file;