From f5ff9443b36f9500b3d676bbc73d3ce24467d01a Mon Sep 17 00:00:00 2001 From: fennecdjay Date: Thu, 11 Jul 2019 15:59:16 +0200 Subject: [PATCH] :art: Allow fptr typedef --- src/emit/emit.c | 7 +++-- src/lib/func.c | 8 +++++ src/lib/instr.c | 5 ++- src/parse/check.c | 58 +++++++++++++++++++++++++++-------- src/parse/scan0.c | 73 ++++++++++++++++++++++++++++++++------------ src/parse/scan1.c | 2 +- src/parse/scan2.c | 21 +++++-------- src/parse/template.c | 52 +++++++++++++++++++++++++------ 8 files changed, 167 insertions(+), 59 deletions(-) diff --git a/src/emit/emit.c b/src/emit/emit.c index df309a90..e169d55e 100644 --- a/src/emit/emit.c +++ b/src/emit/emit.c @@ -693,8 +693,7 @@ ANN static m_bool prepare_call(const Emitter emit, const Exp_Call* exp_call) { ANN static inline m_int push_tmpl_func(const Emitter emit, const Func f) { const Value v = f->value_ref; - if(isa(v->type, t_class) > 0 && - is_fptr(v->type)) + if(isa(v->type, t_class) > 0 && is_fptr(v->type)) return emit->env->scope->depth; const m_uint scope = emit_push(emit, v->owner_class, v->owner); CHECK_BB(traverse_func_def(emit->env, f->def)) @@ -820,7 +819,9 @@ ANN static Instr get_prelude(const Emitter emit, const Func f) { if(f->def->base->tmpl) { // TODO: put in func struct dottmpl_ *dt = (struct dottmpl_*)mp_calloc(emit->gwion->mp, dottmpl); size_t len = strlen(f->name); - size_t sz = len - strlen(f->value_ref->owner->name); + size_t slen = strlen(f->value_ref->owner->name); + assert(len > slen); + size_t sz = len - slen; char c[sz + 1]; memcpy(c, f->name, sz); c[sz] = '\0'; diff --git a/src/lib/func.c b/src/lib/func.c index 4d8cc62b..9fd775c8 100644 --- a/src/lib/func.c +++ b/src/lib/func.c @@ -197,6 +197,14 @@ ANN static m_bool fptr_do(const Env env, struct FptrInfo *info) { static OP_CHECK(opck_fptr_at) { Exp_Binary* bin = (Exp_Binary*)data; + if(bin->rhs->type->e->d.func->def->base->tmpl && + bin->rhs->type->e->d.func->def->base->tmpl->call) { + struct FptrInfo info = { bin->lhs->type->e->d.func, bin->rhs->type->e->parent->e->d.func, + bin->lhs, exp_self(bin)->pos }; + CHECK_BO(fptr_do(env, &info)) + bin->rhs->emit_var = 1; + return bin->rhs->type; +} struct FptrInfo info = { bin->lhs->type->e->d.func, bin->rhs->type->e->d.func, bin->lhs, exp_self(bin)->pos }; CHECK_BO(fptr_do(env, &info)) diff --git a/src/lib/instr.c b/src/lib/instr.c index 1963d9a0..9c050591 100644 --- a/src/lib/instr.c +++ b/src/lib/instr.c @@ -93,11 +93,14 @@ INSTR(GTmpl) { dt->owner = f->value_ref->owner; dt->owner_class = f->value_ref->owner_class; if(traverse_dot_tmpl(emit, dt) > 0) { + if(GET_FLAG(f, member)) // TODO: CHECK ME + shred->reg += SZ_INT; else if(GET_FLAG(def, static)) shred->reg -= SZ_INT; *(VM_Code*)(shred->reg -SZ_INT) = def->base->func->code; return; - } + } else + Except(shred, "TemplateException"); } INSTR(DotTmpl) { diff --git a/src/parse/check.c b/src/parse/check.c index 495e1e21..401ac531 100644 --- a/src/parse/check.c +++ b/src/parse/check.c @@ -451,7 +451,7 @@ ANN static Func _find_template_match(const Env env, const Value v, const Exp_Cal if(is_fptr(v->type)) { const Symbol sym = func_symbol(env, v->owner->name, v->name, tmpl_name, 0); const Value value = nspc_lookup_value1(v->owner, sym); - Func_Def base = v->d.func_ref->def; + Func_Def base = v->d.func_ref ? v->d.func_ref->def : exp->func->type->e->d.func->def; struct Func_Base_ *fbase = new_func_base(env->gwion->mp, base->base->td, sym, base->base->args); fbase->tmpl = new_tmpl(env->gwion->mp, base->base->tmpl->list, 0); fbase->tmpl->call = types; @@ -467,11 +467,10 @@ ANN static Func _find_template_match(const Env env, const Value v, const Exp_Cal m_func = find_func_match(env, fbase->func, exp->args); nspc_pop_type(env->gwion->mp, env->curr); if(!value && m_func) { -printf("m_func %p\n", m_func); -if(!m_func->def->base->ret_type) -CHECK_BO(traverse_func_def(env, m_func->def)) + if(!m_func->def->base->ret_type) + CHECK_BO(traverse_func_def(env, m_func->def)) map_set(&v->owner->info->type->map, (vtype)sym, (vtype)actual_type(m_func->value_ref->type)); -} + } } free_stmt(env->gwion->mp, stmt); } @@ -570,7 +569,7 @@ ANN static Func get_template_func(const Env env, const Exp_Call* func, const Val const Func f = find_template_match(env, v, func); if(f) { Tmpl* tmpl = new_tmpl_call(env->gwion->mp, func->tmpl->call); - tmpl->list = v->d.func_ref->def->base->tmpl->list; + tmpl->list = v->d.func_ref ? v->d.func_ref->def->base->tmpl->list : func->func->type->e->d.func->def->base->tmpl->list; ((Exp_Call*)func)->tmpl = tmpl; return ((Exp_Call*)func)->m_func = f; } @@ -586,9 +585,29 @@ ANN static Type check_exp_call_template(const Env env, const Exp_Call *exp) { const Exp args = exp->args; m_uint args_number = 0; DECL_OO(const Value, value, = nspc_lookup_value1(call->type->e->owner, insert_symbol(call->type->name))) - const m_uint type_number = get_type_number(value->d.func_ref->def->base->tmpl->list); + Tmpl *tm = value->d.func_ref ? value->d.func_ref->def->base->tmpl : call->type->e->d.func->def->base->tmpl; + const m_uint type_number = get_type_number(tm->list); Type_List tl[type_number]; - ID_List list = value->d.func_ref->def->base->tmpl->list; + ID_List list = tm->list; + if(tm->call) { + if(!value->d.func_ref) { + Tmpl tmpl = { .call=tm->call }; + ((Exp_Call*)exp)->tmpl = &tmpl; + DECL_OO(const Func,func, = get_template_func(env, exp, value)) + assert(func->def->base->ret_type); + value->d.func_ref = func; + return func->def->base->ret_type; + } else { + const Func func = value->d.func_ref; + if(!func->def->base->ret_type) { // template fptr + const m_uint scope = env_push(env, value->owner_class, value->owner); + CHECK_BO(traverse_func_def(env, func->def)) + env_pop(env, scope); + } + ((Exp_Call*)exp)->m_func = func; + return func->def->base->ret_type; + } + } while(list) { Arg_List arg = value->d.func_ref->def->base->args; Exp template_arg = args; @@ -614,7 +633,7 @@ ANN static Type check_exp_call_template(const Env env, const Exp_Call *exp) { DECL_OO(const Func,func, = get_template_func(env, exp, value)) if(!func->def->base->ret_type) // template fptr CHECK_BO(traverse_func_def(env, func->def)) - return func->def->base->ret_type; + return func->def->base->ret_type; } ANN static m_bool check_exp_call1_check(const Env env, const Exp exp) { @@ -694,17 +713,32 @@ ANN static Type check_exp_post(const Env env, const Exp_Postfix* post) { return t; } +ANN static m_bool predefined_call(const Env env, const Type t, const loc_t pos) { + const m_str str = tl2str(env, t->e->d.func->def->base->tmpl->call); + env_err(env, pos, _("Type '%s' has '%s' as pre-defined types."), + t->name, str); + free_mstr(env->gwion->mp, str); + if(GET_FLAG(t, typedef)) { + loc_header(t->e->d.func->def->pos, env->name); + gw_err(_("from definition:\n")); + loc_err(t->e->d.func->def->pos, env->name); + } + return GW_ERROR; +} + ANN static Type check_exp_call(const Env env, Exp_Call* exp) { if(exp->tmpl) { CHECK_OO(check_exp(env, exp->func)) const Type t = actual_type(exp->func->type); const Value v = nspc_lookup_value1(t->e->owner, insert_symbol(t->name)); if(!v) - ERR_O(exp_self(exp)->pos, _(" template call of non-existant function.")) - if(!GET_FLAG(v, func)) + ERR_O(exp_self(exp)->pos, _("template call of non-existant function.")) + if(!GET_FLAG(v, func) && !GET_FLAG(exp->func->type, func)) ERR_O(exp_self(exp)->pos, _("template call of non-function value.")) if(!v->d.func_ref->def->base->tmpl) ERR_O(exp_self(exp)->pos, _("template call of non-template function.")) + if(t->e->d.func->def->base->tmpl->call) + CHECK_BO(predefined_call(env, t, exp_self(exp)->pos)) const Func ret = find_template_match(env, v, exp); CHECK_OO((exp->m_func = ret)) return ret->def->base->ret_type; @@ -772,7 +806,7 @@ ANN static Type check_exp_dot(const Env env, Exp_Dot* member) { } ANN m_bool check_stmt_type(const Env env, const Stmt_Type stmt) { - return stmt->type->e->def ? check_class_def(env, stmt->type->e->def) : 1; + return stmt->type->e->def ? check_class_def(env, stmt->type->e->def) : GW_OK; } ANN static Type check_exp_lambda(const Env env NUSED, const Exp_If* exp_if NUSED) { return t_lambda; } diff --git a/src/parse/scan0.c b/src/parse/scan0.c index 463e22e2..b8de83a2 100644 --- a/src/parse/scan0.c +++ b/src/parse/scan0.c @@ -33,6 +33,17 @@ ANN static inline m_bool scan0_defined(const Env env, const Symbol s, const loc_ return already_defined(env, s, pos); } +static void fptr_def(const Env env, const Stmt_Fptr stmt) { + const Func_Def def = new_func_def(env->gwion->mp, new_func_base(env->gwion->mp, stmt->base->td, stmt->base->xid, stmt->base->args), + NULL,stmt->base->td->flag, loc_cpy(env->gwion->mp, stmt_self(stmt)->pos)); + stmt->base->func = new_func(env->gwion->mp, s_name(stmt->base->xid), def); + stmt->value->d.func_ref = stmt->base->func; + stmt->base->func->value_ref = stmt->value; + stmt->type->e->d.func = stmt->base->func; + def->base->tmpl = stmt->base->tmpl; + def->base->func = stmt->base->func; +} + ANN m_bool scan0_stmt_fptr(const Env env, const Stmt_Fptr stmt) { CHECK_BB(env_access(env, stmt->base->td->flag, stmt_self(stmt)->pos)) CHECK_BB(scan0_defined(env, stmt->base->xid, td_pos(stmt->base->td))); @@ -44,33 +55,57 @@ ANN m_bool scan0_stmt_fptr(const Env env, const Stmt_Fptr stmt) { t->flag = stmt->base->td->flag; stmt->type = t; stmt->value = mk_class(env, t); + stmt->value->owner = env->curr; + stmt->value->owner_class = env->class_def; + fptr_def(env, stmt); + SET_FLAG(stmt->value, func); add_type(env, t->e->owner, t); return GW_OK; } +ANN static void typedef_simple(const Env env, const Stmt_Type stmt, const Type base) { + const Type t = new_type(env->gwion->mp, ++env->scope->type_xid, s_name(stmt->xid), base); + t->size = base->size; + const Nspc nspc = (!env->class_def && GET_FLAG(stmt->ext, global)) ? + env->global_nspc : env->curr; + add_type(env, nspc, t); + t->e->owner = nspc; + stmt->type = t; + t->flag = stmt->ext->flag | ae_flag_checked; + if(stmt->ext->array && !stmt->ext->array->exp) + SET_FLAG(t, empty); +} + +ANN static void typedef_complex(const Env env, const Stmt_Type stmt, const Type base) { + const ae_flag flag = base->e->def ? base->e->def->flag : 0; + const Class_Def cdef = new_class_def(env->gwion->mp, flag, stmt->xid, stmt->ext, NULL, + loc_cpy(env->gwion->mp, td_pos(stmt->ext))); + CHECK_BB(scan0_class_def(env, cdef)) + stmt->type = cdef->base.type; + cdef->base.tmpl = stmt->tmpl; +} + +ANN static void typedef_fptr(const Env env, const Stmt_Type stmt, const Type base) { + stmt->type = type_copy(env->gwion->mp, base); + stmt->type->name = s_name(stmt->xid); + stmt->type->e->parent = base; + add_type(env, env->curr, stmt->type); + mk_class(env, stmt->type); + if(base->e->d.func->def->base->tmpl) + SET_FLAG(stmt->type, func); +} + ANN m_bool scan0_stmt_type(const Env env, const Stmt_Type stmt) { CHECK_BB(env_access(env, stmt->ext->flag, stmt_self(stmt)->pos)) DECL_OB(const Type, base, = stmt->tmpl ? find_type(env, stmt->ext->xid) : known_type(env, stmt->ext)) CHECK_BB(scan0_defined(env, stmt->xid, td_pos(stmt->ext))) - if(!stmt->ext->types && (!stmt->ext->array || !stmt->ext->array->exp)) { - const Type t = new_type(env->gwion->mp, ++env->scope->type_xid, s_name(stmt->xid), base); - t->size = base->size; - const Nspc nspc = (!env->class_def && GET_FLAG(stmt->ext, global)) ? - env->global_nspc : env->curr; - add_type(env, nspc, t); - t->e->owner = nspc; - stmt->type = t; - t->flag = stmt->ext->flag | ae_flag_checked; - if(stmt->ext->array && !stmt->ext->array->exp) - SET_FLAG(t, empty); - } else { - const ae_flag flag = base->e->def ? base->e->def->flag : 0; - const Class_Def cdef = new_class_def(env->gwion->mp, flag, stmt->xid, stmt->ext, NULL, - loc_cpy(env->gwion->mp, td_pos(stmt->ext))); - CHECK_BB(scan0_class_def(env, cdef)) - stmt->type = cdef->base.type; - cdef->base.tmpl = stmt->tmpl; - } + if(isa(base, t_function) < 0) { + if(!stmt->ext->types && (!stmt->ext->array || !stmt->ext->array->exp)) + typedef_simple(env, stmt, base); + else + typedef_complex(env, stmt, base); + } else + typedef_fptr(env, stmt, base); SET_FLAG(stmt->type, typedef); return GW_OK; } diff --git a/src/parse/scan1.c b/src/parse/scan1.c index 2856ea9e..6b2684e2 100644 --- a/src/parse/scan1.c +++ b/src/parse/scan1.c @@ -254,7 +254,7 @@ ANN m_bool scan1_stmt_fptr(const Env env, const Stmt_Fptr stmt) { ANN m_bool scan1_stmt_type(const Env env, const Stmt_Type stmt) { if(!stmt->type) CHECK_BB(scan0_stmt_type(env, stmt)) - return stmt->type->e->def ? scan1_class_def(env, stmt->type->e->def) : 1; + return stmt->type->e->def ? scan1_class_def(env, stmt->type->e->def) : GW_OK; } ANN m_bool scan1_stmt_union(const Env env, const Stmt_Union stmt) { diff --git a/src/parse/scan2.c b/src/parse/scan2.c index 2d0af075..50fb06d4 100644 --- a/src/parse/scan2.c +++ b/src/parse/scan2.c @@ -14,7 +14,6 @@ #include "nspc.h" #include "operator.h" -//ANN /* static */ m_bool scan2_exp(const Env, const Exp); ANN static m_bool scan2_stmt(const Env, const Stmt); ANN static m_bool scan2_stmt_list(const Env, Stmt_List); @@ -84,18 +83,12 @@ ANN static Value scan2_func_assign(const Env env, const Func_Def d, } ANN m_bool scan2_stmt_fptr(const Env env, const Stmt_Fptr ptr) { - const Func_Def def = new_func_def(env->gwion->mp, new_func_base(env->gwion->mp, ptr->base->td, ptr->base->xid, ptr->base->args), - NULL,ptr->base->td->flag, loc_cpy(env->gwion->mp, stmt_self(ptr)->pos)); - def->base->ret_type = ptr->base->ret_type; - ptr->base->func = new_func(env->gwion->mp, s_name(ptr->base->xid), def); - ptr->value->d.func_ref = ptr->base->func; - ptr->base->func->value_ref = ptr->value; - ptr->type->e->d.func = ptr->base->func; - def->base->tmpl = ptr->base->tmpl; - SET_FLAG(ptr->value, func | ae_flag_checked); -if(!ptr->base->tmpl)// - if(ptr->base->args) - CHECK_BB(scan2_args(env, def)) + const Func_Def def = ptr->type->e->d.func->def; + if(!ptr->base->tmpl) { + def->base->ret_type = ptr->base->ret_type; + if(ptr->base->args) + CHECK_BB(scan2_args(env, def)) + } if(env->class_def) { if(GET_FLAG(ptr->base->td, global)) { SET_FLAG(ptr->value, global); @@ -118,7 +111,7 @@ if(!ptr->base->tmpl)// } ANN m_bool scan2_stmt_type(const Env env, const Stmt_Type stmt) { - return stmt->type->e->def ? scan2_class_def(env, stmt->type->e->def) : 1; + return stmt->type->e->def ? scan2_class_def(env, stmt->type->e->def) : GW_OK; } ANN static inline Value prim_value(const Env env, const Symbol s) { diff --git a/src/parse/template.c b/src/parse/template.c index aac48450..c9f66576 100644 --- a/src/parse/template.c +++ b/src/parse/template.c @@ -5,6 +5,8 @@ #include "vm.h" #include "env.h" #include "type.h" +#include "func.h" +#include "value.h" #include "nspc.h" #include "traverse.h" #include "template.h" @@ -33,15 +35,15 @@ ANEW ANN static ID_List id_list_copy(MemPool p, ID_List src) { return list; } -ANN static ID_List get_total_type_list(const Env env, const Type t) { +ANN2(1,2) static ID_List get_total_type_list(const Env env, const Type t, const Tmpl *tmpl) { const Type parent = owner_type(env, t); if(!parent) - return t->e->def->base.tmpl ? t->e->def->base.tmpl->list : NULL; + return tmpl ? tmpl->list : NULL; const Vector v = get_types(env, parent); const ID_List base = (ID_List)vector_pop(v); if(!base) { free_vector(env->gwion->mp, v); - return t->e->def->base.tmpl ? t->e->def->base.tmpl->list : NULL; + return tmpl ? tmpl->list : NULL; } const ID_List types = id_list_copy(env->gwion->mp, base); ID_List list, tmp = types; @@ -49,7 +51,7 @@ ANN static ID_List get_total_type_list(const Env env, const Type t) { list = (ID_List)vector_pop(v); tmp = (tmp->next = id_list_copy(env->gwion->mp, list)); } - tmp->next = t->e->def->base.tmpl->list; + tmp->next = tmpl->list; free_vector(env->gwion->mp, v); return types; } @@ -148,6 +150,12 @@ extern ANN m_bool scan1_class_def(const Env, const Class_Def); extern ANN m_bool traverse_func_def(const Env, const Func_Def); extern ANN m_bool traverse_class_def(const Env, const Class_Def); +ANN Tmpl* mk_tmpl(const Env env, const Type t, const Tmpl *tm, const Type_List types) { + Tmpl *tmpl = new_tmpl(env->gwion->mp, get_total_type_list(env, t, tm), 0); + tmpl->call = types; + return tmpl; +} + ANN Type scan_type(const Env env, const Type t, const Type_Decl* type) { if(GET_FLAG(t, template)) { if(GET_FLAG(t, ref)) @@ -161,8 +169,7 @@ ANN Type scan_type(const Env env, const Type t, const Type_Decl* type) { SET_FLAG(a, ref); if(a->base.type) return a->base.type; - a->base.tmpl = new_tmpl(env->gwion->mp, get_total_type_list(env, t), 0); - a->base.tmpl->call = type->types; + a->base.tmpl = mk_tmpl(env, t, t->e->def->base.tmpl, type->types); if(isa(t, t_union) < 0) { CHECK_BO(scan0_class_def(env, a)) map_set(&t->e->owner->info->type->map, (vtype)a->base.xid, (vtype)a->base.type); @@ -186,8 +193,35 @@ ANN Type scan_type(const Env env, const Type t, const Type_Decl* type) { ADD_REF(t->nspc->dtor) } return a->base.type; - } else if(type->types) - ERR_O(type->xid->pos, - _("type '%s' is not template. You should not provide template types"), t->name) + } else if(type->types) { // TODO: clean me + if(isa(t, t_function) > 0 && t->e->d.func->def->base->tmpl) { + const m_str tl_name = tl2str(env, type->types); + const Symbol sym = func_symbol(env, t->e->owner->name, t->e->d.func->name, tl_name, 0); + free_mstr(env->gwion->mp, tl_name); + const Type base_type = nspc_lookup_type1(t->e->owner, sym); + if(base_type) + return base_type; + const Type ret = type_copy(env->gwion->mp, t); + ret->e->parent = t; + ret->name = s_name(sym); + SET_FLAG(ret, func); + nspc_add_type(env->curr, sym, ret); + const Func_Def def = new_func_def(env->gwion->mp, + new_func_base(env->gwion->mp, t->e->d.func->def->base->td, sym, t->e->d.func->def->base->args), + NULL, type->flag, loc_cpy(env->gwion->mp, td_pos(type))); + const Func func = ret->e->d.func = new_func(env->gwion->mp, s_name(sym), def); + const Value value = new_value(env->gwion->mp, ret, s_name(sym)); + value->d.func_ref = func; + value->owner = t->e->owner; + value->owner_class = t->e->d.func->value_ref->owner_class; + func->value_ref = value; + func->def->base->tmpl = mk_tmpl(env, t, t->e->d.func->def->base->tmpl, type->types); + def->base->func = func; + nspc_add_value(env->curr, sym, value); + return ret; + } + ERR_O(type->xid->pos, + _("type '%s' is not template. You should not provide template types"), t->name) + } return t; } -- 2.43.0