Filename | /usr/lib/x86_64-linux-gnu/perl5/5.28/Template/Parser.pm |
Statements | Executed 231636656 statements in 224s |
Calls | P | F | Exclusive Time |
Inclusive Time |
Subroutine |
---|---|---|---|---|---|
384174 | 1 | 1 | 122s | 174s | _parse | Template::Parser::
384174 | 1 | 1 | 28.3s | 58.0s | split_text | Template::Parser::
383161 | 1 | 1 | 25.4s | 53.1s | new | Template::Parser::
314713 | 1 | 1 | 16.6s | 21.9s | tokenise_directive | Template::Parser::
383161 | 1 | 1 | 11.2s | 18.7s | new_style | Template::Parser::
384174 | 1 | 1 | 11.1s | 244s | parse | Template::Parser::
1853838 | 11 | 1 | 6.02s | 6.02s | CORE:subst (opcode) | Template::Parser::
383161 | 1 | 1 | 5.63s | 7.45s | text_splitter | Template::Parser::
2643427 | 7 | 1 | 5.39s | 5.39s | CORE:match (opcode) | Template::Parser::
313428 | 1 | 1 | 2.91s | 3.24s | location | Template::Parser::
2026187 | 6 | 1 | 2.48s | 2.48s | CORE:regcomp (opcode) | Template::Parser::
2498716 | 1 | 1 | 1.81s | 1.81s | __ANON__[:955] | Template::Parser::
767337 | 4 | 1 | 1.32s | 1.32s | CORE:qr (opcode) | Template::Parser::
5968 | 1 | 1 | 85.0ms | 135ms | leave_block | Template::Parser::
5968 | 1 | 1 | 49.9ms | 49.9ms | block_label | Template::Parser::
1991 | 1 | 1 | 48.4ms | 56.3ms | interpolate_text | Template::Parser::
5968 | 1 | 1 | 39.0ms | 39.0ms | enter_block | Template::Parser::
1 | 1 | 1 | 14.0ms | 14.1ms | BEGIN@41 | Template::Parser::
3982 | 1 | 1 | 5.03ms | 5.03ms | CORE:substcont (opcode) | Template::Parser::
1 | 1 | 1 | 4.36ms | 4.61ms | BEGIN@40 | Template::Parser::
1 | 1 | 1 | 16µs | 20µs | BEGIN@35 | Template::Parser::
1 | 1 | 1 | 10µs | 100µs | BEGIN@44 | Template::Parser::
1 | 1 | 1 | 9µs | 88µs | BEGIN@37 | Template::Parser::
1 | 1 | 1 | 8µs | 245µs | BEGIN@39 | Template::Parser::
1 | 1 | 1 | 8µs | 31µs | BEGIN@36 | Template::Parser::
1 | 1 | 1 | 6µs | 29µs | BEGIN@45 | Template::Parser::
1 | 1 | 1 | 6µs | 28µs | BEGIN@46 | Template::Parser::
1 | 1 | 1 | 5µs | 25µs | BEGIN@47 | Template::Parser::
2 | 2 | 1 | 3µs | 3µ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 | 31µs | 2 | 25µs | # spent 20µs (16+5) within Template::Parser::BEGIN@35 which was called:
# once (16µs+5µ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 | 24µs | 2 | 55µs | # spent 31µs (8+24) within Template::Parser::BEGIN@36 which was called:
# once (8µs+24µs) by Template::Config::load at line 36 # spent 31µs making 1 call to Template::Parser::BEGIN@36
# spent 24µs making 1 call to warnings::import |
37 | 2 | 32µs | 2 | 166µs | # spent 88µs (9+79) within Template::Parser::BEGIN@37 which was called:
# once (9µs+79µs) by Template::Config::load at line 37 # spent 88µs making 1 call to Template::Parser::BEGIN@37
# spent 79µs making 1 call to base::import |
38 | |||||
39 | 2 | 31µs | 2 | 482µs | # spent 245µs (8+237) within Template::Parser::BEGIN@39 which was called:
# once (8µs+237µs) by Template::Config::load at line 39 # spent 245µs making 1 call to Template::Parser::BEGIN@39
# spent 237µs making 1 call to Exporter::import |
40 | 2 | 844µs | 2 | 4.62ms | # spent 4.61ms (4.36+251µs) within Template::Parser::BEGIN@40 which was called:
# once (4.36ms+251µs) by Template::Config::load at line 40 # spent 4.61ms making 1 call to Template::Parser::BEGIN@40
# spent 1µs making 1 call to Template::Parser::__ANON__ |
41 | 2 | 706µs | 2 | 14.1ms | # spent 14.1ms (14.0+49µs) within Template::Parser::BEGIN@41 which was called:
# once (14.0ms+49µs) by Template::Config::load at line 41 # spent 14.1ms making 1 call to Template::Parser::BEGIN@41
# spent 2µs making 1 call to Template::Parser::__ANON__ |
42 | |||||
43 | # parser state constants | ||||
44 | 2 | 31µs | 2 | 191µs | # spent 100µs (10+90) within Template::Parser::BEGIN@44 which was called:
# once (10µs+90µs) by Template::Config::load at line 44 # spent 100µs making 1 call to Template::Parser::BEGIN@44
# spent 90µs making 1 call to constant::import |
45 | 2 | 23µs | 2 | 52µs | # spent 29µs (6+23) within Template::Parser::BEGIN@45 which was called:
# once (6µs+23µs) by Template::Config::load at line 45 # spent 29µs making 1 call to Template::Parser::BEGIN@45
# spent 23µs making 1 call to constant::import |
46 | 2 | 21µs | 2 | 50µs | # spent 28µs (6+22) within Template::Parser::BEGIN@46 which was called:
# once (6µs+22µs) by Template::Config::load at line 46 # spent 28µs making 1 call to Template::Parser::BEGIN@46
# spent 22µs making 1 call to constant::import |
47 | 2 | 3.62ms | 2 | 45µs | # spent 25µs (5+20) within Template::Parser::BEGIN@47 which was called:
# once (5µs+20µs) by Template::Config::load at line 47 # spent 25µs making 1 call to Template::Parser::BEGIN@47
# spent 20µs making 1 call to constant::import |
48 | |||||
49 | 1 | 600ns | our $VERSION = 2.89; | ||
50 | 1 | 500ns | our $DEBUG = 0 unless defined $DEBUG; | ||
51 | 1 | 300ns | 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 | 12µ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 | 21µ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 | 4µ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 | 4µ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 | 700ns | our $CHOMP_FLAGS = qr/[-=~+]/; # spent 700ns 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 53.1s (25.4+27.7) within Template::Parser::new which was called 383161 times, avg 139µs/call:
# 383161 times (25.4s+27.7s) by Template::Config::parser at line 103 of Template/Config.pm, avg 139µs/call | ||||
130 | 383161 | 217ms | my $class = shift; | ||
131 | 383161 | 746ms | my $config = $_[0] && ref($_[0]) eq 'HASH' ? shift(@_) : { @_ }; | ||
132 | 383161 | 158ms | 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 | 383161 | 6.13s | FACTORY => $config->{ FACTORY } || 'Template::Directive', | ||
151 | }, $class; | ||||
152 | |||||
153 | # update self with any relevant keys in config | ||||
154 | 383161 | 1.45s | foreach $key (keys %$self) { | ||
155 | 6130576 | 1.87s | $self->{ $key } = $config->{ $key } if defined $config->{ $key }; | ||
156 | } | ||||
157 | 383161 | 577ms | $self->{ FILEINFO } = [ ]; | ||
158 | |||||
159 | # DEBUG config item can be a bitmask | ||||
160 | 383161 | 881ms | 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 | 383161 | 346ms | $self->{ DEBUG } = $DEBUG & ( Template::Constants::DEBUG_PARSER | ||
173 | | Template::Constants::DEBUG_FLAGS ); | ||||
174 | 383161 | 274ms | $self->{ DEBUG_DIRS } = $DEBUG & Template::Constants::DEBUG_DIRS; | ||
175 | } | ||||
176 | |||||
177 | 383161 | 521ms | $grammar = $self->{ GRAMMAR } ||= do { | ||
178 | 383161 | 285ms | require Template::Grammar; | ||
179 | 383161 | 1.55s | 383161 | 1.97s | Template::Grammar->new(); # spent 1.97s making 383161 calls to Template::Grammar::new, avg 5µs/call |
180 | }; | ||||
181 | |||||
182 | # instantiate a FACTORY object | ||||
183 | 383161 | 651ms | unless (ref $self->{ FACTORY }) { | ||
184 | 383161 | 346ms | my $fclass = $self->{ FACTORY }; | ||
185 | $self->{ FACTORY } = $self->{ FACTORY }->new( | ||||
186 | NAMESPACE => $config->{ NAMESPACE } | ||||
187 | ) | ||||
188 | 383161 | 1.99s | 383161 | 7.07s | || return $class->error($self->{ FACTORY }->error()); # spent 7.07s making 383161 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 | 383161 | 1.63s | = @$grammar{ qw( LEXTABLE STATES RULES ) }; | ||
194 | |||||
195 | 383161 | 1.37s | 383161 | 18.7s | $self->new_style($config) # spent 18.7s making 383161 calls to Template::Parser::new_style, avg 49µs/call |
196 | || return $class->error($self->error()); | ||||
197 | |||||
198 | 383161 | 1.75s | 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 39.0ms within Template::Parser::enter_block which was called 5968 times, avg 7µs/call:
# 5968 times (39.0ms+0s) by Template::Grammar::__ANON__[Parser.yp:167] at line 167 of /root/tor-browser-build/Parser.yp, avg 7µs/call | ||||
209 | 5968 | 4.59ms | my ($self, $name) = @_; | ||
210 | 5968 | 11.5ms | my $blocks = $self->{ IN_BLOCK }; | ||
211 | 5968 | 49.6ms | push(@{ $self->{ IN_BLOCK } }, $name); | ||
212 | } | ||||
213 | |||||
214 | # spent 135ms (85.0+49.9) within Template::Parser::leave_block which was called 5968 times, avg 23µs/call:
# 5968 times (85.0ms+49.9ms) by Template::Grammar::__ANON__[Parser.yp:168] at line 168 of /root/tor-browser-build/Parser.yp, avg 23µs/call | ||||
215 | 5968 | 3.77ms | my $self = shift; | ||
216 | 5968 | 21.9ms | 5968 | 49.9ms | my $label = $self->block_label; # spent 49.9ms making 5968 calls to Template::Parser::block_label, avg 8µs/call |
217 | 5968 | 8.09ms | pop(@{ $self->{ IN_BLOCK } }); | ||
218 | 5968 | 31.8ms | 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 49.9ms within Template::Parser::block_label which was called 5968 times, avg 8µs/call:
# 5968 times (49.9ms+0s) by Template::Parser::leave_block at line 216, avg 8µs/call | ||||
228 | 5968 | 4.55ms | my ($self, $prefix, $suffix) = @_; | ||
229 | 5968 | 7.22ms | my $blocks = $self->{ IN_BLOCK }; | ||
230 | 5968 | 14.3ms | my $name = @$blocks | ||
231 | ? $blocks->[-1] . scalar @$blocks | ||||
232 | : undef; | ||||
233 | 5968 | 62.3ms | 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 18.7s (11.2+7.45) within Template::Parser::new_style which was called 383161 times, avg 49µs/call:
# 383161 times (11.2s+7.45s) by Template::Parser::new at line 195, avg 49µs/call | ||||
247 | 383161 | 248ms | my ($self, $config) = @_; | ||
248 | 383161 | 770ms | my $styles = $self->{ STYLE } ||= [ ]; | ||
249 | 383161 | 172ms | my ($tagstyle, $tags, $start, $end, $out, $key); | ||
250 | |||||
251 | # clone new style from previous or default style | ||||
252 | 383161 | 2.73s | my $style = { %{ $styles->[-1] || $DEFAULT_STYLE } }; | ||
253 | |||||
254 | # expand START_TAG and END_TAG from specified TAG_STYLE | ||||
255 | 383161 | 364ms | 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 | 383161 | 1.02s | foreach $key (keys %$DEFAULT_STYLE) { | ||
265 | 3448449 | 1.14s | $style->{ $key } = $config->{ $key } if defined $config->{ $key }; | ||
266 | } | ||||
267 | |||||
268 | 383161 | 298ms | $start = $style->{ START_TAG }; | ||
269 | 383161 | 288ms | $end = $style->{ END_TAG }; | ||
270 | 383161 | 287ms | $out = $style->{ OUTLINE_TAG }; | ||
271 | 383161 | 1.52s | 383161 | 7.45s | $style->{ TEXT_SPLIT } = $self->text_splitter($start, $end, $out); # spent 7.45s making 383161 calls to Template::Parser::text_splitter, avg 19µs/call |
272 | |||||
273 | 383161 | 273ms | push(@$styles, $style); | ||
274 | 383161 | 2.06s | return $style; | ||
275 | } | ||||
276 | |||||
277 | # spent 7.45s (5.63+1.82) within Template::Parser::text_splitter which was called 383161 times, avg 19µs/call:
# 383161 times (5.63s+1.82s) by Template::Parser::new_style at line 271, avg 19µs/call | ||||
278 | 383161 | 382ms | my ($self, $start, $end, $out) = @_; | ||
279 | |||||
280 | 383161 | 264ms | 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 | 383161 | 8.00s | 766322 | 1.82s | return qr/ # spent 1.05s making 383161 calls to Template::Parser::CORE:regcomp, avg 3µs/call
# spent 769ms making 383161 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 244s (11.1+232) within Template::Parser::parse which was called 384174 times, avg 634µs/call:
# 384174 times (11.1s+232s) by Template::Provider::_compile at line 844 of Template/Provider.pm, avg 634µs/call | ||||
336 | 384174 | 364ms | my ($self, $text, $info) = @_; | ||
337 | 384174 | 109ms | my ($tokens, $block); | ||
338 | |||||
339 | $info->{ DEBUG } = $self->{ DEBUG_DIRS } | ||||
340 | 384174 | 675ms | 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 | 384174 | 679ms | my $defblock = $self->{ DEFBLOCK } = { }; | ||
346 | 384174 | 557ms | my $metadata = $self->{ METADATA } = [ ]; | ||
347 | 384174 | 527ms | my $variables = $self->{ VARIABLES } = { }; | ||
348 | 384174 | 321ms | $self->{ DEFBLOCKS } = [ ]; | ||
349 | |||||
350 | 384174 | 271ms | $self->{ _ERROR } = ''; | ||
351 | |||||
352 | # split file into TEXT/DIRECTIVE chunks | ||||
353 | 384174 | 961ms | 384174 | 58.0s | $tokens = $self->split_text($text) # spent 58.0s making 384174 calls to Template::Parser::split_text, avg 151µs/call |
354 | || return undef; ## RETURN ## | ||||
355 | |||||
356 | 384174 | 422ms | push(@{ $self->{ FILEINFO } }, $info); | ||
357 | |||||
358 | # parse chunks | ||||
359 | 384174 | 1.10s | 384174 | 174s | $block = $self->_parse($tokens, $info); # spent 174s making 384174 calls to Template::Parser::_parse, avg 454µs/call |
360 | |||||
361 | 384174 | 339ms | pop(@{ $self->{ FILEINFO } }); | ||
362 | |||||
363 | 384174 | 159ms | return undef unless $block; ## RETURN ## | ||
364 | |||||
365 | $self->debug("compiled main template document block:\n$block") | ||||
366 | 384174 | 342ms | if $self->{ DEBUG } & Template::Constants::DEBUG_PARSER; | ||
367 | |||||
368 | return { | ||||
369 | 384174 | 3.12s | 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 58.0s (28.3+29.7) within Template::Parser::split_text which was called 384174 times, avg 151µs/call:
# 384174 times (28.3s+29.7s) by Template::Parser::parse at line 353, avg 151µs/call | ||||
385 | 384174 | 383ms | my ($self, $text) = @_; | ||
386 | 384174 | 206ms | my ($pre, $dir, $prelines, $dirlines, $postlines, $chomp, $tags, @tags); | ||
387 | 384174 | 515ms | my $style = $self->{ STYLE }->[-1]; | ||
388 | my ($start, $end, $out, $prechomp, $postchomp, $interp ) = | ||||
389 | 384174 | 897ms | @$style{ qw( START_TAG END_TAG OUTLINE_TAG PRE_CHOMP POST_CHOMP INTERPOLATE ) }; | ||
390 | 384174 | 2.17s | 384174 | 549ms | my $tags_dir = $self->{ANYCASE} ? qr<TAGS>i : qr<TAGS>; # spent 549ms making 384174 calls to Template::Parser::CORE:qr, avg 1µs/call |
391 | 384174 | 267ms | my $split = $style->{ TEXT_SPLIT }; | ||
392 | 384174 | 328ms | my $has_out = defined $out; | ||
393 | |||||
394 | 384174 | 261ms | my @tokens = (); | ||
395 | 384174 | 167ms | my $line = 1; | ||
396 | |||||
397 | return \@tokens ## RETURN ## | ||||
398 | 384174 | 334ms | unless defined $text && length $text; | ||
399 | |||||
400 | # extract all directives from the text | ||||
401 | 384174 | 5.58s | 768348 | 1.93s | while ($text =~ s/$split//) { # spent 1.27s making 384174 calls to Template::Parser::CORE:subst, avg 3µs/call
# spent 666ms making 384174 calls to Template::Parser::CORE:regcomp, avg 2µs/call |
402 | 314713 | 386ms | $pre = $1; | ||
403 | 314713 | 406ms | $dir = defined($2) ? $2 : $3; | ||
404 | 314713 | 109ms | $pre = '' unless defined $pre; | ||
405 | 314713 | 119ms | $dir = '' unless defined $dir; | ||
406 | |||||
407 | 314713 | 269ms | $prelines = ($pre =~ tr/\n//); # newlines in preceding text | ||
408 | 314713 | 110ms | $dirlines = ($dir =~ tr/\n//); # newlines in directive tag | ||
409 | 314713 | 105ms | $postlines = 0; # newlines chomped after tag | ||
410 | |||||
411 | 314713 | 298ms | for ($dir) { | ||
412 | 314713 | 1.56s | 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.45s | 629426 | 751ms | if(s/^($CHOMP_FLAGS)?(\s*)//so && $2) { # spent 664ms making 314713 calls to Template::Parser::CORE:subst, avg 2µs/call
# spent 87.1ms making 314713 calls to Template::Parser::CORE:regcomp, avg 277ns/call |
419 | 314713 | 173ms | my $chomped = $2; | ||
420 | 314713 | 152ms | my $linecount = ($chomped =~ tr/\n//); # newlines in chomped whitespace | ||
421 | 314713 | 135ms | $linecount ||= 0; | ||
422 | 314713 | 100ms | $prelines += $linecount; | ||
423 | 314713 | 120ms | $dirlines -= $linecount; | ||
424 | } | ||||
425 | # PRE_CHOMP: process whitespace before tag | ||||
426 | 314713 | 158ms | $chomp = $1 ? $1 : $prechomp; | ||
427 | 314713 | 125ms | $chomp =~ tr/-=~+/1230/; | ||
428 | 314713 | 118ms | if ($chomp && $pre) { | ||
429 | # chomp off whitespace and newline preceding directive | ||||
430 | 1991 | 943µs | if ($chomp == CHOMP_ALL) { | ||
431 | 1991 | 11.1ms | 1991 | 6.35ms | $pre =~ s{ (\r?\n|^) [^\S\n]* \z }{}mx; # spent 6.35ms 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.43s | 629426 | 3.02s | s/\s*($CHOMP_FLAGS)?\s*$//so; # spent 2.97s making 314713 calls to Template::Parser::CORE:subst, avg 9µs/call
# spent 42.0ms making 314713 calls to Template::Parser::CORE:regcomp, avg 133ns/call |
444 | 314713 | 185ms | $chomp = $1 ? $1 : $postchomp; | ||
445 | 314713 | 121ms | $chomp =~ tr/-=~+/1230/; | ||
446 | 314713 | 172ms | if ($chomp) { | ||
447 | 47165 | 41.3ms | if ($chomp == CHOMP_ALL) { | ||
448 | 47165 | 294ms | 47165 | 124ms | $text =~ s{ ^ ([^\S\n]* \n) }{}x # spent 124ms 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 | 383ms | if (length $pre) { | ||
465 | push(@tokens, $interp | ||||
466 | ? [ $pre, $line, 'ITEXT' ] | ||||
467 | : ('TEXT', $pre) ); | ||||
468 | } | ||||
469 | 314713 | 69.5ms | $line += $prelines; | ||
470 | |||||
471 | # and now the directive, along with line number information | ||||
472 | 314713 | 165ms | if (length $dir) { | ||
473 | # the TAGS directive is a compile-time switch | ||||
474 | 314713 | 2.73s | 629426 | 449ms | if ($dir =~ /^$tags_dir\s+(.*)/) { # spent 355ms making 314713 calls to Template::Parser::CORE:regcomp, avg 1µs/call
# spent 94.1ms making 314713 calls to Template::Parser::CORE:match, avg 299ns/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.36s | 314713 | 21.9s | push(@tokens, # spent 21.9s making 314713 calls to Template::Parser::tokenise_directive, avg 70µ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.30s | 629426 | 809ms | $line += $dirlines + $postlines; # spent 536ms making 314713 calls to Template::Parser::CORE:subst, avg 2µs/call
# spent 273ms making 314713 calls to Template::Parser::CORE:regcomp, avg 868ns/call |
503 | } | ||||
504 | |||||
505 | # anything remaining in the string is plain text | ||||
506 | 384174 | 507ms | push(@tokens, $interp | ||
507 | ? [ $text, $line, 'ITEXT' ] | ||||
508 | : ( 'TEXT', $text) ) | ||||
509 | if length $text; | ||||
510 | |||||
511 | 384174 | 2.44s | 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 56.3ms (48.4+7.91) within Template::Parser::interpolate_text which was called 1991 times, avg 28µs/call:
# 1991 times (48.4ms+7.91ms) by Template::Parser::tokenise_directive at line 656, avg 28µs/call | ||||
524 | 1991 | 2.01ms | my ($self, $text, $line) = @_; | ||
525 | 1991 | 2.56ms | my @tokens = (); | ||
526 | 1991 | 774µs | my ($pre, $var, $dir); | ||
527 | |||||
528 | |||||
529 | 1991 | 20.7ms | 1991 | 7.05ms | while ($text =~ # spent 7.05ms making 1991 calls to Template::Parser::CORE:match, avg 4µ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.82ms | ($pre, $var, $dir) = ($1, $3 || $4, $2); | ||
542 | |||||
543 | # preceding text | ||||
544 | 1991 | 2.42ms | if (defined($pre) && length($pre)) { | ||
545 | 1991 | 1.69ms | $line += $pre =~ tr/\n//; | ||
546 | 1991 | 4.98ms | 1991 | 554µs | $pre =~ s/\\\$/\$/g; # spent 554µs making 1991 calls to Template::Parser::CORE:subst, avg 278ns/call |
547 | 1991 | 2.46ms | push(@tokens, 'TEXT', $pre); | ||
548 | } | ||||
549 | # $variable reference | ||||
550 | 1991 | 6.48ms | 1991 | 310µs | if ($var) { # spent 310µs making 1991 calls to Template::Parser::CORE:match, avg 156ns/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 | 23.9ms | 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.9s (16.6+5.29) within Template::Parser::tokenise_directive which was called 314713 times, avg 70µs/call:
# 314713 times (16.6s+5.29s) by Template::Parser::split_text at line 491, avg 70µs/call | ||||
590 | 314713 | 192ms | my ($self, $text, $line) = @_; | ||
591 | 314713 | 89.7ms | my ($token, $uctoken, $type, $lookup); | ||
592 | 314713 | 224ms | my $lextable = $self->{ LEXTABLE }; | ||
593 | 314713 | 234ms | my $style = $self->{ STYLE }->[-1]; | ||
594 | 314713 | 354ms | my ($anycase, $start, $end) = @$style{ qw( ANYCASE START_TAG END_TAG ) }; | ||
595 | 314713 | 181ms | my @tokens = ( ); | ||
596 | |||||
597 | 314713 | 3.14s | 316704 | 1.77s | while ($text =~ # spent 1.77s making 316704 calls to Template::Parser::CORE:match, avg 6µ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 | 366ms | next if $1; | ||
640 | |||||
641 | # quoted string | ||||
642 | 1536347 | 2.24s | if (defined ($token = $3)) { | ||
643 | # double-quoted string may include $variable references | ||||
644 | 243677 | 173ms | if ($2 eq '"') { | ||
645 | 158959 | 741ms | 158959 | 109ms | if ($token =~ /[\$\\]/) { # spent 109ms making 158959 calls to Template::Parser::CORE:match, avg 687ns/call |
646 | 1991 | 1.03ms | $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.41ms | for ($token) { | ||
652 | 1991 | 13.7ms | 1991 | 4.44ms | s/\\([^\$nrt])/$1/g; # spent 4.44ms making 1991 calls to Template::Parser::CORE:subst, avg 2µs/call |
653 | 1991 | 38.0ms | 5973 | 10.3ms | s/\\([nrt])/$QUOTED_ESCAPES->{ $1 }/ge; # spent 5.25ms making 1991 calls to Template::Parser::CORE:subst, avg 3µs/call
# spent 5.03ms making 3982 calls to Template::Parser::CORE:substcont, avg 1µs/call |
654 | } | ||||
655 | push(@tokens, ('"') x 2, | ||||
656 | 1991 | 14.1ms | 1991 | 56.3ms | @{ $self->interpolate_text($token) }, # spent 56.3ms making 1991 calls to Template::Parser::interpolate_text, avg 28µs/call |
657 | ('"') x 2); | ||||
658 | 1991 | 1.68ms | next; | ||
659 | } | ||||
660 | else { | ||||
661 | 156968 | 61.4ms | $type = 'LITERAL'; | ||
662 | 156968 | 608ms | 156968 | 101ms | $token =~ s['][\\']g; # spent 101ms making 156968 calls to Template::Parser::CORE:subst, avg 644ns/call |
663 | 156968 | 90.3ms | $token = "'$token'"; | ||
664 | } | ||||
665 | } | ||||
666 | else { | ||||
667 | 84718 | 18.8ms | $type = 'LITERAL'; | ||
668 | 84718 | 27.5ms | $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 | 246ms | 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 | 148ms | $uctoken = $token; | ||
698 | } | ||||
699 | 571294 | 573ms | if (defined ($type = $lextable->{ $uctoken })) { | ||
700 | $token = $uctoken; | ||||
701 | } | ||||
702 | else { | ||||
703 | 431260 | 147ms | $type = 'IDENT'; | ||
704 | } | ||||
705 | } | ||||
706 | elsif (defined ($token = $7)) { | ||||
707 | # reserved words may be in lower case unless case sensitive | ||||
708 | 707297 | 138ms | $uctoken = $anycase ? uc $token : $token; | ||
709 | 707297 | 475ms | unless (defined ($type = $lextable->{ $uctoken })) { | ||
710 | $type = 'UNQUOTED'; | ||||
711 | } | ||||
712 | } | ||||
713 | |||||
714 | 1534356 | 10.4s | 1534356 | 3.24s | push(@tokens, $type, $token); # spent 3.24s 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.79s | 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.24s (2.91+334ms) within Template::Parser::location which was called 313428 times, avg 10µs/call:
# 313428 times (2.91s+334ms) by Template::Grammar::__ANON__[Parser.yp:79] at line 78 of /root/tor-browser-build/Parser.yp, avg 10µs/call | ||||
791 | 313428 | 129ms | my $self = shift; | ||
792 | 313428 | 158ms | return "\n" unless $self->{ FILE_INFO }; | ||
793 | 313428 | 224ms | my $line = ${ $self->{ LINE } }; | ||
794 | 313428 | 173ms | my $info = $self->{ FILEINFO }->[-1]; | ||
795 | my $file = $info->{ path } || $info->{ name } | ||||
796 | 313428 | 223ms | || '(unknown template)'; | ||
797 | 313428 | 1.57s | 313428 | 334ms | $line =~ s/\-.*$//; # might be 'n-n' # spent 334ms making 313428 calls to Template::Parser::CORE:subst, avg 1µs/call |
798 | 313428 | 88.2ms | $line ||= 1; | ||
799 | 313428 | 1.59s | 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 174s (122+52.7) within Template::Parser::_parse which was called 384174 times, avg 454µs/call:
# 384174 times (122s+52.7s) by Template::Parser::parse at line 359, avg 454µs/call | ||||
823 | 384174 | 190ms | my ($self, $tokens, $info) = @_; | ||
824 | 384174 | 164ms | my ($token, $value, $text, $line, $inperl); | ||
825 | my ($state, $stateno, $status, $action, $lookup, $coderet, @codevars); | ||||
826 | my ($lhs, $len, $code); # rule contents | ||||
827 | 384174 | 571ms | my $stack = [ [ 0, undef ] ]; # DFA stack | ||
828 | |||||
829 | # DEBUG | ||||
830 | # local $" = ', '; | ||||
831 | |||||
832 | # retrieve internal rule and state tables | ||||
833 | 384174 | 572ms | 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 | 384174 | 346ms | if $self->{ TRACE_VARS }; | ||
840 | |||||
841 | # call the grammar set_factory method to install emitter factory | ||||
842 | 384174 | 1.60s | 384174 | 747ms | $self->{ GRAMMAR }->install_factory($self->{ FACTORY }); # spent 747ms making 384174 calls to Template::Grammar::install_factory, avg 2µs/call |
843 | |||||
844 | 384174 | 197ms | $line = $inperl = 0; | ||
845 | 384174 | 661ms | $self->{ LINE } = \$line; | ||
846 | 384174 | 598ms | $self->{ FILE } = $info->{ name }; | ||
847 | 384174 | 457ms | $self->{ INPERL } = \$inperl; | ||
848 | |||||
849 | 384174 | 180ms | $status = CONTINUE; | ||
850 | 384174 | 213ms | my $in_string = 0; | ||
851 | |||||
852 | 384174 | 9.33s | while(1) { | ||
853 | # get state number and state | ||||
854 | 9983073 | 2.18s | $stateno = $stack->[-1]->[0]; | ||
855 | 9983073 | 2.82s | $state = $states->[$stateno]; | ||
856 | |||||
857 | # see if any lookaheads exist for the current state | ||||
858 | 9983073 | 5.07s | 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 | 4639558 | 1.96s | while (! defined $token && @$tokens) { | ||
863 | 2673171 | 1.05s | $token = shift(@$tokens); | ||
864 | 2673171 | 1.77s | if (ref $token) { | ||
865 | 314713 | 382ms | ($text, $line, $token) = @$token; | ||
866 | 314713 | 127ms | if (ref $token) { | ||
867 | 314713 | 272ms | 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.20s | unshift(@$tokens, @$token, (';') x 2); | ||
894 | } | ||||
895 | 314713 | 90.9ms | $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 | 2358458 | 559ms | $in_string = ! $in_string if $token eq '"'; | ||
914 | 2358458 | 659ms | $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 | 4639558 | 784ms | $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 | 4639558 | 3.82s | : defined ($lookup = $state->{'DEFAULT'}) | ||
925 | ? $lookup | ||||
926 | : undef; | ||||
927 | } | ||||
928 | else { | ||||
929 | # no lookahead actions | ||||
930 | 5343515 | 1.39s | $action = $state->{'DEFAULT'}; | ||
931 | } | ||||
932 | |||||
933 | # ERROR: no ACTION | ||||
934 | 9983073 | 1.27s | last unless defined $action; | ||
935 | |||||
936 | # - - - - - - - - - - - - - - - - - - - - - - - - - - - - | ||||
937 | # shift (+ive ACTION) | ||||
938 | # - - - - - - - - - - - - - - - - - - - - - - - - - - - - | ||||
939 | 9983073 | 1.66s | if ($action > 0) { | ||
940 | 2742632 | 1.57s | push(@$stack, [ $action, $value ]); | ||
941 | 2742632 | 553ms | $token = $value = undef; | ||
942 | 2742632 | 490ms | redo; | ||
943 | }; | ||||
944 | |||||
945 | # - - - - - - - - - - - - - - - - - - - - - - - - - - - - | ||||
946 | # reduce (-ive ACTION) | ||||
947 | # - - - - - - - - - - - - - - - - - - - - - - - - - - - - | ||||
948 | 7240441 | 8.15s | ($lhs, $len, $code) = @{ $rules->[ -$action ] }; | ||
949 | |||||
950 | # no action imples ACCEPTance | ||||
951 | 7240441 | 841ms | $action | ||
952 | or $status = ACCEPT; | ||||
953 | |||||
954 | # use dummy sub if code ref doesn't exist | ||||
955 | 2498716 | 16.5s | # spent 1.81s within Template::Parser::__ANON__[/usr/lib/x86_64-linux-gnu/perl5/5.28/Template/Parser.pm:955] which was called 2498716 times, avg 725ns/call:
# 2498716 times (1.81s+0s) by Template::Parser::_parse at line 963, avg 725ns/call | ||
956 | 7240441 | 3.88s | unless $code; | ||
957 | |||||
958 | @codevars = $len | ||||
959 | 7240441 | 9.51s | ? map { $_->[1] } @$stack[ -$len .. -1 ] | ||
960 | : (); | ||||
961 | |||||
962 | 7240441 | 2.04s | eval { | ||
963 | 7240441 | 11.4s | 7240441 | 51.9s | $coderet = &$code( $self, @codevars ); # spent 16.7s making 503416 calls to Template::Grammar::__ANON__[Parser.yp:76], avg 33µs/call
# spent 7.12s making 384174 calls to Template::Grammar::__ANON__[Parser.yp:64], avg 19µs/call
# spent 5.69s making 321403 calls to Template::Grammar::__ANON__[Parser.yp:79], avg 18µs/call
# spent 4.95s making 439240 calls to Template::Grammar::__ANON__[Parser.yp:67], avg 11µs/call
# spent 4.50s making 372329 calls to Template::Grammar::__ANON__[Parser.yp:305], avg 12µs/call
# spent 2.62s making 250383 calls to Template::Grammar::__ANON__[Parser.yp:90], avg 10µs/call
# spent 2.45s making 242791 calls to Template::Grammar::__ANON__[Parser.yp:342], avg 10µs/call
# spent 1.81s making 2498716 calls to Template::Parser::__ANON__[Template/Parser.pm:955], avg 725ns/call
# spent 1.23s making 439240 calls to Template::Grammar::__ANON__[Parser.yp:73], avg 3µs/call
# spent 966ms making 385579 calls to Template::Grammar::__ANON__[Parser.yp:72], avg 3µs/call
# spent 676ms making 37103 calls to Template::Grammar::__ANON__[Parser.yp:141], avg 18µs/call
# spent 657ms making 424294 calls to Template::Grammar::__ANON__[Parser.yp:345], avg 2µs/call
# spent 514ms making 285731 calls to Template::Grammar::__ANON__[Parser.yp:382], avg 2µs/call
# spent 350ms making 5968 calls to Template::Grammar::__ANON__[Parser.yp:168], avg 59µs/call
# spent 314ms making 159453 calls to Template::Grammar::__ANON__[Parser.yp:341], avg 2µs/call
# spent 314ms making 249772 calls to Template::Grammar::__ANON__[Parser.yp:387], avg 1µs/call
# spent 120ms making 3982 calls to Template::Grammar::__ANON__[Parser.yp:95], avg 30µs/call
# spent 101ms making 5968 calls to Template::Grammar::__ANON__[Parser.yp:167], avg 17µs/call
# spent 96.6ms making 4031 calls to Template::Grammar::__ANON__[Parser.yp:115], avg 24µs/call
# spent 80.8ms making 6966 calls to Template::Grammar::__ANON__[Parser.yp:113], avg 12µs/call
# spent 58.5ms making 21902 calls to Template::Grammar::__ANON__[Parser.yp:334], avg 3µs/call
# spent 54.3ms making 42940 calls to Template::Grammar::__ANON__[Parser.yp:386], avg 1µs/call
# spent 49.0ms making 1991 calls to Template::Grammar::__ANON__[Parser.yp:440], avg 25µs/call
# spent 48.8ms making 22050 calls to Template::Grammar::__ANON__[Parser.yp:331], avg 2µs/call
# spent 47.7ms making 28096 calls to Template::Grammar::__ANON__[Parser.yp:152], avg 2µs/call
# spent 47.6ms making 22921 calls to Template::Grammar::__ANON__[Parser.yp:358], avg 2µs/call
# spent 46.5ms making 1013 calls to Template::Grammar::__ANON__[Parser.yp:118], avg 46µs/call
# spent 39.6ms making 18052 calls to Template::Grammar::__ANON__[Parser.yp:302], avg 2µs/call
# spent 35.3ms making 3982 calls to Template::Grammar::__ANON__[Parser.yp:114], avg 9µs/call
# spent 30.6ms making 1991 calls to Template::Grammar::__ANON__[Parser.yp:307], avg 15µs/call
# spent 21.6ms making 9007 calls to Template::Grammar::__ANON__[Parser.yp:151], avg 2µs/call
# spent 18.6ms making 5988 calls to Template::Grammar::__ANON__[Parser.yp:325], avg 3µs/call
# spent 16.7ms making 6015 calls to Template::Grammar::__ANON__[Parser.yp:361], avg 3µs/call
# spent 13.7ms making 8013 calls to Template::Grammar::__ANON__[Parser.yp:374], avg 2µs/call
# spent 11.1ms making 2984 calls to Template::Grammar::__ANON__[Parser.yp:176], avg 4µs/call
# spent 10.8ms making 2984 calls to Template::Grammar::__ANON__[Parser.yp:175], avg 4µs/call
# spent 8.16ms making 2988 calls to Template::Grammar::__ANON__[Parser.yp:150], avg 3µs/call
# spent 7.46ms making 1991 calls to Template::Grammar::__ANON__[Parser.yp:435], avg 4µs/call
# spent 6.38ms making 2016 calls to Template::Grammar::__ANON__[Parser.yp:359], avg 3µs/call
# spent 5.36ms making 1990 calls to Template::Grammar::__ANON__[Parser.yp:360], avg 3µs/call
# spent 4.99ms making 1991 calls to Template::Grammar::__ANON__[Parser.yp:299], avg 3µs/call
# spent 4.55ms making 1991 calls to Template::Grammar::__ANON__[Parser.yp:301], avg 2µs/call
# spent 4.12ms making 1991 calls to Template::Grammar::__ANON__[Parser.yp:436], avg 2µs/call
# spent 3.90ms making 1990 calls to Template::Grammar::__ANON__[Parser.yp:322], avg 2µs/call
# spent 3.49ms making 1013 calls to Template::Grammar::__ANON__[Parser.yp:407], avg 3µs/call
# spent 3.19ms making 998 calls to Template::Grammar::__ANON__[Parser.yp:416], avg 3µs/call
# spent 2.62ms making 1013 calls to Template::Grammar::__ANON__[Parser.yp:412], avg 3µs/call
# spent 3µs making 1 call to Template::Grammar::__ANON__[Parser.yp:362] |
964 | }; | ||||
965 | 7240441 | 756ms | if ($@) { | ||
966 | my $err = $@; | ||||
967 | chomp $err; | ||||
968 | return $self->_parse_error($err); | ||||
969 | } | ||||
970 | |||||
971 | # reduce stack by $len | ||||
972 | 7240441 | 3.82s | splice(@$stack, -$len, $len); | ||
973 | |||||
974 | # ACCEPT | ||||
975 | 7240441 | 3.99s | return $coderet ## RETURN ## | ||
976 | if $status == ACCEPT; | ||||
977 | |||||
978 | # ABORT | ||||
979 | return undef ## RETURN ## | ||||
980 | 6856267 | 996ms | if $status == ABORT; | ||
981 | |||||
982 | # ERROR | ||||
983 | last | ||||
984 | 6856267 | 1.09s | 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.39s within Template::Parser::CORE:match which was called 2643427 times, avg 2µs/call:
# 1534356 times (3.24s+0s) by Template::Parser::tokenise_directive at line 714, avg 2µs/call
# 316704 times (1.77s+0s) by Template::Parser::tokenise_directive at line 597, avg 6µs/call
# 314713 times (175ms+0s) by Template::Parser::split_text at line 412, avg 557ns/call
# 314713 times (94.1ms+0s) by Template::Parser::split_text at line 474, avg 299ns/call
# 158959 times (109ms+0s) by Template::Parser::tokenise_directive at line 645, avg 687ns/call
# 1991 times (7.05ms+0s) by Template::Parser::interpolate_text at line 529, avg 4µs/call
# 1991 times (310µs+0s) by Template::Parser::interpolate_text at line 550, avg 156ns/call | |||||
# spent 1.32s within Template::Parser::CORE:qr which was called 767337 times, avg 2µs/call:
# 384174 times (549ms+0s) by Template::Parser::split_text at line 390, avg 1µs/call
# 383161 times (769ms+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 (700ns+0s) by Template::Config::load at line 115 | |||||
# spent 2.48s within Template::Parser::CORE:regcomp which was called 2026187 times, avg 1µs/call:
# 384174 times (666ms+0s) by Template::Parser::split_text at line 401, avg 2µs/call
# 383161 times (1.05s+0s) by Template::Parser::text_splitter at line 299, avg 3µs/call
# 314713 times (355ms+0s) by Template::Parser::split_text at line 474, avg 1µs/call
# 314713 times (273ms+0s) by Template::Parser::split_text at line 502, avg 868ns/call
# 314713 times (87.1ms+0s) by Template::Parser::split_text at line 418, avg 277ns/call
# 314713 times (42.0ms+0s) by Template::Parser::split_text at line 443, avg 133ns/call | |||||
# spent 6.02s within Template::Parser::CORE:subst which was called 1853838 times, avg 3µs/call:
# 384174 times (1.27s+0s) by Template::Parser::split_text at line 401, avg 3µs/call
# 314713 times (2.97s+0s) by Template::Parser::split_text at line 443, avg 9µs/call
# 314713 times (664ms+0s) by Template::Parser::split_text at line 418, avg 2µs/call
# 314713 times (536ms+0s) by Template::Parser::split_text at line 502, avg 2µs/call
# 313428 times (334ms+0s) by Template::Parser::location at line 797, avg 1µs/call
# 156968 times (101ms+0s) by Template::Parser::tokenise_directive at line 662, avg 644ns/call
# 47165 times (124ms+0s) by Template::Parser::split_text at line 448, avg 3µs/call
# 1991 times (6.35ms+0s) by Template::Parser::split_text at line 431, avg 3µs/call
# 1991 times (5.25ms+0s) by Template::Parser::tokenise_directive at line 653, avg 3µs/call
# 1991 times (4.44ms+0s) by Template::Parser::tokenise_directive at line 652, avg 2µs/call
# 1991 times (554µs+0s) by Template::Parser::interpolate_text at line 546, avg 278ns/call | |||||
# spent 5.03ms within Template::Parser::CORE:substcont which was called 3982 times, avg 1µs/call:
# 3982 times (5.03ms+0s) by Template::Parser::tokenise_directive at line 653, avg 1µs/call | |||||
sub Template::Parser::__ANON__; # xsub |