summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--cgen.c530
-rw-r--r--decls_cgen.c420
-rw-r--r--main.c7
-rw-r--r--parse.c4
-rw-r--r--test.toc15
-rw-r--r--toc.c3
-rw-r--r--types.c239
-rw-r--r--types.h37
8 files changed, 403 insertions, 852 deletions
diff --git a/cgen.c b/cgen.c
index 9bbeb36..72095a4 100644
--- a/cgen.c
+++ b/cgen.c
@@ -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(&param->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(&param->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);
- }
-}
diff --git a/main.c b/main.c
index 7e58ef1..3299df4 100644
--- a/main.c
+++ b/main.c
@@ -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);
diff --git a/parse.c b/parse.c
index d22af8a..3cb453f 100644
--- a/parse.c
+++ b/parse.c
@@ -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;
+}
diff --git a/test.toc b/test.toc
index 0450b18..e7f8ecd 100644
--- a/test.toc
+++ b/test.toc
@@ -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);
+}
+
diff --git a/toc.c b/toc.c
index b5660f9..2afbc1c 100644
--- a/toc.c
+++ b/toc.c
@@ -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"
diff --git a/types.c b/types.c
index cda8b16..d09b3ec 100644
--- a/types.c
+++ b/types.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);
diff --git a/types.h b/types.h
index b4fc615..cd52028 100644
--- a/types.h
+++ b/types.h
@@ -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