diff --git a/libc3/cfn.c b/libc3/cfn.c
new file mode 100644
index 0000000..6eba261
--- /dev/null
+++ b/libc3/cfn.c
@@ -0,0 +1,92 @@
+/* c3
+ * Copyright 2022,2023 kmx.io <contact@kmx.io>
+ *
+ * Permission is hereby granted to use this software excepted
+ * on Apple computers granted the above copyright notice and
+ * this permission paragraph are included in all copies and
+ * substantial portions of this software.
+ *
+ * THIS SOFTWARE IS PROVIDED "AS-IS" WITHOUT ANY GUARANTEE OF
+ * PURPOSE AND PERFORMANCE. IN NO EVENT WHATSOEVER SHALL THE
+ * AUTHOR BE CONSIDERED LIABLE FOR THE USE AND PERFORMANCE OF
+ * THIS SOFTWARE.
+ */
+#include "cfn.h"
+
+s_tag * cfn_apply (s_cfn *cfn, s_list *args) {
+ ffi_type **arg_types;
+ void **arg_values;
+ ffi_cif cif;
+ sw i;
+ sw num_args;
+ void* result;
+ ffi_type* result_type;
+ num_args = list_length(args);
+ if (! num_args) {
+ /* TODO */
+ assert(! "todo");
+ err(1, "todo");
+ return NULL;
+ }
+ if (! (arg_types = malloc(sizeof(ffi_type *) * num_args)))
+ err(1, "cfn_apply");
+ if (! (arg_values = malloc(sizeof(void *) * num_args)))
+ err(1, "cfn_apply");
+ while (args) {
+ switch (args->tag.type.type) {
+ case TAG_S8:
+ arg_types[num_args] = &ffi_type_sint;
+ arg_values[num_args] = args->data;
+ num_args++;
+ break;
+ case FLOAT:
+ arg_types[num_args] = &ffi_type_float;
+ arg_values[num_args] = args->data;
+ num_args++;
+ break;
+ case STRING:
+ arg_types[num_args] = &ffi_type_pointer;
+ arg_values[num_args] = &args->data;
+ num_args++;
+ break;
+ }
+
+ args = args->next;
+ }
+
+ ffi_type** final_arg_types = malloc(sizeof(ffi_type*) * num_args);
+ void** final_arg_values = malloc(sizeof(void*) * num_args);
+
+ for (int i = 0; i < num_args; i++) {
+ final_arg_types[i] = arg_types[i];
+ final_arg_values[i] = arg_values[i];
+ }
+
+ ffi_prep_cif_var(&cif, FFI_DEFAULT_ABI, num_args, NULL, final_arg_types);
+
+ switch (((Node*)fn_ptr)->tag) {
+ case INT:
+ result_type = &ffi_type_sint;
+ break;
+ case FLOAT:
+ result_type = &ffi_type_float;
+ break;
+ case STRING:
+ result_type = &ffi_type_pointer;
+ break;
+ }
+
+ ffi_call(&cif, ((Node*)fn_ptr)->data, result, final_arg_values);
+
+ free(final_arg_types);
+ free(final_arg_values);
+
+ if (((Node*)fn_ptr)->tag == STRING) {
+ char* result_copy = strdup(result);
+ free_result(result, ((Node*)fn_ptr)->tag);
+ result = result_copy;
+ }
+
+ return result;
+}
+#endif /* CFN_H */
diff --git a/libc3/cfn.h b/libc3/cfn.h
new file mode 100644
index 0000000..0c5a90a
--- /dev/null
+++ b/libc3/cfn.h
@@ -0,0 +1,23 @@
+/* c3
+ * Copyright 2022,2023 kmx.io <contact@kmx.io>
+ *
+ * Permission is hereby granted to use this software excepted
+ * on Apple computers granted the above copyright notice and
+ * this permission paragraph are included in all copies and
+ * substantial portions of this software.
+ *
+ * THIS SOFTWARE IS PROVIDED "AS-IS" WITHOUT ANY GUARANTEE OF
+ * PURPOSE AND PERFORMANCE. IN NO EVENT WHATSOEVER SHALL THE
+ * AUTHOR BE CONSIDERED LIABLE FOR THE USE AND PERFORMANCE OF
+ * THIS SOFTWARE.
+ */
+#ifndef CFN_H
+#define CFN_H
+
+#include "types.h"
+
+/* stack-allocation compatible functions */
+s_cfn * cfn_init (s_cfn *cfn);
+void cfn_clean (s_cfn *cfn);
+
+#endif /* CFN_H */
diff --git a/libc3/types.h b/libc3/types.h
index 279a8dd..6261e22 100644
--- a/libc3/types.h
+++ b/libc3/types.h
@@ -57,6 +57,7 @@ typedef enum {
TAG_CALL,
TAG_CALL_FN,
TAG_CALL_MACRO,
+ TAG_CFN,
TAG_CHARACTER,
TAG_F32,
TAG_F64,
@@ -86,6 +87,7 @@ typedef struct binding s_binding;
typedef struct buf s_buf;
typedef struct buf_save s_buf_save;
typedef struct call s_call;
+typedef struct cfn s_cfn;
typedef struct env s_env;
typedef struct error_handler s_error_handler;
typedef struct fact s_fact;
@@ -110,6 +112,7 @@ typedef struct sym s_sym;
typedef struct sym_list s_sym_list;
typedef struct tag s_tag;
typedef struct tuple s_tuple;
+typedef struct type_list s_type_list;
typedef struct unwind_protect s_unwind_protect;
/* unions */
@@ -136,6 +139,11 @@ struct buf_save {
uw wpos;
};
+struct cfn {
+ const s_sym *name;
+ void *p;
+};
+
struct fact {
const s_tag *subject;
const s_tag *predicate;
@@ -204,6 +212,11 @@ struct tuple {
s_tag *tag;
};
+struct type_list {
+ e_tag_type type;
+ s_type_list *next;
+};
+
struct unwind_protect {
jmp_buf buf;
jmp_buf *jmp;
@@ -283,6 +296,7 @@ struct sym {
union tag_data {
bool bool;
s_call call;
+ s_cfn *cfn;
character character;
f32 f32;
f64 f64;