X-Git-Url: http://git.shadowcat.co.uk/gitweb/gitweb.cgi?a=blobdiff_plain;f=Declare.xs;h=bcde6dfe8c84b2f6ea852818496f0553749930f2;hb=569ac4695601dc2f30048121ebde7b2dab24d20b;hp=d15042ae495550eb519934ea080c6c45ec32b854;hpb=6a0bcf35eb9c731c1cb0fc9dc2b11a8265b86f37;p=p5sagit%2FDevel-Declare.git diff --git a/Declare.xs b/Declare.xs index d15042a..bcde6df 100644 --- a/Declare.xs +++ b/Declare.xs @@ -8,7 +8,14 @@ #include #include +#ifndef Newx +# define Newx(v,n,t) New(0,v,n,t) +#endif /* !Newx */ + +#if 1 #define DD_HAS_TRAITS +#endif + #if 0 #define DD_DEBUG #endif @@ -26,17 +33,112 @@ #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_lineseq)(pTHX_ OP *op); - /* flag to trigger removal of temporary declaree sub */ static int in_declare = 0; +/* thing that decides whether we're dealing with a declarator */ + +int dd_is_declarator(pTHX_ char* name) { + HV* is_declarator; + SV** is_declarator_pack_ref; + HV* is_declarator_pack_hash; + SV** is_declarator_flag_ref; + int dd_flags; + + is_declarator = get_hv("Devel::Declare::declarators", FALSE); + + if (!is_declarator) + return -1; + + /* $declarators{$current_package_name} */ + + is_declarator_pack_ref = hv_fetch(is_declarator, HvNAME(PL_curstash), + strlen(HvNAME(PL_curstash)), FALSE); + + if (!is_declarator_pack_ref || !SvROK(*is_declarator_pack_ref)) + return -1; /* not a hashref */ + + is_declarator_pack_hash = (HV*) SvRV(*is_declarator_pack_ref); + + /* $declarators{$current_package_name}{$name} */ + + is_declarator_flag_ref = hv_fetch( + is_declarator_pack_hash, name, + strlen(name), FALSE + ); + + /* 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 -1; + + dd_flags = SvIVX(*is_declarator_flag_ref); + + return dd_flags; +} + +/* callback thingy */ + +void dd_linestr_callback (pTHX_ char* type, char* name, char* s) { + + char* linestr = SvPVX(PL_linestr); + int offset = s - linestr; + + char* new_linestr; + int count; + + dSP; + + ENTER; + SAVETMPS; + + PUSHMARK(SP); + XPUSHs(sv_2mortal(newSVpv(type, 0))); + XPUSHs(sv_2mortal(newSVpv(name, 0))); + XPUSHs(sv_2mortal(newSViv(offset))); + PUTBACK; + + count = call_pv("Devel::Declare::linestr_callback", G_SCALAR); + + SPAGAIN; + + if (count != 1) + Perl_croak(aTHX_ "linestr_callback didn't return a value, bailing out"); + + printf("linestr_callback returned: %s\n", POPp); + + PUTBACK; + FREETMPS; + LEAVE; +} + +char* dd_get_linestr(pTHX) { + return SvPVX(PL_linestr); +} + +void dd_set_linestr(pTHX_ char* new_value) { + int new_len = strlen(new_value); + char* old_linestr = SvPVX(PL_linestr); + + SvGROW(PL_linestr, strlen(new_value)); + + if (SvPVX(PL_linestr) != old_linestr) + Perl_croak(aTHX_ "forced to realloc PL_linestr for line %s, bailing out before we crash harder", SvPVX(PL_linestr)); + + memcpy(SvPVX(PL_linestr), new_value, new_len+1); + + SvCUR_set(PL_linestr, new_len); + + PL_bufend = SvPVX(PL_linestr) + new_len; +} + /* replacement PL_check rv2cv entry */ +STATIC OP *(*dd_old_ck_rv2cv)(pTHX_ OP *op); + STATIC OP *dd_ck_rv2cv(pTHX_ OP *o) { OP* kid; char* s; @@ -45,11 +147,6 @@ STATIC OP *dd_ck_rv2cv(pTHX_ OP *o) { char found_name[sizeof PL_tokenbuf]; char* found_proto = NULL, *found_traits = NULL; STRLEN len = 0; - HV *stash; - HV* is_declarator; - SV** is_declarator_pack_ref; - HV* is_declarator_pack_hash; - SV** is_declarator_flag_ref; int dd_flags; char* cb_args[6]; dSP; /* define stack pointer for later call stuff */ @@ -87,37 +184,18 @@ STATIC OP *dd_ck_rv2cv(pTHX_ OP *o) { if (PL_lex_state != LEX_NORMAL && PL_lex_state != LEX_INTERPNORMAL) return o; /* not lexing? */ - stash = GvSTASH(kGVOP_gv); + /* I was doing this, but the CONST wrap can't so it didn't gain anything + stash = GvSTASH(kGVOP_gv); */ #ifdef DD_DEBUG - printf("Checking GV %s -> %s\n", HvNAME(stash), GvNAME(kGVOP_gv)); + printf("Checking GV %s -> %s\n", HvNAME(GvSTASH(kGVOP_gv)), GvNAME(kGVOP_gv)); #endif - is_declarator = get_hv("Devel::Declare::declarators", FALSE); - - if (!is_declarator) - return o; - - is_declarator_pack_ref = hv_fetch(is_declarator, HvNAME(stash), - strlen(HvNAME(stash)), FALSE); - - if (!is_declarator_pack_ref || !SvROK(*is_declarator_pack_ref)) - return o; /* not a hashref */ - - is_declarator_pack_hash = (HV*) SvRV(*is_declarator_pack_ref); + dd_flags = dd_is_declarator(aTHX_ GvNAME(kGVOP_gv)); - is_declarator_flag_ref = hv_fetch(is_declarator_pack_hash, GvNAME(kGVOP_gv), - strlen(GvNAME(kGVOP_gv)), FALSE); - - /* 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)) + if (dd_flags == -1) return o; - dd_flags = SvIVX(*is_declarator_flag_ref); - #ifdef DD_DEBUG printf("dd_flags are: %i\n", dd_flags); #endif @@ -150,6 +228,12 @@ STATIC OP *dd_ck_rv2cv(pTHX_ OP *o) { DD_DEBUG_S + /* kill the :: added in the ck_const */ + if (*s == ':') + *s++ = ' '; + if (*s == ':') + *s++ = ' '; + /* arg 4 is allow_package */ s = scan_word(s, tmpbuf, sizeof tmpbuf, dd_flags & DD_HANDLE_PACKAGE, &len); @@ -214,7 +298,7 @@ STATIC OP *dd_ck_rv2cv(pTHX_ OP *o) { #ifdef DD_DEBUG printf("Calling init_declare\n"); #endif - cb_args[0] = HvNAME(stash); + cb_args[0] = HvNAME(PL_curstash); cb_args[1] = GvNAME(kGVOP_gv); cb_args[2] = HvNAME(PL_curstash); cb_args[3] = found_name; @@ -235,6 +319,7 @@ STATIC OP *dd_ck_rv2cv(pTHX_ OP *o) { 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; @@ -249,7 +334,7 @@ STATIC OP *dd_ck_rv2cv(pTHX_ OP *o) { #endif SvGROW(PL_linestr, (STRLEN)(old_len + strlen(retstr))); if (start_diff = SvPVX(PL_linestr) - old_start) { - Perl_croak("forced to realloc PL_linestr for line %s, bailing out before we crash harder", SvPVX(PL_linestr)); + Perl_croak(aTHX_ "forced to realloc PL_linestr for line %s, bailing out before we crash harder", SvPVX(PL_linestr)); } memmove(s+strlen(retstr), s, (PL_bufend - s)+1); memmove(s, retstr, strlen(retstr)); @@ -270,34 +355,36 @@ STATIC OP *dd_ck_rv2cv(pTHX_ OP *o) { 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; +STATIC OP *(*dd_old_ck_entereval)(pTHX_ OP *op); - 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)) { +OP* dd_pp_entereval(pTHX) { + dSP; + dPOPss; + STRLEN len; + const char* s; + if (SvPOK(sv)) { #ifdef DD_DEBUG - printf("Injecting %s into pad\n", SvPVX(*to_inject_ref)); + printf("mangling eval sv\n"); #endif - allocmy(SvPVX(*to_inject_ref)); + if (SvREADONLY(sv)) + sv = sv_2mortal(newSVsv(sv)); + s = SvPVX(sv); + len = SvCUR(sv); + if (!len || s[len-1] != ';') { + if (!(SvFLAGS(sv) & SVs_TEMP)) + sv = sv_2mortal(newSVsv(sv)); + sv_catpvn(sv, "\n;", 2); } + SvGROW(sv, 8192); } + PUSHs(sv); + return PL_ppaddr[OP_ENTEREVAL](aTHX); +} - av_clear(pad_inject_list); - +STATIC OP *dd_ck_entereval(pTHX_ OP *o) { + o = dd_old_ck_entereval(aTHX_ o); /* let the original do its job */ + if (o->op_ppaddr == PL_ppaddr[OP_ENTEREVAL]) + o->op_ppaddr = dd_pp_entereval; return o; } @@ -309,6 +396,81 @@ static I32 dd_filter_realloc(pTHX_ int idx, SV *sv, int maxlen) return count; } +STATIC OP *(*dd_old_ck_const)(pTHX_ OP*op); + +STATIC OP *dd_ck_const(pTHX_ OP *o) { + int dd_flags; + char* s; + char tmpbuf[sizeof PL_tokenbuf]; + char found_name[sizeof PL_tokenbuf]; + STRLEN len = 0; + + o = dd_old_ck_const(aTHX_ o); /* let the original do its job */ + + /* don't try and look this up if it's not a string const */ + if (!SvPOK(cSVOPo->op_sv)) + return o; + + dd_flags = dd_is_declarator(aTHX_ SvPVX(cSVOPo->op_sv)); + + if (dd_flags == -1) + return o; + + if (!(dd_flags & DD_HANDLE_NAME)) + return o; /* if we're not handling name, method intuiting not an issue */ + +#ifdef DD_DEBUG + printf("Think I found a declarator %s\n", PL_tokenbuf); + printf("linestr: %s\n", SvPVX(PL_linestr)); +#endif + + s = PL_bufptr; + + while (s < PL_bufend && isSPACE(*s)) s++; + if (memEQ(s, PL_tokenbuf, strlen(PL_tokenbuf))) + s += strlen(PL_tokenbuf); + + /* dd_linestr_callback(aTHX_ "const", SvPVX(cSVOPo->op_sv), s); */ + + DD_DEBUG_S + + /* find next word */ + + s = skipspace(s); + + 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) { + const char* old_start = SvPVX(PL_linestr); + int start_diff; + const int old_len = SvCUR(PL_linestr); + + strcpy(found_name, tmpbuf); +#ifdef DD_DEBUG + printf("Found %s\n", found_name); +#endif + + s -= len; + SvGROW(PL_linestr, (STRLEN)(old_len + 2)); + if (start_diff = SvPVX(PL_linestr) - old_start) { + Perl_croak(aTHX_ "forced to realloc PL_linestr for line %s, bailing out before we crash harder", SvPVX(PL_linestr)); + } + memmove(s+2, s, (PL_bufend - s)+1); + *s = ':'; + s++; + *s = ':'; + SvCUR_set(PL_linestr, old_len + 2); + PL_bufend += 2; + } + return o; +} + static int initialized = 0; MODULE = Devel::Declare PACKAGE = Devel::Declare @@ -321,5 +483,16 @@ setup() if (!initialized++) { dd_old_ck_rv2cv = PL_check[OP_RV2CV]; PL_check[OP_RV2CV] = dd_ck_rv2cv; + dd_old_ck_entereval = PL_check[OP_ENTEREVAL]; + PL_check[OP_ENTEREVAL] = dd_ck_entereval; + dd_old_ck_const = PL_check[OP_CONST]; + PL_check[OP_CONST] = dd_ck_const; } filter_add(dd_filter_realloc, NULL); + +char* +get_linestr() + CODE: + RETVAL = dd_get_linestr(aTHX); + OUTPUT: + RETVAL