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