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