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 | |
| parent | 99601456e6ad4c86287ba786923c99c5499037e0 (diff) | |
| download | fwd-ee50ee4ef760521c0764177b3bb8fed25beb2092.tar.gz fwd-ee50ee4ef760521c0764177b3bb8fed25beb2092.zip | |
vec example produces C, but broken C
| -rw-r--r-- | include/fwd/ast.h | 18 | ||||
| -rw-r--r-- | include/fwd/mod.h | 69 | ||||
| -rw-r--r-- | mod/mem.c | 7 | ||||
| -rw-r--r-- | src/analyze.c | 21 | ||||
| -rw-r--r-- | src/lower.c | 195 |
5 files changed, 268 insertions, 42 deletions
diff --git a/include/fwd/ast.h b/include/fwd/ast.h index 0fd1118..1d784f1 100644 --- a/include/fwd/ast.h +++ b/include/fwd/ast.h @@ -73,6 +73,24 @@ static inline bool is_ptr_type(enum type_kind k) return false; } +static inline bool is_closure_type(enum type_kind k) +{ + switch (k) { + case TYPE_CLOSURE: + case TYPE_PURE_CLOSURE: + return true; + default: + return false; + } + + return false; +} + +static inline bool is_c_type(enum type_kind k) +{ + return is_int_type(k) || is_ptr_type(k); +} + struct type { enum type_kind k; diff --git a/include/fwd/mod.h b/include/fwd/mod.h index 51aa9c4..c77e76c 100644 --- a/include/fwd/mod.h +++ b/include/fwd/mod.h @@ -1,6 +1,8 @@ #ifndef FWD_MOD_H #define FWD_MOD_H +#include <stdbool.h> +#include <stdint.h> #include <stddef.h> #include <assert.h> #include <stdlib.h> @@ -23,6 +25,13 @@ typedef enum fwd_type { typedef struct fwd_arg { fwd_type_t t; union { + uint8_t u8; + uint16_t u16; + uint32_t u32; + uint64_t u64; + int8_t i8; + int16_t i16; + int32_t i32; int64_t i64; void *p; }; @@ -49,7 +58,7 @@ static inline void *fwd_arg(fwd_extern_args_t args, size_t idx, fwd_type_t id) assert(args.args[idx + 1].t == id); switch (id) { case FWD_I64: return &args.args[idx + 1].i64; - default: + default: abort(); } return NULL; @@ -61,9 +70,63 @@ static inline void *fwd_arg(fwd_extern_args_t args, size_t idx, fwd_type_t id) #define FWD_ARG_T(args, idx, type) \ FWD_ARG(args, idx, type, FWD_T(type)) +static inline fwd_arg_t fwd_ret_u8(uint8_t x) +{ + return (fwd_arg_t){FWD_U8, {.u8 = x}}; +} + +static inline fwd_arg_t fwd_ret_u16(uint16_t x) +{ + return (fwd_arg_t){FWD_U16, {.u16 = x}}; +} + +static inline fwd_arg_t fwd_ret_u32(uint32_t x) +{ + return (fwd_arg_t){FWD_U32, {.u32 = x}}; +} + +static inline fwd_arg_t fwd_ret_u64(uint64_t x) +{ + return (fwd_arg_t){FWD_U64, {.u64 = x}}; +} + +static inline fwd_arg_t fwd_ret_i8(int8_t x) +{ + return (fwd_arg_t){FWD_I8, {.i8 = x}}; +} + +static inline fwd_arg_t fwd_ret_i16(int16_t x) +{ + return (fwd_arg_t){FWD_I16, {.i16 = x}}; +} + +static inline fwd_arg_t fwd_ret_i32(int32_t x) +{ + return (fwd_arg_t){FWD_I32, {.i32 = x}}; +} + +static inline fwd_arg_t fwd_ret_i64(int64_t x) +{ + return (fwd_arg_t){FWD_I64, {.i64 = x}}; +} + +static inline fwd_arg_t fwd_ret_ptr(void *x) +{ + return (fwd_arg_t){FWD_PTR, {.p = x}}; +} + /* unimplemented as of yet */ -#define FWD_RET(id, x) \ - abort() +#define FWD_RET(t, a, x) \ + (a).args[0] = _Generic((t)(0), \ + int8_t : fwd_ret_i8, \ + int16_t : fwd_ret_i16, \ + int32_t : fwd_ret_i32, \ + int64_t : fwd_ret_i64, \ + uint8_t : fwd_ret_u8, \ + uint16_t : fwd_ret_u16, \ + uint32_t : fwd_ret_u32, \ + uint64_t : fwd_ret_u64, \ + default : fwd_ret_ptr)((x)); static inline fwd_type_t fwd_t_signed(size_t s) { @@ -4,7 +4,7 @@ long fwdmalloc(fwd_extern_args_t args) { assert(args.argc == 1); size_t n = FWD_ARG_T(args, 0, size_t); - FWD_RET(FWD_PTR, malloc(n)); + FWD_RET(void *, args, malloc(n)); return 0; } @@ -13,7 +13,7 @@ long fwdrealloc(fwd_extern_args_t args) assert(args.argc == 2); void *ptr = FWD_ARG(args, 0, void *, FWD_PTR); size_t n = FWD_ARG_T(args, 1, size_t); - FWD_RET(FWD_PTR, realloc(ptr, n)); + FWD_RET(void *, args, realloc(ptr, n)); return 0; } @@ -21,6 +21,7 @@ long fwdfree(fwd_extern_args_t args) { assert(args.argc == 1); void *ptr = FWD_ARG(args, 0, void *, FWD_PTR); + free(ptr); return 0; } @@ -29,7 +30,7 @@ long fwdptradd(fwd_extern_args_t args) assert(args.argc == 2); void *ptr = FWD_ARG(args, 0, void *, FWD_PTR); int64_t add = FWD_ARG_T(args, 1, int64_t); - FWD_RET(FWD_PTR, (char *)ptr + add); + FWD_RET(char *, args, (char *)ptr + add); return 0; } 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"); |
