X-Git-Url: http://git.shadowcat.co.uk/gitweb/gitweb.cgi?a=blobdiff_plain;f=Moose.xs;h=f5d4b57dbab09bbf27a644c02fea6f4fb83654de;hb=6011a844b8baffe83df9862755efd5f61be1d2cd;hp=e30b35e49c4565433a8121d6317e07a2d392a27e;hpb=0be3b17fbf10b94affa54a7d557b831b8d6ea849;p=gitmo%2FMoose.git diff --git a/Moose.xs b/Moose.xs index e30b35e..f5d4b57 100644 --- a/Moose.xs +++ b/Moose.xs @@ -16,24 +16,6 @@ #endif /* FIXME - * type constraints are already implemented by konobi - * should be trivial to do coercions for the core types, too - * - * TypeConstraint::Class can compare SvSTASH by ptr, and if it's neq *then* - * call ->isa (should handle vast majority of cases) - * - * base parametrized types are also trivial - * - * ClassName is get_stathpvn - */ - -/* FIXME - * for a constructor we have ATTR *attrs, and iterate that, removing init_arg - * we can preallocate the structure to the right size (maybe even with the - * right HEs?), and do various other prehashing hacks to gain speed - * */ - -/* FIXME * delegations and attribute helpers: * * typedef struct { @@ -128,18 +110,16 @@ typedef union { typedef union { char *builder; - SV *value; - CV *sub; + SV *sv; OP *op; U32 type; } DEFAULT; typedef enum { default_none = 0, - default_type, + default_normal, default_builder, - default_value, - default_sub, + default_type, default_op, } default_kind; @@ -170,11 +150,12 @@ typedef struct { * 00000000 00000000 00000000 00000000 * ^ trigger * ^ weak - * ^ tc refcnt + * ^ tc.sv is refcounted * ^^^ tc_kind * ^ coerce * ^^^ default_kind * ^ lazy + * ^ def.sv is refcounted * ^ required * ^^^^^^^ if 0 then nothing special (just hash)? FIXME TBD */ @@ -186,9 +167,10 @@ typedef struct { #define ATTR_MASK_TYPE 0x7 #define ATTR_MASK_DEFAULT 0x700 -#define ATTR_SHIFT_DEAFULT 8 +#define ATTR_SHIFT_DEFAULT 8 #define ATTR_LAZY 0x800 +#define ATTR_DEFREFCNT 0x1000 #define ATTR_COERCE 0x8 #define ATTR_TCREFCNT 0x10 @@ -402,6 +384,28 @@ STATIC bool check_sv_type (TC type, SV *sv) { return 0; } +STATIC bool check_sv_cv (pTHX_ SV *cv, SV *sv) { + bool ret; + dSP; + + ENTER; + SAVETMPS; + PUSHMARK(SP); + XPUSHs(sv); + PUTBACK; + + call_sv(cv, G_SCALAR); + + SPAGAIN; + ret = SvTRUE(POPs); + + PUTBACK; + FREETMPS; + LEAVE; + + return ret; +} + STATIC bool check_type_constraint(pTHX_ tc_kind kind, TC_CHECK tc_check, SV *type_constraint, SV *sv) { switch (kind) { case tc_none: @@ -417,6 +421,8 @@ STATIC bool check_type_constraint(pTHX_ tc_kind kind, TC_CHECK tc_check, SV *typ return tc_check.fptr(aTHX_ type_constraint, sv); break; case tc_cv: + return check_sv_cv(aTHX_ tc_check.sv, sv); + break; case tc_op: croak("todo"); break; @@ -498,6 +504,25 @@ STATIC void init_attr (MI *mi, ATTR *attr, AV *desc) { flags |= tc_kind; } + + if ( SvTRUE(params[10]) ) { /* has default */ + SV *sv = params[11]; + + if ( SvROK(sv) ) { + attr->def.sv = SvRV(sv); + if ( SvTYPE(attr->def.sv) != SVt_PVCV ) + croak("compiled type constraint is not a coderef"); + } else { + attr->def.sv = newSVsv(sv); + sv_2mortal(attr->def.sv); /* in case of error soon, we refcnt inc it later after we're done checking params */ + } + + flags |= ( ATTR_DEFREFCNT | ( default_normal << ATTR_SHIFT_DEFAULT ) ); + } else if ( SvOK(params[12]) ) { /* builder */ + attr->def.sv = newSVsv(params[12]); + flags |= ( ATTR_DEFREFCNT | ( default_builder << ATTR_SHIFT_DEFAULT ) ); + } + attr->flags = flags; /* FIXME default_kind */ attr->trigger = SvROK(params[6]) ? (CV *)SvRV(params[6]) : NULL; @@ -513,13 +538,12 @@ STATIC void init_attr (MI *mi, ATTR *attr, AV *desc) { attr->type_constraint = newSVsv(tc); SvREFCNT_inc(attr->trigger); SvREFCNT_inc(attr->initializer); - if ( flags & ATTR_TCREFCNT ) SvREFCNT_inc(attr->tc_check.sv); + if ( flags & ATTR_TCREFCNT ) SvREFCNT_inc(attr->tc_check.sv); + if ( flags & ATTR_DEFREFCNT ) SvREFCNT_inc(attr->def.sv); attr->slot_sv = newSVpvn_share(pv, len, hash); attr->slot_u32 = hash; - attr->def.type = 0; - /* cross refs to CVs which use this struct */ attr->cvs = newAV(); } @@ -560,14 +584,15 @@ STATIC void delete_mi (pTHX_ MI *mi) { /* clear the pointers to this meta attr from all the CVs */ SV **cvs = AvARRAY(attr->cvs); for ( j = av_len(attr->cvs); j >= 0; j-- ) { - CV *cv = cvs[j]; + CV *cv = (CV *)cvs[j]; XSANY.any_i32 = 0; } SvREFCNT_dec(attr->cvs); SvREFCNT_dec(attr->slot_sv); SvREFCNT_dec(attr->type_constraint); - if ( attr->flags & ATTR_TCREFCNT ) SvREFCNT_dec(attr->tc_check.sv); + if ( attr->flags & ATTR_TCREFCNT ) SvREFCNT_dec(attr->tc_check.sv); + if ( attr->flags & ATTR_DEFREFCNT ) SvREFCNT_dec(attr->def.sv); SvREFCNT_dec(attr->initializer); SvREFCNT_dec(attr->trigger); SvREFCNT_dec(attr->meta_attr); @@ -611,7 +636,7 @@ STATIC SV *attr_to_meta_instance(pTHX_ SV *meta_attr) { FREETMPS; LEAVE; - return mi; + return sv_2mortal(mi); } STATIC SV *perl_mi_to_c_mi(pTHX_ SV *perl_mi) { @@ -674,8 +699,6 @@ STATIC ATTR *get_attr(pTHX_ CV *cv) { SvREFCNT_dec(c_mi); } - sv_2mortal(perl_mi); - mi = INT2PTR(MI *, SvIV(SvRV(c_mi))); return mi_find_attr(mi, meta_attr); @@ -762,14 +785,73 @@ STATIC SV *deinitialize_slot(pTHX_ SV *self, ATTR *attr) { return hv_delete_ent((HV *)SvRV(self), attr->slot_sv, 0, attr->slot_u32); } +STATIC void setter_common(pTHX_ SV *self, ATTR *attr, SV *value); + + +STATIC SV *get_default(pTHX_ SV *self, ATTR *attr) { + switch ( ATTR_DEFAULT(attr) ) { + case default_none: + return NULL; + break; + case default_builder: + { + SV *sv; + dSP; + + ENTER; + SAVETMPS; + PUSHMARK(SP); + XPUSHs(self); + PUTBACK; + + call_method(SvPV_nolen(attr->def.sv), G_SCALAR); + + SPAGAIN; + sv = POPs; + + SvREFCNT_inc(sv); + + PUTBACK; + FREETMPS; + LEAVE; + + return sv_2mortal(sv); + } + break; + case default_normal: + if ( SvROK(attr->def.sv) ) { + printf("CV default\n"); + } else { + printf("simple value\n"); + return attr->def.sv; /* will be copied by set for lazy, and by reader for both cases */ + } + break; + case default_op: + case default_type: + croak("todo"); + break; + } + + return NULL; +} + STATIC SV *getter_common(pTHX_ SV *self, ATTR *attr) { - assert( ATTR_DUMB_READER(attr) ); - return get_slot_value(aTHX_ self, attr); + SV *value = get_slot_value(aTHX_ self, attr); + + if ( value ) { + return value; + } else if ( ATTR_ISLAZY(attr) ) { + value = get_default(aTHX_ self, attr); + setter_common(aTHX_ self, attr, value); + return value; + } + + return NULL; } STATIC void setter_common(pTHX_ SV *self, ATTR *attr, SV *value) { - if ( attr->flags & ATTR_MASK_TYPE ) { - if ( !check_type_constraint(aTHX_ attr->flags & ATTR_MASK_TYPE, attr->tc_check, attr->type_constraint, value) ) + if ( ATTR_TYPE(attr) ) { + if ( !check_type_constraint(aTHX_ ATTR_TYPE(attr), attr->tc_check, attr->type_constraint, value) ) croak("Bad param"); }