Commit 305b8642bed083e8fe8be6d9c1c1dfff99d02caf

Thomas de Grivel 2023-08-11T09:17:45

fix call

diff --git a/libc3/cfn.c b/libc3/cfn.c
index 4a11cfb..6bea741 100644
--- a/libc3/cfn.c
+++ b/libc3/cfn.c
@@ -153,6 +153,17 @@ s_cfn * cfn_link (s_cfn *cfn)
   return cfn;
 }
 
+s_cfn * cfn_new_copy (const s_cfn *src)
+{
+  s_cfn *cfn;
+  if (! (cfn = calloc(1, sizeof(s_cfn)))) {
+    errx(1, "cfn_new_copy: out of memory");
+    return NULL;
+  }
+  cfn_copy(src, cfn);
+  return cfn;
+}
+
 s_cfn * cfn_prep_cif (s_cfn *cfn)
 {
   s_list *a;
diff --git a/libc3/cfn.h b/libc3/cfn.h
index ce790f2..285c49d 100644
--- a/libc3/cfn.h
+++ b/libc3/cfn.h
@@ -20,6 +20,9 @@ s_cfn * cfn_init (s_cfn *cfn, const s_sym *name, s_list *arg_types,
                   const s_sym *result_type);
 void    cfn_clean (s_cfn *cfn);
 
+/* constructor */
+s_cfn * cfn_new_copy (const s_cfn *src);
+
 /* observers */
 s_tag * cfn_apply (s_cfn *cfn, s_list *args, s_tag *dest);
 s_cfn * cfn_copy (const s_cfn *cfn, s_cfn *dest);
diff --git a/libc3/env.c b/libc3/env.c
index 24c3a40..b4e2396 100644
--- a/libc3/env.c
+++ b/libc3/env.c
@@ -71,98 +71,30 @@ void env_error_tag (s_env *env, const s_tag *tag)
   }
 }
 
-bool env_resolve_call (s_env *env, s_call *call)
-{
-  s_facts_with_cursor cursor;
-  s_tag tag_cfn;
-  s_tag tag_fn;
-  s_tag tag_ident;
-  s_tag tag_is_a;
-  s_tag tag_macro;
-  s_tag tag_module;
-  s_tag tag_module_name;
-  s_tag tag_special_operator;
-  s_tag tag_sym;
-  s_tag tag_symbol;
-  s_tag tag_var;
-  assert(env);
-  assert(call);
-  ident_resolve_module(&call->ident, env);
-  tag_init_1(    &tag_cfn,      ":cfn");
-  tag_init_1(    &tag_fn,       ":fn");
-  tag_init_ident(&tag_ident, &call->ident);
-  tag_init_1(    &tag_is_a,     ":is_a");
-  tag_init_1(    &tag_macro,    ":macro");
-  tag_init_1(    &tag_module,   ":module");
-  tag_init_sym(  &tag_module_name, call->ident.module_name);
-  tag_init_1(    &tag_special_operator, ":special_operator");
-  tag_init_sym(  &tag_sym, call->ident.sym);
-  tag_init_1(    &tag_symbol,   ":symbol");
-  tag_init_var(  &tag_var);
-  facts_with(&env->facts, &cursor, (t_facts_spec) {
-      &tag_module_name,
-      &tag_is_a, &tag_module,     /* module exists */
-      &tag_symbol, &tag_ident,    /* module exports symbol */
-      NULL, NULL });
-  if (! facts_with_cursor_next(&cursor))
-    errx(1, "symbol %s not found in module %s",
-         call->ident.sym->str.ptr.ps8,
-         call->ident.module_name->str.ptr.ps8);
-  facts_with_cursor_clean(&cursor);
-  facts_with(&env->facts, &cursor, (t_facts_spec) {
-      &tag_ident, &tag_fn, &tag_var,
-      NULL, NULL });
-  if (facts_with_cursor_next(&cursor)) {
-    if (tag_var.type != TAG_FN)
-      errx(1, "%s.%s is not a function",
-           call->ident.module_name->str.ptr.ps8,
-           call->ident.sym->str.ptr.ps8);
-    call->fn = tag_var.data.fn;
-  }
-  facts_with_cursor_clean(&cursor);
-  facts_with(&env->facts, &cursor, (t_facts_spec) {
-      &tag_ident, &tag_cfn, &tag_var,
-      NULL, NULL });
-  if (facts_with_cursor_next(&cursor)) {
-    if (tag_var.type != TAG_CFN)
-      errx(1, "%s.%s is not a C function",
-           call->ident.module_name->str.ptr.ps8,
-           call->ident.sym->str.ptr.ps8);
-    call->cfn = &tag_var.data.cfn;
-  }
-  facts_with_cursor_clean(&cursor);
-  facts_with(&env->facts, &cursor, (t_facts_spec) {
-      &tag_ident, &tag_is_a, &tag_macro, NULL, NULL });
-  if (facts_with_cursor_next(&cursor))
-    call->macro = true;
-  facts_with_cursor_clean(&cursor);
-  facts_with(&env->facts, &cursor, (t_facts_spec) {
-      &tag_ident, &tag_is_a, &tag_special_operator, NULL, NULL});
-  if (facts_with_cursor_next(&cursor))
-    call->special_operator = true;
-  facts_with_cursor_clean(&cursor);
-  return true;
-}
-
 bool env_eval_call (s_env *env, const s_call *call, s_tag *dest)
 {
   s_call c;
+  bool result = false;
   assert(env);
   assert(call);
   assert(dest);
   call_copy(call, &c);
   env_resolve_call(env, &c);
   if (c.macro)
-    return env_eval_call_macro(env, &c, dest);
-  if (c.special_operator)
-    return env_eval_call_special_operator(env, &c, dest);
-  if (c.cfn)
-    return env_eval_call_cfn(env, &c, dest);
-  if (c.fn)
-    return env_eval_call_fn(env, &c, dest);
-  warnx("env_eval_call: could not resolve call %s.",
-        call->ident.sym->str.ptr.ps8);
-  return false;
+    result = env_eval_call_macro(env, &c, dest);
+  else if (c.special_operator)
+    result = env_eval_call_special_operator(env, &c, dest);
+  else if (c.cfn)
+    result = env_eval_call_cfn(env, &c, dest);
+  else if (c.fn)
+    result = env_eval_call_fn(env, &c, dest);
+  else {
+    warnx("env_eval_call: could not resolve call %s.",
+          call->ident.sym->str.ptr.ps8);
+    result = false;
+  }
+  call_clean(&c);
+  return result;
 }
 
 bool env_eval_call_arguments (s_env *env, s_list *args, s_list **dest)
@@ -759,6 +691,79 @@ void env_push_unwind_protect (s_env *env,
   env->unwind_protect = unwind_protect;
 }
 
+bool env_resolve_call (s_env *env, s_call *call)
+{
+  s_facts_with_cursor cursor;
+  s_tag tag_cfn;
+  s_tag tag_fn;
+  s_tag tag_ident;
+  s_tag tag_is_a;
+  s_tag tag_macro;
+  s_tag tag_module;
+  s_tag tag_module_name;
+  s_tag tag_special_operator;
+  s_tag tag_sym;
+  s_tag tag_symbol;
+  s_tag tag_var;
+  assert(env);
+  assert(call);
+  ident_resolve_module(&call->ident, env);
+  tag_init_1(    &tag_cfn,      ":cfn");
+  tag_init_1(    &tag_fn,       ":fn");
+  tag_init_ident(&tag_ident, &call->ident);
+  tag_init_1(    &tag_is_a,     ":is_a");
+  tag_init_1(    &tag_macro,    ":macro");
+  tag_init_1(    &tag_module,   ":module");
+  tag_init_sym(  &tag_module_name, call->ident.module_name);
+  tag_init_1(    &tag_special_operator, ":special_operator");
+  tag_init_sym(  &tag_sym, call->ident.sym);
+  tag_init_1(    &tag_symbol,   ":symbol");
+  tag_init_var(  &tag_var);
+  facts_with(&env->facts, &cursor, (t_facts_spec) {
+      &tag_module_name,
+      &tag_is_a, &tag_module,     /* module exists */
+      &tag_symbol, &tag_ident,    /* module exports symbol */
+      NULL, NULL });
+  if (! facts_with_cursor_next(&cursor))
+    errx(1, "symbol %s not found in module %s",
+         call->ident.sym->str.ptr.ps8,
+         call->ident.module_name->str.ptr.ps8);
+  facts_with_cursor_clean(&cursor);
+  facts_with(&env->facts, &cursor, (t_facts_spec) {
+      &tag_ident, &tag_fn, &tag_var,
+      NULL, NULL });
+  if (facts_with_cursor_next(&cursor)) {
+    if (tag_var.type != TAG_FN)
+      errx(1, "%s.%s is not a function",
+           call->ident.module_name->str.ptr.ps8,
+           call->ident.sym->str.ptr.ps8);
+    call->fn = tag_var.data.fn;
+  }
+  facts_with_cursor_clean(&cursor);
+  facts_with(&env->facts, &cursor, (t_facts_spec) {
+      &tag_ident, &tag_cfn, &tag_var,
+      NULL, NULL });
+  if (facts_with_cursor_next(&cursor)) {
+    if (tag_var.type != TAG_CFN)
+      errx(1, "%s.%s is not a C function",
+           call->ident.module_name->str.ptr.ps8,
+           call->ident.sym->str.ptr.ps8);
+    call->cfn = cfn_new_copy(&tag_var.data.cfn);
+  }
+  facts_with_cursor_clean(&cursor);
+  facts_with(&env->facts, &cursor, (t_facts_spec) {
+      &tag_ident, &tag_is_a, &tag_macro, NULL, NULL });
+  if (facts_with_cursor_next(&cursor))
+    call->macro = true;
+  facts_with_cursor_clean(&cursor);
+  facts_with(&env->facts, &cursor, (t_facts_spec) {
+      &tag_ident, &tag_is_a, &tag_special_operator, NULL, NULL});
+  if (facts_with_cursor_next(&cursor))
+    call->special_operator = true;
+  facts_with_cursor_clean(&cursor);
+  return true;
+}
+
 s_tag * env_unwind_protect (s_env *env, s_tag *protected, s_list *cleanup,
                             s_tag *dest)
 {