]> Nishi Git Mirror - gwion.git/commitdiff
:art: Sort form of *not* currying
authorJérémie Astor <fennecdjay@gmail.com>
Tue, 15 Jun 2021 23:10:29 +0000 (01:10 +0200)
committerJérémie Astor <fennecdjay@gmail.com>
Tue, 15 Jun 2021 23:10:29 +0000 (01:10 +0200)
include/env/type.h
include/parse.h
src/lib/engine.c
src/lib/lib_func.c
src/parse/check.c

index c77f7ea9861ecea15d512e92a375bb16634d0142..df5ff724c244d6b6f3900f224dddc8f9e6ee82f6 100644 (file)
@@ -127,6 +127,7 @@ typedef enum {
   et_union,
   et_auto,
   et_none,
+  et_curry,
   MAX_TYPE
 } type_enum;
 #endif
index bde830d2e0d64cc99e596b64a028fbb80fcf79a9..4de09fd6de8121472133c2bfb4c82be6e9db69be 100644 (file)
@@ -98,4 +98,15 @@ ANN static inline void env_weight(const Env env, const uint16_t weight) {
 ANN static inline void env_inline_mult(const Env env, const float mult) {
   if (env->func) env->func->inline_mult += mult;
 }
+
+ANN static inline bool is_hole(const Env env, const Exp exp) {
+  const Symbol hole = insert_symbol("_");
+  if(exp->exp_type == ae_exp_primary) {
+    if(exp->d.prim.prim_type == ae_prim_id) {
+      if(exp->d.prim.d.var == hole)
+        return true;
+    }
+  }
+  return false;
+}
 #endif
index b61a9ad3e3acc6f70df8f78795ba789a5a1d43d6..3d88d5071b266116b2f0a5a68c9b8d33f8ca388a 100644 (file)
@@ -147,10 +147,17 @@ ANN static m_bool import_core_libs(const Gwi gwi) {
   gwidoc(gwi, "the base of decayed operators.");
   const Type t_op = gwi_mk_type(gwi, "@op", SZ_INT, "@function");
   GWI_BB(gwi_set_global_type(gwi, t_op, et_op))
+
+  gwidoc(gwi, "the base of lamdbas.");
   const Type t_lambda = gwi_mk_type(gwi, "@lambda", SZ_INT, "@function");
   set_tflag(t_lambda, tflag_infer);
   GWI_BB(gwi_set_global_type(gwi, t_lambda, et_lambda))
 
+  gwidoc(gwi, "Mark function as curried.");
+  const Type t_curry = gwi_mk_type(gwi, "@Curry", 0, NULL);
+  GWI_BB(gwi_set_global_type(gwi, t_curry, et_curry))
+
+
   gwidoc(gwi, "type for internal pointer data.");
   GWI_BB(gwi_typedef_ini(gwi, "int", "@internal"))
   GWI_BB(gwi_typedef_end(gwi, ae_flag_none))
index c7019f5664afd39d9d5cd58208278cadb1d40bb1..3eabfa43bf7f85addfe12d169ef46aeec9f48475 100644 (file)
@@ -22,6 +22,65 @@ static OP_CHECK(opck_func_call) {
   return check_exp_call1(env, &e->d.exp_call) ?: env->gwion->type[et_error];
 }
 
+ANN static inline Exp cpy_nonext(const Env env, const Exp e) {
+  const MemPool mp = env->gwion->mp;
+  const Exp next = e->next;
+  e->next = NULL;
+  const Exp ret = cpy_exp(mp, e);
+  e->next = next;
+  if(!check_exp(env, ret)) {
+    free_exp(mp, ret);
+    return NULL;
+  }
+  return ret;
+}
+
+ANN static Exp order_curry(const Env env, Exp fn, Exp arg) {
+  const MemPool mp = env->gwion->mp;
+  Exp base   = NULL;
+  Exp next   = NULL;
+  do {
+    const bool hole = is_hole(env, fn);
+    const Exp curr = !hole ? fn : arg;
+    if(hole) {
+      if(!arg) {
+        if(base)
+          free_exp(mp, base);
+        ERR_O(fn->pos, "no enough arguments for holes");
+      }
+      arg = arg->next;
+    }
+    if(!base)
+      base = next = cpy_nonext(env, curr);
+    else {
+      next->next = cpy_nonext(env, curr);
+      next = next->next;
+    }
+  } while ((fn = fn->next));
+  assert(base);
+  if(arg) {
+    free_exp(mp, base);
+    ERR_O(arg->pos, "too many arguments for holes");
+  }
+  return base;
+}
+
+static OP_CHECK(opck_curry) {
+  Exp_Binary *bin  = (Exp_Binary *)data;
+  Exp         lhs  = bin->lhs;
+  Exp_Call    base = bin->rhs->d.exp_call;
+  DECL_OO(const Exp,   args, = order_curry(env, base.args, lhs));
+  Exp_Call    call = {.func = base.func, .args = args};
+  Exp         e    = exp_self(bin);
+  e->exp_type      = ae_exp_call;
+  e->type          = NULL;
+  memcpy(&e->d.exp_call, &call, sizeof(Exp_Call));
+  const MemPool mp = env->gwion->mp;
+  free_exp(mp, base.args);
+  free_exp(mp, lhs);
+  return check_exp_call1(env, &e->d.exp_call) ?: env->gwion->type[et_error];
+}
+
 static inline void fptr_instr(const Emitter emit, const Func f,
                               const m_uint i) {
   const Instr set = emit_add_instr(emit, RegSetImm);
@@ -589,6 +648,9 @@ GWION_IMPORT(func) {
   GWI_BB(gwi_oper_ini(gwi, (m_str)OP_ANY_TYPE, "@function", NULL))
   GWI_BB(gwi_oper_add(gwi, opck_func_call))
   GWI_BB(gwi_oper_end(gwi, "=>", NULL))
+  GWI_BB(gwi_oper_ini(gwi, (m_str)OP_ANY_TYPE, "@Curry", NULL))
+  GWI_BB(gwi_oper_add(gwi, opck_curry))
+  GWI_BB(gwi_oper_end(gwi, "=>", NULL))
   GWI_BB(gwi_oper_ini(gwi, NULL, "@func_ptr", "bool"))
   GWI_BB(gwi_oper_end(gwi, "!", IntNot))
   GWI_BB(gwi_oper_ini(gwi, "@function", "@func_ptr", NULL))
index b451914fee0551e049f86b5cf624a958b9bab68f..39aa16a56fe026111173afe0dee51650bc0266c1 100644 (file)
@@ -887,7 +887,18 @@ ANN static m_bool predefined_call(const Env env, const Type t,
   return GW_ERROR;
 }
 
+ANN2(1) static inline bool curried(const Env env, Exp exp) {
+  while(exp) {
+    if (is_hole(env, exp))
+      return true;
+    exp = exp->next;
+  }
+  return false;
+}
+
 ANN static Type check_exp_call(const Env env, Exp_Call *exp) {
+  if(curried(env, exp->args))
+    return env->gwion->type[et_curry];
   if (exp->tmpl) {
     DECL_BO(const m_bool, ret, = func_check(env, exp));
     if (!ret) return exp_self(exp)->type;