simplify the C level of callback stuff
[p5sagit/Devel-Declare.git] / Declare.xs
CommitLineData
94caac6e 1#define PERL_CORE
2#define PERL_NO_GET_CONTEXT
94caac6e 3#include "EXTERN.h"
4#include "perl.h"
5#include "XSUB.h"
6#undef printf
e807ee50 7#include "stolen_chunk_of_toke.c"
94caac6e 8#include <stdio.h>
9#include <string.h>
10
9673d7ca 11#ifndef Newx
12# define Newx(v,n,t) New(0,v,n,t)
13#endif /* !Newx */
14
53e3ab32 15#if 0
16#define DD_DEBUG
17#endif
c630715a 18
19#ifdef DD_DEBUG
20#define DD_DEBUG_S printf("Buffer: %s\n", s);
21#else
22#define DD_DEBUG_S
23#endif
24
94caac6e 25#define LEX_NORMAL 10
26#define LEX_INTERPNORMAL 9
27
94caac6e 28/* flag to trigger removal of temporary declaree sub */
29
30static int in_declare = 0;
31
72f20f69 32/* thing that decides whether we're dealing with a declarator */
33
34int dd_is_declarator(pTHX_ char* name) {
35 HV* is_declarator;
36 SV** is_declarator_pack_ref;
37 HV* is_declarator_pack_hash;
38 SV** is_declarator_flag_ref;
39 int dd_flags;
40
41 is_declarator = get_hv("Devel::Declare::declarators", FALSE);
42
43 if (!is_declarator)
44 return -1;
45
569ac469 46 /* $declarators{$current_package_name} */
47
72f20f69 48 is_declarator_pack_ref = hv_fetch(is_declarator, HvNAME(PL_curstash),
49 strlen(HvNAME(PL_curstash)), FALSE);
50
51 if (!is_declarator_pack_ref || !SvROK(*is_declarator_pack_ref))
52 return -1; /* not a hashref */
53
54 is_declarator_pack_hash = (HV*) SvRV(*is_declarator_pack_ref);
55
569ac469 56 /* $declarators{$current_package_name}{$name} */
57
72f20f69 58 is_declarator_flag_ref = hv_fetch(
59 is_declarator_pack_hash, name,
60 strlen(name), FALSE
61 );
62
63 /* requires SvIOK as well as TRUE since flags not being an int is useless */
64
65 if (!is_declarator_flag_ref
66 || !SvIOK(*is_declarator_flag_ref)
67 || !SvTRUE(*is_declarator_flag_ref))
68 return -1;
69
70 dd_flags = SvIVX(*is_declarator_flag_ref);
71
72 return dd_flags;
73}
74
569ac469 75/* callback thingy */
76
a9bd9b5e 77void dd_linestr_callback (pTHX_ char* type, char* name) {
569ac469 78
79 char* linestr = SvPVX(PL_linestr);
a9bd9b5e 80 int offset = PL_bufptr - linestr;
569ac469 81
569ac469 82 dSP;
83
84 ENTER;
85 SAVETMPS;
86
87 PUSHMARK(SP);
88 XPUSHs(sv_2mortal(newSVpv(type, 0)));
89 XPUSHs(sv_2mortal(newSVpv(name, 0)));
90 XPUSHs(sv_2mortal(newSViv(offset)));
91 PUTBACK;
92
04a8a223 93 call_pv("Devel::Declare::linestr_callback", G_VOID|G_DISCARD);
569ac469 94
569ac469 95 FREETMPS;
96 LEAVE;
97}
98
99char* dd_get_linestr(pTHX) {
100 return SvPVX(PL_linestr);
101}
102
103void dd_set_linestr(pTHX_ char* new_value) {
104 int new_len = strlen(new_value);
105 char* old_linestr = SvPVX(PL_linestr);
106
107 SvGROW(PL_linestr, strlen(new_value));
108
109 if (SvPVX(PL_linestr) != old_linestr)
110 Perl_croak(aTHX_ "forced to realloc PL_linestr for line %s, bailing out before we crash harder", SvPVX(PL_linestr));
111
112 memcpy(SvPVX(PL_linestr), new_value, new_len+1);
113
114 SvCUR_set(PL_linestr, new_len);
115
116 PL_bufend = SvPVX(PL_linestr) + new_len;
117}
118
04a8a223 119char* dd_get_lex_stuff(pTHX) {
120 return SvPVX(PL_lex_stuff);
121}
122
123char* dd_clear_lex_stuff(pTHX) {
124 PL_lex_stuff = Nullsv;
125}
126
127char* dd_get_curstash_name(pTHX) {
128 return HvNAME(PL_curstash);
129}
130
a9bd9b5e 131char* dd_move_past_token(pTHX_ char* s) {
923c07a8 132
133 /*
134 * buffer will be at the beginning of the declarator, -unless- the
135 * declarator is at EOL in which case it'll be the next useful line
136 * so we don't short-circuit out if we don't find the declarator
137 */
138
139 while (s < PL_bufend && isSPACE(*s)) s++;
140 if (memEQ(s, PL_tokenbuf, strlen(PL_tokenbuf)))
141 s += strlen(PL_tokenbuf);
142 return s;
143}
144
a9bd9b5e 145int dd_toke_move_past_token(pTHX_ int offset) {
04a8a223 146 char* base_s = SvPVX(PL_linestr) + offset;
147 char* s = dd_move_past_token(aTHX_ base_s);
148 return s - base_s;
149}
150
923c07a8 151int dd_toke_scan_word(pTHX_ int offset, int handle_package) {
152 char tmpbuf[sizeof PL_tokenbuf];
153 char* base_s = SvPVX(PL_linestr) + offset;
154 STRLEN len;
155 char* s = scan_word(base_s, tmpbuf, sizeof tmpbuf, handle_package, &len);
156 return s - base_s;
157}
158
159int dd_toke_scan_str(pTHX_ int offset) {
160 char* base_s = SvPVX(PL_linestr) + offset;
161 char* s = scan_str(base_s, FALSE, FALSE);
162 return s - base_s;
163}
164
165int dd_toke_skipspace(pTHX_ int offset) {
166 char* base_s = SvPVX(PL_linestr) + offset;
167 char* s = skipspace(base_s);
168 return s - base_s;
169}
170
94caac6e 171/* replacement PL_check rv2cv entry */
172
bedac9ff 173STATIC OP *(*dd_old_ck_rv2cv)(pTHX_ OP *op);
174
94caac6e 175STATIC OP *dd_ck_rv2cv(pTHX_ OP *o) {
176 OP* kid;
0ba8c7aa 177 int dd_flags;
9026391e 178 char* cb_args[6];
94caac6e 179
180 o = dd_old_ck_rv2cv(aTHX_ o); /* let the original do its job */
181
182 if (in_declare) {
a9bd9b5e 183 dSP;
184 PUSHMARK(SP);
185 call_pv("Devel::Declare::done_declare", G_VOID|G_DISCARD);
0ba8c7aa 186 in_declare--;
94caac6e 187 return o;
188 }
189
190 kid = cUNOPo->op_first;
191
192 if (kid->op_type != OP_GV) /* not a GV so ignore */
193 return o;
194
195 if (PL_lex_state != LEX_NORMAL && PL_lex_state != LEX_INTERPNORMAL)
196 return o; /* not lexing? */
197
72f20f69 198 dd_flags = dd_is_declarator(aTHX_ GvNAME(kGVOP_gv));
94caac6e 199
72f20f69 200 if (dd_flags == -1)
94caac6e 201 return o;
202
a9bd9b5e 203 dd_linestr_callback(aTHX_ "rv2cv", GvNAME(kGVOP_gv));
94caac6e 204
53e3ab32 205 return o;
206}
207
bedac9ff 208STATIC OP *(*dd_old_ck_entereval)(pTHX_ OP *op);
209
b7505981 210OP* dd_pp_entereval(pTHX) {
211 dSP;
212 dPOPss;
213 STRLEN len;
214 const char* s;
215 if (SvPOK(sv)) {
53e3ab32 216#ifdef DD_DEBUG
b7505981 217 printf("mangling eval sv\n");
53e3ab32 218#endif
b7505981 219 if (SvREADONLY(sv))
220 sv = sv_2mortal(newSVsv(sv));
221 s = SvPVX(sv);
222 len = SvCUR(sv);
223 if (!len || s[len-1] != ';') {
224 if (!(SvFLAGS(sv) & SVs_TEMP))
225 sv = sv_2mortal(newSVsv(sv));
226 sv_catpvn(sv, "\n;", 2);
53e3ab32 227 }
b7505981 228 SvGROW(sv, 8192);
53e3ab32 229 }
b7505981 230 PUSHs(sv);
231 return PL_ppaddr[OP_ENTEREVAL](aTHX);
232}
53e3ab32 233
b7505981 234STATIC OP *dd_ck_entereval(pTHX_ OP *o) {
235 o = dd_old_ck_entereval(aTHX_ o); /* let the original do its job */
d8e65fc8 236 if (o->op_ppaddr == PL_ppaddr[OP_ENTEREVAL])
237 o->op_ppaddr = dd_pp_entereval;
94caac6e 238 return o;
239}
240
6a0bcf35 241static I32 dd_filter_realloc(pTHX_ int idx, SV *sv, int maxlen)
242{
243 const I32 count = FILTER_READ(idx+1, sv, maxlen);
244 SvGROW(sv, 8192); /* please try not to have a line longer than this :) */
245 /* filter_del(dd_filter_realloc); */
246 return count;
247}
248
bedac9ff 249STATIC OP *(*dd_old_ck_const)(pTHX_ OP*op);
250
251STATIC OP *dd_ck_const(pTHX_ OP *o) {
bedac9ff 252 int dd_flags;
253 char* s;
04a8a223 254 char* name;
bedac9ff 255
256 o = dd_old_ck_const(aTHX_ o); /* let the original do its job */
257
bedac9ff 258 /* don't try and look this up if it's not a string const */
259 if (!SvPOK(cSVOPo->op_sv))
260 return o;
261
04a8a223 262 name = SvPVX(cSVOPo->op_sv);
263
264 dd_flags = dd_is_declarator(aTHX_ name);
bedac9ff 265
a9fb5fb1 266 if (dd_flags == -1)
bedac9ff 267 return o;
268
a9bd9b5e 269 dd_linestr_callback(aTHX_ "const", name);
bedac9ff 270
bedac9ff 271 return o;
272}
273
94caac6e 274static int initialized = 0;
275
276MODULE = Devel::Declare PACKAGE = Devel::Declare
277
278PROTOTYPES: DISABLE
279
280void
281setup()
282 CODE:
283 if (!initialized++) {
284 dd_old_ck_rv2cv = PL_check[OP_RV2CV];
285 PL_check[OP_RV2CV] = dd_ck_rv2cv;
b7505981 286 dd_old_ck_entereval = PL_check[OP_ENTEREVAL];
287 PL_check[OP_ENTEREVAL] = dd_ck_entereval;
bedac9ff 288 dd_old_ck_const = PL_check[OP_CONST];
289 PL_check[OP_CONST] = dd_ck_const;
94caac6e 290 }
6a0bcf35 291 filter_add(dd_filter_realloc, NULL);
569ac469 292
293char*
294get_linestr()
295 CODE:
296 RETVAL = dd_get_linestr(aTHX);
297 OUTPUT:
298 RETVAL
923c07a8 299
300void
301set_linestr(char* new_value)
302 CODE:
303 dd_set_linestr(aTHX_ new_value);
304
04a8a223 305char*
306get_lex_stuff()
307 CODE:
308 RETVAL = dd_get_lex_stuff(aTHX);
309 OUTPUT:
310 RETVAL
311
312void
313clear_lex_stuff()
314 CODE:
315 dd_clear_lex_stuff(aTHX);
316
317char*
318get_curstash_name()
319 CODE:
320 RETVAL = dd_get_curstash_name(aTHX);
321 OUTPUT:
322 RETVAL
323
923c07a8 324int
325toke_scan_word(int offset, int handle_package)
326 CODE:
327 RETVAL = dd_toke_scan_word(aTHX_ offset, handle_package);
328 OUTPUT:
329 RETVAL
330
331int
04a8a223 332toke_move_past_token(int offset);
333 CODE:
334 RETVAL = dd_toke_move_past_token(aTHX_ offset);
335 OUTPUT:
336 RETVAL
337
338int
923c07a8 339toke_scan_str(int offset);
340 CODE:
341 RETVAL = dd_toke_scan_str(aTHX_ offset);
342 OUTPUT:
343 RETVAL
344
345int
346toke_skipspace(int offset)
347 CODE:
348 RETVAL = dd_toke_skipspace(aTHX_ offset);
349 OUTPUT:
350 RETVAL
04a8a223 351
352int
353get_in_declare()
354 CODE:
355 RETVAL = in_declare;
356 OUTPUT:
357 RETVAL
358
359void
360set_in_declare(int value)
361 CODE:
362 in_declare = value;