From cc29e3de02cfa64be92770f558f804205de96238 Mon Sep 17 00:00:00 2001 From: =?utf8?q?J=C3=A9r=C3=A9mie=20Astor?= Date: Sat, 17 Jul 2021 20:44:59 +0200 Subject: [PATCH] :art: Constructors --- ast | 2 +- fmt | 2 +- src/clean.c | 4 +++- src/emit/emit.c | 2 ++ src/lib/opfunc.c | 25 +++++++++++++++++++------ src/parse/check.c | 3 ++- src/parse/scan2.c | 5 +++++ tests/ctor/ctor_outside.gw | 5 +++++ tests/ctor/ctor_overload.gw | 14 ++++++++++++++ 9 files changed, 52 insertions(+), 10 deletions(-) create mode 100644 tests/ctor/ctor_outside.gw create mode 100644 tests/ctor/ctor_overload.gw diff --git a/ast b/ast index 7492fddf..68044023 160000 --- a/ast +++ b/ast @@ -1 +1 @@ -Subproject commit 7492fddf76bd861aea16e16f6cc66ac257c3c647 +Subproject commit 68044023ce834c80ff2992487835b91e139a467c diff --git a/fmt b/fmt index d78297aa..30bff4e9 160000 --- a/fmt +++ b/fmt @@ -1 +1 @@ -Subproject commit d78297aacc14071b97ae22e47f9e1c06054c15de +Subproject commit 30bff4e9845b15c3af3f8caee300134a4d6fbd27 diff --git a/src/clean.c b/src/clean.c index fb4dee1a..3adaf1d9 100644 --- a/src/clean.c +++ b/src/clean.c @@ -75,7 +75,9 @@ ANN static void clean_exp_unary(Clean *a, Exp_Unary *b) { clean_exp(a, b->exp); break; case unary_td: - clean_type_decl(a, b->td); + clean_type_decl(a, b->ctor.td); + if(b->ctor.exp) + clean_exp(a, b->ctor.exp); break; case unary_code: clean_stmt(a, b->code); diff --git a/src/emit/emit.c b/src/emit/emit.c index d2da9115..5f9091c6 100644 --- a/src/emit/emit.c +++ b/src/emit/emit.c @@ -2560,6 +2560,8 @@ ANN static VM_Code emit_internal(const Emitter emit, const Func f) { ANN static inline VM_Code _emit_func_def_code(const Emitter emit, const Func func) { + if(!strcmp(s_name(func->def->base->xid), "new")) + emit_add_instr(emit, RegPushMem); return !fbflag(func->def->base, fbflag_internal) ? finalyze(emit, FuncReturn) : emit_internal(emit, func); } diff --git a/src/lib/opfunc.c b/src/lib/opfunc.c index 195bb2b9..ac3c17f9 100644 --- a/src/lib/opfunc.c +++ b/src/lib/opfunc.c @@ -97,23 +97,36 @@ OP_CHECK(opck_post) { ANN Type check_td(const Env env, Type_Decl *td); OP_CHECK(opck_new) { - const Exp_Unary *unary = (Exp_Unary *)data; - DECL_ON(const Type, t, = known_type(env, unary->td)); + Exp_Unary *unary = (Exp_Unary *)data; + DECL_ON(const Type, t, = known_type(env, unary->ctor.td)); + if(unary->ctor.exp) { + const Exp self = exp_self(unary); + const Exp args = unary->ctor.exp; + const Exp base = new_exp_unary2(env->gwion->mp, unary->op, unary->ctor.td, NULL, self->pos); + const Exp func = new_exp_dot(env->gwion->mp, base, insert_symbol("new"), self->pos); + self->d.exp_call.func = func; + self->d.exp_call.args = args; + self->d.exp_call.tmpl = NULL; + self->exp_type = ae_exp_call; + CHECK_BN(traverse_exp(env, self)); + return self->type; +// unarytype + } if (isa(t, env->gwion->type[et_object]) < 0) ERR_N(exp_self(unary)->pos, _("can't use 'new' on non-object types...\n")); if (type_ref(t)) - ERR_N(unary->td->pos, _("can't use 'new' on ref type '%s'\n"), t->name); + ERR_N(unary->ctor.td->pos, _("can't use 'new' on ref type '%s'\n"), t->name); if (GET_FLAG(t, abstract)) - ERR_N(unary->td->pos, _("can't use 'new' on abstract type '%s'\n"), + ERR_N(unary->ctor.td->pos, _("can't use 'new' on abstract type '%s'\n"), t->name); - if (unary->td->array) CHECK_BN(check_subscripts(env, unary->td->array, 1)); + if (unary->ctor.td->array) CHECK_BN(check_subscripts(env, unary->ctor.td->array, 1)); return t; } OP_EMIT(opem_new) { const Exp_Unary *unary = (Exp_Unary *)data; CHECK_BB(emit_instantiate_object(emit, exp_self(unary)->type, - unary->td->array, 0)); + unary->ctor.td->array, 0)); emit_gc(emit, -SZ_INT); return GW_OK; } diff --git a/src/parse/check.c b/src/parse/check.c index fbe06144..58952baa 100644 --- a/src/parse/check.c +++ b/src/parse/check.c @@ -1551,7 +1551,8 @@ ANN m_bool check_fdef(const Env env, const Func_Def fdef) { CHECK_BB(check_stmt_code(env, &fdef->d.code->d.stmt_code)); env->scope->depth++; } - if (fdef->base->ret_type && + // check fdef->base->td for `new` + if (fdef->base->td && fdef->base->ret_type && fdef->base->ret_type != env->gwion->type[et_void] && fdef->d.code && !fflag(fdef->base->func, fflag_return)) ERR_B(fdef->base->td->pos, diff --git a/src/parse/scan2.c b/src/parse/scan2.c index 1350c178..3d78ffa0 100644 --- a/src/parse/scan2.c +++ b/src/parse/scan2.c @@ -546,6 +546,11 @@ 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(!strcmp(s_name(fdef->base->xid), "new")) { + if(!env->class_def) + ERR_B(fdef->base->pos, _("{G-}new{0} operator must be set inside {C+}class{0}")); + fdef->base->ret_type = env->class_def; + } 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/ctor/ctor_outside.gw b/tests/ctor/ctor_outside.gw new file mode 100644 index 00000000..a7343cd2 --- /dev/null +++ b/tests/ctor/ctor_outside.gw @@ -0,0 +1,5 @@ +#! [contains] new operator must be set inside class +var int i; +operator new(int arg) { + arg => i; +} diff --git a/tests/ctor/ctor_overload.gw b/tests/ctor/ctor_overload.gw new file mode 100644 index 00000000..3e22ad4a --- /dev/null +++ b/tests/ctor/ctor_overload.gw @@ -0,0 +1,14 @@ +#! [contains] 42 +class C { + var int i; + operator new(int arg) { + arg => i; + } + operator new() {} +} + +new C() => var auto c; +new C(2) => var auto d; +<<< "c:${c.i}, d:${d.i}" >>>; + +<<< "the answer: ${(new C(42)).i}" >>>; -- 2.43.0