diff options
-rw-r--r-- | cgen.c | 85 | ||||
-rw-r--r-- | decls_cgen.c | 2 | ||||
-rw-r--r-- | out.c | 10 | ||||
-rw-r--r-- | test.toc | 9 | ||||
-rw-r--r-- | types.c | 2 |
5 files changed, 95 insertions, 13 deletions
@@ -56,10 +56,26 @@ static void cgen_nl(CGenerator *g) { } /* should declaration be a direct function declaration C (as opposed to using a function pointer or not being a function) */ -static bool cgen_is_fn_direct(CGenerator *g, Declaration *d) { +static bool cgen_fn_is_direct(CGenerator *g, Declaration *d) { return g->block == NULL && (d->flags & DECL_FLAG_HAS_EXPR) && d->expr.kind == EXPR_FN && arr_len(d->idents) == 1; } +static bool cgen_uses_out_param(Type *t) { + switch (t->kind) { + case TYPE_TUPLE: + case TYPE_ARR: + return true; + case TYPE_BUILTIN: + case TYPE_PTR: + case TYPE_FN: + case TYPE_VOID: + case TYPE_UNKNOWN: + return false; + } + assert(0); + return false; +} + static void cgen_ident(CGenerator *g, Identifier i) { if (i == g->main_ident) { /* don't conflict with C's main! */ @@ -102,8 +118,12 @@ static bool cgen_type_pre(CGenerator *g, Type *t, Location where) { cgen_write(g, "("); break; case TYPE_FN: - if (!cgen_type_pre(g, &t->fn.types[0], where)) - return false; + if (cgen_uses_out_param(&t->fn.types[0])) { + cgen_write(g, "void"); + } else { + if (!cgen_type_pre(g, &t->fn.types[0], where)) + return false; + } cgen_write(g, " (*"); break; case TYPE_VOID: cgen_write(g, "void"); break; @@ -131,6 +151,7 @@ static bool cgen_type_post(CGenerator *g, Type *t, Location where) { return false; break; case TYPE_FN: { + bool out_param = cgen_uses_out_param(&t->fn.types[0]); cgen_write(g, ")("); for (size_t i = 1; i < arr_len(t->fn.types); i++) { if (i != 1) @@ -140,9 +161,19 @@ static bool cgen_type_post(CGenerator *g, Type *t, Location where) { if (!cgen_type_post(g, &t->fn.types[i], where)) return false; } + if (out_param) { + if (arr_len(t->fn.types) > 1) + cgen_write(g, ", "); + if (!cgen_type_pre(g, &t->fn.types[0], where)) + return false; + cgen_write(g, "(*)"); + if (!cgen_type_post(g, &t->fn.types[0], where)) + return false; + } cgen_write(g, ")"); - if (!cgen_type_post(g, &t->fn.types[0], where)) - return false; + if (!out_param) + if (!cgen_type_post(g, &t->fn.types[0], where)) + return false; } break; case TYPE_BUILTIN: case TYPE_VOID: @@ -154,19 +185,28 @@ static bool cgen_type_post(CGenerator *g, Type *t, Location where) { } static bool cgen_fn_header(CGenerator *g, FnExpr *f, Location where) { - if (!cgen_type_pre(g, &f->ret_type, where)) return false; - cgen_write(g, " "); + bool out_param = cgen_uses_out_param(&f->ret_type); + bool any_params = false; + if (out_param) { + cgen_write(g, "void "); + } else { + if (!cgen_type_pre(g, &f->ret_type, where)) return false; + cgen_write(g, " "); + } if (f->c.name) { cgen_ident(g, f->c.name); } else { cgen_ident_id(g, f->c.id); } - if (!cgen_type_post(g, &f->ret_type, where)) return false; + if (!out_param) { + if (!cgen_type_post(g, &f->ret_type, where)) return false; + } cgen_write(g, "("); arr_foreach(f->params, Declaration, d) { arr_foreach(d->idents, Identifier, i) { if (d != f->params || i != d->idents) cgen_write(g, ", "); + any_params = true; if (!cgen_type_pre(g, &d->type, where)) return false; cgen_write(g, " "); @@ -175,6 +215,15 @@ static bool cgen_fn_header(CGenerator *g, FnExpr *f, Location where) { return false; } } + if (out_param) { + if (any_params) + cgen_write(g, ", "); + if (!cgen_type_pre(g, &f->ret_type, where)) + return false; + cgen_write(g, " (*ret__)"); + if (!cgen_type_post(g, &f->ret_type, where)) + return false; + } cgen_write(g, ")"); return true; } @@ -359,7 +408,7 @@ static void cgen_zero_value(CGenerator *g, Type *t) { } static bool cgen_decl(CGenerator *g, Declaration *d) { - if (cgen_is_fn_direct(g, d)) { + if (cgen_fn_is_direct(g, d)) { if (!cgen_fn_header(g, &d->expr.fn, d->where)) return false; cgen_write(g, " "); @@ -413,8 +462,22 @@ static bool cgen_stmt(CGenerator *g, Statement *s) { cgen_nl(g); break; case STMT_RET: - cgen_write(g, "return "); - if (!cgen_expr(g, &s->ret.expr)) return false; + /* TODO (this doesn't work -- add fn to CGenerator) */ + if (g->block->ret_expr) { + if (cgen_uses_out_param(&g->block->ret_expr->type)) { + cgen_write(g, "*ret__ = "); + if (!cgen_expr(g, &s->ret.expr)) return false; + cgen_write(g, ";"); + } else { + cgen_write(g, "return "); + + if (!cgen_expr(g, &s->ret.expr)) return false; + } + } else { + cgen_write(g, "return"); + } + cgen_write(g, ";"); + cgen_nl(g); break; } return true; diff --git a/decls_cgen.c b/decls_cgen.c index bbdb8a3..7f0fad0 100644 --- a/decls_cgen.c +++ b/decls_cgen.c @@ -81,7 +81,7 @@ static bool cgen_decls_block(CGenerator *g, Block *b) { } static bool cgen_decls_decl(CGenerator *g, Declaration *d) { - if (cgen_is_fn_direct(g, d)) { + if (cgen_fn_is_direct(g, d)) { d->expr.fn.c.name = d->idents[0]; if (!cgen_fn_header(g, &d->expr.fn, d->where)) return false; @@ -17,6 +17,7 @@ typedef unsigned char bool; /* declarations */ void puti(i64 i); +void asdf(i64 i, i64( (*ret__)[3])); void main__(); /* code */ int main() { @@ -28,6 +29,14 @@ void puti(i64 i) { printf("%ld\n", i); } +void asdf(i64 i, i64( (*ret__)[3])) { +i64( ret[3]) = {0}; +((ret[0])=(0*i)); +((ret[1])=(1*i)); +((ret[2])=(2*i)); +return; +} + void main__() { i64(* x); x = ((i64(*))calloc(1, sizeof(i64))); ((*x)=17); @@ -38,6 +47,7 @@ if (((*x)==0)) { }; (puti((*x))); (free(x)); +void (* fptr)(i64, i64((*)[3])); fptr = asdf; } i64 foo = 5; @@ -2,6 +2,14 @@ puti @= fn(i: int) { #C("printf(\"%ld\\n\", i)"); }; +asdf @= fn(i: int) [3]int { + ret : [3]int; + ret[0] = 0*i; + ret[1] = 1*i; + ret[2] = 2*i; + return ret; +}; + main @= fn() { x := new int; *x = 17; @@ -12,6 +20,7 @@ main @= fn() { } puti(*x); del x; + fptr := asdf; }; foo := 5; @@ -927,7 +927,7 @@ static bool types_expr(Typer *tr, Expression *e) { } break; } - + e->type.flags |= TYPE_FLAG_RESOLVED; return true; } |