aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--include/fwd/ast.h18
-rw-r--r--include/fwd/mod.h69
-rw-r--r--mod/mem.c7
-rw-r--r--src/analyze.c21
-rw-r--r--src/lower.c195
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)
{
diff --git a/mod/mem.c b/mod/mem.c
index 96d6d0e..93360fb 100644
--- a/mod/mem.c
+++ b/mod/mem.c
@@ -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");