X-Git-Url: http://git.shadowcat.co.uk/gitweb/gitweb.cgi?p=gitmo%2FMouse.git;a=blobdiff_plain;f=xs-src%2FMouseTypeConstraints.xs;h=e5b2c2107d32c503cb6cc78a74b90a9c4095b2a3;hp=6f0fe6cb3736ebd1768e0e0b61564c902f2a5a68;hb=6582d0e35a9937aa8869d868f10172935f48e1ce;hpb=619338ac4245c7c523d67645d6cd51cb982d4841 diff --git a/xs-src/MouseTypeConstraints.xs b/xs-src/MouseTypeConstraints.xs index 6f0fe6c..e5b2c21 100644 --- a/xs-src/MouseTypeConstraints.xs +++ b/xs-src/MouseTypeConstraints.xs @@ -19,26 +19,20 @@ typedef int (*check_fptr_t)(pTHX_ SV* const data, SV* const sv); int mouse_tc_check(pTHX_ SV* const tc_code, SV* const sv) { CV* const cv = (CV*)SvRV(tc_code); - assert(SvTYPE(cv) == Svt_PVCV); + assert(SvTYPE(cv) == SVt_PVCV); - if(CvISXSUB(cv)){ /* can be built-in tc */ - if(CvXSUB(cv) == XS_Mouse__Util__TypeConstraints_Item){ - assert(CvXSUBANY(cv).any_iv > 0); - - return mouse_builtin_tc_check(aTHX_ CvXSUBANY(cv).any_iv, sv); - } - else if(CvXSUB(cv) == XS_Mouse_parameterized_check){ - MAGIC* const mg = (MAGIC*)CvXSUBANY(cv).any_ptr; + if(CvXSUB(cv) == XS_Mouse__Util__TypeConstraints_Item){ /* built-in */ + return mouse_builtin_tc_check(aTHX_ CvXSUBANY(cv).any_iv, sv); + } + else if(CvXSUB(cv) == XS_Mouse_parameterized_check){ /* complex type constraints */ + MAGIC* const mg = (MAGIC*)CvXSUBANY(cv).any_ptr; - assert(CvXSUBANY(cv).any_ptr != NULL); + assert(CvXSUBANY(cv).any_ptr != NULL); - /* call the check function directly, skipping call_sv() */ - return CALL_FPTR((check_fptr_t)mg->mg_ptr)(aTHX_ mg->mg_obj, sv); - } + /* call the check function directly, skipping call_sv() */ + return CALL_FPTR((check_fptr_t)mg->mg_ptr)(aTHX_ mg->mg_obj, sv); } - - /* user-defined type constraints */ - { + else { /* custom */ int ok; dSP; @@ -67,6 +61,7 @@ mouse_builtin_tc_check(pTHX_ mouse_tc const tc, SV* const sv) { switch(tc){ case MOUSE_TC_ANY: return mouse_tc_Any(aTHX_ sv); case MOUSE_TC_ITEM: return mouse_tc_Any(aTHX_ sv); + case MOUSE_TC_MAYBE: return mouse_tc_Any(aTHX_ sv); case MOUSE_TC_UNDEF: return mouse_tc_Undef(aTHX_ sv); case MOUSE_TC_DEFINED: return mouse_tc_Defined(aTHX_ sv); case MOUSE_TC_BOOL: return mouse_tc_Bool(aTHX_ sv); @@ -282,7 +277,7 @@ mouse_tc_Object(pTHX_ SV* const sv) { /* Parameterized type constraints */ -int +static int mouse_parameterized_ArrayRef(pTHX_ SV* const param, SV* const sv) { if(mouse_tc_ArrayRef(aTHX_ sv)){ AV* const av = (AV*)SvRV(sv); @@ -300,7 +295,7 @@ mouse_parameterized_ArrayRef(pTHX_ SV* const param, SV* const sv) { return FALSE; } -int +static int mouse_parameterized_HashRef(pTHX_ SV* const param, SV* const sv) { if(mouse_tc_HashRef(aTHX_ sv)){ HV* const hv = (HV*)SvRV(sv); @@ -319,7 +314,7 @@ mouse_parameterized_HashRef(pTHX_ SV* const param, SV* const sv) { return FALSE; } -int +static int mouse_parameterized_Maybe(pTHX_ SV* const param, SV* const sv) { if(SvOK(sv)){ return mouse_tc_check(aTHX_ param, sv); @@ -327,6 +322,41 @@ mouse_parameterized_Maybe(pTHX_ SV* const param, SV* const sv) { return TRUE; } +static int +mouse_types_union_check(pTHX_ AV* const types, SV* const sv) { + I32 const len = AvFILLp(types) + 1; + I32 i; + + for(i = 0; i < len; i++){ + if(mouse_tc_check(aTHX_ AvARRAY(types)[i], sv)){ + return TRUE; + } + } + + return FALSE; +} + +static int +mouse_types_check(pTHX_ AV* const types, SV* const sv) { + I32 const len = AvFILLp(types) + 1; + I32 i; + + ENTER; + SAVE_DEFSV; + DEFSV_set(sv); + + for(i = 0; i < len; i++){ + if(!mouse_tc_check(aTHX_ AvARRAY(types)[i], sv)){ + LEAVE; + return FALSE; + } + } + + LEAVE; + + return TRUE; +} + /* * This class_type generator is taken from Scalar::Util::Instance */ @@ -572,3 +602,85 @@ CODE: OUTPUT: RETVAL +MODULE = Mouse::Util::TypeConstraints PACKAGE = Mouse::Meta::TypeConstraint + +void +compile_type_constraint(SV* self) +CODE: +{ + AV* const checks = newAV(); + SV* check; /* check function */ + SV* parent; + SV* types_ref; + + sv_2mortal((SV*)checks); + + for(parent = get_slots(self, "parent"); parent; parent = get_slots(parent, "parent")){ + check = get_slots(parent, "hand_optimized_type_constraint"); + if(check && SvOK(check)){ + if(!mouse_tc_CodeRef(aTHX_ check)){ + croak("Not a CODE reference"); + } + av_unshift(checks, 1); + av_store(checks, 0, newSVsv(check)); + break; /* a hand optimized constraint must include all the parent */ + } + + check = get_slots(parent, "constraint"); + if(check && SvOK(check)){ + if(!mouse_tc_CodeRef(aTHX_ check)){ + croak("Not a CODE reference"); + } + av_unshift(checks, 1); + av_store(checks, 0, newSVsv(check)); + } + } + + check = get_slots(self, "constraint"); + if(check && SvOK(check)){ + if(!mouse_tc_CodeRef(aTHX_ check)){ + croak("Not a CODE reference"); + } + av_push(checks, newSVsv(check)); + } + + types_ref = get_slots(self, "type_constraints"); + if(types_ref && SvOK(types_ref)){ /* union type */ + AV* types; + AV* union_checks; + CV* union_check; + I32 len; + I32 i; + + if(!mouse_tc_ArrayRef(aTHX_ types_ref)){ + croak("Not an ARRAY reference"); + } + types = (AV*)SvRV(types_ref); + len = av_len(types) + 1; + + union_checks = newAV(); + sv_2mortal((SV*)union_checks); + + for(i = 0; i < len; i++){ + SV* const tc = *av_fetch(types, i, TRUE); + SV* const c = get_slots(tc, "compiled_type_constraint"); + if(!(c && mouse_tc_CodeRef(aTHX_ c))){ + sv_dump(self); + croak("'%"SVf"' has no compiled type constraint", self); + } + av_push(union_checks, newSVsv(c)); + } + + union_check = mouse_tc_parameterize(aTHX_ NULL, (check_fptr_t)mouse_types_union_check, (SV*)union_checks); + av_push(checks, newRV_inc((SV*)union_check)); + } + + if(AvFILLp(checks) < 0){ + check = newRV_inc((SV*)get_cv("Mouse::Util::TypeConstraints::Any", TRUE)); + } + else{ + check = newRV_inc((SV*)mouse_tc_parameterize(aTHX_ NULL, (check_fptr_t)mouse_types_check, (SV*)checks)); + } + set_slots(self, "compiled_type_constraint", check); +} +