Commit d49155243d34fcb0e991724d6a4daecddebdb42a

Thomas de Grivel 2024-04-02T09:38:37

wip defoperator

diff --git a/lib/c3/0.1/c3.facts b/lib/c3/0.1/c3.facts
index dddf44d..e242898 100644
--- a/lib/c3/0.1/c3.facts
+++ b/lib/c3/0.1/c3.facts
@@ -228,3 +228,7 @@ add {C3, :symbol, C3.quote_cfn}
 replace {C3.quote_cfn, :arity, 1}
 replace {C3.quote_cfn, :is_a, :special_operator}
 replace {C3.quote_cfn, :symbol_value, cfn Tag "c3_quote_cfn" (Sym, Result)}
+add {C3, :symbol, C3.defoperator}
+replace {C3.defoperator, :arity, 5}
+replace {C3.defoperator, :is_a, :special_operator}
+replace {C3.defoperator, :symbol_value, cfn Tag "c3_defoperator" (Sym, Sym, Tag, U8, Sym, Result)}
diff --git a/libc3/c3.c b/libc3/c3.c
index 62ac697..97b4f46 100644
--- a/libc3/c3.c
+++ b/libc3/c3.c
@@ -55,6 +55,17 @@ s_tag * c3_defmodule (const s_sym **name, const s_block *block, s_tag *dest)
   return env_defmodule(&g_c3_env, name, block, dest);
 }
 
+s_tag * c3_defoperator (const s_sym **name, const s_sym **sym,
+                        const s_tag *symbol_value,
+                        u8 operator_precedence,
+                        const s_sym **operator_associativity,
+                        s_tag *dest)
+{
+  return env_defoperator(&g_c3_env, name, sym, symbol_value,
+                         operator_precedence,
+                         operator_associativity, dest);
+}
+
 void ** c3_dlopen (const s_str *path, void **dest)
 {
   assert(path);
diff --git a/libc3/c3_main.h b/libc3/c3_main.h
index 357db11..ba5a638 100644
--- a/libc3/c3_main.h
+++ b/libc3/c3_main.h
@@ -37,6 +37,11 @@ void    c3_license (void);
 /* Operators. */
 s_tag * c3_def (const s_call *call, s_tag *dest);
 s_tag * c3_defmodule (const s_sym **name, const s_block *block, s_tag *dest);
+s_tag * c3_defoperator (const s_sym **name, const s_sym **sym,
+                        const s_tag *symbol_value,
+                        u8 operator_precedence,
+                        const s_sym **operator_associativity,
+                        s_tag *dest);
 void ** c3_dlopen (const s_str *path, void **dest);
 void    c3_exit (sw code);
 s_tag * c3_pin (const s_tag *a, s_tag *dest);
diff --git a/libc3/cfn.c b/libc3/cfn.c
index e0a549b..107e67a 100644
--- a/libc3/cfn.c
+++ b/libc3/cfn.c
@@ -132,6 +132,18 @@ s_tag * cfn_apply (s_cfn *cfn, s_list *args, s_tag *dest)
   return NULL;
 }
 
+s8 cfn_arity (const s_cfn *cfn)
+{
+  sw arity;
+  arity = cfn->arity - (cfn->arg_result ? 1 : 0);
+  if (arity < 0 || arity > S8_MAX) {
+    err_puts("fn_arity: invalid arity");
+    assert(! "fn_arity: invalid arity");
+    return -1;
+  }
+  return arity;
+}
+
 void cfn_clean (s_cfn *cfn)
 {
   assert(cfn);
diff --git a/libc3/cfn.h b/libc3/cfn.h
index ba1e20a..3b1da26 100644
--- a/libc3/cfn.h
+++ b/libc3/cfn.h
@@ -28,6 +28,7 @@ s_cfn * cfn_new_copy (const s_cfn *src);
 
 /* Observers */
 s_tag * cfn_apply (s_cfn *cfn, s_list *args, s_tag *dest);
+s8      cfn_arity (const s_cfn *cfn);
 
 /* Modifiers */
 s_cfn * cfn_link (s_cfn *cfn);
diff --git a/libc3/env.c b/libc3/env.c
index 92f9883..fa3bada 100644
--- a/libc3/env.c
+++ b/libc3/env.c
@@ -140,6 +140,57 @@ s_tag * env_defmodule (s_env *env, const s_sym **name,
   return result;
 }
 
+s_tag * env_defoperator (s_env *env, const s_sym **name,
+                         const s_sym **sym, const s_tag *symbol_value,
+                         u8 operator_precedence,
+                         const s_sym **operator_associativity,
+                         s_tag *dest)
+{
+  s8 arity;
+  s_tag tag_module_name;
+  s_tag tag_operator;
+  s_tag tag_ident;
+  s_tag tag_is_a;
+  s_tag tag_symbol;
+  s_tag tag_sym;
+  s_tag tag_arity_sym;
+  s_tag tag_arity_u8;
+  s_tag tag_symbol_value;
+  s_tag tag_operator_precedence_sym;
+  s_tag tag_operator_precedence_u8;
+  s_tag tag_operator_associativity_rel;
+  s_tag tag_operator_associativity_value;
+  tag_init_sym(&tag_module_name, env->current_module);
+  tag_init_sym(&tag_operator, &g_sym_operator);
+  tag_ident.type = TAG_IDENT;
+  tag_ident.data.ident.module = env->current_module;
+  tag_ident.data.ident.sym = *name;
+  tag_init_sym(&tag_is_a, &g_sym_is_a);
+  tag_init_sym(&tag_symbol, &g_sym_symbol);
+  tag_init_sym(&tag_sym, *sym);
+  tag_init_sym(&tag_arity_sym, &g_sym_arity);
+  arity = tag_arity(symbol_value);
+  if (arity < 1) {
+    err_write_1("env_defoperator: invalid arity: ");
+    err_inspect_s8(&arity);
+    err_write_1("\n");
+    assert(! "env_defoperator: invalid arity");
+  };
+  tag_init_u8( &tag_arity_u8, arity);
+  tag_init_sym(&tag_symbol_value, &g_sym_symbol_value);
+  tag_init_sym(&tag_operator_precedence_sym,
+               &g_sym_operator_precedence);
+  tag_init_u8( &tag_operator_precedence_u8, operator_precedence);
+  tag_init_sym(&tag_operator_associativity_rel,
+               &g_sym_operator_associativity);
+  tag_init_sym(&tag_operator_associativity_value,
+               *operator_associativity);
+  facts_add_tags(&env->facts, &tag_module_name, &tag_operator,
+                 &tag_ident);
+  *dest = tag_ident;
+  return dest;
+}
+
 void env_error_f (s_env *env, const char *fmt, ...)
 {
   va_list ap;
diff --git a/libc3/env.h b/libc3/env.h
index 992c616..51f3f5c 100644
--- a/libc3/env.h
+++ b/libc3/env.h
@@ -31,6 +31,12 @@ s_ident *     env_ident_resolve_module (const s_env *env,
 s_tag *       env_def (s_env *env, const s_call *call, s_tag *dest);
 s_tag *       env_defmodule (s_env *env, const s_sym **name,
                              const s_block *block, s_tag *dest);
+s_tag *       env_defoperator (s_env *env, const s_sym **name,
+                               const s_sym **sym,
+                               const s_tag *symbol_value,
+                               u8 operator_precedence,
+                               const s_sym **operator_associativity,
+                               s_tag *dest);
 bool          env_eval_array (s_env *env, const s_array *array,
                               s_array *dest);
 bool          env_eval_array_tag (s_env *env, const s_array *array,
diff --git a/libc3/fn.c b/libc3/fn.c
index 3ef6d7d..b528c8e 100644
--- a/libc3/fn.c
+++ b/libc3/fn.c
@@ -22,6 +22,20 @@
 #include "list.h"
 #include "tag_type.h"
 
+s8 fn_arity (const s_fn *fn)
+{
+  assert(fn);
+  if (fn->clauses) {
+    if (fn->clauses->arity > S8_MAX) {
+      err_puts("fn_arity: invalid arity");
+      assert(! "fn_arity: invalid arity");
+      return -1;
+    }
+    return fn->clauses->arity;
+  }
+  return -1;
+}
+
 void fn_clean (s_fn *fn)
 {
   assert(fn);
diff --git a/libc3/fn.h b/libc3/fn.h
index ed2ba7e..4f678e8 100644
--- a/libc3/fn.h
+++ b/libc3/fn.h
@@ -33,4 +33,7 @@ void   fn_delete (s_fn *fn);
 s_fn * fn_new (void);
 s_fn * fn_new_copy (const s_fn *fn);
 
+/* Observers. */
+s8 fn_arity (const s_fn *fn);
+
 #endif /* LIBC3_FN_H */
diff --git a/libc3/tag.c b/libc3/tag.c
index 0232347..90801b4 100644
--- a/libc3/tag.c
+++ b/libc3/tag.c
@@ -64,6 +64,17 @@ bool * tag_and (const s_tag *a, const s_tag *b, bool *dest)
   return dest;
 }
 
+s8 tag_arity (const s_tag *tag)
+{
+  switch (tag->type) {
+  case TAG_CFN: return cfn_arity(&tag->data.cfn);
+  case TAG_FN:  return fn_arity(&tag->data.fn);
+  default:
+    break;
+  }
+  return -1;
+}
+
 s_tag * tag_cast_integer_to_s8 (s_tag *tag)
 {
   s8 i;
diff --git a/libc3/tag.h b/libc3/tag.h
index 89dfaac..d059d50 100644
--- a/libc3/tag.h
+++ b/libc3/tag.h
@@ -41,6 +41,7 @@ s_tag * tag_new (void);
 s_tag * tag_new_1 (const char *p);
 
 /* Observers */
+s8             tag_arity (const s_tag *tag);
 u64            tag_hash_u64 (const s_tag *tag);
 uw             tag_hash_uw (const s_tag *tag);
 s_str *        tag_inspect (const s_tag *tag, s_str *dest);