fix inject_after_scope
[p5sagit/Filter-Keyword.git] / lib / Filter / Keyword / Parser.pm
CommitLineData
c46d1069 1package Filter::Keyword::Parser;
c46d1069 2use Moo;
3
c15f7959 4use Scalar::Util qw(set_prototype);
c46d1069 5
6has reader => (is => 'ro', required => 1);
7
8has re_add => (is => 'ro', required => 1);
9
c15f7959 10has keywords => (is => 'ro', default => sub { [] });
c46d1069 11
c15f7959 12sub add_keyword {
13 push @{$_[0]->keywords}, $_[1];
c46d1069 14}
c15f7959 15sub remove_keyword {
16 my ($self, $keyword) = @_;
17 my $keywords = $self->keywords;
18 for my $idx (0 .. $#$keywords) {
19 if ($keywords->[$idx] eq $keyword) {
20 splice @$keywords, $idx, 1;
21 last;
22 }
23 }
c46d1069 24}
25
26has current_match => (is => 'rw');
27
28has short_circuit => (is => 'rw');
29
30has code => (is => 'rw', default => sub { '' });
31
32sub get_next {
33 my ($self) = @_;
34 if ($self->short_circuit) {
35 $self->short_circuit(0);
36 $self->${\$self->re_add};
37 return ('', 0);
38 }
c15f7959 39 for my $keyword (@{$self->keywords}) {
40 if ($keyword->have_match) {
41 $keyword->clear_globref;
42 return $keyword->parser->($keyword, $self);
43 }
c46d1069 44 }
45 return $self->check_match;
46}
47
48sub fetch_more {
49 my ($self) = @_;
50 my $code = $self->code||'';
c15f7959 51 my ($extra_code, $not_eof) = $self->reader->();
c46d1069 52 $code .= $extra_code;
53 $self->code($code);
54 return $not_eof;
55}
56
57sub match_source {
58 my ($self, $first, $second) = @_;
87f45e42 59 $self->fetch_more while $self->code =~ /\A$first\s+\z/;
60 if (my @match = ($self->code =~ /(.*?${first}\s+${second})(.*\n?)\z/)) {
61 my $code = pop @match;
62 $self->code($code);
c46d1069 63 my $found = shift(@match);
64 return ($found, \@match);
65 }
66 return;
67}
68
69sub check_match {
70 my ($self) = @_;
71 unless ($self->code) {
72 $self->fetch_more
73 or return ('', 0);
74 }
c15f7959 75 for my $keyword (@{ $self->keywords }) {
76 if (
77 my ($stripped, $matches)
78 = $self->match_source(
79 $keyword->keyword_name, qr/(\(|[A-Za-z][A-Za-z_0-9]*|{)/
80 )
81 ) {
82 my $sub = sub {};
83 set_prototype(\&$sub, '*;@') unless $matches->[0] eq '(';
87f45e42 84 { no warnings 'redefine'; *{$keyword->globref} = $sub; }
c15f7959 85 $keyword->save_refcount;
86 $self->current_match($matches);
87 $self->short_circuit(1);
88 return ($stripped, 1);
89 }
c46d1069 90 }
91 my $code = $self->code;
92 $self->code('');
93 return ($code, 1);
94}
95
961;