line |
stmt |
bran |
cond |
sub |
pod |
time |
code |
1
|
|
|
|
|
|
|
#ifdef __cplusplus |
2
|
|
|
|
|
|
|
extern "C" { |
3
|
|
|
|
|
|
|
#endif |
4
|
|
|
|
|
|
|
|
5
|
|
|
|
|
|
|
#define PERL_NO_GET_CONTEXT /* we want efficiency */ |
6
|
|
|
|
|
|
|
#include |
7
|
|
|
|
|
|
|
#include |
8
|
|
|
|
|
|
|
#include |
9
|
|
|
|
|
|
|
|
10
|
|
|
|
|
|
|
#ifdef __cplusplus |
11
|
|
|
|
|
|
|
} /* extern "C" */ |
12
|
|
|
|
|
|
|
#endif |
13
|
|
|
|
|
|
|
|
14
|
|
|
|
|
|
|
#define NEED_newSVpvn_flags |
15
|
|
|
|
|
|
|
#include "ppport.h" |
16
|
|
|
|
|
|
|
|
17
|
|
|
|
|
|
|
#ifndef GvCV_set |
18
|
|
|
|
|
|
|
# define GvCV_set(gv,cv) (GvGP(gv)->gp_cv = (cv)) |
19
|
|
|
|
|
|
|
#endif |
20
|
|
|
|
|
|
|
|
21
|
|
|
|
|
|
|
#ifndef gv_init_pvn |
22
|
|
|
|
|
|
|
# define gv_init_pvn gv_init |
23
|
|
|
|
|
|
|
#endif |
24
|
|
|
|
|
|
|
|
25
|
|
|
|
|
|
|
#define IsArrayRef(sv) (SvROK(sv) && !SvOBJECT(SvRV(sv)) && SvTYPE(SvRV(sv)) == SVt_PVAV) |
26
|
|
|
|
|
|
|
#define IsHashRef(sv) (SvROK(sv) && !SvOBJECT(SvRV(sv)) && SvTYPE(SvRV(sv)) == SVt_PVHV) |
27
|
|
|
|
|
|
|
#define IsCodeRef(sv) (SvROK(sv) && !SvOBJECT(SvRV(sv)) && SvTYPE(SvRV(sv)) == SVt_PVCV) |
28
|
|
|
|
|
|
|
#define WANT_ARRAY GIMME_V == G_ARRAY |
29
|
|
|
|
|
|
|
|
30
|
|
|
|
|
|
|
XS(XS_prototype_method); |
31
|
|
|
|
|
|
|
XS(XS_prototype_getter); |
32
|
|
|
|
|
|
|
|
33
|
|
|
|
|
|
|
static GV * |
34
|
|
|
|
|
|
|
prototype_gv_pvn(pTHX_ HV *stash, const char *name, STRLEN len, U32 flags) |
35
|
|
|
|
|
|
|
{ |
36
|
159
|
|
|
|
|
|
GV *gv = (GV *)newSV(0); |
37
|
159
|
|
|
|
|
|
gv_init_pvn(gv, stash, name, len, flags); |
38
|
|
|
|
|
|
|
return gv; |
39
|
|
|
|
|
|
|
} |
40
|
|
|
|
|
|
|
|
41
|
|
|
|
|
|
|
static GV * |
42
|
129
|
|
|
|
|
|
prototype_gv_sv(pTHX_ HV *stash, SV *namesv) |
43
|
|
|
|
|
|
|
{ |
44
|
|
|
|
|
|
|
U32 flag; |
45
|
|
|
|
|
|
|
char *namepv; |
46
|
|
|
|
|
|
|
STRLEN namelen; |
47
|
129
|
50
|
|
|
|
|
namepv = SvPV(namesv, namelen); |
48
|
|
|
|
|
|
|
if (SvUTF8(namesv)) flag = SVf_UTF8; |
49
|
258
|
|
|
|
|
|
return prototype_gv_pvn(aTHX_ stash, namepv, namelen, flag); |
50
|
|
|
|
|
|
|
} |
51
|
|
|
|
|
|
|
|
52
|
|
|
|
|
|
|
static void |
53
|
129
|
|
|
|
|
|
add_method(pTHX_ HV *stash, SV *method, CV *code, char *key, I32 keylen) |
54
|
|
|
|
|
|
|
{ |
55
|
|
|
|
|
|
|
GV *gv; |
56
|
129
|
|
|
|
|
|
gv = prototype_gv_sv(aTHX_ stash, method); |
57
|
129
|
|
|
|
|
|
GvCV_set(gv, code); |
58
|
129
|
|
|
|
|
|
hv_store(stash, key, keylen, (SV *)gv, 0); |
59
|
129
|
|
|
|
|
|
} |
60
|
|
|
|
|
|
|
|
61
|
|
|
|
|
|
|
static void |
62
|
8
|
|
|
|
|
|
add_method_sv(pTHX_ HV *stash, SV *method, CV *code) |
63
|
|
|
|
|
|
|
{ |
64
|
|
|
|
|
|
|
char *key; |
65
|
|
|
|
|
|
|
STRLEN keylen; |
66
|
8
|
50
|
|
|
|
|
key = SvPV(method, keylen); |
67
|
8
|
|
|
|
|
|
add_method(aTHX_ stash, method, code, key, keylen); |
68
|
8
|
|
|
|
|
|
} |
69
|
|
|
|
|
|
|
|
70
|
|
|
|
|
|
|
static CV * |
71
|
|
|
|
|
|
|
make_closure(pTHX_ SV *retval) |
72
|
|
|
|
|
|
|
{ |
73
|
|
|
|
|
|
|
CV *xsub; |
74
|
110
|
|
|
|
|
|
xsub = newXS(NULL /* anonymous */, XS_prototype_getter, __FILE__); |
75
|
110
|
|
|
|
|
|
CvXSUBANY(xsub).any_ptr = (void *)retval; |
76
|
|
|
|
|
|
|
return xsub; |
77
|
|
|
|
|
|
|
} |
78
|
|
|
|
|
|
|
|
79
|
|
|
|
|
|
|
static void |
80
|
17
|
|
|
|
|
|
push_values(pTHX_ SV *retval) |
81
|
|
|
|
|
|
|
{ |
82
|
17
|
|
|
|
|
|
dSP; |
83
|
17
|
100
|
|
|
|
|
if (WANT_ARRAY && IsArrayRef(retval)) { |
|
|
100
|
|
|
|
|
|
|
|
50
|
|
|
|
|
|
|
|
100
|
|
|
|
|
|
|
|
100
|
|
|
|
|
|
84
|
|
|
|
|
|
|
AV *av = (AV *)SvRV(retval); |
85
|
1
|
|
|
|
|
|
I32 len = av_len(av) + 1; |
86
|
1
|
50
|
|
|
|
|
EXTEND(SP, len); |
|
|
50
|
|
|
|
|
|
87
|
11
|
100
|
|
|
|
|
for (I32 i = 0; i < len; i++){ |
88
|
10
|
|
|
|
|
|
SV **const svp = av_fetch(av, i, FALSE); |
89
|
10
|
50
|
|
|
|
|
PUSHs(svp ? *svp : &PL_sv_undef); |
90
|
|
|
|
|
|
|
} |
91
|
16
|
100
|
|
|
|
|
} else if (WANT_ARRAY && IsHashRef(retval)) { |
|
|
100
|
|
|
|
|
|
|
|
50
|
|
|
|
|
|
|
|
100
|
|
|
|
|
|
|
|
50
|
|
|
|
|
|
92
|
|
|
|
|
|
|
HV *hv = (HV *)SvRV(retval); |
93
|
|
|
|
|
|
|
HE *he; |
94
|
1
|
|
|
|
|
|
hv_iterinit(hv); |
95
|
3
|
100
|
|
|
|
|
while ((he = hv_iternext(hv)) != NULL){ |
96
|
2
|
50
|
|
|
|
|
EXTEND(SP, 2); |
97
|
2
|
|
|
|
|
|
PUSHs(hv_iterkeysv(he)); |
98
|
2
|
|
|
|
|
|
PUSHs(hv_iterval(hv, he)); |
99
|
|
|
|
|
|
|
} |
100
|
|
|
|
|
|
|
} else { |
101
|
15
|
50
|
|
|
|
|
XPUSHs(retval ? retval : &PL_sv_undef); |
|
|
50
|
|
|
|
|
|
102
|
|
|
|
|
|
|
} |
103
|
17
|
|
|
|
|
|
PUTBACK; |
104
|
17
|
|
|
|
|
|
} |
105
|
|
|
|
|
|
|
|
106
|
|
|
|
|
|
|
static CV * |
107
|
|
|
|
|
|
|
make_prototype_method(pTHX_ HV *stash) |
108
|
|
|
|
|
|
|
{ |
109
|
|
|
|
|
|
|
CV *xsub; |
110
|
30
|
|
|
|
|
|
xsub = newXS(NULL /* anonymous */, XS_prototype_method, __FILE__); |
111
|
30
|
|
|
|
|
|
CvXSUBANY(xsub).any_ptr = (void *)stash; |
112
|
|
|
|
|
|
|
return xsub; |
113
|
|
|
|
|
|
|
} |
114
|
|
|
|
|
|
|
|
115
|
|
|
|
|
|
|
static void |
116
|
30
|
|
|
|
|
|
install_prototype_method(pTHX_ HV *stash) |
117
|
|
|
|
|
|
|
{ |
118
|
|
|
|
|
|
|
char *prototype = "prototype"; |
119
|
|
|
|
|
|
|
CV *prototype_cv = make_prototype_method(aTHX_ stash); |
120
|
|
|
|
|
|
|
GV *prototype_glob = prototype_gv_pvn(aTHX_ stash, prototype, 9, 0); |
121
|
30
|
|
|
|
|
|
GvCV_set(prototype_glob, prototype_cv); |
122
|
30
|
|
|
|
|
|
hv_store(stash, prototype, 9, (SV *)prototype_glob, 0); |
123
|
30
|
|
|
|
|
|
} |
124
|
|
|
|
|
|
|
|
125
|
17
|
|
|
|
|
|
XS(XS_prototype_getter) |
126
|
|
|
|
|
|
|
{ |
127
|
34
|
|
|
|
|
|
dVAR; dXSARGS; |
128
|
17
|
|
|
|
|
|
SV *retval = (SV *)CvXSUBANY(cv).any_ptr; |
129
|
17
|
|
|
|
|
|
SP -= items; /* PPCODE */ |
130
|
17
|
|
|
|
|
|
PUTBACK; |
131
|
17
|
|
|
|
|
|
push_values(aTHX_ retval); |
132
|
17
|
|
|
|
|
|
} |
133
|
|
|
|
|
|
|
|
134
|
3
|
|
|
|
|
|
XS(XS_prototype_method) |
135
|
|
|
|
|
|
|
{ |
136
|
6
|
|
|
|
|
|
dVAR; dXSARGS; |
137
|
3
|
50
|
|
|
|
|
if ((items - 1) % 2 != 0) |
138
|
0
|
|
|
|
|
|
Perl_croak(aTHX_ "Argument isn't hash type"); |
139
|
|
|
|
|
|
|
|
140
|
3
|
|
|
|
|
|
HV *stash = (HV *)CvXSUBANY(cv).any_ptr; |
141
|
|
|
|
|
|
|
I32 i = 1; /* First argument is skip: `my $self = shift;` */ |
142
|
11
|
100
|
|
|
|
|
while (i < items) { |
143
|
8
|
|
|
|
|
|
SV *method = ST(i++); |
144
|
8
|
|
|
|
|
|
SV *val = ST(i++); |
145
|
11
|
100
|
|
|
|
|
CV *cv = IsCodeRef(val) ? (CV *)SvREFCNT_inc(SvRV(val)) : make_closure(aTHX_ val); |
|
|
50
|
|
|
|
|
|
146
|
8
|
|
|
|
|
|
add_method_sv(aTHX_ stash, method, cv); |
147
|
|
|
|
|
|
|
} |
148
|
3
|
|
|
|
|
|
XSRETURN(0); |
149
|
|
|
|
|
|
|
} |
150
|
|
|
|
|
|
|
|
151
|
|
|
|
|
|
|
MODULE = Package::Prototype PACKAGE = Package::Prototype |
152
|
|
|
|
|
|
|
PROTOTYPES: DISABLE |
153
|
|
|
|
|
|
|
|
154
|
|
|
|
|
|
|
void * |
155
|
|
|
|
|
|
|
bless(klass, ref, pkgsv=NULL) |
156
|
|
|
|
|
|
|
SV *klass; |
157
|
|
|
|
|
|
|
SV *ref; |
158
|
|
|
|
|
|
|
SV *pkgsv; |
159
|
|
|
|
|
|
|
PREINIT: |
160
|
|
|
|
|
|
|
char *pkg; |
161
|
|
|
|
|
|
|
STRLEN pkglen; |
162
|
|
|
|
|
|
|
HE* entry; |
163
|
|
|
|
|
|
|
HV *stash; |
164
|
|
|
|
|
|
|
PPCODE: |
165
|
|
|
|
|
|
|
{ |
166
|
30
|
50
|
|
|
|
|
if (!IsHashRef(ref)) |
|
|
50
|
|
|
|
|
|
167
|
0
|
|
|
|
|
|
Perl_croak(aTHX_ "Please pass an hash reference to the first argument"); |
168
|
|
|
|
|
|
|
|
169
|
30
|
100
|
|
|
|
|
if (pkgsv) { |
170
|
3
|
50
|
|
|
|
|
pkg = SvPV(pkgsv, pkglen); |
171
|
|
|
|
|
|
|
} else { |
172
|
|
|
|
|
|
|
pkg = "__ANON__"; |
173
|
27
|
|
|
|
|
|
pkglen = 8; |
174
|
|
|
|
|
|
|
} |
175
|
|
|
|
|
|
|
|
176
|
30
|
|
|
|
|
|
stash = (HV *)sv_2mortal((SV *)newHV()); |
177
|
30
|
|
|
|
|
|
hv_name_set(stash, pkg, pkglen, 0); |
178
|
|
|
|
|
|
|
|
179
|
30
|
|
|
|
|
|
install_prototype_method(aTHX_ stash); |
180
|
|
|
|
|
|
|
|
181
|
30
|
|
|
|
|
|
HV *hv = (HV *)SvRV(ref); |
182
|
30
|
|
|
|
|
|
hv_iterinit(hv); |
183
|
151
|
100
|
|
|
|
|
while ((entry = hv_iternext(hv)) != NULL){ |
184
|
|
|
|
|
|
|
I32 keylen; |
185
|
121
|
|
|
|
|
|
char* key = hv_iterkey(entry, &keylen); |
186
|
121
|
50
|
|
|
|
|
if (0 < keylen && key[0] != '_') { |
|
|
50
|
|
|
|
|
|
187
|
121
|
|
|
|
|
|
SV *method = hv_iterkeysv(entry); |
188
|
121
|
|
|
|
|
|
SV *val = hv_delete(hv, key, keylen, 1); |
189
|
|
|
|
|
|
|
SvREFCNT_inc(val); /* was made mortal by hv_delete */ |
190
|
121
|
100
|
|
|
|
|
CV *cv = IsCodeRef(val) ? (CV *)SvRV(val) : make_closure(aTHX_ val); |
|
|
100
|
|
|
|
|
|
191
|
121
|
|
|
|
|
|
add_method(aTHX_ stash, method, cv, key, keylen); |
192
|
|
|
|
|
|
|
} |
193
|
|
|
|
|
|
|
} |
194
|
|
|
|
|
|
|
|
195
|
30
|
|
|
|
|
|
ST(0) = sv_bless(ref, stash); |
196
|
30
|
|
|
|
|
|
XSRETURN(1); |
197
|
|
|
|
|
|
|
} |