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