fun ($a, $b) { ... }
[p5sagit/Devel-Declare.git] / Declare.xs
CommitLineData
e807ee50 1#define PERL_IN_TOKE_C
94caac6e 2#define PERL_CORE
3#define PERL_NO_GET_CONTEXT
94caac6e 4#include "EXTERN.h"
5#include "perl.h"
6#include "XSUB.h"
7#undef printf
e807ee50 8#include "stolen_chunk_of_toke.c"
94caac6e 9#include <stdio.h>
10#include <string.h>
11
c630715a 12#define DD_DEBUG 0
13
0ba8c7aa 14#define DD_HANDLE_NAME 1
15#define DD_HANDLE_PROTO 2
16
c630715a 17#ifdef DD_DEBUG
18#define DD_DEBUG_S printf("Buffer: %s\n", s);
19#else
20#define DD_DEBUG_S
21#endif
22
94caac6e 23#define LEX_NORMAL 10
24#define LEX_INTERPNORMAL 9
25
26/* placeholders for PL_check entries we wrap */
27
28STATIC OP *(*dd_old_ck_rv2cv)(pTHX_ OP *op);
29STATIC OP *(*dd_old_ck_nextstate)(pTHX_ OP *op);
30
31/* flag to trigger removal of temporary declaree sub */
32
33static int in_declare = 0;
34
35/* replacement PL_check rv2cv entry */
36
37STATIC OP *dd_ck_rv2cv(pTHX_ OP *o) {
38 OP* kid;
39 char* s;
0ba8c7aa 40 char* save_s;
94caac6e 41 char tmpbuf[sizeof PL_tokenbuf];
0ba8c7aa 42 char found_name[sizeof PL_tokenbuf];
43 char* found_proto = NULL;
44 STRLEN len = 0;
94caac6e 45 HV *stash;
46 HV* is_declarator;
47 SV** is_declarator_pack_ref;
48 HV* is_declarator_pack_hash;
49 SV** is_declarator_flag_ref;
0ba8c7aa 50 int dd_flags;
51 char* cb_args[5];
94caac6e 52
53 o = dd_old_ck_rv2cv(aTHX_ o); /* let the original do its job */
54
55 if (in_declare) {
56 cb_args[0] = NULL;
57 call_argv("Devel::Declare::done_declare", G_VOID|G_DISCARD, cb_args);
0ba8c7aa 58 in_declare--;
94caac6e 59 return o;
60 }
61
62 kid = cUNOPo->op_first;
63
64 if (kid->op_type != OP_GV) /* not a GV so ignore */
65 return o;
66
67 if (PL_lex_state != LEX_NORMAL && PL_lex_state != LEX_INTERPNORMAL)
68 return o; /* not lexing? */
69
70 stash = GvSTASH(kGVOP_gv);
71
c630715a 72#ifdef DD_DEBUG
73 printf("Checking GV %s -> %s\n", HvNAME(stash), GvNAME(kGVOP_gv));
74#endif
94caac6e 75
76 is_declarator = get_hv("Devel::Declare::declarators", FALSE);
77
78 if (!is_declarator)
79 return o;
80
81 is_declarator_pack_ref = hv_fetch(is_declarator, HvNAME(stash),
82 strlen(HvNAME(stash)), FALSE);
83
84 if (!is_declarator_pack_ref || !SvROK(*is_declarator_pack_ref))
85 return o; /* not a hashref */
86
87 is_declarator_pack_hash = (HV*) SvRV(*is_declarator_pack_ref);
88
89 is_declarator_flag_ref = hv_fetch(is_declarator_pack_hash, GvNAME(kGVOP_gv),
90 strlen(GvNAME(kGVOP_gv)), FALSE);
91
0ba8c7aa 92 /* requires SvIOK as well as TRUE since flags not being an int is useless */
93
94 if (!is_declarator_flag_ref
95 || !SvIOK(*is_declarator_flag_ref)
96 || !SvTRUE(*is_declarator_flag_ref))
94caac6e 97 return o;
98
0ba8c7aa 99 dd_flags = SvIVX(*is_declarator_flag_ref);
100
101#ifdef DD_DEBUG
102 printf("dd_flags are: %i\n", dd_flags);
103#endif
104
94caac6e 105 s = PL_bufptr; /* copy the current buffer pointer */
106
c630715a 107 DD_DEBUG_S
108
109#ifdef DD_DEBUG
0ba8c7aa 110 printf("PL_tokenbuf: %s\n", PL_tokenbuf);
c630715a 111#endif
112
113 /*
114 * buffer will be at the beginning of the declarator, -unless- the
115 * declarator is at EOL in which case it'll be the next useful line
116 * so we don't short-circuit out if we don't find the declarator
117 */
118
94caac6e 119 while (s < PL_bufend && isSPACE(*s)) s++;
120 if (memEQ(s, PL_tokenbuf, strlen(PL_tokenbuf)))
121 s += strlen(PL_tokenbuf);
c630715a 122
123 DD_DEBUG_S
94caac6e 124
0ba8c7aa 125 if (dd_flags & DD_HANDLE_NAME) {
94caac6e 126
0ba8c7aa 127 /* find next word */
94caac6e 128
0ba8c7aa 129 s = skipspace(s);
c630715a 130
0ba8c7aa 131 DD_DEBUG_S
94caac6e 132
0ba8c7aa 133 /* 0 in arg 4 is allow_package - not trying that yet :) */
94caac6e 134
0ba8c7aa 135 s = scan_word(s, tmpbuf, sizeof tmpbuf, 0, &len);
136
137 DD_DEBUG_S
c630715a 138
0ba8c7aa 139 if (len) {
140 strcpy(found_name, tmpbuf);
141#ifdef DD_DEBUG
142 printf("Found %s\n", found_name);
143#endif
144 }
145 }
146
147 if (dd_flags & DD_HANDLE_PROTO) {
148
149 s = skipspace(s);
150
151 if (*s == '(') { /* found a prototype-ish thing */
152 save_s = s;
153 s = scan_str(s, FALSE, FALSE); /* no keep_quoted, no keep_delims */
154 if (SvPOK(PL_lex_stuff)) {
155#ifdef DD_DEBUG
156 printf("Found proto %s\n", SvPVX(PL_lex_stuff));
157#endif
158 found_proto = SvPVX(PL_lex_stuff);
159 *save_s++ = '=';
160 *save_s++ = 'X';
161 while (save_s < s) {
162 *save_s++ = ' ';
163 }
164#ifdef DD_DEBUG
165 printf("Curbuf %s\n", PL_bufptr);
166#endif
167 }
168 }
169 }
170
171 if (len || found_proto) {
172 if (!len)
173 found_name[0] = 0;
174#ifdef DD_DEBUG
175 printf("Calling init_declare");
176#endif
94caac6e 177 cb_args[0] = HvNAME(stash);
178 cb_args[1] = GvNAME(kGVOP_gv);
0ba8c7aa 179 cb_args[2] = found_name;
180 cb_args[3] = found_proto;
181 cb_args[4] = NULL;
94caac6e 182 call_argv("Devel::Declare::init_declare", G_VOID|G_DISCARD, cb_args);
0ba8c7aa 183 if (len && found_proto)
184 in_declare = 2;
185 else
186 in_declare = 1;
187 if (found_proto)
188 PL_lex_stuff = Nullsv;
94caac6e 189 }
190
191 return o;
192}
193
194static int initialized = 0;
195
196MODULE = Devel::Declare PACKAGE = Devel::Declare
197
198PROTOTYPES: DISABLE
199
200void
201setup()
202 CODE:
203 if (!initialized++) {
204 dd_old_ck_rv2cv = PL_check[OP_RV2CV];
205 PL_check[OP_RV2CV] = dd_ck_rv2cv;
206 }
207
208void
209teardown()
210 CODE:
211 /* ensure we only uninit when number of teardown calls matches
212 number of setup calls */
213 if (initialized && !--initialized) {
214 PL_check[OP_RV2CV] = dd_old_ck_rv2cv;
215 }