X-Git-Url: http://git.shadowcat.co.uk/gitweb/gitweb.cgi?p=gitmo%2FMouse.git;a=blobdiff_plain;f=xs-src%2FMouse.xs;h=34ba35140a23dd7140daf4b37309ecc6cb10f545;hp=627eabd51e68c51d7713074291cf4185ffcfa7ca;hb=40e57f0af7f9fafe8001b59552a5e18e6e205ae6;hpb=a5c683f611022dcabb13169162fa2f57ba72b200 diff --git a/xs-src/Mouse.xs b/xs-src/Mouse.xs index 627eabd..34ba351 100644 --- a/xs-src/Mouse.xs +++ b/xs-src/Mouse.xs @@ -1,12 +1,14 @@ #define NEED_newSVpvn_flags_GLOBAL #include "mouse.h" +/* keywords for methods/keys */ SV* mouse_package; SV* mouse_namespace; SV* mouse_methods; SV* mouse_name; SV* mouse_get_attribute; SV* mouse_get_attribute_list; +SV* mouse_coerce; #define MOUSE_xc_flags(a) SvUVX(MOUSE_av_at((a), MOUSE_XC_FLAGS)) #define MOUSE_xc_gen(a) MOUSE_av_at((a), MOUSE_XC_GEN) @@ -150,7 +152,7 @@ mouse_class_update_xc(pTHX_ SV* const metaclass PERL_UNUSED_DECL, HV* const stas sv_setuv(MOUSE_xc_gen(xc), mro_get_pkg_gen(stash)); } -AV* +static AV* mouse_get_xc(pTHX_ SV* const metaclass) { AV* xc; SV* gen; @@ -202,7 +204,7 @@ mouse_get_xc(pTHX_ SV* const metaclass) { return xc; } -HV* +static HV* mouse_buildargs(pTHX_ SV* metaclass, SV* const klass, I32 ax, I32 items) { HV* args; @@ -237,7 +239,7 @@ mouse_buildargs(pTHX_ SV* metaclass, SV* const klass, I32 ax, I32 items) { return args; } -void +static void mouse_class_initialize_object(pTHX_ SV* const meta, SV* const object, HV* const args, bool const ignore_triggers) { AV* const xc = mouse_get_xc(aTHX_ meta); AV* const attrs = MOUSE_xc_attrall(xc); @@ -249,16 +251,17 @@ mouse_class_initialize_object(pTHX_ SV* const meta, SV* const object, HV* const assert(args); assert(SvTYPE(args) == SVt_PVHV); - ENTER; - SAVETMPS; + if(mg_find((SV*)args, PERL_MAGIC_tied)){ + croak("You cannot use tied HASH reference as initializing arguments"); + } if(!ignore_triggers){ triggers_queue = newAV_mortal(); } for(i = 0; i < len; i++){ - SV* const attr = AvARRAY(attrs)[i]; - AV* const xa = mouse_get_xa(aTHX_ AvARRAY(attrs)[i]); + SV* const attr = MOUSE_av_at(attrs, i); + AV* const xa = mouse_get_xa(aTHX_ attr); SV* const slot = MOUSE_xa_slot(xa); U16 const flags = (U16)MOUSE_xa_flags(xa); @@ -270,7 +273,7 @@ mouse_class_initialize_object(pTHX_ SV* const meta, SV* const object, HV* const if(flags & MOUSEf_ATTR_HAS_TC){ value = mouse_xa_apply_type_constraint(aTHX_ xa, value, flags); } - set_slot(object, slot, value); + value = set_slot(object, slot, value); if(SvROK(value) && flags & MOUSEf_ATTR_IS_WEAK_REF){ weaken_slot(object, slot); } @@ -306,11 +309,9 @@ mouse_class_initialize_object(pTHX_ SV* const meta, SV* const object, HV* const } if(MOUSE_xc_flags(xc) & MOUSEf_XC_IS_ANON){ - set_slot(object, newSVpvs_flags("__ANON__", SVs_TEMP), meta); + (void)set_slot(object, newSVpvs_flags("__METACLASS__", SVs_TEMP), meta); } - FREETMPS; - LEAVE; } static SV* @@ -335,6 +336,29 @@ mouse_initialize_metaclass(pTHX_ SV* const klass) { return meta; } +static void +mouse_buildall(pTHX_ AV* const xc, SV* const object, SV* const args) { + AV* const buildall = MOUSE_xc_buildall(xc); + I32 const len = AvFILLp(buildall) + 1; + I32 i; + for(i = 0; i < len; i++){ + dSP; + + PUSHMARK(SP); + EXTEND(SP, 2); + PUSHs(object); + PUSHs(args); + PUTBACK; + + call_sv(AvARRAY(buildall)[i], G_VOID); + + /* discard a scalar which G_VOID returns */ + SPAGAIN; + (void)POPs; + PUTBACK; + } +} + MODULE = Mouse PACKAGE = Mouse PROTOTYPES: DISABLE @@ -344,6 +368,7 @@ BOOT: mouse_namespace = newSVpvs_share("namespace"); mouse_methods = newSVpvs_share("methods"); mouse_name = newSVpvs_share("name"); + mouse_coerce = newSVpvs_share("coerce"); mouse_get_attribute = newSVpvs_share("get_attribute"); mouse_get_attribute_list = newSVpvs_share("get_attribute_list"); @@ -403,8 +428,8 @@ CODE: SV* sv = code_ref; /* used in tryAMAGICunDEREF */ SV** sp = &sv; /* used in tryAMAGICunDEREF */ tryAMAGICunDEREF(to_cv); /* try \&{$code} */ - if(SvROK(sv) && SvTYPE(SvRV(sv)) == SVt_PVCV){ - mouse_throw_error(self, NULL, "Not a CODE reference"); + if(!(SvROK(sv) && SvTYPE(SvRV(sv)) == SVt_PVCV)){ + mouse_throw_error(self, NULL, "You must pass a CODE reference to add_method"); } code_ref = sv; } @@ -417,16 +442,36 @@ CODE: } sv_setsv_mg((SV*)gv, code_ref); /* *gv = $code_ref */ - set_slot(methods, name, code); /* $self->{methods}{$name} = $code */ - - /* TODO: name the CODE ref if it's anonymous */ - //code_entity = (CV*)SvRV(code_ref); - //if(CvANON(code_entity) - // && CvGV(code_entity) /* a cv under construction has no gv */ ){ + (void)set_slot(methods, name, code); /* $self->{methods}{$name} = $code */ + + /* name the CODE ref if it's anonymous */ + { + CV* const code_entity = (CV*)SvRV(code_ref); + if(CvANON(code_entity) + && CvGV(code_entity) /* a cv under construction has no gv */ ){ + HV* dbsub; + + /* update %DB::sub to make NYTProf happy */ + if((PL_perldb & (PERLDBf_SUBLINE|PERLDB_NAMEANON)) + && PL_DBsub && (dbsub = GvHV(PL_DBsub)) + ){ + /* see Perl_newATTRSUB() in op.c */ + SV* const subname = sv_newmortal(); + HE* orig; + + gv_efullname3(subname, CvGV(code_entity), NULL); + orig = hv_fetch_ent(dbsub, subname, FALSE, 0U); + if(orig){ + gv_efullname3(subname, gv, NULL); + (void)hv_store_ent(dbsub, subname, HeVAL(orig), 0U); + SvREFCNT_inc_simple_void_NN(HeVAL(orig)); + } + } - // CvGV(code_entity) = gv; - // CvANON_off(code_entity); - //} + CvGV(code_entity) = gv; + CvANON_off(code_entity); + } + } } MODULE = Mouse PACKAGE = Mouse::Meta::Class @@ -434,11 +479,12 @@ MODULE = Mouse PACKAGE = Mouse::Meta::Class BOOT: INSTALL_SIMPLE_READER(Class, roles); INSTALL_SIMPLE_PREDICATE_WITH_KEY(Class, is_anon_class, anon_serial_id); - newCONSTSUB(gv_stashpvs("Mouse::Meta::Class", TRUE), "constructor_class", - newSVpvs("Mouse::Meta::Method::Constructor::XS")); - newCONSTSUB(gv_stashpvs("Mouse::Meta::Class", TRUE), "destructor_class", - newSVpvs("Mouse::Meta::Method::Destructor::XS")); + INSTALL_SIMPLE_READER(Class, is_immutable); + INSTALL_CLASS_HOLDER(Class, method_metaclass, "Mouse::Meta::Method"); + INSTALL_CLASS_HOLDER(Class, attribute_metaclass, "Mouse::Meta::Attribute"); + INSTALL_CLASS_HOLDER(Class, constructor_class, "Mouse::Meta::Method::Constructor::XS"); + INSTALL_CLASS_HOLDER(Class, destructor_class, "Mouse::Meta::Method::Destructor::XS"); newCONSTSUB(gv_stashpvs("Mouse::Meta::Method::Constructor::XS", TRUE), "_generate_constructor", newRV_inc((SV*)get_cvs("Mouse::Object::new", TRUE))); @@ -470,7 +516,7 @@ get_all_attributes(SV* self) PPCODE: { AV* const xc = mouse_get_xc(aTHX_ self); - AV* const all_attrs = MOUSE_xc_attrall(xc); + AV* const all_attrs = MOUSE_xc_attrall(xc); I32 const len = AvFILLp(all_attrs) + 1; I32 i; @@ -481,7 +527,7 @@ PPCODE: } SV* -new_object_(SV* meta, ...) +new_object(SV* meta, ...) CODE: { AV* const xc = mouse_get_xc(aTHX_ meta); @@ -490,7 +536,8 @@ CODE: RETVAL = mouse_instance_create(aTHX_ MOUSE_xc_stash(xc)); mouse_class_initialize_object(aTHX_ meta, RETVAL, args, FALSE); } - +OUTPUT: + RETVAL void _initialize_object(SV* meta, SV* object, HV* args, bool ignore_triggers = FALSE) @@ -499,22 +546,14 @@ CODE: mouse_class_initialize_object(aTHX_ meta, object, args, ignore_triggers); } -void -__xc(SV* meta) -PPCODE: -{ - AV* const xc = mouse_get_xc(aTHX_ meta); - mXPUSHu(MOUSE_xc_flags(xc)); - mXPUSHs(newRV_inc((SV*)MOUSE_xc_buildall(xc))); - mXPUSHs(newRV_inc((SV*)MOUSE_xc_demolishall(xc))); -} - MODULE = Mouse PACKAGE = Mouse::Meta::Role BOOT: INSTALL_SIMPLE_READER_WITH_KEY(Role, get_roles, roles); INSTALL_SIMPLE_PREDICATE_WITH_KEY(Role, is_anon_role, anon_serial_id); + INSTALL_CLASS_HOLDER(Role, method_metaclass, "Mouse::Meta::Role::Method"); + MODULE = Mouse PACKAGE = Mouse::Object SV* @@ -525,11 +564,10 @@ CODE: AV* const xc = mouse_get_xc(aTHX_ meta); UV const flags = MOUSE_xc_flags(xc); SV* args; - AV* buildall; - I32 len, i; /* BUILDARGS */ if(flags & MOUSEf_XC_HAS_BUILDARGS){ + I32 i; SPAGAIN; PUSHMARK(SP); @@ -557,26 +595,16 @@ CODE: RETVAL = mouse_instance_create(aTHX_ MOUSE_xc_stash(xc)); mouse_class_initialize_object(aTHX_ meta, RETVAL, (HV*)SvRV(args), FALSE); - /* BUILDALL */ - buildall = MOUSE_xc_buildall(xc); - len = AvFILLp(buildall) + 1; - for(i = 0; i < len; i++){ - dSP; - - PUSHMARK(SP); - EXTEND(SP, 2); - PUSHs(RETVAL); - PUSHs(args); - PUTBACK; - - call_sv(AvARRAY(buildall)[i], G_VOID | G_DISCARD); - } + mouse_buildall(aTHX_ xc, RETVAL, args); } OUTPUT: RETVAL void DESTROY(SV* object) +ALIAS: + DESTROY = 0 + DEMOLISHALL = 1 CODE: { SV* const meta = get_metaclass(object); @@ -584,7 +612,8 @@ CODE: I32 len, i; if(!IsObject(object)){ - croak("You must not call DESTROY as a class method"); + croak("You must not call %s as a class method", + ix == 0 ? "DESTROY" : "DEMOLISHALL"); } if(SvOK(meta)){ @@ -592,7 +621,7 @@ CODE: demolishall = MOUSE_xc_demolishall(xc); } - else { + else { /* The metaclass is already destroyed */ AV* const linearized_isa = mro_get_linear_isa(SvSTASH(SvRV(object))); len = AvFILLp(linearized_isa) + 1; @@ -608,24 +637,29 @@ CODE: } } - /* DEMOLISHALL */ len = AvFILLp(demolishall) + 1; if(len > 0){ GV* const statusvalue = gv_fetchpvs("?", 0, SVt_PV); SAVESPTR(GvSV(statusvalue)); /* local $? */ SAVESPTR(ERRSV); /* local $@ */ - GvSV(statusvalue) = sv_2mortal(newSViv(0)); - ERRSV = sv_2mortal(newSVpvs("")); + GvSV(statusvalue) = sv_newmortal(); + ERRSV = newSVpvs_flags("", SVs_TEMP); for(i = 0; i < len; i++){ - dSP; + SPAGAIN; PUSHMARK(SP); XPUSHs(object); PUTBACK; - call_sv(AvARRAY(demolishall)[i], G_VOID | G_DISCARD | G_EVAL); - if(SvTRUE(ERRSV)){ + call_sv(AvARRAY(demolishall)[i], G_VOID | G_EVAL); + + /* discard a scalar which G_VOID returns */ + SPAGAIN; + (void)POPs; + PUTBACK; + + if(sv_true(ERRSV)){ SV* const e = newSVsv(ERRSV); FREETMPS; @@ -649,3 +683,15 @@ OUTPUT: RETVAL +void +BUILDALL(SV* self, SV* args) +CODE: +{ + SV* const meta = get_metaclass(self); + AV* const xc = mouse_get_xc(aTHX_ meta); + + if(!IsHashRef(args)){ + croak("You must pass a HASH reference to BUILDALL"); + } + mouse_buildall(aTHX_ xc, self, args); +}