← Index
NYTProf Performance Profile   « block view • line view • sub view »
For -e
  Run on Wed Nov 17 21:45:08 2010
Reported on Wed Nov 17 22:10:10 2010

Filename/home/doy/perl5/perlbrew/perls/perl-5.10.1/lib/site_perl/5.10.1/Markdent/Dialect/Standard/BlockParser.pm
StatementsExecuted 101 statements in 22.3ms
Subroutines
Calls P F Exclusive
Time
Inclusive
Time
Subroutine
1112.55ms4.65msMarkdent::Dialect::Standard::BlockParser::::BEGIN@9Markdent::Dialect::Standard::BlockParser::BEGIN@9
1111.63ms7.90msMarkdent::Dialect::Standard::BlockParser::::BEGIN@28Markdent::Dialect::Standard::BlockParser::BEGIN@28
1111.61ms132msMarkdent::Dialect::Standard::BlockParser::::BEGIN@15Markdent::Dialect::Standard::BlockParser::BEGIN@15
1111.58ms143msMarkdent::Dialect::Standard::BlockParser::::BEGIN@26Markdent::Dialect::Standard::BlockParser::BEGIN@26
1111.51ms139msMarkdent::Dialect::Standard::BlockParser::::BEGIN@27Markdent::Dialect::Standard::BlockParser::BEGIN@27
1111.49ms149msMarkdent::Dialect::Standard::BlockParser::::BEGIN@25Markdent::Dialect::Standard::BlockParser::BEGIN@25
1111.46ms139msMarkdent::Dialect::Standard::BlockParser::::BEGIN@14Markdent::Dialect::Standard::BlockParser::BEGIN@14
1111.36ms115msMarkdent::Dialect::Standard::BlockParser::::BEGIN@20Markdent::Dialect::Standard::BlockParser::BEGIN@20
1111.25ms112msMarkdent::Dialect::Standard::BlockParser::::BEGIN@11Markdent::Dialect::Standard::BlockParser::BEGIN@11
1111.22ms111msMarkdent::Dialect::Standard::BlockParser::::BEGIN@16Markdent::Dialect::Standard::BlockParser::BEGIN@16
1111.22ms119msMarkdent::Dialect::Standard::BlockParser::::BEGIN@19Markdent::Dialect::Standard::BlockParser::BEGIN@19
1111.21ms111msMarkdent::Dialect::Standard::BlockParser::::BEGIN@22Markdent::Dialect::Standard::BlockParser::BEGIN@22
1111.19ms119msMarkdent::Dialect::Standard::BlockParser::::BEGIN@13Markdent::Dialect::Standard::BlockParser::BEGIN@13
1111.19ms111msMarkdent::Dialect::Standard::BlockParser::::BEGIN@18Markdent::Dialect::Standard::BlockParser::BEGIN@18
1111.18ms111msMarkdent::Dialect::Standard::BlockParser::::BEGIN@21Markdent::Dialect::Standard::BlockParser::BEGIN@21
1111.18ms111msMarkdent::Dialect::Standard::BlockParser::::BEGIN@12Markdent::Dialect::Standard::BlockParser::BEGIN@12
1111.17ms114msMarkdent::Dialect::Standard::BlockParser::::BEGIN@17Markdent::Dialect::Standard::BlockParser::BEGIN@17
1111.16ms112msMarkdent::Dialect::Standard::BlockParser::::BEGIN@23Markdent::Dialect::Standard::BlockParser::BEGIN@23
1111.16ms628msMarkdent::Dialect::Standard::BlockParser::::BEGIN@10Markdent::Dialect::Standard::BlockParser::BEGIN@10
1111.16ms111msMarkdent::Dialect::Standard::BlockParser::::BEGIN@24Markdent::Dialect::Standard::BlockParser::BEGIN@24
441284µs284µsMarkdent::Dialect::Standard::BlockParser::::CORE:regcompMarkdent::Dialect::Standard::BlockParser::CORE:regcomp (opcode)
11196µs28.0msMarkdent::Dialect::Standard::BlockParser::::BEGIN@34Markdent::Dialect::Standard::BlockParser::BEGIN@34
11155µs55µsMarkdent::Dialect::Standard::BlockParser::::BEGIN@2Markdent::Dialect::Standard::BlockParser::BEGIN@2
66148µs48µsMarkdent::Dialect::Standard::BlockParser::::CORE:qrMarkdent::Dialect::Standard::BlockParser::CORE:qr (opcode)
11147µs18.8msMarkdent::Dialect::Standard::BlockParser::::BEGIN@29Markdent::Dialect::Standard::BlockParser::BEGIN@29
11147µs23.1msMarkdent::Dialect::Standard::BlockParser::::BEGIN@33Markdent::Dialect::Standard::BlockParser::BEGIN@33
11145µs228µsMarkdent::Dialect::Standard::BlockParser::::BEGIN@31Markdent::Dialect::Standard::BlockParser::BEGIN@31
11143µs23.0msMarkdent::Dialect::Standard::BlockParser::::BEGIN@32Markdent::Dialect::Standard::BlockParser::BEGIN@32
11140µs57µsMarkdent::Dialect::Standard::BlockParser::::BEGIN@6Markdent::Dialect::Standard::BlockParser::BEGIN@6
11138µs105µsMarkdent::Dialect::Standard::BlockParser::::BEGIN@7Markdent::Dialect::Standard::BlockParser::BEGIN@7
0000s0sClass::MOP::Method::Generated::::__ANON__[:57] Class::MOP::Method::Generated::__ANON__[:57]
0000s0sClass::MOP::Method::Generated::::__ANON__[:66] Class::MOP::Method::Generated::__ANON__[:66]
0000s0sClass::MOP::Method::Generated::::__ANON__[:69] Class::MOP::Method::Generated::__ANON__[:69]
0000s0sClass::MOP::Method::Generated::::__ANON__[:81] Class::MOP::Method::Generated::__ANON__[:81]
0000s0sMarkdent::Dialect::Standard::BlockParser::::__ANON__[:42]Markdent::Dialect::Standard::BlockParser::__ANON__[:42]
0000s0sMarkdent::Dialect::Standard::BlockParser::::_hash_and_save_htmlMarkdent::Dialect::Standard::BlockParser::_hash_and_save_html
0000s0sMarkdent::Dialect::Standard::BlockParser::::_hash_html_blocksMarkdent::Dialect::Standard::BlockParser::_hash_html_blocks
0000s0sMarkdent::Dialect::Standard::BlockParser::::_headerMarkdent::Dialect::Standard::BlockParser::_header
0000s0sMarkdent::Dialect::Standard::BlockParser::::_list_reMarkdent::Dialect::Standard::BlockParser::_list_re
0000s0sMarkdent::Dialect::Standard::BlockParser::::_match_atx_headerMarkdent::Dialect::Standard::BlockParser::_match_atx_header
0000s0sMarkdent::Dialect::Standard::BlockParser::::_match_blockquoteMarkdent::Dialect::Standard::BlockParser::_match_blockquote
0000s0sMarkdent::Dialect::Standard::BlockParser::::_match_hashed_htmlMarkdent::Dialect::Standard::BlockParser::_match_hashed_html
0000s0sMarkdent::Dialect::Standard::BlockParser::::_match_horizontal_ruleMarkdent::Dialect::Standard::BlockParser::_match_horizontal_rule
0000s0sMarkdent::Dialect::Standard::BlockParser::::_match_html_commentMarkdent::Dialect::Standard::BlockParser::_match_html_comment
0000s0sMarkdent::Dialect::Standard::BlockParser::::_match_listMarkdent::Dialect::Standard::BlockParser::_match_list
0000s0sMarkdent::Dialect::Standard::BlockParser::::_match_list_itemMarkdent::Dialect::Standard::BlockParser::_match_list_item
0000s0sMarkdent::Dialect::Standard::BlockParser::::_match_paragraphMarkdent::Dialect::Standard::BlockParser::_match_paragraph
0000s0sMarkdent::Dialect::Standard::BlockParser::::_match_preformattedMarkdent::Dialect::Standard::BlockParser::_match_preformatted
0000s0sMarkdent::Dialect::Standard::BlockParser::::_match_two_line_headerMarkdent::Dialect::Standard::BlockParser::_match_two_line_header
0000s0sMarkdent::Dialect::Standard::BlockParser::::_parse_textMarkdent::Dialect::Standard::BlockParser::_parse_text
0000s0sMarkdent::Dialect::Standard::BlockParser::::_possible_block_matchesMarkdent::Dialect::Standard::BlockParser::_possible_block_matches
0000s0sMarkdent::Dialect::Standard::BlockParser::::_split_chunks_on_regexMarkdent::Dialect::Standard::BlockParser::_split_chunks_on_regex
0000s0sMarkdent::Dialect::Standard::BlockParser::::_split_list_itemsMarkdent::Dialect::Standard::BlockParser::_split_list_items
0000s0sMarkdent::Dialect::Standard::BlockParser::::parse_documentMarkdent::Dialect::Standard::BlockParser::parse_document
Call graph for these subroutines as a Graphviz dot language file.
Line State
ments
Time
on line
Calls Time
in subs
Code
1package Markdent::Dialect::Standard::BlockParser;
2
# spent 55µs within Markdent::Dialect::Standard::BlockParser::BEGIN@2 which was called: # once (55µs+0s) by Markdent::Parser::BEGIN@10 at line 4
BEGIN {
3134µs $Markdent::Dialect::Standard::BlockParser::VERSION = '0.17';
4183µs155µs}
5
6392µs274µs
# spent 57µs (40+17) within Markdent::Dialect::Standard::BlockParser::BEGIN@6 which was called: # once (40µs+17µs) by Markdent::Parser::BEGIN@10 at line 6
use strict;
# spent 57µs making 1 call to Markdent::Dialect::Standard::BlockParser::BEGIN@6 # spent 17µs making 1 call to strict::import
73104µs2173µs
# spent 105µs (38+68) within Markdent::Dialect::Standard::BlockParser::BEGIN@7 which was called: # once (38µs+68µs) by Markdent::Parser::BEGIN@10 at line 7
use warnings;
# spent 105µs making 1 call to Markdent::Dialect::Standard::BlockParser::BEGIN@7 # spent 68µs making 1 call to warnings::import
8
93456µs24.90ms
# spent 4.65ms (2.55+2.10) within Markdent::Dialect::Standard::BlockParser::BEGIN@9 which was called: # once (2.55ms+2.10ms) by Markdent::Parser::BEGIN@10 at line 9
use Digest::SHA1 qw( sha1_hex );
# spent 4.65ms making 1 call to Markdent::Dialect::Standard::BlockParser::BEGIN@9 # spent 252µs making 1 call to Exporter::import
103553µs1628ms
# spent 628ms (1.16+627) within Markdent::Dialect::Standard::BlockParser::BEGIN@10 which was called: # once (1.16ms+627ms) by Markdent::Parser::BEGIN@10 at line 10
use Markdent::Event::StartDocument;
113575µs1112ms
# spent 112ms (1.25+110) within Markdent::Dialect::Standard::BlockParser::BEGIN@11 which was called: # once (1.25ms+110ms) by Markdent::Parser::BEGIN@10 at line 11
use Markdent::Event::EndDocument;
123576µs1111ms
# spent 111ms (1.18+110) within Markdent::Dialect::Standard::BlockParser::BEGIN@12 which was called: # once (1.18ms+110ms) by Markdent::Parser::BEGIN@10 at line 12
use Markdent::Event::StartBlockquote;
133545µs1119ms
# spent 119ms (1.19+118) within Markdent::Dialect::Standard::BlockParser::BEGIN@13 which was called: # once (1.19ms+118ms) by Markdent::Parser::BEGIN@10 at line 13
use Markdent::Event::EndBlockquote;
143547µs1139ms
# spent 139ms (1.46+138) within Markdent::Dialect::Standard::BlockParser::BEGIN@14 which was called: # once (1.46ms+138ms) by Markdent::Parser::BEGIN@10 at line 14
use Markdent::Event::StartHeader;
153662µs1132ms
# spent 132ms (1.61+130) within Markdent::Dialect::Standard::BlockParser::BEGIN@15 which was called: # once (1.61ms+130ms) by Markdent::Parser::BEGIN@10 at line 15
use Markdent::Event::EndHeader;
163552µs1111ms
# spent 111ms (1.22+110) within Markdent::Dialect::Standard::BlockParser::BEGIN@16 which was called: # once (1.22ms+110ms) by Markdent::Parser::BEGIN@10 at line 16
use Markdent::Event::StartListItem;
173544µs1114ms
# spent 114ms (1.17+113) within Markdent::Dialect::Standard::BlockParser::BEGIN@17 which was called: # once (1.17ms+113ms) by Markdent::Parser::BEGIN@10 at line 17
use Markdent::Event::EndListItem;
183543µs1111ms
# spent 111ms (1.19+110) within Markdent::Dialect::Standard::BlockParser::BEGIN@18 which was called: # once (1.19ms+110ms) by Markdent::Parser::BEGIN@10 at line 18
use Markdent::Event::StartOrderedList;
193598µs1119ms
# spent 119ms (1.22+118) within Markdent::Dialect::Standard::BlockParser::BEGIN@19 which was called: # once (1.22ms+118ms) by Markdent::Parser::BEGIN@10 at line 19
use Markdent::Event::EndOrderedList;
203550µs1115ms
# spent 115ms (1.36+113) within Markdent::Dialect::Standard::BlockParser::BEGIN@20 which was called: # once (1.36ms+113ms) by Markdent::Parser::BEGIN@10 at line 20
use Markdent::Event::StartParagraph;
213573µs1111ms
# spent 111ms (1.18+110) within Markdent::Dialect::Standard::BlockParser::BEGIN@21 which was called: # once (1.18ms+110ms) by Markdent::Parser::BEGIN@10 at line 21
use Markdent::Event::EndParagraph;
223552µs1111ms
# spent 111ms (1.21+109) within Markdent::Dialect::Standard::BlockParser::BEGIN@22 which was called: # once (1.21ms+109ms) by Markdent::Parser::BEGIN@10 at line 22
use Markdent::Event::StartUnorderedList;
233548µs1112ms
# spent 112ms (1.16+111) within Markdent::Dialect::Standard::BlockParser::BEGIN@23 which was called: # once (1.16ms+111ms) by Markdent::Parser::BEGIN@10 at line 23
use Markdent::Event::EndUnorderedList;
243547µs1111ms
# spent 111ms (1.16+110) within Markdent::Dialect::Standard::BlockParser::BEGIN@24 which was called: # once (1.16ms+110ms) by Markdent::Parser::BEGIN@10 at line 24
use Markdent::Event::HorizontalRule;
253542µs1149ms
# spent 149ms (1.49+147) within Markdent::Dialect::Standard::BlockParser::BEGIN@25 which was called: # once (1.49ms+147ms) by Markdent::Parser::BEGIN@10 at line 25
use Markdent::Event::HTMLBlock;
263545µs1143ms
# spent 143ms (1.58+142) within Markdent::Dialect::Standard::BlockParser::BEGIN@26 which was called: # once (1.58ms+142ms) by Markdent::Parser::BEGIN@10 at line 26
use Markdent::Event::HTMLCommentBlock;
273598µs1139ms
# spent 139ms (1.51+138) within Markdent::Dialect::Standard::BlockParser::BEGIN@27 which was called: # once (1.51ms+138ms) by Markdent::Parser::BEGIN@10 at line 27
use Markdent::Event::Preformatted;
283558µs28.91ms
# spent 7.90ms (1.63+6.27) within Markdent::Dialect::Standard::BlockParser::BEGIN@28 which was called: # once (1.63ms+6.27ms) by Markdent::Parser::BEGIN@10 at line 28
use Markdent::Regexes qw( :block $HTMLComment );
# spent 7.90ms making 1 call to Markdent::Dialect::Standard::BlockParser::BEGIN@28 # spent 1.01ms making 1 call to Exporter::import
293156µs237.5ms
# spent 18.8ms (47µs+18.7) within Markdent::Dialect::Standard::BlockParser::BEGIN@29 which was called: # once (47µs+18.7ms) by Markdent::Parser::BEGIN@10 at line 29
use Markdent::Types qw( Str Int Bool ArrayRef HashRef );
# spent 18.8ms making 1 call to Markdent::Dialect::Standard::BlockParser::BEGIN@29 # spent 18.7ms making 1 call to MooseX::Types::Combine::import
30
313107µs2411µs
# spent 228µs (45+183) within Markdent::Dialect::Standard::BlockParser::BEGIN@31 which was called: # once (45µs+183µs) by Markdent::Parser::BEGIN@10 at line 31
use namespace::autoclean;
# spent 228µs making 1 call to Markdent::Dialect::Standard::BlockParser::BEGIN@31 # spent 183µs making 1 call to namespace::autoclean::import
323160µs245.9ms
# spent 23.0ms (43µs+22.9) within Markdent::Dialect::Standard::BlockParser::BEGIN@32 which was called: # once (43µs+22.9ms) by Markdent::Parser::BEGIN@10 at line 32
use Moose;
333156µs246.2ms
# spent 23.1ms (47µs+23.1) within Markdent::Dialect::Standard::BlockParser::BEGIN@33 which was called: # once (47µs+23.1ms) by Markdent::Parser::BEGIN@10 at line 33
use MooseX::SemiAffordanceAccessor;
3439.06ms255.9ms
# spent 28.0ms (96µs+27.9) within Markdent::Dialect::Standard::BlockParser::BEGIN@34 which was called: # once (96µs+27.9ms) by Markdent::Parser::BEGIN@10 at line 34
use MooseX::StrictConstructor;
35
36117µs1205mswith 'Markdent::Role::BlockParser';
# spent 205ms making 1 call to Moose::with
37
38has __html_blocks => (
39 traits => ['Hash'],
40 is => 'ro',
41 isa => HashRef[Str],
42 default => sub { {} },
43168µs31.20s init_arg => undef,
# spent 1.19s making 1 call to Moose::has # spent 7.88ms making 1 call to __TYPE__::HashRef # spent 328µs making 1 call to __TYPE__::Str
44 handles => {
45 _save_html_block => 'set',
46 _get_html_block => 'get',
47 },
48);
49
50137µs2472mshas _list_level => (
# spent 472ms making 1 call to Moose::has # spent 361µs making 1 call to __TYPE__::Int
51 traits => ['Counter'],
52 is => 'rw',
53 isa => Int,
54 default => 0,
55 init_arg => undef,
56 handles => {
57 '_inc_list_level' => 'inc',
58130µs '_dec_list_level' => 'dec',
59 },
60);
61
62136µs2442mshas _list_item_is_paragraph => (
# spent 442ms making 1 call to Moose::has # spent 327µs making 1 call to __TYPE__::Bool
63 traits => ['Bool'],
64 is => 'ro',
65 isa => Bool,
66 default => 0,
67138µs init_arg => undef,
68 handles => {
69 _treat_list_item_as_paragraph => 'set',
70272µs _treat_list_item_as_line => 'unset',
71 },
72);
73
74sub parse_document {
75 my $self = shift;
76 my $text = shift;
77
78 $self->_treat_list_item_as_line();
79
80 $self->_hash_html_blocks($text);
81
82278µs $self->_span_parser()->extract_link_ids($text);
83
84 $self->_parse_text($text);
85}
86
87{
88 # Stolen from Text::Markdown, along with the whole "extract and replace
89 # with hash" concept.
90243µs113µs my $block_names_re = qr{
91 p | div | h[1-6] | blockquote | pre | table |
92 dl | ol | ul | script | noscript | form |
93 fieldset | iframe | math | ins | del
94 }xi;
95
96 sub _hash_html_blocks {
97 my $self = shift;
98 my $text = shift;
99
100 ${$text}
101 =~ s{
102 ( $BlockStart )
103 (
104 ^ < ($block_names_re) [^>]* >
105 (?s: .+? )
106 (?: </ \3 > \n )+ # This catches repetitions of the final closing block
107 )
108 $BlockEnd
109 }
110 { ( $1 || q{} ) . $self->_hash_and_save_html($2) }egxm;
111
112 return;
113 }
114}
115
116sub _hash_and_save_html {
117 my $self = shift;
118 my $html = shift;
119
120 my $sha1 = sha1_hex($html);
121
122 $self->_save_html_block( $sha1 => $html );
123
124 return 'html:' . $sha1 . "\n";
125}
126
127sub _parse_text {
128 my $self = shift;
129 my $text = shift;
130
131 my $last_pos;
132 my $x = 1;
133 PARSE:
134 while (1) {
135 if ( $self->debug() && pos ${$text} ) {
136 $self->_print_debug( "Remaining text:\n[\n"
137 . substr( ${$text}, pos ${$text} )
138 . "\n]\n" );
139 }
140
141 if ( ${$text} =~ / \G \p{Space}* \z /xgc ) {
142 last;
143 }
144
145 my $current_pos = pos ${$text} || 0;
146 if ( defined $last_pos && $last_pos == $current_pos ) {
147 my $msg = "About to enter an endless loop (pos = $current_pos)!\n";
148 $msg .= "\n";
149 $msg .= substr( ${$text}, $last_pos );
150 $msg .= "\n";
151
152 die $msg;
153 }
154
155 my @look_for = $self->_possible_block_matches();
156
157 $self->_debug_look_for(@look_for);
158
159 for my $block (@look_for) {
160 my $meth = '_match_' . $block;
161
162 $self->$meth($text)
163 and next PARSE;
164 }
165
166 $last_pos = pos ${$text} || 0;
167 }
168}
169
170sub _possible_block_matches {
171 my $self = shift;
172
173 my @look_for;
174
175 push @look_for, qw( hashed_html horizontal_rule )
176 unless $self->_list_level();
177
178 push @look_for,
179 qw( html_comment
180 atx_header two_line_header
181 blockquote preformatted list );
182
183 push @look_for, 'list_item'
184 if $self->_list_level();
185
186 push @look_for, 'paragraph';
187
188 return @look_for;
189}
190
191sub _match_hashed_html {
192 my $self = shift;
193 my $text = shift;
194
195 return unless ${$text} =~ / \G
196 $BlockStart
197 ^
198 (
199 html:(.{40})
200 \n
201 )
202 $BlockEnd
203 /xmgc;
204
205 my $html = $self->_get_html_block($2);
206
207 return unless defined $html;
208
209 $self->_debug_parse_result(
210 $1,
211 'hashed html',
212 ) if $self->debug();
213
214 $self->_send_event(
215 HTMLBlock => html => $html,
216 );
217
218 return 1;
219}
220
221sub _match_html_comment {
222 my $self = shift;
223 my $text = shift;
224
225 return unless ${$text} =~ / \G
226 $EmptyLine*?
227 ^
228 \p{SpaceSeparator}{0,3}
229 $HTMLComment
230 $HorizontalWS*
231 \n
232 /xmgc;
233
234 my $comment = $1;
235
236 $self->_debug_parse_result(
237 $comment,
238 'html comment block',
239 ) if $self->debug();
240
241 $self->_detab_text(\$comment);
242
243 $self->_send_event( HTMLCommentBlock => text => $comment );
244
245 return 1;
246}
247
2481146µs2110µsmy $AtxHeader = qr/ ^
249 (\#{1,6})
250 (
251 $HorizontalWS*
252 \S
253 .+?
254 )
255 (?:
256 $HorizontalWS*
257 \#+
258 )?
259 \n
260 /xm;
261
262sub _match_atx_header {
263 my $self = shift;
264 my $text = shift;
265
266 return unless ${$text} =~ / \G
267 (?:$EmptyLines)?
268 ($AtxHeader)
269 /xmgc;
270
271 my $level = length $2;
272 my $header_text = $3 . "\n";
273
274 $self->_debug_parse_result(
275 $1,
276 'atx header',
277 [ level => $level ],
278 ) if $self->debug();
279
280 $header_text =~ s/^$HorizontalWS*//;
281
282 $self->_header( $level, $header_text );
283
284 return 1;
285}
286
287195µs269µsmy $TwoLineHeader = qr/ ^
288 (
289 $HorizontalWS*
290 \S # must have some non-ws
291 .+ # anything else
292 \n
293 )
294 ^(=+|-+) # underline marking a header
295 \n
296 /xm;
297
298sub _match_two_line_header {
299 my $self = shift;
300 my $text = shift;
301
302 return unless ${$text} =~ / \G
303 (?:$EmptyLines)?
304 ($TwoLineHeader)
305 /xmgc;
306
307 my $level = substr( $3, 0, 1 ) eq '=' ? 1 : 2;
308
309 $self->_debug_parse_result(
310 $1,
311 'two-line header',
312 [ level => $level ],
313 ) if $self->debug();
314
315 $self->_header( $level, $2 );
316
317 return 1;
318}
319
320sub _header {
321 my $self = shift;
322 my $level = shift;
323 my $text = shift;
324
325 $self->_send_event( StartHeader => level => $level );
326
327 $self->_span_parser()->parse_block($text);
328
329 $self->_send_event( EndHeader => level => $level );
330
331 return 1;
332}
333
334121µs17µsmy $HorizontalRule = qr/ ^
335 (
336 \p{SpaceSeparator}{0,3}
337 (?:
338 (?: \* \p{SpaceSeparator}? ){3,}
339 |
340 (?: - \p{SpaceSeparator}? ){3,}
341 |
342 (?: _ \p{SpaceSeparator}? ){3,}
343 )
344 \n
345 )
346 /xm;
347
348sub _match_horizontal_rule {
349 my $self = shift;
350 my $text = shift;
351
352 return unless ${$text} =~ / \G
353 (?:$EmptyLines)?
354 $HorizontalRule
355 /xmgc;
356
357 $self->_debug_parse_result(
358 $1,
359 'horizontal rule',
360 ) if $self->debug();
361
362 $self->_send_event('HorizontalRule');
363
364 return 1;
365}
366
367sub _match_blockquote {
368 my $self = shift;
369 my $text = shift;
370
371 return unless ${$text} =~ / \G
372 $BlockStart
373 (
374 ^
375 >
376 $HorizontalWS*
377 \S
378 (?:
379 .*
380 \n
381 )+?
382 )
383 (?=
384 $EmptyLine # ... an empty line
385 ^
386 (?=
387 \S # ... followed by content in column 1
388 )
389 (?! # ... which is not
390 > # ... a blockquote
391 $HorizontalWS*
392 \S
393 )
394 |
395 \s* # or end of the document
396 \z
397 )
398 /xmgc;
399
400 my $bq = $1;
401
402 $self->_debug_parse_result(
403 $bq,
404 'blockquote',
405 ) if $self->debug();
406
407
408 $self->_send_event('StartBlockquote');
409
410 $bq =~ s/^>(?: \p{SpaceSeparator} | \t )?//gxm;
411
412 # Even if the blockquote is inside a list, we want to look for paragraphs,
413 # not list items.
414 my $list_level = $self->_list_level();
415 $self->_set_list_level(0);
416
417 # Dingus treats a new blockquote level as starting a new paragraph as
418 # well. If we treat each change of blockquote level as starting a new
419 # sub-document, we get the same behavior.
420 for my $chunk (
421 $self->_split_chunks_on_regex( $bq, qr/^>(?: \p{SpaceSeparator} | \t )*\S/xm ) ) {
422
423 $self->_parse_text( \$chunk );
424 }
425
426 $self->_set_list_level($list_level);
427
428 $self->_send_event('EndBlockquote');
429
430 return 1;
431}
432
433191µs265µsmy $PreLine = qr/ ^
434 (?:
435 \p{spaceSeparator}{4,}
436 |
437 \t
438 )
439 $HorizontalWS*
440 \S
441 .*
442 \n
443 /xm;
444
445sub _match_preformatted {
446 my $self = shift;
447 my $text = shift;
448
449 return unless ${$text} =~ / \G
450 $BlockStart
451 (
452 (?:
453 $PreLine
454 (?:$EmptyLine)*
455 )*
456 $PreLine
457 )
458 /xmgc;
459
460 my $pre = $1;
461
462 $self->_debug_parse_result(
463 $pre,
464 'preformatted',
465 ) if $self->debug();
466
467 $pre =~ s/^(?:\p{SpaceSeparator}{4}|\t)//gm;
468
469 $self->_detab_text(\$pre);
470
471 $self->_send_event( Preformatted => text => $pre );
472
473 return 1;
474}
475
476195µs269µsmy $Bullet = qr/ (?:
477 \p{SpaceSeparator}{0,3}
478 (
479 [\+\*\-] # unordered list bullet
480 |
481 \d+\. # ordered list number
482 )
483 )
484 $HorizontalWS+
485 /xm;
486
487sub _list_re {
488 my $self = shift;
489
490 my $block_start;
491
492 if ( $self->_list_level() ) {
493 $block_start = qr/(?: (?<= \n ) | $EmptyLines )/xm;
494 }
495 else {
496 $block_start = qr/ $BlockStart /xm;
497 }
498
499 my $list = qr/ $block_start
500 (
501 $Bullet
502 (?: .* \n )+?
503 )
504 /xm;
505
506 return $list;
507}
508
509sub _match_list {
510 my $self = shift;
511 my $text = shift;
512
513 my $list_re = $self->_list_re();
514
515 return unless ${$text} =~ / \G
516 $list_re
517 (?= # list ends with
518 $EmptyLine # ... an empty line
519 (?:
520 (?=
521 $HorizontalRule # ... followed by a horizontal rule
522 )
523 |
524 (?=
525 \S # ... or followed by content in column 1
526 )
527 (?! # ... which is not
528 $Bullet # ... a bullet
529 )
530 )
531 |
532 \s* # or end of the document
533 \z
534 )
535 /xmgc;
536
537 my $list = $1;
538 my $bullet = $2;
539
540 my $type = $bullet =~ /\d/ ? 'OrderedList' : 'UnorderedList';
541
542 $self->_debug_parse_result(
543 $list,
544 $type,
545 ) if $self->debug();
546
547 $self->_send_event( 'Start' . $type );
548
549 $self->_inc_list_level();
550
551 my @items = $self->_split_list_items($list);
552
553 for my $item (@items) {
554 $self->_send_event('StartListItem');
555
556 $item =~ s/^ (?: $Bullet | \p{SpaceSeparator}{4} | \t )//xgm;
557
558 $self->_print_debug( "Parsing list item for blocks:\n[$item]\n" )
559 if $self->debug();
560
561 # This is a hack to ensure that the last item in a loose list (each
562 # item is a paragraph) also is treated as a paragraph, not just a list
563 # item.
564 if ( $item eq $items[-1] ) {
565 if ( @items > 1
566 && $items[-2] =~ /^$EmptyLine\z/m ) {
567
568 $self->_print_debug(
569 "Treating last list item as a paragraph because previous item ends with empty line\n"
570 ) if $self->debug();
571
572 $self->_treat_list_item_as_paragraph();
573 }
574 else {
575 $self->_treat_list_item_as_line();
576 }
577 }
578 elsif ( $item =~ /^$EmptyLine\z/m ) {
579 $self->_print_debug("Treating item as a paragraph because it ends with empty line\n")
580 if $self->debug();
581
582 $self->_treat_list_item_as_paragraph();
583 }
584 else {
585 $self->_treat_list_item_as_line();
586 }
587
588 $self->_parse_text( \$item );
589
590 $self->_send_event('EndListItem');
591 }
592
593 $self->_dec_list_level();
594
595 $self->_send_event( 'End' . $type );
596
597 return 1;
598}
599
600sub _split_list_items {
601 my $self = shift;
602 my $list = shift;
603
604 my @items;
605 my @chunk;
606
607 for my $line ( split /\n/, $list ) {
608 if ( $line =~ /^$Bullet/ && @chunk ) {
609 push @items, join q{}, map { $_ . "\n" } @chunk;
610
611 @chunk = ();
612 }
613
614 push @chunk, $line;
615 }
616
617 push @items, join q{}, map { $_ . "\n" } @chunk
618 if @chunk;
619
620 return @items;
621}
622
623# A list item matches multiple lines of text without any separating
624# newlines. These lines stop when we see a blockquote or indented list
625# bullet. This match is only done inside a list, and lets us distinguish
626# between list items which contain paragraphs and those which don't.
627sub _match_list_item {
628 my $self = shift;
629 my $text = shift;
630
631 return unless ${$text} =~ / \G
632 ((?:
633 ^
634 \p{SpaceSeparator}*
635 \S
636 .*
637 \n
638 )+?)
639 (?=
640 ^
641 $Bullet
642 |
643 ^
644 > \p{SpaceSeparator}*
645 \S
646 .*
647 \n
648 |
649 \z
650 )
651 /xmgc;
652
653 $self->_debug_parse_result(
654 $1,
655 'list_item',
656 ) if $self->debug();
657
658 $self->_send_event('StartParagraph')
659 if $self->_list_item_is_paragraph();
660
661 $self->_span_parser()->parse_block($1);
662
663 $self->_send_event('EndParagraph')
664 if $self->_list_item_is_paragraph();
665
666 return 1;
667}
668
669sub _match_paragraph {
670 my $self = shift;
671 my $text = shift;
672
673 my $list_re = $self->_list_re();
674
675 # At this point anything that is not an empty line must be a paragraph.
676 return unless ${$text} =~ / \G
677 (?:$EmptyLines)?
678 ((?:
679 ^
680 \p{SpaceSeparator}*
681 \S
682 .*
683 \n
684 )+?)
685 (?:
686 $BlockEnd
687 |
688 (?= $HorizontalRule )
689 |
690 (?= $TwoLineHeader )
691 |
692 (?= $AtxHeader )
693 |
694 (?= $list_re )
695 )
696 /xmgc;
697
698 $self->_debug_parse_result(
699 $1,
700 'paragraph',
701 ) if $self->debug();
702
703 $self->_send_event('StartParagraph');
704
705 $self->_span_parser()->parse_block($1);
706
707 $self->_send_event('EndParagraph');
708
709 return 1;
710}
711
712sub _split_chunks_on_regex {
713 my $self = shift;
714 my $text = shift;
715 my $regex = shift;
716
717 my @chunks;
718 my @chunk;
719 my $in_regex = 0;
720
721 for my $line ( split /\n/, $text ) {
722 my $new_chunk;
723
724 if ( $in_regex && $line !~ $regex ) {
725 $in_regex = 0;
726 $new_chunk = 1;
727 }
728 elsif ( $line =~ $regex && !$in_regex ) {
729 $in_regex = 1;
730 $new_chunk = 1;
731 }
732
733 if ($new_chunk) {
734 push @chunks, join q{}, map { $_ . "\n" } @chunk
735 if @chunk;
736 @chunk = ();
737 }
738
739 push @chunk, $line;
740 }
741
742 push @chunks, join q{}, map { $_ . "\n" } @chunk
743 if @chunk;
744
745 return @chunks;
746}
747
748125µs224.8ms__PACKAGE__->meta()->make_immutable();
# spent 24.7ms making 1 call to Class::MOP::Class::make_immutable # spent 119µs making 1 call to Markdent::Dialect::Standard::BlockParser::meta
749
7501190µs1;
751
752# ABSTRACT: Block parser for standard Markdown
753
- -
756=pod
757
- -
8081139µs133.1ms__END__
 
# spent 48µs within Markdent::Dialect::Standard::BlockParser::CORE:qr which was called 6 times, avg 8µs/call: # once (13µs+0s) by Markdent::Parser::BEGIN@10 at line 90 # once (7µs+0s) by Markdent::Parser::BEGIN@10 at line 334 # once (7µs+0s) by Markdent::Parser::BEGIN@10 at line 476 # once (7µs+0s) by Markdent::Parser::BEGIN@10 at line 433 # once (7µs+0s) by Markdent::Parser::BEGIN@10 at line 248 # once (7µs+0s) by Markdent::Parser::BEGIN@10 at line 287
sub Markdent::Dialect::Standard::BlockParser::CORE:qr; # opcode
# spent 284µs within Markdent::Dialect::Standard::BlockParser::CORE:regcomp which was called 4 times, avg 71µs/call: # once (103µs+0s) by Markdent::Parser::BEGIN@10 at line 248 # once (62µs+0s) by Markdent::Parser::BEGIN@10 at line 287 # once (62µs+0s) by Markdent::Parser::BEGIN@10 at line 476 # once (58µs+0s) by Markdent::Parser::BEGIN@10 at line 433
sub Markdent::Dialect::Standard::BlockParser::CORE:regcomp; # opcode