← Index
NYTProf Performance Profile   « block view • line view • sub view »
For /usr/share/koha/opac/cgi-bin/opac/opac-search.pl
  Run on Tue Oct 15 17:10:45 2013
Reported on Tue Oct 15 17:12:56 2013

Filename/usr/lib/perl5/Template/Parser.pm
StatementsExecuted 328231 statements in 582ms
Subroutines
Calls P F Exclusive
Time
Inclusive
Time
Subroutine
811410ms549msTemplate::Parser::::_parseTemplate::Parser::_parse
81158.1ms151msTemplate::Parser::::split_textTemplate::Parser::split_text
10351152.9ms68.7msTemplate::Parser::::tokenise_directiveTemplate::Parser::tokenise_directive
11121.9ms22.0msTemplate::Parser::::BEGIN@41Template::Parser::BEGIN@41
37599119.7ms19.7msTemplate::Parser::::CORE:substTemplate::Parser::CORE:subst (opcode)
59167117.4ms17.4msTemplate::Parser::::CORE:matchTemplate::Parser::CORE:match (opcode)
6261110.3ms11.8msTemplate::Parser::::locationTemplate::Parser::location
3116119.01ms9.01msTemplate::Parser::::__ANON__[:864]Template::Parser::__ANON__[:864]
4148514.73ms4.73msTemplate::Parser::::CORE:regcompTemplate::Parser::CORE:regcomp (opcode)
1114.71ms5.00msTemplate::Parser::::BEGIN@40Template::Parser::BEGIN@40
2711547µs923µsTemplate::Parser::::leave_blockTemplate::Parser::leave_block
811537µs701msTemplate::Parser::::parseTemplate::Parser::parse
2711376µs376µsTemplate::Parser::::block_labelTemplate::Parser::block_label
2711335µs335µsTemplate::Parser::::enter_blockTemplate::Parser::enter_block
111173µs254µsTemplate::Parser::::newTemplate::Parser::new
92165µs65µsTemplate::Parser::::CORE:qrTemplate::Parser::CORE:qr (opcode)
11142µs47µsTemplate::Parser::::interpolate_textTemplate::Parser::interpolate_text
11136µs36µsTemplate::Parser::::new_styleTemplate::Parser::new_style
11127µs34µsTemplate::Parser::::BEGIN@35Template::Parser::BEGIN@35
11121µs104µsTemplate::Parser::::BEGIN@44Template::Parser::BEGIN@44
11118µs181µsTemplate::Parser::::BEGIN@37Template::Parser::BEGIN@37
11118µs48µsTemplate::Parser::::BEGIN@36Template::Parser::BEGIN@36
11114µs440µsTemplate::Parser::::BEGIN@39Template::Parser::BEGIN@39
11114µs55µsTemplate::Parser::::BEGIN@46Template::Parser::BEGIN@46
11113µs58µsTemplate::Parser::::BEGIN@45Template::Parser::BEGIN@45
11111µs48µsTemplate::Parser::::BEGIN@47Template::Parser::BEGIN@47
2114µs4µsTemplate::Parser::::CORE:substcontTemplate::Parser::CORE:substcont (opcode)
0000s0sTemplate::Parser::::_dumpTemplate::Parser::_dump
0000s0sTemplate::Parser::::_parse_errorTemplate::Parser::_parse_error
0000s0sTemplate::Parser::::add_metadataTemplate::Parser::add_metadata
0000s0sTemplate::Parser::::define_blockTemplate::Parser::define_block
0000s0sTemplate::Parser::::in_blockTemplate::Parser::in_block
0000s0sTemplate::Parser::::old_styleTemplate::Parser::old_style
0000s0sTemplate::Parser::::pop_defblockTemplate::Parser::pop_defblock
0000s0sTemplate::Parser::::push_defblockTemplate::Parser::push_defblock
Call graph for these subroutines as a Graphviz dot language file.
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 assocated 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
33package Template::Parser;
34
35338µs240µs
# spent 34µs (27+7) within Template::Parser::BEGIN@35 which was called: # once (27µs+7µs) by Template::Config::load at line 35
use strict;
# spent 34µs making 1 call to Template::Parser::BEGIN@35 # spent 7µs making 1 call to strict::import
36339µs278µs
# spent 48µs (18+30) within Template::Parser::BEGIN@36 which was called: # once (18µs+30µs) by Template::Config::load at line 36
use warnings;
# spent 48µs making 1 call to Template::Parser::BEGIN@36 # spent 30µs making 1 call to warnings::import
37347µs2344µs
# spent 181µs (18+163) within Template::Parser::BEGIN@37 which was called: # once (18µs+163µs) by Template::Config::load at line 37
use base 'Template::Base';
# spent 181µs making 1 call to Template::Parser::BEGIN@37 # spent 163µs making 1 call to base::import
38
39348µs2865µs
# spent 440µs (14+425) within Template::Parser::BEGIN@39 which was called: # once (14µs+425µs) by Template::Config::load at line 39
use Template::Constants qw( :status :chomp );
# spent 440µs making 1 call to Template::Parser::BEGIN@39 # spent 425µs making 1 call to Exporter::import
403310µs25.01ms
# spent 5.00ms (4.71+297µs) within Template::Parser::BEGIN@40 which was called: # once (4.71ms+297µs) by Template::Config::load at line 40
use Template::Directive;
# spent 5.00ms making 1 call to Template::Parser::BEGIN@40 # spent 3µs making 1 call to UNIVERSAL::import
413305µs222.0ms
# spent 22.0ms (21.9+64µs) within Template::Parser::BEGIN@41 which was called: # once (21.9ms+64µs) by Template::Config::load at line 41
use Template::Grammar;
# spent 22.0ms making 1 call to Template::Parser::BEGIN@41 # spent 7µs making 1 call to UNIVERSAL::import
42
43# parser state constants
44386µs2187µs
# spent 104µs (21+83) within Template::Parser::BEGIN@44 which was called: # once (21µs+83µs) by Template::Config::load at line 44
use constant CONTINUE => 0;
# spent 104µs making 1 call to Template::Parser::BEGIN@44 # spent 83µs making 1 call to constant::import
453419µs2104µs
# spent 58µs (13+45) within Template::Parser::BEGIN@45 which was called: # once (13µs+45µs) by Template::Config::load at line 45
use constant ACCEPT => 1;
# spent 58µs making 1 call to Template::Parser::BEGIN@45 # spent 45µs making 1 call to constant::import
46345µs296µs
# spent 55µs (14+41) within Template::Parser::BEGIN@46 which was called: # once (14µs+41µs) by Template::Config::load at line 46
use constant ERROR => 2;
# spent 55µs making 1 call to Template::Parser::BEGIN@46 # spent 41µs making 1 call to constant::import
4734.39ms285µs
# spent 48µs (11+37) within Template::Parser::BEGIN@47 which was called: # once (11µs+37µs) by Template::Config::load at line 47
use constant ABORT => 3;
# spent 48µs making 1 call to Template::Parser::BEGIN@47 # spent 37µs making 1 call to constant::import
48
491700nsour $VERSION = 2.89;
501700nsour $DEBUG = 0 unless defined $DEBUG;
511800nsour $ERROR = '';
52
53
54#========================================================================
55# -- COMMON TAG STYLES --
56#========================================================================
57
58118µsour $TAG_STYLE = {
59 'default' => [ '\[%', '%\]' ],
60 'template1' => [ '[\[%]%', '%[\]%]' ],
61 'metatext' => [ '%%', '%%' ],
62 'html' => [ '<!--', '-->' ],
63 'mason' => [ '<%', '>' ],
64 'asp' => [ '<%', '%>' ],
65 'php' => [ '<\?', '\?>' ],
66 'star' => [ '\[\*', '\*\]' ],
67};
6814µs$TAG_STYLE->{ template } = $TAG_STYLE->{ tt2 } = $TAG_STYLE->{ default };
69
70
71our $DEFAULT_STYLE = {
72 START_TAG => $TAG_STYLE->{ default }->[0],
7318µs END_TAG => $TAG_STYLE->{ default }->[1],
74# TAG_STYLE => 'default',
75 ANYCASE => 0,
76 INTERPOLATE => 0,
77 PRE_CHOMP => 0,
78 POST_CHOMP => 0,
79 V1DOLLAR => 0,
80 EVAL_PERL => 0,
81};
82
8314µsour $QUOTED_ESCAPES = {
84 n => "\n",
85 r => "\r",
86 t => "\t",
87};
88
89# note that '-' must come first so Perl doesn't think it denotes a range
90123µs16µsour $CHOMP_FLAGS = qr/[-=~+]/;
# spent 6µs making 1 call to Template::Parser::CORE:qr
91
- -
94#========================================================================
95# ----- PUBLIC METHODS -----
96#========================================================================
97
98#------------------------------------------------------------------------
99# new(\%config)
100#
101# Constructor method.
102#------------------------------------------------------------------------
103
104
# spent 254µs (173+81) within Template::Parser::new which was called: # once (173µs+81µs) by Template::Config::parser at line 103 of Template/Config.pm
sub new {
10513µs my $class = shift;
10614µs my $config = $_[0] && ref($_[0]) eq 'HASH' ? shift(@_) : { @_ };
10713µs my ($tagstyle, $debug, $start, $end, $defaults, $grammar, $hash, $key, $udef);
108
109 my $self = bless {
110 START_TAG => undef,
111 END_TAG => undef,
112 TAG_STYLE => 'default',
113 ANYCASE => 0,
114 INTERPOLATE => 0,
115 PRE_CHOMP => 0,
116 POST_CHOMP => 0,
117 V1DOLLAR => 0,
118 EVAL_PERL => 0,
119 FILE_INFO => 1,
120 GRAMMAR => undef,
121 _ERROR => '',
122 IN_BLOCK => [ ],
123143µs FACTORY => $config->{ FACTORY } || 'Template::Directive',
124 }, $class;
125
126 # update self with any relevant keys in config
12718µs foreach $key (keys %$self) {
1281418µs $self->{ $key } = $config->{ $key } if defined $config->{ $key };
129 }
13013µs $self->{ FILEINFO } = [ ];
131
132 # DEBUG config item can be a bitmask
13314µs if (defined ($debug = $config->{ DEBUG })) {
134 $self->{ DEBUG } = $debug & ( Template::Constants::DEBUG_PARSER
135 | Template::Constants::DEBUG_FLAGS );
136 $self->{ DEBUG_DIRS } = $debug & Template::Constants::DEBUG_DIRS;
137 }
138 # package variable can be set to 1 to support previous behaviour
139 elsif ($DEBUG == 1) {
140 $self->{ DEBUG } = Template::Constants::DEBUG_PARSER;
141 $self->{ DEBUG_DIRS } = 0;
142 }
143 # otherwise let $DEBUG be a bitmask
144 else {
14514µs $self->{ DEBUG } = $DEBUG & ( Template::Constants::DEBUG_PARSER
146 | Template::Constants::DEBUG_FLAGS );
14713µs $self->{ DEBUG_DIRS } = $DEBUG & Template::Constants::DEBUG_DIRS;
148 }
149
15013µs $grammar = $self->{ GRAMMAR } ||= do {
15112µs require Template::Grammar;
152111µs145µs Template::Grammar->new();
# spent 45µs making 1 call to Template::Grammar::new
153 };
154
155 # build a FACTORY object to include any NAMESPACE definitions,
156 # but only if FACTORY isn't already an object
15712µs if ($config->{ NAMESPACE } && ! ref $self->{ FACTORY }) {
158 my $fclass = $self->{ FACTORY };
159 $self->{ FACTORY } = $fclass->new( NAMESPACE => $config->{ NAMESPACE } )
160 || return $class->error($fclass->error());
161 }
162
163 # load grammar rules, states and lex table
16416µs @$self{ qw( LEXTABLE STATES RULES ) }
165 = @$grammar{ qw( LEXTABLE STATES RULES ) };
166
16716µs136µs $self->new_style($config)
# spent 36µs making 1 call to Template::Parser::new_style
168 || return $class->error($self->error());
169
17018µs return $self;
171}
172
173#-----------------------------------------------------------------------
174# These methods are used to track nested IF and WHILE blocks. Each
175# generated if/while block is given a label indicating the directive
176# type and nesting depth, e.g. FOR0, WHILE1, FOR2, WHILE3, etc. The
177# NEXT and LAST directives use the innermost label, e.g. last WHILE3;
178#-----------------------------------------------------------------------
179
180
# spent 335µs within Template::Parser::enter_block which was called 27 times, avg 12µs/call: # 27 times (335µs+0s) by Template::Grammar::__ANON__[Parser.yp:167] at line 167 of Parser.yp, avg 12µs/call
sub enter_block {
1812780µs my ($self, $name) = @_;
18227118µs my $blocks = $self->{ IN_BLOCK };
18327215µs push(@{ $self->{ IN_BLOCK } }, $name);
184}
185
186
# spent 923µs (547+376) within Template::Parser::leave_block which was called 27 times, avg 34µs/call: # 27 times (547µs+376µs) by Template::Grammar::__ANON__[Parser.yp:168] at line 168 of Parser.yp, avg 34µs/call
sub leave_block {
1872743µs my $self = shift;
18827149µs27376µs my $label = $self->block_label;
# spent 376µs making 27 calls to Template::Parser::block_label, avg 14µs/call
1892757µs pop(@{ $self->{ IN_BLOCK } });
19027133µs return $label;
191}
192
193sub in_block {
194 my ($self, $name) = @_;
195 my $blocks = $self->{ IN_BLOCK };
196 return @$blocks && $blocks->[-1] eq $name;
197}
198
199
# spent 376µs within Template::Parser::block_label which was called 27 times, avg 14µs/call: # 27 times (376µs+0s) by Template::Parser::leave_block at line 188, avg 14µs/call
sub block_label {
2002785µs my ($self, $prefix, $suffix) = @_;
2012754µs my $blocks = $self->{ IN_BLOCK };
2022776µs my $name = @$blocks
203 ? $blocks->[-1] . scalar @$blocks
204 : undef;
20527351µs return join('', grep { defined $_ } $prefix, $name, $suffix);
206}
207
- -
210#------------------------------------------------------------------------
211# new_style(\%config)
212#
213# Install a new (stacked) parser style. This feature is currently
214# experimental but should mimic the previous behaviour with regard to
215# TAG_STYLE, START_TAG, END_TAG, etc.
216#------------------------------------------------------------------------
217
218
# spent 36µs within Template::Parser::new_style which was called: # once (36µs+0s) by Template::Parser::new at line 167
sub new_style {
21912µs my ($self, $config) = @_;
22014µs my $styles = $self->{ STYLE } ||= [ ];
22111µs my ($tagstyle, $tags, $start, $end, $key);
222
223 # clone new style from previous or default style
22418µs my $style = { %{ $styles->[-1] || $DEFAULT_STYLE } };
225
226 # expand START_TAG and END_TAG from specified TAG_STYLE
22712µs if ($tagstyle = $config->{ TAG_STYLE }) {
228 return $self->error("Invalid tag style: $tagstyle")
229 unless defined ($tags = $TAG_STYLE->{ $tagstyle });
230 ($start, $end) = @$tags;
231 $config->{ START_TAG } ||= $start;
232 $config->{ END_TAG } ||= $end;
233 }
234
23514µs foreach $key (keys %$DEFAULT_STYLE) {
23689µs $style->{ $key } = $config->{ $key } if defined $config->{ $key };
237 }
23812µs push(@$styles, $style);
239142µs return $style;
240}
241
242
243#------------------------------------------------------------------------
244# old_style()
245#
246# Pop the current parser style and revert to the previous one. See
247# new_style(). ** experimental **
248#------------------------------------------------------------------------
249
250sub old_style {
251 my $self = shift;
252 my $styles = $self->{ STYLE };
253 return $self->error('only 1 parser style remaining')
254 unless (@$styles > 1);
255 pop @$styles;
256 return $styles->[-1];
257}
258
259
260#------------------------------------------------------------------------
261# parse($text, $data)
262#
263# Parses the text string, $text and returns a hash array representing
264# the compiled template block(s) as Perl code, in the format expected
265# by Template::Document.
266#------------------------------------------------------------------------
267
268
# spent 701ms (537µs+701) within Template::Parser::parse which was called 8 times, avg 87.7ms/call: # 8 times (537µs+701ms) by Template::Provider::_compile at line 844 of Template/Provider.pm, avg 87.7ms/call
sub parse {
269843µs my ($self, $text, $info) = @_;
27089µs my ($tokens, $block);
271
272 $info->{ DEBUG } = $self->{ DEBUG_DIRS }
273837µs unless defined $info->{ DEBUG };
274
275# print "info: { ", join(', ', map { "$_ => $info->{ $_ }" } keys %$info), " }\n";
276
277 # store for blocks defined in the template (see define_block())
278825µs my $defblock = $self->{ DEFBLOCK } = { };
279825µs my $metadata = $self->{ METADATA } = [ ];
280819µs $self->{ DEFBLOCKS } = [ ];
281
282816µs $self->{ _ERROR } = '';
283
284 # split file into TEXT/DIRECTIVE chunks
285849µs16151ms $tokens = $self->split_text($text)
# spent 151ms making 8 calls to Template::Parser::split_text, avg 18.9ms/call # spent 18µs making 8 calls to Regexp::DESTROY, avg 2µs/call
286 || return undef; ## RETURN ##
287
288861µs push(@{ $self->{ FILEINFO } }, $info);
289
290 # parse chunks
291856µs8549ms $block = $self->_parse($tokens, $info);
# spent 549ms making 8 calls to Template::Parser::_parse, avg 68.7ms/call
292
293818µs pop(@{ $self->{ FILEINFO } });
294
29584µs return undef unless $block; ## RETURN ##
296
297 $self->debug("compiled main template document block:\n$block")
298825µs if $self->{ DEBUG } & Template::Constants::DEBUG_PARSER;
299
300 return {
3018135µs BLOCK => $block,
302 DEFBLOCKS => $defblock,
303 METADATA => { @$metadata },
304 };
305}
306
- -
309#------------------------------------------------------------------------
310# split_text($text)
311#
312# Split input template text into directives and raw text chunks.
313#------------------------------------------------------------------------
314
315
# spent 151ms (58.1+93.3) within Template::Parser::split_text which was called 8 times, avg 18.9ms/call: # 8 times (58.1ms+93.3ms) by Template::Parser::parse at line 285, avg 18.9ms/call
sub split_text {
316854µs my ($self, $text) = @_;
317814µs my ($pre, $dir, $prelines, $dirlines, $postlines, $chomp, $tags, @tags);
318821µs my $style = $self->{ STYLE }->[-1];
319853µs my ($start, $end, $prechomp, $postchomp, $interp ) =
320 @$style{ qw( START_TAG END_TAG PRE_CHOMP POST_CHOMP INTERPOLATE ) };
3218124µs858µs my $tags_dir = $self->{ANYCASE} ? qr<TAGS>i : qr<TAGS>;
# spent 58µs making 8 calls to Template::Parser::CORE:qr, avg 7µs/call
322
323844µs my @tokens = ();
32487µs my $line = 1;
325
326 return \@tokens ## RETURN ##
327882µs unless defined $text && length $text;
328
329 # extract all directives from the text
3308238µs16140µs while ($text =~ s/
# spent 93µs making 8 calls to Template::Parser::CORE:subst, avg 12µs/call # spent 47µs making 8 calls to Template::Parser::CORE:regcomp, avg 6µs/call
331 ^(.*?) # $1 - start of line up to directive
332 (?:
333 $start # start of tag
334 (.*?) # $2 - tag contents
335 $end # end of tag
336 )
337 //sx) {
338
33910353.14ms ($pre, $dir) = ($1, $2);
3401035583µs $pre = '' unless defined $pre;
3411035401µs $dir = '' unless defined $dir;
342
34310351.28ms $prelines = ($pre =~ tr/\n//); # newlines in preceeding text
3441035730µs $dirlines = ($dir =~ tr/\n//); # newlines in directive tag
3451035351µs $postlines = 0; # newlines chomped after tag
346
34710352.12ms for ($dir) {
34810355.31ms1035957µs if (/^\#/) {
# spent 957µs making 1035 calls to Template::Parser::CORE:match, avg 925ns/call
349 # comment out entire directive except for any end chomp flag
350 $dir = ($dir =~ /($CHOMP_FLAGS)$/o) ? $1 : '';
351 }
352 else {
35310358.98ms20703.84ms s/^($CHOMP_FLAGS)?\s*//so;
# spent 3.30ms making 1035 calls to Template::Parser::CORE:subst, avg 3µs/call # spent 538µs making 1035 calls to Template::Parser::CORE:regcomp, avg 520ns/call
354 # PRE_CHOMP: process whitespace before tag
35510351.54ms $chomp = $1 ? $1 : $prechomp;
35610351.05ms $chomp =~ tr/-=~+/1230/;
3571035856µs if ($chomp && $pre) {
358 # chomp off whitespace and newline preceding directive
359 if ($chomp == CHOMP_ALL) {
360 $pre =~ s{ (\r?\n|^) [^\S\n]* \z }{}mx;
361 }
362 elsif ($chomp == CHOMP_COLLAPSE) {
363 $pre =~ s{ (\s+) \z }{ }x;
364 }
365 elsif ($chomp == CHOMP_GREEDY) {
366 $pre =~ s{ (\s+) \z }{}x;
367 }
368 }
369 }
370
371 # POST_CHOMP: process whitespace after tag
372103515.3ms20709.42ms s/\s*($CHOMP_FLAGS)?\s*$//so;
# spent 9.02ms making 1035 calls to Template::Parser::CORE:subst, avg 9µs/call # spent 405µs making 1035 calls to Template::Parser::CORE:regcomp, avg 391ns/call
37310351.44ms $chomp = $1 ? $1 : $postchomp;
3741035765µs $chomp =~ tr/-=~+/1230/;
37510352.03ms if ($chomp) {
376 if ($chomp == CHOMP_ALL) {
377 $text =~ s{ ^ ([^\S\n]* \n) }{}x
378 && $postlines++;
379 }
380 elsif ($chomp == CHOMP_COLLAPSE) {
381 $text =~ s{ ^ (\s+) }{ }x
382 && ($postlines += $1=~y/\n//);
383 }
384 # any trailing whitespace
385 elsif ($chomp == CHOMP_GREEDY) {
386 $text =~ s{ ^ (\s+) }{}x
387 && ($postlines += $1=~y/\n//);
388 }
389 }
390 }
391
392 # any text preceding the directive can now be added
39310352.46ms if (length $pre) {
394 push(@tokens, $interp
395 ? [ $pre, $line, 'ITEXT' ]
396 : ('TEXT', $pre) );
397 }
3981035645µs $line += $prelines;
399
400 # and now the directive, along with line number information
4011035958µs if (length $dir) {
402 # the TAGS directive is a compile-time switch
40310358.54ms20702.27ms if ($dir =~ /^$tags_dir\s+(.*)/) {
# spent 1.63ms making 1035 calls to Template::Parser::CORE:regcomp, avg 2µs/call # spent 634µs making 1035 calls to Template::Parser::CORE:match, avg 613ns/call
404 my @tags = split(/\s+/, $1);
405 if (scalar @tags > 1) {
406 ($start, $end) = map { quotemeta($_) } @tags;
407 }
408 elsif ($tags = $TAG_STYLE->{ $tags[0] }) {
409 ($start, $end) = @$tags;
410 }
411 else {
412 warn "invalid TAGS style: $tags[0]\n";
413 }
414 }
415 else {
416 # DIRECTIVE is pushed as:
417 # [ $dirtext, $line_no(s), \@tokens ]
41810356.35ms103568.7ms push(@tokens,
# spent 68.7ms making 1035 calls to Template::Parser::tokenise_directive, avg 66µs/call
419 [ $dir,
420 ($dirlines
421 ? sprintf("%d-%d", $line, $line + $dirlines)
422 : $line),
423 $self->tokenise_directive($dir) ]);
424 }
425 }
426
427 # update line counter to include directive lines and any extra
428 # newline chomped off the start of the following text
429103516.5ms20707.87ms $line += $dirlines + $postlines;
# spent 5.77ms making 1035 calls to Template::Parser::CORE:subst, avg 6µs/call # spent 2.11ms making 1035 calls to Template::Parser::CORE:regcomp, avg 2µs/call
430 }
431
432 # anything remaining in the string is plain text
433826µs push(@tokens, $interp
434 ? [ $text, $line, 'ITEXT' ]
435 : ( 'TEXT', $text) )
436 if length $text;
437
4388171µs return \@tokens; ## RETURN ##
439}
440
441
442
443#------------------------------------------------------------------------
444# interpolate_text($text, $line)
445#
446# Examines $text looking for any variable references embedded like
447# $this or like ${ this }.
448#------------------------------------------------------------------------
449
450
# spent 47µs (42+6) within Template::Parser::interpolate_text which was called: # once (42µs+6µs) by Template::Parser::tokenise_directive at line 583
sub interpolate_text {
45113µs my ($self, $text, $line) = @_;
45211µs my @tokens = ();
45311µs my ($pre, $var, $dir);
454
455
456111µs14µs while ($text =~
# spent 4µs making 1 call to Template::Parser::CORE:match
457 /
458 ( (?: \\. | [^\$] ){1,3000} ) # escaped or non-'$' character [$1]
459 |
460 ( \$ (?: # embedded variable [$2]
461 (?: \{ ([^\}]*) \} ) # ${ ... } [$3]
462 |
463 ([\w\.]+) # $word [$4]
464 )
465 )
466 /gx) {
467
46814µs ($pre, $var, $dir) = ($1, $3 || $4, $2);
469
470 # preceding text
47112µs if (defined($pre) && length($pre)) {
47212µs $line += $pre =~ tr/\n//;
47318µs1700ns $pre =~ s/\\\$/\$/g;
# spent 700ns making 1 call to Template::Parser::CORE:subst
47413µs push(@tokens, 'TEXT', $pre);
475 }
476 # $variable reference
47718µs1700ns if ($var) {
# spent 700ns making 1 call to Template::Parser::CORE:match
478 $line += $dir =~ tr/\n/ /;
479 push(@tokens, [ $dir, $line, $self->tokenise_directive($var) ]);
480 }
481 # other '$' reference - treated as text
482 elsif ($dir) {
483 $line += $dir =~ tr/\n//;
484 push(@tokens, 'TEXT', $dir);
485 }
486 }
487
48818µs return \@tokens;
489}
490
- -
493#------------------------------------------------------------------------
494# tokenise_directive($text)
495#
496# Called by the private _parse() method when it encounters a DIRECTIVE
497# token in the list provided by the split_text() or interpolate_text()
498# methods. The directive text is passed by parameter.
499#
500# The method splits the directive into individual tokens as recognised
501# by the parser grammar (see Template::Grammar for details). It
502# constructs a list of tokens each represented by 2 elements, as per
503# split_text() et al. The first element contains the token type, the
504# second the token itself.
505#
506# The method tokenises the string using a complex (but fast) regex.
507# For a deeper understanding of the regex magic at work here, see
508# Jeffrey Friedl's excellent book "Mastering Regular Expressions",
509# from O'Reilly, ISBN 1-56592-257-3
510#
511# Returns a reference to the list of chunks (each one being 2 elements)
512# identified in the directive text. On error, the internal _ERROR string
513# is set and undef is returned.
514#------------------------------------------------------------------------
515
516
# spent 68.7ms (52.9+15.9) within Template::Parser::tokenise_directive which was called 1035 times, avg 66µs/call: # 1035 times (52.9ms+15.9ms) by Template::Parser::split_text at line 418, avg 66µs/call
sub tokenise_directive {
51710351.36ms my ($self, $text, $line) = @_;
5181035459µs my ($token, $uctoken, $type, $lookup);
51910351.09ms my $lextable = $self->{ LEXTABLE };
5201035985µs my $style = $self->{ STYLE }->[-1];
52110352.31ms my ($anycase, $start, $end) = @$style{ qw( ANYCASE START_TAG END_TAG ) };
5221035867µs my @tokens = ( );
523
524103510.5ms10365.94ms while ($text =~
# spent 5.94ms making 1036 calls to Template::Parser::CORE:match, avg 6µs/call
525 /
526 # strip out any comments
527 (\#[^\n]*)
528 |
529 # a quoted phrase matches in $3
530 (["']) # $2 - opening quote, ' or "
531 ( # $3 - quoted text buffer
532 (?: # repeat group (no backreference)
533 \\\\ # an escaped backslash \\
534 | # ...or...
535 \\\2 # an escaped quote \" or \' (match $1)
536 | # ...or...
537 . # any other character
538 | \n
539 )*? # non-greedy repeat
540 ) # end of $3
541 \2 # match opening quote
542 |
543 # an unquoted number matches in $4
544 (-?\d+(?:\.\d+)?) # numbers
545 |
546 # filename matches in $5
547 ( \/?\w+(?:(?:\/|::?)\w*)+ | \/\w+)
548 |
549 # an identifier matches in $6
550 (\w+) # variable identifier
551 |
552 # an unquoted word or symbol matches in $7
553 ( [(){}\[\]:;,\/\\] # misc parenthesis and symbols
554# | \-> # arrow operator (for future?)
555 | [+\-*] # math operations
556 | \$\{? # dollar with option left brace
557 | => # like '='
558 | [=!<>]?= | [!<>] # eqality tests
559 | &&? | \|\|? # boolean ops
560 | \.\.? # n..n sequence
561 | \S+ # something unquoted
562 ) # end of $7
563 /gmxo) {
564
565 # ignore comments to EOL
56627913.52ms next if $1;
567
568 # quoted string
56927919.06ms if (defined ($token = $3)) {
570 # double-quoted string may include $variable references
5713755µs if ($2 eq '"') {
5721868µs1817µs if ($token =~ /[\$\\]/) {
# spent 17µs making 18 calls to Template::Parser::CORE:match, avg 933ns/call
57311µs $type = 'QUOTED';
574 # unescape " and \ but leave \$ escaped so that
575 # interpolate_text() doesn't incorrectly treat it
576 # as a variable reference
577# $token =~ s/\\([\\"])/$1/g;
57813µs for ($token) {
579130µs310µs s/\\([^\$nrt])/$1/g;
# spent 5µs making 1 call to Template::Parser::CORE:subst # spent 4µs making 2 calls to Template::Parser::CORE:substcont, avg 2µs/call
58018µs1600ns s/\\([nrt])/$QUOTED_ESCAPES->{ $1 }/ge;
# spent 600ns making 1 call to Template::Parser::CORE:subst
581 }
582 push(@tokens, ('"') x 2,
583112µs147µs @{ $self->interpolate_text($token) },
# spent 47µs making 1 call to Template::Parser::interpolate_text
584 ('"') x 2);
58512µs next;
586 }
587 else {
588178µs $type = 'LITERAL';
5891750µs1717µs $token =~ s['][\\']g;
# spent 17µs making 17 calls to Template::Parser::CORE:subst, avg 988ns/call
5901718µs $token = "'$token'";
591 }
592 }
593 else {
5941911µs $type = 'LITERAL';
5951926µs $token = "'$token'";
596 }
597 }
598 # number
599 elsif (defined ($token = $4)) {
600 $type = 'NUMBER';
601 }
602 elsif (defined($token = $5)) {
603 $type = 'FILENAME';
604 }
605 elsif (defined($token = $6)) {
606 # Fold potential keywords to UPPER CASE if the ANYCASE option is
607 # set, unless (we've got some preceeding tokens and) the previous
608 # token is a DOT op. This prevents the 'last' in 'data.last'
609 # from being interpreted as the LAST keyword.
6101780869µs $uctoken =
611 ($anycase && (! @tokens || $tokens[-2] ne 'DOT'))
612 ? uc $token
613 : $token;
61417803.08ms if (defined ($type = $lextable->{ $uctoken })) {
615 $token = $uctoken;
616 }
617 else {
6181020888µs $type = 'IDENT';
619 }
620 }
621 elsif (defined ($token = $7)) {
622 # reserved words may be in lower case unless case sensitive
623966388µs $uctoken = $anycase ? uc $token : $token;
6249661.42ms unless (defined ($type = $lextable->{ $uctoken })) {
625 $type = 'UNQUOTED';
626 }
627 }
628
629279026.8ms27909.83ms push(@tokens, $type, $token);
# spent 9.83ms making 2790 calls to Template::Parser::CORE:match, avg 4µs/call
630
631# print(STDERR " +[ $type, $token ]\n")
632# if $DEBUG;
633 }
634
635# print STDERR "tokenise directive() returning:\n [ @tokens ]\n"
636# if $DEBUG;
637
63810355.47ms return \@tokens; ## RETURN ##
639}
640
641
642#------------------------------------------------------------------------
643# define_block($name, $block)
644#
645# Called by the parser 'defblock' rule when a BLOCK definition is
646# encountered in the template. The name of the block is passed in the
647# first parameter and a reference to the compiled block is passed in
648# the second. This method stores the block in the $self->{ DEFBLOCK }
649# hash which has been initialised by parse() and will later be used
650# by the same method to call the store() method on the calling cache
651# to define the block "externally".
652#------------------------------------------------------------------------
653
654sub define_block {
655 my ($self, $name, $block) = @_;
656 my $defblock = $self->{ DEFBLOCK }
657 || return undef;
658
659 $self->debug("compiled block '$name':\n$block")
660 if $self->{ DEBUG } & Template::Constants::DEBUG_PARSER;
661
662 $defblock->{ $name } = $block;
663
664 return undef;
665}
666
667sub push_defblock {
668 my $self = shift;
669 my $stack = $self->{ DEFBLOCK_STACK } ||= [];
670 push(@$stack, $self->{ DEFBLOCK } );
671 $self->{ DEFBLOCK } = { };
672}
673
674sub pop_defblock {
675 my $self = shift;
676 my $defs = $self->{ DEFBLOCK };
677 my $stack = $self->{ DEFBLOCK_STACK } || return $defs;
678 return $defs unless @$stack;
679 $self->{ DEFBLOCK } = pop @$stack;
680 return $defs;
681}
682
683
684#------------------------------------------------------------------------
685# add_metadata(\@setlist)
686#------------------------------------------------------------------------
687
688sub add_metadata {
689 my ($self, $setlist) = @_;
690 my $metadata = $self->{ METADATA }
691 || return undef;
692
693 push(@$metadata, @$setlist);
694
695 return undef;
696}
697
698
699#------------------------------------------------------------------------
700# location()
701#
702# Return Perl comment indicating current parser file and line
703#------------------------------------------------------------------------
704
705
# spent 11.8ms (10.3+1.53) within Template::Parser::location which was called 626 times, avg 19µs/call: # 626 times (10.3ms+1.53ms) by Template::Grammar::__ANON__[Parser.yp:79] at line 78 of Parser.yp, avg 19µs/call
sub location {
706626676µs my $self = shift;
707626588µs return "\n" unless $self->{ FILE_INFO };
708626706µs my $line = ${ $self->{ LINE } };
709626564µs my $info = $self->{ FILEINFO }->[-1];
710 my $file = $info->{ path } || $info->{ name }
711626781µs || '(unknown template)';
7126264.63ms6261.53ms $line =~ s/\-.*$//; # might be 'n-n'
# spent 1.53ms making 626 calls to Template::Parser::CORE:subst, avg 2µs/call
713626209µs $line ||= 1;
7146264.46ms return "#line $line \"$file\"\n";
715}
716
717
718#========================================================================
719# ----- PRIVATE METHODS -----
720#========================================================================
721
722#------------------------------------------------------------------------
723# _parse(\@tokens, \@info)
724#
725# Parses the list of input tokens passed by reference and returns a
726# Template::Directive::Block object which contains the compiled
727# representation of the template.
728#
729# This is the main parser DFA loop. See embedded comments for
730# further details.
731#
732# On error, undef is returned and the internal _ERROR field is set to
733# indicate the error. This can be retrieved by calling the error()
734# method.
735#------------------------------------------------------------------------
736
737
# spent 549ms (410+139) within Template::Parser::_parse which was called 8 times, avg 68.7ms/call: # 8 times (410ms+139ms) by Template::Parser::parse at line 291, avg 68.7ms/call
sub _parse {
738813µs my ($self, $tokens, $info) = @_;
73989µs my ($token, $value, $text, $line, $inperl);
740840µs my ($state, $stateno, $status, $action, $lookup, $coderet, @codevars);
74185µs my ($lhs, $len, $code); # rule contents
742820µs my $stack = [ [ 0, undef ] ]; # DFA stack
743
744# DEBUG
745# local $" = ', ';
746
747 # retrieve internal rule and state tables
748828µs my ($states, $rules) = @$self{ qw( STATES RULES ) };
749
750 # call the grammar set_factory method to install emitter factory
751865µs883µs $self->{ GRAMMAR }->install_factory($self->{ FACTORY });
# spent 83µs making 8 calls to Template::Grammar::install_factory, avg 10µs/call
752
75389µs $line = $inperl = 0;
754816µs $self->{ LINE } = \$line;
755822µs $self->{ FILE } = $info->{ name };
756811µs $self->{ INPERL } = \$inperl;
757
75887µs $status = CONTINUE;
75986µs my $in_string = 0;
760
761845.6ms while(1) {
762 # get state number and state
7631586510.7ms $stateno = $stack->[-1]->[0];
7641586511.7ms $state = $states->[$stateno];
765
766 # see if any lookaheads exist for the current state
7671586518.5ms if (exists $state->{'ACTIONS'}) {
768
769 # get next token and expand any directives (i.e. token is an
770 # array ref) onto the front of the token list
77177088.88ms while (! defined $token && @$tokens) {
77257775.86ms $token = shift(@$tokens);
77357779.95ms if (ref $token) {
77410352.85ms ($text, $line, $token) = @$token;
77510351.06ms if (ref $token) {
77610351.62ms if ($info->{ DEBUG } && ! $in_string) {
777 # - - - - - - - - - - - - - - - - - - - - - - - - -
778 # This is gnarly. Look away now if you're easily
779 # frightened. We're pushing parse tokens onto the
780 # pending list to simulate a DEBUG directive like so:
781 # [% DEBUG msg line='20' text='INCLUDE foo' %]
782 # - - - - - - - - - - - - - - - - - - - - - - - - -
783 my $dtext = $text;
784 $dtext =~ s[(['\\])][\\$1]g;
785 unshift(@$tokens,
786 DEBUG => 'DEBUG',
787 IDENT => 'msg',
788 IDENT => 'line',
789 ASSIGN => '=',
790 LITERAL => "'$line'",
791 IDENT => 'text',
792 ASSIGN => '=',
793 LITERAL => "'$dtext'",
794 IDENT => 'file',
795 ASSIGN => '=',
796 LITERAL => "'$info->{ name }'",
797 (';') x 2,
798 @$token,
799 (';') x 2);
800 }
801 else {
80210354.60ms unshift(@$tokens, @$token, (';') x 2);
803 }
8041035834µs $token = undef; # force redo
805 }
806 elsif ($token eq 'ITEXT') {
807 if ($inperl) {
808 # don't perform interpolation in PERL blocks
809 $token = 'TEXT';
810 $value = $text;
811 }
812 else {
813 unshift(@$tokens,
814 @{ $self->interpolate_text($text, $line) });
815 $token = undef; # force redo
816 }
817 }
818 }
819 else {
820 # toggle string flag to indicate if we're crossing
821 # a string boundary
82247423.29ms $in_string = ! $in_string if $token eq '"';
82347425.24ms $value = shift(@$tokens);
824 }
825 };
826 # clear undefined token to avoid 'undefined variable blah blah'
827 # warnings and let the parser logic pick it up in a minute
82877082.82ms $token = '' unless defined $token;
829
830 # get the next state for the current lookahead token
831770812.2ms $action = defined ($lookup = $state->{'ACTIONS'}->{ $token })
832 ? $lookup
833 : defined ($lookup = $state->{'DEFAULT'})
834 ? $lookup
835 : undef;
836 }
837 else {
838 # no lookahead actions
83981577.46ms $action = $state->{'DEFAULT'};
840 }
841
842 # ERROR: no ACTION
843158655.87ms last unless defined $action;
844
845 # - - - - - - - - - - - - - - - - - - - - - - - - - - - -
846 # shift (+ive ACTION)
847 # - - - - - - - - - - - - - - - - - - - - - - - - - - - -
8481586510.9ms if ($action > 0) {
84947508.80ms push(@$stack, [ $action, $value ]);
85047502.54ms $token = $value = undef;
85147503.65ms redo;
852 };
853
854 # - - - - - - - - - - - - - - - - - - - - - - - - - - - -
855 # reduce (-ive ACTION)
856 # - - - - - - - - - - - - - - - - - - - - - - - - - - - -
8571111533.9ms ($lhs, $len, $code) = @{ $rules->[ -$action ] };
858
859 # no action imples ACCEPTance
860111154.25ms $action
861 or $status = ACCEPT;
862
863 # use dummy sub if code ref doesn't exist
864311615.1ms
# spent 9.01ms within Template::Parser::__ANON__[/usr/lib/perl5/Template/Parser.pm:864] which was called 3116 times, avg 3µs/call: # 3116 times (9.01ms+0s) by Template::Parser::_parse at line 872, avg 3µs/call
$code = sub { $_[1] }
8651111514.3ms unless $code;
866
867 @codevars = $len
8681111559.1ms ? map { $_->[1] } @$stack[ -$len .. -1 ]
869 : ();
870
8711111513.1ms eval {
8721111546.8ms11115139ms $coderet = &$code( $self, @codevars );
# spent 48.2ms making 914 calls to Template::Grammar::__ANON__[Parser.yp:76], avg 53µs/call # spent 19.0ms making 626 calls to Template::Grammar::__ANON__[Parser.yp:79], avg 30µs/call # spent 12.1ms making 643 calls to Template::Grammar::__ANON__[Parser.yp:305], avg 19µs/call # spent 9.01ms making 3116 calls to Template::Parser::__ANON__[Template/Parser.pm:864], avg 3µs/call # spent 8.50ms making 416 calls to Template::Grammar::__ANON__[Parser.yp:67], avg 20µs/call # spent 7.36ms making 273 calls to Template::Grammar::__ANON__[Parser.yp:141], avg 27µs/call # spent 6.05ms making 1124 calls to Template::Grammar::__ANON__[Parser.yp:72], avg 5µs/call # spent 4.42ms making 919 calls to Template::Grammar::__ANON__[Parser.yp:345], avg 5µs/call # spent 4.05ms making 915 calls to Template::Grammar::__ANON__[Parser.yp:341], avg 4µs/call # spent 3.74ms making 236 calls to Template::Grammar::__ANON__[Parser.yp:90], avg 16µs/call # spent 2.86ms making 27 calls to Template::Grammar::__ANON__[Parser.yp:168], avg 106µs/call # spent 2.70ms making 74 calls to Template::Grammar::__ANON__[Parser.yp:229], avg 36µs/call # spent 1.78ms making 416 calls to Template::Grammar::__ANON__[Parser.yp:73], avg 4µs/call # spent 1.74ms making 273 calls to Template::Grammar::__ANON__[Parser.yp:334], avg 6µs/call # spent 1.20ms making 8 calls to Template::Grammar::__ANON__[Parser.yp:64], avg 150µs/call # spent 1.17ms making 276 calls to Template::Grammar::__ANON__[Parser.yp:364], avg 4µs/call # spent 1.07ms making 67 calls to Template::Grammar::__ANON__[Parser.yp:109], avg 16µs/call # spent 729µs making 192 calls to Template::Grammar::__ANON__[Parser.yp:152], avg 4µs/call # spent 610µs making 27 calls to Template::Grammar::__ANON__[Parser.yp:167], avg 23µs/call # spent 403µs making 93 calls to Template::Grammar::__ANON__[Parser.yp:151], avg 4µs/call # spent 371µs making 113 calls to Template::Grammar::__ANON__[Parser.yp:387], avg 3µs/call # spent 329µs making 79 calls to Template::Grammar::__ANON__[Parser.yp:407], avg 4µs/call # spent 327µs making 74 calls to Template::Grammar::__ANON__[Parser.yp:416], avg 4µs/call # spent 320µs making 12 calls to Template::Grammar::__ANON__[Parser.yp:144], avg 27µs/call # spent 315µs making 82 calls to Template::Grammar::__ANON__[Parser.yp:412], avg 4µs/call # spent 251µs making 8 calls to Template::Grammar::__ANON__[Parser.yp:118], avg 31µs/call # spent 143µs making 27 calls to Template::Grammar::__ANON__[Parser.yp:176], avg 5µs/call # spent 109µs making 3 calls to Template::Grammar::__ANON__[Parser.yp:115], avg 36µs/call # spent 97µs making 23 calls to Template::Grammar::__ANON__[Parser.yp:357], avg 4µs/call # spent 85µs making 4 calls to Template::Grammar::__ANON__[Parser.yp:342], avg 21µs/call # spent 78µs making 12 calls to Template::Grammar::__ANON__[Parser.yp:359], avg 7µs/call # spent 71µs making 9 calls to Template::Grammar::__ANON__[Parser.yp:382], avg 8µs/call # spent 37µs making 9 calls to Template::Grammar::__ANON__[Parser.yp:360], avg 4µs/call # spent 30µs making 1 call to Template::Grammar::__ANON__[Parser.yp:440] # spent 28µs making 4 calls to Template::Grammar::__ANON__[Parser.yp:150], avg 7µs/call # spent 21µs making 1 call to Template::Grammar::__ANON__[Parser.yp:307] # spent 19µs making 1 call to Template::Grammar::__ANON__[Parser.yp:145] # spent 17µs making 4 calls to Template::Grammar::__ANON__[Parser.yp:312], avg 4µs/call # spent 14µs making 1 call to Template::Grammar::__ANON__[Parser.yp:68] # spent 13µs making 3 calls to Template::Grammar::__ANON__[Parser.yp:408], avg 4µs/call # spent 9µs making 3 calls to Template::Grammar::__ANON__[Parser.yp:374], avg 3µs/call # spent 9µs making 3 calls to Template::Grammar::__ANON__[Parser.yp:386], avg 3µs/call # spent 7µs making 1 call to Template::Grammar::__ANON__[Parser.yp:361] # spent 7µs making 1 call to Template::Grammar::__ANON__[Parser.yp:299] # spent 6µs making 1 call to Template::Grammar::__ANON__[Parser.yp:435] # spent 4µs making 1 call to Template::Grammar::__ANON__[Parser.yp:436]
873 };
874111154.02ms if ($@) {
875 my $err = $@;
876 chomp $err;
877 return $self->_parse_error($err);
878 }
879
880 # reduce stack by $len
8811111519.1ms splice(@$stack, -$len, $len);
882
883 # ACCEPT
884111155.52ms return $coderet ## RETURN ##
885 if $status == ACCEPT;
886
887 # ABORT
888 return undef ## RETURN ##
889111073.51ms if $status == ABORT;
890
891 # ERROR
892 last
893111076.09ms if $status == ERROR;
894 }
895 continue {
896 push(@$stack, [ $states->[ $stack->[-1][0] ]->{'GOTOS'}->{ $lhs },
897 $coderet ]),
898 }
899
900 # ERROR ## RETURN ##
901 return $self->_parse_error('unexpected end of input')
902 unless defined $value;
903
904 # munge text of last directive to make it readable
905# $text =~ s/\n/\\n/g;
906
907 return $self->_parse_error("unexpected end of directive", $text)
908 if $value eq ';'; # end of directive SEPARATOR
909
910 return $self->_parse_error("unexpected token ($value)", $text);
911}
912
- -
915#------------------------------------------------------------------------
916# _parse_error($msg, $dirtext)
917#
918# Method used to handle errors encountered during the parse process
919# in the _parse() method.
920#------------------------------------------------------------------------
921
922sub _parse_error {
923 my ($self, $msg, $text) = @_;
924 my $line = $self->{ LINE };
925 $line = ref($line) ? $$line : $line;
926 $line = 'unknown' unless $line;
927
928 $msg .= "\n [% $text %]"
929 if defined $text;
930
931 return $self->error("line $line: $msg");
932}
933
934
935#------------------------------------------------------------------------
936# _dump()
937#
938# Debug method returns a string representing the internal state of the
939# object.
940#------------------------------------------------------------------------
941
942sub _dump {
943 my $self = shift;
944 my $output = "[Template::Parser] {\n";
945 my $format = " %-16s => %s\n";
946 my $key;
947
948 foreach $key (qw( START_TAG END_TAG TAG_STYLE ANYCASE INTERPOLATE
949 PRE_CHOMP POST_CHOMP V1DOLLAR )) {
950 my $val = $self->{ $key };
951 $val = '<undef>' unless defined $val;
952 $output .= sprintf($format, $key, $val);
953 }
954
955 $output .= '}';
956 return $output;
957}
958
959
960122µs1;
961
962__END__
 
# spent 17.4ms within Template::Parser::CORE:match which was called 5916 times, avg 3µs/call: # 2790 times (9.83ms+0s) by Template::Parser::tokenise_directive at line 629, avg 4µs/call # 1036 times (5.94ms+0s) by Template::Parser::tokenise_directive at line 524, avg 6µs/call # 1035 times (957µs+0s) by Template::Parser::split_text at line 348, avg 925ns/call # 1035 times (634µs+0s) by Template::Parser::split_text at line 403, avg 613ns/call # 18 times (17µs+0s) by Template::Parser::tokenise_directive at line 572, avg 933ns/call # once (4µs+0s) by Template::Parser::interpolate_text at line 456 # once (700ns+0s) by Template::Parser::interpolate_text at line 477
sub Template::Parser::CORE:match; # opcode
# spent 65µs within Template::Parser::CORE:qr which was called 9 times, avg 7µs/call: # 8 times (58µs+0s) by Template::Parser::split_text at line 321, avg 7µs/call # once (6µs+0s) by Template::Config::load at line 90
sub Template::Parser::CORE:qr; # opcode
# spent 4.73ms within Template::Parser::CORE:regcomp which was called 4148 times, avg 1µs/call: # 1035 times (2.11ms+0s) by Template::Parser::split_text at line 429, avg 2µs/call # 1035 times (1.63ms+0s) by Template::Parser::split_text at line 403, avg 2µs/call # 1035 times (538µs+0s) by Template::Parser::split_text at line 353, avg 520ns/call # 1035 times (405µs+0s) by Template::Parser::split_text at line 372, avg 391ns/call # 8 times (47µs+0s) by Template::Parser::split_text at line 330, avg 6µs/call
sub Template::Parser::CORE:regcomp; # opcode
# spent 19.7ms within Template::Parser::CORE:subst which was called 3759 times, avg 5µs/call: # 1035 times (9.02ms+0s) by Template::Parser::split_text at line 372, avg 9µs/call # 1035 times (5.77ms+0s) by Template::Parser::split_text at line 429, avg 6µs/call # 1035 times (3.30ms+0s) by Template::Parser::split_text at line 353, avg 3µs/call # 626 times (1.53ms+0s) by Template::Parser::location at line 712, avg 2µs/call # 17 times (17µs+0s) by Template::Parser::tokenise_directive at line 589, avg 988ns/call # 8 times (93µs+0s) by Template::Parser::split_text at line 330, avg 12µs/call # once (5µs+0s) by Template::Parser::tokenise_directive at line 579 # once (700ns+0s) by Template::Parser::interpolate_text at line 473 # once (600ns+0s) by Template::Parser::tokenise_directive at line 580
sub Template::Parser::CORE:subst; # opcode
# spent 4µs within Template::Parser::CORE:substcont which was called 2 times, avg 2µs/call: # 2 times (4µs+0s) by Template::Parser::tokenise_directive at line 579, avg 2µs/call
sub Template::Parser::CORE:substcont; # opcode