diff --git a/lib/c3/0.1/c3.facts b/lib/c3/0.1/c3.facts
index b7cab56..7ffb67b 100644
--- a/lib/c3/0.1/c3.facts
+++ b/lib/c3/0.1/c3.facts
@@ -7,7 +7,8 @@
{C3, :symbol, C3.first}
{C3.first, :fn, fn {
([a | _b]) { a }
- ({a, b}) { a }
- ({a, b, c}) { a }
+ ({a, _b}) { a }
+ ({a, _b, _c}) { a }
+ ({a, _b, _c, _d}) { a }
}}
-%{hash: 0xED618BE2629E5F67}
+%{hash: 0xEB60A3EFBF9FC908}
diff --git a/libc3/cfn.c b/libc3/cfn.c
index c6df368..0cbb147 100644
--- a/libc3/cfn.c
+++ b/libc3/cfn.c
@@ -14,157 +14,366 @@
#include <assert.h>
#include <err.h>
#include <stdlib.h>
+#include <string.h>
#include "cfn.h"
#include "list.h"
+#include "sym.h"
-s_cfn * cfn_set_arg_types (s_cfn *cfn, s_list *arg_types)
+ffi_type * cfn_sym_to_ffi_type (const s_sym *sym);
+s_tag * cfn_tag_init (s_tag *tag, const s_sym *type);
+void * cfn_tag_to_ffi_value (s_tag *tag, const s_sym *type);
+
+s_tag * cfn_apply (s_cfn *cfn, s_list *args, s_tag *dest) {
+ void **arg_values = NULL;
+ s_list *cfn_arg_type;
+ sw i;
+ sw num_args;
+ void* result;
+ s_tag tmp;
+ assert(cfn);
+ num_args = list_length(args);
+ if (cfn->arity != num_args) {
+ warnx("cfn_apply: invalid number of arguments, expected %d, have %ld",
+ cfn->arity, num_args);
+ return NULL;
+ }
+ cfn_tag_init(&tmp, cfn->result_type);
+ /* make result point to tmp value */
+ result = cfn_tag_to_ffi_value(&tmp, cfn->result_type);
+ if (args) {
+ if (! (arg_values = malloc(sizeof(void *) * num_args)))
+ err(1, "cfn_apply");
+ cfn_arg_type = cfn->arg_types;
+ i = 0;
+ while (args) {
+ assert(cfn_arg_type->tag.type.type == TAG_SYM);
+ arg_values[i] = cfn_tag_to_ffi_value(&args->tag,
+ cfn_arg_type->tag.data.sym);
+ args = list_next(args);
+ cfn_arg_type = list_next(cfn_arg_type);
+ i++;
+ }
+ }
+ ffi_call(&cfn->cif, FFI_FN(cfn->p), result, arg_values);
+ free(arg_values);
+ *dest = tmp;
+ return dest;
+}
+
+void cfn_clean (s_cfn *cfn)
+{
+ assert(cfn);
+ list_delete_all(cfn->arg_types);
+}
+
+s_cfn * cfn_copy (const s_cfn *cfn, s_cfn *dest)
+{
+ assert(cfn);
+ assert(dest);
+ dest->name = cfn->name;
+ list_copy(cfn->arg_types, &dest->arg_types);
+ return dest;
+}
+
+s_cfn * cfn_init (s_cfn *cfn)
+{
+ assert(cfn);
+ bzero(cfn, sizeof(s_cfn));
+ return cfn;
+}
+
+s_cfn * cfn_set_type (s_cfn *cfn, s_list *arg_type,
+ const s_sym *result_type)
{
s_list *a;
ffi_type **arg_ffi_type = NULL;
sw arity;
ffi_cif cif;
u8 i = 0;
- ffi_type *result_type;
+ ffi_type *result_ffi_type;
assert(cfn);
- if ((arity = list_length(arg_types))) {
+ result_ffi_type = cfn_sym_to_ffi_type(result_type);
+ if ((arity = list_length(arg_type))) {
if (arity > 255) {
assert(arity <= 255);
errx(1, "cfn_set_arg_types: arity > 255");
}
- if (! (arg_types = malloc(sizeof(ffi_type *) * arity)))
+ if (! (arg_ffi_type = malloc(sizeof(ffi_type *) * arity)))
err(1, "cfn_set_arg_types");
- a = arg_types;
+ a = arg_type;
while (a) {
assert(i < arity);
- arg_ffi_type[i] = cfn_arg_type_to_ffi_type(&a->tag);
+ if (a->tag.type.type != TAG_SYM) {
+ assert(! "cfn_set_type: invalid type");
+ errx(1, "cfn_set_type: invalid type");
+ }
+ arg_ffi_type[i] = cfn_sym_to_ffi_type(a->tag.data.sym);
i++;
a = list_next(a);
}
}
- cfn->arg_types = arg_types;
+ ffi_prep_cif(&cif, FFI_DEFAULT_ABI, arity, result_ffi_type, arg_ffi_type);
+ cfn->arg_types = arg_type;
cfn->arity = arity;
+ cfn->cif = cif;
+ cfn->result_type = result_type;
return cfn;
}
-ffi_type * cfn_arg_type_to_ffi_type (const s_tag *tag)
+ffi_type * cfn_sym_to_ffi_type (const s_sym *sym)
{
assert(tag);
- assert(tag->type.type == TAG_SYM);
- if (tag->data.sym == sym_1("s8"))
+ if (sym == sym_1("s8"))
return &ffi_type_sint8;
- if (tag->data.sym == sym_1("s16"))
+ if (sym == sym_1("s16"))
return &ffi_type_sint16;
- if (tag->data.sym == sym_1("s32"))
+ if (sym == sym_1("s32"))
return &ffi_type_sint32;
- if (tag->data.sym == sym_1("s64"))
+ if (sym == sym_1("s64"))
return &ffi_type_sint64;
- if (tag->data.sym == sym_1("sw"))
+ if (sym == sym_1("sw"))
return &ffi_type_sint;
- if (tag->data.sym == sym_1("u8"))
+ if (sym == sym_1("u8"))
return &ffi_type_uint8;
- if (tag->data.sym == sym_1("u16"))
+ if (sym == sym_1("u16"))
return &ffi_type_uint16;
- if (tag->data.sym == sym_1("u32"))
+ if (sym == sym_1("u32"))
return &ffi_type_uint32;
- if (tag->data.sym == sym_1("u64"))
+ if (sym == sym_1("u64"))
return &ffi_type_uint64;
- if (tag->data.sym == sym_1("uw"))
+ if (sym == sym_1("uw"))
return &ffi_type_uint;
+ assert(! "cfn_sym_to_ffi_type: unknown type");
+ errx(1, "cfn_sym_to_ffi_type: unknown type");
+ return NULL;
}
-
-s_tag * cfn_apply (s_cfn *cfn, s_list *args) {
- void **arg_values;
- sw i;
- sw num_args;
- void* result;
- assert(cfn);
- assert(args);
- num_args = list_length(args);
- if (! num_args) {
- /* TODO */
- assert(! "todo");
- err(1, "todo");
- return NULL;
- }
- 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;
+e_tag_type cfn_sym_to_tag_type (const s_sym *sym)
+{
+ assert(tag);
+ if (sym == sym_1("void"))
+ return TAG_VOID;
+ if (sym == sym_1("bool"))
+ return TAG_BOOL;
+ if (sym == sym_1("call"))
+ return TAG_CALL;
+ if (sym == sym_1("call_fn"))
+ return TAG_CALL_FN;
+ if (sym == sym_1("call_macro"))
+ return TAG_CALL_MACRO;
+ if (sym == sym_1("cfn"))
+ return TAG_CFN;
+ if (sym == sym_1("character"))
+ return TAG_CHARACTER;
+ if (sym == sym_1("f32"))
+ return TAG_F32;
+ if (sym == sym_1("f64"))
+ return TAG_F64;
+ if (sym == sym_1("fn"))
+ return TAG_FN;
+ if (sym == sym_1("ident"))
+ return TAG_IDENT;
+ if (sym == sym_1("integer"))
+ return TAG_INTEGER;
+ if (sym == sym_1("s64"))
+ return TAG_S64;
+ if (sym == sym_1("s32"))
+ return TAG_S32;
+ if (sym == sym_1("s16"))
+ return TAG_S16;
+ if (sym == sym_1("s8"))
+ return TAG_S8;
+ if (sym == sym_1("u8"))
+ return TAG_U8;
+ if (sym == sym_1("u16"))
+ return TAG_U16;
+ if (sym == sym_1("u32"))
+ return TAG_U32;
+ if (sym == sym_1("u64"))
+ return TAG_U64;
+ if (sym == sym_1("list"))
+ return TAG_LIST;
+ if (sym == sym_1("ptag"))
+ return TAG_PTAG;
+ if (sym == sym_1("quote"))
+ return TAG_QUOTE;
+ if (sym == sym_1("str"))
+ return TAG_STR;
+ if (sym == sym_1("sym"))
+ return TAG_SYM;
+ if (sym == sym_1("tuple"))
+ return TAG_TUPLE;
+ assert(! "cfn_sym_to_tag_type: unknown type");
+ errx(1, "cfn_sym_to_tag_type: unknown type");
+ return TAG_VOID;
}
-void cfn_clean (s_cfn *cfn)
+s_tag * cfn_tag_init (s_tag *tag, const s_sym *type)
{
- assert(cfn);
- list_delete_all(cfn->arg_types);
+ assert(tag);
+ bzero(tag, sizeof(s_tag));
+ tag->type.type = cfn_sym_to_tag_type(type);
+ return tag;
}
-s_cfn * cfn_copy (const s_cfn *cfn, s_cfn *dest)
+const s_sym * cfn_tag_type_to_sym (e_tag_type tag_type)
{
- assert(cfn);
- assert(dest);
- dest->name = cfn->name;
- dest->arg_types = list_copy(cfn->arg_types);
- return dest;
+ switch (tag_type) {
+ case TAG_VOID: return sym_1("void");
+ case TAG_BOOL: return sym_1("bool");
+ case TAG_CALL: return sym_1("call");
+ case TAG_CALL_FN: return sym_1("call_fn");
+ case TAG_CALL_MACRO: return sym_1("call_macro");
+ case TAG_CFN: return sym_1("cfn");
+ case TAG_CHARACTER: return sym_1("character");
+ case TAG_F32: return sym_1("f32");
+ case TAG_F64: return sym_1("f64");
+ case TAG_FN: return sym_1("fn");
+ case TAG_IDENT: return sym_1("ident");
+ case TAG_INTEGER: return sym_1("integer");
+ case TAG_S64: return sym_1("s64");
+ case TAG_S32: return sym_1("s32");
+ case TAG_S16: return sym_1("s16");
+ case TAG_S8: return sym_1("s8");
+ case TAG_U8: return sym_1("u8");
+ case TAG_U16: return sym_1("u16");
+ case TAG_U32: return sym_1("u32");
+ case TAG_U64: return sym_1("u64");
+ case TAG_LIST: return sym_1("list");
+ case TAG_PTAG: return sym_1("ptag");
+ case TAG_QUOTE: return sym_1("quote");
+ case TAG_STR: return sym_1("str");
+ case TAG_SYM: return sym_1("sym");
+ case TAG_TUPLE: return sym_1("tuple");
+ case TAG_VAR: return sym_1("var");
+ }
+ assert(! "cfn_tag_type_to_sym: invalid tag type");
+ errx(1, "cfn_tag_type_to_sym: invalid tag type");
+ return NULL;
}
-s_cfn * cfn_init (s_cfn *cfn)
+void * cfn_tag_to_ffi_value (s_tag *tag, const s_sym *type)
{
- assert(cfn);
- bzero(cfn, sizeof(s_cfn));
- return cfn;
+ switch (tag->type.type) {
+ case TAG_VOID:
+ if (type == sym_1("void"))
+ return NULL;
+ goto invalid_type;
+ case TAG_BOOL:
+ if (type == sym_1("bool"))
+ return &tag->data.bool;
+ goto invalid_type;
+ case TAG_CALL:
+ if (type == sym_1("call"))
+ return &tag->data.call;
+ goto invalid_type;
+ case TAG_CALL_FN:
+ if (type == sym_1("call_fn"))
+ return &tag->data.call;
+ goto invalid_type;
+ case TAG_CALL_MACRO:
+ if (type == sym_1("call_macro"))
+ return &tag->data.call;
+ goto invalid_type;
+ case TAG_CFN:
+ if (type == sym_1("cfn"))
+ return &tag->data.cfn;
+ goto invalid_type;
+ case TAG_CHARACTER:
+ if (type == sym_1("character"))
+ return &tag->data.character;
+ goto invalid_type;
+ case TAG_F32:
+ if (type == sym_1("f32"))
+ return &tag->data.f32;
+ goto invalid_type;
+ case TAG_F64:
+ if (type == sym_1("f64"))
+ return &tag->data.f64;
+ goto invalid_type;
+ case TAG_FN:
+ if (type == sym_1("fn"))
+ return tag->data.fn;
+ goto invalid_type;
+ case TAG_IDENT:
+ if (type == sym_1("ident"))
+ return &tag->data.ident;
+ goto invalid_type;
+ case TAG_INTEGER:
+ if (type == sym_1("integer"))
+ return &tag->data.integer;
+ goto invalid_type;
+ case TAG_S64:
+ if (type == sym_1("s64"))
+ return &tag->data.s64;
+ goto invalid_type;
+ case TAG_S32:
+ if (type == sym_1("s32"))
+ return &tag->data.s32;
+ goto invalid_type;
+ case TAG_S16:
+ if (type == sym_1("s16"))
+ return &tag->data.s16;
+ goto invalid_type;
+ case TAG_S8:
+ if (type == sym_1("s8"))
+ return &tag->data.s8;
+ goto invalid_type;
+ case TAG_U8:
+ if (type == sym_1("u8"))
+ return &tag->data.u8;
+ goto invalid_type;
+ case TAG_U16:
+ if (type == sym_1("u16"))
+ return &tag->data.u16;
+ goto invalid_type;
+ case TAG_U32:
+ if (type == sym_1("u32"))
+ return &tag->data.u32;
+ goto invalid_type;
+ case TAG_U64:
+ if (type == sym_1("u64"))
+ return &tag->data.u64;
+ goto invalid_type;
+ case TAG_LIST:
+ if (type == sym_1("list"))
+ return tag->data.list;
+ goto invalid_type;
+ case TAG_PTAG:
+ if (type == sym_1("ptag"))
+ return (void *) tag->data.ptag;
+ goto invalid_type;
+ case TAG_QUOTE:
+ if (type == sym_1("quote"))
+ return &tag->data.quote;
+ goto invalid_type;
+ case TAG_STR:
+ if (type == sym_1("str"))
+ return &tag->data.str;
+ if (type == sym_1("char*"))
+ return (void *) tag->data.str.ptr.ps8;
+ goto invalid_type;
+ case TAG_SYM:
+ if (type == sym_1("sym"))
+ return (void *) tag->data.sym;
+ if (type == sym_1("str"))
+ return (void *) &tag->data.sym->str;
+ if (type == sym_1("char*"))
+ return (void *) tag->data.sym->str.ptr.ps8;
+ goto invalid_type;
+ case TAG_TUPLE:
+ if (type == sym_1("tuple"))
+ return &tag->data.tuple;
+ goto invalid_type;
+ case TAG_VAR:
+ goto invalid_type;
+ }
+ assert(! "cfn_tag_to_ffi_value: invalid tag type");
+ errx(1, "cfn_tag_to_ffi_value: invalid tag type");
+ return NULL;
+ invalid_type:
+ warnx("cfn_tag_to_ffi_value: cannot cast %s to %s",
+ cfn_tag_type_to_sym(tag->type.type)->str.ptr.ps8,
+ type->str.ptr.ps8);
+ return NULL;
}
diff --git a/libc3/types.h b/libc3/types.h
index d1d2b7b..ffe11ea 100644
--- a/libc3/types.h
+++ b/libc3/types.h
@@ -144,6 +144,7 @@ struct cfn {
const s_sym *name;
void *p;
u8 arity;
+ const s_sym *result_type;
s_list *arg_types;
ffi_cif cif;
};
diff --git a/test/facts_test_dump_file.expected.facts b/test/facts_test_dump_file.expected.facts
index 52b1c78..b171f23 100644
--- a/test/facts_test_dump_file.expected.facts
+++ b/test/facts_test_dump_file.expected.facts
@@ -24,4 +24,4 @@
{{:a, :b}, {:a, :b}, {:a, :b}}
{{{a, b}, {c, d}}, {{a, b}, {c, d}}, {{a, b}, {c, d}}}
{{{:a, :b}, {:c, :d}}, {{:a, :b}, {:c, :d}}, {{:a, :b}, {:c, :d}}}
-%{hash: 0x12B617E8ED748848}
+%{hash: 0xF8C5A41402BC491F}
diff --git a/test/facts_test_load_file.facts b/test/facts_test_load_file.facts
index 52b1c78..b171f23 100644
--- a/test/facts_test_load_file.facts
+++ b/test/facts_test_load_file.facts
@@ -24,4 +24,4 @@
{{:a, :b}, {:a, :b}, {:a, :b}}
{{{a, b}, {c, d}}, {{a, b}, {c, d}}, {{a, b}, {c, d}}}
{{{:a, :b}, {:c, :d}}, {{:a, :b}, {:c, :d}}, {{:a, :b}, {:c, :d}}}
-%{hash: 0x12B617E8ED748848}
+%{hash: 0xF8C5A41402BC491F}
diff --git a/test/facts_test_open_file.1.expected.facts b/test/facts_test_open_file.1.expected.facts
index 849c5b3..345a021 100644
--- a/test/facts_test_open_file.1.expected.facts
+++ b/test/facts_test_open_file.1.expected.facts
@@ -26,7 +26,7 @@
{{:a, :b}, {:a, :b}, {:a, :b}}
{{{a, b}, {c, d}}, {{a, b}, {c, d}}, {{a, b}, {c, d}}}
{{{:a, :b}, {:c, :d}}, {{:a, :b}, {:c, :d}}, {{:a, :b}, {:c, :d}}}
-%{hash: 0x12B617E8ED748848}
+%{hash: 0xF8C5A41402BC491F}
remove {"a", "a", "a"}
remove {:a, :a, :a}
remove {A, A, A}
diff --git a/test/facts_test_open_file.1.in.facts b/test/facts_test_open_file.1.in.facts
index 442f3c6..7cbcba1 100644
--- a/test/facts_test_open_file.1.in.facts
+++ b/test/facts_test_open_file.1.in.facts
@@ -26,4 +26,4 @@
{{:a, :b}, {:a, :b}, {:a, :b}}
{{{a, b}, {c, d}}, {{a, b}, {c, d}}, {{a, b}, {c, d}}}
{{{:a, :b}, {:c, :d}}, {{:a, :b}, {:c, :d}}, {{:a, :b}, {:c, :d}}}
-%{hash: 0x12B617E8ED748848}
+%{hash: 0xF8C5A41402BC491F}
diff --git a/test/facts_test_open_file.2.expected.facts b/test/facts_test_open_file.2.expected.facts
index e88f68e..a6435d5 100644
--- a/test/facts_test_open_file.2.expected.facts
+++ b/test/facts_test_open_file.2.expected.facts
@@ -26,7 +26,7 @@
{{:a, :b}, {:a, :b}, {:a, :b}}
{{{a, b}, {c, d}}, {{a, b}, {c, d}}, {{a, b}, {c, d}}}
{{{:a, :b}, {:c, :d}}, {{:a, :b}, {:c, :d}}, {{:a, :b}, {:c, :d}}}
-%{hash: 0x12B617E8ED748848}
+%{hash: 0xF8C5A41402BC491F}
add {b, b, b}
add {-18446744073709551617, -18446744073709551617, -18446744073709551617}
add {18446744073709551617, 18446744073709551617, 18446744073709551617}
diff --git a/test/facts_test_open_file.2.in.facts b/test/facts_test_open_file.2.in.facts
index e88f68e..a6435d5 100644
--- a/test/facts_test_open_file.2.in.facts
+++ b/test/facts_test_open_file.2.in.facts
@@ -26,7 +26,7 @@
{{:a, :b}, {:a, :b}, {:a, :b}}
{{{a, b}, {c, d}}, {{a, b}, {c, d}}, {{a, b}, {c, d}}}
{{{:a, :b}, {:c, :d}}, {{:a, :b}, {:c, :d}}, {{:a, :b}, {:c, :d}}}
-%{hash: 0x12B617E8ED748848}
+%{hash: 0xF8C5A41402BC491F}
add {b, b, b}
add {-18446744073709551617, -18446744073709551617, -18446744073709551617}
add {18446744073709551617, 18446744073709551617, 18446744073709551617}
diff --git a/test/facts_test_open_file.3.expected.facts b/test/facts_test_open_file.3.expected.facts
index fc578b8..8fe30ac 100644
--- a/test/facts_test_open_file.3.expected.facts
+++ b/test/facts_test_open_file.3.expected.facts
@@ -26,7 +26,7 @@
{{:a, :b}, {:a, :b}, {:a, :b}}
{{{a, b}, {c, d}}, {{a, b}, {c, d}}, {{a, b}, {c, d}}}
{{{:a, :b}, {:c, :d}}, {{:a, :b}, {:c, :d}}, {{:a, :b}, {:c, :d}}}
-%{hash: 0x12B617E8ED748848}
+%{hash: 0xF8C5A41402BC491F}
remove {a, a, a}
remove {-18446744073709551616, -18446744073709551616, -18446744073709551616}
remove {18446744073709551616, 18446744073709551616, 18446744073709551616}
diff --git a/test/facts_test_open_file.3.in.facts b/test/facts_test_open_file.3.in.facts
index ebbeb2a..0c8b296 100644
--- a/test/facts_test_open_file.3.in.facts
+++ b/test/facts_test_open_file.3.in.facts
@@ -26,7 +26,7 @@
{{:a, :b}, {:a, :b}, {:a, :b}}
{{{a, b}, {c, d}}, {{a, b}, {c, d}}, {{a, b}, {c, d}}}
{{{:a, :b}, {:c, :d}}, {{:a, :b}, {:c, :d}}, {{:a, :b}, {:c, :d}}}
-%{hash: 0x12B617E8ED748848}
+%{hash: 0xF8C5A41402BC491F}
remove {a, a, a}
remove {-18446744073709551616, -18446744073709551616, -18446744073709551616}
remove {18446744073709551616, 18446744073709551616, 18446744073709551616}
diff --git a/test/facts_test_save.expected.facts b/test/facts_test_save.expected.facts
index 442f3c6..7cbcba1 100644
--- a/test/facts_test_save.expected.facts
+++ b/test/facts_test_save.expected.facts
@@ -26,4 +26,4 @@
{{:a, :b}, {:a, :b}, {:a, :b}}
{{{a, b}, {c, d}}, {{a, b}, {c, d}}, {{a, b}, {c, d}}}
{{{:a, :b}, {:c, :d}}, {{:a, :b}, {:c, :d}}, {{:a, :b}, {:c, :d}}}
-%{hash: 0x12B617E8ED748848}
+%{hash: 0xF8C5A41402BC491F}