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   35538 use strict; use warnings FATAL => 'all';
  98     98   733  
  98         3745  
  98         1023  
  98         1477  
  98         4457  
3 98     98   1330 use parent 'DTL::Fast::Renderer';
  98         885  
  98         1183  
4              
5 98     98   39773 use DTL::Fast::Expression;
  98         196  
  98         2984  
6 98     98   34306 use DTL::Fast::Text;
  98         173  
  98         2231  
7 98     98   437 use DTL::Fast::Template;
  98         107  
  98         1588  
8 98     98   1469 use DTL::Fast qw(count_lines);
  98         107  
  98         58775  
9              
10             sub new
11             {
12 1805     1805 0 3840 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     7855 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     6586 or ref $kwargs{'raw_chunks'} ne 'ARRAY'
22             ;
23            
24 1805   50     4964 $kwargs{'safe'} //= 0;
25            
26 1805         6038 my $self = $proto->SUPER::new(%kwargs)->parse_chunks();;
27            
28 1749         2437 delete @{$self}{'raw_chunks'};
  1749         2799  
29            
30 1749         4319 return $self;
31             }
32              
33             sub parse_chunks
34             {
35 1790     1790 0 1553 my( $self ) = @_;
36 1790         1659 while( scalar @{$self->{'raw_chunks'}} )
  8460         13438  
37             {
38 6711         9120 $self->add_chunk( $self->parse_next_chunk());
39             }
40 1749         2391 return $self;
41             }
42              
43             sub parse_next_chunk
44             {
45 6501     6501 0 4601 my( $self ) = @_;
46              
47 6501         4223 my $chunk = shift @{$self->{'raw_chunks'}};
  6501         7436  
48 6501         9465 my $chunk_lines = count_lines($chunk);
49            
50 6501 100       28915 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       1610 if( $1 eq 'block.super' )
59             {
60 1         8 require DTL::Fast::Tag::BlockSuper;
61             $chunk = DTL::Fast::Tag::BlockSuper->new(
62             ''
63 1         6 , 'dirs' => $self->{'dirs'}
64             , '_open_tag_lines' => $chunk_lines
65             );
66             }
67             else
68             {
69 637         2156 $chunk = DTL::Fast::Variable->new($1);
70 637         809 $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         7275 $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         5395 $chunk = DTL::Fast::Text->new( $chunk);
99 2364         2150 $DTL::Fast::Template::CURRENT_TEMPLATE_LINE += $chunk_lines;
100             }
101             else
102             {
103 1074         1043 $chunk = undef;
104             }
105            
106 6460         12630 return $chunk;
107             }
108              
109             sub parse_tag_chunk
110             {
111 849     849 0 1277 my( $self, $tag_name, $tag_param, $chunk_lines ) = @_;
112            
113 849         725 my $result = undef;
114              
115             # dynamic module loading
116 849 100 66     1834 if(
117             not exists $DTL::Fast::TAG_HANDLERS{$tag_name}
118             and exists $DTL::Fast::KNOWN_TAGS{$tag_name}
119             )
120             {
121 53         17094 require Module::Load;
122 53         26197 Module::Load::load($DTL::Fast::KNOWN_TAGS{$tag_name});
123 53         541 $DTL::Fast::LOADED_MODULES{$DTL::Fast::KNOWN_TAGS{$tag_name}} = time;
124             }
125              
126             # handling tag
127 849 100       1223 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         3133 , 'dirs' => $self->{'dirs'}
133             , '_open_tag_lines' => $chunk_lines
134             );
135             }
136             else # not found
137             {
138 6         24 my $full_tag_name = join ' ', grep $_, ($tag_name, $tag_param);
139            
140 6 100 66     81 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     30 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     52 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         43 $DTL::Fast::Template::CURRENT_TEMPLATE_LINE += $chunk_lines;
173            
174 6         20 $result = DTL::Fast::Text->new();
175             }
176            
177 809         1225 return $result;
178             }
179              
180             1;