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