cast to CV to avoid warning
[gitmo/Moose.git] / Moose.xs
index e30b35e..f5d4b57 100644 (file)
--- a/Moose.xs
+++ b/Moose.xs
 #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");
     }