X-Git-Url: http://git.shadowcat.co.uk/gitweb/gitweb.cgi?p=gitmo%2FMouse.git;a=blobdiff_plain;f=xs-src%2FMouse.xs;h=137e5a04b6d3301a4491f59092098232023300af;hp=c4ba5f14796e036f38ba96d6ef2725148e049b63;hb=4b55a023c6fe98b7a512956836d4f114b192b2f5;hpb=3ea28db6c35f2f60bfcce151cb4fcee58d6edcf7 diff --git a/xs-src/Mouse.xs b/xs-src/Mouse.xs index c4ba5f1..137e5a0 100644 --- a/xs-src/Mouse.xs +++ b/xs-src/Mouse.xs @@ -2,6 +2,8 @@ SV* mouse_package; SV* mouse_namespace; +SV* mouse_methods; +SV* mouse_name; MODULE = Mouse PACKAGE = Mouse::Util @@ -10,10 +12,14 @@ PROTOTYPES: DISABLE BOOT: mouse_package = newSVpvs_share("package"); mouse_namespace = newSVpvs_share("namespace"); + mouse_methods = newSVpvs_share("methods"); + mouse_name = newSVpvs_share("name"); + + MOUSE_CALL_BOOT(Mouse__Util__TypeConstraints); bool -is_class_loaded(SV* sv = &PL_sv_undef) +is_class_loaded(SV* sv) void get_code_info(CV* code) @@ -80,36 +86,45 @@ CODE: OUTPUT: RETVAL +void +generate_isa_predicate_for(SV* klass, const char* predicate_name = NULL) +PPCODE: +{ + STRLEN klass_len; + const char* klass_pv; + HV* stash; + CV* xsub; -MODULE = Mouse PACKAGE = Mouse::Util::TypeConstraints + if(!SvOK(klass)){ + croak("You must define a class name for generate_for"); + } + klass_pv = SvPV_const(klass, klass_len); + klass_pv = mouse_canonicalize_package_name(klass_pv); -void -Item(SV* sv = &PL_sv_undef) -ALIAS: - Any = MOUSE_TC_ANY - Item = MOUSE_TC_ITEM - Undef = MOUSE_TC_UNDEF - Defined = MOUSE_TC_DEFINED - Bool = MOUSE_TC_BOOL - Value = MOUSE_TC_VALUE - Ref = MOUSE_TC_REF - Str = MOUSE_TC_STR - Num = MOUSE_TC_NUM - Int = MOUSE_TC_INT - ScalarRef = MOUSE_TC_SCALAR_REF - ArrayRef = MOUSE_TC_ARRAY_REF - HashRef = MOUSE_TC_HASH_REF - CodeRef = MOUSE_TC_CODE_REF - GlobRef = MOUSE_TC_GLOB_REF - FileHandle = MOUSE_TC_FILEHANDLE - RegexpRef = MOUSE_TC_REGEXP_REF - Object = MOUSE_TC_OBJECT - ClassName = MOUSE_TC_CLASS_NAME - RoleName = MOUSE_TC_ROLE_NAME -CODE: - SvGETMAGIC(sv); - ST(0) = boolSV( mouse_tc_check(aTHX_ ix, sv) ); - XSRETURN(1); + if(strNE(klass_pv, "UNIVERSAL")){ + static MGVTBL mouse_util_type_constraints_vtbl; /* not used, only for identity */ + + xsub = newXS(predicate_name, XS_isa_check, __FILE__); + + stash = gv_stashpvn(klass_pv, klass_len, GV_ADD); + + CvXSUBANY(xsub).any_ptr = sv_magicext( + (SV*)xsub, + (SV*)stash, /* mg_obj */ + PERL_MAGIC_ext, + &mouse_util_type_constraints_vtbl, + klass_pv, /* mg_ptr */ + klass_len /* mg_len */ + ); + } + else{ + xsub = newXS(predicate_name, XS_isa_check_for_universal, __FILE__); + } + + if(predicate_name == NULL){ /* anonymous predicate */ + XPUSHs( newRV_noinc((SV*)xsub) ); + } +} MODULE = Mouse PACKAGE = Mouse::Meta::Module @@ -125,13 +140,68 @@ CODE: { SV* const package = mouse_instance_get_slot(aTHX_ self, mouse_package); if(!(package && SvOK(package))){ - croak("No package name"); + croak("No package name defined"); } RETVAL = gv_stashsv(package, GV_ADDMULTI); } OUTPUT: RETVAL +# ignore extra arguments for extensibility +void +add_method(SV* self, SV* name, SV* code, ...) +CODE: +{ + SV* const package = mouse_instance_get_slot(aTHX_ self, mouse_package); /* $self->{package} */ + SV* const methods = mouse_instance_get_slot(aTHX_ self, mouse_methods); /* $self->{methods} */ + GV* gv; + SV* code_ref; + + if(!(package && SvOK(package))){ + croak("No package name defined"); + } + + SvGETMAGIC(name); + SvGETMAGIC(code); + + if(!SvOK(name)){ + mouse_throw_error(self, NULL, "You must define a method name"); + } + if(!SvROK(code)){ + mouse_throw_error(self, NULL, "You must define a CODE reference"); + } + + code_ref = code; + if(SvTYPE(SvRV(code_ref)) != SVt_PVCV){ + 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"); + } + code_ref = sv; + } + + /* *{$package . '::' . $name} -> *gv */ + gv = gv_fetchpv(form("%"SVf"::%"SVf, package, name), GV_ADDMULTI, SVt_PVCV); + if(GvCVu(gv)){ /* delete *slot{gv} to work around "redefine" warning */ + SvREFCNT_dec(GvCV(gv)); + GvCV(gv) = NULL; + } + sv_setsv_mg((SV*)gv, code_ref); /* *gv = $code_ref */ + + mouse_instance_set_slot(aTHX_ 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 */ ){ + + // CvGV(code_entity) = gv; + // CvANON_off(code_entity); + //} +} + MODULE = Mouse PACKAGE = Mouse::Meta::Class BOOT: @@ -222,12 +292,6 @@ BOOT: MODULE = Mouse PACKAGE = Mouse::Meta::Method::Accessor::XS -BOOT: -{ - AV* const isa = get_av("Mouse::Meta::Method::Accessor::XS::ISA", TRUE); - av_push(isa, newSVpvs("Mouse::Meta::Method::Accessor")); -} - CV* _generate_accessor(klass, SV* attr, metaclass) CODE: