summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--cgen.c85
-rw-r--r--decls_cgen.c2
-rw-r--r--out.c10
-rw-r--r--test.toc9
-rw-r--r--types.c2
5 files changed, 95 insertions, 13 deletions
diff --git a/cgen.c b/cgen.c
index be9bdb1..95dae48 100644
--- a/cgen.c
+++ b/cgen.c
@@ -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;
diff --git a/out.c b/out.c
index 1e45b85..2426dd0 100644
--- a/out.c
+++ b/out.c
@@ -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;
diff --git a/test.toc b/test.toc
index c4f76db..6160362 100644
--- a/test.toc
+++ b/test.toc
@@ -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;
diff --git a/types.c b/types.c
index dfda38b..8426b3b 100644
--- a/types.c
+++ b/types.c
@@ -927,7 +927,7 @@ static bool types_expr(Typer *tr, Expression *e) {
}
break;
}
-
+ e->type.flags |= TYPE_FLAG_RESOLVED;
return true;
}