]> Nishi Git Mirror - gwion.git/commitdiff
:art: Allow template operators
authorJérémie Astor <fennecdjay@gmail.com>
Sun, 20 Jun 2021 11:37:27 +0000 (13:37 +0200)
committerJérémie Astor <fennecdjay@gmail.com>
Sun, 20 Jun 2021 11:37:27 +0000 (13:37 +0200)
ast
include/env/nspc.h
include/operator.h
src/emit/emit.c
src/env/nspc.c
src/parse/check.c
src/parse/operator.c
src/parse/scan1.c
src/parse/scan2.c
tests/usr_op/op_tmpl.gw [new file with mode: 0644]

diff --git a/ast b/ast
index 476773eed83abcd74bf28cccebc59cf9eccca8bb..d7cc060e0fe49405ca5494810c181ef211daf7f2 160000 (submodule)
--- a/ast
+++ b/ast
@@ -1 +1 @@
-Subproject commit 476773eed83abcd74bf28cccebc59cf9eccca8bb
+Subproject commit d7cc060e0fe49405ca5494810c181ef211daf7f2
index 53624c66ed82746dc99253f8be8febd4f7834d72..1980cd09a0b23592debd6ddc2f95195af2422ee9 100644 (file)
@@ -7,7 +7,7 @@ struct NspcInfo_ {
   Scope          type;
   Scope          func;
   Scope          trait;
-  struct Vector_ op_map_tmpl;
+  struct Vector_ op_tmpl;
   uint16_t       offset;
   uint16_t       class_data_size;
 };
index 6dadf873199e9cbecfc7884bfb4e2993709ea274..72996780aa3863515740d79e219a92862febd8eb 100644 (file)
@@ -82,6 +82,7 @@ ANN Type   op_check(const Env, struct Op_Import *);
 ANN m_bool op_emit(const Emitter, const struct Op_Import *);
 ANN m_bool operator_set_func(const struct Op_Import *);
 ANN void   free_op_map(Map map, struct Gwion_ *gwion);
+ANN void   free_op_tmpl(Vector v, struct Gwion_ *gwion);
 
 ANN void               operator_suspend(const Nspc, struct Op_Import *);
 ANN static inline void operator_resume(struct Op_Import *opi) {
index 64d871204081336a1a0c786e490a0dc39cedf533..9059e70ab2f0475d65a6564f1a463e98739c8fa2 100644 (file)
@@ -2651,6 +2651,7 @@ ANN static void emit_fdef_finish(const Emitter emit, const Func_Def fdef) {
 }
 
 ANN m_bool emit_func_def(const Emitter emit, const Func_Def f) {
+  if (tmpl_base(f->base->tmpl) && fbflag(f->base, fbflag_op)) return GW_OK;
   const Func     func   = f->base->func;
   const Func_Def fdef   = func->def;
   const Func     former = emit->env->func;
index fadbf4ad610ab9584f280d9e19b9adb7ad2a6cb8..5e4ed2999ebb5bd376318a67d4bce327ab104a49 100644 (file)
@@ -78,6 +78,7 @@ ANN void free_nspc(const Nspc a, const Gwion gwion) {
   nspc_free_func(a, gwion);
   nspc_free_trait(a, gwion);
   if (a->info->op_map.ptr) free_op_map(&a->info->op_map, gwion);
+  if (a->info->op_tmpl.ptr) free_op_tmpl(&a->info->op_tmpl, gwion);
   nspc_free_type(a, gwion);
   if (a->info->class_data && a->info->class_data_size)
     mp_free2(gwion->mp, a->info->class_data_size, a->info->class_data);
index 85b4ee2dc9d65aba0f884772b94edd2d13ad572b..eb38a44dae07255717b9dbada96b6e31c0b434fc 100644 (file)
@@ -590,9 +590,9 @@ ANN static m_bool check_func_args(const Env env, Arg_List arg_list) {
     if (next) gw_err(", ");                                                    \
     return next;                                                               \
   }
-next_arg(Exp) next_arg(Arg_List)
+next_arg(Exp) next_arg(Arg_List);
 
-    ANN static void print_current_args(Exp e) {
+ANN static void print_current_args(Exp e) {
   gw_err(_("and not\n  "));
   do gw_err(" {G}%s{0}", e->type ? e->type->name : "{-/}Unknown");
   while ((e = next_arg_Exp(e)));
@@ -1546,6 +1546,7 @@ ANN m_bool check_fdef(const Env env, const Func_Def fdef) {
 }
 
 ANN m_bool check_func_def(const Env env, const Func_Def f) {
+  if (tmpl_base(f->base->tmpl) && fbflag(f->base, fbflag_op)) return GW_OK;
   const Func     func = f->base->func;
   const Func_Def fdef = func->def;
   assert(func == fdef->base->func);
index ece58a178b8e9dce96d857b0a3aa8d3615a5cf8f..c38e8efed928a029bd0a89f6dbd34ae7a9b76c92 100644 (file)
@@ -10,6 +10,9 @@
 #include "operator.h"
 #include "object.h"
 #include "array.h"
+#include "import.h"
+#include "traverse.h"
+#include "clean.h"
 
 typedef Type (*f_type)(const Env env, const Exp exp);
 
@@ -37,6 +40,15 @@ ANN void free_op_map(Map map, struct Gwion_ *gwion) {
   map_release(map);
 }
 
+ANN void free_op_tmpl(Vector v, struct Gwion_ *gwion) {
+  LOOP_OPTIM
+  for (m_uint i = vector_size(v) + 1; --i;) {
+    const Func_Def fdef = (Func_Def)vector_at(v, i - 1);
+    free_func_def(gwion->mp, fdef);
+  }
+  vector_release(v);
+}
+
 static m_str type_name(const Type t) {
   return t ? t == OP_ANY_TYPE ? "any" : t->name : "";
 }
@@ -172,6 +184,77 @@ ANN static Type op_check_inner(const Env env, struct OpChecker *ock,
   return NULL;
 }
 
+//! check if type matches for template operator
+ANN bool _tmpl_match(const Env env, const Type t, Type_Decl *const td,
+                     Specialized_List *sl) {
+  if (!td->next && td->xid == (*sl)->xid) {
+    *sl = (*sl)->next;
+    return true;
+  }
+  const Type base = known_type(env, td);
+  return isa(t, base) > 0;
+}
+
+//! check Func_Base matches for template operator
+ANN bool tmpl_match(const Env env, const struct Op_Import *opi,
+                    Func_Base *const base) {
+  Specialized_List sl  = base->tmpl->list;
+  const Arg_List   arg = base->args;
+  if (opi->lhs) {
+    if (fbflag(base, fbflag_unary) ||
+        !_tmpl_match(env, opi->lhs, arg->td, &sl) ||
+        (opi->rhs && fbflag(base, fbflag_postfix)) ||
+        !_tmpl_match(env, opi->rhs, arg->next->td, &sl))
+      return false;
+  } else {
+    if (!fbflag(base, fbflag_unary) ||
+        !_tmpl_match(env, opi->rhs, arg->td, &sl))
+      return false;
+  }
+  return true;
+}
+
+//! make template operator Type_List
+ANN2(1, 2)
+static Type_List op_type_list(const Env env, const Type t, const Type_List next,
+                              const loc_t loc) {
+  Type_Decl *const td0 = type2td(env->gwion, t, loc);
+  return new_type_list(env->gwion->mp, td0, next);
+}
+
+//! make template operator Func_def
+ANN Type op_def(const Env env, struct Op_Import *const opi,
+                const Func_Def fdef) {
+  const Func_Def tmpl_fdef    = cpy_func_def(env->gwion->mp, fdef);
+  tmpl_fdef->base->tmpl->base = 0;
+  if (opi->lhs) {
+    Type_List next =
+        opi->rhs ? op_type_list(env, opi->rhs, NULL, opi->pos) : NULL;
+    tmpl_fdef->base->tmpl->call = op_type_list(env, opi->lhs, next, opi->pos);
+  } else
+    tmpl_fdef->base->tmpl->call = op_type_list(env, opi->rhs, NULL, opi->pos);
+  if (traverse_func_def(env, tmpl_fdef) < 0) {
+    if (!tmpl_fdef->base->func) func_def_cleaner(env->gwion, tmpl_fdef);
+    return NULL;
+  }
+  return op_check(env, opi);
+}
+
+//! find template operator
+ANN static Type op_check_tmpl(const Env env, struct Op_Import *opi) {
+  Nspc nspc = env->curr;
+  do {
+    if (!nspc->info->op_tmpl.ptr) continue;
+    const Vector v = &nspc->info->op_tmpl;
+    for (m_uint i = vector_size(v) + 1; --i;) {
+      const Func_Def fdef = (Func_Def)vector_at(v, i - 1);
+      if (!tmpl_match(env, opi, fdef->base)) continue;
+      return op_def(env, opi, fdef);
+    }
+  } while ((nspc = nspc->parent));
+  return NULL;
+}
+
 ANN Type op_check(const Env env, struct Op_Import *opi) {
   for (int i = 0; i < 2; ++i) {
     Nspc nspc = env->curr;
@@ -197,6 +280,8 @@ ANN Type op_check(const Env env, struct Op_Import *opi) {
       } while (l && (l = op_parent(env, l)));
     } while ((nspc = nspc->parent));
   }
+  const Type try_tmpl = op_check_tmpl(env, opi);
+  if (try_tmpl) return try_tmpl;
   // this should be an any case
   if (opi->op == insert_symbol(env->gwion->st, "$") && opi->rhs == opi->lhs)
     return opi->rhs;
index de04f4bf394977a323941010cdf62cdd0b09d7e9..c7e66316a92eba2a47d0514e3954b32f0046bc1a 100644 (file)
@@ -418,7 +418,7 @@ ANN static Type scan1_noret(const Env env, const Func_Base *base) {
   ERR_O(base->pos, _("Can't use type `{+G}%s{0}` for return"), t->name);
 }
 
-ANN static m_bool _scan1_fdef_base_tmpl(const Env env, Func_Base *base) {
+ANN static m_bool _scan1_fbase_tmpl(const Env env, Func_Base *base) {
   Specialized_List id = base->tmpl->list;
   do nspc_add_type(env->curr, id->xid, env->gwion->type[et_auto]);
   while ((id = id->next));
@@ -431,15 +431,30 @@ ANN static m_bool _scan1_fdef_base_tmpl(const Env env, Func_Base *base) {
   return GW_OK;
 }
 
-ANN static m_bool scan1_fdef_base_tmpl(const Env env, Func_Base *base) {
+ANN static m_bool scan1_fbase_tmpl(const Env env, Func_Base *const base) {
   nspc_push_type(env->gwion->mp, env->curr);
-  const m_bool ret = _scan1_fdef_base_tmpl(env, base);
+  const m_bool ret = _scan1_fbase_tmpl(env, base);
   nspc_pop_type(env->gwion->mp, env->curr);
   return ret;
 }
 
+ANN static m_bool scan1_fdef_base_tmpl(const Env env, const Func_Def fdef) {
+  Func_Base *const base = fdef->base;
+  if (!fbflag(base, fbflag_op)) return scan1_fbase_tmpl(env, base);
+  Arg_List         arg = fdef->base->args;
+  Specialized_List sl  = fdef->base->tmpl->list;
+  do {
+    if (!arg->td->next && sl && arg->td->xid == sl->xid) { sl = sl->next; }
+  } while ((arg = arg->next));
+  if (sl) ERR_B(base->pos, "too many template types for operator");
+  const Vector v = &env->curr->info->op_tmpl;
+  if (!v->ptr) vector_init(v);
+  vector_add(v, (m_uint)cpy_func_def(env->gwion->mp, fdef));
+  return GW_OK;
+}
+
 ANN m_bool scan1_fptr_def(const Env env, const Fptr_Def fptr) {
-  if (tmpl_base(fptr->base->tmpl)) return scan1_fdef_base_tmpl(env, fptr->base);
+  if (tmpl_base(fptr->base->tmpl)) return scan1_fbase_tmpl(env, fptr->base);
   if (!fptr->base->func) {
     fptr->base->func =
         nspc_lookup_value0(env->curr, fptr->base->xid)->d.func_ref;
@@ -629,7 +644,7 @@ ANN m_bool scan1_func_def(const Env env, const Func_Def fdef) {
   if (fdef->base->td)
     CHECK_BB(env_storage(env, fdef->base->flag, fdef->base->td->pos));
   CHECK_BB(scan1_fdef_defined(env, fdef));
-  if (tmpl_base(fdef->base->tmpl)) return scan1_fdef_base_tmpl(env, fdef->base);
+  if (tmpl_base(fdef->base->tmpl)) return scan1_fdef_base_tmpl(env, fdef);
   struct Func_ fake = {.name = s_name(fdef->base->xid)}, *const former =
                                                              env->func;
   env->func = &fake;
index e65ca1950395f5383cd71f23df7aa13f81e2cb37..801514e44b145e42610d7c955d00c604d446c9f4 100644 (file)
@@ -544,6 +544,8 @@ static inline int is_cpy(const Func_Def fdef) {
 }
 
 ANN m_bool scan2_func_def(const Env env, const Func_Def fdef) {
+  if (tmpl_base(fdef->base->tmpl) && fbflag(fdef->base, fbflag_op))
+    return GW_OK;
   if (GET_FLAG(fdef->base, global) && !env->class_def) env->context->global = 1;
   const Func_Def f = !is_cpy(fdef) ? fdef : scan2_cpy_fdef(env, fdef);
   const m_uint   scope =
diff --git a/tests/usr_op/op_tmpl.gw b/tests/usr_op/op_tmpl.gw
new file mode 100644 (file)
index 0000000..032cd6b
--- /dev/null
@@ -0,0 +1,3 @@
+operator int --- :[A,C] (A i, C j) { return i;}
+<<< 1 --- 2 >>>;
+<<< 2 --- 2 >>>;