Fix a stack operation
[gitmo/Class-MOP.git] / xs / MethodConstructor.xs
CommitLineData
87cfe982 1#include "mop.h"
2
3
87cfe982 4static MGVTBL mop_constructor_vtbl;
5
6static HV*
7mop_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
87cfe982 37
38XS(mop_xs_constructor);
39XS(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
2b20ec6a 57 SP -= items;
58 PUTBACK;
59
87cfe982 60 klass = ST(0);
61
62 if(SvROK(klass)){
63 croak("The constructor must be called as a class method");
64 }
65
87cfe982 66 args = mop_build_args(aTHX_ cv, ax+1, items-1);
67
5bd0f967 68 stash = gv_stashsv(klass, TRUE);
87cfe982 69 if( stash != GvSTASH(CvGV(cv)) ){
70 SV* const metaclass = mop_class_of(aTHX_ klass);
71 dSP;
72
73 PUSHMARK(SP);
74 EXTEND(SP, 2);
75 PUSHs(metaclass);
76 mPUSHs(newRV_inc((SV*)args));
77 PUTBACK;
78
79 call_method("new_object", GIMME_V);
80 return;
81 }
82
83 instance = sv_2mortal( MOP_mg_create_instance(mg, stash) );
84 if(!IsObject(instance)){
85 croak("create_instance() did not return an object instance");
86 }
87
88 len = AvFILLp(attrs) + 1;
89 for(i = 0; i < len; i++){
90 mop_attr_initialize_instance_slot(aTHX_ AvARRAY(attrs)[i], MOP_mg_vtbl(mg), instance, args);
91 }
92
93 ST(0) = instance;
94 XSRETURN(1);
95}
96
97
98static CV*
99mop_generate_constructor_method_xs(pTHX_ SV* const constructor, mop_instance_vtbl* const vtbl){
100 SV* const metaclass = mop_call0(aTHX_ constructor, mop_associated_metaclass);
101
102 CV* const xsub = newXS(NULL, mop_xs_constructor, __FILE__);
103 MAGIC* mg;
104 AV* attrs;
105
106 sv_2mortal((SV*)xsub);
107
108 attrs = mop_class_get_all_attributes(aTHX_ metaclass);
109 mg = sv_magicext((SV*)xsub, (SV*)attrs, PERL_MAGIC_ext, &mop_constructor_vtbl, (char*)vtbl, 0);
110 SvREFCNT_dec(attrs);
111 CvXSUBANY(xsub).any_ptr = (void*)mg;
112
113 return xsub;
114}
115
116
117MODULE = Class::MOP::Method::Constructor PACKAGE = Class::MOP::Method::Constructor
118
119PROTOTYPES: DISABLE
120
b66ddbab 121VERSIONCHECK: DISABLE
122
87cfe982 123BOOT:
124 INSTALL_SIMPLE_READER(Method::Constructor, options);
125 INSTALL_SIMPLE_READER(Method::Constructor, associated_metaclass);
126
127CV*
128_generate_constructor_method_xs(SV* self, void* instance_vtbl)
129CODE:
130 RETVAL = mop_generate_constructor_method_xs(aTHX_ self, instance_vtbl);
131OUTPUT:
132 RETVAL
133