diff options
author | Lukas Mai <l.mai@web.de> | 2014-10-25 12:25:14 +0200 |
---|---|---|
committer | Father Chrysostomos <sprout@cpan.org> | 2014-10-25 11:56:32 -0700 |
commit | 25f5d540536c9ee920ad9bdc29e43e3284465acb (patch) | |
tree | 62f0c4973c83bc872ad0e9bedfe4da325562d81f /ext/XS-APItest | |
parent | 96801525df66a32483d0872bdbfffea111d7add5 (diff) | |
download | perl-25f5d540536c9ee920ad9bdc29e43e3284465acb.tar.gz |
APIfy block_start/block_end/intro_my
Diffstat (limited to 'ext/XS-APItest')
-rw-r--r-- | ext/XS-APItest/APItest.pm | 4 | ||||
-rw-r--r-- | ext/XS-APItest/APItest.xs | 89 | ||||
-rw-r--r-- | ext/XS-APItest/t/synthetic_scope.t | 42 |
3 files changed, 133 insertions, 2 deletions
diff --git a/ext/XS-APItest/APItest.pm b/ext/XS-APItest/APItest.pm index a5953c62aa..9cca610b1c 100644 --- a/ext/XS-APItest/APItest.pm +++ b/ext/XS-APItest/APItest.pm @@ -5,7 +5,7 @@ use strict; use warnings; use Carp; -our $VERSION = '0.66'; +our $VERSION = '0.67'; require XSLoader; @@ -40,7 +40,7 @@ sub import { } } foreach (keys %{$exports||{}}) { - next unless /\A(?:rpn|calcrpn|stufftest|swaptwostmts|looprest|scopelessblock|stmtasexpr|stmtsasexpr|loopblock|blockasexpr|swaplabel|labelconst|arrayfullexpr|arraylistexpr|arraytermexpr|arrayarithexpr|arrayexprflags|DEFSV)\z/; + next unless /\A(?:rpn|calcrpn|stufftest|swaptwostmts|looprest|scopelessblock|stmtasexpr|stmtsasexpr|loopblock|blockasexpr|swaplabel|labelconst|arrayfullexpr|arraylistexpr|arraytermexpr|arrayarithexpr|arrayexprflags|DEFSV|with_vars)\z/; $^H{"XS::APItest/$_"} = 1; delete $exports->{$_}; } diff --git a/ext/XS-APItest/APItest.xs b/ext/XS-APItest/APItest.xs index de0b2eb045..ccdc8d5def 100644 --- a/ext/XS-APItest/APItest.xs +++ b/ext/XS-APItest/APItest.xs @@ -663,6 +663,7 @@ static SV *hintkey_arrayfullexpr_sv, *hintkey_arraylistexpr_sv; static SV *hintkey_arraytermexpr_sv, *hintkey_arrayarithexpr_sv; static SV *hintkey_arrayexprflags_sv; static SV *hintkey_DEFSV_sv; +static SV *hintkey_with_vars_sv; static int (*next_keyword_plugin)(pTHX_ char *, STRLEN, OP **); /* low-level parser helpers */ @@ -958,6 +959,89 @@ static OP *THX_parse_keyword_DEFSV(pTHX) return newDEFSVOP(); } +static void sv_cat_c(pTHX_ SV *sv, U32 c) { + char ds[UTF8_MAXBYTES + 1], *d; + d = (char *)uvchr_to_utf8((U8 *)ds, c); + if (d - ds > 1) { + sv_utf8_upgrade(sv); + } + sv_catpvn(sv, ds, d - ds); +} + +#define parse_keyword_with_vars() THX_parse_keyword_with_vars(aTHX) +static OP *THX_parse_keyword_with_vars(pTHX) +{ + I32 c; + IV count; + int save_ix; + OP *vardeclseq, *body; + + save_ix = block_start(TRUE); + vardeclseq = NULL; + + count = 0; + + lex_read_space(0); + c = lex_peek_unichar(0); + while (c != '{') { + SV *varname; + PADOFFSET padoff; + + if (c == -1) { + croak("unexpected EOF; expecting '{'"); + } + + if (!isIDFIRST_uni(c)) { + croak("unexpected '%c'; expecting an identifier", (int)c); + } + + varname = newSVpvs("$"); + if (lex_bufutf8()) { + SvUTF8_on(varname); + } + + sv_cat_c(varname, c); + lex_read_unichar(0); + + while (c = lex_peek_unichar(0), c != -1 && isIDCONT_uni(c)) { + sv_cat_c(varname, c); + lex_read_unichar(0); + } + + padoff = pad_add_name_sv(varname, padadd_NO_DUP_CHECK, NULL, NULL); + + { + OP *my_var = newOP(OP_PADSV, OPf_MOD | (OPpLVAL_INTRO << 8)); + my_var->op_targ = padoff; + + vardeclseq = op_append_list( + OP_LINESEQ, + vardeclseq, + newSTATEOP( + 0, NULL, + newASSIGNOP( + OPf_STACKED, + my_var, 0, + newSVOP( + OP_CONST, 0, + newSViv(++count) + ) + ) + ) + ); + } + + lex_read_space(0); + c = lex_peek_unichar(0); + } + + intro_my(); + + body = parse_block(0); + + return block_end(save_ix, op_append_list(OP_LINESEQ, vardeclseq, body)); +} + /* plugin glue */ #define keyword_active(hintkey_sv) THX_keyword_active(aTHX_ hintkey_sv) @@ -1046,6 +1130,10 @@ static int my_keyword_plugin(pTHX_ keyword_active(hintkey_DEFSV_sv)) { *op_ptr = parse_keyword_DEFSV(); return KEYWORD_PLUGIN_EXPR; + } else if(keyword_len == 9 && strnEQ(keyword_ptr, "with_vars", 9) && + keyword_active(hintkey_with_vars_sv)) { + *op_ptr = parse_keyword_with_vars(); + return KEYWORD_PLUGIN_STMT; } else { return next_keyword_plugin(aTHX_ keyword_ptr, keyword_len, op_ptr); } @@ -3333,6 +3421,7 @@ BOOT: hintkey_arrayarithexpr_sv = newSVpvs_share("XS::APItest/arrayarithexpr"); hintkey_arrayexprflags_sv = newSVpvs_share("XS::APItest/arrayexprflags"); hintkey_DEFSV_sv = newSVpvs_share("XS::APItest/DEFSV"); + hintkey_with_vars_sv = newSVpvs_share("XS::APItest/with_vars"); next_keyword_plugin = PL_keyword_plugin; PL_keyword_plugin = my_keyword_plugin; } diff --git a/ext/XS-APItest/t/synthetic_scope.t b/ext/XS-APItest/t/synthetic_scope.t new file mode 100644 index 0000000000..43a758f077 --- /dev/null +++ b/ext/XS-APItest/t/synthetic_scope.t @@ -0,0 +1,42 @@ +#!perl + +use strict; +use warnings; + +use Test::More tests => 18; + +use XS::APItest qw(with_vars); + +my $foo = "A"; my $rfoo = \$foo; +my $bar = "B"; my $rbar = \$bar; +my $baz = "C"; my $rbaz = \$baz; + +with_vars foo bar baz { + is $foo, 1; + is $$rfoo, "A"; + isnt \$foo, $rfoo; + + is $bar, 2; + is $$rbar, "B"; + isnt \$bar, $rbar; + + is $baz, 3; + is $$rbaz, "C"; + isnt \$baz, $rbaz; +} + +is $foo, "A"; +is \$foo, $rfoo; + +is $bar, "B"; +is \$bar, $rbar; + +is $baz, "C"; +is \$baz, $rbaz; + +with_vars x { + is $x, 1; +} + +is eval('$x++'), undef; +like $@, qr/explicit package name/; |