diff options
| author | Kimplul <kimi.h.kuparinen@gmail.com> | 2026-02-25 22:42:22 +0200 |
|---|---|---|
| committer | Kimplul <kimi.h.kuparinen@gmail.com> | 2026-02-25 22:42:22 +0200 |
| commit | ee50ee4ef760521c0764177b3bb8fed25beb2092 (patch) | |
| tree | 667aa45aa853e31e856f557fe73325929cb8fa08 /src | |
| parent | 99601456e6ad4c86287ba786923c99c5499037e0 (diff) | |
| download | fwd-ee50ee4ef760521c0764177b3bb8fed25beb2092.tar.gz fwd-ee50ee4ef760521c0764177b3bb8fed25beb2092.zip | |
vec example produces C, but broken C
Diffstat (limited to 'src')
| -rw-r--r-- | src/analyze.c | 21 | ||||
| -rw-r--r-- | src/lower.c | 195 |
2 files changed, 180 insertions, 36 deletions
diff --git a/src/analyze.c b/src/analyze.c index 04b7856..c05542a 100644 --- a/src/analyze.c +++ b/src/analyze.c @@ -447,16 +447,9 @@ static int analyze_str(struct state *state, struct scope *scope, (void)scope; /** @todo do this properly, very hacky, bad bad bad */ - char *i = strdup("char"); - if (!i) { - internal_error("failed allocating constant char type string"); - return -1; - } - - struct type *ch = tgen_id(i, node->loc); + struct type *ch = tgen_type(TYPE_U8, NULL, NULL, node->loc); if (!ch) { internal_error("failed allocating constant char type"); - free(i); return -1; } @@ -1117,13 +1110,15 @@ static struct type *fwd_type_kind(fwd_type_t type) { switch (type) { case FWD_VOID: return tgen_void(NULL_LOC()); + case FWD_I8: return tgen_type(TYPE_I8, NULL, NULL, NULL_LOC()); + case FWD_I16: return tgen_type(TYPE_I16, NULL, NULL, NULL_LOC()); + case FWD_I32: return tgen_type(TYPE_I32, NULL, NULL, NULL_LOC()); case FWD_I64: return tgen_type(TYPE_I64, NULL, NULL, NULL_LOC()); + case FWD_U8: return tgen_type(TYPE_U8, NULL, NULL, NULL_LOC()); + case FWD_U16: return tgen_type(TYPE_U16, NULL, NULL, NULL_LOC()); + case FWD_U32: return tgen_type(TYPE_U32, NULL, NULL, NULL_LOC()); case FWD_U64: return tgen_type(TYPE_U64, NULL, NULL, NULL_LOC()); - case FWD_PTR: { - /* hack? */ - return tgen_nil(NULL_LOC()); - } - + case FWD_PTR: return tgen_nil(NULL_LOC()); default: break; } 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"); |
