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