#define IsHashRef(sv) (SvROK(sv) && !SvOBJECT(SvRV(sv)) && SvTYPE(SvRV(sv)) == SVt_PVHV)
#define IsCodeRef(sv) (SvROK(sv) && !SvOBJECT(SvRV(sv)) && SvTYPE(SvRV(sv)) == SVt_PVCV)
-#define mcall0(invocant, m) mouse_call0(aTHX_ (invocant), (m))
-#define mcall1(invocant, m, arg1) mouse_call1(aTHX_ (invocant), (m), (arg1))
-#define mcall0s(invocant, m) mcall0((invocant), sv_2mortal(newSVpvs_share(m)))
-#define mcall1s(invocant, m, arg1) mcall1((invocant), sv_2mortal(newSVpvs_share(m)), (arg1))
+#define mcall0(invocant, m) mouse_call0(aTHX_ (invocant), (m))
+#define mcall1(invocant, m, arg1) mouse_call1(aTHX_ (invocant), (m), (arg1))
+#define predicate_call(invocant, m) mouse_predicate_call(aTHX_ (invocant), (m))
+
+#define mcall0s(invocant, m) mcall0((invocant), sv_2mortal(newSVpvs_share(m)))
+#define mcall1s(invocant, m, arg1) mcall1((invocant), sv_2mortal(newSVpvs_share(m)), (arg1))
+#define predicate_calls(invocant, m) predicate_call((invocant), sv_2mortal(newSVpvs_share(m)))
+
#define get_metaclass(name) mouse_get_metaclass(aTHX_ name)
SV* mouse_call0(pTHX_ SV *const self, SV *const method);
SV* mouse_call1(pTHX_ SV *const self, SV *const method, SV* const arg1);
+int mouse_predicate_call(pTHX_ SV* const self, SV* const method);
SV* mouse_get_metaclass(pTHX_ SV* metaclass_name);
XS(XS_Mouse_constraint_check);
+/* Mouse XS Attribute object */
+
+AV* mouse_get_xa(pTHX_ SV* const attr);
+
+enum mouse_xa_ix_t{
+ MOUSE_XA_SLOT, /* for constructors, sync to mg_obj */
+ MOUSE_XA_FLAGS, /* for constructors, sync to mg_private */
+ MOUSE_XA_ATTRIBUTE,
+ MOUSE_XA_TC,
+ MOUSE_XA_TC_CODE,
+
+ MOUSE_XA_last
+};
+
+#define MOUSE_xa_slot(m) MOUSE_av_at(m, MOUSE_XA_SLOT)
+#define MOUSE_xa_flags(m) MOUSE_av_at(m, MOUSE_XA_FLAGS)
+#define MOUSE_xa_attribute(m) MOUSE_av_at(m, MOUSE_XA_ATTRIBUTE)
+#define MOUSE_xa_tc(m) MOUSE_av_at(m, MOUSE_XA_TC)
+#define MOUSE_xa_tc_code(m) MOUSE_av_at(m, MOUSE_XA_TC_CODE)
+
+
+enum mouse_xa_flags_t{
+ MOUSEf_ATTR_HAS_TC = 0x0001,
+ MOUSEf_ATTR_HAS_DEFAULT = 0x0002,
+ MOUSEf_ATTR_HAS_BUILDER = 0x0004,
+ MOUSEf_ATTR_HAS_INITIALIZER = 0x0008,
+ MOUSEf_ATTR_HAS_TRIGGER = 0x0010,
+
+ MOUSEf_ATTR_IS_LAZY = 0x0020,
+ MOUSEf_ATTR_IS_WEAK_REF = 0x0040,
+ MOUSEf_ATTR_IS_REQUIRED = 0x0080,
+
+ MOUSEf_ATTR_SHOULD_COERCE = 0x0100,
+
+ MOUSEf_ATTR_SHOULD_AUTO_DEREF
+ = 0x0200,
+ MOUSEf_TC_IS_ARRAYREF = 0x0400,
+ MOUSEf_TC_IS_HASHREF = 0x0800,
+
+ MOUSEf_OTHER1 = 0x1000,
+ MOUSEf_OTHER2 = 0x2000,
+ MOUSEf_OTHER3 = 0x4000,
+ MOUSEf_OTHER4 = 0x8000,
+
+ MOUSEf_MOUSE_MASK = 0xFFFF /* not used */
+};
+
+
#endif /* !MOUSE_H */
XS(XS_Mouse__Object_BUILDARGS); /* prototype */
GV* const buildargs = gv_fetchmeth_autoload(stash, "BUILDARGS", sizeof("BUILDARGS")-1, 0);
- CV* const cv = GvCV(buildargs);
- assert(cv);
- return CvXSUB(cv) == XS_Mouse__Object_BUILDARGS;
+ return buildargs && CvXSUB(GvCV(buildargs)) == XS_Mouse__Object_BUILDARGS;
}
static void
return xc;
}
-AV*
-mouse_get_all_attributes(pTHX_ SV* const metaclass) {
- AV* const xc = mouse_get_xc(aTHX_ metaclass);
- return MOUSE_xc_attrall(xc);
-}
-
HV*
-mouse_build_args(aTHX_ SV* metaclass, SV* const klass, I32 const start, I32 const items, I32 const ax) {
+mouse_build_args(pTHX_ SV* metaclass, SV* const klass, I32 const start, I32 const items, I32 const ax) {
HV* args;
if((items - start) == 1){
SV* const args_ref = ST(start);
AV* const attrs = MOUSE_xc_attrall(xc);
I32 const len = AvFILLp(attrs) + 1;
I32 i;
- AV* const triggers_queue = (invoke_triggers ? newAV_mortal() : NULL);
+ AV* const triggers_queue = (ignore_triggers ? NULL : newAV_mortal());
+
for(i = 0; i < len; i++){
- AV* const = mouse_get_xa(aTHX_ AvARRAY(attrs)[i]);
+ AV* const xa = mouse_get_xa(aTHX_ AvARRAY(attrs)[i]);
}
}
get_all_attributes(SV* self)
PPCODE:
{
- AV* const all_attrs = mouse_get_all_attributes(aTHX_ self);
+ AV* const xc = mouse_get_xc(aTHX_ self);
+ AV* const all_attrs = MOUSE_xc_attrall(xc);
I32 const len = AvFILLp(all_attrs) + 1;
I32 i;
} \
} STMT_END
-/* Mouse XS Attribute object */
-enum mouse_xa_ix_t{
- MOUSE_XA_SLOT, /* for constructors, sync to mg_obj */
- MOUSE_XA_FLAGS, /* for constructors, sync to mg_private */
- MOUSE_XA_ATTRIBUTE,
- MOUSE_XA_TC,
- MOUSE_XA_TC_CODE,
-
- MOUSE_XA_last
-};
-
-#define MOUSE_xa_attribute(m) MOUSE_av_at(m, MOUSE_XA_ATTRIBUTE)
-#define MOUSE_xa_tc(m) MOUSE_av_at(m, MOUSE_XA_TC)
-#define MOUSE_xa_tc_code(m) MOUSE_av_at(m, MOUSE_XA_TC_CODE)
#define MOUSE_mg_attribute(mg) MOUSE_xa_attribute(MOUSE_mg_xa(mg))
-enum mouse_xa_flags_t{
- MOUSEf_ATTR_HAS_TC = 0x0001,
- MOUSEf_ATTR_HAS_DEFAULT = 0x0002,
- MOUSEf_ATTR_HAS_BUILDER = 0x0004,
- MOUSEf_ATTR_HAS_INITIALIZER = 0x0008,
- MOUSEf_ATTR_HAS_TRIGGER = 0x0010,
-
- MOUSEf_ATTR_IS_LAZY = 0x0020,
- MOUSEf_ATTR_IS_WEAK_REF = 0x0040,
- MOUSEf_ATTR_IS_REQUIRED = 0x0080,
-
- MOUSEf_ATTR_SHOULD_COERCE = 0x0100,
-
- MOUSEf_ATTR_SHOULD_AUTO_DEREF
- = 0x0200,
- MOUSEf_TC_IS_ARRAYREF = 0x0400,
- MOUSEf_TC_IS_HASHREF = 0x0800,
-
- MOUSEf_OTHER1 = 0x1000,
- MOUSEf_OTHER2 = 0x2000,
- MOUSEf_OTHER3 = 0x4000,
- MOUSEf_OTHER4 = 0x8000,
-
- MOUSEf_MOUSE_MASK = 0xFFFF /* not used */
-};
-
static MGVTBL mouse_accessor_vtbl; /* MAGIC identity */
CV*
mouse_instantiate_xs_accessor(pTHX_ SV* const attr, XSUBADDR_t const accessor_impl){
- SV* const slot = mcall0(attr, mouse_name);
- AV* const xa = newAV();
+ AV* const xa = mouse_get_xa(aTHX_ attr);
CV* xsub;
MAGIC* mg;
- U16 flags = 0;
-
- sv_2mortal((SV*)xa);
xsub = newXS(NULL, accessor_impl, __FILE__);
sv_2mortal((SV*)xsub);
- mg = sv_magicext((SV*)xsub, slot, PERL_MAGIC_ext, &mouse_accessor_vtbl, (char*)xa, HEf_SVKEY);
+ mg = sv_magicext((SV*)xsub, MOUSE_xa_slot(xa), PERL_MAGIC_ext, &mouse_accessor_vtbl, (char*)xa, HEf_SVKEY);
+
+ MOUSE_mg_flags(mg) = (U16)SvUV(MOUSE_xa_flags(xa));
/* NOTE:
* although we use MAGIC for gc, we also store mg to CvXSUBANY for efficiency (gfx)
*/
CvXSUBANY(xsub).any_ptr = (void*)mg;
- av_extend(xa, MOUSE_XA_last - 1);
-
- av_store(xa, MOUSE_XA_ATTRIBUTE, newSVsv(attr));
-
- /* prepare attribute status */
- /* XXX: making it lazy is a good way? */
-
- if(SvTRUEx(mcall0s(attr, "has_type_constraint"))){
- SV* tc;
- flags |= MOUSEf_ATTR_HAS_TC;
-
- ENTER;
- SAVETMPS;
-
- tc = mcall0s(attr, "type_constraint");
- av_store(xa, MOUSE_XA_TC, newSVsv(tc));
-
- if(SvTRUEx(mcall0s(attr, "should_auto_deref"))){
- flags |= MOUSEf_ATTR_SHOULD_AUTO_DEREF;
- if( SvTRUEx(mcall1s(tc, "is_a_type_of", newSVpvs_flags("ArrayRef", SVs_TEMP))) ){
- flags |= MOUSEf_TC_IS_ARRAYREF;
- }
- else if( SvTRUEx(mcall1s(tc, "is_a_type_of", newSVpvs_flags("HashRef", SVs_TEMP))) ){
- flags |= MOUSEf_TC_IS_HASHREF;
- }
- else{
- mouse_throw_error(attr, tc,
- "Can not auto de-reference the type constraint '%"SVf"'",
- mcall0(tc, mouse_name));
- }
- }
-
- if(SvTRUEx(mcall0s(attr, "should_coerce"))){
- flags |= MOUSEf_ATTR_SHOULD_COERCE;
- }
-
- FREETMPS;
- LEAVE;
- }
-
- if(SvTRUEx(mcall0s(attr, "has_trigger"))){
- flags |= MOUSEf_ATTR_HAS_TRIGGER;
- }
-
- if(SvTRUEx(mcall0s(attr, "is_lazy"))){
- flags |= MOUSEf_ATTR_IS_LAZY;
-
- if(SvTRUEx(mcall0s(attr, "has_builder"))){
- flags |= MOUSEf_ATTR_HAS_BUILDER;
- }
- else if(SvTRUEx(mcall0s(attr, "has_default"))){
- flags |= MOUSEf_ATTR_HAS_DEFAULT;
- }
- }
-
- if(SvTRUEx(mcall0s(attr, "is_weak_ref"))){
- flags |= MOUSEf_ATTR_IS_WEAK_REF;
- }
-
- if(SvTRUEx(mcall0s(attr, "is_required"))){
- flags |= MOUSEf_ATTR_IS_REQUIRED;
- }
-
- MOUSE_mg_flags(mg) = flags;
-
return xsub;
}
-#define NEED_newSVpvn_flags_GLOBAL
#include "mouse.h"
+
+AV*
+mouse_get_xa(pTHX_ SV* const attr) {
+ static MGVTBL mouse_xa_vtbl; /* identity */
+
+ AV* xa;
+ MAGIC* mg;
+
+ if(!IsObject(attr)){
+ croak("Not a Mouse meta attribute");
+ }
+
+ mg = mouse_mg_find(aTHX_ SvRV(attr), &mouse_xa_vtbl, 0x00);
+ if(!mg){
+ SV* slot;
+ STRLEN len;
+ const char* pv;
+ U16 flags = 0x00;
+
+ ENTER;
+ SAVETMPS;
+
+ xa = newAV();
+
+ mg = sv_magicext(SvRV(attr), (SV*)xa, PERL_MAGIC_ext, &mouse_xa_vtbl,NULL, 0);
+ SvREFCNT_dec(xa); /* refcnt++ in sv_magicext */
+
+ av_extend(xa, MOUSE_XA_last - 1);
+
+ slot = mcall0(attr, mouse_name);
+ pv = SvPV_const(slot, len);
+ av_store(xa, MOUSE_XA_SLOT, newSVpvn_share(pv, len, 0U));
+
+ av_store(xa, MOUSE_XA_ATTRIBUTE, newSVsv(attr));
+
+ if(predicate_calls(attr, "has_type_constraint")){
+ SV* tc;
+ flags |= MOUSEf_ATTR_HAS_TC;
+
+ tc = mcall0s(attr, "type_constraint");
+ av_store(xa, MOUSE_XA_TC, newSVsv(tc));
+
+ if(predicate_calls(attr, "should_auto_deref")){
+ SV* const is_a_type_of = sv_2mortal(newSVpvs_share("is_a_type_of"));
+
+ flags |= MOUSEf_ATTR_SHOULD_AUTO_DEREF;
+ if( SvTRUEx(mcall1(tc, is_a_type_of, newSVpvs_flags("ArrayRef", SVs_TEMP))) ){
+ flags |= MOUSEf_TC_IS_ARRAYREF;
+ }
+ else if( SvTRUEx(mcall1(tc, is_a_type_of, newSVpvs_flags("HashRef", SVs_TEMP))) ){
+ flags |= MOUSEf_TC_IS_HASHREF;
+ }
+ else{
+ mouse_throw_error(attr, tc,
+ "Can not auto de-reference the type constraint '%"SVf"'",
+ mcall0(tc, mouse_name));
+ }
+ }
+
+ if(predicate_calls(attr, "should_coerce")){
+ flags |= MOUSEf_ATTR_SHOULD_COERCE;
+ }
+
+ }
+
+ if(predicate_calls(attr, "has_trigger")){
+ flags |= MOUSEf_ATTR_HAS_TRIGGER;
+ }
+
+ if(predicate_calls(attr, "is_lazy")){
+ flags |= MOUSEf_ATTR_IS_LAZY;
+
+ if(predicate_calls(attr, "has_builder")){
+ flags |= MOUSEf_ATTR_HAS_BUILDER;
+ }
+ else if(predicate_calls(attr, "has_default")){
+ flags |= MOUSEf_ATTR_HAS_DEFAULT;
+ }
+ }
+
+ if(predicate_calls(attr, "is_weak_ref")){
+ flags |= MOUSEf_ATTR_IS_WEAK_REF;
+ }
+
+ if(predicate_calls(attr, "is_required")){
+ flags |= MOUSEf_ATTR_IS_REQUIRED;
+ }
+
+ av_store(xa, MOUSE_XA_FLAGS, newSVuv(flags));
+ MOUSE_mg_flags(mg) = flags;
+
+ FREETMPS;
+ LEAVE;
+ }
+ else{
+ xa = (AV*)MOUSE_mg_obj(mg);
+
+ assert(xa);
+ assert(SvTYPE(xa) == SVt_PVAV);
+ }
+
+ return xa;
+}
+
+
MODULE = Mouse::Meta::Attribute PACKAGE = Mouse::Meta::Attribute
PROTOTYPES: DISABLE
}
-SV *
-mouse_call0 (pTHX_ SV *const self, SV *const method)
-{
+SV*
+mouse_call0 (pTHX_ SV* const self, SV* const method) {
dSP;
SV *ret;
return ret;
}
-SV *
-mouse_call1 (pTHX_ SV *const self, SV *const method, SV* const arg1)
-{
+SV*
+mouse_call1 (pTHX_ SV* const self, SV* const method, SV* const arg1) {
dSP;
SV *ret;
return ret;
}
+int
+mouse_predicate_call(pTHX_ SV* const self, SV* const method) {
+ SV* const value = mcall0(self, method);
+ return SvTRUE(value);
+}
+
SV*
mouse_get_metaclass(pTHX_ SV* metaclass_name){
CV* const get_metaclass = get_cvs("Mouse::Util::get_metaclass_by_name", TRUE);