File Coverage

blib/lib/DTL/Fast/Parser.pm
Criterion Covered Total %
statement 66 66 100.0
branch 18 20 90.0
condition 11 22 50.0
subroutine 11 11 100.0
pod 0 4 0.0
total 106 123 86.1


line stmt bran cond sub pod time code
1             package DTL::Fast::Parser;
2 98     98   54572 use strict; use warnings FATAL => 'all';
  98     98   187  
  98         6299  
  98         484  
  98         182  
  98         3935  
3 98     98   1660 use parent 'DTL::Fast::Renderer';
  98         1407  
  98         3066  
4              
5 98     98   61388 use DTL::Fast::Expression;
  98         301  
  98         3645  
6 98     98   53108 use DTL::Fast::Text;
  98         260  
  98         2720  
7 98     98   549 use DTL::Fast::Template;
  98         172  
  98         2233  
8 98     98   2445 use DTL::Fast qw(count_lines);
  98         177  
  98         83922  
9              
10             sub new
11             {
12 1805     1805 0 5968 my( $proto, %kwargs ) = @_;
13              
14             die $proto->get_parse_error('no directory arrays passed into constructor')
15             if not $kwargs{'dirs'}
16 1805 50 33     10605 or ref $kwargs{'dirs'} ne 'ARRAY'
17             ;
18            
19             die $proto->get_parse_error('no raw chunks array passed into constructor')
20             if not $kwargs{'raw_chunks'}
21 1805 50 33     9390 or ref $kwargs{'raw_chunks'} ne 'ARRAY'
22             ;
23            
24 1805   50     7078 $kwargs{'safe'} //= 0;
25            
26 1805         8370 my $self = $proto->SUPER::new(%kwargs)->parse_chunks();;
27            
28 1749         3953 delete @{$self}{'raw_chunks'};
  1749         3723  
29            
30 1749         6598 return $self;
31             }
32              
33             sub parse_chunks
34             {
35 1790     1790 0 2576 my( $self ) = @_;
36 1790         2467 while( scalar @{$self->{'raw_chunks'}} )
  8460         22737  
37             {
38 6711         14680 $self->add_chunk( $self->parse_next_chunk());
39             }
40 1749         3601 return $self;
41             }
42              
43             sub parse_next_chunk
44             {
45 6501     6501 0 8495 my( $self ) = @_;
46              
47 6501         7028 my $chunk = shift @{$self->{'raw_chunks'}};
  6501         12709  
48 6501         15489 my $chunk_lines = count_lines($chunk);
49            
50 6501 100       39635 if(
    100          
    100          
    100          
51             $chunk =~ /^
52             \{\{\s* # open sequence
53             ([^\s].*?) # variable name or value $1
54             \s*\}\} # close sequence
55             $/xs
56             )
57             {
58 638 100       2049 if( $1 eq 'block.super' )
59             {
60 1         8 require DTL::Fast::Tag::BlockSuper;
61             $chunk = DTL::Fast::Tag::BlockSuper->new(
62             ''
63 1         7 , 'dirs' => $self->{'dirs'}
64             , '_open_tag_lines' => $chunk_lines
65             );
66             }
67             else
68             {
69 637         2688 $chunk = DTL::Fast::Variable->new($1);
70 637         1231 $DTL::Fast::Template::CURRENT_TEMPLATE_LINE += $chunk_lines;
71             }
72             }
73             elsif
74             (
75             $chunk =~ /^
76             \{\%\s* # open sequence
77             ([^\s]+?) # tag keyword $1
78             (?:
79             \s+ # spaces
80             (.*?) # parameters $2
81             )?
82             \s*\%\} # close sequence
83             $/xs
84             )
85             {
86 2423         10266 $chunk = $self->parse_tag_chunk(lc $1, $2, $chunk_lines);
87             }
88             elsif
89             (
90             $chunk =~ /^\{\#.*\#\}$/s
91             )
92             {
93 2         4 $DTL::Fast::Template::CURRENT_TEMPLATE_LINE += $chunk_lines;
94 2         3 $chunk = undef;
95             }
96             elsif( $chunk ne '' )
97             {
98 2364         7393 $chunk = DTL::Fast::Text->new( $chunk);
99 2364         3761 $DTL::Fast::Template::CURRENT_TEMPLATE_LINE += $chunk_lines;
100             }
101             else
102             {
103 1074         1466 $chunk = undef;
104             }
105            
106 6460         21661 return $chunk;
107             }
108              
109             sub parse_tag_chunk
110             {
111 849     849 0 1958 my( $self, $tag_name, $tag_param, $chunk_lines ) = @_;
112            
113 849         1129 my $result = undef;
114              
115             # dynamic module loading
116 849 100 66     2624 if(
117             not exists $DTL::Fast::TAG_HANDLERS{$tag_name}
118             and exists $DTL::Fast::KNOWN_TAGS{$tag_name}
119             )
120             {
121 53         29987 require Module::Load;
122 53         38168 Module::Load::load($DTL::Fast::KNOWN_TAGS{$tag_name});
123 53         755 $DTL::Fast::LOADED_MODULES{$DTL::Fast::KNOWN_TAGS{$tag_name}} = time;
124             }
125              
126             # handling tag
127 849 100       1835 if( exists $DTL::Fast::TAG_HANDLERS{$tag_name} )
128             {
129             $result = $DTL::Fast::TAG_HANDLERS{$tag_name}->new(
130             $tag_param
131             , 'raw_chunks' => $self->{'raw_chunks'}
132 843         4093 , 'dirs' => $self->{'dirs'}
133             , '_open_tag_lines' => $chunk_lines
134             );
135             }
136             else # not found
137             {
138 6         25 my $full_tag_name = join ' ', grep $_, ($tag_name, $tag_param);
139            
140 6 100 66     90 if ( # block tag parsing error
141             $self->isa('DTL::Fast::Tag')
142             and not $self->isa('DTL::Fast::Tag::Simple')
143             )
144             {
145 2   50     29 warn $self->get_parse_warning(
      50        
146             sprintf( 'unknown tag {%% %s %%}', $full_tag_name )
147             , 'Possible reasons' => sprintf( <<'_EOM_'
148             typo in tag name
149             duplicated close tag {%% %1$s %%}
150             unopened close tag {%% %1$s %%}
151             undisclosed block tag %3$s
152             _EOM_
153             , $tag_name // 'undef'
154             , $DTL::Fast::Template::CURRENT_TEMPLATE_LINE // 'unknown'
155             , $self->open_tag_syntax_with_line_number()
156             )
157             );
158             }
159             else # template parsing error
160             {
161 4   50     64 warn $self->get_parse_warning(
      50        
162             sprintf( 'unknown tag {%% %s %%}', $full_tag_name )
163             , 'Possible reasons' => sprintf( <<'_EOM_'
164             typo, duplicated or unopened close tag {%% %1$s %%} at line %2$s
165             _EOM_
166             , $tag_name // 'undef'
167             , $DTL::Fast::Template::CURRENT_TEMPLATE_LINE // 'unknown'
168             )
169             );
170             }
171            
172 6         44 $DTL::Fast::Template::CURRENT_TEMPLATE_LINE += $chunk_lines;
173            
174 6         22 $result = DTL::Fast::Text->new();
175             }
176            
177 809         2109 return $result;
178             }
179              
180             1;