#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 {
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;
* 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
*/
#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
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:
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;
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;
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();
}
/* 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);
FREETMPS;
LEAVE;
- return mi;
+ return sv_2mortal(mi);
}
STATIC SV *perl_mi_to_c_mi(pTHX_ SV *perl_mi) {
SvREFCNT_dec(c_mi);
}
- sv_2mortal(perl_mi);
-
mi = INT2PTR(MI *, SvIV(SvRV(c_mi)));
return mi_find_attr(mi, meta_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");
}