From 9dd2ff1b23291c2473febf3b44b436df2130057a Mon Sep 17 00:00:00 2001 From: fennecdjay Date: Mon, 24 Oct 2022 00:35:00 +0200 Subject: [PATCH] :art: Improve ctors --- include/emit.h | 10 --------- include/parse.h | 10 +++++++++ src/emit/emit.c | 5 ++--- src/env/value.c | 1 - src/lib/deep_equal.c | 4 ---- src/lib/object_op.c | 48 +++++++++++++++++--------------------------- src/parse/check.c | 34 +++++++++++++++++++++++++++++++ src/parse/scan1.c | 1 + src/vm/vm.c | 7 +++---- 9 files changed, 68 insertions(+), 52 deletions(-) diff --git a/include/emit.h b/include/emit.h index 942f67d4..32fdd692 100644 --- a/include/emit.h +++ b/include/emit.h @@ -95,16 +95,6 @@ ANN static inline Instr emit_compound_addref(const Emitter emit, const Type t, : emit_struct_addref(emit, t, size, emit_var); } -ANN static inline bool is_static_call(const Emitter emit, const Exp e) { - if (e->exp_type != ae_exp_dot) return true; - const Exp_Dot *member = &e->d.exp_dot; - return GET_FLAG(e->type, final) || - GET_FLAG(member->base->type, final) || - is_class(emit->gwion, member->base->type) || -// GET_FLAG(e->type->info->func, static) || - member->base->exp_type == ae_exp_cast; -} - ANN Instr emit_kind(Emitter, const m_uint size, const bool addr, const f_instr func[]); ANN Instr emit_regpushimm(Emitter, const m_uint, const bool); diff --git a/include/parse.h b/include/parse.h index bc2964aa..1041c265 100644 --- a/include/parse.h +++ b/include/parse.h @@ -123,4 +123,14 @@ ANN static inline bool not_upvalue(const Env env, const Value v) { } ANN m_bool abstract_array(const Env env, const Array_Sub array); + +ANN static inline bool is_static_call(const Gwion gwion, const Exp e) { + if (e->exp_type != ae_exp_dot) return true; + const Exp_Dot *member = &e->d.exp_dot; + if(unlikely(!strcmp(s_name(member->xid), "new"))) return true; + return GET_FLAG(e->type, final) || + GET_FLAG(member->base->type, final) || + is_class(gwion, member->base->type) || + member->base->exp_type == ae_exp_cast; +} #endif diff --git a/src/emit/emit.c b/src/emit/emit.c index f0f8883e..a3d78ade 100644 --- a/src/emit/emit.c +++ b/src/emit/emit.c @@ -1358,7 +1358,7 @@ ANN static m_bool _emit_exp_call(const Emitter emit, const Exp_Call *exp_call) { CHECK_BB(emit_func_args(emit, exp_call)); if (is_func(emit->gwion, t)) // is_callable needs type CHECK_BB(emit_exp_call1(emit, t->info->func, - is_static_call(emit, exp_call->func))); + is_static_call(emit->gwion, exp_call->func))); else { struct Op_Import opi = {.op = insert_symbol("@ctor"), .rhs = t, @@ -1659,8 +1659,7 @@ ANN static void call_finish(const Emitter emit, const Func f, const m_uint offset = emit_code_offset(emit); if (f != emit->env->func || !is_static || strcmp(s_name(f->def->base->xid), "new")) regseti(emit, offset); - const bool _is_static = !strcmp(s_name(f->def->base->xid), "new") ? true : is_static; - const Instr instr = emit_call(emit, f, _is_static); + const Instr instr = emit_call(emit, f, is_static); instr->m_val = f->def->base->ret_type->size; instr->m_val2 = offset; } diff --git a/src/env/value.c b/src/env/value.c index ef8f4165..0c06360d 100644 --- a/src/env/value.c +++ b/src/env/value.c @@ -4,7 +4,6 @@ #include "vm.h" #include "gwion.h" -#define MAX(a, b) (a >= b ? a : b) ANN void free_value(Value a, Gwion gwion) { const Type t = a->type; if (t->size > SZ_INT && !vflag(a, vflag_func) && a->d.ptr) diff --git a/src/lib/deep_equal.c b/src/lib/deep_equal.c index 5857500e..343c702a 100644 --- a/src/lib/deep_equal.c +++ b/src/lib/deep_equal.c @@ -212,10 +212,6 @@ ANN static bool deep_emit(const Emitter emit, struct DeepEmits *ds) { struct Exp_ rexp = MK_DOT(emit, ds->rhs->tmp, rhs); struct Exp_ temp = MK_BIN(lexp, rexp, ds->bin); temp.type=emit->gwion->type[et_bool]; - if(tflag(lexp.type, tflag_struct)) - exp_setvar(&lexp, true); - if(tflag(rexp.type, tflag_struct)) - exp_setvar(&rexp, true); if(emit_exp(emit, &temp) < 0) return false; vector_add(&ds->acc, (m_uint)emit_add_instr(emit, BranchEqInt)); } diff --git a/src/lib/object_op.c b/src/lib/object_op.c index bb9b219f..a42dad6b 100644 --- a/src/lib/object_op.c +++ b/src/lib/object_op.c @@ -1,3 +1,4 @@ + #include "gwion_util.h" #include "gwion_ast.h" #include "gwion_env.h" @@ -147,17 +148,13 @@ ANN static void emit_member_func(const Emitter emit, const Exp_Dot *member) { instr->m_val = (m_uint)f; return; } - } else if (is_static_call(emit, exp_self(member))) { + } else if (is_static_call(emit->gwion, exp_self(member))) { if (member->is_call && f == emit->env->func && strcmp(s_name(f->def->base->xid), "new")) return; const Instr func_i = emit_add_instr(emit, f->code ? RegPushImm : SetFunc); func_i->m_val = (m_uint)f->code ?: (m_uint)f; return; } else { if (tflag(member->base->type, tflag_struct)) { - if (!GET_FLAG(f->def->base, static)) { - exp_setvar(member->base, 1); - emit_exp(emit, member->base); - } const Instr func_i = emit_add_instr(emit, f->code ? RegPushImm : SetFunc); func_i->m_val = (m_uint)f->code ?: (m_uint)f; return; @@ -229,12 +226,6 @@ OP_CHECK(opck_object_dot) { _("keyword 'this' must be associated with object instance...")); const Value value = get_value(env, member, the_base); if (!value) { -/* - if(env->class_def != the_base && tflag(the_base, tflag_cdef) && !tflag(the_base, tflag_check)) - CHECK_BN(ensure_traverse(env, the_base)); - return check_exp(env, exp_self(member)); - } -*/ const Value v = nspc_lookup_value1(env->curr, member->xid); if(v) { if (member->is_call) { @@ -242,14 +233,19 @@ OP_CHECK(opck_object_dot) { return v->type; if (is_class(env->gwion, v->type)) { DECL_OO(const Type, parent, = class_type(env, member, v->type)); - // allow only direct parent or smth? - // mark the function as ctor_ok if (isa(the_base, parent) > 0 && parent->nspc) { const Symbol sym = insert_symbol(env->gwion->st, "new"); + if(!env->func || env->func->def->base->xid != sym) + ERR_N(exp_self(member)->pos, "calling a parent constructor is only allowed in `new` definition"); + // is this + if(member->base->exp_type != ae_exp_primary || + member->base->d.prim.prim_type != ae_prim_id || + strcmp(s_name(member->base->d.prim.d.var), "this")) + ERR_N(exp_self(member)->pos, "calling a parent constructor is only allowed with `this`"); + SET_FLAG(env->func, const); // mark the function as ctor_ok const Value ret = nspc_lookup_value1(parent->nspc, sym); member->xid = sym; - if(ret) - return ret->type; + if(ret) return ret->type; } } } else if(is_class(env->gwion, v->type) && the_base == v->type->info->base_type) @@ -275,7 +271,6 @@ OP_CHECK(opck_object_dot) { ERR_N(exp_self(member)->pos, _("cannot access member '%s.%s' without object instance..."), the_base->name, str); -// if current function is a constructor if (GET_FLAG(value, const)) exp_setmeta(exp_self(member), 1); exp_self(member)->acquire = 1; return value->type; @@ -288,7 +283,6 @@ ANN static Type member_type(const Gwion gwion, const Type base) { OP_EMIT(opem_object_dot) { const Exp_Dot *member = (Exp_Dot *)data; -// const Type t_base = actual_type(emit->gwion, member->base->type); const Type t_base = member_type(emit->gwion, member->base->type); const Value value = find_value(t_base, member->xid); if(!tflag(t_base, tflag_emit) /*&& emit->env->class_def != t_base*/) { @@ -299,23 +293,24 @@ OP_EMIT(opem_object_dot) { instr->m_val = (m_uint)value->type; return GW_OK; } + if (tflag(t_base, tflag_struct) && !GET_FLAG(value, static)) { + exp_setvar(member->base, true); + CHECK_BB(emit_exp(emit, member->base)); + } if (!is_class(emit->gwion, member->base->type) && (vflag(value, vflag_member) || (is_func(emit->gwion, exp_self(member)->type)))) { - if (!tflag(t_base, tflag_struct) && vflag(value, vflag_member)) + if (!tflag(t_base, tflag_struct)) CHECK_BB(emit_exp(emit, member->base)); } - if (is_func(emit->gwion, exp_self(member)->type) && // is_func + if (is_func(emit->gwion, exp_self(member)->type) && !fflag(exp_self(member)->type->info->func, fflag_fptr)) emit_member_func(emit, member); else if (vflag(value, vflag_member)) { if (!tflag(t_base, tflag_struct)) emit_member(emit, value, exp_getvar(exp_self(member))); - else { - exp_setvar(member->base, 1); - CHECK_BB(emit_exp(emit, member->base)); + else emit_struct_data(emit, value, exp_getvar(exp_self(member))); - } } else if (GET_FLAG(value, static)) emit_dot_static_import_data(emit, value, exp_getvar(exp_self(member))); else { // member type @@ -387,14 +382,7 @@ ANN Type scan_class(const Env env, const Type t, const Type_Decl *td) { CHECK_BO(envset_pushv(&es, t->info->value)); const bool local = !owner && !tmpl_global(env, td->types) && from_global_nspc(env, env->curr); if(local && env->context) env_push(env, NULL, env->context->nspc); - // these context and env command may fit better somewhere else -// const m_str env_filename = env->name; -// const m_str ctx_filename = env->context->name; -// env->name = t->info->value->from->filename; -// env->context->name = t->info->value->from->ctx->name; const Type ret = _scan_class(env, &info); -// env->name = env_filename; -// env->context->name = ctx_filename; if(local && env->context)env_pop(env, es.scope); envset_pop(&es, owner); return ret; diff --git a/src/parse/check.c b/src/parse/check.c index 68756d4f..1fea7125 100644 --- a/src/parse/check.c +++ b/src/parse/check.c @@ -952,10 +952,24 @@ ANN Type _check_exp_call1(const Env env, Exp_Call *const exp) { return NULL; } +ANN static Type check_static(const Env env, const Exp e) { + const Type t = e->type; + if(unlikely(!is_func(env->gwion, t)) || + !t->info->func || + !GET_FLAG(t->info->func->def->base, abstract) || + !is_static_call(env->gwion, e)) return t; + env_err(env, e->pos, "making a static call to an abstract function"); + env->context->error = false; + gwerr_secondary_from("declared here", t->info->value->from); + env->context->error = true; + return NULL; +} + ANN Type check_exp_call1(const Env env, Exp_Call *const exp) { DECL_BO(const m_bool, ret, = func_check(env, exp)); if (!ret) return exp_self(exp)->type; const Type t = exp->func->type; + CHECK_OO(check_static(env, exp->func)); const Type _ret = _check_exp_call1(env, exp); if(_ret) return _ret; if(isa(exp->func->type, env->gwion->type[et_closure]) > 0) { @@ -1856,11 +1870,31 @@ ANN m_bool _check_func_def(const Env env, const Func_Def f) { return ret; } +ANN m_bool check_new(const Env env, const Func_Def fdef) { + if(!fdef->builtin && !GET_FLAG(fdef->base->func, const) && + GET_FLAG(env->class_def->info->parent, abstract)) { + // we can probably do simpler, but this may require fixing new@ index + const Value v = nspc_lookup_value0(env->class_def->info->parent->nspc, fdef->base->xid); + if(v) { + Func f = v->d.func_ref; + while(f) { + if(compat_func(fdef, f->def)) break; + f = f->next; + } + if(f && GET_FLAG(f, abstract)) ERR_B(fdef->base->pos, "What what?"); + } + } + return GW_OK; +} + ANN m_bool check_func_def(const Env env, const Func_Def fdef) { const uint16_t depth = env->scope->depth; env->scope->depth = 0; const m_bool ret = _check_func_def(env, fdef); env->scope->depth = depth; + // we need to find matching parent and see if abstract + if(!strcmp(s_name(fdef->base->xid), "new")) + CHECK_BB(check_new(env, fdef)); return ret; } diff --git a/src/parse/scan1.c b/src/parse/scan1.c index 0129144f..1a5f3208 100644 --- a/src/parse/scan1.c +++ b/src/parse/scan1.c @@ -724,6 +724,7 @@ ANN static m_bool scan1_parent(const Env env, const Class_Def cdef) { !(tflag(cdef->base.type, tflag_cdef) || tflag(cdef->base.type, tflag_udef))) ERR_B(pos, _("cannot extend primitive type '%s'"), parent->name) if (type_ref(parent)) ERR_B(pos, _("can't use ref type in class extend")) + if (GET_FLAG(parent, abstract)) SET_FLAG(cdef->base.type, abstract); return GW_OK; } diff --git a/src/vm/vm.c b/src/vm/vm.c index 94925406..5f44ab9e 100644 --- a/src/vm/vm.c +++ b/src/vm/vm.c @@ -1195,7 +1195,7 @@ vm_prepare(const VM *vm, m_bit *prepare_code) { // lgtm [cpp/use-of-goto] reg += VAL2; DISPATCH() dotfunc: - *(VM_Code *)(reg + (m_uint)VAL2) = + *(VM_Code *)(reg + IVAL2) = ((Func)(*(M_Object *)(reg - SZ_INT))->type_ref->nspc->vtable.ptr[OFFSET + VAL])->code; DISPATCH() gacktype : { @@ -1207,9 +1207,8 @@ vm_prepare(const VM *vm, m_bit *prepare_code) { // lgtm [cpp/use-of-goto] m_str str = *(m_str *)(reg - SZ_INT); if (!VAL) { gw_out("%s\n", str); -fflush(stdout); -} - else + fflush(stdout); + } else *(M_Object *)(reg - SZ_INT) = new_string(vm->gwion, str); if (str) mp_free2(vm->gwion->mp, strlen(str), str); DISPATCH(); -- 2.43.0