diff --git a/libc3/arg.c b/libc3/arg.c
new file mode 100644
index 0000000..46b322d
--- /dev/null
+++ b/libc3/arg.c
@@ -0,0 +1,60 @@
+/* c3
+ * Copyright 2022 kmx.io <contact@kmx.io>
+ *
+ * Permission is hereby granted to use this software 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 <assert.h>
+#include <err.h>
+#include <stdlib.h>
+#include <strings.h>
+#include "arg.h"
+
+s_arg * arg_delete (s_arg *arg)
+{
+ s_arg *next = NULL;
+ if (arg) {
+ next = arg->next;
+ free(arg);
+ }
+ return next;
+}
+
+void arg_delete_all (s_arg *arg)
+{
+ while (arg)
+ arg = arg_delete(arg);
+}
+
+s_arg * arg_init (s_arg *arg, s_arg *next)
+{
+ assert(arg);
+ bzero(arg, sizeof(s_arg));
+ arg->next = next;
+ return arg;
+}
+
+uw arg_length (s_arg *arg)
+{
+ uw length = 0;
+ while (arg) {
+ length++;
+ arg = arg->next;
+ }
+ return length;
+}
+
+s_arg * arg_new (s_arg *next)
+{
+ s_arg *arg;
+ if (! (arg = malloc(sizeof(s_arg))))
+ errx(1, "arg_new: out of memory");
+ return arg_init(arg, next);
+}
diff --git a/libc3/arg.h b/libc3/arg.h
new file mode 100644
index 0000000..b14ea20
--- /dev/null
+++ b/libc3/arg.h
@@ -0,0 +1,32 @@
+/* c3
+ * Copyright 2022 kmx.io <contact@kmx.io>
+ *
+ * Permission is hereby granted to use this software 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 ARG_H
+#define ARG_H
+
+#include "types.h"
+
+/* stack-allocation compatible functions */
+s_arg * arg_init (s_arg *arg, s_arg *next);
+
+/* constructors */
+s_arg * arg_new ();
+
+/* destructors */
+s_arg * arg_delete (s_arg *arg);
+void arg_delete_all (s_arg *arg);
+
+/* observers */
+uw arg_length (s_arg *args);
+
+#endif /* ARG_H */
diff --git a/libc3/buf_inspect.c b/libc3/buf_inspect.c
index a76d3e1..2d7f89d 100644
--- a/libc3/buf_inspect.c
+++ b/libc3/buf_inspect.c
@@ -787,15 +787,15 @@ sw buf_inspect_tag (s_buf *buf, const s_tag *tag)
case TAG_VOID: return 0;
case TAG_BOOL: return buf_inspect_bool(buf, tag->data.bool);
case TAG_CALL:
- case TAG_CALL_FUNCTION:
+ case TAG_CALL_FN:
case TAG_CALL_MACRO:
return buf_inspect_call(buf, &tag->data.call);
case TAG_CHARACTER:
return buf_inspect_character(buf, tag->data.character);
case TAG_F32: return buf_inspect_f32(buf, tag->data.f32);
case TAG_F64: return buf_inspect_f64(buf, tag->data.f64);
- case TAG_FUNCTION:
- return buf_inspect_uw_hex(buf, (uw) &tag->data.function);
+ case TAG_FN:
+ return buf_inspect_uw_hex(buf, (uw) &tag->data.fn);
case TAG_IDENT: return buf_inspect_ident(buf, &tag->data.ident);
case TAG_INTEGER: return buf_inspect_integer(buf, &tag->data.integer);
case TAG_LIST: return buf_inspect_list(buf, tag->data.list);
@@ -825,14 +825,14 @@ sw buf_inspect_tag_size (const s_tag *tag)
case TAG_VOID: return 0;
case TAG_BOOL: return buf_inspect_bool_size(tag->data.bool);
case TAG_CALL:
- case TAG_CALL_FUNCTION:
+ case TAG_CALL_FN:
case TAG_CALL_MACRO:
return buf_inspect_call_size(&tag->data.call);
case TAG_CHARACTER:
return buf_inspect_character_size(tag->data.character);
case TAG_F32: return buf_inspect_f32_size(tag->data.f32);
case TAG_F64: return buf_inspect_f64_size(tag->data.f64);
- case TAG_FUNCTION: return BUF_INSPECT_UW_HEX_SIZE;
+ case TAG_FN: return BUF_INSPECT_UW_HEX_SIZE;
case TAG_IDENT: return buf_inspect_ident_size(&tag->data.ident);
case TAG_INTEGER:
return buf_inspect_integer_size(&tag->data.integer);
diff --git a/libc3/buf_inspect.h b/libc3/buf_inspect.h
index ab56126..0abd616 100644
--- a/libc3/buf_inspect.h
+++ b/libc3/buf_inspect.h
@@ -27,9 +27,9 @@
sw buf_inspect_bool (s_buf *buf, e_bool b);
sw buf_inspect_bool_size (e_bool b);
-sw buf_inspect_call (s_buf *buf, const s_call *funcall);
+sw buf_inspect_call (s_buf *buf, const s_call *call);
sw buf_inspect_call_args (s_buf *buf, const s_list *args);
-sw buf_inspect_call_size (const s_call *funcall);
+sw buf_inspect_call_size (const s_call *call);
sw buf_inspect_character (s_buf *buf, character c);
sw buf_inspect_character_size (character c);
sw buf_inspect_f32 (s_buf *buf, f32 x);
@@ -39,8 +39,8 @@ sw buf_inspect_f64_size (f64 x);
sw buf_inspect_fact (s_buf *buf, const s_fact *fact);
sw buf_inspect_fact_size (const s_fact *fact);
sw buf_inspect_fact_spec (s_buf *buf, p_facts_spec spec);
-sw buf_inspect_function (s_buf *buf, const s_function *fun);
-sw buf_inspect_function_size (const s_function *fun);
+sw buf_inspect_fn (s_buf *buf, const s_fn *fn);
+sw buf_inspect_fn_size (const s_fn *fn);
sw buf_inspect_ident (s_buf *buf, const s_ident *ident);
sw buf_inspect_ident_size (const s_ident *ident);
sw buf_inspect_integer (s_buf *buf, const s_integer *x);
diff --git a/libc3/buf_parse.c b/libc3/buf_parse.c
index 5ccc13c..5432c1b 100644
--- a/libc3/buf_parse.c
+++ b/libc3/buf_parse.c
@@ -16,18 +16,7 @@
#include <string.h>
#include <math.h>
#include "../libtommath/tommath.h"
-#include "buf.h"
-#include "buf_inspect.h"
-#include "buf_parse.h"
-#include "buf_save.h"
-#include "character.h"
-#include "ident.h"
-#include "integer.h"
-#include "list.h"
-#include "str.h"
-#include "sym.h"
-#include "tag.h"
-#include "tuple.h"
+#include "c3.h"
sw buf_parse_bool (s_buf *buf, bool *p)
{
@@ -427,6 +416,103 @@ sw buf_parse_fact (s_buf *buf, s_fact *dest)
return r;
}
+sw buf_parse_fn (s_buf *buf, s_fn *dest)
+{
+ sw r;
+ sw result = 0;
+ s_buf_save save;
+ assert(buf);
+ assert(dest);
+ buf_save_init(buf, &save);
+ if ((r = buf_read_1(buf, "fn")) <= 0)
+ return r;
+ result += r;
+ if ((r = buf_ignore_spaces(buf)) <= 0)
+ goto restore;
+ result += r;
+ fn_init(dest);
+ if ((r = buf_parse_fn_args(buf, &dest->args)) < 0)
+ goto restore;
+ dest->arity = arg_length(dest->args);
+ result += r;
+ if ((r = buf_ignore_spaces(buf)) < 0)
+ goto restore;
+ result += r;
+ if ((r = buf_parse_fn_algo(buf, &dest->algo)) <= 0)
+ goto restore;
+ r = result;
+ goto clean;
+ restore:
+ buf_save_restore_rpos(buf, &save);
+ clean:
+ buf_save_clean(buf, &save);
+ return r;
+}
+
+sw buf_parse_fn_algo (s_buf *buf, s_list **dest)
+{
+ sw r;
+ sw result = 0;
+ s_buf_save save;
+ s_tag tag;
+ assert(buf);
+ assert(dest);
+ if ((r = buf_read_1(buf, "{")) <= 0)
+ return r;
+ result += r;
+ if ((r = buf_ignore_spaces(buf)) < 0)
+ goto restore;
+ result += r;
+ while ((r = buf_parse_tag(buf, &tag)) > 0) {
+ result += r;
+ if (tag.type.type == TAG_IDENT &&
+ tag.data.ident.sym == sym_1(";"))
+ break;
+ *dest = list_new(NULL);
+ (*dest)->tag = tag;
+ tag_init_list(&(*dest)->next, NULL);
+ dest = &(*dest)->next.data.list;
+ if ((r = buf_ignore_spaces(buf)) < 0)
+ goto restore;
+ if ((r = buf_read_1(buf, ";")) < 0)
+ goto restore;
+ }
+ if (r < 0)
+ goto restore;
+ r = result;
+ goto clean;
+ restore:
+ buf_save_restore_rpos(buf, &save);
+ clean:
+ buf_save_clean(buf, &save);
+ return r;
+}
+
+sw buf_parse_fn_args (s_buf *buf, s_arg **dest)
+{
+ sw r;
+ sw result = 0;
+ s_buf_save save;
+ s_tag tag;
+ assert(buf);
+ assert(dest);
+ buf_save_init(buf, &save);
+ if ((r = buf_read_1(buf, "(")) < 0)
+ goto restore;
+ while (1) {
+ if ((r = buf_parse_tag(buf, &tag)) < 0)
+ goto restore;
+ result += r;
+ if ((r = buf_
+ r = result;
+ goto clean;
+ restore:
+ buf_save_restore_rpos(buf, &save);
+ clean:
+ buf_save_clean(buf, &save);
+ return r;
+}
+
sw buf_parse_ident (s_buf *buf, s_ident *dest)
{
character c;
diff --git a/libc3/buf_parse.h b/libc3/buf_parse.h
index ffa2a36..98e1eb1 100644
--- a/libc3/buf_parse.h
+++ b/libc3/buf_parse.h
@@ -40,6 +40,9 @@ sw buf_parse_digit_dec (s_buf *buf, u8 *dest);
sw buf_parse_f32 (s_buf *buf, f32 *dest);
sw buf_parse_f64 (s_buf *buf, f64 *dest);
sw buf_parse_fact (s_buf *buf, s_fact *dest);
+sw buf_parse_fn (s_buf *buf, s_fn *dest);
+sw buf_parse_fn_algo (s_buf *buf, s_list **dest);
+sw buf_parse_fn_args (s_buf *buf, s_arg **dest);
sw buf_parse_call (s_buf *buf, s_call *dest);
sw buf_parse_call_args (s_buf *buf, s_list **dest);
sw buf_parse_comments (s_buf *buf);
diff --git a/libc3/c3.h b/libc3/c3.h
index b437fbf..f921ab3 100644
--- a/libc3/c3.h
+++ b/libc3/c3.h
@@ -14,11 +14,13 @@
#ifndef C3_H
#define C3_H
+#include "arg.h"
#include "bool.h"
#include "buf.h"
#include "buf_file.h"
#include "buf_inspect.h"
#include "buf_parse.h"
+#include "buf_save.h"
#include "call.h"
#include "character.h"
#include "debug.h"
@@ -28,6 +30,7 @@
#include "f64.h"
#include "fact.h"
#include "facts.h"
+#include "fn.h"
#include "ident.h"
#include "integer.h"
#include "list.h"
diff --git a/libc3/eval.c b/libc3/eval.c
index eac1093..62e1eab 100644
--- a/libc3/eval.c
+++ b/libc3/eval.c
@@ -21,28 +21,29 @@
#include "list.h"
#include "tag.h"
-s_tag * eval_call_function (s_env *env, s_call *call, s_tag *dest)
+s_tag * eval_call_fn (s_env *env, s_call *call, s_tag *dest)
{
s_arg *args;
s_list *call_args;
s_frame frame;
- s_function *function;
+ s_fn *fn;
s_tag tmp;
assert(env);
assert(call);
assert(dest);
- function = call->function;
- assert(function);
+ fn = call->fn;
+ assert(fn);
frame_init(&frame, env->frame);
- frame.bindings = function->bindings;
- args = function->args;
+ frame.bindings = fn->bindings;
+ args = fn->args;
call_args = call->arguments;
while (args) {
if (! call_args) {
- assert(! "eval_function_call: missing argument");
- errx(1, "eval_function_call: missing argument");
+ assert(! "eval_call_fn: missing argument");
+ errx(1, "eval_call_fn: missing argument");
return NULL;
}
+ /* TODO: check type */
eval_tag(env, &call_args->tag, &tmp);
frame.bindings = binding_new(args->name, &call_args->tag,
frame.bindings);
@@ -50,12 +51,12 @@ s_tag * eval_call_function (s_env *env, s_call *call, s_tag *dest)
call_args = list_next(call_args);
}
if (call_args) {
- assert(! "eval_function_call: too many arguments");
- errx(1, "eval_function_call: too many arguments");
+ assert(! "eval_call_fn: too many arguments");
+ errx(1, "eval_call_fn: too many arguments");
return NULL;
}
env->frame = &frame;
- eval_progn(env, function->program, dest);
+ eval_progn(env, fn->program, dest);
env->frame = frame_clean(&frame);
return dest;
}
@@ -107,8 +108,8 @@ s_tag * eval_tag (s_env *env, s_tag *tag, s_tag *dest)
assert(! "eval_tag: invalid tag type: TAG_CALL");
errx(1, "eval_tag: invalid tag type TAG_CALL");
return NULL;
- case TAG_CALL_FUNCTION:
- return eval_call_function(env, &tag->data.call, dest);
+ case TAG_CALL_FN:
+ return eval_call_fn(env, &tag->data.call, dest);
case TAG_CALL_MACRO:
return eval_call_macro(env, &tag->data.call, dest);
case TAG_IDENT:
@@ -117,7 +118,7 @@ s_tag * eval_tag (s_env *env, s_tag *tag, s_tag *dest)
case TAG_CHARACTER:
case TAG_F32:
case TAG_F64:
- case TAG_FUNCTION:
+ case TAG_FN:
case TAG_INTEGER:
case TAG_LIST:
case TAG_PTAG:
diff --git a/libc3/eval.h b/libc3/eval.h
index 77f0a8b..4c8e5e6 100644
--- a/libc3/eval.h
+++ b/libc3/eval.h
@@ -19,8 +19,7 @@
s_tag * eval_call_function (s_env *env, s_call *call,
s_tag *dest);
s_tag * eval_call_macro (s_env *env, s_call *call, s_tag *dest);
-s_tag * eval_function (s_env *env, s_function *function,
- s_tag *dest);
+s_tag * eval_fn (s_env *env, s_fn *fn, s_tag *dest);
const s_tag * eval_ident (s_env *env, s_ident *ident);
s_tag * eval_progn (s_env *env, s_list *program, s_tag *dest);
s_tag * eval_tag (s_env *env, s_tag *tag, s_tag *dest);
diff --git a/libc3/fn.c b/libc3/fn.c
new file mode 100644
index 0000000..46b04b8
--- /dev/null
+++ b/libc3/fn.c
@@ -0,0 +1,34 @@
+/* c3
+ * Copyright 2022 kmx.io <contact@kmx.io>
+ *
+ * Permission is hereby granted to use this software 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 <assert.h>
+#include <strings.h>
+#include "arg.h"
+#include "binding.h"
+#include "fn.h"
+#include "list.h"
+
+void fn_clean (s_fn *fn)
+{
+ assert(fn);
+ arg_delete_all(fn->args);
+ binding_delete_all(fn->bindings);
+ list_delete_all(fn->program);
+}
+
+s_fn * fn_init (s_fn *fn)
+{
+ assert(fn);
+ bzero(fn, sizeof(s_fn));
+ return fn;
+}
diff --git a/libc3/fn.h b/libc3/fn.h
new file mode 100644
index 0000000..2552dc2
--- /dev/null
+++ b/libc3/fn.h
@@ -0,0 +1,28 @@
+/* c3
+ * Copyright 2022 kmx.io <contact@kmx.io>
+ *
+ * Permission is hereby granted to use this software 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.
+ */
+/**
+ * @file fn.h
+ * Function type.
+ *
+ * Syntax : "fn" (type? "(" ((type space)? sym ","?)* ")" "{" prog "}")+
+ */
+#ifndef FN_H
+#define FN_H
+
+#include "types.h"
+
+s_fn * fn_init (s_fn *fn);
+void fn_clean (s_fn *fn);
+
+#endif /* FN_H */
diff --git a/libc3/function.h b/libc3/function.h
deleted file mode 100644
index bbb7a13..0000000
--- a/libc3/function.h
+++ /dev/null
@@ -1,22 +0,0 @@
-/* c3
- * Copyright 2022 kmx.io <contact@kmx.io>
- *
- * Permission is hereby granted to use this software 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 FUNCTION_H
-#define FUNCTION_H
-
-#include "types.h"
-
-s_function * function_init (s_function *function);
-void function_clean (s_function *function);
-
-#endif /* FUNCTION_H */
diff --git a/libc3/list.c b/libc3/list.c
index 862e3bc..acd27aa 100644
--- a/libc3/list.c
+++ b/libc3/list.c
@@ -83,10 +83,21 @@ s_list * list_copy (const s_list *src, s_list **dest)
return result;
}
-void list_delete (s_list *list)
+s_list * list_delete (s_list *list)
{
- list_clean(list);
- free(list);
+ s_list *next = NULL;
+ if (list) {
+ next = list_next(list);
+ list_clean(list);
+ free(list);
+ }
+ return next;
+}
+
+void list_delete_all (s_list *list)
+{
+ while (list)
+ list = list_delete(list);
}
/* FIXME: dotted lists, circular lists */
diff --git a/libc3/list.h b/libc3/list.h
index eee1608..25ceec1 100644
--- a/libc3/list.h
+++ b/libc3/list.h
@@ -34,7 +34,8 @@ s_list * list_1 (const s8 *p);
s_list * list_new ();
/* Destructor */
-void list_delete (s_list *list);
+s_list * list_delete (s_list *list);
+void list_delete_all (s_list *list);
/* Observers */
s8 list_compare (const s_list *a, const s_list *b);
diff --git a/libc3/tag.c b/libc3/tag.c
index a35df0b..407b31a 100644
--- a/libc3/tag.c
+++ b/libc3/tag.c
@@ -151,14 +151,14 @@ s8 tag_compare (const s_tag *a, const s_tag *b) {
case TAG_VOID: return 0;
case TAG_BOOL: return bool_compare(a->data.bool, b->data.bool);
case TAG_CALL:
- case TAG_CALL_FUNCTION:
+ case TAG_CALL_FN:
case TAG_CALL_MACRO:
return call_compare(&a->data.call, &b->data.call);
case TAG_CHARACTER: return character_compare(a->data.character,
b->data.character);
case TAG_F32: return f32_compare(a->data.f32, b->data.f32);
case TAG_F64: return f64_compare(a->data.f64, b->data.f64);
- case TAG_FUNCTION: return ptr_compare(a, b);
+ case TAG_FN: return ptr_compare(a, b);
case TAG_IDENT: return ident_compare(&a->data.ident, &b->data.ident);
case TAG_INTEGER: return integer_compare(&a->data.integer,
&b->data.integer);
@@ -243,14 +243,14 @@ t_hash_context * tag_hash_update (t_hash_context *context,
case TAG_VOID: break;
case TAG_BOOL: bool_hash_update(context, tag->data.bool); break;
case TAG_CALL:
- case TAG_CALL_FUNCTION:
+ case TAG_CALL_FN:
case TAG_CALL_MACRO:
call_hash_update(context, &tag->data.call); break;
case TAG_CHARACTER:
character_hash_update(context, tag->data.character); break;
case TAG_F32: f32_hash_update(context, tag->data.f32); break;
case TAG_F64: f64_hash_update(context, tag->data.f64); break;
- case TAG_FUNCTION: u64_hash_update(context, (u64) tag); break;
+ case TAG_FN: u64_hash_update(context, (u64) tag); break;
case TAG_IDENT: ident_hash_update(context, &tag->data.ident); break;
case TAG_INTEGER:
integer_hash_update(context, &tag->data.integer); break;
diff --git a/libc3/types.h b/libc3/types.h
index 3007a38..850e114 100644
--- a/libc3/types.h
+++ b/libc3/types.h
@@ -47,12 +47,12 @@ typedef enum {
TAG_VOID = 0,
TAG_BOOL = 1,
TAG_CALL,
- TAG_CALL_FUNCTION,
+ TAG_CALL_FN,
TAG_CALL_MACRO,
TAG_CHARACTER,
TAG_F32,
TAG_F64,
- TAG_FUNCTION,
+ TAG_FN,
TAG_IDENT,
TAG_INTEGER,
TAG_S64,
@@ -86,8 +86,8 @@ typedef struct facts_cursor s_facts_cursor;
typedef struct facts_spec_cursor s_facts_spec_cursor;
typedef struct facts_with_cursor s_facts_with_cursor;
typedef struct facts_with_cursor_level s_facts_with_cursor_level;
+typedef struct fn s_fn;
typedef struct frame s_frame;
-typedef struct function s_function;
typedef struct ident s_ident;
typedef struct integer s_integer;
typedef struct list s_list;
@@ -141,11 +141,11 @@ struct frame {
s_frame *next;
};
-struct function {
+struct fn {
uw arity;
s_arg *args;
s_binding *bindings;
- s_list *program;
+ s_list *algo;
};
struct ident {
@@ -214,7 +214,7 @@ struct buf {
struct call {
s_ident ident;
s_list *arguments;
- s_function *function;
+ s_fn *fn;
};
struct facts_spec_cursor {
@@ -243,7 +243,7 @@ union tag_data {
character character;
f32 f32;
f64 f64;
- s_function function;
+ s_fn fn;
s_ident ident;
s_integer integer;
s_list *list;