X-Git-Url: http://git.shadowcat.co.uk/gitweb/gitweb.cgi?a=blobdiff_plain;f=MOP.xs;h=942b3785ba471fb55bd1d6e9c8e9c4ed4f06fbf4;hb=da88f307a9f54e4fef38bf1d7354cdb4d137c451;hp=9f2476b19fe10bacfcb1a4e5e22ba1b77e36f7dd;hpb=b0e94057a140745127762c40aac6dde669dad74e;p=gitmo%2FClass-MOP.git diff --git a/MOP.xs b/MOP.xs index 9f2476b..942b378 100644 --- a/MOP.xs +++ b/MOP.xs @@ -2,13 +2,24 @@ #include "EXTERN.h" #include "perl.h" #include "XSUB.h" + +#define NEED_sv_2pv_flags +#define NEED_sv_2pv_nolen #include "ppport.h" -/* -check_method_cache_flag: - check the PL_sub_generation - ISA/method cache thing +SV *key_name; +U32 hash_name; + +SV *key_package; +U32 hash_package; + +SV *key_package_name; +U32 hash_package_name; + +SV *key_body; +U32 hash_body; +/* get_code_info: Pass in a coderef, returns: [ $pkg_name, $coderef_name ] ie: @@ -17,12 +28,20 @@ get_code_info: MODULE = Class::MOP PACKAGE = Class::MOP -SV* -check_package_cache_flag() - CODE: - RETVAL = newSViv(PL_sub_generation); - OUTPUT: - RETVAL +BOOT: + key_name = newSVpvs("name"); + key_body = newSVpvs("body"); + key_package = newSVpvs("package"); + key_package_name = newSVpvs("package_name"); + + PERL_HASH(hash_name, "name", 4); + PERL_HASH(hash_body, "body", 4); + PERL_HASH(hash_package, "package", 7); + PERL_HASH(hash_package_name, "package_name", 12); + + +PROTOTYPES: ENABLE + void get_code_info(coderef) @@ -31,14 +50,186 @@ get_code_info(coderef) char* name; char* pkg; PPCODE: - if( SvOK(coderef) && SvROK(coderef) && SvTYPE(SvRV(coderef)) == SVt_PVCV){ coderef = SvRV(coderef); - name = GvNAME( CvGV(coderef) ); - pkg = HvNAME( GvSTASH(CvGV(coderef)) ); + /* I think this only gets triggered with a mangled coderef, but if + we hit it without the guard, we segfault. The slightly odd return + value strikes me as an improvement (mst) + */ +#ifdef isGV_with_GP + if ( isGV_with_GP(CvGV(coderef))) { +#endif + pkg = HvNAME( GvSTASH(CvGV(coderef)) ); + name = GvNAME( CvGV(coderef) ); +#ifdef isGV_with_GP + } else { + pkg = "__UNKNOWN__"; + name = "__ANON__"; + } +#endif EXTEND(SP, 2); PUSHs(newSVpvn(pkg, strlen(pkg))); PUSHs(newSVpvn(name, strlen(name))); } + +MODULE = Class::MOP PACKAGE = Class::MOP::Package + +void +get_all_package_symbols(self, ...) + SV *self + PROTOTYPE: $;$ + PREINIT: + HV *stash = NULL; + SV *type_filter = NULL; + register HE *he; + PPCODE: + + switch ( GIMME_V ) { + case G_VOID: return; break; + case G_SCALAR: ST(0) = &PL_sv_undef; return; break; + } + + if ( items > 1 ) type_filter = ST(1); + + PUTBACK; + + if (SvROK(self) && (he = hv_fetch_ent((HV *)SvRV(self), key_package, 0, hash_package))) + stash = gv_stashsv(HeVAL(he),0); + + if ( stash ) { + + (void)hv_iterinit(stash); + + if ( type_filter && SvPOK(type_filter) ) { + const char *const type = SvPV_nolen(type_filter); + + while ((he = hv_iternext(stash))) { + SV *const gv = HeVAL(he); + SV *sv; + char *key; + STRLEN keylen; + char *package; + SV *fq; + + switch( SvTYPE(gv) ) { + case SVt_PVGV: + switch (*type) { + case 'C': sv = (SV *)GvCVu(gv); break; /* CODE */ + case 'A': sv = (SV *)GvAV(gv); break; /* ARRAY */ + case 'I': sv = (SV *)GvIO(gv); break; /* IO */ + case 'H': sv = (SV *)GvHV(gv); break; /* HASH */ + case 'S': sv = (SV *)GvSV(gv); break; /* SCALAR */ + default: + croak("Unknown type %s\n", type); + } + break; + case SVt_RV: + /* BAH! constants are horrible */ + + /* we don't really care about the length, + but that's the API */ + key = HePV(he, keylen); + package = HvNAME(stash); + fq = newSVpvf("%s::%s", package, key); + sv = sv_2mortal((SV*)get_cv(SvPV_nolen(fq), 0)); + break; + default: + continue; + } + + if ( sv ) { + SV *key = hv_iterkeysv(he); + SPAGAIN; + EXTEND(SP, 2); + PUSHs(key); + PUSHs(sv_2mortal(newRV_inc(sv))); + PUTBACK; + } + } + } else { + EXTEND(SP, HvKEYS(stash) * 2); + + while ((he = hv_iternext(stash))) { + SV *key = hv_iterkeysv(he); + SV *sv = HeVAL(he); + SPAGAIN; + PUSHs(key); + PUSHs(sv); + PUTBACK; + } + } + + } + +SV * +name(self) + SV *self + PREINIT: + register HE *he; + PPCODE: + if (SvROK(self) && (he = hv_fetch_ent((HV *)SvRV(self), key_package, 0, hash_package))) + XPUSHs(HeVAL(he)); + else + ST(0) = &PL_sv_undef; + +MODULE = Class::MOP PACKAGE = Class::MOP::Attribute + +SV * +name(self) + SV *self + PREINIT: + register HE *he; + PPCODE: + if (SvROK(self) && (he = hv_fetch_ent((HV *)SvRV(self), key_name, 0, hash_name))) + XPUSHs(HeVAL(he)); + else + ST(0) = &PL_sv_undef; + +MODULE = Class::MOP PACKAGE = Class::MOP::Method + +SV * +name(self) + SV *self + PREINIT: + register HE *he; + PPCODE: + if (! SvROK(self)) { + die("Cannot call name as a class method"); + } + + if (he = hv_fetch_ent((HV *)SvRV(self), key_name, 0, hash_name)) + XPUSHs(HeVAL(he)); + else + ST(0) = &PL_sv_undef; + +SV * +package_name(self) + SV *self + PREINIT: + register HE *he; + PPCODE: + if (! SvROK(self)) { + die("Cannot call package_name as a class method"); + } + + if (he = hv_fetch_ent((HV *)SvRV(self), key_package_name, 0, hash_package_name)) + XPUSHs(HeVAL(he)); + else + ST(0) = &PL_sv_undef; + +SV * +body(self) + SV *self + PREINIT: + register HE *he; + PPCODE: + if (! SvROK(self)) { + die("Cannot call body as a class method"); + } + + if (he = hv_fetch_ent((HV *)SvRV(self), key_body, 0, hash_body)) + XPUSHs(HeVAL(he)); + else + ST(0) = &PL_sv_undef;