Fix mro_get_linear_isa
[gitmo/Mouse.git] / xs-src / Mouse.xs
CommitLineData
1b812057 1#define NEED_newSVpvn_flags_GLOBAL
df6dd016 2#include "mouse.h"
3
cccb83de 4SV* mouse_package;
5SV* mouse_namespace;
3e44140b 6SV* mouse_methods;
a5df48e5 7SV* mouse_name;
cccb83de 8
da4432f3 9static SV* mouse_all_attrs_cache;
10static SV* mouse_all_attrs_cache_gen;
11
12AV*
13mouse_get_all_attributes(pTHX_ SV* const metaclass){
14 SV* const package = get_slot(metaclass, mouse_package);
15 HV* const stash = gv_stashsv(package, TRUE);
16 UV const pkg_gen = mro_get_pkg_gen(stash);
17 SV* cache_gen = get_slot(metaclass, mouse_all_attrs_cache_gen);
18
19 if(!(cache_gen && pkg_gen == SvUV(cache_gen))){ /* update */
20 CV* const get_metaclass = get_cvs("Mouse::Util::get_metaclass_by_name", TRUE);
21 AV* const linearized_isa = mro_get_linear_isa(stash);
22 I32 const len = AvFILLp(linearized_isa);
23 I32 i;
24 HV* seen;
25 AV* const all_attrs = newAV();
26
27 /* warn("Update all_attrs_cache (cache_gen %d != pkg_gen %d)", (cache_gen ? (int)SvIV(cache_gen) : 0), (int)pkg_gen); //*/
28
29 ENTER;
30 SAVETMPS;
31
32 set_slot(metaclass, mouse_all_attrs_cache, sv_2mortal(newRV_inc((SV*)all_attrs)));
33
34 seen = newHV();
35 sv_2mortal((SV*)seen);
36
37 for(i = 0; i < len; i++){
38 SV* const klass = MOUSE_av_at(linearized_isa, i);
39 SV* meta;
40 I32 n;
41 dSP;
42
43 PUSHMARK(SP);
44 XPUSHs(klass);
45 PUTBACK;
46
47 call_sv((SV*)get_metaclass, G_SCALAR);
48
49 SPAGAIN;
50 meta = POPs;
51 PUTBACK;
52
53 if(!SvOK(meta)){
54 continue; /* skip non-Mouse classes */
55 }
56
57 /* $meta->get_attribute_list */
58 PUSHMARK(SP);
59 XPUSHs(meta);
60 PUTBACK;
61
62 n = call_method("get_attribute_list", G_ARRAY);
63 for(NOOP; n > 0; n--){
64 SV* name;
65
66 SPAGAIN;
67 name = POPs;
68 PUTBACK;
69
70 if(hv_exists_ent(seen, name, 0U)){
71 continue;
72 }
73 (void)hv_store_ent(seen, name, &PL_sv_undef, 0U);
74
75 av_push(all_attrs, newSVsv( mcall1s(meta, "get_attribute", name) ));
76 }
77 }
78
79 if(!cache_gen){
80 cache_gen = sv_newmortal();
81 }
82 sv_setuv(cache_gen, mro_get_pkg_gen(stash));
83 set_slot(metaclass, mouse_all_attrs_cache_gen, cache_gen);
84
85 FREETMPS;
86 LEAVE;
87
88 return all_attrs;
89 }
90 else {
91 SV* const all_attrs_ref = get_slot(metaclass, mouse_all_attrs_cache);
92
93 if(!IsArrayRef(all_attrs_ref)){
94 croak("Not an ARRAY reference");
95 }
96
97 return (AV*)SvRV(all_attrs_ref);
98 }
99}
100
646c0371 101MODULE = Mouse PACKAGE = Mouse
df6dd016 102
103PROTOTYPES: DISABLE
104
cccb83de 105BOOT:
106 mouse_package = newSVpvs_share("package");
107 mouse_namespace = newSVpvs_share("namespace");
3e44140b 108 mouse_methods = newSVpvs_share("methods");
a5df48e5 109 mouse_name = newSVpvs_share("name");
3e44140b 110
da4432f3 111 mouse_all_attrs_cache = newSVpvs_share("__all_attrs_cache");
112 mouse_all_attrs_cache_gen = newSVpvs_share("__all_attrs_cache_gen");
113
646c0371 114 MOUSE_CALL_BOOT(Mouse__Util);
1d5ecd5f 115 MOUSE_CALL_BOOT(Mouse__Util__TypeConstraints);
646c0371 116 MOUSE_CALL_BOOT(Mouse__Meta__Method__Accessor__XS);
f48920c1 117
cccb83de 118
7d96ae4d 119MODULE = Mouse PACKAGE = Mouse::Meta::Module
120
121BOOT:
122 INSTALL_SIMPLE_READER_WITH_KEY(Module, name, package);
123 INSTALL_SIMPLE_READER_WITH_KEY(Module, _method_map, methods);
124 INSTALL_SIMPLE_READER_WITH_KEY(Module, _attribute_map, attributes);
125
126HV*
127namespace(SV* self)
128CODE:
129{
6a97bbda 130 SV* const package = get_slot(self, mouse_package);
7d96ae4d 131 if(!(package && SvOK(package))){
3e44140b 132 croak("No package name defined");
7d96ae4d 133 }
134 RETVAL = gv_stashsv(package, GV_ADDMULTI);
135}
136OUTPUT:
137 RETVAL
138
3e44140b 139# ignore extra arguments for extensibility
140void
141add_method(SV* self, SV* name, SV* code, ...)
142CODE:
143{
6a97bbda 144 SV* const package = get_slot(self, mouse_package); /* $self->{package} */
145 SV* const methods = get_slot(self, mouse_methods); /* $self->{methods} */
3e44140b 146 GV* gv;
147 SV* code_ref;
148
149 if(!(package && SvOK(package))){
150 croak("No package name defined");
151 }
152
153 SvGETMAGIC(name);
154 SvGETMAGIC(code);
155
156 if(!SvOK(name)){
157 mouse_throw_error(self, NULL, "You must define a method name");
158 }
159 if(!SvROK(code)){
160 mouse_throw_error(self, NULL, "You must define a CODE reference");
161 }
162
163 code_ref = code;
164 if(SvTYPE(SvRV(code_ref)) != SVt_PVCV){
165 SV* sv = code_ref; /* used in tryAMAGICunDEREF */
166 SV** sp = &sv; /* used in tryAMAGICunDEREF */
167 tryAMAGICunDEREF(to_cv); /* try \&{$code} */
168 if(SvROK(sv) && SvTYPE(SvRV(sv)) == SVt_PVCV){
169 mouse_throw_error(self, NULL, "Not a CODE reference");
170 }
171 code_ref = sv;
172 }
173
174 /* *{$package . '::' . $name} -> *gv */
175 gv = gv_fetchpv(form("%"SVf"::%"SVf, package, name), GV_ADDMULTI, SVt_PVCV);
176 if(GvCVu(gv)){ /* delete *slot{gv} to work around "redefine" warning */
177 SvREFCNT_dec(GvCV(gv));
178 GvCV(gv) = NULL;
179 }
180 sv_setsv_mg((SV*)gv, code_ref); /* *gv = $code_ref */
181
6fe2272b 182 set_slot(methods, name, code); /* $self->{methods}{$name} = $code */
3e44140b 183
184 /* TODO: name the CODE ref if it's anonymous */
185 //code_entity = (CV*)SvRV(code_ref);
186 //if(CvANON(code_entity)
187 // && CvGV(code_entity) /* a cv under construction has no gv */ ){
188
189 // CvGV(code_entity) = gv;
190 // CvANON_off(code_entity);
191 //}
192}
193
43165725 194MODULE = Mouse PACKAGE = Mouse::Meta::Class
195
196BOOT:
197 INSTALL_SIMPLE_READER(Class, roles);
198 INSTALL_SIMPLE_PREDICATE_WITH_KEY(Class, is_anon_class, anon_serial_id);
199
cccb83de 200void
201linearized_isa(SV* self)
202PPCODE:
203{
204 SV* const stash_ref = mcall0(self, mouse_namespace); /* $self->namespace */
205 AV* linearized_isa;
206 I32 len;
207 I32 i;
208 if(!(SvROK(stash_ref) && SvTYPE(SvRV(stash_ref)) == SVt_PVHV)){
209 croak("namespace() didn't return a HASH reference");
210 }
211 linearized_isa = mro_get_linear_isa((HV*)SvRV(stash_ref));
212 len = AvFILLp(linearized_isa) + 1;
213 EXTEND(SP, len);
214 for(i = 0; i < len; i++){
215 PUSHs(AvARRAY(linearized_isa)[i]);
216 }
217}
218
da4432f3 219void
220get_all_attributes(SV* self)
221PPCODE:
222{
223 AV* const all_attrs = mouse_get_all_attributes(aTHX_ self);
224 I32 const len = AvFILLp(all_attrs) + 1;
225 I32 i;
226
227 EXTEND(SP, len);
228 for(i = 0; i < len; i++){
229 PUSHs( MOUSE_av_at(all_attrs, i) );
230 }
231}
441964ce 232
43165725 233MODULE = Mouse PACKAGE = Mouse::Meta::Role
234
235BOOT:
236 INSTALL_SIMPLE_READER_WITH_KEY(Role, get_roles, roles);
237 INSTALL_SIMPLE_PREDICATE_WITH_KEY(Role, is_anon_role, anon_serial_id);
238
43165725 239MODULE = Mouse PACKAGE = Mouse::Meta::Attribute
240
241BOOT:
242 /* readers */
243 INSTALL_SIMPLE_READER(Attribute, name);
244 INSTALL_SIMPLE_READER(Attribute, associated_class);
245 INSTALL_SIMPLE_READER(Attribute, accessor);
246 INSTALL_SIMPLE_READER(Attribute, reader);
247 INSTALL_SIMPLE_READER(Attribute, writer);
248 INSTALL_SIMPLE_READER(Attribute, predicate);
249 INSTALL_SIMPLE_READER(Attribute, clearer);
250 INSTALL_SIMPLE_READER(Attribute, handles);
251
252 INSTALL_SIMPLE_READER_WITH_KEY(Attribute, _is_metadata, is);
253 INSTALL_SIMPLE_READER_WITH_KEY(Attribute, is_required, required);
254 INSTALL_SIMPLE_READER(Attribute, default);
255 INSTALL_SIMPLE_READER_WITH_KEY(Attribute, is_lazy, lazy);
256 INSTALL_SIMPLE_READER_WITH_KEY(Attribute, is_lazy_build, lazy_build);
257 INSTALL_SIMPLE_READER_WITH_KEY(Attribute, is_weak_ref, weak_ref);
258 INSTALL_SIMPLE_READER(Attribute, init_arg);
259 INSTALL_SIMPLE_READER(Attribute, type_constraint);
260 INSTALL_SIMPLE_READER(Attribute, trigger);
261 INSTALL_SIMPLE_READER(Attribute, builder);
262 INSTALL_SIMPLE_READER_WITH_KEY(Attribute, should_auto_deref, auto_deref);
263 INSTALL_SIMPLE_READER_WITH_KEY(Attribute, should_coerce, coerce);
264 INSTALL_SIMPLE_READER(Attribute, documentation);
265
266 /* predicates */
267 INSTALL_SIMPLE_PREDICATE_WITH_KEY(Attribute, has_accessor, accessor);
268 INSTALL_SIMPLE_PREDICATE_WITH_KEY(Attribute, has_reader, reader);
269 INSTALL_SIMPLE_PREDICATE_WITH_KEY(Attribute, has_writer, writer);
270 INSTALL_SIMPLE_PREDICATE_WITH_KEY(Attribute, has_predicate, predicate);
271 INSTALL_SIMPLE_PREDICATE_WITH_KEY(Attribute, has_clearer, clearer);
272 INSTALL_SIMPLE_PREDICATE_WITH_KEY(Attribute, has_handles, handles);
273
274 INSTALL_SIMPLE_PREDICATE_WITH_KEY(Attribute, has_default, default);
275 INSTALL_SIMPLE_PREDICATE_WITH_KEY(Attribute, has_type_constraint, type_constraint);
276 INSTALL_SIMPLE_PREDICATE_WITH_KEY(Attribute, has_trigger, trigger);
277 INSTALL_SIMPLE_PREDICATE_WITH_KEY(Attribute, has_builder, builder);
278 INSTALL_SIMPLE_PREDICATE_WITH_KEY(Attribute, has_documentation, documentation);
279
93540011 280 newCONSTSUB(gv_stashpvs("Mouse::Meta::Attribute", TRUE), "accessor_metaclass",
281 newSVpvs("Mouse::Meta::Method::Accessor::XS"));
282