X-Git-Url: http://git.shadowcat.co.uk/gitweb/gitweb.cgi?a=blobdiff_plain;f=Declare.xs;h=bbff3fd78926c55ae09d0b700ced1391206032ba;hb=daf381005ce960e2daebd1739ff6b4af96233179;hp=68f070dc3009a5810e9728f672bd651c49d8e18c;hpb=e807ee502b7c21edb01594764925aabdc8948f37;p=p5sagit%2FDevel-Declare.git diff --git a/Declare.xs b/Declare.xs index 68f070d..bbff3fd 100644 --- a/Declare.xs +++ b/Declare.xs @@ -9,13 +9,27 @@ #include #include +#if 0 +#define DD_DEBUG +#endif + +#define DD_HANDLE_NAME 1 +#define DD_HANDLE_PROTO 2 +#define DD_HANDLE_PACKAGE 8 + +#ifdef DD_DEBUG +#define DD_DEBUG_S printf("Buffer: %s\n", s); +#else +#define DD_DEBUG_S +#endif + #define LEX_NORMAL 10 #define LEX_INTERPNORMAL 9 /* placeholders for PL_check entries we wrap */ STATIC OP *(*dd_old_ck_rv2cv)(pTHX_ OP *op); -STATIC OP *(*dd_old_ck_nextstate)(pTHX_ OP *op); +STATIC OP *(*dd_old_ck_lineseq)(pTHX_ OP *op); /* flag to trigger removal of temporary declaree sub */ @@ -26,21 +40,28 @@ static int in_declare = 0; STATIC OP *dd_ck_rv2cv(pTHX_ OP *o) { OP* kid; char* s; + char* save_s; char tmpbuf[sizeof PL_tokenbuf]; - STRLEN len; + char found_name[sizeof PL_tokenbuf]; + char* found_proto = NULL; + STRLEN len = 0; HV *stash; HV* is_declarator; SV** is_declarator_pack_ref; HV* is_declarator_pack_hash; SV** is_declarator_flag_ref; - char* cb_args[4]; + int dd_flags; + char* cb_args[6]; + dSP; /* define stack pointer for later call stuff */ + char* retstr; + STRLEN n_a; /* for POPpx */ o = dd_old_ck_rv2cv(aTHX_ o); /* let the original do its job */ if (in_declare) { cb_args[0] = NULL; call_argv("Devel::Declare::done_declare", G_VOID|G_DISCARD, cb_args); - in_declare = 0; + in_declare--; return o; } @@ -54,7 +75,9 @@ STATIC OP *dd_ck_rv2cv(pTHX_ OP *o) { stash = GvSTASH(kGVOP_gv); - /* printf("Checking GV %s -> %s\n", HvNAME(stash), GvNAME(kGVOP_gv)); */ +#ifdef DD_DEBUG + printf("Checking GV %s -> %s\n", HvNAME(stash), GvNAME(kGVOP_gv)); +#endif is_declarator = get_hv("Devel::Declare::declarators", FALSE); @@ -72,33 +95,167 @@ STATIC OP *dd_ck_rv2cv(pTHX_ OP *o) { is_declarator_flag_ref = hv_fetch(is_declarator_pack_hash, GvNAME(kGVOP_gv), strlen(GvNAME(kGVOP_gv)), FALSE); - if (!is_declarator_flag_ref || !SvTRUE(*is_declarator_flag_ref)) + /* requires SvIOK as well as TRUE since flags not being an int is useless */ + + if (!is_declarator_flag_ref + || !SvIOK(*is_declarator_flag_ref) + || !SvTRUE(*is_declarator_flag_ref)) return o; + dd_flags = SvIVX(*is_declarator_flag_ref); + +#ifdef DD_DEBUG + printf("dd_flags are: %i\n", dd_flags); +#endif + s = PL_bufptr; /* copy the current buffer pointer */ + DD_DEBUG_S + +#ifdef DD_DEBUG + printf("PL_tokenbuf: %s\n", PL_tokenbuf); +#endif + + /* + * buffer will be at the beginning of the declarator, -unless- the + * declarator is at EOL in which case it'll be the next useful line + * so we don't short-circuit out if we don't find the declarator + */ + while (s < PL_bufend && isSPACE(*s)) s++; if (memEQ(s, PL_tokenbuf, strlen(PL_tokenbuf))) s += strlen(PL_tokenbuf); - else - return o; - /* find next word */ + DD_DEBUG_S - s = skipspace(s); + if (dd_flags & DD_HANDLE_NAME) { - /* 0 in arg 4 is allow_package - not trying that yet :) */ + /* find next word */ - s = scan_word(s, tmpbuf, sizeof tmpbuf, 0, &len); + s = skipspace(s); - if (len) { - cb_args[0] = HvNAME(stash); - cb_args[1] = GvNAME(kGVOP_gv); - cb_args[2] = tmpbuf; - cb_args[3] = NULL; - call_argv("Devel::Declare::init_declare", G_VOID|G_DISCARD, cb_args); + DD_DEBUG_S + + /* arg 4 is allow_package */ + + s = scan_word(s, tmpbuf, sizeof tmpbuf, dd_flags & DD_HANDLE_PACKAGE, &len); + + DD_DEBUG_S + + if (len) { + strcpy(found_name, tmpbuf); +#ifdef DD_DEBUG + printf("Found %s\n", found_name); +#endif + } + } + + if (dd_flags & DD_HANDLE_PROTO) { + + s = skipspace(s); + + if (*s == '(') { /* found a prototype-ish thing */ + save_s = s; + s = scan_str(s, FALSE, FALSE); /* no keep_quoted, no keep_delims */ + if (SvPOK(PL_lex_stuff)) { +#ifdef DD_DEBUG + printf("Found proto %s\n", SvPVX(PL_lex_stuff)); +#endif + found_proto = SvPVX(PL_lex_stuff); + if (len) /* foo name () => foo name X, only foo parsed so works */ + *save_s++ = ' '; + else /* foo () => foo =X, TOKEN('&') won't handle foo X */ + *save_s++ = '='; + *save_s++ = 'X'; + while (save_s < s) { + *save_s++ = ' '; + } +#ifdef DD_DEBUG + printf("Curbuf %s\n", PL_bufptr); +#endif + } + } + } + + if (!len) + found_name[0] = 0; + +#ifdef DD_DEBUG + printf("Calling init_declare\n"); +#endif + cb_args[0] = HvNAME(stash); + cb_args[1] = GvNAME(kGVOP_gv); + cb_args[2] = HvNAME(PL_curstash); + cb_args[3] = found_name; + cb_args[4] = found_proto; + cb_args[5] = NULL; + + if (len && found_proto) + in_declare = 2; + else if (len || found_proto) in_declare = 1; + if (found_proto) + PL_lex_stuff = Nullsv; + s = skipspace(s); +#ifdef DD_DEBUG + printf("cur buf: %s\n", s); + printf("bufend at: %i\n", PL_bufend - s); + printf("linestr: %s\n", SvPVX(PL_linestr)); + printf("linestr len: %i\n", PL_bufend - SvPVX(PL_linestr)); +#endif + if (*s++ == '{') { + call_argv("Devel::Declare::init_declare", G_SCALAR, cb_args); + SPAGAIN; + retstr = POPpx; + PUTBACK; + if (retstr && strlen(retstr)) { +#ifdef DD_DEBUG + printf("Got string %s\n", retstr); +#endif + SvGROW(PL_linestr, strlen(retstr)); + memmove(s+strlen(retstr), s, (PL_bufend - s)+1); + memmove(s, retstr, strlen(retstr)); + PL_bufend += strlen(retstr); +#ifdef DD_DEBUG + printf("cur buf: %s\n", s); + printf("bufend at: %i\n", PL_bufend - s); + printf("linestr: %s\n", SvPVX(PL_linestr)); + printf("linestr len: %i\n", PL_bufend - SvPVX(PL_linestr)); +#endif + } + } else { + call_argv("Devel::Declare::init_declare", G_VOID|G_DISCARD, cb_args); } + return o; +} + +STATIC OP *dd_ck_lineseq(pTHX_ OP *o) { + AV* pad_inject_list; + SV** to_inject_ref; + int i, pad_inject_list_last; + + o = dd_old_ck_lineseq(aTHX_ o); + + pad_inject_list = get_av("Devel::Declare::next_pad_inject", FALSE); + if (!pad_inject_list) + return o; + + pad_inject_list_last = av_len(pad_inject_list); + + if (pad_inject_list_last == -1) + return o; + + for (i = 0; i <= pad_inject_list_last; i++) { + to_inject_ref = av_fetch(pad_inject_list, i, FALSE); + if (to_inject_ref && SvPOK(*to_inject_ref)) { +#ifdef DD_DEBUG + printf("Injecting %s into pad\n", SvPVX(*to_inject_ref)); +#endif + allocmy(SvPVX(*to_inject_ref)); + } + } + + av_clear(pad_inject_list); return o; } @@ -115,6 +272,8 @@ setup() if (!initialized++) { dd_old_ck_rv2cv = PL_check[OP_RV2CV]; PL_check[OP_RV2CV] = dd_ck_rv2cv; + dd_old_ck_lineseq = PL_check[OP_LINESEQ]; + PL_check[OP_LINESEQ] = dd_ck_lineseq; } void