From 77438042ce4eb7949479466b13b94dbb3fd6bc3c Mon Sep 17 00:00:00 2001 From: =?utf8?q?J=C3=A9r=C3=A9mie=20Astor?= Date: Sat, 29 May 2021 13:05:09 +0200 Subject: [PATCH] :art: Update --- examples/template_dyn.gw | 10 +- include/env/nspc.h | 28 ++--- include/env/trait.h | 13 +++ include/env/type.h | 1 + include/gwi.h | 2 +- include/gwion_env.h | 1 + include/import/checker.h | 1 + include/tmpl_info.h | 2 +- plug | 2 +- src/clean.c | 19 +++- src/emit/emit.c | 3 + src/env/nspc.c | 18 +++- src/env/trait.c | 17 ++++ src/env/type.c | 4 +- src/import/import_cdef.c | 10 +- src/import/import_checker.c | 32 +++--- src/lib/array.c | 24 ++--- src/lib/lib_func.c | 2 +- src/lib/object.c | 2 +- src/lib/tmpl_info.c | 2 +- src/lib/union.c | 4 +- src/parse/check.c | 187 +++++++++++++++++++++++++++++++--- src/parse/func_resolve_tmpl.c | 34 ++++++- src/parse/scan0.c | 43 ++++++++ src/parse/scan1.c | 9 +- src/parse/scan2.c | 4 +- src/parse/template.c | 2 +- 27 files changed, 391 insertions(+), 85 deletions(-) create mode 100644 include/env/trait.h create mode 100644 src/env/trait.c diff --git a/examples/template_dyn.gw b/examples/template_dyn.gw index 32e81dfe..e355caf4 100644 --- a/examples/template_dyn.gw +++ b/examples/template_dyn.gw @@ -4,15 +4,15 @@ fun void test(C cc, int i) { <<< 1 >>>; <<< cc.test(i, i) >>>; } class C { - fun int test:[A](A a) { <<< " A ", a >>>; } - fun int test:[A](A a, int i) { <<< " ", a >>>; } - fun int test:[A](A a, int i, int j) { <<< a >>>; } + fun void test:[A](A a) { <<< " A ", a >>>; } + fun void test:[A](A a, int i) { <<< " ", a >>>; } + fun void test:[A](A a, int i, int j) { <<< a >>>; } } class D extends C { - fun int test:[A](A a, int i) { <<< this, " extent ", a, __func__ >>>; } + fun void test:[A](A a, int i) { <<< this, " extent ", a, __func__ >>>; } } class E extends D { - fun int test:[A](A a, int i) { <<< this, " Extent ", a, __func__ >>>; } + fun void test:[A](A a, int i) { <<< this, " Extent ", a, __func__ >>>; } } diff --git a/include/env/nspc.h b/include/env/nspc.h index f8dda3c8..3790790c 100644 --- a/include/env/nspc.h +++ b/include/env/nspc.h @@ -1,23 +1,24 @@ #ifndef __NSPC #define __NSPC struct NspcInfo_ { - m_bit* class_data; - struct Vector_ vtable; - struct Map_ op_map; - Scope value; - Scope type; - Scope func; - size_t offset; - size_t class_data_size; + m_bit* class_data; + struct Map_ op_map; + Scope value; + Scope type; + Scope func; + Scope trait; + size_t offset; + size_t class_data_size; }; struct Nspc_ { struct NspcInfo_* info; - Nspc parent; - m_str name; - struct VM_Code_* pre_ctor; - struct VM_Code_* dtor; - uint16_t ref; + Nspc parent; + m_str name; + struct Vector_ vtable; + struct VM_Code_* pre_ctor; + struct VM_Code_* dtor; + uint16_t ref; }; REF_FUNC(Nspc, nspc) @@ -63,6 +64,7 @@ describe_lookups(A, b) describe_nspc_func(Value, value) describe_nspc_func(Type, type) describe_nspc_func(Func, func) +describe_nspc_func(Trait, trait) /* howere there is no need for lookup_func0, push_func, pop_func */ ANN void did_you_mean_nspc(const Nspc, const char*); ANN void did_you_mean_type(const Type, const char*); diff --git a/include/env/trait.h b/include/env/trait.h new file mode 100644 index 00000000..6a83b10f --- /dev/null +++ b/include/env/trait.h @@ -0,0 +1,13 @@ +#ifndef __TRAIT +#define __TRAIT + +typedef struct Trait_ { + struct Vector_ requested_values; + struct Vector_ requested_funcs; + m_str filename; + loc_t loc; +} *Trait; + +ANN Trait new_trait(MemPool, const loc_t); +ANN void free_trait(MemPool, Trait); +#endif diff --git a/include/env/type.h b/include/env/type.h index c0777f44..0b021da4 100644 --- a/include/env/type.h +++ b/include/env/type.h @@ -12,6 +12,7 @@ struct TypeInfo_ { Type base_type; struct TupleForm_* tuple; struct VM_Code_ *gack; + ID_List traits; }; enum tflag { diff --git a/include/gwi.h b/include/gwi.h index 5330e939..2ded2e39 100644 --- a/include/gwi.h +++ b/include/gwi.h @@ -19,7 +19,7 @@ struct Gwi_ { #include "import/internals.h" static inline Tmpl* gwi_tmpl(const Gwi gwi) { - return new_tmpl_base(gwi->gwion->mp, gwi->ck->tmpl); + return new_tmpl_base(gwi->gwion->mp, gwi->ck->sl); } ANN void gwi_effects(const Gwi gwi, const m_str name); diff --git a/include/gwion_env.h b/include/gwion_env.h index a97ae2e6..70489558 100644 --- a/include/gwion_env.h +++ b/include/gwion_env.h @@ -2,6 +2,7 @@ #define __GWION_ENV #include "env/oo.h" +#include "env/trait.h" #include "env/nspc.h" #include "env/env.h" diff --git a/include/import/checker.h b/include/import/checker.h index 29024ebd..5f80b16e 100644 --- a/include/import/checker.h +++ b/include/import/checker.h @@ -15,6 +15,7 @@ typedef struct ImportCK { // name_checker ? Symbol sym; union { ID_List tmpl; + Specialized_List sl; Exp exp; }; union { diff --git a/include/tmpl_info.h b/include/tmpl_info.h index 30acc1bf..9f46f95d 100644 --- a/include/tmpl_info.h +++ b/include/tmpl_info.h @@ -2,7 +2,7 @@ #define _TMPL_INFO struct tmpl_info { Symbol name; - ID_List list; + Specialized_List list; const Type_Decl* td; Type ret; Type base; diff --git a/plug b/plug index fb296d97..bbba0ebd 160000 --- a/plug +++ b/plug @@ -1 +1 @@ -Subproject commit fb296d97fea12ee3e44a1120c47033dfe5325a62 +Subproject commit bbba0ebd0da010c4fdaaa53aee5da38e7513c3ff diff --git a/src/clean.c b/src/clean.c index da790e5c..fb9b0764 100644 --- a/src/clean.c +++ b/src/clean.c @@ -16,6 +16,13 @@ ANN static void clean_id_list(Clean *a, ID_List b) { clean_id_list(a, b->next); } +ANN static void clean_specialized_list(Clean *a, Specialized_List b) { + if(b->traits) + clean_id_list(a, b->traits); + if(b->next) + clean_specialized_list(a, b->next); +} + ANN static void clean_type_list(Clean *a, Type_List b) { clean_type_decl(a, b->td); if(b->next) @@ -24,7 +31,7 @@ ANN static void clean_type_list(Clean *a, Type_List b) { ANN static void clean_tmpl(Clean *a, Tmpl *b) { if(b->base < 0 && b->list) - clean_id_list(a, b->list); + clean_specialized_list(a, b->list); if(b->call) clean_type_list(a, b->call); } @@ -322,6 +329,8 @@ ANN static void clean_extend_def(Clean *a, Extend_Def b) { ANN static void clean_class_def(Clean *a, Class_Def b) { clean_type_def(a, &b->base); + if(b->traits) + clean_id_list(a, b->traits); if(b->body) clean_ast(a, b->body); } @@ -367,6 +376,14 @@ ANN static void clean_type_def(Clean *a, Type_Def b) { if(b->tmpl) clean_tmpl(a, b->tmpl); } + +ANN static void clean_trait_def(Clean *a, Trait_Def b) { + if(b->traits) + clean_id_list(a, b->traits); + if(b->body) + clean_ast(a, b->body); +} + DECL_SECTION_FUNC(clean, void, Clean*) ANN static inline void clean_section(Clean *a, Section *b) { diff --git a/src/emit/emit.c b/src/emit/emit.c index f62afc69..d836595a 100644 --- a/src/emit/emit.c +++ b/src/emit/emit.c @@ -1064,11 +1064,13 @@ ANN static inline m_bool emit_inline(const Emitter emit, const Func f, const Exp } ANN static m_bool _emit_exp_call(const Emitter emit, const Exp_Call* exp_call) { +/* #ifndef GWION_NOINLINE const Func f = is_inlinable(emit, exp_call); if(f) return emit_inline(emit, f, exp_call); #endif +*/ CHECK_BB(prepare_call(emit, exp_call)); const Type t = actual_type(emit->gwion, exp_call->func->type); if(isa(t, emit->gwion->type[et_function]) > 0) @@ -2511,6 +2513,7 @@ ANN m_bool emit_func_def(const Emitter emit, const Func_Def f) { ANN static m_bool emit_extend_def(const Emitter emit, const Extend_Def xdef); #define emit_fptr_def dummy_func +#define emit_trait_def dummy_func HANDLE_SECTION_FUNC(emit, m_bool, Emitter) ANN static inline m_bool emit_ast_inner(const Emitter emit, Ast ast) { diff --git a/src/env/nspc.c b/src/env/nspc.c index 247cc17f..1fad63ab 100644 --- a/src/env/nspc.c +++ b/src/env/nspc.c @@ -10,6 +10,7 @@ ANN void nspc_commit(const Nspc nspc) { scope_commit(nspc->info->value); scope_commit(nspc->info->func); scope_commit(nspc->info->type); + scope_commit(nspc->info->trait); } ANN static inline void nspc_release_object(const Nspc a, Value value, Gwion gwion) { @@ -60,17 +61,25 @@ ANN static void nspc_free_##b(Nspc n, Gwion gwion) {\ describe_nspc_free(Func, func) describe_nspc_free(Type, type) +ANN static void nspc_free_trait(Nspc n, Gwion gwion) { + struct scope_iter iter = { n->info->trait, 0, 0 }; + Trait a; + while(scope_iter(&iter, &a) > 0) + free_trait(gwion->mp, a); + free_scope(gwion->mp, n->info->trait); +} ANN void free_nspc(const Nspc a, const Gwion gwion) { free_nspc_value(a, 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); 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); - if(a->info->vtable.ptr) - vector_release(&a->info->vtable); + if(a->vtable.ptr) + vector_release(&a->vtable); mp_free(gwion->mp, NspcInfo, a->info); if(a->pre_ctor) vmcode_remref(a->pre_ctor, gwion); @@ -84,8 +93,9 @@ ANN Nspc new_nspc(MemPool p, const m_str name) { a->name = name; a->info = mp_calloc(p, NspcInfo); a->info->value = new_scope(p); - a->info->type = new_scope(p); - a->info->func = new_scope(p); + a->info->type = new_scope(p); + a->info->func = new_scope(p); + a->info->trait = new_scope(p); a->ref = 1; return a; } diff --git a/src/env/trait.c b/src/env/trait.c new file mode 100644 index 00000000..c6b53fbe --- /dev/null +++ b/src/env/trait.c @@ -0,0 +1,17 @@ +#include +#include +#include + +ANN Trait new_trait(MemPool mp, const loc_t loc) { + const Trait a = mp_calloc(mp, Trait); + a->loc = loc; + return a; +} + +ANN void free_trait(MemPool mp, Trait a) { + if(a->requested_values.ptr) + vector_release(&a->requested_values); + if(a->requested_funcs.ptr) + vector_release(&a->requested_funcs); + mp_free(mp, Trait, a); +} diff --git a/src/env/type.c b/src/env/type.c index 21caa228..547f2fef 100644 --- a/src/env/type.c +++ b/src/env/type.c @@ -157,6 +157,6 @@ ANN void inherit(const Type t) { if(!nspc || !parent) return; nspc->info->offset = parent->info->offset; - if(parent->info->vtable.ptr) - vector_copy2(&parent->info->vtable, &nspc->info->vtable); + if(parent->vtable.ptr) + vector_copy2(&parent->vtable, &nspc->vtable); } diff --git a/src/import/import_cdef.c b/src/import/import_cdef.c index d6fed154..f8f202fd 100644 --- a/src/import/import_cdef.c +++ b/src/import/import_cdef.c @@ -38,7 +38,7 @@ ANN2(1) void add_template(const Env env, const Type t) { Tmpl* tmpl = t->info->cdef->base.tmpl; if(tmpl) { nspc_push_type(env->gwion->mp, env->curr);// - ID_List il = tmpl->list; + Specialized_List il = tmpl->list; do nspc_add_type(env->curr, il->xid, env->gwion->type[et_auto]); while((il = il->next)); } @@ -75,7 +75,7 @@ ANN2(1,2) Type gwi_class_ini(const Gwi gwi, const m_str name, const m_str parent struct ImportCK ck = { .name=name }; CHECK_BO(check_typename_def(gwi, &ck)); DECL_OO(Type_Decl *,td, = gwi_str2td(gwi, parent ?: "Object")); - Tmpl* tmpl = ck.tmpl ? new_tmpl_base(gwi->gwion->mp, ck.tmpl) : NULL; + Tmpl* tmpl = ck.sl ? new_tmpl_base(gwi->gwion->mp, ck.sl) : NULL; if(tmpl) CHECK_BO(template_push_types(gwi->gwion->env, tmpl)); const Type base = find_type(gwi->gwion->env, td); @@ -95,7 +95,7 @@ ANN2(1,2) Type gwi_class_ini(const Gwi gwi, const m_str name, const m_str parent t->info->parent = p; if(td->array) set_tflag(t, tflag_typedef); - if(ck.tmpl) + if(ck.sl) set_tflag(t, tflag_tmpl | tflag_ntmpl); else gwi_type_flag(t); @@ -107,12 +107,12 @@ ANN Type gwi_struct_ini(const Gwi gwi, const m_str name) { CHECK_BO(check_typename_def(gwi, &ck)); const Type t = new_type(gwi->gwion->mp, s_name(ck.sym), gwi->gwion->type[et_compound]); set_tflag(t, tflag_struct); - if(!ck.tmpl) + if(!ck.sl) gwi_type_flag(t); else { t->info->cdef = new_class_def(gwi->gwion->mp, 0, ck.sym, NULL, NULL, gwi->loc); t->info->cdef->base.type = t; - t->info->cdef->base.tmpl = new_tmpl_base(gwi->gwion->mp, ck.tmpl); + t->info->cdef->base.tmpl = new_tmpl_base(gwi->gwion->mp, ck.sl); t->info->tuple = new_tupleform(gwi->gwion->mp, NULL); t->info->parent = NULL; t->info->cdef->cflag |= cflag_struct; diff --git a/src/import/import_checker.c b/src/import/import_checker.c index 46ebe154..85628e66 100644 --- a/src/import/import_checker.c +++ b/src/import/import_checker.c @@ -93,32 +93,34 @@ ANN Var_Decl_List str2varlist(const Gwion gwion, const m_str path, const loc_t p return new_var_decl_list(gwion->mp, var, NULL); } -ANN static ID_List _tmpl_list(const Gwion gwion, struct td_checker *tdc) { +#define SPEC_ERROR (Specialized_List)GW_ERROR +ANN static Specialized_List _tmpl_list(const Gwion gwion, struct td_checker *tdc) { DECL_OO(const Symbol, sym, = __str2sym(gwion, tdc)); - ID_List next = NULL; + Specialized_List next = NULL; if(*tdc->str == ',') { ++tdc->str; - if(!(next = _tmpl_list(gwion, tdc)) || next == (ID_List)GW_ERROR) - return (ID_List)GW_ERROR; + if(!(next = _tmpl_list(gwion, tdc)) || next == SPEC_ERROR) + return SPEC_ERROR; } - const ID_List list = new_id_list(gwion->mp, sym); + // TODO: handle traits? + const Specialized_List list = new_specialized_list(gwion->mp, sym, NULL, tdc->pos); list->next = next; return list; } -ANN static ID_List __tmpl_list(const Gwion gwion, struct td_checker *tdc) { +ANN static Specialized_List __tmpl_list(const Gwion gwion, struct td_checker *tdc) { if(tdc->str[0] != ':') return NULL; if(tdc->str[1] != '[') - return (ID_List)GW_ERROR; + return SPEC_ERROR; tdc->str += 2; - const ID_List list = _tmpl_list(gwion, tdc); - if(list == (ID_List)GW_ERROR) - return (ID_List)GW_ERROR; + const Specialized_List list = _tmpl_list(gwion, tdc); + if(list == SPEC_ERROR) + return SPEC_ERROR; if(tdc->str[0] != ']') { // unfinished template if(list) - free_id_list(gwion->mp, list); - return (ID_List)GW_ERROR; + free_specialized_list(gwion->mp, list); + return SPEC_ERROR; } ++tdc->str; return list; @@ -128,10 +130,10 @@ ANN m_bool check_typename_def(const Gwi gwi, ImportCK *ck) { struct td_checker tdc = { .str= ck->name, .pos=gwi->loc }; if(!(ck->sym = _str2sym(gwi->gwion, &tdc, tdc.str))) return GW_ERROR; - ID_List il = __tmpl_list(gwi->gwion, &tdc); - if(il == (ID_List)GW_ERROR) + Specialized_List sl = __tmpl_list(gwi->gwion, &tdc); + if(sl == SPEC_ERROR) return GW_ERROR; - ck->tmpl = il; + ck->sl = sl; ck->name = s_name(ck->sym); return GW_OK; diff --git a/src/lib/array.c b/src/lib/array.c index ba9a5e61..8a6697de 100644 --- a/src/lib/array.c +++ b/src/lib/array.c @@ -671,20 +671,20 @@ static OP_CHECK(opck_array_scan) { set_tflag(t, tflag_cdef | tflag_tmpl); void* rem = isa(base, env->gwion->type[et_compound]) > 0 ? !tflag(base, tflag_struct) ? vm_vector_rem_obj : vm_vector_rem_struct : vm_vector_rem; - builtin_func(env->gwion->mp, (Func)vector_at(&t->nspc->info->vtable, 0), rem); + builtin_func(env->gwion->mp, (Func)vector_at(&t->nspc->vtable, 0), rem); void* insert = isa(base, env->gwion->type[et_compound]) > 0 ? !tflag(base, tflag_struct) ? vm_vector_insert_obj : vm_vector_insert_struct : vm_vector_insert; - builtin_func(env->gwion->mp, (Func)vector_at(&t->nspc->info->vtable, 1), insert); - builtin_func(env->gwion->mp, (Func)vector_at(&t->nspc->info->vtable, 2), vm_vector_size); - builtin_func(env->gwion->mp, (Func)vector_at(&t->nspc->info->vtable, 3), vm_vector_depth); - builtin_func(env->gwion->mp, (Func)vector_at(&t->nspc->info->vtable, 4), vm_vector_cap); - builtin_func(env->gwion->mp, (Func)vector_at(&t->nspc->info->vtable, 5), vm_vector_random); - builtin_func(env->gwion->mp, (Func)vector_at(&t->nspc->info->vtable, 6), vm_vector_map); - builtin_func(env->gwion->mp, (Func)vector_at(&t->nspc->info->vtable, 7), vm_vector_compactmap); - builtin_func(env->gwion->mp, (Func)vector_at(&t->nspc->info->vtable, 8), vm_vector_filter); - builtin_func(env->gwion->mp, (Func)vector_at(&t->nspc->info->vtable, 9), vm_vector_count); - builtin_func(env->gwion->mp, (Func)vector_at(&t->nspc->info->vtable, 10), vm_vector_foldl); - builtin_func(env->gwion->mp, (Func)vector_at(&t->nspc->info->vtable, 11), vm_vector_foldr); + builtin_func(env->gwion->mp, (Func)vector_at(&t->nspc->vtable, 1), insert); + builtin_func(env->gwion->mp, (Func)vector_at(&t->nspc->vtable, 2), vm_vector_size); + builtin_func(env->gwion->mp, (Func)vector_at(&t->nspc->vtable, 3), vm_vector_depth); + builtin_func(env->gwion->mp, (Func)vector_at(&t->nspc->vtable, 4), vm_vector_cap); + builtin_func(env->gwion->mp, (Func)vector_at(&t->nspc->vtable, 5), vm_vector_random); + builtin_func(env->gwion->mp, (Func)vector_at(&t->nspc->vtable, 6), vm_vector_map); + builtin_func(env->gwion->mp, (Func)vector_at(&t->nspc->vtable, 7), vm_vector_compactmap); + builtin_func(env->gwion->mp, (Func)vector_at(&t->nspc->vtable, 8), vm_vector_filter); + builtin_func(env->gwion->mp, (Func)vector_at(&t->nspc->vtable, 9), vm_vector_count); + builtin_func(env->gwion->mp, (Func)vector_at(&t->nspc->vtable, 10), vm_vector_foldl); + builtin_func(env->gwion->mp, (Func)vector_at(&t->nspc->vtable, 11), vm_vector_foldr); if(isa(base, env->gwion->type[et_compound]) > 0) { t->nspc->dtor = new_vmcode(env->gwion->mp, NULL, SZ_INT, 1, "array component dtor"); set_tflag(t, tflag_dtor); diff --git a/src/lib/lib_func.c b/src/lib/lib_func.c index 08f622d4..992cb370 100644 --- a/src/lib/lib_func.c +++ b/src/lib/lib_func.c @@ -56,7 +56,7 @@ ANN static void _fptr_tmpl_push(const Env env, const Func f) { Type_List tl = tmpl->call; if(!tl) return; - ID_List il = tmpl->list; + Specialized_List il = tmpl->list; while(il) { const Type t = known_type(env, tl->td); nspc_add_type(env->curr, il->xid, t); diff --git a/src/lib/object.c b/src/lib/object.c index 4afab57b..74549429 100644 --- a/src/lib/object.c +++ b/src/lib/object.c @@ -25,7 +25,7 @@ M_Object new_object(MemPool p, const VM_Shred shred, const Type t) { a->ref = 1; a->type_ref = t; if(t->nspc) { - a->vtable.ptr = t->nspc->info->vtable.ptr; + a->vtable.ptr = t->nspc->vtable.ptr; if(t->nspc->info->offset) a->data = (m_bit*)_mp_calloc(p, t->nspc->info->offset); } diff --git a/src/lib/tmpl_info.c b/src/lib/tmpl_info.c index 9a805fe4..8414edcc 100644 --- a/src/lib/tmpl_info.c +++ b/src/lib/tmpl_info.c @@ -66,7 +66,7 @@ ANEW ANN static Symbol template_id(const Env env, struct tmpl_info *const info) return sym; } -ANN static m_bool template_match(ID_List base, Type_List call) { +ANN static m_bool template_match(Specialized_List base, Type_List call) { while((call = call->next) && (base = base->next)); return !call ? GW_OK : GW_ERROR; } diff --git a/src/lib/union.c b/src/lib/union.c index 2ea352d5..611a2b30 100644 --- a/src/lib/union.c +++ b/src/lib/union.c @@ -39,7 +39,7 @@ static OP_EMIT(opem_union_dot) { CHECK_BB(emit_exp(emit, member->base)); if(isa(exp_self(member)->type, emit->gwion->type[et_function]) > 0) { const Instr instr = emit_add_instr(emit, RegPushImm); - const Func f = (Func)vector_front(&member->base->type->info->parent->nspc->info->vtable); + const Func f = (Func)vector_front(&member->base->type->info->parent->nspc->vtable); instr->m_val = (m_uint)f->code; return GW_OK; } @@ -179,7 +179,7 @@ ANN GWION_IMPORT(union) { GWI_BB(gwi_oper_emi(gwi, opem_union_ctor)) GWI_BB(gwi_oper_end(gwi, "@ctor", NULL)) - const Func f = (Func)vector_front(&t_union->nspc->info->vtable); + const Func f = (Func)vector_front(&t_union->nspc->vtable); const struct Op_Func opfunc = { .ck=opck_union_is }; const struct Op_Import opi = { .rhs=f->value_ref->type, .func=&opfunc, .data=(uintptr_t)f, .pos=gwi->loc, .op=insert_symbol(gwi->gwion->st, "@func_check") }; diff --git a/src/parse/check.c b/src/parse/check.c index eb1e692e..c9c88ef8 100644 --- a/src/parse/check.c +++ b/src/parse/check.c @@ -609,7 +609,7 @@ ANN2(1) static void function_alternative(const Env env, const Type f, const Exp gw_err(_("and not:\n {G}void{0}\n")); } -ANN static m_uint get_type_number(ID_List list) { +ANN static m_uint get_type_number(Specialized_List list) { m_uint type_number = 0; do ++type_number; while((list = list->next)); @@ -662,7 +662,7 @@ ANN static Type_List check_template_args(const Env env, Exp_Call *exp, const Tmp const m_uint type_number = get_type_number(tm->list); Type_List tl[type_number]; tl[0] = NULL; - ID_List list = tm->list; + Specialized_List list = tm->list; while(list) { Arg_List arg = fdef->base->args; Exp template_arg = exp->args; @@ -1371,7 +1371,7 @@ ANN static m_bool parent_match_actual(const Env env, const restrict Func_Def fde CHECK_BB(check_signature_match(env, fdef, parent_func)); if(!fdef->base->tmpl) { fdef->base->func->vt_index = parent_func->vt_index; - vector_set(&env->curr->info->vtable, fdef->base->func->vt_index, (vtype)fdef->base->func); + vector_set(&env->curr->vtable, fdef->base->func->vt_index, (vtype)fdef->base->func); } return GW_OK; } @@ -1382,8 +1382,8 @@ ANN static m_bool parent_match_actual(const Env env, const restrict Func_Def fde ANN static m_bool check_parent_match(const Env env, const Func_Def fdef) { const Func func = fdef->base->func; const Type parent = env->class_def->info->parent; - if(!env->curr->info->vtable.ptr) - vector_init(&env->curr->info->vtable); + if(!env->curr->vtable.ptr) + vector_init(&env->curr->vtable); if(parent) { const Value v = find_value(parent, fdef->base->xid); if(v && isa(v->type, env->gwion->type[et_function]) > 0) { @@ -1392,8 +1392,8 @@ ANN static m_bool check_parent_match(const Env env, const Func_Def fdef) { return match; } } - func->vt_index = vector_size(&env->curr->info->vtable); - vector_add(&env->curr->info->vtable, (vtype)func); + func->vt_index = vector_size(&env->curr->vtable); + vector_add(&env->curr->vtable, (vtype)func); return GW_OK; } @@ -1529,6 +1529,39 @@ ANN static m_bool check_extend_def(const Env env, const Extend_Def xdef) { return ret; } +ANN static m_bool _check_trait_def(const Env env, const Trait_Def pdef) { + const Trait trait = nspc_lookup_trait1(env->curr, pdef->xid); + Ast ast = pdef->body; + while(ast) { + Section * section = ast->section; + if(section->section_type == ae_section_stmt) { + Stmt_List list = section->d.stmt_list; + while(list) { + const Stmt stmt = list->stmt; + if(stmt->stmt_type == ae_stmt_exp) { + CHECK_BB(traverse_exp(env, stmt->d.stmt_exp.val)); + Var_Decl_List list = stmt->d.stmt_exp.val->d.exp_decl.list; + while(list) { + const Value value = list->self->value; + valuefrom(env, value->from, list->self->pos); // we do not need owner + if(!trait->requested_values.ptr) + vector_init(&trait->requested_values); + vector_add(&trait->requested_values, (m_uint)value); + list = list->next; + } + } + list = list->next; + } + } + ast = ast->next; + } + return GW_OK; +} + +ANN static m_bool check_trait_def(const Env env, const Trait_Def pdef) { + RET_NSPC(_check_trait_def(env, pdef)); +} + #define check_fptr_def dummy_func HANDLE_SECTION_FUNC(check, m_bool, Env) @@ -1556,11 +1589,11 @@ ANN static m_bool cdef_parent(const Env env, const Class_Def cdef) { } ANN m_bool check_abstract(const Env env, const Class_Def cdef) { - if(!cdef->base.type->nspc->info->vtable.ptr) + if(!cdef->base.type->nspc->vtable.ptr) return GW_OK; bool err = false; - for(m_uint i = 0; i < vector_size(&cdef->base.type->nspc->info->vtable); ++i) { - Func f = (Func)vector_at(&cdef->base.type->nspc->info->vtable, i); + for(m_uint i = 0; i < vector_size(&cdef->base.type->nspc->vtable); ++i) { + Func f = (Func)vector_at(&cdef->base.type->nspc->vtable, i); if(f && GET_FLAG(f->def->base, abstract)) { if(!err) { err = true; @@ -1634,6 +1667,120 @@ if(isa(dlist->self->value->type, env->gwion->type[et_compound]) > 0) return false; } +ANN static bool request_var(const Env env, const Type t, const Value request) { + const Value value = nspc_lookup_value0(t->nspc, insert_symbol(request->name)); + if(!value) { + gwerr_basic("missing requested variable", NULL, NULL, + request->from->filename, request->from->loc, 0); + return false; + } + bool error = true; + if(isa(value->type, request->type) < 0) { + gwerr_basic("invalid variable type", NULL, NULL, + value->from->filename, value->from->loc, 0); + // can we point to the type decl? + error = false; + } + if(GET_FLAG(value, const) && !GET_FLAG(request, const)) { + gwerr_basic("variable differs in {/}constness{0}", NULL, NULL, + value->from->filename, value->from->loc, 0); + // can we point to the flag? + error = false; + } + if(error) + return true; + gwerr_secondary("from requested variable", request->from->filename, request->from->loc); + return error; +} + +ANN static bool check_trait_variables(const Env env, const Type t, const Trait trait) { + bool error = false; + for(m_uint i = 0; i < vector_size(&trait->requested_values); i++) { + const Value request = (Value)vector_at(&trait->requested_values, i); + if(!request_var(env, t, request)) + error = true; + } + return error; +} + +ANN static bool request_fun(const Env env, const Type t, const Func_Def request) { + const Value v = nspc_lookup_value0(t->nspc, request->base->xid); +if(v) { + if(isa(v->type, env->gwion->type[et_function]) < 0 || is_fptr(env->gwion, v->type)) { + gwerr_basic("is not a function", NULL, NULL, + v->from->filename, v->from->loc, 0); + return false; + } + Func f = v->d.func_ref; + do { + if(compat_func(f->def, request) > 0) { + if(!GET_FLAG(f->def->base, abstract)) + return true; + } + } while ((f = f->next)); +} + if(!GET_FLAG(request->base, abstract)){ + const m_uint scope = env_push_type(env, t); + const Func_Def cpy = cpy_func_def(env->gwion->mp, request); + const m_bool ret = traverse_func_def(env, cpy); + env_pop(env, scope); + if(ret > 0){ + Section *section = new_section_func_def(env->gwion->mp, cpy); + const Ast ast = new_ast(env->gwion->mp, section, NULL); + Ast last = t->info->cdef->body; + while(last->next) + last = last->next; + last->next = ast; + return true; + } else + free_func_def(env->gwion->mp, cpy); + } + if(!v) { + gwerr_basic("missing requested function", NULL, NULL, + env->name, request->base->pos, 0); + return false; + } + return true; +} + +ANN static bool check_trait_functions(const Env env, const Type t, const Trait trait) { + bool error = false; + for(m_uint i = 0; i < vector_size(&trait->requested_funcs); i++) { + const Func_Def request = (Func_Def)vector_at(&trait->requested_funcs, i); + if(!request_fun(env, t, request)) + error = true; + } + return error; +} + +ANN2(1,2,3) static inline bool trait_nodup(Type t, const Symbol trait, ID_List list) { + bool nodup = true; + do { + while(list) { + if(trait == list->xid) +// return false; + nodup = false; + list = list->next; + } + } while ((t = t->info->parent)); + return nodup; +} + +ANN static bool check_trait_requests(const Env env, const Type t, const ID_List list) { + const Trait trait = nspc_lookup_trait1(env->curr, list->xid); + if(!trait_nodup(t, list->xid, list->next)) { + gwerr_secondary("duplicated trait", trait->filename, trait->loc); + return false; + } + const bool value_error = check_trait_variables(env, t, trait); + const bool funcs_error = check_trait_functions(env, t, trait); + if(!value_error && !funcs_error) + return true; + const Value request = (Value)vector_front(&trait->requested_values); + gwerr_secondary("from trait", request->from->filename, trait->loc); + return false; +} + ANN static m_bool _check_class_def(const Env env, const Class_Def cdef) { const Type t = cdef->base.type; if(cdef->base.ext) @@ -1647,6 +1794,21 @@ ANN static m_bool _check_class_def(const Env env, const Class_Def cdef) { } if(!GET_FLAG(cdef, abstract)) CHECK_BB(check_abstract(env, cdef)); + if(cdef->traits) { + ID_List list = cdef->traits; + bool value_error = false; + do if(!check_trait_requests(env, t, list)) + value_error = true; + while((list = list->next)); + + if(value_error) { + env->class_def = t; + env_error_footer(env); + env->context->error = true; + return GW_ERROR; + } + } + Value value; struct scope_iter iter = { t->nspc->info->value, 0, 0 }; while(scope_iter(&iter, &value) > 0) { @@ -1657,11 +1819,10 @@ ANN static m_bool _check_class_def(const Env env, const Class_Def cdef) { struct scope_iter inner = { value->type->nspc->info->value, 0, 0 }; while(scope_iter(&inner, &v) > 0) { if(isa(v->type, t) > 0 || isa(t, v->type) > 0) { -//exit(3); env_err(env, v->from->loc, _("recursive type")); -env->context->error = false; + env->context->error = false; env_err(env, value->from->loc, _("recursive type")); -env->context->error = true; + env->context->error = true; return GW_ERROR; } } diff --git a/src/parse/func_resolve_tmpl.c b/src/parse/func_resolve_tmpl.c index 4059908f..52b74fa0 100644 --- a/src/parse/func_resolve_tmpl.c +++ b/src/parse/func_resolve_tmpl.c @@ -140,13 +140,45 @@ ANN static Func find_tmpl(const Env env, const Value v, Exp_Call *const exp, con return m_func; } -ANN static Func _find_template_match(const Env env, const Value v, Exp_Call *const exp) { +ANN static Func __find_template_match(const Env env, const Value v, Exp_Call *const exp) { DECL_OO(const m_str, tmpl_name, = tl2str(env->gwion, exp->tmpl->call, exp->func->pos)); const Func f = find_tmpl(env, v, exp, tmpl_name); free_mstr(env->gwion->mp, tmpl_name); return f; } +ANN static inline bool has_trait(const Type t, const Symbol trait) { + ID_List list = t->info->traits; + while(list) { + if(list->xid == trait) + return true; + list = list->next; + } + return false; +} + +ANN static inline bool has_traits(const Type t, ID_List traits) { + while(traits) { + if(!has_trait(t, traits->xid)) + return false; + traits = traits->next; + } + return true; +} + +ANN static Func _find_template_match(const Env env, const Value v, Exp_Call *const exp) { + DECL_OO(const Func, f, = __find_template_match(env, v, exp)); + Type_List tl = exp->tmpl->call; + Specialized_List sl = f->def->base->tmpl->list; + while(tl) { + DECL_OO(const Type, t, = known_type(env, tl->td)); + if(!has_traits(t, sl->traits)) + return NULL; + tl = tl->next; + } + return f; +} + ANN static inline m_bool check_call(const Env env, const Exp_Call* exp) { const ae_exp_t et = exp->func->exp_type; if(et != ae_exp_primary && et != ae_exp_dot && et != ae_exp_cast) diff --git a/src/parse/scan0.c b/src/parse/scan0.c index 6da11478..b2ff420d 100644 --- a/src/parse/scan0.c +++ b/src/parse/scan0.c @@ -334,11 +334,21 @@ ANN static Type cdef_parent(const Env env, const Class_Def cdef) { return t ?: (Type)GW_ERROR; } +ANN static m_bool cdef_traits(const Env env, ID_List traits, const loc_t pos) { + do { + if(!nspc_lookup_trait1(env->curr, traits->xid)) + ERR_B(pos, _("can't find trait")); + } while((traits = traits->next)); + return GW_OK; +} + ANN static Type scan0_class_def_init(const Env env, const Class_Def cdef) { CHECK_BO(scan0_defined(env, cdef->base.xid, cdef->pos)); const Type parent = cdef_parent(env, cdef); if(parent == (Type)GW_ERROR) return NULL; + if(cdef->traits) + CHECK_BO(cdef_traits(env, cdef->traits, cdef->pos)); const Type t = scan0_type(env, s_name(cdef->base.xid), parent); if(cflag(cdef, cflag_struct)) { t->size = 0; @@ -437,10 +447,43 @@ ANN static m_bool scan0_extend_def(const Env env, const Extend_Def xdef) { return GW_OK; } +ANN static m_bool _scan0_trait_def(const Env env, const Trait_Def pdef) { + const Trait trait = new_trait(env->gwion->mp, pdef->pos); + trait->loc = pdef->pos; + trait->filename = env->name; + nspc_add_trait(env->curr, pdef->xid, trait); + Ast ast = pdef->body; + while(ast) { + Section * section = ast->section; + if(section->section_type == ae_section_func) { + const Func_Def fdef = section->d.func_def; + if(!trait->requested_funcs.ptr) + vector_init(&trait->requested_funcs); + vector_add(&trait->requested_funcs, (m_uint)fdef); + } + ast = ast->next; + } + return GW_OK; +} + +ANN static m_bool scan0_trait_def(const Env env, const Trait_Def pdef) { + const Symbol s = pdef->xid; + const Trait exists = nspc_lookup_trait1(env->curr, s); + if(exists) { + gwerr_basic("trait already defined", NULL, NULL, env->name, pdef->pos, 0); + gwerr_secondary("defined here", env->name, exists->loc); + env->context->error = true; + return already_defined(env, s, pdef->pos); + } + _scan0_trait_def(env, pdef); + return GW_OK; +} + HANDLE_SECTION_FUNC(scan0, m_bool, Env) ANN static m_bool scan0_class_def_inner(const Env env, const Class_Def cdef) { CHECK_OB((cdef->base.type = scan0_class_def_init(env, cdef))); + cdef->base.type->info->traits = cdef->traits; set_tflag(cdef->base.type, tflag_scan0); (void)mk_class(env, cdef->base.type, cdef->pos); add_type(env, cdef->base.type->info->value->from->owner, cdef->base.type); diff --git a/src/parse/scan1.c b/src/parse/scan1.c index 34d05424..6fff9351 100644 --- a/src/parse/scan1.c +++ b/src/parse/scan1.c @@ -109,9 +109,9 @@ ANN static m_bool scan1_decl(const Env env, const Exp_Decl* decl) { env->class_def->size += t->size; } } - } else - set_vflag(v, vflag_fglobal);// file global - } + } + set_vflag(v, vflag_fglobal);// file global + } else if(GET_FLAG(decl->td, global)) SET_FLAG(v, global); } while((list = list->next)); @@ -410,7 +410,7 @@ ANN static Type scan1_noret(const Env env, const Func_Base *base) { } ANN static m_bool _scan1_fdef_base_tmpl(const Env env, Func_Base *base) { - ID_List id = base->tmpl->list; + Specialized_List id = base->tmpl->list; do nspc_add_type(env->curr, id->xid, env->gwion->type[et_auto]); while((id = id->next)); CHECK_OB((base->ret_type = scan1_noret(env, base))); @@ -641,6 +641,7 @@ ANN static m_bool scan1_extend_def(const Env env, const Extend_Def xdef) { return ret; } +#define scan1_trait_def dummy_func HANDLE_SECTION_FUNC(scan1, m_bool, Env) ANN static Type scan1_get_parent(const Env env, const Type_Def tdef) { diff --git a/src/parse/scan2.c b/src/parse/scan2.c index 1998c93d..f8e70f41 100644 --- a/src/parse/scan2.c +++ b/src/parse/scan2.c @@ -415,7 +415,7 @@ ANN static void scan2_func_def_flag(const Env env, const Func_Def f) { ANN static m_str func_tmpl_name(const Env env, const Func_Def f) { const m_str name = s_name(f->base->xid); struct Vector_ v; - ID_List id = f->base->tmpl->list; + Specialized_List id = f->base->tmpl->list; m_uint tlen = 0; vector_init(&v); do { @@ -547,6 +547,8 @@ ANN static m_bool scan2_extend_def(const Env env, const Extend_Def xdef) { } #define scan2_enum_def dummy_func +#define scan2_trait_def dummy_func + HANDLE_SECTION_FUNC(scan2, m_bool, Env) ANN static m_bool scan2_parent(const Env env, const Class_Def cdef) { diff --git a/src/parse/template.c b/src/parse/template.c index 40144b5e..af92ddee 100644 --- a/src/parse/template.c +++ b/src/parse/template.c @@ -13,7 +13,7 @@ #include "import.h" ANN static m_bool push_types(const Env env, const Tmpl *tmpl) { - ID_List list = tmpl->list; + Specialized_List list = tmpl->list; Type_List call = tmpl->call; do { if(!call) -- 2.43.0