aboutsummaryrefslogtreecommitdiff
path: root/src/lower.c
diff options
context:
space:
mode:
Diffstat (limited to 'src/lower.c')
-rw-r--r--src/lower.c133
1 files changed, 102 insertions, 31 deletions
diff --git a/src/lower.c b/src/lower.c
index 141453c..5578319 100644
--- a/src/lower.c
+++ b/src/lower.c
@@ -11,6 +11,9 @@
#include <fwd/scope.h>
#include <fwd/vec.h>
+/** @todo semantics in this file are a bit unclear, should probably do some kind
+ * of "each function starts and ends on an indented empty line" or something */
+
struct state {
long indent;
};
@@ -34,9 +37,10 @@ static void indent(struct state *state)
static int lower_var(struct ast *expr);
static int lower_expr(struct state *state, struct ast *expr);
-static int lower_block(struct state *state, struct ast *block, bool ret);
static int lower_closure(struct state *state, struct ast *closure);
-static int lower_statement(struct state *state, struct ast *stmt);
+
+static int lower_block(struct state *state, struct ast *block, bool ret);
+static int lower_statement(struct state *state, struct ast *stmt, bool ret);
static int lower_type(struct type *type);
static int lower_types(struct type *types);
@@ -128,7 +132,7 @@ static int lower_type_callable(struct type *type)
* fib.fwd example, so use std::function for now. Eventually I might
* instead write a C backend or something to have more control over the
* exact semantics, but for now this is good enough. */
- printf("std::function<void(");
+ printf("std::function<fwd_err_t(");
if (lower_types(type->t0))
return -1;
@@ -289,16 +293,44 @@ static int lower_moves(struct state *state, struct ast *moves)
static int lower_err_branch(struct state *state, struct ast *err)
{
- return lower_block(state, err_branch_body(err), false);
+ if (lower_block(state, err_branch_body(err), false))
+ return -1;
+
+ printf("\n");
+ return 0;
}
-static int lower_call(struct state *state, struct ast *call)
+static int lower_mark_moved(struct state *state, struct ast *moves)
+{
+ if (!moves)
+ return 0;
+
+ foreach_node(move, moves) {
+ if (move->k != AST_ID)
+ continue;
+
+ printf("%s_owned = false;\n", id_str(move));
+ indent(state);
+ }
+
+ return 0;
+}
+
+static int lower_call(struct state *state, struct ast *call, bool ret)
{
struct ast *err = call_err(call);
/** @todo better default error name? */
const char *err_str = err ? err_branch_id(err) : "_fwd_err";
- printf("if (auto %s = ", err_str);
+ if (lower_mark_moved(state, call_args(call)))
+ return -1;
+
+ bool direct_ret = ret && !err;
+ if (direct_ret)
+ printf("return ");
+ else
+ printf("if (auto %s = ", err_str);
+
if (lower_expr(state, call_expr(call)))
return -1;
@@ -307,23 +339,22 @@ static int lower_call(struct state *state, struct ast *call)
if (lower_moves(state, call_args(call)))
return -1;
- printf("))");
-
- if (!err) {
- printf("\n");
- indent(state);
- printf(" return %s;\n", err_str);
+ if (direct_ret) {
+ printf(");\n");
return 0;
}
- if (lower_err_branch(state, call_err(call)))
- return -1;
+ printf("))");
+ if (err)
+ return lower_err_branch(state, err);
printf("\n");
+ indent(state);
+ printf(" return %s;\n", err_str);
return 0;
}
-static int lower_let(struct state *state, struct ast *let)
+static int lower_let(struct state *state, struct ast *let, bool ret)
{
if (lower_var(let_var(let)))
return -1;
@@ -334,10 +365,15 @@ static int lower_let(struct state *state, struct ast *let)
return -1;
printf(";\n");
+ if (ret) {
+ indent(state);
+ printf("return nullptr;\n");
+ }
+
return 0;
}
-static int lower_if(struct state *state, struct ast *stmt)
+static int lower_if(struct state *state, struct ast *stmt, bool ret)
{
printf("if (");
if (lower_expr(state, if_cond(stmt)))
@@ -345,7 +381,7 @@ static int lower_if(struct state *state, struct ast *stmt)
printf(") ");
- if (lower_block(state, if_body(stmt), false))
+ if (lower_block(state, if_body(stmt), ret))
return -1;
if (!if_else(stmt)) {
@@ -354,7 +390,7 @@ static int lower_if(struct state *state, struct ast *stmt)
}
printf(" else ");
- if (lower_block(state, if_else(stmt), false))
+ if (lower_block(state, if_else(stmt), ret))
return -1;
printf("\n");
@@ -374,19 +410,24 @@ static int lower_error(struct ast *err)
return 0;
}
-static int lower_own(struct state *state, struct ast *stmt)
+static int lower_own(struct state *state, struct ast *stmt, bool ret)
{
- printf("/* TODO own */\n");
+ /** @todo name mangling */
+ printf("if (!%s_owned) ", own_id(stmt));
+ if (lower_block(state, own_body(stmt), ret))
+ return -1;
+
+ printf("\n");
return 0;
}
-static int lower_statement(struct state *state, struct ast *stmt)
+static int lower_statement(struct state *state, struct ast *stmt, bool ret)
{
switch (stmt->k) {
- case AST_OWN: return lower_own(state, stmt);
- case AST_LET: return lower_let(state, stmt);
- case AST_CALL: return lower_call(state, stmt);
- case AST_IF: return lower_if(state, stmt);
+ case AST_OWN: return lower_own(state, stmt, ret);
+ case AST_LET: return lower_let(state, stmt, ret);
+ case AST_CALL: return lower_call(state, stmt, ret);
+ case AST_IF: return lower_if(state, stmt, ret);
case AST_EMPTY: return 0;
default:
internal_error("missing statement lowering");
@@ -396,15 +437,50 @@ static int lower_statement(struct state *state, struct ast *stmt)
return 0;
}
+static int lower_block_vars(struct state *state, struct ast *block)
+{
+ struct scope *scope = block->scope;
+
+ bool populated = false;
+ foreach_visible(n, scope->symbols) {
+ struct ast *def = n->node;
+ if (def->k != AST_VAR_DEF)
+ continue;
+
+ if (is_trivially_copyable(def->t))
+ continue;
+
+ if (!populated) {
+ indent(state);
+ printf("[[maybe_unused]] bool %s_owned = true",
+ var_id(def));
+
+ populated = true;
+ continue;
+ }
+
+ printf(", %s_owned = true", var_id(def));
+ }
+
+ if (populated)
+ printf(";\n\n");
+
+ return 0;
+}
+
static int lower_block(struct state *state, struct ast *block, bool ret)
{
printf("{\n");
increase_indent(state);
+ if (lower_block_vars(state, block))
+ return -1;
+
foreach_node(stmt, block_body(block)) {
indent(state);
- if (lower_statement(state, stmt))
+ bool returning = block_error(block) ? false : ret && !stmt->n;
+ if (lower_statement(state, stmt, returning))
return -1;
}
@@ -414,11 +490,6 @@ static int lower_block(struct state *state, struct ast *block, bool ret)
return -1;
}
- if (ret) {
- indent(state);
- printf("return nullptr;\n");
- }
-
decrease_indent(state);
indent(state);
printf("}");