Codebase list libkeyword-simple-perl / 02075e6
New upstream version 0.04 Salvatore Bonaccorso 6 years ago
15 changed file(s) with 583 addition(s) and 316 deletion(s). Raw diff Collapse all Expand all
00 Revision history for Keyword-Simple
1
2 0.04 2017-09-08
3 - Fix crash when using keywords in string eval (RT #122983).
4 - Document that keywords are broken in s//.../e.
15
26 0.03 2014-10-19
37 - Add note to POD about requiring perl v5.12.
00 Changes
1 lib/Keyword/Simple.pm
2 Makefile.PL
3 Makefile_PL_settings.plx
14 MANIFEST
25 MANIFEST.SKIP
3 Makefile.PL
4 README
56 Simple.xs
6 lib/Keyword/Simple.pm
77 t/00-load.t
88 t/basic.t
9 t/eval.t
910 t/lineno.t
10 t/pod.t
11 xt/pod.t
1112 META.yml Module YAML meta-data (added by MakeMaker)
1213 META.json Module JSON meta-data (added by MakeMaker)
14 README generated from Keyword::Simple POD (added by maint/eumm-fixup.pl)
00 \.tar\.gz$
11 ^Build$
22 ^Keyword-Simple-
3 ^GNUmakefile$
43 ^MANIFEST\.(?!SKIP$)
54 ^MYMETA\.
65 ^Makefile$
1312 ^pm_to_blib
1413 ^remote$
1514 ^untracked
15 ^maint/
22 "author" : [
33 "Lukas Mai <l.mai@web.de>"
44 ],
5 "dynamic_config" : 1,
6 "generated_by" : "ExtUtils::MakeMaker version 6.98, CPAN::Meta::Converter version 2.140640",
5 "dynamic_config" : 0,
6 "generated_by" : "ExtUtils::MakeMaker version 7.3, CPAN::Meta::Converter version 2.150010",
77 "license" : [
88 "perl_5"
99 ],
1010 "meta-spec" : {
1111 "url" : "http://search.cpan.org/perldoc?CPAN::Meta::Spec",
12 "version" : "2"
12 "version" : 2
1313 },
1414 "name" : "Keyword-Simple",
1515 "no_index" : {
1616 "directory" : [
1717 "t",
18 "inc"
18 "inc",
19 "xt"
1920 ]
2021 },
2122 "prereqs" : {
2425 },
2526 "configure" : {
2627 "requires" : {
27 "ExtUtils::MakeMaker" : "6.48",
28 "ExtUtils::MakeMaker" : "0",
29 "File::Find" : "0",
30 "File::Spec" : "0",
2831 "strict" : "0",
2932 "warnings" : "0"
3033 }
3134 },
35 "develop" : {
36 "requires" : {
37 "Pod::Markdown" : "3.005",
38 "Pod::Text" : "4.09",
39 "Test::Pod" : "1.22"
40 }
41 },
3242 "runtime" : {
3343 "requires" : {
34 "B::Hooks::EndOfScope" : "0",
3544 "Carp" : "0",
3645 "XSLoader" : "0",
3746 "perl" : "5.012000",
4049 },
4150 "test" : {
4251 "requires" : {
43 "Dir::Self" : "0",
4452 "Test::More" : "0",
4553 "strict" : "0"
4654 }
5462 "web" : "https://github.com/mauke/Keyword-Simple"
5563 }
5664 },
57 "version" : "0.03"
65 "version" : "0.04",
66 "x_serialization_backend" : "JSON::PP version 2.94"
5867 }
22 author:
33 - 'Lukas Mai <l.mai@web.de>'
44 build_requires:
5 Dir::Self: '0'
65 Test::More: '0'
76 strict: '0'
87 configure_requires:
9 ExtUtils::MakeMaker: '6.48'
8 ExtUtils::MakeMaker: '0'
9 File::Find: '0'
10 File::Spec: '0'
1011 strict: '0'
1112 warnings: '0'
12 dynamic_config: 1
13 generated_by: 'ExtUtils::MakeMaker version 6.98, CPAN::Meta::Converter version 2.140640'
13 dynamic_config: 0
14 generated_by: 'ExtUtils::MakeMaker version 7.3, CPAN::Meta::Converter version 2.150010'
1415 license: perl
1516 meta-spec:
1617 url: http://module-build.sourceforge.net/META-spec-v1.4.html
2021 directory:
2122 - t
2223 - inc
24 - xt
2325 requires:
24 B::Hooks::EndOfScope: '0'
2526 Carp: '0'
2627 XSLoader: '0'
2728 perl: '5.012000'
2829 warnings: '0'
2930 resources:
3031 repository: git://github.com/mauke/Keyword-Simple
31 version: '0.03'
32 version: '0.04'
33 x_serialization_backend: 'CPAN::Meta::YAML version 0.018'
00 use strict;
11 use warnings;
22 use ExtUtils::MakeMaker;
3 use File::Spec ();
4 use File::Find ();
35
4 sub merge_key_into {
5 my ($href, $target, $source) = @_;
6 %{$href->{$target}} = (%{$href->{$target}}, %{delete $href->{$source}});
6 sub find_tests_recursively_in {
7 my ($dir) = @_;
8 -d $dir or die "$dir is not a directory";
9
10 my %seen;
11 my $wanted = sub {
12 /\.t\z/ or return;
13 my $directories = (File::Spec->splitpath($File::Find::name))[1];
14 my $depth = grep $_ ne '', File::Spec->splitdir($directories);
15 $seen{$depth} = 1;
16 };
17 File::Find::find($wanted, $dir);
18
19 join ' ',
20 map { $dir . '/*' x $_ . '.t' }
21 sort { $a <=> $b }
22 keys %seen
723 }
824
9 my %opt = (
10 NAME => 'Keyword::Simple',
11 AUTHOR => q{Lukas Mai <l.mai@web.de>},
12 VERSION_FROM => 'lib/Keyword/Simple.pm',
13 ABSTRACT_FROM => 'lib/Keyword/Simple.pm',
25 $::MAINT_MODE = !-f 'META.yml';
26 my $settings_file = 'Makefile_PL_settings.plx';
27 my %settings = %{do "./$settings_file" or die "Internal error: can't do $settings_file: ", $@ || $!};
1428
15 LICENSE => 'perl',
16 PL_FILES => {},
29 {
30 $settings{depend}{Makefile} .= " $settings_file";
31 $settings{LICENSE} ||= 'perl';
32 $settings{PL_FILES} ||= {};
1733
18 MIN_PERL_VERSION => '5.12.0',
19 CONFIGURE_REQUIRES => {
20 'strict' => 0,
21 'warnings' => 0,
22 'ExtUtils::MakeMaker' => '6.48',
23 },
24 BUILD_REQUIRES => {},
25 TEST_REQUIRES => {
26 'strict' => 0,
27 'Dir::Self' => 0,
28 'Test::More' => 0,
29 },
30 PREREQ_PM => {
31 'Carp' => 0,
32 'XSLoader' => 0,
33 'warnings' => 0,
34 'B::Hooks::EndOfScope' => 0,
35 },
34 $settings{CONFIGURE_REQUIRES}{strict} ||= 0;
35 $settings{CONFIGURE_REQUIRES}{warnings} ||= 0;
36 $settings{CONFIGURE_REQUIRES}{'ExtUtils::MakeMaker'} ||= 0;
37 $settings{CONFIGURE_REQUIRES}{'File::Find'} ||= 0;
38 $settings{CONFIGURE_REQUIRES}{'File::Spec'} ||= 0;
3639
37 depend => { Makefile => '$(VERSION_FROM)' },
38 dist => { COMPRESS => 'gzip -9f', SUFFIX => 'gz', },
39 clean => { FILES => 'Keyword-Simple-*' },
40 my $module_file = $settings{NAME};
41 $module_file =~ s!::!/!g;
42 $module_file = "lib/$module_file.pm";
4043
41 META_MERGE => {
42 'meta-spec' => { version => 2 },
43 resources => {
44 repository => {
45 url => 'git://github.com/mauke/Keyword-Simple',
46 web => 'https://github.com/mauke/Keyword-Simple',
47 type => 'git',
48 },
49 },
50 },
51 );
44 $settings{VERSION_FROM} ||= $module_file;
45 $settings{ABSTRACT_FROM} ||= $module_file;
5246
53 (my $mm_version = ExtUtils::MakeMaker->VERSION($opt{CONFIGURE_REQUIRES}{'ExtUtils::MakeMaker'})) =~ tr/_//d;
47 $settings{test}{TESTS} ||= find_tests_recursively_in 't';
5448
55 if ($mm_version < 6.67_04) {
56 # Why? For the glory of satan, of course!
57 no warnings qw(redefine);
58 *ExtUtils::MM_Any::_add_requirements_to_meta_v1_4 = \&ExtUtils::MM_Any::_add_requirements_to_meta_v2;
49 $settings{DISTNAME} ||= do {
50 my $name = $settings{NAME};
51 $name =~ s!::!-!g;
52 $name
53 };
54
55 $settings{clean}{FILES} ||= "$settings{DISTNAME}-*";
56
57 $settings{dist}{COMPRESS} ||= 'gzip -9f';
58 $settings{dist}{SUFFIX} ||= '.gz';
59
60 my $version = $settings{VERSION} || MM->parse_version($settings{VERSION_FROM});
61 if ($version =~ s/-TRIAL[0-9]*\z//) {
62 $settings{META_MERGE}{release_status} ||= 'unstable';
63 $settings{META_MERGE}{version} ||= $version;
64 $settings{XS_VERSION} ||= $version;
65 }
66
67 $settings{META_MERGE}{'meta-spec'}{version} ||= 2;
68 $settings{META_MERGE}{dynamic_config} ||= 0;
69
70 push @{$settings{META_MERGE}{no_index}{directory}}, 'xt';
71 if (my $dev = delete $settings{DEVELOP_REQUIRES}) {
72 @{$settings{META_MERGE}{prereqs}{develop}{requires}}{keys %$dev} = values %$dev;
73 }
74 if (my $rec = delete $settings{RECOMMENDS}) {
75 @{$settings{META_MERGE}{prereqs}{runtime}{recommends}}{keys %$rec} = values %$rec;
76 }
77
78 if (my $sug = delete $settings{SUGGESTS}) {
79 @{$settings{META_MERGE}{prereqs}{runtime}{suggests}}{keys %$sug} = values %$sug;
80 }
81
82 if (my $repo = delete $settings{REPOSITORY}) {
83 if (ref($repo) eq 'ARRAY') {
84 my ($type, @args) = @$repo;
85 if ($type eq 'github') {
86 my ($account, $project) = @args;
87 $project ||= '%d';
88 $project =~ s{%(L?)(.)}{
89 my $x =
90 $2 eq '%' ? '%' :
91 $2 eq 'd' ? $settings{DISTNAME} :
92 $2 eq 'm' ? $settings{NAME} :
93 die "Internal error: unknown placeholder %$1$2";
94 $1 ? lc($x) : $x
95 }seg;
96 my $addr = "github.com/$account/$project";
97 $repo = {
98 type => 'git',
99 url => "git://$addr",
100 web => "https://$addr",
101 };
102 } else {
103 die "Internal error: unknown REPOSITORY type '$type'";
104 }
105 }
106 ref($repo) eq 'HASH' or die "Internal error: REPOSITORY must be a hashref, not $repo";
107 @{$settings{META_MERGE}{resources}{repository}}{keys %$repo} = values %$repo;
108 }
59109 }
60110
111 (do './maint/eumm-fixup.pl' || die $@ || $!)->(\%settings) if $::MAINT_MODE;
112
113 (my $mm_version = ExtUtils::MakeMaker->VERSION) =~ tr/_//d;
114
61115 if ($mm_version < 6.63_03) {
62 merge_key_into \%opt, 'BUILD_REQUIRES', 'TEST_REQUIRES';
116 $settings{META_MERGE}{resources}{repository} = $settings{META_MERGE}{resources}{repository}{url}
117 if $settings{META_MERGE}{resources} &&
118 $settings{META_MERGE}{resources}{repository} &&
119 $settings{META_MERGE}{resources}{repository}{url};
120 delete $settings{META_MERGE}{'meta-spec'}{version};
121 } elsif ($mm_version < 6.67_04) {
122 # Why? For the glory of satan, of course!
123 no warnings qw(redefine);
124 *ExtUtils::MM_Any::_add_requirements_to_meta_v1_4 = \&ExtUtils::MM_Any::_add_requirements_to_meta_v2;
63125 }
64126
65 if ($mm_version < 6.55_01) {
66 merge_key_into \%opt, 'CONFIGURE_REQUIRES', 'BUILD_REQUIRES';
127 {
128 my $merge_key_into = sub {
129 my ($target, $source) = @_;
130 %{$settings{$target}} = (%{$settings{$target}}, %{delete $settings{$source}});
131 };
132
133 $merge_key_into->('BUILD_REQUIRES', 'TEST_REQUIRES')
134 if $mm_version < 6.63_03;
135
136 $merge_key_into->('CONFIGURE_REQUIRES', 'BUILD_REQUIRES')
137 if $mm_version < 6.55_01;
138
139 $merge_key_into->('PREREQ_PM', 'CONFIGURE_REQUIRES')
140 if $mm_version < 6.51_03;
67141 }
68142
69 if ($mm_version < 6.51_03) {
70 merge_key_into \%opt, 'PREREQ_PM', 'CONFIGURE_REQUIRES';
71 }
143 delete $settings{MIN_PERL_VERSION} if $mm_version < 6.47_01;
144 delete $settings{META_MERGE} if $mm_version < 6.46;
145 delete $settings{LICENSE} if $mm_version < 6.30_01;
146 delete $settings{ABSTRACT_FROM} if $mm_version < 6.06_03;
147 delete $settings{AUTHOR} if $mm_version < 6.06_03;
72148
73 WriteMakefile %opt;
149 WriteMakefile %settings;
0 use strict;
1 use warnings;
2
3 return {
4 NAME => 'Keyword::Simple',
5 AUTHOR => q{Lukas Mai <l.mai@web.de>},
6
7 MIN_PERL_VERSION => '5.12.0',
8 CONFIGURE_REQUIRES => {},
9 BUILD_REQUIRES => {},
10 TEST_REQUIRES => {
11 'strict' => 0,
12 'Test::More' => 0,
13 },
14 PREREQ_PM => {
15 'Carp' => 0,
16 'XSLoader' => 0,
17 'warnings' => 0,
18 },
19 DEVELOP_REQUIRES => {
20 'Test::Pod' => 1.22,
21 },
22
23 depend => { Makefile => '$(VERSION_FROM)' },
24
25 REPOSITORY => [ github => 'mauke' ],
26 };
0 Keyword-Simple
0 NAME
11
2 define new keywords in pure Perl
3
2 Keyword::Simple - define new keywords in pure Perl
43
54 INSTALLATION
65
7 To install this module, run the following commands:
6 To download and install this module, use your favorite CPAN client, e.g.
7 "cpan":
88
9 perl Makefile.PL
10 make
11 make test
12 make install
9 cpan Keyword::Simple
10
11 Or "cpanm":
12
13 cpanm Keyword::Simple
14
15 To do it manually, run the following commands (after downloading and
16 unpacking the tarball):
17
18 perl Makefile.PL
19 make
20 make test
21 make install
1322
1423 SUPPORT AND DOCUMENTATION
1524
16 After installing, you can find documentation for this module with the
17 perldoc command.
25 After installing, you can find documentation for this module with the
26 "perldoc" command.
1827
19 perldoc Keyword::Simple
28 perldoc Keyword::Simple
2029
21 You can also look for information at:
30 You can also look for information at
31 <https://metacpan.org/pod/Keyword::Simple>.
2232
23 RT, CPAN's request tracker
24 http://rt.cpan.org/NoAuth/Bugs.html?Dist=Keyword-Simple
33 To see a list of open bugs, visit
34 <https://rt.cpan.org/Public/Dist/Display.html?Name=Keyword-Simple>.
2535
26 AnnoCPAN, Annotated CPAN documentation
27 http://annocpan.org/dist/Keyword-Simple
36 To report a new bug, send an email to "bug-Keyword-Simple [at]
37 rt.cpan.org".
2838
29 CPAN Ratings
30 http://cpanratings.perl.org/d/Keyword-Simple
39 COPYRIGHT & LICENSE
3140
32 MetaCPAN
33 https://metacpan.org/module/Keyword::Simple
41 Copyright (C) 2012, 2013 Lukas Mai.
3442
43 This program is free software; you can redistribute it and/or modify it
44 under the terms of either: the GNU General Public License as published
45 by the Free Software Foundation; or the Artistic License.
3546
36 COPYRIGHT AND LICENCE
47 See http://dev.perl.org/licenses/ for more information.
3748
38 Copyright (C) 2012, 2013 Lukas Mai
39
40 This program is free software; you can redistribute it and/or modify it
41 under the terms of either: the GNU General Public License as published
42 by the Free Software Foundation; or the Artistic License.
43
44 See http://dev.perl.org/licenses/ for more information.
45
00 /*
1 Copyright 2012, 2013 Lukas Mai.
1 Copyright 2012, 2013, 2017 Lukas Mai.
22
33 This program is free software; you can redistribute it and/or modify it
44 under the terms of either: the GNU General Public License as published
88 */
99
1010 #ifdef __GNUC__
11 #if __GNUC__ >= 5
12 #define IF_HAVE_GCC_5(X) X
13 #endif
14
1115 #if (__GNUC__ == 4 && __GNUC_MINOR__ >= 6) || __GNUC__ >= 5
1216 #define PRAGMA_GCC_(X) _Pragma(#X)
1317 #define PRAGMA_GCC(X) PRAGMA_GCC_(GCC X)
1418 #endif
1519 #endif
1620
21 #ifndef IF_HAVE_GCC_5
22 #define IF_HAVE_GCC_5(X)
23 #endif
24
1725 #ifndef PRAGMA_GCC
1826 #define PRAGMA_GCC(X)
1927 #endif
2028
2129 #ifdef DEVEL
2230 #define WARNINGS_RESET PRAGMA_GCC(diagnostic pop)
23 #define WARNINGS_ENABLEW(X) PRAGMA_GCC(diagnostic warning #X)
31 #define WARNINGS_ENABLEW(X) PRAGMA_GCC(diagnostic error #X)
2432 #define WARNINGS_ENABLE \
25 WARNINGS_ENABLEW(-Wall) \
26 WARNINGS_ENABLEW(-Wextra) \
27 WARNINGS_ENABLEW(-Wundef) \
28 /* WARNINGS_ENABLEW(-Wshadow) :-( */ \
29 WARNINGS_ENABLEW(-Wbad-function-cast) \
30 WARNINGS_ENABLEW(-Wcast-align) \
31 WARNINGS_ENABLEW(-Wwrite-strings) \
32 /* WARNINGS_ENABLEW(-Wnested-externs) wtf? */ \
33 WARNINGS_ENABLEW(-Wstrict-prototypes) \
34 WARNINGS_ENABLEW(-Wmissing-prototypes) \
35 WARNINGS_ENABLEW(-Winline) \
36 WARNINGS_ENABLEW(-Wdisabled-optimization)
33 WARNINGS_ENABLEW(-Wall) \
34 WARNINGS_ENABLEW(-Wextra) \
35 WARNINGS_ENABLEW(-Wundef) \
36 WARNINGS_ENABLEW(-Wshadow) \
37 WARNINGS_ENABLEW(-Wbad-function-cast) \
38 WARNINGS_ENABLEW(-Wcast-align) \
39 WARNINGS_ENABLEW(-Wwrite-strings) \
40 WARNINGS_ENABLEW(-Wstrict-prototypes) \
41 WARNINGS_ENABLEW(-Wmissing-prototypes) \
42 WARNINGS_ENABLEW(-Winline) \
43 WARNINGS_ENABLEW(-Wdisabled-optimization) \
44 IF_HAVE_GCC_5(WARNINGS_ENABLEW(-Wnested-externs))
3745
3846 #else
3947 #define WARNINGS_RESET
4755 #include "XSUB.h"
4856
4957 #include <string.h>
58 #include <stdlib.h>
59
60 #ifdef DEVEL
61 #undef NDEBUG
62 #endif
5063 #include <assert.h>
51 #include <stdlib.h>
52
64
65 #define HAVE_PERL_VERSION(R, V, S) \
66 (PERL_REVISION > (R) || (PERL_REVISION == (R) && (PERL_VERSION > (V) || (PERL_VERSION == (V) && (PERL_SUBVERSION >= (S))))))
67
68 #ifndef STATIC_ASSERT_STMT
69 #if (defined(static_assert) || (defined(__cplusplus) && __cplusplus >= 201103L)) && (!defined(__IBMC__) || __IBMC__ >= 1210)
70 /* static_assert is a macro defined in <assert.h> in C11 or a compiler
71 builtin in C++11. But IBM XL C V11 does not support _Static_assert, no
72 matter what <assert.h> says.
73 */
74 # define STATIC_ASSERT_DECL(COND) static_assert(COND, #COND)
75 #else
76 /* We use a bit-field instead of an array because gcc accepts
77 'typedef char x[n]' where n is not a compile-time constant.
78 We want to enforce constantness.
79 */
80 # define STATIC_ASSERT_2(COND, SUFFIX) \
81 typedef struct { \
82 unsigned int _static_assertion_failed_##SUFFIX : (COND) ? 1 : -1; \
83 } _static_assertion_failed_##SUFFIX PERL_UNUSED_DECL
84 # define STATIC_ASSERT_1(COND, SUFFIX) STATIC_ASSERT_2(COND, SUFFIX)
85 # define STATIC_ASSERT_DECL(COND) STATIC_ASSERT_1(COND, __LINE__)
86 #endif
87 /* We need this wrapper even in C11 because 'case X: static_assert(...);' is an
88 error (static_assert is a declaration, and only statements can have labels).
89 */
90 #define STATIC_ASSERT_STMT(COND) do { STATIC_ASSERT_DECL(COND); } while (0)
91 #endif
5392
5493 WARNINGS_ENABLE
55
56
57 #define HAVE_PERL_VERSION(R, V, S) \
58 (PERL_REVISION > (R) || (PERL_REVISION == (R) && (PERL_VERSION > (V) || (PERL_VERSION == (V) && (PERL_SUBVERSION >= (S))))))
5994
6095
6196 #define MY_PKG "Keyword::Simple"
67102 #define PL_rsfp_filters (PL_parser->rsfp_filters)
68103 #endif
69104
105 #ifndef PL_parser_filtered
106 #if HAVE_PERL_VERSION(5, 15, 5)
107 #define PL_parser_filtered (PL_parser->filtered)
108 #else
109 #define PL_parser_filtered 0
110 #endif
111 #endif
112
113
70114 static int (*next_keyword_plugin)(pTHX_ char *, STRLEN, OP **);
71115
72 static long kw_index(pTHX_ const char *kw_ptr, STRLEN kw_len) {
73 HV *hints;
74 SV *sv, **psv;
75 char *p, *pv;
76 STRLEN pv_len;
77
78 if (!(hints = GvHV(PL_hintgv))) {
79 return -1;
80 }
81 if (!(psv = hv_fetchs(hints, HINTK_KEYWORDS, 0))) {
82 return -1;
83 }
84 sv = *psv;
85
86 pv = SvPV(sv, pv_len);
87 if (pv_len < 4 || pv_len - 2 <= kw_len) {
88 return -1;
89 }
90
91 for (
92 p = pv;
93 (p = strchr(p + 1, *kw_ptr)) &&
94 p < pv + pv_len - 1 - kw_len;
95 ) {
96 if (
97 p[-1] == ' ' &&
98 p[kw_len] == ':' &&
99 memcmp(kw_ptr, p, kw_len) == 0
100 ) {
101 if (p[kw_len + 1] == '-') {
102 return -1;
103 }
104 assert(p[kw_len + 1] >= '0' && p[kw_len + 1] <= '9');
105 return strtol(p + kw_len + 1, NULL, 10);
106 }
107 }
108
109 return -1;
116 static SV *kw_handler(pTHX_ const char *kw_ptr, STRLEN kw_len) {
117 HV *hints;
118 SV **psv, *sv, *sv2;
119 I32 kw_xlen;
120
121
122 /* don't bother doing anything fancy after a syntax error */
123 if (PL_parser && PL_parser->error_count) {
124 return NULL;
125 }
126
127 STATIC_ASSERT_STMT(~(STRLEN)0 > (U32)I32_MAX);
128 if (kw_len > (STRLEN)I32_MAX) {
129 return NULL;
130 }
131
132 if (!(hints = GvHV(PL_hintgv))) {
133 return NULL;
134 }
135
136 if (!(psv = hv_fetchs(hints, HINTK_KEYWORDS, 0))) {
137 return NULL;
138 }
139
140 sv = *psv;
141 if (!(SvROK(sv) && (sv2 = SvRV(sv), SvTYPE(sv2) == SVt_PVHV))) {
142 croak("%s: internal error: $^H{'%s'} not a hashref: %"SVf, MY_PKG, HINTK_KEYWORDS, SVfARG(sv));
143 }
144
145 kw_xlen = kw_len;
146 if (lex_bufutf8()) {
147 kw_xlen = -kw_xlen;
148 }
149 if (!(psv = hv_fetch((HV *)sv2, kw_ptr, kw_xlen, 0))) {
150 return NULL;
151 }
152
153 sv = *psv;
154 if (!(SvROK(sv) && (sv2 = SvRV(sv), SvTYPE(sv2) == SVt_PVCV))) {
155 croak("%s: internal error: $^H{'%s'}{'%.*s'} not a coderef: %"SVf, MY_PKG, HINTK_KEYWORDS, (int)kw_len, kw_ptr, SVfARG(sv));
156 }
157
158 return sv2;
110159 }
111160
112161 static I32 playback(pTHX_ int idx, SV *buf, int n) {
113 char *ptr;
114 STRLEN len, d;
115 SV *sv = FILTER_DATA(idx);
116
117 ptr = SvPV(sv, len);
118 if (!len) {
119 return 0;
120 }
121
122 if (!n) {
123 char *nl = memchr(ptr, '\n', len);
124 d = nl ? (STRLEN)(nl - ptr + 1) : len;
125 } else {
126 d = n < 0 ? INT_MAX : n;
127 if (d > len) {
128 d = len;
129 }
130 }
131
132 sv_catpvn(buf, ptr, d);
133 sv_chop(sv, ptr + d);
134 return 1;
135 }
136
137 static void total_recall(pTHX_ I32 n) {
138 SV *sv, *cb;
139 AV *meta;
140 dSP;
141
142 ENTER;
143 SAVETMPS;
144
145 meta = get_av(MY_PKG "::meta", GV_ADD);
146 cb = *av_fetch(meta, n, 0);
147
148 sv = sv_2mortal(newSVpvs(""));
149 if (lex_bufutf8()) {
150 SvUTF8_on(sv);
151 }
152
153 /* sluuuuuurrrrp */
154
155 sv_setpvn(sv, PL_parser->bufptr, PL_parser->bufend - PL_parser->bufptr);
156 lex_unstuff(PL_parser->bufend); /* you saw nothing */
157
158 if (!PL_rsfp_filters) {
159 /* because FILTER_READ fails with filters=null but DTRT with filters=[] */
160 PL_rsfp_filters = newAV();
161 }
162 while (FILTER_READ(0, sv, 4096) > 0)
163 ;
164
165 PUSHMARK(SP);
166 mXPUSHs(newRV_inc(sv));
167 PUTBACK;
168
169 call_sv(cb, G_VOID);
170 SPAGAIN;
171
172 { /* $sv .= "\n" */
173 char *p;
174 STRLEN n;
175 SvPV_force(sv, n);
176 p = SvGROW(sv, n + 2);
177 p[n] = '\n';
178 p[n + 1] = '\0';
179 SvCUR_set(sv, n + 1);
180 }
181
182 filter_add(playback, SvREFCNT_inc_simple_NN(sv));
183
184 CopLINE_dec(PL_curcop);
185
186 PUTBACK;
187 FREETMPS;
188 LEAVE;
162 char *ptr;
163 STRLEN len, d;
164 SV *sv = FILTER_DATA(idx);
165
166 ptr = SvPV(sv, len);
167 if (!len) {
168 return 0;
169 }
170
171 if (!n) {
172 char *nl = memchr(ptr, '\n', len);
173 d = nl ? (STRLEN)(nl - ptr + 1) : len;
174 } else {
175 d = n < 0 ? INT_MAX : n;
176 if (d > len) {
177 d = len;
178 }
179 }
180
181 sv_catpvn(buf, ptr, d);
182 sv_chop(sv, ptr + d);
183 return 1;
184 }
185
186 static void total_recall(pTHX_ SV *cb) {
187 SV *sv;
188 dSP;
189
190 ENTER;
191 SAVETMPS;
192
193 sv = sv_2mortal(newSVpvs(""));
194 if (lex_bufutf8()) {
195 SvUTF8_on(sv);
196 }
197
198 /* sluuuuuurrrrp */
199
200 sv_setpvn(sv, PL_parser->bufptr, PL_parser->bufend - PL_parser->bufptr);
201 lex_unstuff(PL_parser->bufend); /* you saw nothing */
202
203 if (PL_parser->rsfp || PL_parser_filtered) {
204 if (!PL_rsfp_filters) {
205 /* because FILTER_READ fails with filters=null but DTRT with filters=[] */
206 PL_rsfp_filters = newAV();
207 }
208 while (FILTER_READ(0, sv, 4096) > 0)
209 ;
210 }
211
212 PUSHMARK(SP);
213 mXPUSHs(newRV_inc(sv));
214 PUTBACK;
215
216 call_sv(cb, G_VOID);
217 SPAGAIN;
218
219 { /* $sv .= "\n" */
220 char *p;
221 STRLEN n;
222 SvPV_force(sv, n);
223 p = SvGROW(sv, n + 2);
224 p[n] = '\n';
225 p[n + 1] = '\0';
226 SvCUR_set(sv, n + 1);
227 }
228
229 if (PL_parser->rsfp || PL_parser_filtered) {
230 filter_add(playback, SvREFCNT_inc_simple_NN(sv));
231 CopLINE_dec(PL_curcop);
232 } else {
233 lex_stuff_sv(sv, 0);
234 }
235
236 FREETMPS;
237 LEAVE;
189238 }
190239
191240 static int my_keyword_plugin(pTHX_ char *keyword_ptr, STRLEN keyword_len, OP **op_ptr) {
192 long n;
193
194 if ((n = kw_index(aTHX_ keyword_ptr, keyword_len)) >= 0) {
195 total_recall(aTHX_ n);
196 *op_ptr = newOP(OP_NULL, 0);
197 return KEYWORD_PLUGIN_STMT;
198 }
199
200 return next_keyword_plugin(aTHX_ keyword_ptr, keyword_len, op_ptr);
201 }
202
241 SV *cb;
242
243 if ((cb = kw_handler(aTHX_ keyword_ptr, keyword_len))) {
244 total_recall(aTHX_ cb);
245 *op_ptr = newOP(OP_NULL, 0);
246 return KEYWORD_PLUGIN_STMT;
247 }
248
249 return next_keyword_plugin(aTHX_ keyword_ptr, keyword_len, op_ptr);
250 }
251
252
253 static void my_boot(pTHX) {
254 HV *const stash = gv_stashpvs(MY_PKG, GV_ADD);
255
256 newCONSTSUB(stash, "HINTK_KEYWORDS", newSVpvs(HINTK_KEYWORDS));
257
258 next_keyword_plugin = PL_keyword_plugin;
259 PL_keyword_plugin = my_keyword_plugin;
260 }
203261
204262 WARNINGS_RESET
205263
207265 PROTOTYPES: ENABLE
208266
209267 BOOT:
210 WARNINGS_ENABLE {
211 HV *const stash = gv_stashpvs(MY_PKG, GV_ADD);
212 /**/
213 newCONSTSUB(stash, "HINTK_KEYWORDS", newSVpvs(HINTK_KEYWORDS));
214 /**/
215 next_keyword_plugin = PL_keyword_plugin;
216 PL_keyword_plugin = my_keyword_plugin;
217 } WARNINGS_RESET
268 my_boot(aTHX);
33 use warnings;
44
55 use Carp qw(croak);
6 use B::Hooks::EndOfScope;
76
87 use XSLoader;
98 BEGIN {
10 our $VERSION = '0.03';
11 XSLoader::load __PACKAGE__, $VERSION;
9 our $VERSION = '0.04';
10 XSLoader::load __PACKAGE__, $VERSION;
1211 }
1312
14 # all shall burn
15 our @meta;
13 sub define {
14 my ($kw, $sub) = @_;
15 $kw =~ /^\p{XIDS}\p{XIDC}*\z/ or croak "'$kw' doesn't look like an identifier";
16 ref($sub) eq 'CODE' or croak "'$sub' doesn't look like a coderef";
1617
17 sub define {
18 my ($kw, $sub) = @_;
19 $kw =~ /^\p{XIDS}\p{XIDC}*\z/ or croak "'$kw' doesn't look like an identifier";
20 ref($sub) eq 'CODE' or croak "'$sub' doesn't look like a coderef";
21
22 my $n = @meta;
23 push @meta, $sub;
24
25 $^H{+HINTK_KEYWORDS} .= " $kw:$n";
26 on_scope_end {
27 delete $meta[$n];
28 };
18 my %keywords = %{$^H{+HINTK_KEYWORDS} // {}};
19 $keywords{$kw} = $sub;
20 $^H{+HINTK_KEYWORDS} = \%keywords;
2921 }
3022
3123 sub undefine {
32 my ($kw) = @_;
33 $kw =~ /^\p{XIDS}\p{XIDC}*\z/ or croak "'$kw' doesn't look like an identifier";
24 my ($kw) = @_;
25 $kw =~ /^\p{XIDS}\p{XIDC}*\z/ or croak "'$kw' doesn't look like an identifier";
3426
35 $^H{+HINTK_KEYWORDS} .= " $kw:-";
27 my %keywords = %{$^H{+HINTK_KEYWORDS} // {}};
28 delete $keywords{$kw};
29 $^H{+HINTK_KEYWORDS} = \%keywords;
3630 }
3731
3832 'ok'
4034 __END__
4135
4236 =encoding UTF-8
37
38 =for highlighter language=perl
4339
4440 =head1 NAME
4541
126122 This also means your new keywords can only occur at the beginning of a
127123 statement, not embedded in an expression.
128124
125 Keywords in the replacement part of a C<s//.../e> substitution aren't handled
126 correctly and break parsing.
127
129128 There are barely any tests.
129
130 =begin :README
131
132 =head1 INSTALLATION
133
134 To download and install this module, use your favorite CPAN client, e.g.
135 L<C<cpan>|cpan>:
136
137 =for highlighter language=sh
138
139 cpan Keyword::Simple
140
141 Or L<C<cpanm>|cpanm>:
142
143 cpanm Keyword::Simple
144
145 To do it manually, run the following commands (after downloading and unpacking
146 the tarball):
147
148 perl Makefile.PL
149 make
150 make test
151 make install
152
153 =end :README
154
155 =head1 SUPPORT AND DOCUMENTATION
156
157 After installing, you can find documentation for this module with the
158 L<C<perldoc>|perldoc> command.
159
160 =for highlighter language=sh
161
162 perldoc Keyword::Simple
163
164 You can also look for information at
165 L<https://metacpan.org/pod/Keyword::Simple>.
166
167 To see a list of open bugs, visit
168 L<https://rt.cpan.org/Public/Dist/Display.html?Name=Keyword-Simple>.
169
170 To report a new bug, send an email to
171 C<bug-Keyword-Simple [at] rt.cpan.org>.
130172
131173 =head1 AUTHOR
132174
134176
135177 =head1 COPYRIGHT & LICENSE
136178
137 Copyright 2012, 2013 Lukas Mai.
179 Copyright (C) 2012, 2013 Lukas Mai.
138180
139181 This program is free software; you can redistribute it and/or modify it
140182 under the terms of either: the GNU General Public License as published
44 use Test::More tests => 2;
55
66 {
7 package Foo;
7 package Foo;
88
9 use Keyword::Simple;
9 use Keyword::Simple;
1010
11 sub import {
12 Keyword::Simple::define peek => sub {
13 substr ${$_[0]}, 0, 0, "ok 1, 'synthetic test';";
14 };
15 }
11 sub import {
12 Keyword::Simple::define peek => sub {
13 substr ${$_[0]}, 0, 0, "ok 1, 'synthetic test';";
14 };
15 }
1616
17 sub unimport {
18 Keyword::Simple::undefine 'peek';
19 }
17 sub unimport {
18 Keyword::Simple::undefine 'peek';
19 }
2020
21 BEGIN { $INC{"Foo.pm"} = 1; }
21 BEGIN { $INC{"Foo.pm"} = 1; }
2222 }
2323
2424 use Foo;
0 #!perl
1 use strict;
2 use warnings FATAL => 'all';
3 no warnings 'once';
4
5 use Test::More;
6
7 {
8 package Foo;
9
10 use Keyword::Simple;
11
12 sub import {
13 Keyword::Simple::define class => sub {
14 substr ${$_[0]}, 0, 0, "package";
15 };
16 }
17
18 sub unimport {
19 Keyword::Simple::undefine 'peek';
20 }
21
22 BEGIN { $INC{"Foo.pm"} = 1; }
23 }
24
25 use Foo;
26
27 { class Gpkg0; our $v = __PACKAGE__; }
28 is $Gpkg0::v, 'Gpkg0';
29
30 eval q{ class Gpkg1; our $v = __PACKAGE__ };
31 is $@, '';
32 is $Gpkg1::v, 'Gpkg1';
33
34 SKIP: {
35 skip "evalbytes() requires v5.16", 3
36 if $^V lt v5.16;
37 my $err;
38 eval q{
39 use v5.16;
40 evalbytes q{ class Gpkg2; our $v = __PACKAGE__ };
41 $err = $@;
42 };
43 is $@, '';
44 is $err, '';
45 is $Gpkg2::v, 'Gpkg2';
46 }
47
48 TODO: {
49 local $TODO = 's//.../e handling is broken';
50 my $str = '';
51 eval q{ $str =~ s/^/ class Gpkg3; our $v = __PACKAGE__ /e };
52 is $@, '';
53 is $str, 'Gpkg3';
54 is $Gpkg3::v, 'Gpkg3';
55 }
56
57 done_testing;
44 use Test::More tests => 6;
55
66 BEGIN {
7 package Some::Module;
8 use Keyword::Simple;
9 sub import {
10 Keyword::Simple::define 'provided', sub {
11 my ($ref) = @_;
12 substr($$ref, 0, 0) = 'if';
13 };
14 }
15 sub unimport {
16 Keyword::Simple::undefine 'provided';
17 }
18 $INC{'Some/Module.pm'} = __FILE__;
7 package Some::Module;
8 use Keyword::Simple;
9 sub import {
10 Keyword::Simple::define 'provided', sub {
11 my ($ref) = @_;
12 substr($$ref, 0, 0) = 'if';
13 };
14 }
15 sub unimport {
16 Keyword::Simple::undefine 'provided';
17 }
18 $INC{'Some/Module.pm'} = __FILE__;
1919 };
2020
2121 use Some::Module;
2222
2323 provided (1) {
24 is(__LINE__, 25);
24 is(__LINE__, 25);
2525 }
2626
2727 #line 1
3434 is __LINE__, 2;
3535
3636 provided (2) { provided (3) {
37 is __LINE__, 5;
38 }
37 is __LINE__, 5;
38 }
3939 }
+0
-14
t/pod.t less more
0 #!perl
1
2 use strict;
3 use warnings;
4 use Test::More;
5
6 plan skip_all => "set RELEASE_TESTING=1 to run this test" unless $ENV{RELEASE_TESTING};
7
8 # Ensure a recent version of Test::Pod
9 my $min_tp = 1.22;
10 eval "use Test::Pod $min_tp";
11 plan skip_all => "Test::Pod $min_tp required for testing POD" if $@;
12
13 all_pod_files_ok();
0 #!perl
1
2 use strict;
3 use warnings;
4 use Test::Pod 1.22;
5
6 all_pod_files_ok();