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)
{