Implement a XS constructor generator
[gitmo/Class-MOP.git] / xs / MOP.xs
1 #include "mop.h"
2
3 SV *mop_method_metaclass;
4 SV *mop_associated_metaclass;
5 SV *mop_wrap;
6 SV *mop_methods;
7 SV *mop_name;
8 SV *mop_body;
9 SV *mop_package;
10 SV *mop_package_name;
11 SV *mop_package_cache_flag;
12 SV *mop_initialize;
13 SV *mop_isa;
14 SV *mop_can;
15 SV *mop_Class;
16 SV *mop_VERSION;
17 SV *mop_ISA;
18
19 /* equivalent to "blessed($x) && $x->isa($klass)" */
20 bool
21 mop_is_instance_of(pTHX_ SV* const sv, SV* const klass){
22     assert(sv);
23     assert(klass);
24
25     if(SvROK(sv) && SvOBJECT(SvRV(sv)) && SvOK(klass)){
26         bool ok;
27
28         ENTER;
29         SAVETMPS;
30
31         ok = SvTRUEx(mop_call1(aTHX_ sv, mop_isa, klass));
32
33         FREETMPS;
34         LEAVE;
35
36         return ok;
37     }
38
39     return FALSE;
40 }
41
42 static bool
43 find_method (const char *key, STRLEN keylen, SV *val, void *ud)
44 {
45     bool * const found_method = (bool *)ud;
46     PERL_UNUSED_ARG(key);
47     PERL_UNUSED_ARG(keylen);
48     PERL_UNUSED_ARG(val);
49     *found_method = TRUE;
50     return FALSE;
51 }
52
53
54 bool
55 mop_is_class_loaded(pTHX_ SV * const klass){
56     HV *stash;
57
58     if (!(SvPOKp(klass) && SvCUR(klass))) { /* XXX: SvPOK does not work with magical scalars */
59         return FALSE;
60     }
61
62     stash = gv_stashsv(klass, 0);
63     if (!stash) {
64         return FALSE;
65     }
66
67     if (hv_exists_ent (stash, mop_VERSION, 0U)) {
68         HE *version = hv_fetch_ent(stash, mop_VERSION, 0, 0U);
69         SV *version_sv;
70         if (version && HeVAL(version) && (version_sv = GvSV(HeVAL(version)))) {
71             if (SvROK(version_sv)) {
72                 SV *version_sv_ref = SvRV(version_sv);
73
74                 if (SvOK(version_sv_ref)) {
75                     return TRUE;
76                 }
77             }
78             else if (SvOK(version_sv)) {
79                 return TRUE;
80             }
81         }
82     }
83
84     if (hv_exists_ent (stash, mop_ISA, 0U)) {
85         HE *isa = hv_fetch_ent(stash, mop_ISA, 0, 0U);
86         if (isa && HeVAL(isa) && GvAV(HeVAL(isa)) && av_len(GvAV(HeVAL(isa))) != -1) {
87             return TRUE;;
88         }
89     }
90
91     {
92         bool found_method = FALSE;
93         mop_get_package_symbols(stash, TYPE_FILTER_CODE, find_method, &found_method);
94        return found_method;
95     }
96 }
97
98 EXTERN_C XS(boot_Class__MOP__Package);
99 EXTERN_C XS(boot_Class__MOP__Attribute);
100 EXTERN_C XS(boot_Class__MOP__Method);
101 EXTERN_C XS(boot_Class__MOP__Instance);
102 EXTERN_C XS(boot_Class__MOP__Method__Accessor);
103 EXTERN_C XS(boot_Class__MOP__Method__Constructor);
104
105 MODULE = Class::MOP   PACKAGE = Class::MOP
106
107 PROTOTYPES: DISABLE
108
109 BOOT:
110     mop_method_metaclass     = MAKE_KEYSV(method_metaclass);
111     mop_wrap                 = MAKE_KEYSV(wrap);
112     mop_associated_metaclass = MAKE_KEYSV(associated_metaclass);
113     mop_methods              = MAKE_KEYSV(methods);
114     mop_name                 = MAKE_KEYSV(name);
115     mop_body                 = MAKE_KEYSV(body);
116     mop_package              = MAKE_KEYSV(package);
117     mop_package_name         = MAKE_KEYSV(package_name);
118     mop_package_cache_flag   = MAKE_KEYSV(_package_cache_flag);
119     mop_initialize           = MAKE_KEYSV(initialize);
120     mop_Class                = MAKE_KEYSV(Class::MOP::Class);
121     mop_VERSION              = MAKE_KEYSV(VERSION);
122     mop_ISA                  = MAKE_KEYSV(ISA);
123     mop_isa                  = MAKE_KEYSV(isa);
124     mop_can                  = MAKE_KEYSV(can);
125
126     MOP_CALL_BOOT (boot_Class__MOP__Package);
127     MOP_CALL_BOOT (boot_Class__MOP__Attribute);
128     MOP_CALL_BOOT (boot_Class__MOP__Instance);
129     MOP_CALL_BOOT (boot_Class__MOP__Method);
130     MOP_CALL_BOOT (boot_Class__MOP__Method__Accessor);
131     MOP_CALL_BOOT (boot_Class__MOP__Method__Constructor);
132
133 # use prototype here to be compatible with get_code_info from Sub::Identify
134 void
135 get_code_info(coderef)
136     SV *coderef
137     PROTOTYPE: $
138     PREINIT:
139         char *pkg  = NULL;
140         char *name = NULL;
141     PPCODE:
142         SvGETMAGIC(coderef);
143         if (mop_get_code_info(coderef, &pkg, &name)) {
144             EXTEND(SP, 2);
145             mPUSHs(newSVpv(pkg, 0));
146             mPUSHs(newSVpv(name, 0));
147         }
148
149
150 bool
151 is_class_loaded(SV* klass = &PL_sv_undef)
152 INIT:
153     SvGETMAGIC(klass);
154
155
156
157 #bool
158 #is_instance_of(SV* sv, SV* klass)
159 #INIT:
160 #    SvGETMAGIC(sv);
161 #    SvGETMAGIC(klass);
162 #