Filename | /usr/lib/x86_64-linux-gnu/perl5/5.28/Template/Parser.pm |
Statements | Executed 229996342 statements in 218s |
Calls | P | F | Exclusive Time |
Inclusive Time |
Subroutine |
---|---|---|---|---|---|
376400 | 1 | 1 | 120s | 171s | _parse | Template::Parser::
376400 | 1 | 1 | 28.5s | 57.4s | split_text | Template::Parser::
375387 | 1 | 1 | 23.0s | 49.2s | new | Template::Parser::
314713 | 1 | 1 | 16.1s | 21.3s | tokenise_directive | Template::Parser::
376400 | 1 | 1 | 10.7s | 239s | parse | Template::Parser::
375387 | 1 | 1 | 10.3s | 17.5s | new_style | Template::Parser::
1846064 | 11 | 1 | 6.08s | 6.08s | CORE:subst (opcode) | Template::Parser::
375387 | 1 | 1 | 5.41s | 7.19s | text_splitter | Template::Parser::
2643427 | 7 | 1 | 5.23s | 5.23s | CORE:match (opcode) | Template::Parser::
313428 | 1 | 1 | 2.84s | 3.20s | location | Template::Parser::
2010639 | 6 | 1 | 2.33s | 2.33s | CORE:regcomp (opcode) | Template::Parser::
2490942 | 1 | 1 | 1.83s | 1.83s | __ANON__[:955] | Template::Parser::
751789 | 4 | 1 | 1.22s | 1.22s | CORE:qr (opcode) | Template::Parser::
1991 | 1 | 1 | 78.9ms | 86.4ms | interpolate_text | Template::Parser::
5968 | 1 | 1 | 70.5ms | 121ms | leave_block | Template::Parser::
5968 | 1 | 1 | 50.2ms | 50.2ms | block_label | Template::Parser::
5968 | 1 | 1 | 32.0ms | 32.0ms | enter_block | Template::Parser::
1 | 1 | 1 | 14.6ms | 14.7ms | BEGIN@41 | Template::Parser::
3982 | 1 | 1 | 5.01ms | 5.01ms | CORE:substcont (opcode) | Template::Parser::
1 | 1 | 1 | 3.70ms | 3.94ms | BEGIN@40 | Template::Parser::
1 | 1 | 1 | 15µs | 20µs | BEGIN@35 | Template::Parser::
1 | 1 | 1 | 12µs | 83µs | BEGIN@44 | Template::Parser::
1 | 1 | 1 | 9µs | 102µs | BEGIN@37 | Template::Parser::
1 | 1 | 1 | 8µs | 246µs | BEGIN@39 | Template::Parser::
1 | 1 | 1 | 7µs | 31µs | BEGIN@45 | Template::Parser::
1 | 1 | 1 | 6µs | 32µs | BEGIN@36 | Template::Parser::
1 | 1 | 1 | 5µs | 27µs | BEGIN@46 | Template::Parser::
1 | 1 | 1 | 5µs | 26µs | BEGIN@47 | Template::Parser::
2 | 2 | 1 | 4µs | 4µs | __ANON__ (xsub) | Template::Parser::
0 | 0 | 0 | 0s | 0s | _dump | Template::Parser::
0 | 0 | 0 | 0s | 0s | _parse_error | Template::Parser::
0 | 0 | 0 | 0s | 0s | add_metadata | Template::Parser::
0 | 0 | 0 | 0s | 0s | define_block | Template::Parser::
0 | 0 | 0 | 0s | 0s | in_block | Template::Parser::
0 | 0 | 0 | 0s | 0s | old_style | Template::Parser::
0 | 0 | 0 | 0s | 0s | pop_defblock | Template::Parser::
0 | 0 | 0 | 0s | 0s | push_defblock | Template::Parser::
Line | State ments |
Time on line |
Calls | Time in subs |
Code |
---|---|---|---|---|---|
1 | #============================================================= -*-Perl-*- | ||||
2 | # | ||||
3 | # Template::Parser | ||||
4 | # | ||||
5 | # DESCRIPTION | ||||
6 | # This module implements a LALR(1) parser and associated support | ||||
7 | # methods to parse template documents into the appropriate "compiled" | ||||
8 | # format. Much of the parser DFA code (see _parse() method) is based | ||||
9 | # on Francois Desarmenien's Parse::Yapp module. Kudos to him. | ||||
10 | # | ||||
11 | # AUTHOR | ||||
12 | # Andy Wardley <abw@wardley.org> | ||||
13 | # | ||||
14 | # COPYRIGHT | ||||
15 | # Copyright (C) 1996-2007 Andy Wardley. All Rights Reserved. | ||||
16 | # | ||||
17 | # This module is free software; you can redistribute it and/or | ||||
18 | # modify it under the same terms as Perl itself. | ||||
19 | # | ||||
20 | # The following copyright notice appears in the Parse::Yapp | ||||
21 | # documentation. | ||||
22 | # | ||||
23 | # The Parse::Yapp module and its related modules and shell | ||||
24 | # scripts are copyright (c) 1998 Francois Desarmenien, | ||||
25 | # France. All rights reserved. | ||||
26 | # | ||||
27 | # You may use and distribute them under the terms of either | ||||
28 | # the GNU General Public License or the Artistic License, as | ||||
29 | # specified in the Perl README file. | ||||
30 | # | ||||
31 | #============================================================================ | ||||
32 | |||||
33 | package Template::Parser; | ||||
34 | |||||
35 | 2 | 24µs | 2 | 24µs | # spent 20µs (15+4) within Template::Parser::BEGIN@35 which was called:
# once (15µs+4µs) by Template::Config::load at line 35 # spent 20µs making 1 call to Template::Parser::BEGIN@35
# spent 4µs making 1 call to strict::import |
36 | 2 | 23µs | 2 | 58µs | # spent 32µs (6+26) within Template::Parser::BEGIN@36 which was called:
# once (6µs+26µs) by Template::Config::load at line 36 # spent 32µs making 1 call to Template::Parser::BEGIN@36
# spent 26µs making 1 call to warnings::import |
37 | 2 | 30µs | 2 | 196µs | # spent 102µs (9+94) within Template::Parser::BEGIN@37 which was called:
# once (9µs+94µs) by Template::Config::load at line 37 # spent 102µs making 1 call to Template::Parser::BEGIN@37
# spent 94µs making 1 call to base::import |
38 | |||||
39 | 2 | 30µs | 2 | 484µs | # spent 246µs (8+238) within Template::Parser::BEGIN@39 which was called:
# once (8µs+238µs) by Template::Config::load at line 39 # spent 246µs making 1 call to Template::Parser::BEGIN@39
# spent 238µs making 1 call to Exporter::import |
40 | 2 | 179µs | 2 | 3.95ms | # spent 3.94ms (3.70+246µs) within Template::Parser::BEGIN@40 which was called:
# once (3.70ms+246µs) by Template::Config::load at line 40 # spent 3.94ms making 1 call to Template::Parser::BEGIN@40
# spent 2µs making 1 call to Template::Parser::__ANON__ |
41 | 2 | 258µs | 2 | 14.7ms | # spent 14.7ms (14.6+58µs) within Template::Parser::BEGIN@41 which was called:
# once (14.6ms+58µs) by Template::Config::load at line 41 # spent 14.7ms making 1 call to Template::Parser::BEGIN@41
# spent 3µs making 1 call to Template::Parser::__ANON__ |
42 | |||||
43 | # parser state constants | ||||
44 | 2 | 30µs | 2 | 153µs | # spent 83µs (12+71) within Template::Parser::BEGIN@44 which was called:
# once (12µs+71µs) by Template::Config::load at line 44 # spent 83µs making 1 call to Template::Parser::BEGIN@44
# spent 71µs making 1 call to constant::import |
45 | 2 | 23µs | 2 | 55µs | # spent 31µs (7+24) within Template::Parser::BEGIN@45 which was called:
# once (7µs+24µs) by Template::Config::load at line 45 # spent 31µs making 1 call to Template::Parser::BEGIN@45
# spent 24µs making 1 call to constant::import |
46 | 2 | 21µs | 2 | 49µs | # spent 27µs (5+22) within Template::Parser::BEGIN@46 which was called:
# once (5µs+22µs) by Template::Config::load at line 46 # spent 27µs making 1 call to Template::Parser::BEGIN@46
# spent 22µs making 1 call to constant::import |
47 | 2 | 3.52ms | 2 | 48µs | # spent 26µs (5+21) within Template::Parser::BEGIN@47 which was called:
# once (5µs+21µs) by Template::Config::load at line 47 # spent 26µs making 1 call to Template::Parser::BEGIN@47
# spent 21µs making 1 call to constant::import |
48 | |||||
49 | 1 | 400ns | our $VERSION = 2.89; | ||
50 | 1 | 400ns | our $DEBUG = 0 unless defined $DEBUG; | ||
51 | 1 | 400ns | our $ERROR = ''; | ||
52 | |||||
53 | # The ANYCASE option can cause conflicts when reserved words are used as | ||||
54 | # variable names, hash keys, template names, plugin names, etc. The | ||||
55 | # | ||||
56 | # $ANYCASE_BEFORE regex identifies where such a word precedes an assignment, | ||||
57 | # either as a variable (C<wrapper = 'html'>) or hash key (C<{ wrapper => 'html' }). | ||||
58 | # In that case it is treated as a simple words rather than being the lower case | ||||
59 | # equivalent of the upper case keyword (e.g. WRAPPER). | ||||
60 | # | ||||
61 | # $ANYCASE_AFTER is used to identify when such a word follows a symbols that | ||||
62 | # suggests it can't be a keyword, e.g. after BLOCK INCLUDE WRAPPER, USE, etc. | ||||
63 | 1 | 11µs | 1 | 2µs | our $ANYCASE_BEFORE = qr/\G((?=\s*[=\.]))/; # spent 2µs making 1 call to Template::Parser::CORE:qr |
64 | our $ANYCASE_AFTER = { | ||||
65 | 1 | 22µs | map { $_ => 1 } | ||
66 | qw( | ||||
67 | GET SET CALL DEFAULT INSERT INCLUDE PROCESS WRAPPER BLOCK USE | ||||
68 | PLUGIN FILTER MACRO IN TO STEP AND OR NOT DIV MOD DOT | ||||
69 | IF UNLESS ELSIF FOR WHILE SWITCH CASE META THROW CATCH VIEW | ||||
70 | CMPOP BINOP COMMA | ||||
71 | ), | ||||
72 | '(', '[', '{' | ||||
73 | # not sure about ASSIGN as it breaks C<header_html = include header> | ||||
74 | }; | ||||
75 | |||||
76 | |||||
77 | #======================================================================== | ||||
78 | # -- COMMON TAG STYLES -- | ||||
79 | #======================================================================== | ||||
80 | |||||
81 | 1 | 8µs | our $TAG_STYLE = { | ||
82 | 'outline' => [ '\[%', '%\]', '%%' ], # NEW! Outline tag | ||||
83 | 'default' => [ '\[%', '%\]' ], | ||||
84 | 'template1' => [ '[\[%]%', '%[\]%]' ], | ||||
85 | 'metatext' => [ '%%', '%%' ], | ||||
86 | 'html' => [ '<!--', '-->' ], | ||||
87 | 'mason' => [ '<%', '>' ], | ||||
88 | 'asp' => [ '<%', '%>' ], | ||||
89 | 'php' => [ '<\?', '\?>' ], | ||||
90 | 'star' => [ '\[\*', '\*\]' ], | ||||
91 | }; | ||||
92 | 1 | 1µs | $TAG_STYLE->{ template } = $TAG_STYLE->{ tt2 } = $TAG_STYLE->{ default }; | ||
93 | |||||
94 | |||||
95 | our $DEFAULT_STYLE = { | ||||
96 | START_TAG => $TAG_STYLE->{ default }->[0], | ||||
97 | END_TAG => $TAG_STYLE->{ default }->[1], | ||||
98 | 1 | 7µs | OUTLINE_TAG => $TAG_STYLE->{ default }->[2], | ||
99 | # TAG_STYLE => 'default', | ||||
100 | ANYCASE => 0, | ||||
101 | INTERPOLATE => 0, | ||||
102 | PRE_CHOMP => 0, | ||||
103 | POST_CHOMP => 0, | ||||
104 | V1DOLLAR => 0, | ||||
105 | EVAL_PERL => 0, | ||||
106 | }; | ||||
107 | |||||
108 | 1 | 2µs | our $QUOTED_ESCAPES = { | ||
109 | n => "\n", | ||||
110 | r => "\r", | ||||
111 | t => "\t", | ||||
112 | }; | ||||
113 | |||||
114 | # note that '-' must come first so Perl doesn't think it denotes a range | ||||
115 | 1 | 3µs | 1 | 600ns | our $CHOMP_FLAGS = qr/[-=~+]/; # spent 600ns making 1 call to Template::Parser::CORE:qr |
116 | |||||
- - | |||||
119 | #======================================================================== | ||||
120 | # ----- PUBLIC METHODS ----- | ||||
121 | #======================================================================== | ||||
122 | |||||
123 | #------------------------------------------------------------------------ | ||||
124 | # new(\%config) | ||||
125 | # | ||||
126 | # Constructor method. | ||||
127 | #------------------------------------------------------------------------ | ||||
128 | |||||
129 | # spent 49.2s (23.0+26.2) within Template::Parser::new which was called 375387 times, avg 131µs/call:
# 375387 times (23.0s+26.2s) by Template::Config::parser at line 103 of Template/Config.pm, avg 131µs/call | ||||
130 | 375387 | 155ms | my $class = shift; | ||
131 | 375387 | 706ms | my $config = $_[0] && ref($_[0]) eq 'HASH' ? shift(@_) : { @_ }; | ||
132 | 375387 | 168ms | my ($tagstyle, $debug, $start, $end, $defaults, $grammar, $hash, $key, $udef); | ||
133 | |||||
134 | my $self = bless { | ||||
135 | START_TAG => undef, | ||||
136 | END_TAG => undef, | ||||
137 | OUTLINE_TAG => undef, | ||||
138 | TAG_STYLE => 'default', | ||||
139 | ANYCASE => 0, | ||||
140 | INTERPOLATE => 0, | ||||
141 | PRE_CHOMP => 0, | ||||
142 | POST_CHOMP => 0, | ||||
143 | V1DOLLAR => 0, | ||||
144 | EVAL_PERL => 0, | ||||
145 | FILE_INFO => 1, | ||||
146 | GRAMMAR => undef, | ||||
147 | _ERROR => '', | ||||
148 | IN_BLOCK => [ ], | ||||
149 | TRACE_VARS => $config->{ TRACE_VARS }, | ||||
150 | 375387 | 5.56s | FACTORY => $config->{ FACTORY } || 'Template::Directive', | ||
151 | }, $class; | ||||
152 | |||||
153 | # update self with any relevant keys in config | ||||
154 | 375387 | 1.40s | foreach $key (keys %$self) { | ||
155 | 6006192 | 1.73s | $self->{ $key } = $config->{ $key } if defined $config->{ $key }; | ||
156 | } | ||||
157 | 375387 | 510ms | $self->{ FILEINFO } = [ ]; | ||
158 | |||||
159 | # DEBUG config item can be a bitmask | ||||
160 | 375387 | 805ms | if (defined ($debug = $config->{ DEBUG })) { | ||
161 | $self->{ DEBUG } = $debug & ( Template::Constants::DEBUG_PARSER | ||||
162 | | Template::Constants::DEBUG_FLAGS ); | ||||
163 | $self->{ DEBUG_DIRS } = $debug & Template::Constants::DEBUG_DIRS; | ||||
164 | } | ||||
165 | # package variable can be set to 1 to support previous behaviour | ||||
166 | elsif ($DEBUG == 1) { | ||||
167 | $self->{ DEBUG } = Template::Constants::DEBUG_PARSER; | ||||
168 | $self->{ DEBUG_DIRS } = 0; | ||||
169 | } | ||||
170 | # otherwise let $DEBUG be a bitmask | ||||
171 | else { | ||||
172 | 375387 | 341ms | $self->{ DEBUG } = $DEBUG & ( Template::Constants::DEBUG_PARSER | ||
173 | | Template::Constants::DEBUG_FLAGS ); | ||||
174 | 375387 | 285ms | $self->{ DEBUG_DIRS } = $DEBUG & Template::Constants::DEBUG_DIRS; | ||
175 | } | ||||
176 | |||||
177 | 375387 | 427ms | $grammar = $self->{ GRAMMAR } ||= do { | ||
178 | 375387 | 229ms | require Template::Grammar; | ||
179 | 375387 | 1.34s | 375387 | 1.92s | Template::Grammar->new(); # spent 1.92s making 375387 calls to Template::Grammar::new, avg 5µs/call |
180 | }; | ||||
181 | |||||
182 | # instantiate a FACTORY object | ||||
183 | 375387 | 553ms | unless (ref $self->{ FACTORY }) { | ||
184 | 375387 | 272ms | my $fclass = $self->{ FACTORY }; | ||
185 | $self->{ FACTORY } = $self->{ FACTORY }->new( | ||||
186 | NAMESPACE => $config->{ NAMESPACE } | ||||
187 | ) | ||||
188 | 375387 | 1.66s | 375387 | 6.75s | || return $class->error($self->{ FACTORY }->error()); # spent 6.75s making 375387 calls to Template::Base::new, avg 18µs/call |
189 | } | ||||
190 | |||||
191 | # load grammar rules, states and lex table | ||||
192 | @$self{ qw( LEXTABLE STATES RULES ) } | ||||
193 | 375387 | 1.39s | = @$grammar{ qw( LEXTABLE STATES RULES ) }; | ||
194 | |||||
195 | 375387 | 1.25s | 375387 | 17.5s | $self->new_style($config) # spent 17.5s making 375387 calls to Template::Parser::new_style, avg 47µs/call |
196 | || return $class->error($self->error()); | ||||
197 | |||||
198 | 375387 | 1.93s | return $self; | ||
199 | } | ||||
200 | |||||
201 | #----------------------------------------------------------------------- | ||||
202 | # These methods are used to track nested IF and WHILE blocks. Each | ||||
203 | # generated if/while block is given a label indicating the directive | ||||
204 | # type and nesting depth, e.g. FOR0, WHILE1, FOR2, WHILE3, etc. The | ||||
205 | # NEXT and LAST directives use the innermost label, e.g. last WHILE3; | ||||
206 | #----------------------------------------------------------------------- | ||||
207 | |||||
208 | # spent 32.0ms within Template::Parser::enter_block which was called 5968 times, avg 5µs/call:
# 5968 times (32.0ms+0s) by Template::Grammar::__ANON__[Parser.yp:167] at line 167 of /root/tor-browser-build/Parser.yp, avg 5µs/call | ||||
209 | 5968 | 3.94ms | my ($self, $name) = @_; | ||
210 | 5968 | 6.57ms | my $blocks = $self->{ IN_BLOCK }; | ||
211 | 5968 | 43.7ms | push(@{ $self->{ IN_BLOCK } }, $name); | ||
212 | } | ||||
213 | |||||
214 | # spent 121ms (70.5+50.2) within Template::Parser::leave_block which was called 5968 times, avg 20µs/call:
# 5968 times (70.5ms+50.2ms) by Template::Grammar::__ANON__[Parser.yp:168] at line 168 of /root/tor-browser-build/Parser.yp, avg 20µs/call | ||||
215 | 5968 | 3.33ms | my $self = shift; | ||
216 | 5968 | 23.9ms | 5968 | 50.2ms | my $label = $self->block_label; # spent 50.2ms making 5968 calls to Template::Parser::block_label, avg 8µs/call |
217 | 5968 | 8.52ms | pop(@{ $self->{ IN_BLOCK } }); | ||
218 | 5968 | 35.1ms | return $label; | ||
219 | } | ||||
220 | |||||
221 | sub in_block { | ||||
222 | my ($self, $name) = @_; | ||||
223 | my $blocks = $self->{ IN_BLOCK }; | ||||
224 | return @$blocks && $blocks->[-1] eq $name; | ||||
225 | } | ||||
226 | |||||
227 | # spent 50.2ms within Template::Parser::block_label which was called 5968 times, avg 8µs/call:
# 5968 times (50.2ms+0s) by Template::Parser::leave_block at line 216, avg 8µs/call | ||||
228 | 5968 | 5.99ms | my ($self, $prefix, $suffix) = @_; | ||
229 | 5968 | 7.18ms | my $blocks = $self->{ IN_BLOCK }; | ||
230 | 5968 | 14.0ms | my $name = @$blocks | ||
231 | ? $blocks->[-1] . scalar @$blocks | ||||
232 | : undef; | ||||
233 | 5968 | 45.5ms | return join('', grep { defined $_ } $prefix, $name, $suffix); | ||
234 | } | ||||
235 | |||||
- - | |||||
238 | #------------------------------------------------------------------------ | ||||
239 | # new_style(\%config) | ||||
240 | # | ||||
241 | # Install a new (stacked) parser style. This feature is currently | ||||
242 | # experimental but should mimic the previous behaviour with regard to | ||||
243 | # TAG_STYLE, START_TAG, END_TAG, etc. | ||||
244 | #------------------------------------------------------------------------ | ||||
245 | |||||
246 | # spent 17.5s (10.3+7.19) within Template::Parser::new_style which was called 375387 times, avg 47µs/call:
# 375387 times (10.3s+7.19s) by Template::Parser::new at line 195, avg 47µs/call | ||||
247 | 375387 | 246ms | my ($self, $config) = @_; | ||
248 | 375387 | 661ms | my $styles = $self->{ STYLE } ||= [ ]; | ||
249 | 375387 | 171ms | my ($tagstyle, $tags, $start, $end, $out, $key); | ||
250 | |||||
251 | # clone new style from previous or default style | ||||
252 | 375387 | 2.47s | my $style = { %{ $styles->[-1] || $DEFAULT_STYLE } }; | ||
253 | |||||
254 | # expand START_TAG and END_TAG from specified TAG_STYLE | ||||
255 | 375387 | 351ms | if ($tagstyle = $config->{ TAG_STYLE }) { | ||
256 | return $self->error("Invalid tag style: $tagstyle") | ||||
257 | unless defined ($tags = $TAG_STYLE->{ $tagstyle }); | ||||
258 | ($start, $end, $out) = @$tags; | ||||
259 | $config->{ START_TAG } ||= $start; | ||||
260 | $config->{ END_TAG } ||= $end; | ||||
261 | $config->{ OUTLINE_TAG } ||= $out; | ||||
262 | } | ||||
263 | |||||
264 | 375387 | 832ms | foreach $key (keys %$DEFAULT_STYLE) { | ||
265 | 3378483 | 1.08s | $style->{ $key } = $config->{ $key } if defined $config->{ $key }; | ||
266 | } | ||||
267 | |||||
268 | 375387 | 305ms | $start = $style->{ START_TAG }; | ||
269 | 375387 | 317ms | $end = $style->{ END_TAG }; | ||
270 | 375387 | 227ms | $out = $style->{ OUTLINE_TAG }; | ||
271 | 375387 | 1.26s | 375387 | 7.19s | $style->{ TEXT_SPLIT } = $self->text_splitter($start, $end, $out); # spent 7.19s making 375387 calls to Template::Parser::text_splitter, avg 19µs/call |
272 | |||||
273 | 375387 | 166ms | push(@$styles, $style); | ||
274 | 375387 | 2.12s | return $style; | ||
275 | } | ||||
276 | |||||
277 | # spent 7.19s (5.41+1.78) within Template::Parser::text_splitter which was called 375387 times, avg 19µs/call:
# 375387 times (5.41s+1.78s) by Template::Parser::new_style at line 271, avg 19µs/call | ||||
278 | 375387 | 365ms | my ($self, $start, $end, $out) = @_; | ||
279 | |||||
280 | 375387 | 262ms | if (defined $out) { | ||
281 | return qr/ | ||||
282 | \A(.*?) # $1 - start of line up to directive | ||||
283 | (?: | ||||
284 | (?: | ||||
285 | ^$out # outline tag at start of line | ||||
286 | (.*?) # $2 - content of that line | ||||
287 | (?:\n|$) # end of that line or file | ||||
288 | ) | ||||
289 | | | ||||
290 | (?: | ||||
291 | $start # start of tag | ||||
292 | (.*?) # $3 - tag contents | ||||
293 | $end # end of tag | ||||
294 | ) | ||||
295 | ) | ||||
296 | /msx; | ||||
297 | } | ||||
298 | else { | ||||
299 | 375387 | 7.85s | 750774 | 1.78s | return qr/ # spent 996ms making 375387 calls to Template::Parser::CORE:regcomp, avg 3µs/call
# spent 788ms making 375387 calls to Template::Parser::CORE:qr, avg 2µs/call |
300 | ^(.*?) # $1 - start of line up to directive | ||||
301 | (?: | ||||
302 | $start # start of tag | ||||
303 | (.*?) # $2 - tag contents | ||||
304 | $end # end of tag | ||||
305 | ) | ||||
306 | /sx; | ||||
307 | } | ||||
308 | } | ||||
309 | |||||
310 | #------------------------------------------------------------------------ | ||||
311 | # old_style() | ||||
312 | # | ||||
313 | # Pop the current parser style and revert to the previous one. See | ||||
314 | # new_style(). ** experimental ** | ||||
315 | #------------------------------------------------------------------------ | ||||
316 | |||||
317 | sub old_style { | ||||
318 | my $self = shift; | ||||
319 | my $styles = $self->{ STYLE }; | ||||
320 | return $self->error('only 1 parser style remaining') | ||||
321 | unless (@$styles > 1); | ||||
322 | pop @$styles; | ||||
323 | return $styles->[-1]; | ||||
324 | } | ||||
325 | |||||
326 | |||||
327 | #------------------------------------------------------------------------ | ||||
328 | # parse($text, $data) | ||||
329 | # | ||||
330 | # Parses the text string, $text and returns a hash array representing | ||||
331 | # the compiled template block(s) as Perl code, in the format expected | ||||
332 | # by Template::Document. | ||||
333 | #------------------------------------------------------------------------ | ||||
334 | |||||
335 | # spent 239s (10.7+228) within Template::Parser::parse which was called 376400 times, avg 634µs/call:
# 376400 times (10.7s+228s) by Template::Provider::_compile at line 844 of Template/Provider.pm, avg 634µs/call | ||||
336 | 376400 | 321ms | my ($self, $text, $info) = @_; | ||
337 | 376400 | 134ms | my ($tokens, $block); | ||
338 | |||||
339 | $info->{ DEBUG } = $self->{ DEBUG_DIRS } | ||||
340 | 376400 | 629ms | unless defined $info->{ DEBUG }; | ||
341 | |||||
342 | # print "info: { ", join(', ', map { "$_ => $info->{ $_ }" } keys %$info), " }\n"; | ||||
343 | |||||
344 | # store for blocks defined in the template (see define_block()) | ||||
345 | 376400 | 456ms | my $defblock = $self->{ DEFBLOCK } = { }; | ||
346 | 376400 | 416ms | my $metadata = $self->{ METADATA } = [ ]; | ||
347 | 376400 | 432ms | my $variables = $self->{ VARIABLES } = { }; | ||
348 | 376400 | 327ms | $self->{ DEFBLOCKS } = [ ]; | ||
349 | |||||
350 | 376400 | 340ms | $self->{ _ERROR } = ''; | ||
351 | |||||
352 | # split file into TEXT/DIRECTIVE chunks | ||||
353 | 376400 | 980ms | 376400 | 57.4s | $tokens = $self->split_text($text) # spent 57.4s making 376400 calls to Template::Parser::split_text, avg 153µs/call |
354 | || return undef; ## RETURN ## | ||||
355 | |||||
356 | 376400 | 487ms | push(@{ $self->{ FILEINFO } }, $info); | ||
357 | |||||
358 | # parse chunks | ||||
359 | 376400 | 1.21s | 376400 | 171s | $block = $self->_parse($tokens, $info); # spent 171s making 376400 calls to Template::Parser::_parse, avg 453µs/call |
360 | |||||
361 | 376400 | 300ms | pop(@{ $self->{ FILEINFO } }); | ||
362 | |||||
363 | 376400 | 149ms | return undef unless $block; ## RETURN ## | ||
364 | |||||
365 | $self->debug("compiled main template document block:\n$block") | ||||
366 | 376400 | 377ms | if $self->{ DEBUG } & Template::Constants::DEBUG_PARSER; | ||
367 | |||||
368 | return { | ||||
369 | 376400 | 2.95s | BLOCK => $block, | ||
370 | DEFBLOCKS => $defblock, | ||||
371 | VARIABLES => $variables, | ||||
372 | METADATA => { @$metadata }, | ||||
373 | }; | ||||
374 | } | ||||
375 | |||||
- - | |||||
378 | #------------------------------------------------------------------------ | ||||
379 | # split_text($text) | ||||
380 | # | ||||
381 | # Split input template text into directives and raw text chunks. | ||||
382 | #------------------------------------------------------------------------ | ||||
383 | |||||
384 | # spent 57.4s (28.5+28.9) within Template::Parser::split_text which was called 376400 times, avg 153µs/call:
# 376400 times (28.5s+28.9s) by Template::Parser::parse at line 353, avg 153µs/call | ||||
385 | 376400 | 245ms | my ($self, $text) = @_; | ||
386 | 376400 | 198ms | my ($pre, $dir, $prelines, $dirlines, $postlines, $chomp, $tags, @tags); | ||
387 | 376400 | 412ms | my $style = $self->{ STYLE }->[-1]; | ||
388 | my ($start, $end, $out, $prechomp, $postchomp, $interp ) = | ||||
389 | 376400 | 1.11s | @$style{ qw( START_TAG END_TAG OUTLINE_TAG PRE_CHOMP POST_CHOMP INTERPOLATE ) }; | ||
390 | 376400 | 2.38s | 376400 | 434ms | my $tags_dir = $self->{ANYCASE} ? qr<TAGS>i : qr<TAGS>; # spent 434ms making 376400 calls to Template::Parser::CORE:qr, avg 1µs/call |
391 | 376400 | 281ms | my $split = $style->{ TEXT_SPLIT }; | ||
392 | 376400 | 303ms | my $has_out = defined $out; | ||
393 | |||||
394 | 376400 | 265ms | my @tokens = (); | ||
395 | 376400 | 192ms | my $line = 1; | ||
396 | |||||
397 | return \@tokens ## RETURN ## | ||||
398 | 376400 | 315ms | unless defined $text && length $text; | ||
399 | |||||
400 | # extract all directives from the text | ||||
401 | 376400 | 5.54s | 752800 | 1.92s | while ($text =~ s/$split//) { # spent 1.30s making 376400 calls to Template::Parser::CORE:subst, avg 3µs/call
# spent 619ms making 376400 calls to Template::Parser::CORE:regcomp, avg 2µs/call |
402 | 314713 | 436ms | $pre = $1; | ||
403 | 314713 | 521ms | $dir = defined($2) ? $2 : $3; | ||
404 | 314713 | 123ms | $pre = '' unless defined $pre; | ||
405 | 314713 | 118ms | $dir = '' unless defined $dir; | ||
406 | |||||
407 | 314713 | 272ms | $prelines = ($pre =~ tr/\n//); # newlines in preceding text | ||
408 | 314713 | 128ms | $dirlines = ($dir =~ tr/\n//); # newlines in directive tag | ||
409 | 314713 | 97.7ms | $postlines = 0; # newlines chomped after tag | ||
410 | |||||
411 | 314713 | 284ms | for ($dir) { | ||
412 | 314713 | 1.61s | 314713 | 175ms | if (/^\#/) { # spent 175ms making 314713 calls to Template::Parser::CORE:match, avg 557ns/call |
413 | # comment out entire directive except for any end chomp flag | ||||
414 | $dir = ($dir =~ /($CHOMP_FLAGS)$/o) ? $1 : ''; | ||||
415 | } | ||||
416 | else { | ||||
417 | |||||
418 | 314713 | 3.52s | 629426 | 718ms | if(s/^($CHOMP_FLAGS)?(\s*)//so && $2) { # spent 651ms making 314713 calls to Template::Parser::CORE:subst, avg 2µs/call
# spent 67.2ms making 314713 calls to Template::Parser::CORE:regcomp, avg 214ns/call |
419 | 314713 | 205ms | my $chomped = $2; | ||
420 | 314713 | 180ms | my $linecount = ($chomped =~ tr/\n//); # newlines in chomped whitespace | ||
421 | 314713 | 105ms | $linecount ||= 0; | ||
422 | 314713 | 56.2ms | $prelines += $linecount; | ||
423 | 314713 | 120ms | $dirlines -= $linecount; | ||
424 | } | ||||
425 | # PRE_CHOMP: process whitespace before tag | ||||
426 | 314713 | 173ms | $chomp = $1 ? $1 : $prechomp; | ||
427 | 314713 | 149ms | $chomp =~ tr/-=~+/1230/; | ||
428 | 314713 | 107ms | if ($chomp && $pre) { | ||
429 | # chomp off whitespace and newline preceding directive | ||||
430 | 1991 | 1.11ms | if ($chomp == CHOMP_ALL) { | ||
431 | 1991 | 27.6ms | 1991 | 6.47ms | $pre =~ s{ (\r?\n|^) [^\S\n]* \z }{}mx; # spent 6.47ms making 1991 calls to Template::Parser::CORE:subst, avg 3µs/call |
432 | } | ||||
433 | elsif ($chomp == CHOMP_COLLAPSE) { | ||||
434 | $pre =~ s{ (\s+) \z }{ }x; | ||||
435 | } | ||||
436 | elsif ($chomp == CHOMP_GREEDY) { | ||||
437 | $pre =~ s{ (\s+) \z }{}x; | ||||
438 | } | ||||
439 | } | ||||
440 | } | ||||
441 | |||||
442 | # POST_CHOMP: process whitespace after tag | ||||
443 | 314713 | 5.32s | 629426 | 3.05s | s/\s*($CHOMP_FLAGS)?\s*$//so; # spent 3.01s making 314713 calls to Template::Parser::CORE:subst, avg 10µs/call
# spent 36.7ms making 314713 calls to Template::Parser::CORE:regcomp, avg 117ns/call |
444 | 314713 | 205ms | $chomp = $1 ? $1 : $postchomp; | ||
445 | 314713 | 122ms | $chomp =~ tr/-=~+/1230/; | ||
446 | 314713 | 215ms | if ($chomp) { | ||
447 | 47165 | 32.1ms | if ($chomp == CHOMP_ALL) { | ||
448 | 47165 | 364ms | 47165 | 122ms | $text =~ s{ ^ ([^\S\n]* \n) }{}x # spent 122ms making 47165 calls to Template::Parser::CORE:subst, avg 3µs/call |
449 | && $postlines++; | ||||
450 | } | ||||
451 | elsif ($chomp == CHOMP_COLLAPSE) { | ||||
452 | $text =~ s{ ^ (\s+) }{ }x | ||||
453 | && ($postlines += $1=~y/\n//); | ||||
454 | } | ||||
455 | # any trailing whitespace | ||||
456 | elsif ($chomp == CHOMP_GREEDY) { | ||||
457 | $text =~ s{ ^ (\s+) }{}x | ||||
458 | && ($postlines += $1=~y/\n//); | ||||
459 | } | ||||
460 | } | ||||
461 | } | ||||
462 | |||||
463 | # any text preceding the directive can now be added | ||||
464 | 314713 | 392ms | if (length $pre) { | ||
465 | push(@tokens, $interp | ||||
466 | ? [ $pre, $line, 'ITEXT' ] | ||||
467 | : ('TEXT', $pre) ); | ||||
468 | } | ||||
469 | 314713 | 112ms | $line += $prelines; | ||
470 | |||||
471 | # and now the directive, along with line number information | ||||
472 | 314713 | 138ms | if (length $dir) { | ||
473 | # the TAGS directive is a compile-time switch | ||||
474 | 314713 | 2.72s | 629426 | 472ms | if ($dir =~ /^$tags_dir\s+(.*)/) { # spent 360ms making 314713 calls to Template::Parser::CORE:regcomp, avg 1µs/call
# spent 112ms making 314713 calls to Template::Parser::CORE:match, avg 357ns/call |
475 | my @tags = split(/\s+/, $1); | ||||
476 | if (scalar @tags > 1) { | ||||
477 | ($start, $end, $out) = map { quotemeta($_) } @tags; | ||||
478 | $split = $self->text_splitter($start, $end, $out); | ||||
479 | } | ||||
480 | elsif ($tags = $TAG_STYLE->{ $tags[0] }) { | ||||
481 | ($start, $end, $out) = @$tags; | ||||
482 | $split = $self->text_splitter($start, $end, $out); | ||||
483 | } | ||||
484 | else { | ||||
485 | warn "invalid TAGS style: $tags[0]\n"; | ||||
486 | } | ||||
487 | } | ||||
488 | else { | ||||
489 | # DIRECTIVE is pushed as: | ||||
490 | # [ $dirtext, $line_no(s), \@tokens ] | ||||
491 | 314713 | 1.16s | 314713 | 21.3s | push(@tokens, # spent 21.3s making 314713 calls to Template::Parser::tokenise_directive, avg 68µs/call |
492 | [ $dir, | ||||
493 | ($dirlines | ||||
494 | ? sprintf("%d-%d", $line, $line + $dirlines) | ||||
495 | : $line), | ||||
496 | $self->tokenise_directive($dir) ]); | ||||
497 | } | ||||
498 | } | ||||
499 | |||||
500 | # update line counter to include directive lines and any extra | ||||
501 | # newline chomped off the start of the following text | ||||
502 | 314713 | 3.23s | 629426 | 777ms | $line += $dirlines + $postlines; # spent 530ms making 314713 calls to Template::Parser::CORE:subst, avg 2µs/call
# spent 248ms making 314713 calls to Template::Parser::CORE:regcomp, avg 787ns/call |
503 | } | ||||
504 | |||||
505 | # anything remaining in the string is plain text | ||||
506 | 376400 | 389ms | push(@tokens, $interp | ||
507 | ? [ $text, $line, 'ITEXT' ] | ||||
508 | : ( 'TEXT', $text) ) | ||||
509 | if length $text; | ||||
510 | |||||
511 | 376400 | 2.69s | return \@tokens; ## RETURN ## | ||
512 | } | ||||
513 | |||||
- - | |||||
516 | #------------------------------------------------------------------------ | ||||
517 | # interpolate_text($text, $line) | ||||
518 | # | ||||
519 | # Examines $text looking for any variable references embedded like | ||||
520 | # $this or like ${ this }. | ||||
521 | #------------------------------------------------------------------------ | ||||
522 | |||||
523 | # spent 86.4ms (78.9+7.44) within Template::Parser::interpolate_text which was called 1991 times, avg 43µs/call:
# 1991 times (78.9ms+7.44ms) by Template::Parser::tokenise_directive at line 656, avg 43µs/call | ||||
524 | 1991 | 2.18ms | my ($self, $text, $line) = @_; | ||
525 | 1991 | 3.16ms | my @tokens = (); | ||
526 | 1991 | 674µs | my ($pre, $var, $dir); | ||
527 | |||||
528 | |||||
529 | 1991 | 21.4ms | 1991 | 6.75ms | while ($text =~ # spent 6.75ms making 1991 calls to Template::Parser::CORE:match, avg 3µs/call |
530 | / | ||||
531 | ( (?: \\. | [^\$] ){1,3000} ) # escaped or non-'$' character [$1] | ||||
532 | | | ||||
533 | ( \$ (?: # embedded variable [$2] | ||||
534 | (?: \{ ([^\}]*) \} ) # ${ ... } [$3] | ||||
535 | | | ||||
536 | ([\w\.]+) # $word [$4] | ||||
537 | ) | ||||
538 | ) | ||||
539 | /gx) { | ||||
540 | |||||
541 | 1991 | 4.32ms | ($pre, $var, $dir) = ($1, $3 || $4, $2); | ||
542 | |||||
543 | # preceding text | ||||
544 | 1991 | 2.28ms | if (defined($pre) && length($pre)) { | ||
545 | 1991 | 2.01ms | $line += $pre =~ tr/\n//; | ||
546 | 1991 | 19.5ms | 1991 | 355µs | $pre =~ s/\\\$/\$/g; # spent 355µs making 1991 calls to Template::Parser::CORE:subst, avg 178ns/call |
547 | 1991 | 2.72ms | push(@tokens, 'TEXT', $pre); | ||
548 | } | ||||
549 | # $variable reference | ||||
550 | 1991 | 21.3ms | 1991 | 330µs | if ($var) { # spent 330µs making 1991 calls to Template::Parser::CORE:match, avg 166ns/call |
551 | $line += $dir =~ tr/\n/ /; | ||||
552 | push(@tokens, [ $dir, $line, $self->tokenise_directive($var) ]); | ||||
553 | } | ||||
554 | # other '$' reference - treated as text | ||||
555 | elsif ($dir) { | ||||
556 | $line += $dir =~ tr/\n//; | ||||
557 | push(@tokens, 'TEXT', $dir); | ||||
558 | } | ||||
559 | } | ||||
560 | |||||
561 | 1991 | 16.5ms | return \@tokens; | ||
562 | } | ||||
563 | |||||
- - | |||||
566 | #------------------------------------------------------------------------ | ||||
567 | # tokenise_directive($text) | ||||
568 | # | ||||
569 | # Called by the private _parse() method when it encounters a DIRECTIVE | ||||
570 | # token in the list provided by the split_text() or interpolate_text() | ||||
571 | # methods. The directive text is passed by parameter. | ||||
572 | # | ||||
573 | # The method splits the directive into individual tokens as recognised | ||||
574 | # by the parser grammar (see Template::Grammar for details). It | ||||
575 | # constructs a list of tokens each represented by 2 elements, as per | ||||
576 | # split_text() et al. The first element contains the token type, the | ||||
577 | # second the token itself. | ||||
578 | # | ||||
579 | # The method tokenises the string using a complex (but fast) regex. | ||||
580 | # For a deeper understanding of the regex magic at work here, see | ||||
581 | # Jeffrey Friedl's excellent book "Mastering Regular Expressions", | ||||
582 | # from O'Reilly, ISBN 1-56592-257-3 | ||||
583 | # | ||||
584 | # Returns a reference to the list of chunks (each one being 2 elements) | ||||
585 | # identified in the directive text. On error, the internal _ERROR string | ||||
586 | # is set and undef is returned. | ||||
587 | #------------------------------------------------------------------------ | ||||
588 | |||||
589 | # spent 21.3s (16.1+5.12) within Template::Parser::tokenise_directive which was called 314713 times, avg 68µs/call:
# 314713 times (16.1s+5.12s) by Template::Parser::split_text at line 491, avg 68µs/call | ||||
590 | 314713 | 182ms | my ($self, $text, $line) = @_; | ||
591 | 314713 | 101ms | my ($token, $uctoken, $type, $lookup); | ||
592 | 314713 | 247ms | my $lextable = $self->{ LEXTABLE }; | ||
593 | 314713 | 211ms | my $style = $self->{ STYLE }->[-1]; | ||
594 | 314713 | 412ms | my ($anycase, $start, $end) = @$style{ qw( ANYCASE START_TAG END_TAG ) }; | ||
595 | 314713 | 156ms | my @tokens = ( ); | ||
596 | |||||
597 | 314713 | 3.03s | 316704 | 1.70s | while ($text =~ # spent 1.70s making 316704 calls to Template::Parser::CORE:match, avg 5µs/call |
598 | / | ||||
599 | # strip out any comments | ||||
600 | (\#[^\n]*) | ||||
601 | | | ||||
602 | # a quoted phrase matches in $3 | ||||
603 | (["']) # $2 - opening quote, ' or " | ||||
604 | ( # $3 - quoted text buffer | ||||
605 | (?: # repeat group (no backreference) | ||||
606 | \\\\ # an escaped backslash \\ | ||||
607 | | # ...or... | ||||
608 | \\\2 # an escaped quote \" or \' (match $1) | ||||
609 | | # ...or... | ||||
610 | . # any other character | ||||
611 | | \n | ||||
612 | )*? # non-greedy repeat | ||||
613 | ) # end of $3 | ||||
614 | \2 # match opening quote | ||||
615 | | | ||||
616 | # an unquoted number matches in $4 | ||||
617 | (-?\d+(?:\.\d+)?) # numbers | ||||
618 | | | ||||
619 | # filename matches in $5 | ||||
620 | ( \/?\w+(?:(?:\/|::?)\w*)+ | \/\w+) | ||||
621 | | | ||||
622 | # an identifier matches in $6 | ||||
623 | (\w+) # variable identifier | ||||
624 | | | ||||
625 | # an unquoted word or symbol matches in $7 | ||||
626 | ( [(){}\[\]:;,\/\\] # misc parenthesis and symbols | ||||
627 | # | \-> # arrow operator (for future?) | ||||
628 | | [+\-*] # math operations | ||||
629 | | \$\{? # dollar with option left brace | ||||
630 | | => # like '=' | ||||
631 | | [=!<>]?= | [!<>] # eqality tests | ||||
632 | | &&? | \|\|? # boolean ops | ||||
633 | | \.\.? # n..n sequence | ||||
634 | | \S+ # something unquoted | ||||
635 | ) # end of $7 | ||||
636 | /gmxo) { | ||||
637 | |||||
638 | # ignore comments to EOL | ||||
639 | 1536347 | 345ms | next if $1; | ||
640 | |||||
641 | # quoted string | ||||
642 | 1536347 | 2.32s | if (defined ($token = $3)) { | ||
643 | # double-quoted string may include $variable references | ||||
644 | 243677 | 175ms | if ($2 eq '"') { | ||
645 | 158959 | 736ms | 158959 | 106ms | if ($token =~ /[\$\\]/) { # spent 106ms making 158959 calls to Template::Parser::CORE:match, avg 664ns/call |
646 | 1991 | 1.37ms | $type = 'QUOTED'; | ||
647 | # unescape " and \ but leave \$ escaped so that | ||||
648 | # interpolate_text() doesn't incorrectly treat it | ||||
649 | # as a variable reference | ||||
650 | # $token =~ s/\\([\\"])/$1/g; | ||||
651 | 1991 | 2.66ms | for ($token) { | ||
652 | 1991 | 10.2ms | 1991 | 4.44ms | s/\\([^\$nrt])/$1/g; # spent 4.44ms making 1991 calls to Template::Parser::CORE:subst, avg 2µs/call |
653 | 1991 | 53.1ms | 5973 | 9.94ms | s/\\([nrt])/$QUOTED_ESCAPES->{ $1 }/ge; # spent 5.01ms making 3982 calls to Template::Parser::CORE:substcont, avg 1µs/call
# spent 4.93ms making 1991 calls to Template::Parser::CORE:subst, avg 2µs/call |
654 | } | ||||
655 | push(@tokens, ('"') x 2, | ||||
656 | 1991 | 14.2ms | 1991 | 86.4ms | @{ $self->interpolate_text($token) }, # spent 86.4ms making 1991 calls to Template::Parser::interpolate_text, avg 43µs/call |
657 | ('"') x 2); | ||||
658 | 1991 | 1.71ms | next; | ||
659 | } | ||||
660 | else { | ||||
661 | 156968 | 74.4ms | $type = 'LITERAL'; | ||
662 | 156968 | 666ms | 156968 | 80.9ms | $token =~ s['][\\']g; # spent 80.9ms making 156968 calls to Template::Parser::CORE:subst, avg 515ns/call |
663 | 156968 | 89.1ms | $token = "'$token'"; | ||
664 | } | ||||
665 | } | ||||
666 | else { | ||||
667 | 84718 | 19.9ms | $type = 'LITERAL'; | ||
668 | 84718 | 37.2ms | $token = "'$token'"; | ||
669 | } | ||||
670 | } | ||||
671 | # number | ||||
672 | elsif (defined ($token = $4)) { | ||||
673 | $type = 'NUMBER'; | ||||
674 | } | ||||
675 | elsif (defined($token = $5)) { | ||||
676 | $type = 'FILENAME'; | ||||
677 | } | ||||
678 | elsif (defined($token = $6)) { | ||||
679 | # Fold potential keywords to UPPER CASE if the ANYCASE option is | ||||
680 | # set, unless (we've got some preceding tokens and) the previous | ||||
681 | # token is a DOT op. This prevents the 'last' in 'data.last' | ||||
682 | # from being interpreted as the LAST keyword. | ||||
683 | 571294 | 229ms | if ($anycase) { | ||
684 | # if the token follows a dot or precedes an assignment then | ||||
685 | # it's not for folding, e.g. the 'wrapper' in this: | ||||
686 | # [% page = { wrapper='html' }; page.wrapper %] | ||||
687 | if ((@tokens && $ANYCASE_AFTER->{ $tokens[-2] }) | ||||
688 | || ($text =~ /$ANYCASE_BEFORE/gc)) { | ||||
689 | # keep the token unmodified | ||||
690 | $uctoken = $token; | ||||
691 | } | ||||
692 | else { | ||||
693 | $uctoken = uc $token; | ||||
694 | } | ||||
695 | } | ||||
696 | else { | ||||
697 | 571294 | 160ms | $uctoken = $token; | ||
698 | } | ||||
699 | 571294 | 616ms | if (defined ($type = $lextable->{ $uctoken })) { | ||
700 | $token = $uctoken; | ||||
701 | } | ||||
702 | else { | ||||
703 | 431260 | 163ms | $type = 'IDENT'; | ||
704 | } | ||||
705 | } | ||||
706 | elsif (defined ($token = $7)) { | ||||
707 | # reserved words may be in lower case unless case sensitive | ||||
708 | 707297 | 145ms | $uctoken = $anycase ? uc $token : $token; | ||
709 | 707297 | 473ms | unless (defined ($type = $lextable->{ $uctoken })) { | ||
710 | $type = 'UNQUOTED'; | ||||
711 | } | ||||
712 | } | ||||
713 | |||||
714 | 1534356 | 9.64s | 1534356 | 3.13s | push(@tokens, $type, $token); # spent 3.13s making 1534356 calls to Template::Parser::CORE:match, avg 2µs/call |
715 | |||||
716 | # print(STDERR " +[ $type, $token ]\n") | ||||
717 | # if $DEBUG; | ||||
718 | } | ||||
719 | |||||
720 | # print STDERR "tokenise directive() returning:\n [ @tokens ]\n" | ||||
721 | # if $DEBUG; | ||||
722 | |||||
723 | 314713 | 1.88s | return \@tokens; ## RETURN ## | ||
724 | } | ||||
725 | |||||
726 | |||||
727 | #------------------------------------------------------------------------ | ||||
728 | # define_block($name, $block) | ||||
729 | # | ||||
730 | # Called by the parser 'defblock' rule when a BLOCK definition is | ||||
731 | # encountered in the template. The name of the block is passed in the | ||||
732 | # first parameter and a reference to the compiled block is passed in | ||||
733 | # the second. This method stores the block in the $self->{ DEFBLOCK } | ||||
734 | # hash which has been initialised by parse() and will later be used | ||||
735 | # by the same method to call the store() method on the calling cache | ||||
736 | # to define the block "externally". | ||||
737 | #------------------------------------------------------------------------ | ||||
738 | |||||
739 | sub define_block { | ||||
740 | my ($self, $name, $block) = @_; | ||||
741 | my $defblock = $self->{ DEFBLOCK } | ||||
742 | || return undef; | ||||
743 | |||||
744 | $self->debug("compiled block '$name':\n$block") | ||||
745 | if $self->{ DEBUG } & Template::Constants::DEBUG_PARSER; | ||||
746 | |||||
747 | $defblock->{ $name } = $block; | ||||
748 | |||||
749 | return undef; | ||||
750 | } | ||||
751 | |||||
752 | sub push_defblock { | ||||
753 | my $self = shift; | ||||
754 | my $stack = $self->{ DEFBLOCK_STACK } ||= []; | ||||
755 | push(@$stack, $self->{ DEFBLOCK } ); | ||||
756 | $self->{ DEFBLOCK } = { }; | ||||
757 | } | ||||
758 | |||||
759 | sub pop_defblock { | ||||
760 | my $self = shift; | ||||
761 | my $defs = $self->{ DEFBLOCK }; | ||||
762 | my $stack = $self->{ DEFBLOCK_STACK } || return $defs; | ||||
763 | return $defs unless @$stack; | ||||
764 | $self->{ DEFBLOCK } = pop @$stack; | ||||
765 | return $defs; | ||||
766 | } | ||||
767 | |||||
768 | |||||
769 | #------------------------------------------------------------------------ | ||||
770 | # add_metadata(\@setlist) | ||||
771 | #------------------------------------------------------------------------ | ||||
772 | |||||
773 | sub add_metadata { | ||||
774 | my ($self, $setlist) = @_; | ||||
775 | my $metadata = $self->{ METADATA } | ||||
776 | || return undef; | ||||
777 | |||||
778 | push(@$metadata, @$setlist); | ||||
779 | |||||
780 | return undef; | ||||
781 | } | ||||
782 | |||||
783 | |||||
784 | #------------------------------------------------------------------------ | ||||
785 | # location() | ||||
786 | # | ||||
787 | # Return Perl comment indicating current parser file and line | ||||
788 | #------------------------------------------------------------------------ | ||||
789 | |||||
790 | # spent 3.20s (2.84+362ms) within Template::Parser::location which was called 313428 times, avg 10µs/call:
# 313428 times (2.84s+362ms) by Template::Grammar::__ANON__[Parser.yp:79] at line 78 of /root/tor-browser-build/Parser.yp, avg 10µs/call | ||||
791 | 313428 | 122ms | my $self = shift; | ||
792 | 313428 | 160ms | return "\n" unless $self->{ FILE_INFO }; | ||
793 | 313428 | 218ms | my $line = ${ $self->{ LINE } }; | ||
794 | 313428 | 242ms | my $info = $self->{ FILEINFO }->[-1]; | ||
795 | my $file = $info->{ path } || $info->{ name } | ||||
796 | 313428 | 275ms | || '(unknown template)'; | ||
797 | 313428 | 1.41s | 313428 | 362ms | $line =~ s/\-.*$//; # might be 'n-n' # spent 362ms making 313428 calls to Template::Parser::CORE:subst, avg 1µs/call |
798 | 313428 | 115ms | $line ||= 1; | ||
799 | 313428 | 1.43s | return "#line $line \"$file\"\n"; | ||
800 | } | ||||
801 | |||||
802 | |||||
803 | #======================================================================== | ||||
804 | # ----- PRIVATE METHODS ----- | ||||
805 | #======================================================================== | ||||
806 | |||||
807 | #------------------------------------------------------------------------ | ||||
808 | # _parse(\@tokens, \@info) | ||||
809 | # | ||||
810 | # Parses the list of input tokens passed by reference and returns a | ||||
811 | # Template::Directive::Block object which contains the compiled | ||||
812 | # representation of the template. | ||||
813 | # | ||||
814 | # This is the main parser DFA loop. See embedded comments for | ||||
815 | # further details. | ||||
816 | # | ||||
817 | # On error, undef is returned and the internal _ERROR field is set to | ||||
818 | # indicate the error. This can be retrieved by calling the error() | ||||
819 | # method. | ||||
820 | #------------------------------------------------------------------------ | ||||
821 | |||||
822 | # spent 171s (120+51.0) within Template::Parser::_parse which was called 376400 times, avg 453µs/call:
# 376400 times (120s+51.0s) by Template::Parser::parse at line 359, avg 453µs/call | ||||
823 | 376400 | 209ms | my ($self, $tokens, $info) = @_; | ||
824 | 376400 | 208ms | my ($token, $value, $text, $line, $inperl); | ||
825 | my ($state, $stateno, $status, $action, $lookup, $coderet, @codevars); | ||||
826 | my ($lhs, $len, $code); # rule contents | ||||
827 | 376400 | 556ms | my $stack = [ [ 0, undef ] ]; # DFA stack | ||
828 | |||||
829 | # DEBUG | ||||
830 | # local $" = ', '; | ||||
831 | |||||
832 | # retrieve internal rule and state tables | ||||
833 | 376400 | 381ms | my ($states, $rules) = @$self{ qw( STATES RULES ) }; | ||
834 | |||||
835 | # If we're tracing variable usage then we need to give the factory a | ||||
836 | # reference to our $self->{ VARIABLES } for it to fill in. This is a | ||||
837 | # bit of a hack to back-patch this functionality into TT2. | ||||
838 | $self->{ FACTORY }->trace_vars($self->{ VARIABLES }) | ||||
839 | 376400 | 373ms | if $self->{ TRACE_VARS }; | ||
840 | |||||
841 | # call the grammar set_factory method to install emitter factory | ||||
842 | 376400 | 1.39s | 376400 | 747ms | $self->{ GRAMMAR }->install_factory($self->{ FACTORY }); # spent 747ms making 376400 calls to Template::Grammar::install_factory, avg 2µs/call |
843 | |||||
844 | 376400 | 179ms | $line = $inperl = 0; | ||
845 | 376400 | 425ms | $self->{ LINE } = \$line; | ||
846 | 376400 | 581ms | $self->{ FILE } = $info->{ name }; | ||
847 | 376400 | 430ms | $self->{ INPERL } = \$inperl; | ||
848 | |||||
849 | 376400 | 190ms | $status = CONTINUE; | ||
850 | 376400 | 179ms | my $in_string = 0; | ||
851 | |||||
852 | 376400 | 9.36s | while(1) { | ||
853 | # get state number and state | ||||
854 | 9928655 | 2.17s | $stateno = $stack->[-1]->[0]; | ||
855 | 9928655 | 2.96s | $state = $states->[$stateno]; | ||
856 | |||||
857 | # see if any lookaheads exist for the current state | ||||
858 | 9928655 | 5.39s | if (exists $state->{'ACTIONS'}) { | ||
859 | |||||
860 | # get next token and expand any directives (i.e. token is an | ||||
861 | # array ref) onto the front of the token list | ||||
862 | 4616236 | 1.81s | while (! defined $token && @$tokens) { | ||
863 | 2665397 | 1.03s | $token = shift(@$tokens); | ||
864 | 2665397 | 1.71s | if (ref $token) { | ||
865 | 314713 | 338ms | ($text, $line, $token) = @$token; | ||
866 | 314713 | 135ms | if (ref $token) { | ||
867 | 314713 | 247ms | if ($info->{ DEBUG } && ! $in_string) { | ||
868 | # - - - - - - - - - - - - - - - - - - - - - - - - - | ||||
869 | # This is gnarly. Look away now if you're easily | ||||
870 | # frightened. We're pushing parse tokens onto the | ||||
871 | # pending list to simulate a DEBUG directive like so: | ||||
872 | # [% DEBUG msg line='20' text='INCLUDE foo' %] | ||||
873 | # - - - - - - - - - - - - - - - - - - - - - - - - - | ||||
874 | my $dtext = $text; | ||||
875 | $dtext =~ s[(['\\])][\\$1]g; | ||||
876 | unshift(@$tokens, | ||||
877 | DEBUG => 'DEBUG', | ||||
878 | IDENT => 'msg', | ||||
879 | IDENT => 'line', | ||||
880 | ASSIGN => '=', | ||||
881 | LITERAL => "'$line'", | ||||
882 | IDENT => 'text', | ||||
883 | ASSIGN => '=', | ||||
884 | LITERAL => "'$dtext'", | ||||
885 | IDENT => 'file', | ||||
886 | ASSIGN => '=', | ||||
887 | LITERAL => "'$info->{ name }'", | ||||
888 | (';') x 2, | ||||
889 | @$token, | ||||
890 | (';') x 2); | ||||
891 | } | ||||
892 | else { | ||||
893 | 314713 | 1.22s | unshift(@$tokens, @$token, (';') x 2); | ||
894 | } | ||||
895 | 314713 | 74.1ms | $token = undef; # force redo | ||
896 | } | ||||
897 | elsif ($token eq 'ITEXT') { | ||||
898 | if ($inperl) { | ||||
899 | # don't perform interpolation in PERL blocks | ||||
900 | $token = 'TEXT'; | ||||
901 | $value = $text; | ||||
902 | } | ||||
903 | else { | ||||
904 | unshift(@$tokens, | ||||
905 | @{ $self->interpolate_text($text, $line) }); | ||||
906 | $token = undef; # force redo | ||||
907 | } | ||||
908 | } | ||||
909 | } | ||||
910 | else { | ||||
911 | # toggle string flag to indicate if we're crossing | ||||
912 | # a string boundary | ||||
913 | 2350684 | 558ms | $in_string = ! $in_string if $token eq '"'; | ||
914 | 2350684 | 687ms | $value = shift(@$tokens); | ||
915 | } | ||||
916 | }; | ||||
917 | # clear undefined token to avoid 'undefined variable blah blah' | ||||
918 | # warnings and let the parser logic pick it up in a minute | ||||
919 | 4616236 | 740ms | $token = '' unless defined $token; | ||
920 | |||||
921 | # get the next state for the current lookahead token | ||||
922 | $action = defined ($lookup = $state->{'ACTIONS'}->{ $token }) | ||||
923 | ? $lookup | ||||
924 | 4616236 | 3.99s | : defined ($lookup = $state->{'DEFAULT'}) | ||
925 | ? $lookup | ||||
926 | : undef; | ||||
927 | } | ||||
928 | else { | ||||
929 | # no lookahead actions | ||||
930 | 5312419 | 1.39s | $action = $state->{'DEFAULT'}; | ||
931 | } | ||||
932 | |||||
933 | # ERROR: no ACTION | ||||
934 | 9928655 | 1.09s | last unless defined $action; | ||
935 | |||||
936 | # - - - - - - - - - - - - - - - - - - - - - - - - - - - - | ||||
937 | # shift (+ive ACTION) | ||||
938 | # - - - - - - - - - - - - - - - - - - - - - - - - - - - - | ||||
939 | 9928655 | 1.57s | if ($action > 0) { | ||
940 | 2727084 | 1.58s | push(@$stack, [ $action, $value ]); | ||
941 | 2727084 | 596ms | $token = $value = undef; | ||
942 | 2727084 | 583ms | redo; | ||
943 | }; | ||||
944 | |||||
945 | # - - - - - - - - - - - - - - - - - - - - - - - - - - - - | ||||
946 | # reduce (-ive ACTION) | ||||
947 | # - - - - - - - - - - - - - - - - - - - - - - - - - - - - | ||||
948 | 7201571 | 8.02s | ($lhs, $len, $code) = @{ $rules->[ -$action ] }; | ||
949 | |||||
950 | # no action imples ACCEPTance | ||||
951 | 7201571 | 834ms | $action | ||
952 | or $status = ACCEPT; | ||||
953 | |||||
954 | # use dummy sub if code ref doesn't exist | ||||
955 | 2490942 | 15.9s | # spent 1.83s within Template::Parser::__ANON__[/usr/lib/x86_64-linux-gnu/perl5/5.28/Template/Parser.pm:955] which was called 2490942 times, avg 734ns/call:
# 2490942 times (1.83s+0s) by Template::Parser::_parse at line 963, avg 734ns/call | ||
956 | 7201571 | 3.95s | unless $code; | ||
957 | |||||
958 | @codevars = $len | ||||
959 | 7201571 | 9.32s | ? map { $_->[1] } @$stack[ -$len .. -1 ] | ||
960 | : (); | ||||
961 | |||||
962 | 7201571 | 1.96s | eval { | ||
963 | 7201571 | 11.4s | 7201571 | 50.2s | $coderet = &$code( $self, @codevars ); # spent 15.4s making 495642 calls to Template::Grammar::__ANON__[Parser.yp:76], avg 31µs/call
# spent 7.08s making 376400 calls to Template::Grammar::__ANON__[Parser.yp:64], avg 19µs/call
# spent 5.53s making 321403 calls to Template::Grammar::__ANON__[Parser.yp:79], avg 17µs/call
# spent 4.75s making 431466 calls to Template::Grammar::__ANON__[Parser.yp:67], avg 11µs/call
# spent 4.59s making 372329 calls to Template::Grammar::__ANON__[Parser.yp:305], avg 12µs/call
# spent 2.66s making 250383 calls to Template::Grammar::__ANON__[Parser.yp:90], avg 11µs/call
# spent 2.37s making 242791 calls to Template::Grammar::__ANON__[Parser.yp:342], avg 10µs/call
# spent 1.83s making 2490942 calls to Template::Parser::__ANON__[Template/Parser.pm:955], avg 734ns/call
# spent 1.11s making 431466 calls to Template::Grammar::__ANON__[Parser.yp:73], avg 3µs/call
# spent 923ms making 385579 calls to Template::Grammar::__ANON__[Parser.yp:72], avg 2µs/call
# spent 739ms making 424294 calls to Template::Grammar::__ANON__[Parser.yp:345], avg 2µs/call
# spent 588ms making 37103 calls to Template::Grammar::__ANON__[Parser.yp:141], avg 16µs/call
# spent 506ms making 285731 calls to Template::Grammar::__ANON__[Parser.yp:382], avg 2µs/call
# spent 423ms making 159453 calls to Template::Grammar::__ANON__[Parser.yp:341], avg 3µs/call
# spent 357ms making 5968 calls to Template::Grammar::__ANON__[Parser.yp:168], avg 60µs/call
# spent 307ms making 249772 calls to Template::Grammar::__ANON__[Parser.yp:387], avg 1µs/call
# spent 130ms making 4031 calls to Template::Grammar::__ANON__[Parser.yp:115], avg 32µs/call
# spent 123ms making 3982 calls to Template::Grammar::__ANON__[Parser.yp:95], avg 31µs/call
# spent 89.7ms making 5968 calls to Template::Grammar::__ANON__[Parser.yp:167], avg 15µs/call
# spent 70.2ms making 6966 calls to Template::Grammar::__ANON__[Parser.yp:113], avg 10µs/call
# spent 67.4ms making 21902 calls to Template::Grammar::__ANON__[Parser.yp:334], avg 3µs/call
# spent 57.0ms making 22050 calls to Template::Grammar::__ANON__[Parser.yp:331], avg 3µs/call
# spent 53.4ms making 28096 calls to Template::Grammar::__ANON__[Parser.yp:152], avg 2µs/call
# spent 49.3ms making 1991 calls to Template::Grammar::__ANON__[Parser.yp:440], avg 25µs/call
# spent 46.9ms making 42940 calls to Template::Grammar::__ANON__[Parser.yp:386], avg 1µs/call
# spent 44.0ms making 22921 calls to Template::Grammar::__ANON__[Parser.yp:358], avg 2µs/call
# spent 43.9ms making 1013 calls to Template::Grammar::__ANON__[Parser.yp:118], avg 43µs/call
# spent 42.1ms making 3982 calls to Template::Grammar::__ANON__[Parser.yp:114], avg 11µs/call
# spent 36.4ms making 18052 calls to Template::Grammar::__ANON__[Parser.yp:302], avg 2µs/call
# spent 29.2ms making 1991 calls to Template::Grammar::__ANON__[Parser.yp:307], avg 15µs/call
# spent 24.9ms making 9007 calls to Template::Grammar::__ANON__[Parser.yp:151], avg 3µs/call
# spent 17.9ms making 6015 calls to Template::Grammar::__ANON__[Parser.yp:361], avg 3µs/call
# spent 15.8ms making 5988 calls to Template::Grammar::__ANON__[Parser.yp:325], avg 3µs/call
# spent 15.2ms making 8013 calls to Template::Grammar::__ANON__[Parser.yp:374], avg 2µs/call
# spent 14.1ms making 2984 calls to Template::Grammar::__ANON__[Parser.yp:175], avg 5µs/call
# spent 11.5ms making 2984 calls to Template::Grammar::__ANON__[Parser.yp:176], avg 4µs/call
# spent 8.12ms making 2988 calls to Template::Grammar::__ANON__[Parser.yp:150], avg 3µs/call
# spent 7.43ms making 1990 calls to Template::Grammar::__ANON__[Parser.yp:360], avg 4µs/call
# spent 6.88ms making 1991 calls to Template::Grammar::__ANON__[Parser.yp:435], avg 3µs/call
# spent 5.54ms making 2016 calls to Template::Grammar::__ANON__[Parser.yp:359], avg 3µs/call
# spent 4.79ms making 1991 calls to Template::Grammar::__ANON__[Parser.yp:299], avg 2µs/call
# spent 4.44ms making 1990 calls to Template::Grammar::__ANON__[Parser.yp:322], avg 2µs/call
# spent 3.56ms making 1991 calls to Template::Grammar::__ANON__[Parser.yp:301], avg 2µs/call
# spent 3.50ms making 1991 calls to Template::Grammar::__ANON__[Parser.yp:436], avg 2µs/call
# spent 3.42ms making 1013 calls to Template::Grammar::__ANON__[Parser.yp:412], avg 3µs/call
# spent 3.08ms making 1013 calls to Template::Grammar::__ANON__[Parser.yp:407], avg 3µs/call
# spent 2.94ms making 998 calls to Template::Grammar::__ANON__[Parser.yp:416], avg 3µs/call
# spent 3µs making 1 call to Template::Grammar::__ANON__[Parser.yp:362] |
964 | }; | ||||
965 | 7201571 | 731ms | if ($@) { | ||
966 | my $err = $@; | ||||
967 | chomp $err; | ||||
968 | return $self->_parse_error($err); | ||||
969 | } | ||||
970 | |||||
971 | # reduce stack by $len | ||||
972 | 7201571 | 3.51s | splice(@$stack, -$len, $len); | ||
973 | |||||
974 | # ACCEPT | ||||
975 | 7201571 | 3.64s | return $coderet ## RETURN ## | ||
976 | if $status == ACCEPT; | ||||
977 | |||||
978 | # ABORT | ||||
979 | return undef ## RETURN ## | ||||
980 | 6825171 | 1.01s | if $status == ABORT; | ||
981 | |||||
982 | # ERROR | ||||
983 | last | ||||
984 | 6825171 | 1.07s | if $status == ERROR; | ||
985 | } | ||||
986 | continue { | ||||
987 | push(@$stack, [ $states->[ $stack->[-1][0] ]->{'GOTOS'}->{ $lhs }, | ||||
988 | $coderet ]), | ||||
989 | } | ||||
990 | |||||
991 | # ERROR ## RETURN ## | ||||
992 | return $self->_parse_error('unexpected end of input') | ||||
993 | unless defined $value; | ||||
994 | |||||
995 | # munge text of last directive to make it readable | ||||
996 | # $text =~ s/\n/\\n/g; | ||||
997 | |||||
998 | return $self->_parse_error("unexpected end of directive", $text) | ||||
999 | if $value eq ';'; # end of directive SEPARATOR | ||||
1000 | |||||
1001 | return $self->_parse_error("unexpected token ($value)", $text); | ||||
1002 | } | ||||
1003 | |||||
- - | |||||
1006 | #------------------------------------------------------------------------ | ||||
1007 | # _parse_error($msg, $dirtext) | ||||
1008 | # | ||||
1009 | # Method used to handle errors encountered during the parse process | ||||
1010 | # in the _parse() method. | ||||
1011 | #------------------------------------------------------------------------ | ||||
1012 | |||||
1013 | sub _parse_error { | ||||
1014 | my ($self, $msg, $text) = @_; | ||||
1015 | my $line = $self->{ LINE }; | ||||
1016 | $line = ref($line) ? $$line : $line; | ||||
1017 | $line = 'unknown' unless $line; | ||||
1018 | |||||
1019 | $msg .= "\n [% $text %]" | ||||
1020 | if defined $text; | ||||
1021 | |||||
1022 | return $self->error("line $line: $msg"); | ||||
1023 | } | ||||
1024 | |||||
1025 | |||||
1026 | #------------------------------------------------------------------------ | ||||
1027 | # _dump() | ||||
1028 | # | ||||
1029 | # Debug method returns a string representing the internal state of the | ||||
1030 | # object. | ||||
1031 | #------------------------------------------------------------------------ | ||||
1032 | |||||
1033 | sub _dump { | ||||
1034 | my $self = shift; | ||||
1035 | my $output = "[Template::Parser] {\n"; | ||||
1036 | my $format = " %-16s => %s\n"; | ||||
1037 | my $key; | ||||
1038 | |||||
1039 | foreach $key (qw( START_TAG END_TAG TAG_STYLE ANYCASE INTERPOLATE | ||||
1040 | PRE_CHOMP POST_CHOMP V1DOLLAR )) { | ||||
1041 | my $val = $self->{ $key }; | ||||
1042 | $val = '<undef>' unless defined $val; | ||||
1043 | $output .= sprintf($format, $key, $val); | ||||
1044 | } | ||||
1045 | |||||
1046 | $output .= '}'; | ||||
1047 | return $output; | ||||
1048 | } | ||||
1049 | |||||
1050 | |||||
1051 | 1 | 18µs | 1; | ||
1052 | |||||
1053 | __END__ | ||||
# spent 5.23s within Template::Parser::CORE:match which was called 2643427 times, avg 2µs/call:
# 1534356 times (3.13s+0s) by Template::Parser::tokenise_directive at line 714, avg 2µs/call
# 316704 times (1.70s+0s) by Template::Parser::tokenise_directive at line 597, avg 5µs/call
# 314713 times (175ms+0s) by Template::Parser::split_text at line 412, avg 557ns/call
# 314713 times (112ms+0s) by Template::Parser::split_text at line 474, avg 357ns/call
# 158959 times (106ms+0s) by Template::Parser::tokenise_directive at line 645, avg 664ns/call
# 1991 times (6.75ms+0s) by Template::Parser::interpolate_text at line 529, avg 3µs/call
# 1991 times (330µs+0s) by Template::Parser::interpolate_text at line 550, avg 166ns/call | |||||
# spent 1.22s within Template::Parser::CORE:qr which was called 751789 times, avg 2µs/call:
# 376400 times (434ms+0s) by Template::Parser::split_text at line 390, avg 1µs/call
# 375387 times (788ms+0s) by Template::Parser::text_splitter at line 299, avg 2µs/call
# once (2µs+0s) by Template::Config::load at line 63
# once (600ns+0s) by Template::Config::load at line 115 | |||||
# spent 2.33s within Template::Parser::CORE:regcomp which was called 2010639 times, avg 1µs/call:
# 376400 times (619ms+0s) by Template::Parser::split_text at line 401, avg 2µs/call
# 375387 times (996ms+0s) by Template::Parser::text_splitter at line 299, avg 3µs/call
# 314713 times (360ms+0s) by Template::Parser::split_text at line 474, avg 1µs/call
# 314713 times (248ms+0s) by Template::Parser::split_text at line 502, avg 787ns/call
# 314713 times (67.2ms+0s) by Template::Parser::split_text at line 418, avg 214ns/call
# 314713 times (36.7ms+0s) by Template::Parser::split_text at line 443, avg 117ns/call | |||||
# spent 6.08s within Template::Parser::CORE:subst which was called 1846064 times, avg 3µs/call:
# 376400 times (1.30s+0s) by Template::Parser::split_text at line 401, avg 3µs/call
# 314713 times (3.01s+0s) by Template::Parser::split_text at line 443, avg 10µs/call
# 314713 times (651ms+0s) by Template::Parser::split_text at line 418, avg 2µs/call
# 314713 times (530ms+0s) by Template::Parser::split_text at line 502, avg 2µs/call
# 313428 times (362ms+0s) by Template::Parser::location at line 797, avg 1µs/call
# 156968 times (80.9ms+0s) by Template::Parser::tokenise_directive at line 662, avg 515ns/call
# 47165 times (122ms+0s) by Template::Parser::split_text at line 448, avg 3µs/call
# 1991 times (6.47ms+0s) by Template::Parser::split_text at line 431, avg 3µs/call
# 1991 times (4.93ms+0s) by Template::Parser::tokenise_directive at line 653, avg 2µs/call
# 1991 times (4.44ms+0s) by Template::Parser::tokenise_directive at line 652, avg 2µs/call
# 1991 times (355µs+0s) by Template::Parser::interpolate_text at line 546, avg 178ns/call | |||||
# spent 5.01ms within Template::Parser::CORE:substcont which was called 3982 times, avg 1µs/call:
# 3982 times (5.01ms+0s) by Template::Parser::tokenise_directive at line 653, avg 1µs/call | |||||
sub Template::Parser::__ANON__; # xsub |