File Coverage

blib/lib/Text/APL/Parser.pm
Criterion Covered Total %
statement 64 64 100.0
branch 28 28 100.0
condition 11 15 73.3
subroutine 9 9 100.0
pod 1 1 100.0
total 113 117 96.5


line stmt bran cond sub pod time code
1             package Text::APL::Parser;
2              
3 3     3   70314 use strict;
  3         18  
  3         82  
4 3     3   16 use warnings;
  3         12  
  3         82  
5              
6 3     3   17 use base 'Text::APL::Base';
  3         6  
  3         1978  
7              
8             sub _BUILD {
9 37     37   59 my $self = shift;
10              
11 37   50     171 $self->{start_token} ||= '<%';
12 37   50     133 $self->{end_token} ||= '%>';
13              
14 37   50     164 $self->{line_token} ||= '%';
15              
16 37         77 $self->{leftover_token} = $self->_build_leftover_pattern;
17              
18 37         87 return $self;
19             }
20              
21             sub parse {
22 63     63 1 140 my $self = shift;
23 63         109 my ($input) = @_;
24              
25 63         247 my $TOKEN_START = qr/$self->{start_token}/;
26 63         189 my $TOKEN_END = qr/$self->{end_token}/;
27 63         289 my $TOKEN = qr/$TOKEN_START(==?)? [ ] (.*?) \s* $TOKEN_END/xms;
28              
29 63         226 my $LINE_TOKEN_START = qr/^ \s* $self->{line_token} /xms;
30 63         251 my $LINE_TOKEN = qr/$LINE_TOKEN_START(==?)? \s* ([^\n]*)/xms;
31              
32 63         105 my $LEFTOVER_TOKEN = $self->{leftover_token};
33              
34 63 100       142 if (!defined $input) {
35 24 100       86 return [] unless defined $self->{buffer};
36              
37 12         24 my $buffer = delete $self->{buffer};
38 12 100       117 return [$buffer =~ m/$LINE_TOKEN/xms
39             ? $self->_build_line_token($1, $2)
40             : $self->_build_text($buffer)
41             ];
42             }
43              
44 39 100       99 if (defined $self->{buffer}) {
45 2         7 $input = delete($self->{buffer}) . $input;
46             }
47              
48 39         66 my $tape = [];
49              
50 39         117 pos $input = 0;
51 39         121 while (pos $input < length $input) {
52 62 100       749 if ($input =~ m/\G $TOKEN/gcxms) {
    100          
    100          
53 16         48 push @$tape, $self->_build_token($1, $2);
54             }
55             elsif ($input =~ m/\G $LINE_TOKEN \n/gcxms) {
56 14         40 push @$tape, $self->_build_line_token($1, $2);
57             }
58             elsif ($input =~ m/\G (.+?) (?=$TOKEN_START | $LINE_TOKEN_START)/gcxms) {
59 11         40 push @$tape, $self->_build_text($1);
60             }
61             else {
62 21 100       196 if ($input =~ m/( (?:$TOKEN_START | $LINE_TOKEN_START) .* )/gcxms) {
    100          
63 13         44 $self->{buffer} = $1;
64             }
65             elsif ($input =~ m/( $LEFTOVER_TOKEN ) $/gcxms) {
66 1         3 $self->{buffer} = $1;
67             }
68              
69 21         60 my $value = substr($input, pos($input));
70              
71 21 100 66     84 if (defined $value && $value ne '') {
72 7         22 push @$tape, $self->_build_text($value);
73             }
74              
75 21         57 last;
76             }
77             }
78              
79 39         312 $tape;
80             }
81              
82             sub _build_token {
83 16     16   27 my $self = shift;
84 16         56 my ($modifier, $value) = @_;
85              
86 16 100       62 my $token = {type => defined $modifier ? 'expr' : 'exec', value => $value};
87 16 100 100     83 $token->{as_is} = 1 if defined $modifier && length $modifier == 2;
88              
89 16         78 return $token;
90             }
91              
92             sub _build_line_token {
93 23     23   70 my $self = shift;
94 23         77 my ($modifier, $value) = @_;
95              
96 23 100       97 my $token = {type => defined $modifier ? 'expr' : 'exec', value => $value, line => 1};
97 23 100 100     81 $token->{as_is} = 1 if defined $modifier && length $modifier == 2;
98              
99 23         95 return $token;
100             }
101              
102             sub _build_text {
103 21     21   35 my $self =shift;
104 21         54 my ($value) = @_;
105              
106 21         156 return {type => 'text', value => $value};
107             }
108              
109             sub _build_leftover_pattern {
110 37     37   55 my $self = shift;
111              
112 37         112 my @token = split //, $self->{start_token};
113              
114 37         66 my $pattern = '';
115 37         121 $pattern .= '(?:' . $_ for @token;
116 37         88 $pattern .= ')?' for @token;
117 37         208 $pattern =~ s{\?$}{};
118              
119 37         222 return qr/$pattern/;
120             }
121              
122             1;
123             __END__