fix inject_after_scope
[p5sagit/Filter-Keyword.git] / lib / Filter / Keyword.pm
CommitLineData
3b08744b 1package Filter::Keyword;
3b08744b 2use Moo;
3
c15f7959 4use Filter::Keyword::Filter;
fd60cdd6 5use Filter::Util::Call;
c15f7959 6use Scalar::Util qw(weaken);
7use Package::Stash::PP;
8use B qw(svref_2object);
6c0ec68b 9use B::Hooks::EndOfScope;
3b08744b 10
c15f7959 11sub _compiling_file () {
12 my $depth = 0;
13 while (my @caller = caller(++$depth)) {
14 if ($caller[3] =~ /::BEGIN$/) {
15 # older perls report the BEGIN in the wrong file
16 return $depth > 1 ? (caller($depth-1))[1] : $caller[1];
17 #return $caller[1];
18 }
19 }
20 die;
21}
3b08744b 22
c15f7959 23my %filters;
24sub install {
3b08744b 25 my ($self) = @_;
c15f7959 26 $self->shadow_sub;
6c0ec68b 27
28 my $file = _compiling_file;
c15f7959 29 my $filter = $filters{$file} ||= Filter::Keyword::Filter->new;
30 $filter->install;
6c0ec68b 31
c15f7959 32 my $parser = $filter->parser;
33 $parser->add_keyword($self);
34 $self->keyword_parser($parser);
6c0ec68b 35
36 on_scope_end {
37 $self->remove;
38 };
3b08744b 39}
40
17022343 41has _shadowed_sub => (is => 'rw', clearer => '_clear_shadowed_sub');
42
c15f7959 43sub shadow_sub {
44 my $self = shift;
45 my $stash = $self->stash;
46 if (my $shadowed = $stash->get_symbol('&'.$self->keyword_name)) {
17022343 47 $self->_shadowed_sub($shadowed);
c15f7959 48 $stash->remove_symbol('&'.$self->keyword_name);
49 $stash->add_symbol('&__'.$self->keyword_name, $shadowed);
50 }
51}
52
53sub remove {
54 my ($self) = @_;
55 $self->keyword_parser->remove_keyword($self);
56 $self->clear_keyword_parser;
57 $self->clear_globref;
17022343 58 my $stash = $self->stash;
59 if (my $shadowed = $self->_shadowed_sub) {
60 $self->_clear_shadowed_sub;
61 $stash->remove_symbol('&__'.$self->keyword_name);
62 $stash->add_symbol('&'.$self->keyword_name, $shadowed);
63 }
c15f7959 64}
65
809ae673 66has keyword_parser => (
67 is => 'rw',
68 weak_ref => 1,
69 clearer => 1,
70 handles => [
71 'match_source',
72 'current_match',
73 ],
74);
c15f7959 75
76has target_package => (is => 'ro', required => 1);
77has keyword_name => (is => 'ro', required => 1);
78has parser => (is => 'ro', required => 1);
79
80has stash => (is => 'lazy');
81
82sub _build_stash {
83 my ($self) = @_;
84 Package::Stash::PP->new($self->target_package);
85}
86
87has globref => (is => 'lazy', clearer => 'clear_globref');
88
89sub _build_globref {
90 no strict 'refs'; no warnings 'once';
91 \*{join'::',$_[0]->target_package,$_[0]->keyword_name}
92}
93
94after clear_globref => sub {
95 my ($self) = @_;
96 $self->stash->remove_symbol('&'.$self->keyword_name);
97 $self->globref_refcount(undef);
98};
99
100has globref_refcount => (is => 'rw');
101
102sub save_refcount {
103 my ($self) = @_;
104 $self->globref_refcount(svref_2object($self->globref)->REFCNT);
105}
106
107sub have_match {
108 my ($self) = @_;
109 return 0 unless defined($self->globref_refcount);
110 svref_2object($self->globref)->REFCNT > $self->globref_refcount;
111}
112
bee972ee 113sub inject_after_scope {
114 my $inject = shift;
115 on_scope_end {
116 filter_add(sub {
117 my($status) ;
118 $status = filter_read();
119 if ($status >= 0) {
120 $_ = $inject . $_;
121 }
122 filter_del();
123 $status ;
124 });
125 };
3b08744b 126}
127
1281;