| 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 | Template::Parser::_parse |
| 384174 | 1 | 1 | 28.3s | 58.0s | Template::Parser::split_text |
| 383161 | 1 | 1 | 25.4s | 53.1s | Template::Parser::new |
| 314713 | 1 | 1 | 16.6s | 21.9s | Template::Parser::tokenise_directive |
| 383161 | 1 | 1 | 11.2s | 18.7s | Template::Parser::new_style |
| 384174 | 1 | 1 | 11.1s | 244s | Template::Parser::parse |
| 1853838 | 11 | 1 | 6.02s | 6.02s | Template::Parser::CORE:subst (opcode) |
| 383161 | 1 | 1 | 5.63s | 7.45s | Template::Parser::text_splitter |
| 2643427 | 7 | 1 | 5.39s | 5.39s | Template::Parser::CORE:match (opcode) |
| 313428 | 1 | 1 | 2.91s | 3.24s | Template::Parser::location |
| 2026187 | 6 | 1 | 2.48s | 2.48s | Template::Parser::CORE:regcomp (opcode) |
| 2498716 | 1 | 1 | 1.81s | 1.81s | Template::Parser::__ANON__[:955] |
| 767337 | 4 | 1 | 1.32s | 1.32s | Template::Parser::CORE:qr (opcode) |
| 5968 | 1 | 1 | 85.0ms | 135ms | Template::Parser::leave_block |
| 5968 | 1 | 1 | 49.9ms | 49.9ms | Template::Parser::block_label |
| 1991 | 1 | 1 | 48.4ms | 56.3ms | Template::Parser::interpolate_text |
| 5968 | 1 | 1 | 39.0ms | 39.0ms | Template::Parser::enter_block |
| 1 | 1 | 1 | 14.0ms | 14.1ms | Template::Parser::BEGIN@41 |
| 3982 | 1 | 1 | 5.03ms | 5.03ms | Template::Parser::CORE:substcont (opcode) |
| 1 | 1 | 1 | 4.36ms | 4.61ms | Template::Parser::BEGIN@40 |
| 1 | 1 | 1 | 16µs | 20µs | Template::Parser::BEGIN@35 |
| 1 | 1 | 1 | 10µs | 100µs | Template::Parser::BEGIN@44 |
| 1 | 1 | 1 | 9µs | 88µs | Template::Parser::BEGIN@37 |
| 1 | 1 | 1 | 8µs | 245µs | Template::Parser::BEGIN@39 |
| 1 | 1 | 1 | 8µs | 31µs | Template::Parser::BEGIN@36 |
| 1 | 1 | 1 | 6µs | 29µs | Template::Parser::BEGIN@45 |
| 1 | 1 | 1 | 6µs | 28µs | Template::Parser::BEGIN@46 |
| 1 | 1 | 1 | 5µs | 25µs | Template::Parser::BEGIN@47 |
| 2 | 2 | 1 | 3µs | 3µs | Template::Parser::__ANON__ (xsub) |
| 0 | 0 | 0 | 0s | 0s | Template::Parser::_dump |
| 0 | 0 | 0 | 0s | 0s | Template::Parser::_parse_error |
| 0 | 0 | 0 | 0s | 0s | Template::Parser::add_metadata |
| 0 | 0 | 0 | 0s | 0s | Template::Parser::define_block |
| 0 | 0 | 0 | 0s | 0s | Template::Parser::in_block |
| 0 | 0 | 0 | 0s | 0s | Template::Parser::old_style |
| 0 | 0 | 0 | 0s | 0s | Template::Parser::pop_defblock |
| 0 | 0 | 0 | 0s | 0s | Template::Parser::push_defblock |
| 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 |