Code tidy. No functionality changed
[gitmo/Class-MOP.git] / xs / MethodConstructor.xs
1 #include "mop.h"
2
3
4 static MGVTBL mop_constructor_vtbl;
5
6 static HV*
7 mop_build_args(pTHX_ CV* const cv, I32 const ax, I32 const items){
8     HV* args;
9     if(items == 1){
10         SV* const sv = ST(0);
11         SvGETMAGIC(sv);
12         if(!(SvROK(sv) && SvTYPE(SvRV(sv)) == SVt_PVHV)){
13             croak("Single arguments to %s() must be a HASH ref", GvNAME(CvGV(cv)));
14         }
15         args = (HV*)SvRV(sv);
16     }
17     else{
18         I32 i;
19
20         if( items % 2 ){
21             croak("Odd number of arguments for %s()", GvNAME(CvGV(cv)));
22         }
23
24         args = newHV();
25         sv_2mortal((SV*)args);
26
27         for(i = 0; i < items; i += 2){
28             SV* const key   = ST(i);
29             SV* const value = ST(i+1);
30             (void)hv_store_ent(args, key, value, 0U);
31             SvREFCNT_inc_simple_void_NN(value);
32         }
33     }
34     return args;
35 }
36
37
38 XS(mop_xs_constructor);
39 XS(mop_xs_constructor)
40 {
41     dVAR; dXSARGS;
42     dMOP_mg(cv);
43     AV* const attrs = (AV*)MOP_mg_obj(mg);
44     SV* klass;
45     HV* stash;
46     SV* instance;
47     I32 i;
48     I32 len;
49     HV* args;
50
51     assert(SvTYPE(attrs) == SVt_PVAV);
52
53     if(items < 0){
54         croak("Not enough arguments for %s()", GvNAME(CvGV(cv)));
55     }
56
57     klass = ST(0);
58
59     if(SvROK(klass)){
60         croak("The constructor must be called as a class method");
61     }
62
63     args = mop_build_args(aTHX_ cv, ax+1, items-1);
64
65     stash = gv_stashsv(klass, TRUE);
66     if( stash != GvSTASH(CvGV(cv)) ){
67         SV* const metaclass = mop_class_of(aTHX_ klass);
68         dSP;
69
70         PUSHMARK(SP);
71         EXTEND(SP, 2);
72         PUSHs(metaclass);
73         mPUSHs(newRV_inc((SV*)args));
74         PUTBACK;
75
76         call_method("new_object", GIMME_V);
77         return;
78     }
79
80     instance = sv_2mortal( MOP_mg_create_instance(mg, stash) );
81     if(!IsObject(instance)){
82         croak("create_instance() did not return an object instance");
83     }
84
85     len = AvFILLp(attrs) + 1;
86     for(i = 0; i < len; i++){
87         mop_attr_initialize_instance_slot(aTHX_ AvARRAY(attrs)[i], MOP_mg_vtbl(mg), instance, args);
88     }
89
90     ST(0) = instance;
91     XSRETURN(1);
92 }
93
94
95 static CV*
96 mop_generate_constructor_method_xs(pTHX_ SV* const constructor, mop_instance_vtbl* const vtbl){
97     SV* const metaclass = mop_call0(aTHX_ constructor, mop_associated_metaclass);
98
99     CV* const xsub  = newXS(NULL, mop_xs_constructor, __FILE__);
100     MAGIC* mg;
101     AV* attrs;
102
103     sv_2mortal((SV*)xsub);
104
105     attrs = mop_class_get_all_attributes(aTHX_ metaclass);
106     mg = sv_magicext((SV*)xsub, (SV*)attrs, PERL_MAGIC_ext, &mop_constructor_vtbl, (char*)vtbl, 0);
107     SvREFCNT_dec(attrs);
108     CvXSUBANY(xsub).any_ptr = (void*)mg;
109
110     return xsub;
111 }
112
113
114 MODULE = Class::MOP::Method::Constructor   PACKAGE = Class::MOP::Method::Constructor
115
116 PROTOTYPES: DISABLE
117
118 VERSIONCHECK: DISABLE
119
120 BOOT:
121     INSTALL_SIMPLE_READER(Method::Constructor, options);
122     INSTALL_SIMPLE_READER(Method::Constructor, associated_metaclass);
123
124 CV*
125 _generate_constructor_method_xs(SV* self, void* instance_vtbl)
126 CODE:
127     RETVAL = mop_generate_constructor_method_xs(aTHX_ self, instance_vtbl);
128 OUTPUT:
129     RETVAL
130