From: Jérémie Astor Date: Sun, 20 Jun 2021 11:37:27 +0000 (+0200) Subject: :art: Allow template operators X-Git-Tag: nightly~576 X-Git-Url: http://10.10.0.4:5575/?a=commitdiff_plain;h=97f7b934614b398ca634e45ccef9ddfed88b90b7;p=gwion.git :art: Allow template operators --- diff --git a/ast b/ast index 476773ee..d7cc060e 160000 --- a/ast +++ b/ast @@ -1 +1 @@ -Subproject commit 476773eed83abcd74bf28cccebc59cf9eccca8bb +Subproject commit d7cc060e0fe49405ca5494810c181ef211daf7f2 diff --git a/include/env/nspc.h b/include/env/nspc.h index 53624c66..1980cd09 100644 --- a/include/env/nspc.h +++ b/include/env/nspc.h @@ -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; }; diff --git a/include/operator.h b/include/operator.h index 6dadf873..72996780 100644 --- a/include/operator.h +++ b/include/operator.h @@ -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) { diff --git a/src/emit/emit.c b/src/emit/emit.c index 64d87120..9059e70a 100644 --- a/src/emit/emit.c +++ b/src/emit/emit.c @@ -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; diff --git a/src/env/nspc.c b/src/env/nspc.c index fadbf4ad..5e4ed299 100644 --- a/src/env/nspc.c +++ b/src/env/nspc.c @@ -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); diff --git a/src/parse/check.c b/src/parse/check.c index 85b4ee2d..eb38a44d 100644 --- a/src/parse/check.c +++ b/src/parse/check.c @@ -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); diff --git a/src/parse/operator.c b/src/parse/operator.c index ece58a17..c38e8efe 100644 --- a/src/parse/operator.c +++ b/src/parse/operator.c @@ -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; diff --git a/src/parse/scan1.c b/src/parse/scan1.c index de04f4bf..c7e66316 100644 --- a/src/parse/scan1.c +++ b/src/parse/scan1.c @@ -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; diff --git a/src/parse/scan2.c b/src/parse/scan2.c index e65ca195..801514e4 100644 --- a/src/parse/scan2.c +++ b/src/parse/scan2.c @@ -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 index 00000000..032cd6b8 --- /dev/null +++ b/tests/usr_op/op_tmpl.gw @@ -0,0 +1,3 @@ +operator int --- :[A,C] (A i, C j) { return i;} +<<< 1 --- 2 >>>; +<<< 2 --- 2 >>>;