diff options
-rw-r--r-- | cgen.c | 99 | ||||
-rw-r--r-- | decls_cgen.c | 24 | ||||
-rw-r--r-- | eval.c | 30 | ||||
-rw-r--r-- | main.c | 25 | ||||
-rw-r--r-- | parse.c | 28 | ||||
-rw-r--r-- | sdecls_cgen.c | 46 | ||||
-rw-r--r-- | test.toc | 12 | ||||
-rw-r--r-- | toc.c | 36 | ||||
-rw-r--r-- | tokenizer.c | 2 | ||||
-rw-r--r-- | types.c | 113 | ||||
-rw-r--r-- | types.h | 6 |
11 files changed, 223 insertions, 198 deletions
@@ -3,11 +3,10 @@ This file is part of toc. toc is distributed under version 3 of the GNU General Public License, without any warranty whatsoever. You should have received a copy of the GNU General Public License along with toc. If not, see <https://www.gnu.org/licenses/>. */ -static void cgen_create(CGenerator *g, FILE *out, Identifiers *ids, Evaluator *ev, Allocator *allocr) { +static void cgen_create(CGenerator *g, FILE *out, Identifiers *ids, Allocator *allocr) { g->outc = out; g->ident_counter = 0; g->main_ident = ident_get(ids, "main"); - g->evalr = ev; g->will_indent = true; g->indent_lvl = 0; g->globals = ids; @@ -16,25 +15,25 @@ static void cgen_create(CGenerator *g, FILE *out, Identifiers *ids, Evaluator *e *(char *)arr_adda(&g->nms_prefix, g->allocr) = '\0'; } -static bool cgen_stmt(CGenerator *g, Statement *s); +static Status cgen_stmt(CGenerator *g, Statement *s); enum { CGEN_BLOCK_NOBRACES = 0x01 /* should it use braces? */ }; -static bool cgen_block(CGenerator *g, Block *b, const char *ret_name, uint16_t flags); -static bool cgen_expr_pre(CGenerator *g, Expression *e); -static bool cgen_expr(CGenerator *g, Expression *e); -static bool cgen_set(CGenerator *g, Expression *set_expr, const char *set_str, Expression *to_expr, +static Status cgen_block(CGenerator *g, Block *b, const char *ret_name, uint16_t flags); +static Status cgen_expr_pre(CGenerator *g, Expression *e); +static Status cgen_expr(CGenerator *g, Expression *e); +static Status cgen_set(CGenerator *g, Expression *set_expr, const char *set_str, Expression *to_expr, const char *to_str); -static bool cgen_set_tuple(CGenerator *g, Expression *exprs, Identifier *idents, const char *prefix, Expression *to); -static bool cgen_type_pre(CGenerator *g, Type *t, Location where); -static bool cgen_type_post(CGenerator *g, Type *t, Location where); -static bool cgen_decl(CGenerator *g, Declaration *d); -static bool cgen_ret(CGenerator *g, Expression *ret); -static bool cgen_val(CGenerator *g, Value v, Type *t, Location where); -static bool cgen_val_pre(CGenerator *g, Value v, Type *t, Location where); -static bool cgen_val_ptr(CGenerator *g, void *v, Type *t, Location where); -static bool cgen_defs_block(CGenerator *g, Block *b); -static bool cgen_defs_decl(CGenerator *g, Declaration *d); +static Status cgen_set_tuple(CGenerator *g, Expression *exprs, Identifier *idents, const char *prefix, Expression *to); +static Status cgen_type_pre(CGenerator *g, Type *t, Location where); +static Status cgen_type_post(CGenerator *g, Type *t, Location where); +static Status cgen_decl(CGenerator *g, Declaration *d); +static Status cgen_ret(CGenerator *g, Expression *ret); +static Status cgen_val(CGenerator *g, Value v, Type *t, Location where); +static Status cgen_val_pre(CGenerator *g, Value v, Type *t, Location where); +static Status cgen_val_ptr(CGenerator *g, void *v, Type *t, Location where); +static Status cgen_defs_block(CGenerator *g, Block *b); +static Status cgen_defs_decl(CGenerator *g, Declaration *d); #define cgen_recurse_subexprs_fn_simple(fn, decl_f, block_f) \ FnExpr *prev_fn = g->f##n; \ @@ -351,7 +350,7 @@ static void cgen_struct_name(CGenerator *g, StructDef *sdef) { } } -static bool cgen_type_pre(CGenerator *g, Type *t, Location where) { +static Status cgen_type_pre(CGenerator *g, Type *t, Location where) { assert(t->flags & TYPE_IS_RESOLVED); switch (t->kind) { case TYPE_BUILTIN: @@ -411,7 +410,7 @@ static bool cgen_type_pre(CGenerator *g, Type *t, Location where) { return true; } -static bool cgen_type_post(CGenerator *g, Type *t, Location where) { +static Status cgen_type_post(CGenerator *g, Type *t, Location where) { assert(t->flags & TYPE_IS_RESOLVED); switch (t->kind) { case TYPE_PTR: @@ -513,7 +512,7 @@ static void cgen_full_fn_name(CGenerator *g, FnExpr *f, U64 instance) { } } -static bool cgen_fn_args(CGenerator *g, FnExpr *f, U64 instance, U64 which_are_const) { +static Status cgen_fn_args(CGenerator *g, FnExpr *f, U64 instance, U64 which_are_const) { (void)instance; /* not needed atm */ bool out_param = cgen_uses_ptr(&f->ret_type); bool any_params = false; @@ -598,7 +597,7 @@ static inline bool cgen_arg(CGenerator *g, Expression *arg) { } /* unless f has const/semi-const args, instance and which_are_const can be set to 0 */ -static bool cgen_fn_header(CGenerator *g, FnExpr *f, U64 instance, U64 which_are_const) { +static Status cgen_fn_header(CGenerator *g, FnExpr *f, U64 instance, U64 which_are_const) { bool out_param = cgen_uses_ptr(&f->ret_type); assert(cgen_should_gen_fn(f)); if (!(f->flags & FN_EXPR_EXPORT)) @@ -624,7 +623,7 @@ static bool cgen_fn_header(CGenerator *g, FnExpr *f, U64 instance, U64 which_are Also, set_str and/or to_str should be NULL this DOES NOT call cgen_expr_pre for set_expr or to_expr */ -static bool cgen_set(CGenerator *g, Expression *set_expr, const char *set_str, Expression *to_expr, +static Status cgen_set(CGenerator *g, Expression *set_expr, const char *set_str, Expression *to_expr, const char *to_str) { Type *type; Location where; @@ -701,7 +700,7 @@ static bool cgen_set(CGenerator *g, Expression *set_expr, const char *set_str, E } /* one of exprs, idents, and prefix should be NULL. does NOT call cgen_expr_pre for to/exprs */ -static bool cgen_set_tuple(CGenerator *g, Expression *exprs, Identifier *idents, const char *prefix, Expression *to) { +static Status cgen_set_tuple(CGenerator *g, Expression *exprs, Identifier *idents, const char *prefix, Expression *to) { switch (to->kind) { case EXPR_VAL: assert(0); /* never needed at the moment */ @@ -853,7 +852,7 @@ static bool cgen_set_tuple(CGenerator *g, Expression *exprs, Identifier *idents, return true; } -static bool cgen_expr_pre(CGenerator *g, Expression *e) { +static Status cgen_expr_pre(CGenerator *g, Expression *e) { IdentID id = 0; char ret_name[CGEN_IDENT_ID_STR_SIZE+20]; switch (e->kind) { @@ -1319,7 +1318,7 @@ static bool cgen_expr_pre(CGenerator *g, Expression *e) { return true; } -static bool cgen_expr(CGenerator *g, Expression *e) { +static Status cgen_expr(CGenerator *g, Expression *e) { switch (e->kind) { case EXPR_LITERAL_FLOAT: cgen_write(g, "%.16Lf", (long double)e->floatl); /* TODO(eventually): better precision? */ @@ -1453,7 +1452,8 @@ static bool cgen_expr(CGenerator *g, Expression *e) { if (struct_type->kind == TYPE_PTR) struct_type = struct_type->ptr; if (struct_type->kind == TYPE_STRUCT) { cgen_write(g, "("); - cgen_expr(g, e->binary.lhs); + if (!cgen_expr(g, e->binary.lhs)) + return false; bool is_ptr = e->binary.lhs->type.kind == TYPE_PTR; cgen_write(g, is_ptr ? "->" :"."); cgen_ident_simple(g, e->binary.dot.field->name); @@ -1640,8 +1640,10 @@ static bool cgen_expr(CGenerator *g, Expression *e) { return false; } else { cgen_write(g, "(("); - cgen_type_pre(g, to, e->where); - cgen_type_post(g, to, e->where); + if (!cgen_type_pre(g, to, e->where)) + return false; + if (!cgen_type_post(g, to, e->where)) + return false; cgen_write(g, ")("); if (!cgen_expr(g, e->cast.expr)) return false; @@ -1680,7 +1682,7 @@ static bool cgen_expr(CGenerator *g, Expression *e) { functions always call with NULL as ret_name, even if they use out params, for now at least. */ -static bool cgen_block(CGenerator *g, Block *b, const char *ret_name, U16 flags) { +static Status cgen_block(CGenerator *g, Block *b, const char *ret_name, U16 flags) { if (!(flags & CGEN_BLOCK_NOBRACES)) { cgen_write(g, "{"); cgen_nl(g); @@ -1732,7 +1734,7 @@ static void cgen_zero_value(CGenerator *g, Type *t) { } /* pass 0 for instance and NULL for compile_time_args if there are no compile time arguments. */ -static bool cgen_fn(CGenerator *g, FnExpr *f, U64 instance, Value *compile_time_args) { +static Status cgen_fn(CGenerator *g, FnExpr *f, U64 instance, Value *compile_time_args) { /* see also cgen_defs_expr */ FnExpr *prev_fn = g->fn; U64 which_are_const = compile_time_args ? compile_time_args->u64 : 0; @@ -1800,7 +1802,7 @@ static bool cgen_fn(CGenerator *g, FnExpr *f, U64 instance, Value *compile_time_ return true; } -static bool cgen_val_ptr_pre(CGenerator *g, void *v, Type *t, Location where) { +static Status cgen_val_ptr_pre(CGenerator *g, void *v, Type *t, Location where) { assert(t->flags & TYPE_IS_RESOLVED); switch (t->kind) { case TYPE_SLICE: { @@ -1843,7 +1845,7 @@ static bool cgen_val_ptr_pre(CGenerator *g, void *v, Type *t, Location where) { } /* generate a value from a pointer */ -static bool cgen_val_ptr(CGenerator *g, void *v, Type *t, Location where) { +static Status cgen_val_ptr(CGenerator *g, void *v, Type *t, Location where) { assert(t->flags & TYPE_IS_RESOLVED); switch (t->kind) { case TYPE_TUPLE: @@ -1871,7 +1873,8 @@ static bool cgen_val_ptr(CGenerator *g, void *v, Type *t, Location where) { arr_foreach(t->struc->fields, Field, f) { if (f != t->struc->fields) cgen_write(g, ", "); - cgen_val_ptr(g, (char *)v + f->offset, &f->type, where); + if (!cgen_val_ptr(g, (char *)v + f->offset, &f->type, where)) + return false; } cgen_write(g, "}"); break; @@ -1879,8 +1882,9 @@ static bool cgen_val_ptr(CGenerator *g, void *v, Type *t, Location where) { cgen_fn_name(g, *(FnExpr **)v); break; case TYPE_PTR: - err_print(where, "Cannot bring compile time pointer to runtime."); - return false; + /* see: You can't have a constant pointer. */ + assert(0); + break; case TYPE_BUILTIN: switch (t->builtin) { case BUILTIN_I8: cgen_write(g, I8_FMT, *(I8 *)v); break; @@ -1905,16 +1909,16 @@ static bool cgen_val_ptr(CGenerator *g, void *v, Type *t, Location where) { return true; } -static bool cgen_val_pre(CGenerator *g, Value v, Type *t, Location where) { +static Status cgen_val_pre(CGenerator *g, Value v, Type *t, Location where) { return cgen_val_ptr_pre(g, val_get_ptr(&v, t), t, where); } /* generates a value fit for use as an initializer */ -static bool cgen_val(CGenerator *g, Value v, Type *t, Location where) { +static Status cgen_val(CGenerator *g, Value v, Type *t, Location where) { return cgen_val_ptr(g, val_get_ptr(&v, t), t, where); } -static bool cgen_decl(CGenerator *g, Declaration *d) { +static Status cgen_decl(CGenerator *g, Declaration *d) { if (d->flags & DECL_FOREIGN) return true; /* already dealt with */ if (g->block == NULL && g->fn == NULL) @@ -2012,7 +2016,7 @@ static bool cgen_decl(CGenerator *g, Declaration *d) { return true; } -static bool cgen_ret(CGenerator *g, Expression *ret) { +static Status cgen_ret(CGenerator *g, Expression *ret) { FnExpr *f = g->fn; if (f->ret_decls) { assert(!ret); @@ -2080,7 +2084,7 @@ static bool cgen_ret(CGenerator *g, Expression *ret) { } -static bool cgen_stmt(CGenerator *g, Statement *s) { +static Status cgen_stmt(CGenerator *g, Statement *s) { /* TODO(eventually): optionally this: cgen_write(g, "/\* %s:%d *\/", s->where.ctx->filename, s->where.line); @@ -2111,7 +2115,7 @@ static bool cgen_stmt(CGenerator *g, Statement *s) { return true; } -static bool cgen_defs_fn(CGenerator *g, FnExpr *f, Type *t) { +static Status cgen_defs_fn(CGenerator *g, FnExpr *f, Type *t) { FnType *fn_type = &t->fn; bool any_const = false; if (fn_type->constness) { @@ -2137,7 +2141,7 @@ static bool cgen_defs_fn(CGenerator *g, FnExpr *f, Type *t) { return true; } -static bool cgen_defs_expr(CGenerator *g, Expression *e) { +static Status cgen_defs_expr(CGenerator *g, Expression *e) { if (e->kind == EXPR_FN) { if (!cgen_defs_fn(g, e->fn, &e->type)) return false; @@ -2146,7 +2150,7 @@ static bool cgen_defs_expr(CGenerator *g, Expression *e) { return true; } -static bool cgen_defs_decl(CGenerator *g, Declaration *d) { +static Status cgen_defs_decl(CGenerator *g, Declaration *d) { if (d->flags & DECL_FOREIGN) { return true; /* dealt with by decls_cgen */ } @@ -2158,7 +2162,7 @@ static bool cgen_defs_decl(CGenerator *g, Declaration *d) { } -static bool cgen_defs_stmt(CGenerator *g, Statement *s) { +static Status cgen_defs_stmt(CGenerator *g, Statement *s) { switch (s->kind) { case STMT_DECL: if (!cgen_defs_decl(g, s->decl)) @@ -2182,7 +2186,7 @@ static bool cgen_defs_stmt(CGenerator *g, Statement *s) { return true; } -static bool cgen_defs_block(CGenerator *g, Block *b) { +static Status cgen_defs_block(CGenerator *g, Block *b) { /* NOTE: since we exit as soon as there's an error for cgen, we don't need to make sure we set g->block to the previous block if there's an error @@ -2201,7 +2205,7 @@ static bool cgen_defs_block(CGenerator *g, Block *b) { return true; } -static bool cgen_file(CGenerator *g, ParsedFile *f) { +static Status cgen_file(CGenerator *g, ParsedFile *f) { g->block = NULL; g->nms = NULL; g->fn = NULL; @@ -2230,8 +2234,7 @@ static bool cgen_file(CGenerator *g, ParsedFile *f) { "static void _free(void *data) { extern void free(void *data); free(data); }\n" /* don't introduce free to global namespace */ "static void *_ecalloc(size_t n, size_t sz) { extern void *calloc(size_t n, size_t size); extern void abort(void); extern int printf(const char *fmt, ...); void *ret = calloc(n, sz); if (n && sz && !ret) { printf(\"Out of memory.\\n\"); abort(); } return ret; }\n\n\n"); - if (!cgen_sdecls_file(g, f)) - return false; + cgen_sdecls_file(g, f); if (!cgen_decls_file(g, f)) return false; cgen_write(g, "/* code */\n"); diff --git a/decls_cgen.c b/decls_cgen.c index 2c6fc63..9776547 100644 --- a/decls_cgen.c +++ b/decls_cgen.c @@ -3,11 +3,11 @@ This file is part of toc. toc is distributed under version 3 of the GNU General Public License, without any warranty whatsoever. You should have received a copy of the GNU General Public License along with toc. If not, see <https://www.gnu.org/licenses/>. */ -static bool cgen_decls_stmt(CGenerator *g, Statement *s); -static bool cgen_decls_block(CGenerator *g, Block *b); -static bool cgen_decls_decl(CGenerator *g, Declaration *d); +static Status cgen_decls_stmt(CGenerator *g, Statement *s); +static Status cgen_decls_block(CGenerator *g, Block *b); +static Status cgen_decls_decl(CGenerator *g, Declaration *d); -static bool cgen_decls_type(CGenerator *g, Type *type) { +static Status cgen_decls_type(CGenerator *g, Type *type) { if (!(type->flags & TYPE_IS_RESOLVED)) /* non-instance constant fn parameter type */ return true; if (type->kind == TYPE_STRUCT) { @@ -37,7 +37,7 @@ static bool cgen_decls_type(CGenerator *g, Type *type) { return true; } -static bool cgen_single_fn_decl(CGenerator *g, FnExpr *f, U64 instance, U64 which_are_const) { +static Status cgen_single_fn_decl(CGenerator *g, FnExpr *f, U64 instance, U64 which_are_const) { if (cgen_should_gen_fn(f)) { if (!cgen_fn_header(g, f, instance, which_are_const)) return false; @@ -48,7 +48,7 @@ static bool cgen_single_fn_decl(CGenerator *g, FnExpr *f, U64 instance, U64 whic } -static bool cgen_decls_fn_instances(CGenerator *g, FnExpr *f) { +static Status cgen_decls_fn_instances(CGenerator *g, FnExpr *f) { Instance **data = f->instances.data; for (U64 i = 0; i < f->instances.cap; ++i) { if (f->instances.occupied[i]) { @@ -66,7 +66,7 @@ static bool cgen_decls_fn_instances(CGenerator *g, FnExpr *f) { return true; } -static bool cgen_fn_decl(CGenerator *g, FnExpr *f, Type *t) { +static Status cgen_fn_decl(CGenerator *g, FnExpr *f, Type *t) { FnType *fn_type = &t->fn; if (fn_type->constness) { if (!cgen_decls_fn_instances(g, f)) @@ -78,7 +78,7 @@ static bool cgen_fn_decl(CGenerator *g, FnExpr *f, Type *t) { return true; } -static bool cgen_decls_expr(CGenerator *g, Expression *e) { +static Status cgen_decls_expr(CGenerator *g, Expression *e) { assert(e->flags & EXPR_FOUND_TYPE); cgen_recurse_subexprs(g, e, cgen_decls_expr, cgen_decls_block, cgen_decls_decl); switch (e->kind) { @@ -111,7 +111,7 @@ static bool cgen_decls_expr(CGenerator *g, Expression *e) { return true; } -static bool cgen_decls_block(CGenerator *g, Block *b) { +static Status cgen_decls_block(CGenerator *g, Block *b) { Block *prev_block = g->block; g->block = b; arr_foreach(b->stmts, Statement, s) @@ -123,7 +123,7 @@ static bool cgen_decls_block(CGenerator *g, Block *b) { return true; } -static bool cgen_decls_decl(CGenerator *g, Declaration *d) { +static Status cgen_decls_decl(CGenerator *g, Declaration *d) { if (d->flags & DECL_FOREIGN) { cgen_write(g, "extern "); if ((d->flags & DECL_IS_CONST) && (d->type.kind == TYPE_FN) && arr_len(d->idents) == 1) { @@ -218,7 +218,7 @@ static bool cgen_decls_decl(CGenerator *g, Declaration *d) { return true; } -static bool cgen_decls_stmt(CGenerator *g, Statement *s) { +static Status cgen_decls_stmt(CGenerator *g, Statement *s) { switch (s->kind) { case STMT_DECL: if (!cgen_decls_decl(g, s->decl)) @@ -242,7 +242,7 @@ static bool cgen_decls_stmt(CGenerator *g, Statement *s) { return true; } -static bool cgen_decls_file(CGenerator *g, ParsedFile *f) { +static Status cgen_decls_file(CGenerator *g, ParsedFile *f) { cgen_write(g, "/* declarations */\n"); arr_foreach(f->stmts, Statement, s) { if (!cgen_decls_stmt(g, s)) @@ -4,11 +4,11 @@ You should have received a copy of the GNU General Public License along with toc. If not, see <https://www.gnu.org/licenses/>. */ -static bool types_block(Typer *tr, Block *b); -static bool types_decl(Typer *tr, Declaration *d); -static bool type_resolve(Typer *tr, Type *t, Location where); -static bool eval_block(Evaluator *ev, Block *b, Value *v); -static bool eval_expr(Evaluator *ev, Expression *e, Value *v); +static Status types_block(Typer *tr, Block *b); +static Status types_decl(Typer *tr, Declaration *d); +static Status type_resolve(Typer *tr, Type *t, Location where); +static Status eval_block(Evaluator *ev, Block *b, Value *v); +static Status eval_expr(Evaluator *ev, Expression *e, Value *v); static Value get_builtin_val(BuiltinVal val); static void evalr_create(Evaluator *ev, Typer *tr, Allocator *allocr) { @@ -567,7 +567,7 @@ static void eval_deref_set(void *set, Value *to, Type *type) { } } -static bool eval_val_ptr_at_index(Location where, Value *arr, U64 i, Type *arr_type, void **ptr, Type **type) { +static Status eval_val_ptr_at_index(Location where, Value *arr, U64 i, Type *arr_type, void **ptr, Type **type) { switch (arr_type->kind) { case TYPE_ARR: { U64 arr_sz = (U64)arr_type->arr.n; @@ -592,7 +592,7 @@ static bool eval_val_ptr_at_index(Location where, Value *arr, U64 i, Type *arr_t return true; } -static bool eval_expr_ptr_at_index(Evaluator *ev, Expression *e, void **ptr, Type **type) { +static Status eval_expr_ptr_at_index(Evaluator *ev, Expression *e, void **ptr, Type **type) { Value arr; if (!eval_expr(ev, e->binary.lhs, &arr)) return false; Value index; @@ -679,7 +679,7 @@ static inline bool eval_address_of_ident(Identifier i, Location where, Type *typ return true; } -static bool eval_ptr_to_struct_field(Evaluator *ev, Expression *dot_expr, void **p) { +static Status eval_ptr_to_struct_field(Evaluator *ev, Expression *dot_expr, void **p) { Type *struct_type = &dot_expr->binary.lhs->type; bool is_ptr = struct_type->kind == TYPE_PTR; if (is_ptr) { @@ -711,7 +711,7 @@ static bool eval_ptr_to_struct_field(Evaluator *ev, Expression *dot_expr, void * return true; } -static bool eval_address_of(Evaluator *ev, Expression *e, void **ptr) { +static Status eval_address_of(Evaluator *ev, Expression *e, void **ptr) { switch (e->kind) { case EXPR_IDENT: { if (!eval_address_of_ident(e->ident, e->where, &e->type, ptr)) @@ -755,7 +755,7 @@ static bool eval_address_of(Evaluator *ev, Expression *e, void **ptr) { return true; } -static bool eval_set(Evaluator *ev, Expression *set, Value *to) { +static Status eval_set(Evaluator *ev, Expression *set, Value *to) { switch (set->kind) { case EXPR_IDENT: { Identifier i = set->ident; @@ -996,7 +996,7 @@ static bool val_is_nonnegative(Value *v, Type *t) { return val_to_i64(v, t->builtin) >= 0; } -static bool eval_ident(Evaluator *ev, Identifier ident, Value *v, Location where) { +static Status eval_ident(Evaluator *ev, Identifier ident, Value *v, Location where) { if (ident->decl_kind == IDECL_NONE) { char *s = ident_to_str(ident); err_print(where, "Undeclared identifier: %s.", s); @@ -1068,7 +1068,7 @@ static void decl_remove_val(Declaration *d) { arr_remove_last(&d->val_stack); } -static bool eval_expr(Evaluator *ev, Expression *e, Value *v) { +static Status eval_expr(Evaluator *ev, Expression *e, Value *v) { #define eval_unary_op_one(low, up, op) \ case BUILTIN_##up: \ @@ -1572,7 +1572,7 @@ static bool eval_expr(Evaluator *ev, Expression *e, Value *v) { return true; } -static bool eval_decl(Evaluator *ev, Declaration *d) { +static Status eval_decl(Evaluator *ev, Declaration *d) { unsigned has_expr = d->flags & DECL_HAS_EXPR; unsigned is_const = d->flags & DECL_IS_CONST; Value val = {0}; @@ -1620,7 +1620,7 @@ static bool eval_decl(Evaluator *ev, Declaration *d) { return true; } -static bool eval_stmt(Evaluator *ev, Statement *stmt) { +static Status eval_stmt(Evaluator *ev, Statement *stmt) { switch (stmt->kind) { case STMT_DECL: if (!eval_decl(ev, stmt->decl)) return false; @@ -1656,7 +1656,7 @@ static void eval_exit_stmts(Statement *stmts) { } } -static bool eval_block(Evaluator *ev, Block *b, Value *v) { +static Status eval_block(Evaluator *ev, Block *b, Value *v) { Block *prev = ev->typer->block; ev->typer->block = b; bool success = true; @@ -4,25 +4,14 @@ You should have received a copy of the GNU General Public License along with toc. If not, see <https://www.gnu.org/licenses/>. */ -/* - NOTE: - Structure of the toc compiler: - tokenizer => parser => typing (types.c) => cgen - (lexing) - - toc tries to continue even after the first error. - It will not continue during cgen, but it will during tokenization, - parsing, and typing. If one stage fails, the following ones do not - start. -*/ +/* see toc.c for development information */ /* TODO: -make sure we're checking for redecls with #include - +try to make cgen not have return values anymore nice syntax for #including something into a namespace run stuff at compile time without assigning it to a constant -the problem of #foreign stuff currently requiring that source and target have the same sizeof(int), etc. -- we may need #C_int, etc. +better #foreign system- something like f := #foreign fn (int,float, #C int); --- constants in structs #if @@ -123,6 +112,7 @@ int main(int argc, char **argv) { tokr_create(&t, &err_ctx, &main_allocr); if (!tokenize_file(&t, &file)) { err_text_important(&err_ctx, "Errors occured during preprocessing.\n"); + allocr_free_all(&main_allocr); return EXIT_FAILURE; } @@ -140,6 +130,7 @@ int main(int argc, char **argv) { ParsedFile f; if (!parse_file(&p, &f)) { err_text_important(&err_ctx, "Errors occured during parsing.\n"); + allocr_free_all(&main_allocr); return EXIT_FAILURE; } /* fprint_parsed_file(stdout, &f); */ @@ -154,6 +145,7 @@ int main(int argc, char **argv) { if (!types_file(&tr, &f)) { /* TODO(eventually): fix this if the error occured while exporting something */ err_text_important(&err_ctx, "Errors occured while determining types.\n"); + allocr_free_all(&main_allocr); return EXIT_FAILURE; } #ifdef TOC_DEBUG @@ -164,13 +156,16 @@ int main(int argc, char **argv) { if (!out) { err_text_important(&err_ctx, "Could not open output file: "); err_fprint(&err_ctx, "%s\n", out_filename); + allocr_free_all(&main_allocr); return EXIT_FAILURE; } CGenerator g; - cgen_create(&g, out, &globals, &ev, &main_allocr); + cgen_create(&g, out, &globals, &main_allocr); if (!cgen_file(&g, &f)) { fclose(out); err_text_important(&err_ctx, "Errors occured while generating C code.\n"); + allocr_free_all(&main_allocr); + fclose(out); return EXIT_FAILURE; } @@ -3,16 +3,16 @@ This file is part of toc. toc is distributed under version 3 of the GNU General Public License, without any warranty whatsoever. You should have received a copy of the GNU General Public License along with toc. If not, see <https://www.gnu.org/licenses/>. */ -static bool parse_expr(Parser *p, Expression *e, Token *end); -static bool parse_stmt(Parser *p, Statement *s, bool *was_a_statement); +static Status parse_expr(Parser *p, Expression *e, Token *end); +static Status parse_stmt(Parser *p, Statement *s, bool *was_a_statement); enum { PARSE_DECL_ALLOW_CONST_WITH_NO_EXPR = 0x01, PARSE_DECL_ALLOW_SEMI_CONST = 0x02, PARSE_DECL_ALLOW_INFER = 0x04, PARSE_DECL_ALLOW_EXPORT = 0x08 }; -static bool parse_decl(Parser *p, Declaration *d, DeclEndKind ends_with, uint16_t flags); -static bool parse_decl_list(Parser *p, Declaration **decls, DeclEndKind decl_end); +static Status parse_decl(Parser *p, Declaration *d, DeclEndKind ends_with, uint16_t flags); +static Status parse_decl_list(Parser *p, Declaration **decls, DeclEndKind decl_end); static bool is_decl(Tokenizer *t); static inline bool ends_decl(Token *t, DeclEndKind ends_with); @@ -421,7 +421,7 @@ static Token *expr_find_end(Parser *p, ExprEndFlags flags) { } /* parses, e.g. "(3, 5, foo)" */ -static bool parse_args(Parser *p, Argument **args) { +static Status parse_args(Parser *p, Argument **args) { Tokenizer *t = p->tokr; Token *start = t->token; assert(token_is_kw(start, KW_LPAREN)); @@ -460,7 +460,7 @@ static bool parse_args(Parser *p, Argument **args) { return true; } -static bool parse_type(Parser *p, Type *type) { +static Status parse_type(Parser *p, Type *type) { Tokenizer *t = p->tokr; type->where = parser_mk_loc(p); type->where.start = t->token; @@ -835,7 +835,7 @@ static bool parser_is_definitely_type(Parser *p, Token **end) { enum { PARSE_BLOCK_DONT_CREATE_IDENTS = 0x01 }; -static bool parse_block(Parser *p, Block *b, U8 flags) { +static Status parse_block(Parser *p, Block *b, U8 flags) { Tokenizer *t = p->tokr; Block *prev_block = p->block; b->flags = 0; @@ -886,7 +886,7 @@ static bool parse_block(Parser *p, Block *b, U8 flags) { } /* does NOT handle empty declaration lists */ -static bool parse_decl_list(Parser *p, Declaration **decls, DeclEndKind decl_end) { +static Status parse_decl_list(Parser *p, Declaration **decls, DeclEndKind decl_end) { Tokenizer *t = p->tokr; bool ret = true; bool first = true; @@ -920,7 +920,7 @@ static bool parse_decl_list(Parser *p, Declaration **decls, DeclEndKind decl_end return ret; } -static bool parse_fn_expr(Parser *p, FnExpr *f) { +static Status parse_fn_expr(Parser *p, FnExpr *f) { Tokenizer *t = p->tokr; f->ret_decls = NULL; { @@ -1043,7 +1043,7 @@ static Identifier parser_ident_insert(Parser *p, char *str) { return i; } -static bool check_ident_redecl(Parser *p, Identifier i) { +static Status check_ident_redecl(Parser *p, Identifier i) { Tokenizer *t = p->tokr; if (i->idents == &p->block->idents) { if (i->decl_kind != IDECL_NONE) { @@ -1057,7 +1057,7 @@ static bool check_ident_redecl(Parser *p, Identifier i) { return true; } -static bool parse_expr(Parser *p, Expression *e, Token *end) { +static Status parse_expr(Parser *p, Expression *e, Token *end) { Tokenizer *t = p->tokr; #if 0 @@ -1928,7 +1928,7 @@ static inline bool ends_decl(Token *t, DeclEndKind ends_with) { } } -static bool parse_decl(Parser *p, Declaration *d, DeclEndKind ends_with, U16 flags) { +static Status parse_decl(Parser *p, Declaration *d, DeclEndKind ends_with, U16 flags) { Tokenizer *t = p->tokr; d->where = parser_mk_loc(p); d->where.start = t->token; @@ -2126,7 +2126,7 @@ static bool is_decl(Tokenizer *t) { } /* sets *was_a_statement to false if s was not filled, but the token was advanced */ -static bool parse_stmt(Parser *p, Statement *s, bool *was_a_statement) { +static Status parse_stmt(Parser *p, Statement *s, bool *was_a_statement) { Tokenizer *t = p->tokr; if (t->token->kind == TOKEN_EOF) { tokr_err(t, "Expected statement."); @@ -2223,7 +2223,7 @@ static void parser_create(Parser *p, Identifiers *globals, Tokenizer *t, Allocat p->allocr = allocr; } -static bool parse_file(Parser *p, ParsedFile *f) { +static Status parse_file(Parser *p, ParsedFile *f) { Tokenizer *t = p->tokr; f->stmts = NULL; p->file = t->file; diff --git a/sdecls_cgen.c b/sdecls_cgen.c index a146eb2..6900b78 100644 --- a/sdecls_cgen.c +++ b/sdecls_cgen.c @@ -3,7 +3,7 @@ This file is part of toc. toc is distributed under version 3 of the GNU General Public License, without any warranty whatsoever. You should have received a copy of the GNU General Public License along with toc. If not, see <https://www.gnu.org/licenses/>. */ -static bool cgen_sdecls_stmt(CGenerator *g, Statement *s); +static void cgen_sdecls_stmt(CGenerator *g, Statement *s); static bool cgen_sdecls_decl(CGenerator *g, Declaration *d); static bool cgen_sdecls_expr(CGenerator *g, Expression *e); @@ -33,19 +33,20 @@ static bool cgen_sdecls_type(CGenerator *g, Type *type) { return true; } +/* ALWAYS RETURNS TRUE. just returns a bool for cgen_recurse_subexprs to work. */ static bool cgen_sdecls_block(CGenerator *g, Block *b) { Block *prev_block = g->block; g->block = b; arr_foreach(b->stmts, Statement, s) - if (!cgen_sdecls_stmt(g, s)) - return false; - if (b->ret_expr && !cgen_sdecls_expr(g, b->ret_expr)) - return false; + cgen_sdecls_stmt(g, s); + if (b->ret_expr) + cgen_sdecls_expr(g, b->ret_expr); g->block = prev_block; return true; } +/* ALWAYS RETURNS TRUE. just returns a bool for cgen_recurse_subexprs to work. */ static bool cgen_sdecls_expr(CGenerator *g, Expression *e) { switch (e->kind) { case EXPR_CAST: @@ -56,8 +57,7 @@ static bool cgen_sdecls_expr(CGenerator *g, Expression *e) { e->fn->c.id = ++g->ident_counter; break; case EXPR_TYPE: - if (!cgen_sdecls_type(g, &e->typeval)) - return false; + cgen_sdecls_type(g, &e->typeval); break; case EXPR_NMS: e->nms.c.id = 0; @@ -66,15 +66,16 @@ static bool cgen_sdecls_expr(CGenerator *g, Expression *e) { } cgen_recurse_subexprs(g, e, cgen_sdecls_expr, cgen_sdecls_block, cgen_sdecls_decl); return true; - } + +/* ALWAYS RETURNS TRUE. just returns a bool for cgen_recurse_subexprs to work. */ static bool cgen_sdecls_decl(CGenerator *g, Declaration *d) { if (d->flags & DECL_FOREIGN) { /* handled by cgen_decls */ return true; } - cgen_sdecls_type(g, &d->type); + cgen_sdecls_type(g, &d->type); if (cgen_fn_is_direct(g, d)) { d->expr.fn->c.name = d->idents[0]; } @@ -82,13 +83,11 @@ static bool cgen_sdecls_decl(CGenerator *g, Declaration *d) { Type *type = decl_type_at_index(d, idx); Value *val = decl_val_at_index(d, idx); if (type_is_builtin(type, BUILTIN_TYPE)) { - if (!cgen_sdecls_type(g, val->type)) - return false; + cgen_sdecls_type(g, val->type); } } if (d->flags & DECL_HAS_EXPR) { - if (!cgen_sdecls_expr(g, &d->expr)) - return false; + cgen_sdecls_expr(g, &d->expr); if (d->flags & DECL_EXPORT) { if (d->expr.kind == EXPR_FN) d->expr.fn->flags |= FN_EXPR_EXPORT; @@ -97,34 +96,27 @@ static bool cgen_sdecls_decl(CGenerator *g, Declaration *d) { return true; } -static bool cgen_sdecls_stmt(CGenerator *g, Statement *s) { +static void cgen_sdecls_stmt(CGenerator *g, Statement *s) { switch (s->kind) { case STMT_DECL: - if (!cgen_sdecls_decl(g, s->decl)) - return false; + cgen_sdecls_decl(g, s->decl); break; case STMT_EXPR: - if (!cgen_sdecls_expr(g, &s->expr)) - return false; + cgen_sdecls_expr(g, &s->expr); break; case STMT_RET: if (s->ret.flags & RET_HAS_EXPR) - if (!cgen_sdecls_expr(g, &s->ret.expr)) - return false; + cgen_sdecls_expr(g, &s->ret.expr); break; case STMT_INCLUDE: arr_foreach(s->inc.stmts, Statement, sub) - if (!cgen_sdecls_stmt(g, sub)) - return false; + cgen_sdecls_stmt(g, sub); break; } - return true; } -static bool cgen_sdecls_file(CGenerator *g, ParsedFile *f) { +static void cgen_sdecls_file(CGenerator *g, ParsedFile *f) { arr_foreach(f->stmts, Statement, s) { - if (!cgen_sdecls_stmt(g, s)) - return false; + cgen_sdecls_stmt(g, s); } - return true; } @@ -1,13 +1,5 @@ -io ::= nms { -#include "std/io.toc"; -}; - -foo ::= fn() <int, int> { - 3, 5 -}; main ::= fn() { - _, x := foo(); - y, _ := foo(); - io.puti(x); io.puti(y); + x :: &int = new(int); + y := x; };
\ No newline at end of file @@ -4,7 +4,38 @@ You should have received a copy of the GNU General Public License along with toc. If not, see <https://www.gnu.org/licenses/>. */ -/* NOTE: all stages should use the same allocator! */ + +/* + NOTE: + Structure of the toc compiler: + tokenizer => parser => typing (types.c) => cgen + (lexing) + + toc tries to continue even after the first error. + It will not continue during cgen, but it will during tokenization, + parsing, and typing. If one stage fails, the following ones do not + start. + + toc's memory management works using an allocator which never frees anything. + This is because most of toc's data is kept around until the end of the program anyways. + Use the allocator for "permanent" allocations, and err_malloc/calloc/realloc for temporary + allocations (to avoid having it take up space for a long time). + + Because of this, memory leaks can happen if the compilation fails at any point, but they + should not happen if the compilation succeeds. Usually if there's an error + which causes a memory leak, it will be very small. + + Functions which can fail (i.e. print an error message and stop) return a Status, + which is a bool, but GCC warns about not using the return value. + + The fixed-width types U8/16/32/64 and I8/16/32/64 have been defined. + data_structures.c contains a dynamic array implementation which is very useful. + Many of the members of the types below are dynamic arrays. + + It is assumed that the number of identifiers in a declaration, or parameters to a function + will fit in an int, since a function with (at least) 32768 parameters is ridiculous. +*/ + /* Includes all of toc's files */ #include <assert.h> @@ -70,7 +101,6 @@ static void print_block_location(Block *b); #define join3(a,b) a##b #define join2(a,b) join3(a,b) #define join(a,b) join2(a,b) -#define eval(x) x static void fprint_char_literal(FILE *f, char c) { if (isprint(c)) @@ -137,7 +167,7 @@ static char *read_file_contents(Allocator *a, const char *filename, Location whe #include "infer.c" #include "types.c" static bool cgen_decls_file(CGenerator *g, ParsedFile *f); -static bool cgen_sdecls_file(CGenerator *g, ParsedFile *f); +static void cgen_sdecls_file(CGenerator *g, ParsedFile *f); #include "cgen.c" #include "sdecls_cgen.c" #include "decls_cgen.c" diff --git a/tokenizer.c b/tokenizer.c index 5a7e272..cd82c81 100644 --- a/tokenizer.c +++ b/tokenizer.c @@ -277,7 +277,7 @@ static Token *tokr_add(Tokenizer *t) { return token; } -static bool tokenize_file(Tokenizer *t, File *file) { +static Status tokenize_file(Tokenizer *t, File *file) { int has_err = 0; t->s = file->contents; t->file = file; @@ -3,8 +3,8 @@ This file is part of toc. toc is distributed under version 3 of the GNU General Public License, without any warranty whatsoever. You should have received a copy of the GNU General Public License along with toc. If not, see <https://www.gnu.org/licenses/>. */ -static bool types_stmt(Typer *tr, Statement *s); -static bool type_resolve(Typer *tr, Type *t, Location where); +static Status types_stmt(Typer *tr, Statement *s); +static Status type_resolve(Typer *tr, Type *t, Location where); static inline void *typer_malloc(Typer *tr, size_t bytes) { @@ -72,7 +72,7 @@ static size_t compiler_alignof_builtin(BuiltinType b) { } /* finds offsets and size */ -static bool struct_find_offsets(StructDef *s) { +static Status struct_find_offsets(StructDef *s) { /* assume the align of a struct is the greatest align out of its children's */ if (!(s->flags & STRUCT_DEF_FOUND_OFFSETS)) { if (s->flags & STRUCT_DEF_FINDING_OFFSETS) { @@ -246,7 +246,7 @@ static bool type_eq(Type *a, Type *b) { } /* expected must equal got, or an error will be produced */ -static bool type_must_eq(Location where, Type *expected, Type *got) { +static Status type_must_eq(Location where, Type *expected, Type *got) { if (!type_eq(expected, got)) { char *str_ex = type_to_str(expected); char *str_got = type_to_str(got); @@ -257,7 +257,7 @@ static bool type_must_eq(Location where, Type *expected, Type *got) { } /* prints an error and returns false if the given expression is not an l-value */ -static bool expr_must_lval(Expression *e) { +static Status expr_must_lval(Expression *e) { /* NOTE: make sure you update eval when you change this */ switch (e->kind) { case EXPR_IDENT: { @@ -359,7 +359,7 @@ enum { TYPE_OF_FN_IS_INSTANCE = 0x01 }; -static bool type_of_fn(Typer *tr, FnExpr *f, Type *t, U16 flags) { +static Status type_of_fn(Typer *tr, FnExpr *f, Type *t, U16 flags) { t->kind = TYPE_FN; t->fn.types = NULL; t->fn.constness = NULL; /* OPTIM: constness doesn't need to be a dynamic array */ @@ -509,7 +509,7 @@ static bool type_of_fn(Typer *tr, FnExpr *f, Type *t, U16 flags) { } /* may modify ident */ -static bool type_of_ident(Typer *tr, Location where, Identifier *ident, Type *t) { +static Status type_of_ident(Typer *tr, Location where, Identifier *ident, Type *t) { t->flags = 0; Identifier i = *ident; #if 0 @@ -660,7 +660,7 @@ static bool type_of_ident(Typer *tr, Location where, Identifier *ident, Type *t) } /* fixes the type (replaces [5+3]int with [8]int, etc.) */ -static bool type_resolve(Typer *tr, Type *t, Location where) { +static Status type_resolve(Typer *tr, Type *t, Location where) { Evaluator *ev = tr->evalr; if (t->flags & TYPE_IS_RESOLVED) return true; t->was_expr = NULL; @@ -817,22 +817,22 @@ static bool type_can_be_truthy(Type *t) { } typedef enum { - STATUS_NONE, - STATUS_WARN, - STATUS_ERR -} Status; + CAST_STATUS_NONE, + CAST_STATUS_WARN, + CAST_STATUS_ERR +} CastStatus; -static Status type_cast_status(Type *from, Type *to) { +static CastStatus type_cast_status(Type *from, Type *to) { assert(from->flags & TYPE_IS_RESOLVED); assert(to->flags & TYPE_IS_RESOLVED); if (to->kind == TYPE_UNKNOWN) - return STATUS_NONE; + return CAST_STATUS_NONE; switch (from->kind) { - case TYPE_UNKNOWN: return STATUS_NONE; + case TYPE_UNKNOWN: return CAST_STATUS_NONE; case TYPE_STRUCT: case TYPE_VOID: - return STATUS_ERR; + return CAST_STATUS_ERR; case TYPE_BUILTIN: switch (from->builtin) { case BUILTIN_I8: @@ -858,24 +858,24 @@ static Status type_cast_status(Type *from, Type *to) { case BUILTIN_F64: case BUILTIN_BOOL: case BUILTIN_CHAR: - return STATUS_NONE; + return CAST_STATUS_NONE; case BUILTIN_TYPE: case BUILTIN_NMS: - return STATUS_ERR; + return CAST_STATUS_ERR; } assert(0); break; case TYPE_UNKNOWN: - return STATUS_NONE; + return CAST_STATUS_NONE; case TYPE_PTR: - return STATUS_WARN; + return CAST_STATUS_WARN; default: - return STATUS_ERR; + return CAST_STATUS_ERR; } break; case BUILTIN_F32: case BUILTIN_F64: - if (to->kind != TYPE_BUILTIN) return STATUS_ERR; + if (to->kind != TYPE_BUILTIN) return CAST_STATUS_ERR; switch (to->builtin) { case BUILTIN_I8: case BUILTIN_U8: @@ -888,50 +888,50 @@ static Status type_cast_status(Type *from, Type *to) { case BUILTIN_F32: case BUILTIN_F64: case BUILTIN_BOOL: - return STATUS_NONE; + return CAST_STATUS_NONE; case BUILTIN_CHAR: case BUILTIN_TYPE: case BUILTIN_NMS: - return STATUS_ERR; + return CAST_STATUS_ERR; } assert(0); break; case BUILTIN_CHAR: if (to->kind == TYPE_BUILTIN && type_builtin_is_int(to->builtin)) - return STATUS_NONE; - return STATUS_ERR; + return CAST_STATUS_NONE; + return CAST_STATUS_ERR; case BUILTIN_BOOL: - return type_can_be_truthy(to) ? STATUS_NONE : STATUS_ERR; + return type_can_be_truthy(to) ? CAST_STATUS_NONE : CAST_STATUS_ERR; case BUILTIN_TYPE: case BUILTIN_NMS: - return STATUS_ERR; + return CAST_STATUS_ERR; } break; - case TYPE_TUPLE: return STATUS_ERR; + case TYPE_TUPLE: return CAST_STATUS_ERR; case TYPE_FN: if (to->kind == TYPE_PTR || to->kind == TYPE_FN) - return STATUS_WARN; - return STATUS_ERR; + return CAST_STATUS_WARN; + return CAST_STATUS_ERR; case TYPE_PTR: if (to->kind == TYPE_BUILTIN && type_builtin_is_int(to->builtin)) - return STATUS_WARN; + return CAST_STATUS_WARN; if (to->kind == TYPE_PTR) - return STATUS_NONE; + return CAST_STATUS_NONE; if (to->kind == TYPE_FN) - return STATUS_WARN; + return CAST_STATUS_WARN; /* TODO: Cast from ptr to arr */ - return STATUS_ERR; + return CAST_STATUS_ERR; case TYPE_ARR: - return STATUS_ERR; + return CAST_STATUS_ERR; case TYPE_SLICE: if (to->kind == TYPE_PTR && type_eq(from->slice, to->ptr)) - return STATUS_NONE; - return STATUS_ERR; + return CAST_STATUS_NONE; + return CAST_STATUS_ERR; case TYPE_EXPR: break; } assert(0); - return STATUS_ERR; + return CAST_STATUS_ERR; } static bool arg_is_const(Expression *arg, Constness constness) { @@ -947,7 +947,7 @@ static bool arg_is_const(Expression *arg, Constness constness) { /* MUST be called after type_of_fn. */ /* pass NULL for instance if this isn't an instance */ -static bool types_fn(Typer *tr, FnExpr *f, Type *t, Instance *instance) { +static Status types_fn(Typer *tr, FnExpr *f, Type *t, Instance *instance) { FnExpr *prev_fn = tr->fn; bool success = true; Expression *ret_expr; @@ -1009,7 +1009,7 @@ static bool types_fn(Typer *tr, FnExpr *f, Type *t, Instance *instance) { } /* puts a dynamic array of the argument indices of the parameters into order. *order must be freed, even if function fails */ -static bool call_arg_param_order(FnExpr *fn, Type *fn_type, Argument *args, Location where, I16 **orderp) { +static Status call_arg_param_order(FnExpr *fn, Type *fn_type, Argument *args, Location where, I16 **orderp) { *orderp = NULL; assert(fn_type->flags & TYPE_IS_RESOLVED); size_t nparams = arr_len(fn_type->fn.types)-1; @@ -1132,7 +1132,7 @@ static bool call_arg_param_order(FnExpr *fn, Type *fn_type, Argument *args, Loca /* *order must be freed, regardless of return value. if (*order)[i] == -1, that parameter was not set. */ -static bool parameterized_struct_arg_order(StructDef *struc, Argument *args, I16 **order, Location where) { +static Status parameterized_struct_arg_order(StructDef *struc, Argument *args, I16 **order, Location where) { size_t nargs = arr_len(args); /* @@ -1336,10 +1336,10 @@ static char *eval_expr_as_cstr(Typer *tr, Expression *e, const char *what_is_thi } -static bool types_expr(Typer *tr, Expression *e) { +static Status types_expr(Typer *tr, Expression *e) { if (e->flags & EXPR_FOUND_TYPE) return true; Type *t = &e->type; - t->flags = 0; + t->flags = TYPE_IS_RESOLVED; t->was_expr = NULL; t->kind = TYPE_UNKNOWN; /* default to unknown type (in the case of an error) */ e->flags |= EXPR_FOUND_TYPE; /* even if failed, pretend we found the type */ @@ -1533,18 +1533,18 @@ static bool types_expr(Typer *tr, Expression *e) { return false; if (!type_resolve(tr, &c->type, e->where)) return false; - Status status = type_cast_status(&c->expr->type, &c->type); - if (status != STATUS_NONE) { + CastStatus status = type_cast_status(&c->expr->type, &c->type); + if (status != CAST_STATUS_NONE) { char *from = type_to_str(&c->expr->type); char *to = type_to_str(&c->type); - if (status == STATUS_ERR) + if (status == CAST_STATUS_ERR) err_print(e->where, "Cannot cast from type %s to %s.", from, to); else warn_print(e->where, "Casting from type %s to %s.", from, to); free(from); free(to); - if (status == STATUS_ERR) + if (status == CAST_STATUS_ERR) return false; } *t = c->type; @@ -2592,7 +2592,7 @@ static bool types_expr(Typer *tr, Expression *e) { } -static bool types_block(Typer *tr, Block *b) { +static Status types_block(Typer *tr, Block *b) { if (b->flags & BLOCK_FOUND_TYPES) return true; @@ -2643,7 +2643,7 @@ static bool types_block(Typer *tr, Block *b) { return success; } -static bool types_decl(Typer *tr, Declaration *d) { +static Status types_decl(Typer *tr, Declaration *d) { if (d->flags & DECL_FOUND_TYPE) return true; bool success = true; @@ -2673,6 +2673,7 @@ static bool types_decl(Typer *tr, Declaration *d) { success = false; goto ret; } + assert(d->expr.type.flags & TYPE_IS_RESOLVED); if (d->flags & DECL_ANNOTATES_TYPE) { if (!type_must_eq(d->expr.where, &d->type, &d->expr.type)) { success = false; @@ -2783,6 +2784,14 @@ static bool types_decl(Typer *tr, Declaration *d) { goto ret; } } + if (d->flags & DECL_IS_CONST) { + if (d->type.kind == TYPE_PTR) { + err_print(d->where, "You can't have a constant pointer."); + success = false; + goto ret; + } + } + if (n_idents == 1 && (d->flags & DECL_HAS_EXPR) && d->expr.kind == EXPR_NMS) { bool is_at_top_level = true; typedef Block *BlockPtr; @@ -2811,7 +2820,7 @@ static bool types_decl(Typer *tr, Declaration *d) { return success; } -static bool types_stmt(Typer *tr, Statement *s) { +static Status types_stmt(Typer *tr, Statement *s) { if (s->flags & STMT_TYPED) return true; switch (s->kind) { case STMT_EXPR: @@ -2914,7 +2923,7 @@ static void typer_create(Typer *tr, Evaluator *ev, ErrCtx *err_ctx, Allocator *a *(Block **)arr_adda(&tr->blocks, allocr) = NULL; } -static bool types_file(Typer *tr, ParsedFile *f) { +static Status types_file(Typer *tr, ParsedFile *f) { bool ret = true; tr->parsed_file = f; arr_foreach(f->stmts, Statement, s) { @@ -64,6 +64,11 @@ typedef U8 bool; #define true ((bool)1) #endif +#if defined __GNUC__ && !defined NO_WARN_UNUSED_RESULT +#define Status bool __attribute__((warn_unused_result)) +#else +#define Status bool +#endif typedef int8_t I8; #define I8_MAX INT8_MAX @@ -923,7 +928,6 @@ typedef struct CGenerator { Block *block; Namespace *nms; FnExpr *fn; /* which function are we in? (NULL for none) - not used during decls */ - Evaluator *evalr; Identifier main_ident; Identifiers *globals; char *nms_prefix; /* dynamic (null-terminated) array of characters, the current namespace C prefix (e.g. "foo__bar__") */ |