diff options
-rw-r--r-- | cgen.c | 530 | ||||
-rw-r--r-- | decls_cgen.c | 420 | ||||
-rw-r--r-- | main.c | 7 | ||||
-rw-r--r-- | parse.c | 4 | ||||
-rw-r--r-- | test.toc | 15 | ||||
-rw-r--r-- | toc.c | 3 | ||||
-rw-r--r-- | types.c | 239 | ||||
-rw-r--r-- | types.h | 37 |
8 files changed, 403 insertions, 852 deletions
@@ -33,165 +33,6 @@ static void cgen_ret(CGenerator *g, Block *returning_from, Expression *ret_expr) static void cgen_val(CGenerator *g, Value *v, Type *t); static void cgen_val_pre(CGenerator *g, Value *v, Type *t); static void cgen_val_ptr(CGenerator *g, void *v, Type *t); -static void cgen_defs_block(CGenerator *g, Block *b); -static void cgen_defs_decl(CGenerator *g, Declaration *d); - -#define cgen_recurse_subexprs_fn_simple(fn, decl_f, block_f, type_f) \ - if (!(fn->flags & FN_EXPR_FOREIGN)) { \ - FnExpr *prev_fn = g->f##n; \ - Block *prev_block = g->block; \ - g->f##n = fn; \ - g->block = &fn->body; \ - arr_foreach(fn->params, Declaration, param) \ - decl_f(g, param); \ - if (fn->ret_decls) { \ - arr_foreach(fn->ret_decls, Declaration, r) \ - decl_f(g, r); \ - } else { \ - type_f(g, &fn->ret_type); \ - } \ - block_f(g, &fn->body); \ - g->f##n = prev_fn; \ - g->block = prev_block; \ - } - -/* calls f on every sub-expression of e, block_f on every sub-block, type_f on every type, and decl_f on every sub-declaration. */ -#define cgen_recurse_subexprs(g, e, f, block_f, decl_f, type_f) \ - switch (e->kind) { \ - case EXPR_VAL: \ - case EXPR_C: \ - case EXPR_BUILTIN: \ - case EXPR_IDENT: \ - case EXPR_LITERAL_BOOL: \ - case EXPR_LITERAL_INT: \ - case EXPR_LITERAL_STR: \ - case EXPR_LITERAL_CHAR: \ - case EXPR_LITERAL_FLOAT: \ - break; \ - case EXPR_TYPE: \ - type_f(g, e->typeval); \ - break; \ - case EXPR_UNARY_OP: \ - f(g, e->unary.of); \ - break; \ - case EXPR_BINARY_OP: \ - f(g, e->binary.lhs); \ - if (e->binary.op != BINARY_DOT) \ - f(g, e->binary.rhs); \ - break; \ - case EXPR_CAST: \ - f(g, e->cast.expr); \ - type_f(g, &e->cast.type); \ - break; \ - case EXPR_CALL: \ - f(g, e->call.fn); \ - arr_foreach(e->call.arg_exprs, Expression, arg) \ - f(g, arg); \ - break; \ - case EXPR_BLOCK: \ - block_f(g, e->block); \ - break; \ - case EXPR_NMS: { \ - Namespace *prev = g->nms; \ - g->nms = e->nms; \ - block_f(g, &e->nms->body); \ - g->nms = prev; \ - } break; \ - case EXPR_IF: { \ - IfExpr *i = e->if_; \ - if (i->cond) \ - f(g, i->cond); \ - block_f(g, &i->body); \ - if (i->next_elif) \ - f(g, i->next_elif); \ - } break; \ - case EXPR_WHILE: { \ - WhileExpr *w = e->while_; \ - f(g, w->cond); \ - block_f(g, &w->body); \ - } break; \ - case EXPR_FOR: { \ - ForExpr *fo = e->for_; \ - if (fo->flags & FOR_IS_RANGE) { \ - f(g, fo->range.from); \ - if (fo->range.to) f(g, fo->range.to); \ - /* step is a value, not an expression */ \ - } else { \ - f(g, fo->of); \ - } \ - block_f(g, &fo->body); \ - } break; \ - case EXPR_TUPLE: \ - arr_foreach(e->tuple, Expression, x) \ - f(g, x); \ - break; \ - case EXPR_SLICE: \ - f(g, e->slice.of); \ - if (e->slice.from) f(g, e->slice.from); \ - if (e->slice.to) f(g, e->slice.to); \ - break; \ - case EXPR_FN: { \ - FnExpr *fn = e->fn; \ - if (fn_has_instances(fn)) { \ - Instance **data = fn->instances->data; \ - for (U64 i = 0; i < fn->instances->cap; ++i) { \ - if (fn->instances->occupied[i]) { \ - cgen_recurse_subexprs_fn_simple(((*data)->fn), decl_f, block_f, type_f); \ - } \ - ++data; \ - } \ - } else { \ - cgen_recurse_subexprs_fn_simple(fn, decl_f, block_f, type_f); \ - } \ - } break; \ - } - -#include <signal.h> - -#define cgen_recurse_subtypes(g, type, f, decl_f, block_f, struct_flag) \ - switch (type->kind) { \ - case TYPE_STRUCT: { \ - StructDef *struc = type->struc; \ - if (!(struc->flags & struct_flag)) { \ - struc->flags |= struct_flag; \ - if (struc->params) { \ - if (struct_is_template(struc)) break; \ - arr_foreach(struc->params, Declaration, param) \ - decl_f(g, param); \ - } \ - block_f(g, &struc->body); \ - } \ - } break; \ - case TYPE_FN: \ - if (type->kind == TYPE_FN && (type->fn.constness || fn_type_has_varargs(&type->fn))) { \ - /* we don't want to do this, because it's a template-y thing */ \ - } \ - else { \ - arr_foreach(type->fn.types, Type, sub) { \ - f(g, sub); \ - } \ - } \ - break; \ - case TYPE_TUPLE: \ - arr_foreach(type->tuple, Type, sub) \ - f(g, sub); \ - break; \ - case TYPE_ARR: \ - f(g, type->arr.of); \ - break; \ - case TYPE_SLICE: \ - f(g, type->slice); \ - break; \ - case TYPE_PTR: \ - f(g, type->ptr); \ - break; \ - case TYPE_BUILTIN: \ - case TYPE_UNKNOWN: \ - break; \ - case TYPE_EXPR: assert(0); \ - } - - static inline FILE *cgen_writing_to(CGenerator *g) { return g->outc; /* for now */ @@ -284,7 +125,7 @@ static inline void cgen_char(CGenerator *g, char c) { } /* should this declaration be a direct function declaration C? (as opposed to using a function pointer or not being a function) */ static bool cgen_fn_is_direct(CGenerator *g, Declaration *d) { - return (!g->block || g->block->kind == BLOCK_NMS) && (d->flags & DECL_HAS_EXPR) && d->expr.kind == EXPR_FN && arr_len(d->idents) == 1; + return (!g->block || g->block->kind == BLOCK_NMS) && (d->flags & DECL_IS_CONST) && (d->flags & DECL_HAS_EXPR) && d->expr.kind == EXPR_FN && arr_len(d->idents) == 1; } static bool fn_has_instances(FnExpr *f) { @@ -487,20 +328,17 @@ static void cgen_ctype(CGenerator *g, CType *c) { } } - - -static inline void cgen_fn_instance_number(CGenerator *g, U64 instance) { - cgen_write(g, U64_FMT "_", instance); -} static inline void cgen_fn_name(CGenerator *g, FnExpr *f) { if (f->c.name) { cgen_ident(g, f->c.name); + if (f->instance_id) { + cgen_write(g, U64_FMT "_", f->instance_id); + } } else { + assert(!fn_is_template(f)); + assert(f->c.id); cgen_ident_id(g, f->c.id); } - if (f->instance_id) { - cgen_fn_instance_number(g, f->instance_id); - } } /* should we generate this function? (or is it just meant for compile time) */ @@ -645,13 +483,12 @@ static inline bool cgen_is_type_simple(Type *t) { return t->kind == TYPE_BUILTIN || t->kind == TYPE_FN; } -static void cgen_fn_params(CGenerator *g, FnExpr *f, U64 which_are_const) { +static void cgen_fn_params(CGenerator *g, FnExpr *f) { bool out_param = cgen_uses_ptr(&f->ret_type); cgen_write(g, "("); - int semi_const_idx = 0; bool any_params = false; arr_foreach(f->params, Declaration, d) { - if (d->flags & DECL_IS_CONST) continue; + if (d->flags & DECL_FOUND_VAL) continue; if (type_is_builtin(&d->type, BUILTIN_VARARGS)) { int idx = 0; arr_foreach(d->val.varargs, VarArg, varg) { @@ -665,9 +502,6 @@ static void cgen_fn_params(CGenerator *g, FnExpr *f, U64 which_are_const) { cgen_type_post(g, varg->type); ++idx; } - } else if ((d->flags & DECL_SEMI_CONST) - && (which_are_const & (((U64)1) << semi_const_idx++))) { - /* semi constant argument is constant */ } else { int idx = 0; arr_foreach(d->idents, Identifier, i) { @@ -733,7 +567,7 @@ static inline void cgen_arg(CGenerator *g, Expression *arg) { } /* unless f has const/semi-const args, which_are_const can be set to 0 */ -static void cgen_fn_header(CGenerator *g, FnExpr *f, U64 which_are_const) { +static void cgen_fn_header(CGenerator *g, FnExpr *f) { assert(!(f->flags & FN_EXPR_FOREIGN)); bool out_param = cgen_uses_ptr(&f->ret_type); @@ -747,7 +581,7 @@ static void cgen_fn_header(CGenerator *g, FnExpr *f, U64 which_are_const) { cgen_write(g, " "); } cgen_fn_name(g, f); - cgen_fn_params(g, f, which_are_const); + cgen_fn_params(g, f); if (!out_param) { cgen_type_post(g, &f->ret_type); } @@ -908,8 +742,6 @@ static void cgen_set_tuple(CGenerator *g, Expression *exprs, Identifier *idents, cgen_expr_pre(g, to->call.fn); cgen_expr(g, to->call.fn); - if (to->call.instance) - cgen_fn_instance_number(g, to->call.instance->fn->instance_id); cgen_write(g, "("); bool any_args = false; i = 0; @@ -1081,9 +913,6 @@ static void cgen_expr_pre(CGenerator *g, Expression *e) { cgen_write(g, "; "); } cgen_expr(g, e->call.fn); - if (e->call.instance) { - cgen_fn_instance_number(g, e->call.instance->fn->instance_id); - } cgen_write(g, "("); bool any_args = false; i = 0; @@ -1110,9 +939,6 @@ static void cgen_expr_pre(CGenerator *g, Expression *e) { cgen_type_post(g, &e->type); cgen_write(g, ";"); cgen_nl(g); cgen_expr(g, e->call.fn); - if (e->call.instance) { - cgen_fn_instance_number(g, e->call.instance->fn->instance_id); - } cgen_write(g, "("); bool any_args = false; i = 0; @@ -1281,16 +1107,7 @@ static void cgen_expr(CGenerator *g, Expression *e) { int index = decl_ident_index(d, i); Value fn_val = *decl_val_at_index(d, index); FnExpr *fn = fn_val.fn; - Expression fn_expr; - /* @TODO: is this all really necessary? */ - - fn_expr.kind = EXPR_FN; - fn_expr.fn = allocr_malloc(g->allocr, sizeof *fn_expr.fn); - *fn_expr.fn = *fn; - fn_expr.flags = EXPR_FOUND_TYPE; - fn_expr.type = *decl_type_at_index(d, index); - - cgen_expr(g, &fn_expr); + cgen_fn_name(g, fn); handled = true; } } @@ -1684,9 +1501,6 @@ static void cgen_expr(CGenerator *g, Expression *e) { } else { FnType *fn_type = &e->call.fn->type.fn; cgen_expr(g, e->call.fn); - if (e->call.instance) { - cgen_fn_instance_number(g, e->call.instance->fn->instance_id); - } cgen_write(g, "("); bool first_arg = true; size_t i = 0; @@ -1854,68 +1668,60 @@ static void cgen_zero_value(CGenerator *g, Type *t) { compile_time_args is needed because we can't determine which_are_const from just f. */ -static void cgen_fn(CGenerator *g, FnExpr *f, Value *compile_time_args) { +static void cgen_fn(CGenerator *g, FnExpr *f) { if (f->flags & FN_EXPR_FOREIGN) - return; /* handled by decls_cgen */ - /* see also cgen_defs_expr */ - U64 which_are_const = compile_time_args ? compile_time_args->u64 : 0; + return; /* handled by cgen_fn_decl */ if (!cgen_should_gen_fn(f)) return; FnExpr *prev_fn = g->fn; Block *prev_block = g->block; g->fn = f; g->block = &f->body; - cgen_fn_header(g, f, which_are_const); + cgen_fn_header(g, f); cgen_write(g, " {"); cgen_nl(g); - if (compile_time_args) { - ++compile_time_args; /* move past which_are_const */ - int semi_const_idx = 0; - arr_foreach(f->params, Declaration, param) { - if ((param->flags & DECL_IS_CONST) - || ((param->flags & DECL_SEMI_CONST) - && (which_are_const & (((U64)1) << semi_const_idx++)))) { - int i = 0; - if (type_is_builtin(¶m->type, BUILTIN_VARARGS)) { - VarArg *vararg = param->val.varargs; - size_t nvarargs = arr_len(vararg); - for (size_t v = 0; v < nvarargs; ++v, ++vararg) { - Type *type = vararg->type; - Value *arg = &vararg->val; - if (!type_is_compileonly(type)) { - cgen_val_pre(g, arg, type); - cgen_type_pre(g, type); - cgen_write(g, " const "); - assert(arr_len(param->idents) == 1); - cgen_ident(g, param->idents[0]); - cgen_write(g, "%lu_", (unsigned long)v); - cgen_type_post(g, type); - cgen_write(g, " = "); - cgen_val(g, arg, type); - cgen_writeln(g, ";"); - } + arr_foreach(f->params, Declaration, param) { + if (param->flags & DECL_FOUND_VAL) { + int i = 0; + if (type_is_builtin(¶m->type, BUILTIN_VARARGS)) { + VarArg *vararg = param->val.varargs; + size_t nvarargs = arr_len(vararg); + for (size_t v = 0; v < nvarargs; ++v, ++vararg) { + Type *type = vararg->type; + Value *arg = &vararg->val; + if (!type_is_compileonly(type)) { + cgen_val_pre(g, arg, type); + cgen_type_pre(g, type); + cgen_write(g, " const "); + assert(arr_len(param->idents) == 1); + cgen_ident(g, param->idents[0]); + cgen_write(g, "%lu_", (unsigned long)v); + cgen_type_post(g, type); + cgen_write(g, " = "); + cgen_val(g, arg, type); + cgen_writeln(g, ";"); } - } else { - arr_foreach(param->idents, Identifier, ident) { - Type *type = decl_type_at_index(param, i); - Value *arg = decl_val_at_index(param, i); - if (!type_is_compileonly(type)) { - cgen_val_pre(g, arg, type); - cgen_type_pre(g, type); - cgen_write(g, " const "); - cgen_ident(g, *ident); - cgen_type_post(g, type); - cgen_write(g, " = "); - cgen_val(g, arg, type); - cgen_writeln(g, ";"); - } - ++i; + } + } else { + arr_foreach(param->idents, Identifier, ident) { + Type *type = decl_type_at_index(param, i); + Value *arg = decl_val_at_index(param, i); + if (!type_is_compileonly(type)) { + cgen_val_pre(g, arg, type); + cgen_type_pre(g, type); + cgen_write(g, " const "); + cgen_ident(g, *ident); + cgen_type_post(g, type); + cgen_write(g, " = "); + cgen_val(g, arg, type); + cgen_writeln(g, ";"); } + ++i; } } } - } + /* retdecls need to be after compile time arguments to allow fn(x::int) y := x */ arr_foreach(f->ret_decls, Declaration, d) { cgen_decl(g, d); @@ -1935,7 +1741,7 @@ static void cgen_decl(CGenerator *g, Declaration *d) { return; /* already dealt with */ int has_expr = d->flags & DECL_HAS_EXPR; if (cgen_fn_is_direct(g, d)) - return; /* dealt with in cgen_defs_ */ + return; /* dealt with in the loop that defines all the functions in cgen_file */ if (d->flags & DECL_FOUND_VAL) { /* declarations where we use a value */ for (int idx = 0, nidents = (int)arr_len(d->idents); idx < nidents; ++idx) { @@ -2168,90 +1974,113 @@ static void cgen_stmt(CGenerator *g, Statement *s) { } } -static void cgen_defs_type(CGenerator *g, Type *t) { - cgen_recurse_subtypes(g, t, cgen_defs_type, cgen_defs_decl, cgen_defs_block, STRUCT_DEF_CGEN_FN_DEFS); -} - -static void cgen_defs_fn(CGenerator *g, FnExpr *f) { - if (fn_has_instances(f)) { - HashTable *instances = f->instances; - /* generate each instance */ - Instance **is = instances->data; - for (U64 i = 0; i < instances->cap; ++i) { - if (instances->occupied[i]) { - /* generate this instance */ - cgen_fn(g, is[i]->fn, is[i]->val.tuple); +static void cgen_fn_decl(CGenerator *g, FnExpr *f) { + if (f->flags & FN_EXPR_FOREIGN) { + Type *t = &f->foreign.type; + /* foreign function declaration */ + cgen_write(g, "extern "); + Type *fn_types = t->fn.types; + const char *foreign_name = f->foreign.name; + CType *ctypes = f->foreign.ctypes; + if (ctypes[0].kind == CTYPE_NONE) { + cgen_type_pre(g, &fn_types[0]); + } else { + cgen_ctype(g, &ctypes[0]); + } + cgen_write(g, " %s", foreign_name); + cgen_write(g, "("); + + for (size_t i = 1; i < arr_len(fn_types); ++i) { + if (i > 1) + cgen_write(g, ", "); + CType *csub = &ctypes[i]; + if (csub->kind == CTYPE_NONE) { + Type *sub = &fn_types[i]; + cgen_type_pre(g, sub); + cgen_type_post(g, sub); + } else { + cgen_ctype(g, csub); } } - } else { - cgen_fn(g, f, NULL); - } -} - -static void cgen_defs_expr(CGenerator *g, Expression *e) { - if (e->kind == EXPR_FN) { - cgen_defs_fn(g, e->fn); - } - cgen_recurse_subexprs(g, e, cgen_defs_expr, cgen_defs_block, cgen_defs_decl, cgen_defs_type); -} + cgen_write(g, ")"); + if (ctypes[0].kind == CTYPE_NONE) + cgen_type_post(g, &fn_types[0]); + cgen_write(g, ";"); -static void cgen_defs_decl(CGenerator *g, Declaration *d) { - if (d->flags & DECL_HAS_EXPR) { - cgen_defs_expr(g, &d->expr); + if (!f->c.name || !ident_eq_str(f->c.name, foreign_name) || g->nms != NULL) { + cgen_write(g, "static "); + if (ctypes[0].kind == CTYPE_NONE) { + cgen_type_pre(g, &fn_types[0]); + } else { + cgen_ctype(g, &ctypes[0]); + } + + cgen_write(g, " (* const "); + cgen_fn_name(g, f); + cgen_write(g, ")("); + for (size_t i = 1; i < arr_len(fn_types); ++i) { + if (i > 1) + cgen_write(g, ", "); + CType *csub = &ctypes[i]; + if (csub->kind == CTYPE_NONE) { + Type *sub = &fn_types[i]; + cgen_type_pre(g, sub); + cgen_type_post(g, sub); + } else { + cgen_ctype(g, csub); + } + } + cgen_write(g, ")"); + if (ctypes[0].kind == CTYPE_NONE) + cgen_type_post(g, &fn_types[0]); + cgen_write(g, "= %s;", foreign_name); + } + cgen_nl(g); + return; } - if (d->flags & DECL_ANNOTATES_TYPE) - cgen_defs_type(g, &d->type); /* we only need to do this if d has an annotated type, because otherwise we've already generated the defs for that type (because it can't be a new type) */ -} - - -static void cgen_defs_stmt(CGenerator *g, Statement *s) { - switch (s->kind) { - case STMT_DECL: - cgen_defs_decl(g, s->decl); - break; - case STMT_EXPR: - cgen_defs_expr(g, s->expr); - break; - case STMT_RET: - if (s->ret->flags & RET_HAS_EXPR) - cgen_defs_expr(g, &s->ret->expr); - break; - case STMT_BREAK: - case STMT_CONT: - case STMT_MESSAGE: - break; - case STMT_DEFER: - cgen_defs_stmt(g, s->defer); - break; - case STMT_USE: - cgen_defs_expr(g, &s->use->expr); - break; - case STMT_INLINE_BLOCK: - arr_foreach(s->inline_block, Statement, sub) - cgen_defs_stmt(g, sub); - break; - case STMT_INCLUDE: - assert(0); - break; + if (cgen_should_gen_fn(f)) { + cgen_fn_header(g, f); + cgen_write(g, ";"); + cgen_nl(g); } } -static void 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 - */ - Block *prev_block = g->block; - g->block = b; - b->deferred = NULL; - arr_foreach(b->stmts, Statement, s) { - cgen_defs_stmt(g, s); +static void cgen_global_decl(CGenerator *g, Declaration *d) { + if (cgen_fn_is_direct(g, d)) { + /* handled by cgen_fn_decl */ + } else { + /* global variables */ + for (int i = 0, n_idents = (int)arr_len(d->idents); i < n_idents; ++i) { + Identifier ident = d->idents[i]; + Type *type = decl_type_at_index(d, i); + Value *val = NULL; + if (d->flags & DECL_HAS_EXPR) + assert(d->flags & DECL_FOUND_VAL); + if (d->flags & DECL_FOUND_VAL) + val = decl_val_at_index(d, i); + if (!type_is_compileonly(type)) { + if (val) cgen_val_pre(g, val, type); + if (!(d->flags & DECL_EXPORT)) + cgen_write(g, "static "); + cgen_type_pre(g, type); + cgen_write(g, " "); + cgen_ident(g, ident); + cgen_type_post(g, type); + if (val) { + cgen_write(g, " = "); + cgen_val(g, val, type); + } else { + cgen_write(g, " = "); + cgen_zero_value(g, type); + } + cgen_write(g, ";"); + cgen_nl(g); + } + } } - if (b->ret_expr) cgen_defs_expr(g, b->ret_expr); - g->block = prev_block; } -static void cgen_file(CGenerator *g, ParsedFile *f) { +static void cgen_file(CGenerator *g, ParsedFile *f, Typer *tr) { g->block = NULL; g->nms = NULL; g->fn = NULL; @@ -2289,14 +2118,69 @@ static void cgen_file(CGenerator *g, ParsedFile *f) { "#define platform__ " stringify(PLATFORM_OTHER) "\n" "#endif\n" "static slice_ mkslice_(void *data, i64 len) { slice_ ret; ret.data = data; ret.len = len; return ret; }\n"); + cgen_write(g, "/* types */\n"); + /* struct declarations */ + arr_foreach(tr->all_structs, StructDefPtr, sdefp) { + StructDef *sdef = *sdefp; + cgen_write(g, "struct "); + if (!sdef->name) { + sdef->c.id = ++g->ident_counter; + } + cgen_struct_name(g, sdef); + cgen_write(g, ";"); + cgen_nl(g); + } + + /* struct definitions */ + arr_foreach(tr->all_structs, StructDefPtr, sdefp) { + StructDef *sdef = *sdefp; + cgen_write(g, "struct "); + cgen_struct_name(g, sdef); + cgen_write(g, "{"); + cgen_nl(g); + ++g->indent_lvl; + arr_foreach(sdef->fields, Field, field) { + cgen_type_pre(g, field->type); + cgen_write(g, " "); + cgen_ident_simple(g, field->name); + cgen_type_post(g, field->type); + cgen_write(g, ";"); + cgen_nl(g); + } + --g->indent_lvl; + cgen_write(g, "};"); + cgen_nl(g); + } + + cgen_write(g, "/* declarations */\n"); + /* function declarations */ + arr_foreach(tr->all_fns, FnWithCtx, fn_ctx) { + g->nms = fn_ctx->nms; + g->block = fn_ctx->block; + FnExpr *fn = fn_ctx->fn; + if (!fn->c.name) { + fn->c.id = ++g->ident_counter; + } + cgen_fn_decl(g, fn); + } + + /* global (non-function) declarations */ + arr_foreach(tr->all_globals, DeclWithCtx, dctx) { + g->nms = dctx->nms; + g->block = dctx->block; + cgen_global_decl(g, dctx->d); + } - cgen_sdecls_file(g, f); - cgen_decls_file(g, f); cgen_write(g, "/* code */\n"); cgen_write(g, "int main() {\n\tmain_();\n\treturn 0;\n}\n\n"); - arr_foreach(f->stmts, Statement, s) { - cgen_defs_stmt(g, s); + /* function definitions */ + arr_foreach(tr->all_fns, FnWithCtx, fn_ctx) { + g->nms = fn_ctx->nms; + g->block = fn_ctx->block; + cgen_fn(g, fn_ctx->fn); } + g->nms = NULL; + g->block = NULL; arr_foreach(f->stmts, Statement, s) { cgen_stmt(g, s); diff --git a/decls_cgen.c b/decls_cgen.c deleted file mode 100644 index 67e6a80..0000000 --- a/decls_cgen.c +++ /dev/null @@ -1,420 +0,0 @@ -/* - Copyright (C) 2019, 2020 Leo Tenenbaum. - 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_sdecls_stmt(CGenerator *g, Statement *s); -static void cgen_sdecls_decl(CGenerator *g, Declaration *d); -static void cgen_sdecls_expr(CGenerator *g, Expression *e); -static void cgen_decls_stmt(CGenerator *g, Statement *s); -static void cgen_decls_block(CGenerator *g, Block *b); -static void cgen_decls_decl(CGenerator *g, Declaration *d); - -static void cgen_sdecls_block(CGenerator *g, Block *b) { - Block *prev_block = g->block; - g->block = b; - b->c.break_lbl = 0; - b->c.cont_lbl = 0; - - arr_foreach(b->stmts, Statement, s) - cgen_sdecls_stmt(g, s); - if (b->ret_expr) - cgen_sdecls_expr(g, b->ret_expr); - g->block = prev_block; -} - -/* i is the name for this type, NULL if not available */ -static void cgen_sdecls_type(CGenerator *g, Type *type) { - if (type->kind == TYPE_STRUCT) { - StructDef *sdef = type->struc; - /* we'll actually define the struct later; here we can just declare it */ - - if ((sdef->flags & STRUCT_DEF_RESOLVED) && !(sdef->flags & STRUCT_DEF_CGEN_DECLARED)) { - cgen_write(g, "struct "); - if (!sdef->name) { - sdef->c.id = ++g->ident_counter; - } - cgen_struct_name(g, sdef); - cgen_write(g, ";"); - cgen_nl(g); - /* we don't need to set the STRUCT_DEF_CGEN_DECLARED flag; that's done in cgen_recurse_subtypes */ - } - } - cgen_recurse_subtypes(g, type, cgen_sdecls_type, cgen_sdecls_decl, cgen_sdecls_block, STRUCT_DEF_CGEN_DECLARED); -} - -static char *cgen_nms_prefix_part(CGenerator *g, Namespace *n) { - char *s; - if (n->associated_ident) { - size_t ident_len = n->associated_ident->len; - s = malloc(ident_len + 3); - memcpy(s, n->associated_ident->str, ident_len); - s[ident_len] = '_'; - s[ident_len+1] = '_'; - s[ident_len+2] = '\0'; - } else { - s = calloc(CGEN_IDENT_ID_STR_SIZE + 3, 1); - cgen_ident_id_to_str(s, ++g->ident_counter); - size_t len = strlen(s); - s[len] = '_'; - s[len+1] = '_'; - s[len+2] = '\0'; - } - return s; -} - -static void cgen_sdecls_expr(CGenerator *g, Expression *e) { - switch (e->kind) { - case EXPR_FN: - /* needs to go before decls_cgen.c... */ - e->fn->c.id = ++g->ident_counter; - break; - case EXPR_TYPE: - cgen_sdecls_type(g, e->typeval); - break; - case EXPR_NMS: { - char *prefix_part = cgen_nms_prefix_part(g, e->nms); - size_t prefix_part_len = strlen(prefix_part); - const char *prev_prefix = g->nms_prefixes ? arr_last(g->nms_prefixes) - : ""; - size_t prev_prefix_len = strlen(prev_prefix); - char *new_prefix = cgen_malloc(g, prev_prefix_len + prefix_part_len + 1); - memcpy(new_prefix, prev_prefix, prev_prefix_len); - memcpy(new_prefix + prev_prefix_len, prefix_part, prefix_part_len); - free(prefix_part); - arr_add(g->nms_prefixes, new_prefix); - new_prefix[prev_prefix_len + prefix_part_len] = 0; - e->nms->c.prefix = new_prefix; - } break; - default: break; - } - if (e->kind != EXPR_IDENT) { - cgen_recurse_subexprs(g, e, cgen_sdecls_expr, cgen_sdecls_block, cgen_sdecls_decl, cgen_sdecls_type); - } - if (e->kind == EXPR_NMS) { - arr_remove_last(g->nms_prefixes); - } -} - - -static void cgen_sdecls_decl(CGenerator *g, Declaration *d) { - cgen_sdecls_type(g, &d->type); - if (cgen_fn_is_direct(g, d)) { - d->expr.fn->c.name = d->idents[0]; - } - for (int idx = 0; idx < (int)arr_len(d->idents); ++idx) { - Type *type = decl_type_at_index(d, idx); - - if (type_is_builtin(type, BUILTIN_TYPE) && !(d->flags & DECL_IS_PARAM)) { - Value *val = decl_val_at_index(d, idx); - cgen_sdecls_type(g, val->type); - } - } - if (d->flags & DECL_HAS_EXPR) { - cgen_sdecls_expr(g, &d->expr); - if (d->flags & DECL_EXPORT) { - if (d->expr.kind == EXPR_FN) - d->expr.fn->flags |= FN_EXPR_EXPORT; - } - } -} - -static void cgen_sdecls_stmt(CGenerator *g, Statement *s) { - switch (s->kind) { - case STMT_DECL: - cgen_sdecls_decl(g, s->decl); - break; - case STMT_EXPR: - cgen_sdecls_expr(g, s->expr); - break; - case STMT_RET: { - Return *r = s->ret; - if (r->flags & RET_HAS_EXPR) - cgen_sdecls_expr(g, &r->expr); - } break; - case STMT_BREAK: - if (!s->referring_to->c.break_lbl) { - s->referring_to->c.break_lbl = ++g->lbl_counter; - } - break; - case STMT_CONT: - if (!s->referring_to->c.cont_lbl) { - s->referring_to->c.cont_lbl = ++g->lbl_counter; - } - break; - case STMT_MESSAGE: - break; - case STMT_DEFER: - cgen_sdecls_stmt(g, s->defer); - break; - case STMT_USE: - cgen_sdecls_expr(g, &s->use->expr); - break; - case STMT_INLINE_BLOCK: - arr_foreach(s->inline_block, Statement, sub) - cgen_sdecls_stmt(g, sub); - break; - case STMT_INCLUDE: - assert(0); - break; - } -} - -static void cgen_sdecls_file(CGenerator *g, ParsedFile *f) { - arr_foreach(f->stmts, Statement, s) { - cgen_sdecls_stmt(g, s); - } -} - -static void cgen_decls_type(CGenerator *g, Type *type) { - /* this check needs to go before cgen_recurse_subtypes, because that sets the STRUCT_DEF_CGEN_DEFINED flag */ - bool need_to_generate_struct_definition = type->kind == TYPE_STRUCT && !(type->struc->flags & STRUCT_DEF_CGEN_DEFINED) - && !struct_is_template(type->struc); - /* - this has to go BEFORE defining the struct, so that if it has struct fields, they're defined before it is, - because - struct Foo; - struct Bar { - struct Foo f; - } - struct Foo { - int x; - } - does not work in C - */ - cgen_recurse_subtypes(g, type, cgen_decls_type, cgen_decls_decl, cgen_decls_block, STRUCT_DEF_CGEN_DEFINED); - - if (need_to_generate_struct_definition) { - StructDef *sdef = type->struc; - /* generate struct definition */ - cgen_write(g, "struct "); - cgen_struct_name(g, sdef); - cgen_write(g, "{"); - cgen_nl(g); - ++g->indent_lvl; - arr_foreach(sdef->fields, Field, f) { - cgen_type_pre(g, f->type); - cgen_write(g, " "); - cgen_ident_simple(g, f->name); - cgen_type_post(g, f->type); - cgen_write(g, ";"); - cgen_nl(g); - } - --g->indent_lvl; - cgen_write(g, "};"); - cgen_nl(g); - /* we don't need to set the STRUCT_DEF_CGEN_DEFINED flag; that's done in cgen_recurse_subtypes */ - } -} - -static void cgen_single_fn_decl(CGenerator *g, FnExpr *f, U64 which_are_const) { - if (cgen_should_gen_fn(f)) { - cgen_fn_header(g, f, which_are_const); - cgen_write(g, ";"); - cgen_nl(g); - } -} - - -static void 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]) { - if (cgen_should_gen_fn((*data)->fn)) { - (*data)->fn->c.name = f->c.name; - (*data)->fn->c.id = f->c.id; - cgen_single_fn_decl(g, (*data)->fn, (*data)->val.tuple[0].u64); - cgen_write(g, ";"); - cgen_nl(g); - } - } - ++data; - } -} - -static void cgen_fn_decl(CGenerator *g, FnExpr *f, Type *t) { - if (f->flags & FN_EXPR_FOREIGN) { - - /* foreign function declaration */ - cgen_write(g, "extern "); - Type *fn_types = t->fn.types; - const char *foreign_name = f->foreign.name; - CType *ctypes = f->foreign.ctypes; - if (ctypes[0].kind == CTYPE_NONE) { - cgen_type_pre(g, &fn_types[0]); - } else { - cgen_ctype(g, &ctypes[0]); - } - cgen_write(g, " %s", foreign_name); - cgen_write(g, "("); - - for (size_t i = 1; i < arr_len(fn_types); ++i) { - if (i > 1) - cgen_write(g, ", "); - CType *csub = &ctypes[i]; - if (csub->kind == CTYPE_NONE) { - Type *sub = &fn_types[i]; - cgen_type_pre(g, sub); - cgen_type_post(g, sub); - } else { - cgen_ctype(g, csub); - } - } - cgen_write(g, ")"); - if (ctypes[0].kind == CTYPE_NONE) - cgen_type_post(g, &fn_types[0]); - cgen_write(g, ";"); - - if (!f->c.name || !ident_eq_str(f->c.name, foreign_name) || g->nms != NULL) { - cgen_write(g, "static "); - if (ctypes[0].kind == CTYPE_NONE) { - cgen_type_pre(g, &fn_types[0]); - } else { - cgen_ctype(g, &ctypes[0]); - } - - cgen_write(g, " (* const "); - cgen_fn_name(g, f); - cgen_write(g, ")("); - for (size_t i = 1; i < arr_len(fn_types); ++i) { - if (i > 1) - cgen_write(g, ", "); - CType *csub = &ctypes[i]; - if (csub->kind == CTYPE_NONE) { - Type *sub = &fn_types[i]; - cgen_type_pre(g, sub); - cgen_type_post(g, sub); - } else { - cgen_ctype(g, csub); - } - } - cgen_write(g, ")"); - if (ctypes[0].kind == CTYPE_NONE) - cgen_type_post(g, &fn_types[0]); - cgen_write(g, "= %s;", foreign_name); - } - cgen_nl(g); - return; - } - if (fn_has_instances(f)) { - cgen_decls_fn_instances(g, f); - } else { - cgen_single_fn_decl(g, f, 0); - } -} - -static void 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, cgen_decls_type); - switch (e->kind) { - case EXPR_FN: { - FnExpr *f = e->fn; - f->c.name = NULL; - if (!f->c.id) - f->c.id = ++g->ident_counter; - cgen_fn_decl(g, e->fn, &e->type); - } break; - case EXPR_TYPE: { - Type *type = e->typeval; - cgen_decls_type(g, type); - } break; - case EXPR_BINARY_OP: { - Type *lhs_type = &e->binary.lhs->type; - if (lhs_type->kind == TYPE_PTR) - lhs_type = lhs_type->ptr; - } break; - default: - break; - } -} - -static void cgen_decls_block(CGenerator *g, Block *b) { - Block *prev_block = g->block; - g->block = b; - arr_foreach(b->stmts, Statement, s) - cgen_decls_stmt(g, s); - if (b->ret_expr) cgen_decls_expr(g, b->ret_expr); - g->block = prev_block; -} - -static void cgen_decls_decl(CGenerator *g, Declaration *d) { - cgen_decls_type(g, &d->type); - if (cgen_fn_is_direct(g, d)) { - cgen_fn_decl(g, d->expr.fn, &d->expr.type); - cgen_recurse_subexprs(g, (&d->expr), cgen_decls_expr, cgen_decls_block, cgen_decls_decl, cgen_decls_type); - } else { - if (d->flags & DECL_HAS_EXPR) { - cgen_decls_expr(g, &d->expr); - } - if (!g->block || g->block->kind == BLOCK_NMS) { - /* global variables */ - for (int i = 0, n_idents = (int)arr_len(d->idents); i < n_idents; ++i) { - Identifier ident = d->idents[i]; - Type *type = decl_type_at_index(d, i); - Value *val = NULL; - if (d->flags & DECL_HAS_EXPR) - assert(d->flags & DECL_FOUND_VAL); - if (d->flags & DECL_FOUND_VAL) - val = decl_val_at_index(d, i); - if (!type_is_compileonly(type)) { - if (val) cgen_val_pre(g, val, type); - if (!(d->flags & DECL_EXPORT)) - cgen_write(g, "static "); - cgen_type_pre(g, type); - cgen_write(g, " "); - cgen_ident(g, ident); - cgen_type_post(g, type); - if (val) { - cgen_write(g, " = "); - cgen_val(g, val, type); - } else { - cgen_write(g, " = "); - cgen_zero_value(g, type); - } - cgen_write(g, ";"); - cgen_nl(g); - } - } - } - } -} - -static void cgen_decls_stmt(CGenerator *g, Statement *s) { - switch (s->kind) { - case STMT_DECL: - cgen_decls_decl(g, s->decl); - break; - case STMT_EXPR: - cgen_decls_expr(g, s->expr); - break; - case STMT_RET: { - Return *r = s->ret; - if (r->flags & RET_HAS_EXPR) - cgen_decls_expr(g, &r->expr); - } break; - case STMT_BREAK: - case STMT_CONT: - case STMT_MESSAGE: - break; - case STMT_DEFER: - cgen_decls_stmt(g, s->defer); - break; - case STMT_USE: - cgen_sdecls_expr(g, &s->use->expr); - break; - case STMT_INLINE_BLOCK: - arr_foreach(s->inline_block, Statement, sub) - cgen_decls_stmt(g, sub); - break; - case STMT_INCLUDE: - assert(0); - break; - } -} - -static void cgen_decls_file(CGenerator *g, ParsedFile *f) { - cgen_write(g, "/* declarations */\n"); - arr_foreach(f->stmts, Statement, s) { - cgen_decls_stmt(g, s); - } -} @@ -8,6 +8,7 @@ /* @TODO: +get rid of blocks returning values 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: @@ -43,10 +44,10 @@ once you have a bunch of test code: error on x ::= {return; 3} struct param inference maybe macros are just inline functions +passing untyped expressions to macros #returns_code (struct body is a block, to be evaluated at compile time, which returns the actual statements) - struct varargs - - also use with functions for macros -passing untyped expressions to macros + - also use with functions for macros? */ #if defined __unix__ || (defined __APPLE__ && defined __MACH__) @@ -258,7 +259,7 @@ int main(int argc, char **argv) { if (verbose) printf("Generating C code...\n"); CGenerator g; cgen_create(&g, out, &globals, &main_allocr); - cgen_file(&g, &f); + cgen_file(&g, &f, &tr); if (verbose) printf("Cleaning up...\n"); fclose(out); @@ -3073,3 +3073,7 @@ char *location_to_str(Location *where) { static inline bool struct_is_template(StructDef *s) { return s->params && !(s->params[0].flags & DECL_FOUND_VAL); } + +static inline bool fn_is_template(FnExpr *f) { + return f->instances && !f->instance_id; +} @@ -1,9 +1,14 @@ -#include "test.toc"; -foo ::= fn() int { - 5 +main ::= fn() { + nums : []int; + l := slice_to_ll(nums); } -main ::= fn() { - foo(); +slice_to_ll ::= fn(t::=, slice: []t) use ll: LinkedList(t) { } + +LinkedList ::= struct (of :: Type) { + head: of; + tail: &LinkedList(of); +} + @@ -174,10 +174,7 @@ static void ffmgr_create(ForeignFnManager *ffmgr, Allocator *allocr) { #include "infer.c" #include "types.c" #include "eval.c" -static void cgen_decls_file(CGenerator *g, ParsedFile *f); -static void cgen_sdecls_file(CGenerator *g, ParsedFile *f); #include "cgen.c" -#include "decls_cgen.c" #if RUN_TESTS #include "tests.c" @@ -296,6 +296,7 @@ static Status struct_resolve(Typer *tr, StructDef *s) { return false; /* silently fail; do not try to resolve again, because there'll be duplicate errors */ if (!(s->flags & STRUCT_DEF_RESOLVED)) { s->flags |= STRUCT_DEF_RESOLVING; + typer_arr_add(tr, tr->all_structs, s); { /* resolving stuff */ Block *body = &s->body; if (!types_block(tr, body)) @@ -523,8 +524,8 @@ static bool type_is_compileonly(Type *t) { case TYPE_UNKNOWN: return false; case TYPE_BUILTIN: - return t->builtin == BUILTIN_TYPE || t->builtin == BUILTIN_NMS; - case TYPE_PTR: + return t->builtin == BUILTIN_TYPE || t->builtin == BUILTIN_NMS || t->builtin == BUILTIN_VARARGS; + case TYPE_PTR: return type_is_compileonly(t->ptr); case TYPE_SLICE: return type_is_compileonly(t->slice); @@ -1155,7 +1156,11 @@ 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) { - if (f->flags & FN_EXPR_FOREIGN) return true; + if (f->flags & FN_EXPR_FOREIGN) { + FnWithCtx fn_ctx = {f, tr->nms, tr->block}; + typer_arr_add(tr, tr->all_fns, fn_ctx); + return true; + } FnExpr *prev_fn = tr->fn; bool success = true; Expression *ret_expr; @@ -1168,7 +1173,10 @@ static Status types_fn(Typer *tr, FnExpr *f, Type *t, Instance *instance) { if (t->fn.constness) return true; /* don't type function body yet; we need to do that for every instance */ } - + { + FnWithCtx fn_ctx = {f, tr->nms, tr->block}; + typer_arr_add(tr, tr->all_fns, fn_ctx); + } tr->fn = f; if (!types_block(tr, &f->body)) { success = false; @@ -1577,6 +1585,33 @@ static Status use_ident(Typer *tr, Identifier i, Type *t, Location where) { return true; } +static void typer_gen_nms_prefix(Typer *tr, Namespace *n) { + assert(tr->nms != n); + /* create a C prefix for this namespace */ + const char *prev_prefix = ""; + size_t prev_prefix_len = 0; + if (tr->nms) { + prev_prefix = tr->nms->c.prefix; + assert(prev_prefix); + prev_prefix_len = strlen(prev_prefix); + } + if (n->associated_ident) { + size_t ident_len = n->associated_ident->len; + char *prefix = n->c.prefix = typer_malloc(tr, ident_len + prev_prefix_len + 3); + memcpy(prefix, prev_prefix, prev_prefix_len); + prefix += prev_prefix_len; + memcpy(prefix, n->associated_ident->str, ident_len); + prefix += ident_len; + *prefix++ = '_'; + *prefix++ = '_'; + *prefix++ = '\0'; + } else { + size_t bytes = prev_prefix_len + 20; + char *prefix = n->c.prefix = typer_malloc(tr, bytes); + snprintf(prefix, bytes, "%sa%lu__", prev_prefix, ++tr->nms_counter); + } +} + static Status types_expr(Typer *tr, Expression *e) { if (e->flags & EXPR_FOUND_TYPE) return true; e->flags |= EXPR_FOUND_TYPE; /* even if failed, pretend we found the type */ @@ -1589,14 +1624,15 @@ static Status types_expr(Typer *tr, Expression *e) { t->kind = TYPE_UNKNOWN; /* default to unknown type (in the case of an error) */ switch (e->kind) { case EXPR_FN: { - if (!type_of_fn(tr, e->fn, &e->type, 0)) { + FnExpr *fn = e->fn; + if (!type_of_fn(tr, fn, &e->type, 0)) { return false; } - if (fn_has_any_const_params(e->fn) || fn_type_has_varargs(&e->type.fn)) { - e->fn->instances = typer_calloc(tr, 1, sizeof *e->fn->instances); + if (!(fn->flags & FN_EXPR_FOREIGN) && (fn_has_any_const_params(fn) || fn_type_has_varargs(&e->type.fn))) { + fn->instances = typer_calloc(tr, 1, sizeof *fn->instances); t->flags |= TYPE_IS_RESOLVED; /* pretend this type is resolved, even though its children aren't to fix some assertions */ } else { - if (!types_fn(tr, e->fn, &e->type, NULL)) { + if (!types_fn(tr, fn, &e->type, NULL)) { return false; } } @@ -2769,6 +2805,8 @@ static Status types_expr(Typer *tr, Expression *e) { arr_remove_last(err_ctx->instance_stack); if (!success) return false; } + c->fn->kind = EXPR_VAL; + c->fn->val.fn = c->instance->fn; } free(order); @@ -3312,13 +3350,14 @@ static Status types_expr(Typer *tr, Expression *e) { } break; case EXPR_NMS: { Namespace *prev_nms = tr->nms; - Namespace *n = tr->nms = e->nms; + Namespace *n = e->nms; + typer_gen_nms_prefix(tr, n); + tr->nms = n; if (!types_block(tr, &n->body)) { tr->nms = prev_nms; return false; } tr->nms = prev_nms; - n->associated_ident = NULL; /* set when we type the declaration which contains this namespace */ t->kind = TYPE_BUILTIN; t->builtin = BUILTIN_NMS; } break; @@ -3342,6 +3381,9 @@ static Status types_block(Typer *tr, Block *b) { return false; } b->flags |= BLOCK_FINDING_TYPES; + + b->c.break_lbl = 0; + b->c.cont_lbl = 0; /* for and fn need to deal with their own useds, because you can use stuff in the header */ if (b->kind != BLOCK_FOR && b->kind != BLOCK_FN) @@ -3391,6 +3433,15 @@ static Status types_block(Typer *tr, Block *b) { return success; } +static bool is_at_top_level(Typer *tr) { + arr_foreach(tr->blocks, BlockPtr, b) { + if (*b && (*b)->kind != BLOCK_NMS) { + return false; + } + } + return true; +} + static Status types_decl(Typer *tr, Declaration *d) { Type *dtype = &d->type; if (d->flags & DECL_FOUND_TYPE) return true; @@ -3423,6 +3474,12 @@ static Status types_decl(Typer *tr, Declaration *d) { && 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; @@ -3476,6 +3533,9 @@ 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 */ @@ -3492,7 +3552,7 @@ static Status types_decl(Typer *tr, Declaration *d) { if (type_is_compileonly(dtype)) { - if (!(d->flags & DECL_IS_CONST)) { + if (!(d->flags & DECL_IS_CONST) && !type_is_builtin(dtype, BUILTIN_VARARGS)) { char *s = type_to_str(dtype); err_print(d->where, "Declarations with type %s must be constant.", s); free(s); @@ -3569,24 +3629,21 @@ static Status types_decl(Typer *tr, Declaration *d) { return false; } - if (n_idents == 1 && e && e->kind == EXPR_NMS) { - bool is_at_top_level = true; - arr_foreach(tr->blocks, BlockPtr, b) { - if (*b && (*b)->kind != BLOCK_NMS) { - is_at_top_level = false; - break; - } - } - if (is_at_top_level) - d->expr.nms->associated_ident = d->idents[0]; - } - if (tr->nms && tr->block == &tr->nms->body) { arr_foreach(d->idents, Identifier, ident) { (*ident)->nms = tr->nms; } } + if (d->flags & DECL_EXPORT) { + if (d->expr.kind == EXPR_FN) + d->expr.fn->flags |= FN_EXPR_EXPORT; + } + + if (is_at_top_level(tr)) { + DeclWithCtx dctx = {d, tr->nms, tr->block}; + typer_arr_add(tr, tr->all_globals, dctx); + } ret: /* pretend we found the type even if we didn't to prevent too many errors */ @@ -3773,38 +3830,79 @@ static Status types_stmt(Typer *tr, Statement *s) { Namespace *prev_nms = tr->nms; IncludedFile *inc_f = NULL; Namespace *inc_nms = NULL; /* non-NULL if this is an include to nms */ + bool success = true; if (inc->nms) { inc_nms = typer_calloc(tr, 1, sizeof *inc_nms); + Block *body = &inc_nms->body; body->kind = BLOCK_NMS; body->where = s->where; idents_create(&body->idents, tr->allocr, body); body->parent = tr->block; + + inc_nms->inc_file = inc_f; + /* turn #include "foo", bar into bar ::= nms { ... } */ + s->kind = STMT_DECL; + Declaration *d = s->decl = typer_calloc(tr, 1, sizeof *d); + d->flags = DECL_FOUND_TYPE | DECL_HAS_EXPR | DECL_IS_CONST | DECL_FOUND_VAL; + construct_resolved_builtin_type(&d->type, BUILTIN_NMS); + char *ident_str = inc->nms; + Identifier i = ident_insert(typer_get_idents(tr), &ident_str); + if (i->decl) { + Declaration *d2 = i->decl; + /* maybe they included it twice into one namespace */ + if ((d2->flags & DECL_HAS_EXPR) && (d2->expr.kind == EXPR_NMS) && + (d2->expr.nms->inc_file == inc_f)) { + /* that's okay; get rid of this declaration */ + s->kind = STMT_INLINE_BLOCK; + s->inline_block = NULL; + break; + } else { + char *istr = ident_to_str(i); + err_print(s->where, "Redeclaration of identifier %s.", istr); + info_print(ident_decl_location(i), "Previous declaration was here."); + free(istr); + return false; /* NOT goto inc_fail; */ + } + } + typer_arr_add(tr, d->idents, i); + i->decl = d; + if (is_at_top_level(tr)) inc_nms->associated_ident = i; + typer_gen_nms_prefix(tr, inc_nms); + + d->expr.kind = EXPR_NMS; + d->expr.nms = inc_nms; + d->expr.flags = EXPR_FOUND_TYPE; + d->expr.type = d->type; + d->val.nms = inc_nms; + d->where = d->expr.where = s->where; + /* go inside namespace and block (it'll help to be there later on) */ tr->nms = inc_nms; typer_block_enter(tr, &inc_nms->body); + } else { + s->kind = STMT_INLINE_BLOCK; } - s->kind = STMT_INLINE_BLOCK; - if (!(inc->flags & INC_FORCED)) { size_t filename_len = strlen(filename); if (streq(filename, tr->main_file->filename)) { err_print(s->where, "Circular #include detected. You can add #force to this #include to force it to be included."); - goto inc_fail; + success = false; goto nms_done; } inc_f = str_hash_table_get(&tr->included_files, filename, filename_len); if (inc_f) { /* has already been included */ if (inc_f->flags & INC_FILE_INCLUDING) { err_print(s->where, "Circular #include detected. You can add #force to this #include to force it to be included."); - goto inc_fail; + success = false; goto nms_done; } - s->inline_block = NULL; /* nothing needed here */ + if (s->kind == STMT_INLINE_BLOCK) s->inline_block = NULL; /* nothing needed here */ /* just set ident declarations */ - if (!include_stmts_link_to_nms(tr, inc_f->main_nms, inc_f->stmts)) - goto inc_fail; - goto nms_transform; + if (!include_stmts_link_to_nms(tr, inc_f->main_nms, inc_f->stmts)) { + success = false; goto nms_done; + } + goto nms_done; } inc_f = str_hash_table_insert(&tr->included_files, filename, filename_len); inc_f->flags |= INC_FILE_INCLUDING; @@ -3814,7 +3912,7 @@ static Status types_stmt(Typer *tr, Statement *s) { char *contents = read_file_contents(tr->allocr, filename, s->where); if (!contents) { tr->had_include_err = true; - goto inc_fail; + success = false; goto nms_done; } Tokenizer tokr; @@ -3824,80 +3922,38 @@ static Status types_stmt(Typer *tr, Statement *s) { file->contents = contents; file->ctx = tr->err_ctx; - if (!tokenize_file(&tokr, file)) - goto inc_fail; + if (!tokenize_file(&tokr, file)) { + success = false; goto nms_done; + } Parser parser; parser_create(&parser, tr->globals, &tokr, tr->allocr); parser.block = tr->block; ParsedFile parsed_file; if (!parse_file(&parser, &parsed_file)) { - goto inc_fail; + success = false; goto nms_done; } Statement *stmts_inc = parsed_file.stmts; if (inc_f) { inc_f->stmts = stmts_inc; } - s->inline_block = stmts_inc; + if (s->kind == STMT_INLINE_BLOCK) s->inline_block = stmts_inc; arr_foreach(stmts_inc, Statement, s_incd) { if (!types_stmt(tr, s_incd)) { - goto inc_fail; + success = false; goto nms_done; } } if (inc_nms) { inc_nms->body.stmts = stmts_inc; } } - nms_transform: + nms_done: if (inc_nms) { - /* go back to parent namespace/block because that's where the declaration is gonna be */ tr->nms = prev_nms; typer_block_exit(tr); - - inc_nms->inc_file = inc_f; - /* turn #include "foo", bar into bar ::= nms { ... } */ - s->kind = STMT_DECL; - Declaration *d = s->decl = typer_calloc(tr, 1, sizeof *d); - d->flags = DECL_FOUND_TYPE | DECL_HAS_EXPR | DECL_IS_CONST | DECL_FOUND_VAL; - construct_resolved_builtin_type(&d->type, BUILTIN_NMS); - char *ident_str = inc->nms; - Identifier i = ident_insert(typer_get_idents(tr), &ident_str); - typer_arr_add(tr, d->idents, i); - if (i->decl) { - Declaration *d2 = i->decl; - /* maybe they included it twice into one namespace */ - if ((d2->flags & DECL_HAS_EXPR) && (d2->expr.kind == EXPR_NMS) && - (d2->expr.nms->inc_file == inc_f)) { - /* that's okay; get rid of this declaration */ - s->kind = STMT_INLINE_BLOCK; - s->inline_block = NULL; - break; - } else { - char *istr = ident_to_str(i); - err_print(s->where, "Redeclaration of identifier %s.", istr); - info_print(ident_decl_location(i), "Previous declaration was here."); - free(istr); - return false; /* NOT goto inc_fail; */ - } - } - i->decl = d; - inc_nms->associated_ident = i; - d->expr.kind = EXPR_NMS; - d->expr.nms = inc_nms; - d->expr.flags = EXPR_FOUND_TYPE; - d->expr.type = d->type; - d->val.nms = inc_nms; - d->where = d->expr.where = s->where; } if (inc_f) inc_f->flags &= (IncFileFlags)~(IncFileFlags)INC_FILE_INCLUDING; - break; - inc_fail: - if (inc_f) inc_f->flags &= (IncFileFlags)~(IncFileFlags)INC_FILE_INCLUDING; - if (inc_nms) { - tr->nms = prev_nms; - typer_block_exit(tr); - } - return false; - } + if (!success) return false; + } break; case STMT_MESSAGE: { Message *m = s->message; char *text = eval_expr_as_cstr(tr, &m->text, "message"); @@ -3922,6 +3978,16 @@ static Status types_stmt(Typer *tr, Statement *s) { for (block = tr->block; block; block = block->parent) { if (block->kind == BLOCK_FOR || block->kind == BLOCK_WHILE) { s->referring_to = block; + if (s->kind == STMT_BREAK) { + if (!block->c.break_lbl) { + block->c.break_lbl = ++tr->lbl_counter; + } + } else { + assert(s->kind == STMT_CONT); + if (!block->c.cont_lbl) { + block->c.cont_lbl = ++tr->lbl_counter; + } + } break; } } @@ -3969,15 +4035,10 @@ success: } static void typer_create(Typer *tr, Evaluator *ev, ErrCtx *err_ctx, Allocator *allocr, Identifiers *idents, File *main_file) { - tr->block = NULL; - tr->blocks = NULL; - tr->fn = NULL; - tr->nms = NULL; + memset(tr, 0, sizeof *tr); tr->evalr = ev; tr->main_file = main_file; tr->err_ctx = err_ctx; - tr->in_decls = NULL; - tr->had_include_err = false; tr->allocr = allocr; tr->globals = idents; typer_arr_add(tr, tr->blocks, NULL); @@ -514,7 +514,7 @@ typedef struct Block { BlockKind kind; /* set during the parsing phase, but don't access while this specific block is being parsed, because sometimes it's set after parse_block */ struct { - IdentID break_lbl, cont_lbl; /* initially 0, set to non-zero values if needed (++g->lbl_counter); set by sdecls_cgen. */ + IdentID break_lbl, cont_lbl; /* initially 0, set to non-zero values if needed (tr->lbl_counter); set during typing */ } c; Location where; Identifiers idents; @@ -528,9 +528,6 @@ typedef Block *BlockPtr; enum { STRUCT_DEF_FOUND_OFFSETS = 0x01, - STRUCT_DEF_CGEN_DECLARED = 0x02, - STRUCT_DEF_CGEN_DEFINED = 0x04, - STRUCT_DEF_CGEN_FN_DEFS = 0x08, /* have the functions contained in this struct been defined? */ STRUCT_DEF_RESOLVED = 0x10, STRUCT_DEF_RESOLVING = 0x20, STRUCT_DEF_RESOLVING_FAILED = 0x40 @@ -562,7 +559,7 @@ typedef struct StructDef { } c; StructFlags flags; } StructDef; - +typedef StructDef *StructDefPtr; typedef enum { EXPR_LITERAL_FLOAT, @@ -688,7 +685,7 @@ typedef struct FnExpr { struct { struct Declaration *params; /* declarations of the parameters to this function */ struct Declaration *ret_decls; /* array of decls, if this has named return values. otherwise, NULL */ - U64 instance_id; + U64 instance_id; /* 0 if not an instance */ Type ret_type; Block body; }; @@ -709,7 +706,6 @@ typedef struct FnExpr { HashTable *instances; /* for fns with constant parameters. the key is a tuple where the first element is a u64 value whose ith bit (1<<i) is 1 if the ith semi-constant parameter is constant. - cgen relies on this being here even for foreign fns. */ struct { /* if name = NULL, this is an anonymous function, and id will be the ID of the fn. */ @@ -718,6 +714,7 @@ typedef struct FnExpr { } c; U8 flags; } FnExpr; /* an expression such as fn(x: int) int { 2 * x } */ +typedef FnExpr *FnExprPtr; typedef struct Instance { Value val; /* key into hash table */ @@ -772,7 +769,7 @@ typedef struct Namespace { Identifier associated_ident; /* if this is foo ::= nms { ... }, then associated_ident is foo; can be NULL. used by cgen. only non-null if the namespace isn't in a non-namespace block */ struct IncludedFile *inc_file; /* NULL if this is not generated from an include to nms */ struct { - char *prefix; /* generated during sdecls_cgen */ + char *prefix; /* generated during typing */ } c; } Namespace; typedef Namespace *NamespacePtr; @@ -899,7 +896,7 @@ enum { }; enum { FN_EXPR_FOREIGN = 0x01, - FN_EXPR_EXPORT = 0x02, /* set by sdecls_cgen.c */ + FN_EXPR_EXPORT = 0x02, /* set during typing */ FN_EXPR_HAS_VARARGS = 0x04 }; typedef struct ForExpr { @@ -1050,6 +1047,23 @@ typedef struct Evaluator { ForeignFnManager ffmgr; } Evaluator; + +/* + so there are loops in cgen that generate all the function declarations/definitions + and they need to know what namespace they're in (because we name mangle stuff in namespaces) +*/ +typedef struct { + FnExpr *fn; + Namespace *nms; + Block *block; +} FnWithCtx; + +typedef struct { + Declaration *d; + Namespace *nms; + Block *block; +} DeclWithCtx; + typedef struct Typer { Allocator *allocr; Evaluator *evalr; @@ -1063,6 +1077,11 @@ typedef struct Typer { ErrCtx *err_ctx; ParsedFile *parsed_file; Namespace *nms; + FnWithCtx *all_fns; /* does not include templates */ + StructDef **all_structs; + DeclWithCtx *all_globals; /* includes stuff in namespaces, as long as it's not in a function */ + IdentID lbl_counter; + unsigned long nms_counter; /* counter for namespace IDs */ StrHashTable included_files; /* maps to IncludedFile */ /* have we had an error because we couldn't find a file that was #include'd |