aboutsummaryrefslogtreecommitdiff
path: root/src/lower.c
diff options
context:
space:
mode:
Diffstat (limited to 'src/lower.c')
-rw-r--r--src/lower.c221
1 files changed, 210 insertions, 11 deletions
diff --git a/src/lower.c b/src/lower.c
index e29365d..9689928 100644
--- a/src/lower.c
+++ b/src/lower.c
@@ -27,7 +27,11 @@
static inline void mangle(FILE *f, struct ast *id)
{
- assert(id->k == AST_PROC_DEF || id->k == AST_VAR_DEF || id->k == AST_ID);
+ assert(id->k == AST_STRUCT_DEF
+ || id->k == AST_PROC_DEF
+ || id->k == AST_VAR_DEF
+ || id->k == AST_ID);
+
assert(id->s && id->scope);
fprintf(f, "%s_s%zu", id->s, id->scope->number);
}
@@ -150,6 +154,12 @@ static void add_defn(struct state *state, char *defn)
string_vec_append(state->defns, defn);
}
+static bool type_lowered(struct ast *type)
+{
+ assert(type->k == AST_STRUCT_DEF);
+ return ast_flags(type, AST_FLAG_LOWERED);
+}
+
static void add_type(struct state *state, char *type)
{
string_vec_append(state->types, type);
@@ -160,8 +170,10 @@ static int lower_block(struct state *state, struct ast *block, bool last);
static int lower_params(struct state *state, struct ast *params);
static int lower_expr(struct state *state, struct ast *expr);
static int lower_proc(struct state *state, struct ast *proc);
+static int lower_type_def(struct state *state, struct ast *type);
+static char *lower_type_str(struct state *state, struct scope *scope, struct type *type);
-static void _type_str(FILE *f, struct type *type)
+static int _type_str(FILE *f, struct state *state, struct scope *scope, struct type *type)
{
assert(type);
switch (type->k) {
@@ -201,14 +213,40 @@ static void _type_str(FILE *f, struct type *type)
fprintf(f, "fwd_closure_t");
break;
+ case TYPE_PURE_CLOSURE:
+ fprintf(f, "fwd_closure_t");
+ break;
+
+ case TYPE_ID: {
+ struct ast *def = file_scope_find_type(scope, type_str(type));
+
+ if (!ast_flags(def, AST_FLAG_LOWERED))
+ if (lower_type_def(state, def))
+ return -1;
+
+ char *name = mangle2(def);
+ fprintf(f, "%s", name);
+ free(name);
+ break;
+ }
+
+ case TYPE_PTR: {
+ char *rest = lower_type_str(state, scope, tptr_base(type));
+ fprintf(f, "%s*", rest);
+ free(rest);
+ break;
+ }
+
default:
internal_error("unhandled type lowering for %s", type_str(type));
abort();
break;
}
+
+ return 0;
}
-static char *lower_type_str(struct type *type)
+static char *lower_type_str(struct state *state, struct scope *scope, struct type *type)
{
assert(type);
@@ -216,9 +254,15 @@ static char *lower_type_str(struct type *type)
FILE *f = open_memstream(&type_buf, &type_len);
assert(f);
- _type_str(f, type);
+ int r = _type_str(f, state, scope, type);
fclose(f);
assert(type_buf);
+
+ if (r) {
+ free(type_buf);
+ return NULL;
+ }
+
return type_buf;
}
@@ -243,7 +287,7 @@ static int lower_closure_call(struct state *state, struct ast *call, struct ast
foreach_node(a, call_args(call)) {
returning |= a->k == AST_CLOSURE;
- char *type = lower_type_str(a->t);
+ char *type = lower_type_str(state, a->scope, a->t);
fprintf(ctx, " %s a%zu;\n", type, idx);
free(type);
@@ -269,7 +313,7 @@ out:
q, q);
}
else {
- fprintf(state->code, "stack = %s_call(stack, %s_ctx);\n",
+ fprintf(state->code, "stack = %s(stack, %s_ctx);\n",
q, q);
}
@@ -340,10 +384,26 @@ static int lower_comparison(struct state *state, struct ast *expr)
fprintf(state->code, " <= ");
break;
+ case AST_GE:
+ fprintf(state->code, " >= ");
+ break;
+
case AST_LT:
fprintf(state->code, " < ");
break;
+ case AST_GT:
+ fprintf(state->code, " > ");
+ break;
+
+ case AST_EQ:
+ fprintf(state->code, " == ");
+ break;
+
+ case AST_NE:
+ fprintf(state->code, " != ");
+ break;
+
default:
internal_error("unhandled lowering for comparison %s", ast_str(expr->k));
abort();
@@ -366,8 +426,12 @@ static int lower_binop(struct state *state, struct ast *expr)
fprintf(state->code, " + ");
break;
+ case AST_MUL:
+ fprintf(state->code, " * ");
+ break;
+
default:
- internal_error("unhandled comparison %s", ast_str(expr->k));
+ internal_error("unhandled binop %s", ast_str(expr->k));
abort();
}
@@ -406,6 +470,41 @@ static int lower_expr(struct state *state, struct ast *expr)
fprintf(state->code, "%lld", (long long)int_val(expr));
break;
}
+
+ case AST_NIL: {
+ fprintf(state->code, "NULL");
+ break;
+ }
+
+ case AST_CONSTRUCT: {
+ char *name = lower_type_str(state, expr->scope, expr->t);
+ fprintf(state->code, "(%s){", name);
+ free(name);
+
+ foreach_node(n, construct_members(expr)) {
+ fprintf(state->code, ".%s = ", construction_id(n));
+
+ if (lower_expr(state, construction_expr(n)))
+ return -1;
+
+ fprintf(state->code, ", ");
+ }
+ fprintf(state->code, "}");
+ break;
+ }
+
+ case AST_AS: {
+ char *name = lower_type_str(state, expr->scope, expr->t);
+ fprintf(state->code, "(%s)(", name);
+ free(name);
+
+ if (lower_expr(state, as_expr(expr)))
+ return -1;
+
+ fprintf(state->code, ")");
+ break;
+ }
+
default:
internal_error("unhandled expr lowering: %s", ast_str(expr->k));
abort();
@@ -445,7 +544,7 @@ static int lower_call(struct state *state, struct ast *call, bool last)
foreach_node(a, call_args(call)) {
returning |= a->k == AST_CLOSURE;
- char *type = lower_type_str(a->t);
+ char *type = lower_type_str(state, a->scope, a->t);
fprintf(ctx, " %s a%zu;\n", type, idx);
free(type);
@@ -508,11 +607,72 @@ static int lower_if(struct state *state, struct ast *stmt, bool last)
return lower_block(state, if_else(stmt), last);
}
+static int lower_explode(struct state *state, struct ast *stmt, bool last)
+{
+ /* not significant to us */
+ (void)last;
+
+ int u = uniq(state);
+ struct ast *expr = explode_expr(stmt);
+
+ char *type = lower_type_str(state, expr->scope, expr->t);
+
+ indent(state);
+ fprintf(state->code, "%s explode_%d = ", type, u);
+ free(type);
+
+ if (lower_expr(state, expr))
+ return -1;
+
+ fprintf(state->code, ";\n");
+
+ foreach_node(node, explode_deconstruct(stmt)) {
+ struct ast *var = deconstruction_var(node);
+
+ char *type = lower_type_str(state, var->scope, var->t);
+ char *name = mangle2(var);
+
+ indent(state);
+ fprintf(state->code, "%s %s = explode_%d.%s;\n",
+ type, name, u, deconstruction_id(node));
+
+ free(type);
+ free(name);
+ }
+
+ return 0;
+}
+
+static int lower_let(struct state *state, struct ast *stmt, bool last)
+{
+ /* not relevant */
+ (void)last;
+
+ struct ast *var = let_var(stmt);
+ char *type = lower_type_str(state, var->scope, var->t);
+ char *name = mangle2(var);
+
+ indent(state);
+ fprintf(state->code, "%s %s = ", type, name);
+
+ free(type);
+ free(name);
+
+ if (lower_expr(state, let_expr(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_EXPLODE: return lower_explode(state, stmt, last);
+ case AST_LET: return lower_let(state, stmt, last);
+ case AST_EMPTY: break;
default:
internal_error("unhandled statement kind %s", ast_str(stmt->k));
abort();
@@ -548,7 +708,7 @@ static int lower_block(struct state *state, struct ast *block, bool last)
static int lower_param(struct state *state, struct ast *param)
{
- char *type = lower_type_str(param->t);
+ char *type = lower_type_str(state, param->scope, param->t);
char *name = mangle2(param);
fprintf(state->ctx, " %s %s;\n", type, name);
@@ -644,7 +804,7 @@ static int lower_extern_proc(struct state *state, struct ast *proc)
idx + 1, fwd_typeid(p->t), fwd_typeparam(p->t), idx);
- char *type_str = lower_type_str(p->t);
+ 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++;
@@ -679,7 +839,7 @@ static int lower_extern_proc(struct state *state, struct ast *proc)
static int lower_param_copy(struct state *state, struct ast *param, FILE *f, size_t idx)
{
- char *type = lower_type_str(param->t);
+ char *type = lower_type_str(state, param->scope, param->t);
fprintf(f, " %s a%zu;\n", type, idx);
free(type);
@@ -716,6 +876,45 @@ static int lower_param_copies(struct state *state, struct ast *params)
return 0;
}
+static int lower_type_def(struct state *state, struct ast *type)
+{
+ assert(type->k == AST_STRUCT_DEF);
+ if (type_lowered(type))
+ return 0;
+
+ ast_flags(type, AST_FLAG_LOWERED);
+
+ char *decl_buf = NULL; size_t decl_len = 0;
+ FILE *decl = open_memstream(&decl_buf, &decl_len);
+ assert(decl);
+
+ char *name = mangle2(type);
+ fprintf(decl, "struct %s;\n", name);
+ fclose(decl);
+
+ char *defn_buf = NULL; size_t defn_len = 0;
+ FILE *defn = open_memstream(&defn_buf, &defn_len);
+ assert(defn);
+
+ fprintf(defn, "typedef struct %s {\n", name);
+
+ foreach_node(n, struct_body(type)) {
+ assert(n->k == AST_VAR_DEF);
+ char *t = lower_type_str(state, n->scope, var_type(n));
+ fprintf(defn, "\t%s %s;\n", t, var_id(n));
+ free(t);
+ }
+
+ fprintf(defn, "} %s;\n", name);
+
+ fclose(defn);
+ free(name);
+
+ add_type(state, decl_buf);
+ add_type(state, defn_buf);
+ return 0;
+}
+
static int lower_proc(struct state *state, struct ast *proc)
{
if (proc_lowered(state, proc))