aboutsummaryrefslogtreecommitdiff
path: root/src/lower.c
diff options
context:
space:
mode:
Diffstat (limited to 'src/lower.c')
-rw-r--r--src/lower.c195
1 files changed, 172 insertions, 23 deletions
diff --git a/src/lower.c b/src/lower.c
index 9689928..ee8253a 100644
--- a/src/lower.c
+++ b/src/lower.c
@@ -237,6 +237,23 @@ static int _type_str(FILE *f, struct state *state, struct scope *scope, struct t
break;
}
+ case TYPE_REF: {
+ char *rest = lower_type_str(state, scope, tref_base(type));
+ fprintf(f, "%s*", rest);
+ free(rest);
+ break;
+ }
+
+ case TYPE_BOOL: {
+ fprintf(f, "bool");
+ break;
+ }
+
+ case TYPE_NIL: {
+ fprintf(f, "void*");
+ break;
+ }
+
default:
internal_error("unhandled type lowering for %s", type_str(type));
abort();
@@ -505,6 +522,36 @@ static int lower_expr(struct state *state, struct ast *expr)
break;
}
+ case AST_SIZEOF: {
+ char *type = lower_type_str(state, expr->scope, sizeof_type(expr));
+ fprintf(state->code, "sizeof(%s)", type);
+ free(type);
+ break;
+ }
+
+ case AST_PUT: {
+ fprintf(state->code, "*(");
+ if (lower_expr(state, put_dst(expr)))
+ return -1;
+
+ fprintf(state->code, ")");
+ break;
+ }
+
+ case AST_DEREF: {
+ fprintf(state->code, "*(");
+ if (lower_expr(state, deref_base(expr)))
+ return -1;
+
+ fprintf(state->code, ")");
+ break;
+ }
+
+ case AST_CONST_STR: {
+ fprintf(state->code, "\"%s\"", str_val(expr));
+ break;
+ }
+
default:
internal_error("unhandled expr lowering: %s", ast_str(expr->k));
abort();
@@ -607,6 +654,22 @@ static int lower_if(struct state *state, struct ast *stmt, bool last)
return lower_block(state, if_else(stmt), last);
}
+static int lower_nil_check(struct state *state, struct ast *stmt, bool last)
+{
+ indent(state);
+ fprintf(state->code, "if (");
+ if (lower_expr(state, nil_check_expr(stmt)))
+ return -1;
+
+ fprintf(state->code, ")\n");
+ if (lower_block(state, nil_check_body(stmt), last))
+ return -1;
+
+ indent(state);
+ fprintf(state->code, "else\n");
+ return lower_block(state, nil_check_rest(stmt), last);
+}
+
static int lower_explode(struct state *state, struct ast *stmt, bool last)
{
/* not significant to us */
@@ -665,13 +728,29 @@ static int lower_let(struct state *state, struct ast *stmt, bool last)
return 0;
}
+static int lower_write(struct state *state, struct ast *stmt)
+{
+ if (lower_expr(state, write_dst(stmt)))
+ return -1;
+
+ fprintf(state->code, " = ");
+ if (lower_expr(state, write_src(stmt)))
+ return -1;
+
+ fprintf(state->code, ";\n");
+ return 0;
+}
+
static int lower_stmt(struct state *state, struct ast *stmt, bool last)
{
switch (stmt->k) {
case AST_CALL: return lower_call(state, stmt, last);
case AST_IF: return lower_if(state, stmt, last);
+ case AST_NIL_CHECK: return lower_nil_check(state, stmt, last);
case AST_EXPLODE: return lower_explode(state, stmt, last);
case AST_LET: return lower_let(state, stmt, last);
+ case AST_WRITE: return lower_write(state, stmt);
+ case AST_FORGET: break;
case AST_EMPTY: break;
default:
internal_error("unhandled statement kind %s", ast_str(stmt->k));
@@ -728,37 +807,82 @@ static int lower_params(struct state *state, struct ast *params)
return 0;
}
-static size_t fwd_typeid(struct type *t)
+static const char *fwd_typeparam(struct type *t)
{
- /** @todo this should maybe be cached somewhere earlier? */
switch (t->k) {
- case TYPE_I64: return FWD_I64;
- case TYPE_PTR: return FWD_PTR;
+ case TYPE_I8: return "i8";
+ case TYPE_I16: return "i16";
+ case TYPE_I32: return "i32";
+ case TYPE_I64: return "i64";
+ case TYPE_U8: return "u8";
+ case TYPE_U16: return "u16";
+ case TYPE_U32: return "u32";
+ case TYPE_U64: return "u64";
+ case TYPE_PTR: return "p";
+ case TYPE_NIL: return "p";
+ case TYPE_FUNC_PTR: return "p";
default:
abort();
}
- return 0;
+ return NULL;
}
-static const char *fwd_typeparam(struct type *t)
+static const char *fwd_ctypestr(struct type *t)
{
switch (t->k) {
- case TYPE_I64: return "i64";
- case TYPE_PTR: return "p";
+ case TYPE_I8: return "FWD_I8";
+ case TYPE_I16: return "FWD_I16";
+ case TYPE_I32: return "FWD_I32";
+ case TYPE_I64: return "FWD_I64";
+ case TYPE_U8: return "FWD_U8";
+ case TYPE_U16: return "FWD_U16";
+ case TYPE_U32: return "FWD_U32";
+ case TYPE_U64: return "FWD_U64";
+ case TYPE_PTR: return "FWD_PTR";
+ case TYPE_NIL: return "FWD_PTR"; /* void ptr */
+ case TYPE_FUNC_PTR: return "FWD_PTR";
default:
- abort();
+ abort();
}
+ return NULL;
+}
+
+static int lower_extern_closure_call(struct state *state, struct type *rtype, size_t idx)
+{
+ char *q = buildstr("%s_call%zu", state->prefix, uniq(state));
+
+ char *ctx_buf = NULL; size_t ctx_size = 0;
+ FILE *ctx = open_memstream(&ctx_buf, &ctx_size);
+ fprintf(ctx, "struct %s {\n fwd_start_t start;\n fwd_call_t closure;\n};\n", q);
+ fclose(ctx);
+ assert(ctx_buf);
+
+ add_type(state, ctx_buf);
+
+ indent(state);
+ fprintf(state->code, "fwd_call_t call = ctx->a%zu.call;\n", idx);
+
+ indent(state);
+ fprintf(state->code, "struct %s *call_ctx = ctx->a%zu.args;\n", q, idx);
+
+ indent(state);
+ fprintf(state->code, "call_ctx->a0 = extern_args[0].%s;\n",
+ fwd_typeparam(rtype));
+
+ indent(state);
+ fprintf(state->code, "fwd_stack_free(&stack, extern_args);\n");
+
+ indent(state);
+ fprintf(state->code, "FWD_MUSTTAIL return call(stack, call_ctx);\n");
+
+ free(q);
return 0;
}
static int lower_extern_proc(struct state *state, struct ast *proc)
{
- /* only void external functions supported atm */
- struct type *rtype = proc_rtype(proc);
- assert(rtype->k == TYPE_VOID);
-
add_proc(state, proc);
char *name = mangle2(proc);
char *proto = buildstr("static fwd_stack_t %s(fwd_stack_t stack, fwd_args_t args)",
@@ -796,17 +920,26 @@ static int lower_extern_proc(struct state *state, struct ast *proc)
fprintf(new_state.code, "struct fwd_arg *extern_args = fwd_stack_alloc(&stack);\n");
size_t idx = 0;
+ struct type *rtype = NULL;
foreach_node(p, proc_params(proc)) {
+ /* lower arg */
+ char *type_str = lower_type_str(state, p->scope, p->t);
+ fprintf(new_state.ctx, " %s a%zu;\n", type_str, idx);
+ free(type_str);
+
+ /* don't lower last parameter as an extern arg if it's a
+ * closure, since that's our return type */
+ if (!p->n && is_closure_type(p->t->k)) {
+ rtype = p->t;
+ break;
+ }
+
indent(&new_state);
/* leave place for return value */
- fprintf(new_state.code, "extern_args[%zu] = (fwd_arg_t){%zu, "
+ fprintf(new_state.code, "extern_args[%zu] = (fwd_arg_t){%s, "
"{.%s = ctx->a%zu}};\n",
- idx + 1, fwd_typeid(p->t), fwd_typeparam(p->t), idx);
-
+ idx + 1, fwd_ctypestr(p->t), fwd_typeparam(p->t), idx);
- char *type_str = lower_type_str(state, p->scope, p->t);
- fprintf(new_state.ctx, " %s a%zu;\n", type_str, idx);
- free(type_str);
idx++;
}
@@ -815,11 +948,27 @@ static int lower_extern_proc(struct state *state, struct ast *proc)
proc_id(proc), idx);
- indent(&new_state);
- fprintf(new_state.code, "fwd_stack_free(&stack, extern_args);\n");
+ if (rtype) {
+ struct type *ctype = rtype->k == TYPE_PURE_CLOSURE
+ ? tpure_closure_args(rtype)
+ : tclosure_args(rtype)
+ ;
- indent(&new_state);
- fprintf(new_state.code, "return stack;\n");
+ indent(&new_state);
+ fprintf(new_state.code, "assert(extern_args[0].type == %s);\n",
+ fwd_ctypestr(ctype));
+
+ if (lower_extern_closure_call(&new_state, ctype, idx))
+ return -1;
+
+ } else {
+ /* void func */
+ indent(&new_state);
+ fprintf(new_state.code, "fwd_stack_free(&stack, extern_args);\n");
+
+ indent(&new_state);
+ fprintf(new_state.code, "return stack;\n");
+ }
fprintf(new_state.code, "}\n\n");
fprintf(new_state.ctx, "};\n\n");