File Coverage

blib/lib/Perl6/Perldoc/Parser.pm
Criterion Covered Total %
statement 978 1197 81.7
branch 226 374 60.4
condition 137 176 77.8
subroutine 169 202 83.6
pod 1 1 100.0
total 1511 1950 77.4


line stmt bran cond sub pod time code
1             package Perl6::Perldoc::Parser;
2             #use Smart::Comments;
3 55     55   70236 use re 'eval';
  55         100  
  55         2484  
4              
5 55     55   302 use warnings;
  55         64  
  55         1379  
6 55     55   206 use strict;
  55         63  
  55         1410  
7              
8 55     55   25338 use version; our $VERSION = qv('0.0.6');
  55         89061  
  55         264  
9              
10             # Regexes the parser needs...
11             my $LDAB = qq{\x{AB}};
12             my $RDAB = qq{\x{BB}};
13             my $LDAB_CJK = qq{\x{300A}};
14             my $RDAB_CJK = qq{\x{300B}};
15             my $LEFT_ANGLE = qr{ < | $LDAB | $LDAB_CJK }x;
16             my $RIGHT_ANGLE = qr{ > | $RDAB | $RDAB_CJK }x;
17              
18             my $FAIL = q{(?!)};
19              
20             my $BLANK_LINE = q{^ \\s* $};
21              
22             my $IDENT = qr{ [^\W\d]\w* }xms;
23             my $QUAL_IDENT = qr{ (?: $IDENT ::)* $IDENT }xms;
24             my $P6_QUAL_IDENT = qr{ $QUAL_IDENT (?: -\S+ )}xms;
25              
26             my $DIR_NC # DIRective but Not a Comment
27             = qr{ (?= ^ = (?! \s | (?:(?:begin|end|for) [^\S\n]+)? comment\b ))}xms;
28              
29             my $DIR_COMMENT_BLOCK # DIRective that is a COMMENT BLOCK
30             = qr{ ^ =begin \s+ comment \b }xms;
31              
32              
33             our $BALANCED_BRACKETS;
34             $BALANCED_BRACKETS = qr{ < (?: (??{$BALANCED_BRACKETS}) | . )*? >
35             | \[ (?: (??{$BALANCED_BRACKETS}) | . )*? \]
36             | \{ (?: (??{$BALANCED_BRACKETS}) | . )*? \}
37             | \( (?: (??{$BALANCED_BRACKETS}) | . )*? \)
38             | $LEFT_ANGLE
39             (?: (??{$BALANCED_BRACKETS}) | . )*?
40             $RIGHT_ANGLE
41             }xms;
42              
43             my $OPTION = qr{ : $IDENT $BALANCED_BRACKETS? | : ! $IDENT }xms;
44             my $OPTION_EXTRACT = qr{ :()($IDENT)($BALANCED_BRACKETS?) | :(!)($IDENT)() }xms;
45              
46             my $OPTIONS = qr{ (?: \s* $OPTION)+ }xms;
47              
48             my $FORMATTING_CODE = q{[BCDEIKLMNPRSTUVXZ]};
49              
50             my $PERMITS_IMPLICIT
51             = qr{\A (?: pod | (?! DATA ) [[:upper:]]+ ) \z}xms;
52              
53             my $PERMITS_IMPLICIT_IF_DELIMITED
54             = qr{ $PERMITS_IMPLICIT | \A (?: item | nested ) \z}xms;
55              
56             # Error handlers (push error messages to the correct queue: warnings or errors)
57              
58             # Format location nicely...
59             sub _loc {
60 152     152   393 my ($range_ref) = @_;
61 152 50       605 return defined $range_ref->{file}
62             ? "$range_ref->{file} line $range_ref->{from}"
63             : "line $range_ref->{from}"
64             ;
65             }
66              
67             # Missing block terminators must be (at least) warned about...
68             sub _err_no_closing_delim {
69 291     291   347 my ($top, $errors_ref, $warnings_ref) = @_;
70              
71             # Paragraphed, parser-introduced, and magic blocks don't need terminators...
72 291 100 100     1416 return if $top->{is_blank_terminated}
      100        
73             || $top->{is_implicit}
74             || $top->{typename} =~ m{\A (?: \(ambient\) | list | DATA | END ) }xms;
75              
76 1         3 my $location = _loc( $top->{range} );
77 1 50       6 my $msg = 'No closing delimiter for '
78             . ( $top->{style} eq 'formatting'
79             ? "$top->{typename}$top->{left_delim}..."
80             : "'$top->{typename}' block"
81             )
82             . " opened at $location";
83              
84             # Only a fatal problem if the block is missing an =end...
85 1 50       4 if ($top->{style} eq 'delimited') {
86 1         2 push @{$errors_ref}, $msg;
  1         3  
87             }
88             else {
89 0         0 push @{$warnings_ref}, $msg;
  0         0  
90             }
91             }
92              
93             # Nothing except options allowed after the block declarator...
94             sub _err_trailing_junk {
95 1     1   2 my ($block_type, $range_ref, $junk, $errors_ref) = @_;
96 1         2 my $location = _loc($range_ref);
97              
98 1 50       2 push @{$errors_ref}, 'Trailing junk after '
  1         7  
99             . ( $block_type =~ /[ ]/
100             ? $block_type
101             : "'$block_type' block specifier"
102             )
103             . " at $location: $junk"
104             ;
105             }
106              
107             # All lowercase and uppercase block names are reserved...
108             sub _err_unknown_reserved_block {
109 1     1   2 my ($block, $errors_ref) = @_;
110 1         3 my $location = _loc($block->{range});
111              
112 1         2 push @{$errors_ref}, "Unknown reserved block type ('$block->{typename}') "
  1         4  
113             . " at $location"
114             ;
115             }
116              
117             # No extra option lines after the content starts...
118             sub _err_options_too_late {
119 1     1   2 my ($top, $range_ref, $warnings_ref) = @_;
120 1         2 my $location = _loc($range_ref);
121            
122 1         1 push @{$warnings_ref}, 'Possible attempt to specify extra options '
  1         5  
123             . "too late in '$top->{typename}' block at $location";
124             }
125              
126             # Unexpected block terminators often mean an typo on the opener...
127             sub _err_closed_unopened_block {
128 1     1   8 my ($type, $range_ref, $errors_ref) = @_;
129 1         2 my $location = _loc($range_ref);
130              
131 1         2 push @{$errors_ref}, "Invalid '=end $type' (not in '$type' block) "
  1         4  
132             . "at $location";
133             }
134              
135             # A terminator on an END block is meaningless; report it...
136             sub _err_closed_END_block {
137 2     2   4 my ($range_ref, $warnings_ref) = @_;
138 2         4 my $location = _loc($range_ref);
139              
140 2         4 push @{$warnings_ref}, q{Ignored explicit '=end END' }
  2         8  
141             . q{(END blocks run to end-of-file) }
142             . qq{at $location}
143             ;
144             }
145              
146             # No =itemN unless there's a preceding =item(N-1)...
147             sub _err_missing_list_level {
148 2     2   4 my ($range_ref, $item_level, $errors_ref) = @_;
149 2         5 my $location = _loc($range_ref);
150              
151 2         3 push @{$errors_ref}, q{No =item} . ($item_level-1)
  2         13  
152             . qq{ before =item$item_level at $location};
153             }
154              
155              
156             # User-defined M<> code do have to be defined...
157             sub _err_missing_M_scheme {
158 1     1   2 my ($range_ref, $errors_ref) = @_;
159 1         2 my $location = _loc($range_ref);
160              
161 1         2 push @{$errors_ref}, q{Missing scheme specifier in M<> formatting code }
  1         3  
162             . qq{at $location};
163             }
164              
165             # Link and =use targets actually have to point somewhere real...
166             sub _err_bad_use_uri {
167 1     1   2 my ($uri, $range_ref, $errors_ref) = @_;
168 1         2 my $location = _loc($range_ref);
169              
170 1         1 push @{$errors_ref}, qq{Unable to open URI in '=use $uri' }
  1         5  
171             . qq{at $location};
172             }
173              
174             # =use targets must be loadable
175             sub _err_use_cant_load {
176 0     0   0 my ($source, $range_ref, $errors_ref) = @_;
177 0         0 my $location = _loc($range_ref);
178              
179 0         0 push @{$errors_ref}, qq{Unable to load module in '=use $source' }
  0         0  
180             . qq{at $location};
181             }
182              
183             # Various places need to add content to the top of the stack...
184             sub _add_content {
185 1043     1043   1620 my ($top, $content) = @_;
186              
187 1043 100 100     3508 if (!$top->{content} || ref $top->{content}[-1]) {
188 329         309 push @{ $top->{content} }, $content;
  329         954  
189             }
190             else {
191 714         1145 $top->{content}[-1] .= $content;
192             }
193             }
194              
195              
196             # Extract options in Perl 6 format...
197              
198             # Handled embedded quotes in <<>>
199             sub _shell_split {
200 0     0   0 my ($content) = @_;
201 0         0 my @components;
202 0         0 pos $content = 0;
203 0         0 while (pos $content < length $content) {
204 0         0 $content =~ m{ \G \s*
205             (?: " ( [^"\\]* (?: \\. [^"\\]* )* ) "
206             | ' ( [^'\\]* (?: \\. [^'\\]* )* ) '
207             | ( \S+ )
208             )
209             \s*
210             }gcxms;
211 0         0 push @components, $+;
212             }
213 0         0 return @components;
214             }
215              
216             # Parse and convert Perl 6 style :key(value) and key=>value pairs...
217             sub _extract_options {
218 71     71   109 my ($options) = @_;
219              
220 71 100       288 return {} if $options !~ /\S/;
221              
222 47         2787 my @components = grep { defined } $options =~ m{ $OPTION_EXTRACT }ogxms;
  300         766  
223              
224 47         160 my %options;
225 47         245 while (my ($neg, $key, $val) = splice @components, 0, 3) {
226 50 0       972 $options{$key} = $neg ? 0
    50          
    50          
    50          
    100          
    100          
    100          
227             : !length $val ? 1
228             : $val =~ /^ \((.*)\) $/xms ? eval($1)
229             : $val =~ /^(\[ .* \])$/xms ? eval($1)
230             : $val =~ /^(\{ .* \})$/xms ? eval($1)
231             : $val =~ /^ \<\s*(.*?)\s*\> $/xms ? [split /\s+/, $1]
232             : $val =~ /^ $LEFT_ANGLE\s*(.*?)\s*$RIGHT_ANGLE $/xms
233             ? [_shell_split($1)]
234             : die "Internal error"
235             ;
236             }
237              
238 47         165 return \%options;
239             }
240              
241              
242             # Track hierarchical counters for numbered blocks...
243             sub _next_number_for {
244 46     46   64 my ($type, $depth, $disjoint, $state_ref) = @_;
245              
246             # Retrieve (or create) counter for this block type...
247 46   100     170 my $numbers = $state_ref->{numberer_for}{$type} ||= [];
248              
249             # Reset top-level item if disjoint from previous items...
250 46 50 66     151 if ($disjoint && $depth == 1 && $type eq 'item') {
      66        
251 8         13 @{$numbers} = (0);
  8         21  
252             }
253              
254             # Update according to relative depth...
255 46 100       47 if ($depth > @{$numbers}) { # nesting increased -> extend
  46 100       118  
  33         65  
256 13         14 push @{$numbers}, (1) x ($depth-@{$numbers});
  13         23  
  13         29  
257             }
258             elsif ($depth == @{$numbers}) { # nesting stays at same level
259 30         37 $numbers->[-1]++;
260             }
261             else { # nesting decreased -> truncate
262 3         14 @{$numbers} = @{$numbers}[0..$depth-1];
  3         10  
  3         7  
263 3         6 $numbers->[-1]++;
264             }
265            
266 46         50 return join '.', @{$numbers};
  46         137  
267             }
268              
269             # Handle block numbering and formatting...
270             sub _resolve_numbering {
271 577     577   577 my ($data, $state_ref) = @_;
272              
273             # Handle :numbered set-up
274 577 100       2277 if ($data->{typename} =~ m{\A (\w+?)(\d*) \Z}xms) {
275 450   100     1688 my ($type, $depth) = ($1, $2||1);
276 450         633 my $content_ref = \($data->{content}[0]);
277              
278             # Is this block explicitly numbered?
279 450         687 my $explicitly_numbered = $data->{options}{numbered};
280 450 100       910 if (!defined $explicitly_numbered) {
281 430         572 $explicitly_numbered = $data->{config}{numbered};
282             }
283            
284             # Otherwise, two types of block support implicit (#) numbering...
285             my $implicitly_numbered
286             = ($type eq 'head' || $type eq 'item')
287             && !defined($explicitly_numbered)
288             && !ref(${$content_ref})
289             && defined ${$content_ref}
290 450   100     2009 && ${$content_ref} =~ m{ \A \s* [#] [^\S\n]+ }xms
291             ;
292              
293             # Number if necessary...
294 450 100 100     1539 if ($explicitly_numbered || $implicitly_numbered) {
295             # Clean up the magic leading # if present...
296 46 100       81 if ($implicitly_numbered) {
297 23         24 ${$content_ref} =~ s{\A \s* [#] [^\S\n]+ }{}xms
  23         67  
298             }
299 46   66     172 my $disjoint = $data->{disjoint}
300             && !$data->{options}{continued}
301             && !$data->{config}{continued};
302 46         92 $data->{number}
303             = _next_number_for($type, $depth, $disjoint, $state_ref);
304             }
305             }
306              
307             # Recurse to process contents...
308 577         504 for my $subtree ( @{ $data->{content} } ) {
  577         861  
309 798 100       1733 next if !ref $subtree;
310 450         1005 _resolve_numbering($subtree, $state_ref);
311             }
312             }
313              
314              
315             # Create object tree from hash tree...
316             my $head_max = 4; # Maximum predefined =headN block
317              
318             sub _create_objects {
319 577     577   528 my ($tree, $state_ref) = @_; # $state_ref tracks global numbering, etc.
320              
321             # Recursively create subtrees first...
322 577 50       440 for my $subtree ( @{ $tree->{content} || [] }) {
  577         1257  
323 798 100       1492 if (ref $subtree) {
324 450         1221 $subtree = _create_objects($subtree, $state_ref);
325             }
326             }
327              
328             # Translate block names to class names, tracking reserved blocks...
329 577         542 my $is_reserved;
330 577         541 my $classname = 'Perl6::Perldoc::';
331 577         643 my $typename = $tree->{typename};
332              
333             # Parenthesized name -> parser introduced (so its given its own name)
334 577 100 100     2680 if ($typename =~ m{^\( (\w+) \)}xms) {
    100          
    100          
    100          
335 127         380 $classname .= "\u$1";
336             }
337             # Formatting codes are all subclasses of FormattingCode...
338             elsif ($tree->{style} eq 'formatting') {
339 66         129 $classname .= "FormattingCode::$typename";
340             }
341             # Directives are all subclasses of Directive...
342             elsif ($tree->{style} eq 'directive') {
343 9         18 $classname .= "Directive::$typename";
344             }
345             # Mixed-class block names -> user-defined subclass of Named...
346             elsif ($typename =~ m{[[:upper:]]}xms && $typename =~ m{[[:lower:]]}xms) {
347 7         19 $classname .= "Block::Named::$tree->{typename}";
348 55     55   124890 no strict 'refs';
  55         98  
  55         7428  
349 7         9 push @{$classname.'::ISA'}, 'Perl6::Perldoc::Block::Named';
  7         106  
350             }
351             # All upper or all lower case -> reserved block
352             else {
353 368         714 $tree->{is_semantic} = $typename =~ m{[[:upper:]]}xms;
354 368         563 $is_reserved = $typename !~ m{\A (?:head|item) \d+ \z }xms;
355 368         631 $classname .= "Block::$tree->{typename}";
356              
357             # Any non-existent headN classes inherit last defined headN class...
358 368 100       1253 if ($classname =~ m{:: head (\d+) \z}xms) {
    100          
359 36         49 my $head_level = $1;
360 36         50 $tree->{level} = $head_level;
361 36 100       76 if ($head_level > $head_max) {
362 55     55   261 no strict 'refs';
  55         75  
  55         5166  
363 3         5 @{ 'Perl6::Perldoc::Block::head'.$head_level.'::ISA' }
  3         41  
364             = 'Perl6::Perldoc::Block::head'.$head_max;
365             }
366             }
367              
368             # Any non-existent itemN classes act like existent itemN classes...
369             elsif ($classname =~ m{:: item (\d+) \z}xms) {
370 30   50     85 my $item_level = $1 || 1;
371 30         55 $tree->{level} = $item_level;
372              
373 55     55   274 no strict 'refs';
  55         77  
  55         308648  
374 30         30 @{ 'Perl6::Perldoc::Block::item'.$item_level.'::ISA' }
  30         370  
375             = 'Perl6::Perldoc::Block::item';
376             }
377             }
378              
379             # Construct corresponding object if possible...
380 577 100       6084 return $classname->new($tree, { errors=>$state_ref->{errors}, })
381             if $classname->can('new');
382              
383             # If a built-in but no constructor, must be unknown...
384 1 50       2 if ($is_reserved) {
385 1         4 _err_unknown_reserved_block($tree, $state_ref->{errors});
386             }
387              
388             # Otherwise, bless the raw data itself as an object...
389 1         8 return bless $tree, $classname;
390             }
391              
392             # Create a new config frame for a =config directive...
393             sub _extend_config {
394 9     9   13 my ($curr_config_ref, $target_block, $new_opts_ref) = @_;
395              
396             # Default new config to copy of old config...
397 9         12 my %config = %{$curr_config_ref};
  9         25  
398              
399             # Default new target block in config to copy of old target block...
400 0         0 $config{$target_block}
401 9 50       30 = $config{$target_block} ? {%{$config{$target_block}}} : {};
402              
403             # Change basis of target if :like specified
404 9         12 my $likeness = $new_opts_ref->{like};
405 9 100       26 if ($likeness) {
406 1 50       4 for my $alike (ref $likeness eq 'ARRAY' ? reverse @{$likeness} : $likeness) {
  1         2  
407 1         2 my $like_config_ref = $curr_config_ref->{$alike};
408 1         1 for my $option (keys %{$like_config_ref}) {
  1         7  
409 1 50       2 unshift @{ $config{$target_block}{$option} },
  1         6  
410 1         1 @{$curr_config_ref->{$alike}{$option}||[]};
411             }
412             }
413             }
414              
415             # Update all keys of target that appear in new options...
416 9         9 for my $opt (keys %{$new_opts_ref}) {
  9         23  
417 10 100       30 next if $opt eq 'like';
418              
419 9         16 my $old_type = ref $config{$target_block}{$opt};
420 9         14 my $new_type = ref $new_opts_ref->{$opt};
421              
422 9 100       20 if (!$old_type) {
    50          
    50          
    0          
423 8         22 $config{$target_block}{$opt} = $new_opts_ref->{$opt};
424             }
425             elsif ($old_type ne $new_type) {
426 0         0 die "Internal error: type mismatch on :$opt ($old_type vs $new_type)";
427             }
428             elsif ($old_type eq 'ARRAY') {
429 1         2 $config{$target_block}{$opt}
430 1         1 = [@{$config{$target_block}{$opt}}, @{$new_opts_ref->{$opt}}];
  1         3  
431             }
432             elsif ($old_type eq 'HASH') {
433 0         0 $config{$target_block}{$opt}
434 0         0 = { %{$config{$target_block}{$opt}}, %{$new_opts_ref->{$opt}}};
  0         0  
435             }
436             else {
437 0         0 die "Internal error: bad :$opt of type $new_type";
438             }
439             }
440              
441 9         19 return \%config;
442             }
443              
444             # Open or close implicit list blocks around item blocks
445              
446             sub _adjust_lists {
447 1395     1395   2030 my ($stack_ref, $line, $is_item, $is_comment,
448             $item_level, $range_ref, $warnings_ref) = @_;
449              
450 1395         1433 my $parent_ref = $stack_ref->[-1];
451              
452             # Ignore blank lines and comments...
453 1395 100 100     7251 return $parent_ref if $line !~ m{\S}xms || $is_comment;
454              
455             # Are we there yet?
456 1320         1797 my $is_in_list = $parent_ref->{typename} eq 'list';
457 1320   100     3364 my $list_level = $parent_ref->{level} || 0;
458              
459             # Ignore non-transition points...
460 1320 100 100     6446 return $parent_ref
      100        
      100        
      66        
461             if !$is_in_list && !$is_item
462             || $is_in_list && $is_item && $list_level == $item_level;
463              
464             # Detect missing items...
465 24 100       260 if ($list_level < $item_level-1) {
466 2         8 _err_missing_list_level($range_ref, $item_level, $warnings_ref);
467             }
468              
469             # Add required number of additional implicit lists...
470 24         32 my %range = %{ $range_ref };
  24         102  
471 24         77 while ($list_level < $item_level) {
472 22         24 $list_level++;
473 22         24 push @{$stack_ref}, {
  22         379  
474             typename => 'list',
475             style => 'implicit',
476             range => \%range,
477             level => $list_level,
478             # terminator => $FAIL,
479             terminator => qr{ (?= $parent_ref->{terminator} ) }xms,
480             allow => $parent_ref->{allow},
481             };
482             }
483              
484             # Alternatively, close required number of nested lists...
485 24         70 while ($list_level > $item_level) {
486 4         8 my $list_block = pop @{$stack_ref};
  4         7  
487 4         15 $list_block->{range}{to} = $range{from}-1;
488 4         8 push @{ $stack_ref->[-1]{content} }, $list_block;
  4         12  
489 4         11 $list_level--;
490             }
491              
492 24         73 return $stack_ref->[-1];
493             }
494              
495             # Handle :like option (effectively prepending other defn to options)...
496             sub _handle_likeness {
497 150     150   187 my ($top_ref, $config_ref) = @_;
498              
499 150 100       161 my %options = %{ $top_ref->{options} || {} };
  150         707  
500 150 100       440 if ( my $like = $options{like} ) {
501 1 50 50     5 my @likenesses = (ref($like)||q{}) eq 'ARRAY' ? @{ $like } : $like;
  1         3  
502              
503 1         2 for my $likeness (reverse @likenesses) {
504 1 50       6 %options = (
505 1         1 %{ $config_ref->{$likeness} || {} },
506             %options,
507             );
508             }
509             }
510              
511 150         357 return \%options;
512             }
513              
514              
515             # Handle any :formatted() options by imposing extra levels on stack...
516             sub _handle_formatted {
517 141     141   187 my ($top, $range_ref, $config_ref, $errors_ref) = @_;
518 141         305 my $location = _loc($range_ref);
519              
520             # Locate formatted options (on block itself or in block type's config)...
521 141   100     700 my $formatted = $top->{options}{formatted}
522             || $config_ref->{$top->{typename}}{formatted};
523 141 100       367 return if !$formatted;
524              
525             # Bad option! No biscuit!
526 3 50 50     11 if ((ref($formatted)||q{}) ne 'ARRAY') {
527 0         0 push @{$errors_ref},
  0         0  
528             qq{Value of :formatted option not an array at $location};
529 0         0 return;
530             }
531              
532 3         12 my $terminator = "(?=$top->{terminator})";
533 3         4 my $verbatim = $top->{is_verbatim};
534              
535 3         5 my $permits_implicit_blocks = $top->{permits_implicit_blocks};
536              
537             # Work through specified formatting codes, adding nested block for each...
538 3         3 my @blocks;
539 3         3 my %range = %{$range_ref};
  3         9  
540 3         5 FCODE:
541 3         5 for my $fcode (@{ $formatted }) {
542 5 50       33 if ($fcode !~ $FORMATTING_CODE) {
543 0         0 push @{$errors_ref},
  0         0  
544             qq{Unknown formatting code ($fcode) in :formatted option at $location};
545 0         0 next FCODE;
546             }
547 5   33     17 $verbatim ||= $fcode =~ m{[VCMP]}xms;
548 5         34 push @blocks, {
549             typename => $fcode,
550             style => 'formatting',
551             config => $config_ref->{"$fcode<>"},
552             range => \%range,
553             initiator => '(?!)',
554             terminator => $terminator,
555             left_delim => q{},
556             right_delim => q{},
557             is_verbatim => $verbatim,
558             is_implicit => 1,
559             permits_implicit_blocks => $permits_implicit_blocks,
560             };
561             }
562 3         8 return @blocks;
563             }
564              
565             # Track which nested formatting codes are allowed for a given block...
566             sub _update_allow {
567 434     434   572 my ($top, $config, $options) = @_;
568 434 100       401 my %new_allow = %{ $top->{allow} || {} };
  434         1618  
569              
570             # If not explicit on block, try config...
571 434 100 100     1791 if (my $src_ref = $options->{allow} || $config->{allow}) {
572 10 50       25 if (ref $src_ref eq 'ARRAY') {
573 10         11 @new_allow{ @{$src_ref} } = ();
  10         22  
574             }
575             else {
576 0         0 $new_allow{ $src_ref } = undef;
577             }
578             }
579              
580 434         1131 return \%new_allow;
581             }
582              
583              
584             # Parse input from a filehandle or filename, extracting the Pod...
585             sub parse {
586 128     128 1 67630 my ($classname, $filehandle, $opt_ref) = @_;
587 128         256 my $filename = $opt_ref->{filename};
588              
589             # Reset the id generator if asked to
590 128 50       380 Perl6::Perldoc::Root::_reset_id() if $opt_ref->{reset_id};
591              
592             # If filename passed, open it...
593 128 100       553 if (!ref $filehandle) {
    100          
594 1         3 $filename = $filehandle;
595 1         1 undef $filehandle;
596 1 50 33     204 open $filehandle, '<', $filename
597             or require Carp
598             and Carp::croak("parse() can't open file $filename ($!)");
599              
600 0 0 0     0 if (!exists $opt_ref->{all_pod} || $opt_ref->{all_pod} =~ m{\A auto \z}ixms) {
601 0         0 $opt_ref->{all_pod} = $filename =~ m{ [.] pod6? }xms;
602             }
603             }
604              
605             # If a reference to a scalar is passed, convert it to a filehandle...
606             elsif (ref($filehandle) eq 'SCALAR') {
607 1         2 my $data_source = $filehandle;
608 1         2 undef $filehandle;
609 1 50 0 1   26 open $filehandle, '<', $data_source
  1         6  
  1         2  
  1         6  
610             or require Carp
611             and Carp::croak("parse() can't parse from string ($!)");
612             }
613              
614             # Remember where we found this data...
615 127         1181 my %range = ( file=>$filename, from => 0 );
616              
617             # Initialize stack representation of Pod...
618 127         667 my @stack = {
619             typename => '(document)',
620             terminator => $FAIL,
621             range => {%range},
622             };
623              
624             # Initialize configuration stack to track lexical =config directives
625 127   100     666 my @config_stack = $opt_ref->{config_stack} || {};
626              
627             # Track P requests...
628 127         167 my @toc_placements;
629              
630             # Add implicit =pod block if caller indicates it's all pod...
631 127 100       313 if ($opt_ref->{all_pod}) {
632 116         700 push @stack, {
633             typename => 'pod',
634             style => 'implicit',
635             config => {},
636             range => { %range },
637             terminator => $FAIL,
638             is_implicit => 1,
639             permits_implicit_blocks => 1,
640             };
641             }
642              
643             # Initialize look-up table of allowed formatting codes...
644 127   50     565 $stack[-1]{allow} = _update_allow($opt_ref||{},{},{});
645              
646             # Storage for reporting problems...
647 127         190 my (@errors, @warnings);
648              
649             # Is a block with options waiting for possible extra options?
650 0         0 my $has_options_pending;
651              
652              
653             # Parse input line-by-line...
654             LINE:
655 127         544 while (my $line = <$filehandle>) {
656 582         1169 pos $line = 0;
657 582         1057 $range{from} = $.;
658 582         943 my $is_directive = substr($line, 0, 1) eq '=';
659              
660             # Within line, parse out each token...
661             TOKEN:
662 582         1127 while (pos $line < length $line) {
663             ### AT: substr($line, pos $line)
664 1656         1503 my $top = $stack[-1];
665              
666             # Check and process options pending...
667 1656 100       2399 if ($has_options_pending) {
668             # Extra options on a line immediately after a block specifier...
669 71 100       3881 if ($line =~ m{ \G ^ = (\s+ $OPTIONS) \s* $ }ogcxms) {
670 2         7 my $options = $1;
671              
672 2         8 $top->{options} =
673 2         6 { %{ $top->{options} },
674 2         3 %{ _extract_options($options) },
675             };
676              
677             ### Adding more options: $stack[-1]
678 2         16 next LINE;
679             }
680              
681             # No extra options, then handle :like, :formatted options...
682             else {
683 69         104 my $config_ref = $config_stack[-1];
684 69         195 $top->{options} = _handle_likeness($top, $config_ref);
685              
686 69 100       412 if ($top->{style} =~ m{\A (?:delimited|paragraph) \z}xms) {
687 60         184 push @stack, _handle_formatted(
688             $top, \%range, $config_ref, \@errors
689             );
690             }
691 69         94 $has_options_pending = 0;
692              
693 69         222 $top->{allow}
694             = _update_allow( $stack[-2],
695             $config_ref->{$top->{typename}},
696             $top->{options}
697             );
698             }
699             }
700              
701             # A close marker for the innermost block or formatting code...
702 1654 100       23646 if ($line =~ m{ \G ($top->{terminator}) }gcxms) {
703 248         399 my $terminator = $1;
704              
705             # Is this an implicit close (i.e. an outer block closing)?
706 248 100       548 if (length($terminator) == 0) {
707 85         227 _err_no_closing_delim($top, \@errors, \@warnings);
708 85         163 pos $line = pos $line; # Workaround for bug in /gc :-(
709             }
710              
711             # Is this a nested close marker in a formatting code?
712 248 100 100     897 if ($top->{style} eq 'formatting' && $top->{delim_nesting}) {
713             # If so, decrease the nesting and treat as plain content...
714 7         9 $top->{delim_nesting}--;
715 7         11 _add_content($top, $terminator);
716             ### Added nested formatting code terminator
717             }
718             # If not nested formatting code delimiter, close the block...
719             else {
720 241         307 my $block = pop @stack;
721              
722             # Ignore attempts to terminate an END block...
723 241 100       500 if ($block->{typename} eq 'END') {
724 1         1 push @stack, $block;
725 1         8 next TOKEN;
726             }
727              
728             # Execute any use statement...
729 240 50       643 if ($block->{typename} eq '(use)') {
730 0         0 my $source = $block->{source};
731 0 0       0 if (eval "require $source") {
732 0 0       0 my %options = (
733 0 0       0 %{ $block->{config}{use}||{} },
734 0         0 %{ $block->{options} || {} },
735             );
736 0         0 $source->import(\%options);
737             }
738             else {
739 0         0 _err_use_cant_load($source, \%range, \@errors);
740 0         0 next TOKEN;
741             }
742             }
743              
744             # Syncronize config stack...
745 240   50     1164 for (1..$block->{has_config}||0) {
746 0         0 pop @config_stack;
747             }
748            
749             # Incorporate closed block into representation...
750 240 50 66     722 if ($block->{style} ne 'implicit' || $block->{content}) {
751             # Complete line range...
752 240         455 $block->{range}{to} = $range{from};
753              
754             # Remove parser-specific internal data...
755 240         254 delete @{$block}{qw};
  240         801  
756              
757             # Add block to parent...
758 240         228 push @{ $stack[-1]{content} }, $block;
  240         532  
759            
760             ### Terminated block: $block
761             }
762             else {
763             ### Threw away empty implicit block: $block
764             }
765             }
766 247         851 next TOKEN;
767             }
768              
769             # Content of comments is appended raw...
770 1406 100 100     3330 if ($top->{typename} eq 'comment' && $line !~ $DIR_COMMENT_BLOCK) {
771 7 100 100     26 if (!$top->{content} || ref $top->{content}[-1]) {
772 6         6 push @{ $top->{content} }, $line;
  6         20  
773             }
774             else {
775 1         3 $top->{content}[-1] .= $line;
776             }
777 7         29 next LINE;
778             }
779              
780             # All directives start with '=' on the line...
781 1399 100       1989 if ($is_directive) {
782             # Unexpected close marker for unopened block...
783 156 100       457 if ($line =~ m{\G ^ =end \s+ (\S+) }gcxms) {
784 3         6 my $type = $1;
785 3 100       8 if ($type eq 'END') {
786 2         8 _err_closed_END_block(\%range, \@warnings);
787             }
788             else {
789 1         3 _err_closed_unopened_block($type, \%range, \@errors);
790             }
791              
792             ### Unexpected =end $type: $line
793 3         17 next LINE;
794             }
795              
796             # Open marker for delimited block...
797 153 100       7408 if ($line =~ m{\G ^ =begin \s+ ($IDENT) ($OPTIONS?) \s* (.*) $}ogcxms) {
798 35         158 my ($type, $options, $junk) = ($1, $2, $3);
799              
800             # Anything after last option is junk...
801 35 50       92 if ($junk) {
802 0         0 _err_trailing_junk($type, \%range, $junk, \@errors);
803             }
804              
805             # Track level of =item blocks...
806 35         98 my ($is_item, $item_level)
807             = $type =~ m{\A (item)(\d+)? \Z}xms;
808 35 100 100     239 $item_level ||= $is_item ? 1 : 0;
809              
810 35         70 my $is_comment = $type eq 'comment';
811              
812             # Insert or close implicit list block if required...
813 35         143 $top = _adjust_lists(\@stack, $line, $is_item,
814             $is_comment, $item_level,
815             \%range, \@warnings
816             );
817 35   100     836 my $disjoint_item1
818             = $is_item && $item_level==1 && !$top->{content};
819              
820 35         223 my $permits_implicit_blocks
821             = $type =~ m{$PERMITS_IMPLICIT_IF_DELIMITED}xms;
822              
823 35         55 $has_options_pending = 1;
824              
825             # Terminator is corresponding =end or parent's terminator...
826 35 100       889 my $terminator
827             = $type eq 'END' ? '(?!)'
828             : qr{^ =end \s+ \Q$type\E [^\n]* \n? $
829             | (?= $top->{terminator} )
830             }xms
831             ;
832              
833 35         134 $options = _extract_options($options);
834              
835 35         96 my $config = $config_stack[-1]{$type};
836             my @config_stack_entry
837 35 100       103 = $type eq 'table' ? (config_stack=>$config_stack[-1])
838             : ();
839              
840 35         63 my $verbatim = $type eq 'code';
841              
842             # Add to parsing stack (not yet in tree)...
843 35   100     461 push @stack, {
844             typename => $type,
845             style => 'delimited',
846             range => { %range },
847             options => $options,
848             config => $config,
849             @config_stack_entry,
850             terminator => $terminator,
851             is_verbatim => $verbatim || $top->{is_verbatim},
852             disjoint => $disjoint_item1,
853             permits_implicit_blocks => $permits_implicit_blocks,
854             };
855              
856             ### Opened delimited block: $stack[-1]
857 35         297 next TOKEN;
858             }
859              
860             # Open marker for paragraph block...
861 118 100       4382 if ($line =~ m{ \G ^ =for \s+ ($IDENT) ($OPTIONS?) \s* (.*) $ }ogcxms) {
862 25         97 my ($type, $options, $junk) = ($1, $2, $3);
863              
864             # Anything after last option is junk...
865 25 100       80 if ($junk) {
866 1         4 _err_trailing_junk($type, \%range, $junk, \@errors);
867             }
868              
869 25         149 my $permits_implicit_blocks
870             = $type =~ m{$PERMITS_IMPLICIT}xms;
871              
872             # Track level of =item blocks...
873 25         84 my ($is_item, $item_level)
874             = $type =~ m{\A (item)(\d+)? \Z}xms;
875 25 100 100     112 $item_level ||= $is_item ? 1 : 0;
876            
877 25         28 $has_options_pending = 1;
878              
879 25         66 my $is_comment = $type eq 'comment';
880              
881             # Insert or close implicit list block if required...
882 25         92 $top = _adjust_lists(\@stack, $line, $is_item,
883             $is_comment, $item_level,
884             \%range, \@warnings
885             );
886              
887 25   100     151 my $disjoint_item1
888             = $is_item && $item_level==1 && !$top->{content};
889              
890 25         40 my $verbatim = $type eq 'code';
891              
892 25         60 $options = _extract_options($options);
893 25         55 my $config = $config_stack[-1]{$type};
894             my @config_stack_entry
895 25 100       65 = $type eq 'table' ? (config_stack=>$config_stack[-1])
896             : ();
897              
898             # Add to parsing stack (not yet in tree)...
899 25   33     872 push @stack, {
900             typename => $type,
901             style => 'paragraph',
902             range => { %range },
903             options => $options,
904             config => $config,
905             @config_stack_entry,
906             terminator => qr{ ^ \s* $
907             | $DIR_NC
908             | (?= $top->{terminator} )
909             }xms,
910             is_verbatim => $verbatim || $top->{is_verbatim},
911             is_blank_terminated => 1,
912             disjoint => $disjoint_item1,
913             permits_implicit_blocks => $permits_implicit_blocks,
914             };
915              
916             ### Opened paragraph block: $stack[-1]
917 25         246 next TOKEN;
918             }
919              
920             # =use URI directive
921 93 100       2972 if ($line =~ m{ \G ^ =use \s+ (\S+) ($OPTIONS?) \s* ([^\n]*) \n }ogcxms) {
922 1         8 my ($source, $options, $junk) = ($1, $2, $3);
923 1         2 my $orig_source = $source;
924              
925             # Anything after last option is junk...
926 1 50       4 if ($junk) {
927 0         0 _err_trailing_junk('=use directive', \%range, $junk, \@errors);
928             }
929              
930 1         2 $has_options_pending = 1;
931              
932             # Insert or close implicit list block if required...
933 1         6 $top = _adjust_lists(\@stack, $line, 0, 0, 0, \%range, \@warnings);
934              
935             # Can use Perl 5 modules...
936 1 50       1013 if ($source =~ m{\A (?:perl5:)? $QUAL_IDENT \Z}xms) {
937 0         0 push @stack, {
938             typename => '(use)',
939             style => 'directive',
940             source => $source,
941             range => { %range },
942             terminator => qr{ ^ \s* $
943             | $DIR_NC
944             | (?= [^=] )
945             | (?= $top->{terminator} )
946             }xms,
947             options => _extract_options($options),
948             config => $config_stack[-1]{use},
949             is_blank_terminated => 1,
950             };
951              
952             ### =use directive: $stack[-1]
953 0         0 next TOKEN;
954             }
955              
956             # Otherwise, no options allowed (on direct inclusions)...
957 1 50       15 if ($options) {
958 0         0 _err_trailing_junk('=use directive', \%range,
959             $options, \@errors
960             );
961             }
962              
963             # Assume it's a Pod file; open it...
964 1         2 $source =~ s{\A file:}{}xms;
965 1 50       10 if (!-r $source) {
966 1         4 _err_bad_use_uri($orig_source, \%range, \@errors);
967             next TOKEN
968 1         10 }
969              
970 0         0 my %opts;
971 0 0       0 if ($source =~ m{ [.]pod6 \Z }xms) {
972 0         0 $opts{all_pod} = 1;
973             }
974              
975             # Then read, parse, and add in the result (recursively)...
976 0         0 my $result_ref
977             = Perl6::Perldoc::Parser->parse($source, \%opts);
978 0 0       0 if ($result_ref->{tree}) {
979 0         0 push @{$stack[-1]{content}}, {
  0         0  
980             typename => 'use',
981             style => 'directive',
982             uri => $orig_source,
983             range => { %range, to => $range{from} },
984             content => $result_ref->{tree}{content},
985             };
986             }
987              
988             # Propagate any warnings or errors...
989 0 0       0 if ($result_ref->{errors}) {
990 0         0 push @errors, @{ $result_ref->{errors} };
  0         0  
991             }
992 0 0       0 if ($result_ref->{warnings}) {
993 0         0 push @warnings, @{ $result_ref->{warnings} };
  0         0  
994             }
995              
996             ### =use directive: $stack[-1]
997 0         0 next TOKEN;
998             }
999              
1000             # =encoding directive
1001 92 50       228 if ($line =~ m{ \G ^ =encoding \s+ (\S+) \s* ([^\n]*) \n }ogcxms) {
1002 0         0 my ($encoding, $junk) = ($1, $2);
1003              
1004             # =encoding takes no options...
1005 0 0       0 if ($junk) {
1006 0         0 _err_trailing_junk('=encoding directive', \%range, $junk, \@errors);
1007             }
1008              
1009             # It also terminates any surrounding list...
1010 0         0 $top = _adjust_lists(\@stack, $line, 0, 0, 0, \%range, \@warnings);
1011              
1012             # Add it to the stack (not yet in the representation)...
1013 0         0 push @stack, {
1014             typename => 'encoding',
1015             style => 'directive',
1016             encoding => $encoding,
1017             range => { %range },
1018             terminator => qr{ ^ \s* $
1019             | $DIR_NC
1020             | (?= [^=] )
1021             | (?= $top->{terminator} )
1022             }xms,
1023             is_blank_terminated => 1,
1024             };
1025              
1026             ### =encoding directive: $stack[-1]
1027 0         0 next TOKEN;
1028             }
1029              
1030             # =config directive
1031 92 100       3487 if ($line =~ m{ \G ^ =config \s+ ($FORMATTING_CODE<>|$IDENT) ($OPTIONS?) \s* ([^\n]*) \n }ogcxms) {
1032 9         34 my ($config_type, $options, $junk) = ($1, $2, $3);
1033              
1034             # Anything after last option is junk...
1035 9 50       17 if ($junk) {
1036 0         0 _err_trailing_junk("=config directive", \%range, $junk, \@errors);
1037             }
1038              
1039 9         14 $has_options_pending = 1;
1040              
1041 9         25 my $parsed_opts_ref
1042             = _extract_options($options);
1043              
1044             # Record added config scope in parent...
1045 9         22 $stack[-1]{has_config}++;
1046              
1047             # Add new lexical config frame...
1048 9         26 push @config_stack, _extend_config(
1049             $config_stack[-1],
1050             $config_type,
1051             $parsed_opts_ref,
1052             );
1053              
1054             # Directive closes any surrounding list...
1055 9         31 $top = _adjust_lists(\@stack, $line, 0, 0, 0, \%range, \@warnings);
1056              
1057             # Save representation of =config directive...
1058 9         352 push @stack, {
1059             typename => 'config',
1060             style => 'directive',
1061             target => $config_type,
1062             options => $parsed_opts_ref,
1063             range => { %range },
1064             terminator => qr{ ^ \s* $
1065             | $DIR_NC
1066             | (?= [^=] )
1067             | (?= $top->{terminator} )
1068             }xms,
1069             is_blank_terminated => 1,
1070             };
1071              
1072             ### =config directive: $stack[-1]
1073             ### Config now: $config_stack[-1]
1074 9         82 next TOKEN;
1075             }
1076              
1077             # Open marker for abbreviated block...
1078 83 100       1320 if ($line =~ m{ \G ^ = ($IDENT) \s* }ogcxms) {
1079 81         157 my $type = $1;
1080              
1081             # Work out its nesting level if it's an item block...
1082 81         192 my ($is_item, $item_level)
1083             = $type =~ m{\A (item)(\d+)? \Z}xms;
1084 81 100 100     363 $item_level ||= $is_item ? 1 : 0;
1085              
1086 81         104 my $is_comment = $type eq 'comment';
1087              
1088             # Open or close implicit list if necessary...
1089 81         223 $top = _adjust_lists(\@stack, $line, $is_item, $is_comment,
1090             $item_level, \%range, \@warnings
1091             );
1092              
1093 81   100     329 my $disjoint_item1
1094             = $is_item && $item_level==1 && !$top->{content};
1095              
1096 81         358 my $permits_implicit_blocks
1097             = $type =~ m{$PERMITS_IMPLICIT}xms;
1098              
1099 81         99 my $verbatim = $type eq 'code';
1100              
1101 81         131 my $config = $config_stack[-1]{$type};
1102             my @config_stack_entry
1103 81 100       188 = $type eq 'table' ? (config_stack=>$config_stack[-1])
1104             : ();
1105              
1106             # Copy allowed fcodes...
1107 81         159 my $allow_ref = _update_allow($top, $config, {});
1108              
1109             # Add it to the stack (not yet in the representation)...
1110 81   33     2486 push @stack, {
1111             typename => $type,
1112             style => 'abbreviated',
1113             config => $config,
1114             @config_stack_entry,
1115             range => { %range },
1116             terminator => qr{ ^ \s* $
1117             | $DIR_NC
1118             | (?= $top->{terminator} )
1119             }xms,
1120             is_verbatim => $verbatim || $top->{is_verbatim},
1121             is_blank_terminated => 1,
1122             allow => $allow_ref,
1123             disjoint => $disjoint_item1,
1124             permits_implicit_blocks => $permits_implicit_blocks,
1125             };
1126              
1127             # Handling configured implicit formatting, if any...
1128 81         267 $stack[-1]->{options}
1129             = _handle_likeness($stack[-1], $config_stack[-1]);
1130 81         194 push @stack, _handle_formatted(
1131             $stack[-1], \%range, $config_stack[-1], \@errors
1132             );
1133              
1134             # Finished with directive (may be trailing data)
1135 81         97 $is_directive = 0;
1136              
1137             ### Opened abbreviated block: $stack[-1]
1138 81         372 next TOKEN;
1139             }
1140              
1141             # Treat "late" option lines as content (with warning)...
1142 2 100       166 if ($line =~ m{ \G ^ = (\s+ $OPTIONS) \s* $ }ogcxms) {
1143 1         5 _err_options_too_late($top, \%range, \@warnings);
1144              
1145 1         2 _add_content($top, $line);
1146              
1147             ### Added dubious raw content: $stack[-1]
1148 1         9 next LINE;
1149             }
1150             }
1151              
1152             # If not directive, must be ambient text, raw para or code block...
1153              
1154             # Close implicit item list if necessary...
1155 1244         2429 $top = _adjust_lists(\@stack, $line, 0, 0, 0, \%range, \@warnings);
1156              
1157             # Deal with ambient text (i.e. non-Pod) and unprocessed blocks...
1158 1244 50       2234 if (@stack == 1) {
1159 0         0 $top = {
1160             typename => '(ambient)',
1161             style => 'implicit',
1162             range => { %range },
1163             terminator => qr{(?= ^ = $IDENT) }xms,
1164             };
1165 0         0 push @stack, $top;
1166             }
1167 1244 100 100     4933 if ($top->{typename} =~ m{^(?:\(ambient\)|table)$}xms
      66        
1168             || $top->{typename} =~ m{[[:upper:]]}
1169             && $top->{typename} =~ m{[[:lower:]]}
1170             ) {
1171 46 50       128 if ($line =~ m{ \G (.*) }gcxms) {
1172 46         91 _add_content($top, $1);
1173             ### Unprocessed text: $1
1174             }
1175              
1176 46         186 next LINE;
1177             }
1178              
1179             # Implicit code/para Pod block depends on indenting...
1180 1198 100 100     2905 if (pos($line) == 0 && $top->{permits_implicit_blocks}) {
1181 143 100       325 my $terminator
1182             = $top->{style} eq 'delimited' ? '^ \s* $' : '(?= ^ \s* $)';
1183              
1184             # Indented block is code block...
1185 143 100       710 if ($line =~ m{ \G ^ (?= [^\S\n]+ \S [^\n]* $ ) }gcxms) {
    100          
1186              
1187 2         5 my $config = $config_stack[-1]{'code'};
1188 2         5 my $allow_ref = _update_allow($top, $config, {});
1189              
1190 2         133 push @stack, {
1191             typename => 'code',
1192             style => 'implicit',
1193             config => $config,
1194             allow => $allow_ref,
1195             range => { %range },
1196             terminator => qr{ $terminator
1197             | $DIR_NC
1198             | (?= $top->{terminator} )
1199             }xms,
1200             is_verbatim => 1,
1201             is_blank_terminated => 1,
1202             };
1203              
1204 2         9 _add_content($stack[-1], $line);
1205              
1206             ### Opened implicit code block: $stack[-1]
1207 2         10 next LINE;
1208             }
1209             # Unindented block is para block...
1210             elsif ($line =~ m{ \G (?= \S .* $ ) }gcxms) {
1211              
1212 94         158 my $config = $config_stack[-1]{'para'};
1213 94         185 my $allow_ref = _update_allow($top, $config, {});
1214              
1215 94         3193 push @stack, {
1216             typename => 'para',
1217             style => 'implicit',
1218             config => $config,
1219             allow => $allow_ref,
1220             range => { %range },
1221             terminator => qr{ $terminator
1222             | $DIR_NC
1223             | (?= $top->{terminator} )
1224             }xms,
1225             is_verbatim=> $top->{is_verbatim},
1226             is_blank_terminated => 1,
1227             };
1228              
1229             ### Opened implicit para block: $stack[-1]
1230 94         407 next TOKEN;
1231             }
1232             else { # Meaningless empty line
1233 47         248 next LINE;
1234             }
1235             }
1236              
1237             # Open marker for formatting code (only outside V<> and C<>)...
1238 1055 100 100     6397 if ( ( !$top->{is_verbatim}
      100        
1239             || exists $top->{allow}{substr($line,pos $line,1)}
1240             )
1241             && $line =~ m{ \G ($FORMATTING_CODE) ((?><+)|$LEFT_ANGLE) }ogcxms
1242             ) {
1243 61         184 my ($type, $delim) = ($1, $2);
1244              
1245             # Generate right delimiter (and nested matcher) from left...
1246 61         70 my $rdelim = $delim;
1247 61         92 $rdelim =~ tr//;
1248 61         271 $rdelim =~ s{$LDAB}{$RDAB}g;
1249 61         284 $rdelim =~ s{$LDAB_CJK}{$RDAB_CJK}g;
1250 61 100       215 my $initiator = $delim . ($delim =~ /
1251 61 100       136 my $terminator = length($delim) == 1 ? $rdelim
1252             : "$rdelim(?!>)"
1253             ;
1254              
1255             # Don't look up terminator stack if partial matches might
1256             # occur...
1257 61 100 100     627 if ($rdelim =~ />/ && $rdelim !~ $top->{terminator}) {
1258 47         256 $terminator .= "|(?=$top->{terminator})"
1259             }
1260              
1261 61         121 my $config_ref = $config_stack[-1]{"$type<>"};
1262 61         132 my $allow_ref = _update_allow($top, $config_ref, {});
1263              
1264 61   100     795 push @stack, {
1265             typename => $type,
1266             style => 'formatting',
1267             config => $config_ref,
1268             allow => $allow_ref,
1269             range => { %range },
1270             initiator => $initiator,
1271             terminator => $terminator,
1272             left_delim => $delim,
1273             right_delim => $rdelim,
1274             is_verbatim => ($type =~ m{[VCMP]}xms ? 1 : 0)
1275             || $top->{is_verbatim},
1276             permits_implicit_blocks
1277             => $top->{permits_implicit_blocks},
1278             };
1279              
1280             # Track placement requests for table-of-contents...
1281 61 100       156 if ($type eq 'P') {
1282 2         4 push @toc_placements, $stack[-1];
1283             }
1284              
1285             ### Opened formatting code: $stack[-1]
1286 61         244 next TOKEN;
1287             }
1288              
1289             # Balance nested delimiters inside a formatting code...
1290 994 100 100     2721 if ( $top->{style} eq 'formatting'
1291             && $line =~ m{ \G ($top->{initiator}) }gcxms
1292             ) {
1293 7         18 my $delim = $1;
1294 7         30 $top->{delim_nesting}++;
1295 7         13 _add_content($top, $delim);
1296              
1297             ### Nested left delimiter in formatting code: $stack[-1]
1298 7         17 next TOKEN;
1299             }
1300              
1301             # Is there a separator in one of the "separable" codes?
1302 987 100 100     2261 if ( $top->{style} eq 'formatting'
      100        
1303             && $top->{typename} =~ m{\A [DLX] \Z}xms
1304             && $line =~ m{ \G [|] }gcxms) {
1305 4         7 $top->{target} = "";
1306             }
1307              
1308             # Otherwise, it's raw content or target (eat *all* angles, if any)..
1309 987 50       2518 if ($line =~ m{ \G ( [\xAB<]+ | [^A-Z|\n<>\xAB\xBB]+ | . ) }gcxms) {
1310             # Are we in the "target" section yet?
1311 987 100       1472 if (exists $top->{target}) {
1312 7         14 $top->{target} .= $1;
1313             ### Added target: $stack[-1]
1314             }
1315             # Otherwise, still in the "appearance" section
1316             else {
1317 980         1382 _add_content($top, $1);
1318             ### Added raw content: $stack[-1]
1319             }
1320              
1321 987         3450 next TOKEN;
1322             }
1323              
1324             # Should be impossible to get to here...
1325 0         0 die "Internal error near: ", substr($line, pos $line);
1326             }
1327             }
1328              
1329             # Close and nest any unclosed blocks at the end of the file...
1330 127         361 while (@stack > 1) {
1331 206         273 my $top = $stack[-1];
1332 206         270 my $line_num = $.;
1333              
1334             # Record the missing closing delimiter...
1335 206         385 _err_no_closing_delim($top, \@errors, \@warnings);
1336              
1337             # Finish line range and remove internal parsing data...
1338 206         221 my $block = pop @stack;
1339 206         340 $block->{range}{to} = $line_num;
1340 206         205 delete @{$block}{qw< terminator initiator has_config allow>};
  206         559  
1341              
1342             # Execute any use statement...
1343 206 50       492 if ($block->{typename} eq '(use)') {
1344 0         0 my $source = $block->{source};
1345 0 0       0 if (eval "require $source") {
1346 0 0       0 my %options = (
1347 0 0       0 %{ $block->{config}{use}||{} },
1348 0         0 %{ $block->{options} || {} },
1349             );
1350 0         0 $source->import(\%options);
1351             }
1352             else {
1353 0         0 _err_use_cant_load($source, $line_num, \@errors);
1354 0         0 next TOKEN;
1355             }
1356             }
1357              
1358 206         193 push @{ $stack[-1]{content} }, $block;
  206         676  
1359              
1360             ### Implicitly terminated block: $block
1361             }
1362              
1363             # Apply global processing to root of data structure...
1364 127         170 my $root = pop(@stack);
1365              
1366             # Number all numbered blocks...
1367 127         278 my $state_ref = { errors => \@errors };
1368 127         327 _resolve_numbering($root, $state_ref);
1369              
1370             # Convert internal hash-based representation to objects...
1371 127         366 my $tree = _create_objects($root, $state_ref);
1372              
1373             # Build and install any tables-of-content for P codes...
1374             TOC:
1375 127         272 for my $toc_placement_obj (@toc_placements) {
1376 2 100       15 next TOC if $toc_placement_obj->{content}[0] !~ m{\A \s* toc:}xms;
1377              
1378             # Replace P's contents with TOC...
1379 1         3 $toc_placement_obj->{content}
1380             = [ _build_toc($tree, $toc_placement_obj) ];
1381              
1382             # Set flag to ignore this node on subsequent TOC-building passes...
1383 1         4 $toc_placement_obj->{ignore_toc} = 1;
1384             }
1385              
1386             # Aggregrate and return information in an object...
1387 127         983 return bless {
1388             tree => $tree,
1389             errors => \@errors,
1390             warnings => \@warnings,
1391             }, 'Perl6::Perldoc::Parser::ReturnVal';
1392              
1393             }
1394              
1395             # Build the table of contents for a given P request...
1396             sub _build_toc {
1397 1     1   2 my ($data_structure, $placement_obj) = @_;
1398              
1399             # Work out what's in the TOC (including the =item/=item1 alias)...
1400 1         2 my $requested_types = $placement_obj->{target};
1401 1         4 $requested_types =~ s{\A \s* toc: \s*}{}xms;
1402 1         2 my %toc_wants;
1403 1         4 @toc_wants{ split m/\s+/, $requested_types } = ();
1404 1 50 33     6 if (exists $toc_wants{item} || exists $toc_wants{item1}) {
1405 0         0 @toc_wants{qw< item item1 >} = ();
1406             }
1407              
1408             # Build flat list of tocitems into nested toclists...
1409 1         2 my @toc_stack = [];
1410 1         7 for my $toc_entry ( _walk_toc($data_structure, \%toc_wants) ) {
1411 4         9 my $level = $toc_entry->{level};
1412              
1413             # Increase nesting for higher numbered items...
1414 4         9 while ($level > @toc_stack) {
1415 0         0 push @toc_stack, [];
1416             }
1417             # Decrease nesting for lower numbered items...
1418 4         13 while ($level < @toc_stack) {
1419 0         0 my $content = pop @toc_stack;
1420 0         0 push @{ $toc_stack[-1] }, Perl6::Perldoc::Block::toclist->new({
  0         0  
1421             typename => 'toclist',
1422             style => 'implicit',
1423             content => $content,
1424             range => {},
1425             });
1426             }
1427             # Insert the item into the hierarchy...
1428 4         2 push @{ $toc_stack[-1] }, $toc_entry;
  4         7  
1429             }
1430              
1431             # Nest any unclosed lists...
1432 1         4 while (@toc_stack > 1) {
1433 0         0 my $content = pop @toc_stack;
1434 0         0 push @{ $toc_stack[-1] }, Perl6::Perldoc::Block::toclist->new({
  0         0  
1435             typename => 'toclist',
1436             style => 'implicit',
1437             content => $content,
1438             range => {},
1439             });
1440             }
1441              
1442             # Retrieve a flat list of tocitem blocks representing the TOC...
1443 1         1 return @{ $toc_stack[-1] };
  1         4  
1444             }
1445              
1446             # Blocks without an inherent nesting level default to this nesting...
1447             my $DEFAULT_LEVEL = 5;
1448              
1449             # Walk DOM tree extracting blocks specified to be part of TOC...
1450 55     55   475 use Scalar::Util qw< reftype >;
  55         93  
  55         15386  
1451             sub _walk_toc {
1452 27     27   25 my ($node, $wanted_ref) = @_;
1453              
1454 27   100     68 my $node_type = reftype($node) || q{};
1455              
1456             # Hashes are nodes: check if this one (and its subnodes) should be included
1457 27 100       41 if ($node_type eq 'HASH') {
    100          
1458 10 50       41 return if $node->{ignore_toc};
1459              
1460 10         10 my $node_class = $node->{typename};
1461 10         7 my @this_node;
1462              
1463             # Is this node part of the TOC?
1464 10   33     34 my $wanted = exists $wanted_ref->{$node_class}
1465             || $node->{is_semantic} && exists $wanted_ref->{'head1'};
1466 10 100       13 if ($wanted) {
1467 4 0       10 my $level
    50          
1468             = $node->{is_semantic} ? 1
1469             : $node_class =~ m{\A head (\d+) \z}xms ? $1
1470             : $DEFAULT_LEVEL
1471             ;
1472              
1473 4         20 my $target = $node->id();
1474              
1475             # Create a TOC entry (a list item with a link inside it)...
1476 4         26 @this_node = bless {
1477             typename => "tocitem$level",
1478             style => 'implicit',
1479             level => $level,
1480             target => "#$target",
1481             content => [$node],
1482             range => {},
1483             }, "Perl6::Perldoc::Block::tocitem$level";
1484              
1485             # Install the TOC entry's class in the DOM...
1486 55     55   301 no strict 'refs';
  55         77  
  55         14428  
1487 4         5 @{"Perl6::Perldoc::Block::tocitem${level}::ISA"}
  4         36  
1488             = 'Perl6::Perldoc::Block::tocitem';
1489             }
1490              
1491             # Does it have subnodes that are part of the TOC?
1492 10         29 my @sub_nodes = _walk_toc($node->{content}, $wanted_ref);
1493              
1494             # Return node's TOC entry (if any) and those of its contents...
1495 10         18 return @this_node, @sub_nodes;
1496             }
1497              
1498             # Arrays may contain nodes: check each element...
1499             elsif ($node_type eq 'ARRAY') {
1500 10         6 return map { _walk_toc($_, $wanted_ref) } @{$node};
  16         34  
  10         11  
1501             }
1502              
1503             # Ignore everything else...
1504             else {
1505 7         13 return;
1506             }
1507             }
1508              
1509              
1510             # Standard classes for Perldoc DOM...
1511              
1512             package Perl6::Perldoc::Parser::ReturnVal;
1513              
1514             sub report_errors {
1515 0     0   0 my $self = shift;
1516              
1517             # Report warnings...
1518 0 0       0 if (@{$self->{warnings}}) {
  0         0  
1519 0         0 print {*STDERR} join "\n", @{$self->{warnings}}, "";
  0         0  
  0         0  
1520             }
1521              
1522             # Report errors and die...
1523 0 0       0 if (@{$self->{errors}}) {
  0         0  
1524 0         0 print {*STDERR} join "\n", @{$self->{errors}}, "";
  0         0  
  0         0  
1525              
1526             # Die in context if a fatality message was specified...
1527 0 0       0 if (@_) {
1528 0 0       0 require Carp and Carp::croak(@_);
1529             }
1530             # Otherwise die silently...
1531             else {
1532 0         0 die "\n";
1533             }
1534             }
1535              
1536             # On success, return self to allow for chaining...
1537 0         0 return $self;
1538             }
1539              
1540             package Perl6::Perldoc::Root;
1541 55     55   784 use strict;
  55         75  
  55         1592  
1542 55     55   246 use warnings;
  55         74  
  55         39006  
1543              
1544             my $id = 1;
1545              
1546             # Reset the id in case someone wants reproducible results
1547             sub _reset_id {
1548 0     0   0 $id = 1;
1549             }
1550              
1551             # Root constructor just assigns id and blesses the data structure...
1552             sub new {
1553 576     576   646 my ($classname, $data_ref) = @_;
1554              
1555 576         740 $data_ref->{id} = $id++;
1556 576         1886 return bless $data_ref, $classname;
1557             }
1558              
1559             # Standard read-only accessor methods shared by all DOM components...
1560 4     4   3 sub id { my ($self) = @_; return $self->{id}; }
  4         6  
1561 487     487   460955 sub typename { my ($self) = @_; return $self->{typename}; }
  487         2009  
1562 434     434   406273 sub style { my ($self) = @_; return $self->{style}; }
  434         1751  
1563 11     11   8400 sub target { my ($self) = @_; return $self->{target}; }
  11         52  
1564 0     0   0 sub range { my ($self) = @_; return $self->{range}; }
  0         0  
1565 0     0   0 sub config { my ($self) = @_; return $self->{config}; }
  0         0  
1566 45     45   40444 sub number { my ($self) = @_; return $self->{number}; }
  45         191  
1567 0     0   0 sub title { my ($self) = @_; return '[' . $self->typename . ']'; }
  0         0  
1568 0     0   0 sub is_verbatim { my ($self) = @_; return $self->{is_verbatim}; }
  0         0  
1569 0     0   0 sub is_semantic { my ($self) = @_; return $self->{is_semantic}; }
  0         0  
1570 0     0   0 sub is_numbered { my ($self) = @_; return exists $self->{number}; }
  0         0  
1571 0     0   0 sub is_post_numbered { 0 }
1572              
1573             sub content {
1574 487     487   418448 my ($self) = @_;
1575 487         955 my $vals_ref = $self->{content};
1576 487 100       1188 if (!wantarray) {
1577 2 100       2 if (@{ $vals_ref } > 1) {
  2         10  
1578 1 50       131 require Carp and Carp::carp(
1579             "Multivalued accessor content() called in scalar context"
1580             );
1581             }
1582 2         37 return $vals_ref->[0];
1583             }
1584 485         426 return @{ $vals_ref };
  485         2257  
1585             }
1586              
1587             # Asking for an option falls back to the config if necessary...
1588             sub option {
1589 0     0   0 my ($self, $opt_name) = @_;
1590 0 0       0 return $self->{options}{$opt_name}
1591             if defined $self->{options}{$opt_name};
1592 0 0       0 return $self->{config}{$opt_name}
1593             if defined $self->{config}{$opt_name};
1594 0         0 return;
1595             }
1596              
1597             # Return an object's term or caption...
1598              
1599             sub _flatten_or_convert_option {
1600 0     0   0 my ($self, $opt_ref, $option_name) = @_;
1601 0         0 my $value = $self->option($option_name);
1602              
1603             # Flatten if value specified as a list...
1604 0 0       0 if (ref($value) eq 'ARRAY') {
1605 0         0 $value = "@{$value}";
  0         0  
1606             }
1607              
1608             # Return raw if not requested as an object...
1609 0 0       0 return $value if !$opt_ref->{as_objects};
1610              
1611 0         0 my $cache_slot = "parsed_$option_name";
1612             # Otherwise, convert to Pod object and cache for reuse...
1613 0 0       0 if (!$self->{$cache_slot}) {
1614 0 0       0 open my $fh, '<', \$value
1615             or die "Internal error: can't parse :$option_name";
1616 0         0 $self->{$cache_slot}
1617             = Perl6::Perldoc::Parser->parse( $fh, { all_pod => 1 })->{tree};
1618             }
1619              
1620 0         0 return $self->{$cache_slot};
1621             }
1622              
1623             sub term {
1624 0     0   0 my ($self, $opt_ref) = @_;
1625 0         0 return _flatten_or_convert_option($self, $opt_ref, 'term');
1626             }
1627              
1628             sub caption {
1629 0     0   0 my ($self, $opt_ref) = @_;
1630 0         0 return _flatten_or_convert_option($self, $opt_ref, 'caption');
1631             }
1632              
1633              
1634              
1635             # Representation of file itself...
1636             package Perl6::Perldoc::File;
1637 55     55   287 use base 'Perl6::Perldoc::Root';
  55         63  
  55         20910  
1638              
1639             # Representation of document...
1640             package Perl6::Perldoc::Document;
1641 55     55   285 use base 'Perl6::Perldoc::Root';
  55         70  
  55         13927  
1642              
1643             # Ambient text around the Pod...
1644             package Perl6::Perldoc::Ambient;
1645 55     55   268 use base 'Perl6::Perldoc::Root';
  55         63  
  55         13698  
1646              
1647              
1648             # Pod directives...
1649             package Perl6::Perldoc::Directive;
1650 55     55   325 use base 'Perl6::Perldoc::Root';
  55         76  
  55         13498  
1651              
1652             # Standard =use directive...
1653             package Perl6::Perldoc::Directive::use;
1654 55     55   350 use base 'Perl6::Perldoc::Directive';
  55         86  
  55         15864  
1655              
1656             # Standard =config directive...
1657             package Perl6::Perldoc::Directive::config;
1658 55     55   291 use base 'Perl6::Perldoc::Directive';
  55         74  
  55         13171  
1659              
1660             # Standard =encoding directive...
1661             package Perl6::Perldoc::Directive::encoding;
1662 55     55   259 use base 'Perl6::Perldoc::Directive';
  55         80  
  55         14029  
1663              
1664              
1665             # Pod blocks...
1666             package Perl6::Perldoc::Block;
1667 55     55   273 use base 'Perl6::Perldoc::Root';
  55         76  
  55         15188  
1668              
1669             # Base class for user-defined blocks...
1670             package Perl6::Perldoc::Block::Named;
1671 55     55   260 use base 'Perl6::Perldoc::Block';
  55         81  
  55         15477  
1672              
1673             # Standard =pod block...
1674             package Perl6::Perldoc::Block::pod;
1675 55     55   278 use base 'Perl6::Perldoc::Block';
  55         80  
  55         13144  
1676              
1677             # Standard =para block (may be implicit)...
1678             package Perl6::Perldoc::Block::para;
1679 55     55   273 use base 'Perl6::Perldoc::Block';
  55         64  
  55         13763  
1680              
1681             # Standard =code block (may be implicit)...
1682             package Perl6::Perldoc::Block::code;
1683 55     55   269 use base 'Perl6::Perldoc::Block';
  55         70  
  55         13233  
1684              
1685             # Standard =input block
1686             package Perl6::Perldoc::Block::input;
1687 55     55   262 use base 'Perl6::Perldoc::Block';
  55         71  
  55         13613  
1688              
1689             # Standard =output block
1690             package Perl6::Perldoc::Block::output;
1691 55     55   334 use base 'Perl6::Perldoc::Block';
  55         82  
  55         13294  
1692              
1693             # Base class for =headN classes
1694             package Perl6::Perldoc::Heading;
1695 55     55   291 use base 'Perl6::Perldoc::Block';
  55         87  
  55         19711  
1696              
1697             # All headings have a title (which is just their contents)...
1698             sub title {
1699 0     0   0 my ($self) = @_;
1700              
1701 0         0 my $vals_ref = $self->{content};
1702              
1703 0 0       0 if (exists $self->{number}) {
1704 0         0 unshift @{$vals_ref}, "$self->{number}. ";
  0         0  
1705             }
1706              
1707 0 0       0 if (!wantarray) {
1708 0 0       0 if (@{ $vals_ref } > 1) {
  0         0  
1709 0 0       0 require Carp and Carp::carp(
1710             "Multivalued accessor title() called in scalar context"
1711             );
1712             }
1713 0         0 return $vals_ref->[0];
1714             }
1715 0         0 return @{ $vals_ref };
  0         0  
1716             }
1717              
1718             # Standard =head1 block...
1719             package Perl6::Perldoc::Block::head1;
1720 55     55   298 use base 'Perl6::Perldoc::Heading';
  55         80  
  55         16009  
1721              
1722             # Standard =head2 block...
1723             package Perl6::Perldoc::Block::head2;
1724 55     55   271 use base 'Perl6::Perldoc::Heading';
  55         67  
  55         13630  
1725              
1726             # Standard =head3 block...
1727             package Perl6::Perldoc::Block::head3;
1728 55     55   261 use base 'Perl6::Perldoc::Heading';
  55         88  
  55         13206  
1729              
1730             # Standard =head4 block...
1731             package Perl6::Perldoc::Block::head4;
1732 55     55   286 use base 'Perl6::Perldoc::Heading';
  55         92  
  55         13203  
1733              
1734             # Standard =item block...
1735             package Perl6::Perldoc::Block::item;
1736 55     55   256 use base 'Perl6::Perldoc::Block';
  55         871  
  55         15262  
1737              
1738             # Standard =defn block...
1739             package Perl6::Perldoc::Block::defn;
1740 55     55   274 use base 'Perl6::Perldoc::Block';
  55         68  
  55         13395  
1741              
1742             # Implicit =list block...
1743             package Perl6::Perldoc::Block::list;
1744 55     55   297 use base 'Perl6::Perldoc::Block';
  55         62  
  55         13129  
1745              
1746             # Implicit =tocitem block...
1747             package Perl6::Perldoc::Block::tocitem;
1748 55     55   271 use base 'Perl6::Perldoc::Block';
  55         76  
  55         16218  
1749              
1750             sub title {
1751 0     0   0 my ($self) = @_;
1752 0         0 my $content = $self->{content}[0];
1753 0         0 return $content->title();
1754             }
1755              
1756             # Implicit =toclist block...
1757             package Perl6::Perldoc::Block::toclist;
1758 55     55   289 use base 'Perl6::Perldoc::Block';
  55         71  
  55         13870  
1759              
1760             # Standard =nested block...
1761             package Perl6::Perldoc::Block::nested;
1762 55     55   280 use base 'Perl6::Perldoc::Block';
  55         71  
  55         16850  
1763              
1764             sub new {
1765 2     2   7 my ($self, $data) = splice @_, 0, 2;
1766 2   50     9 $data->{nested} ||= 1;
1767 2         7 return $self->SUPER::new($data, @_);
1768             }
1769              
1770             # Standard =comment block...
1771             package Perl6::Perldoc::Block::comment;
1772 55     55   274 use base 'Perl6::Perldoc::Block';
  55         69  
  55         13582  
1773              
1774             # Standard =END block...
1775             package Perl6::Perldoc::Block::END;
1776 55     55   292 use base 'Perl6::Perldoc::Block';
  55         74  
  55         14330  
1777              
1778             # Standard =DATA block...
1779             package Perl6::Perldoc::Block::DATA;
1780 55     55   272 use base 'Perl6::Perldoc::Block';
  55         86  
  55         13273  
1781              
1782             # Standard SEMANTIC blocks...
1783             package Perl6::Perldoc::Semantic;
1784 55     55   270 use base 'Perl6::Perldoc::Block';
  55         63  
  55         17323  
1785            
1786             # For most semantic blocks, their title is their name, suitably de-shouted...
1787             sub title {
1788 0     0   0 my ($self) = @_;
1789 0         0 my $title = ucfirst lc $self->{typename};
1790            
1791 0 0       0 if (exists $self->{number}) {
1792 0 0       0 $title = $self->is_post_numbered ? "$title $self->{number}"
1793             : "$self->{number}. $title"
1794             ;
1795             }
1796              
1797 0         0 return $title;
1798             };
1799              
1800             package Perl6::Perldoc::Block::ACKNOWLEDGEMENT;
1801 55     55   285 use base 'Perl6::Perldoc::Semantic';
  55         68  
  55         15767  
1802             package Perl6::Perldoc::Block::ACKNOWLEDGEMENTS;
1803 55     55   266 use base 'Perl6::Perldoc::Semantic';
  55         70  
  55         13042  
1804 55     55   290 package Perl6::Perldoc::Block::APPENDICES; use base 'Perl6::Perldoc::Semantic';
  55         90  
  55         13538  
1805 55     55   286 package Perl6::Perldoc::Block::APPENDIX; use base 'Perl6::Perldoc::Semantic';
  55         88  
  55         14042  
1806 0     0   0 sub is_post_numbered {1}
1807              
1808 55     55   274 package Perl6::Perldoc::Block::APPENDIXES; use base 'Perl6::Perldoc::Semantic';
  55         77  
  55         13763  
1809 55     55   262 package Perl6::Perldoc::Block::AUTHOR; use base 'Perl6::Perldoc::Semantic';
  55         78  
  55         13666  
1810 55     55   258 package Perl6::Perldoc::Block::AUTHORS; use base 'Perl6::Perldoc::Semantic';
  55         69  
  55         13241  
1811 55     55   300 package Perl6::Perldoc::Block::BUG; use base 'Perl6::Perldoc::Semantic';
  55         95  
  55         13267  
1812 55     55   301 package Perl6::Perldoc::Block::BUGS; use base 'Perl6::Perldoc::Semantic';
  55         60  
  55         13347  
1813 55     55   266 package Perl6::Perldoc::Block::CHAPTER; use base 'Perl6::Perldoc::Semantic';
  55         69  
  55         13982  
1814 0     0   0 sub is_post_numbered {1}
1815              
1816 55     55   261 package Perl6::Perldoc::Block::CHAPTERS; use base 'Perl6::Perldoc::Semantic';
  55         66  
  55         13217  
1817 55     55   271 package Perl6::Perldoc::Block::COPYRIGHT; use base 'Perl6::Perldoc::Semantic';
  55         97  
  55         13810  
1818 55     55   296 package Perl6::Perldoc::Block::COPYRIGHTS; use base 'Perl6::Perldoc::Semantic';
  55         90  
  55         13408  
1819 55     55   275 package Perl6::Perldoc::Block::DEFAULT; use base 'Perl6::Perldoc::Semantic';
  55         134  
  55         13126  
1820             package Perl6::Perldoc::Block::DEPENDENCIES;
1821 55     55   264 use base 'Perl6::Perldoc::Semantic';
  55         68  
  55         12885  
1822 55     55   260 package Perl6::Perldoc::Block::DEPENDENCY; use base 'Perl6::Perldoc::Semantic';
  55         70  
  55         13991  
1823 55     55   307 package Perl6::Perldoc::Block::DESCRIPTION; use base 'Perl6::Perldoc::Semantic';
  55         72  
  55         13914  
1824             package Perl6::Perldoc::Block::DESCRIPTIONS;
1825 55     55   285 use base 'Perl6::Perldoc::Semantic';
  55         81  
  55         13907  
1826 55     55   282 package Perl6::Perldoc::Block::DIAGNOSTIC; use base 'Perl6::Perldoc::Semantic';
  55         74  
  55         13799  
1827 55     55   281 package Perl6::Perldoc::Block::DIAGNOSTICS; use base 'Perl6::Perldoc::Semantic';
  55         69  
  55         13502  
1828 55     55   282 package Perl6::Perldoc::Block::DISCLAIMER; use base 'Perl6::Perldoc::Semantic';
  55         81  
  55         13967  
1829 55     55   293 package Perl6::Perldoc::Block::DISCLAIMERS; use base 'Perl6::Perldoc::Semantic';
  55         103  
  55         13720  
1830 55     55   302 package Perl6::Perldoc::Block::ERROR; use base 'Perl6::Perldoc::Semantic';
  55         83  
  55         13176  
1831 55     55   272 package Perl6::Perldoc::Block::ERRORS; use base 'Perl6::Perldoc::Semantic';
  55         112  
  55         14102  
1832 55     55   291 package Perl6::Perldoc::Block::FOREWORD; use base 'Perl6::Perldoc::Semantic';
  55         81  
  55         13595  
1833 55     55   301 package Perl6::Perldoc::Block::FOREWORDS; use base 'Perl6::Perldoc::Semantic';
  55         95  
  55         13326  
1834 55     55   304 package Perl6::Perldoc::Block::INDEX; use base 'Perl6::Perldoc::Semantic';
  55         81  
  55         14420  
1835 0     0   0 sub is_post_numbered {1}
1836              
1837 55     55   283 package Perl6::Perldoc::Block::INDEXES; use base 'Perl6::Perldoc::Semantic';
  55         83  
  55         13774  
1838 55     55   285 package Perl6::Perldoc::Block::INDICES; use base 'Perl6::Perldoc::Semantic';
  55         79  
  55         13298  
1839 55     55   278 package Perl6::Perldoc::Block::INTERFACE; use base 'Perl6::Perldoc::Semantic';
  55         92  
  55         13347  
1840 55     55   276 package Perl6::Perldoc::Block::INTERFACES; use base 'Perl6::Perldoc::Semantic';
  55         76  
  55         13636  
1841 55     55   278 package Perl6::Perldoc::Block::LICENCE; use base 'Perl6::Perldoc::Semantic';
  55         81  
  55         13592  
1842 55     55   289 package Perl6::Perldoc::Block::LICENCES; use base 'Perl6::Perldoc::Semantic';
  55         75  
  55         13938  
1843 55     55   1955 package Perl6::Perldoc::Block::LICENSE; use base 'Perl6::Perldoc::Semantic';
  55         97  
  55         13564  
1844 55     55   273 package Perl6::Perldoc::Block::LICENSES; use base 'Perl6::Perldoc::Semantic';
  55         68  
  55         13965  
1845 55     55   268 package Perl6::Perldoc::Block::METHOD; use base 'Perl6::Perldoc::Semantic';
  55         62  
  55         13400  
1846 55     55   275 package Perl6::Perldoc::Block::METHODS; use base 'Perl6::Perldoc::Semantic';
  55         83  
  55         13554  
1847 55     55   295 package Perl6::Perldoc::Block::NAME; use base 'Perl6::Perldoc::Semantic';
  55         86  
  55         14092  
1848 55     55   273 package Perl6::Perldoc::Block::NAMES; use base 'Perl6::Perldoc::Semantic';
  55         68  
  55         13758  
1849 55     55   275 package Perl6::Perldoc::Block::OPTION; use base 'Perl6::Perldoc::Semantic';
  55         68  
  55         13693  
1850 55     55   269 package Perl6::Perldoc::Block::OPTIONS; use base 'Perl6::Perldoc::Semantic';
  55         68  
  55         14308  
1851 55     55   295 package Perl6::Perldoc::Block::PURPOSE; use base 'Perl6::Perldoc::Semantic';
  55         74  
  55         13478  
1852 55     55   274 package Perl6::Perldoc::Block::SECTION; use base 'Perl6::Perldoc::Semantic';
  55         71  
  55         14574  
1853 0     0   0 sub is_post_numbered {1}
1854              
1855 55     55   308 package Perl6::Perldoc::Block::SECTIONS; use base 'Perl6::Perldoc::Semantic';
  55         56  
  55         13565  
1856 55     55   269 package Perl6::Perldoc::Block::SUBROUTINE; use base 'Perl6::Perldoc::Semantic';
  55         72  
  55         12906  
1857 55     55   270 package Perl6::Perldoc::Block::SUBROUTINES; use base 'Perl6::Perldoc::Semantic';
  55         80  
  55         13285  
1858 55     55   296 package Perl6::Perldoc::Block::SUMMARIES; use base 'Perl6::Perldoc::Semantic';
  55         97  
  55         13753  
1859 55     55   297 package Perl6::Perldoc::Block::SUMMARY; use base 'Perl6::Perldoc::Semantic';
  55         82  
  55         13547  
1860 55     55   335 package Perl6::Perldoc::Block::SYNOPSES; use base 'Perl6::Perldoc::Semantic';
  55         95  
  55         13746  
1861 55     55   264 package Perl6::Perldoc::Block::SYNOPSIS; use base 'Perl6::Perldoc::Semantic';
  55         71  
  55         13440  
1862 55     55   263 package Perl6::Perldoc::Block::TITLE; use base 'Perl6::Perldoc::Semantic';
  55         71  
  55         13644  
1863 55     55   285 package Perl6::Perldoc::Block::TITLES; use base 'Perl6::Perldoc::Semantic';
  55         80  
  55         13405  
1864 55     55   328 package Perl6::Perldoc::Block::USAGE; use base 'Perl6::Perldoc::Semantic';
  55         85  
  55         13228  
1865 55     55   268 package Perl6::Perldoc::Block::USAGES; use base 'Perl6::Perldoc::Semantic';
  55         79  
  55         13298  
1866 55     55   273 package Perl6::Perldoc::Block::VERSION; use base 'Perl6::Perldoc::Semantic';
  55         93  
  55         13659  
1867 55     55   279 package Perl6::Perldoc::Block::VERSIONS; use base 'Perl6::Perldoc::Semantic';
  55         84  
  55         13265  
1868 55     55   279 package Perl6::Perldoc::Block::WARNING; use base 'Perl6::Perldoc::Semantic';
  55         81  
  55         13263  
1869 55     55   290 package Perl6::Perldoc::Block::WARNINGS; use base 'Perl6::Perldoc::Semantic';
  55         83  
  55         13416  
1870              
1871             # A few semantic classes need to translate their titles...
1872 55     55   277 package Perl6::Perldoc::Block::TOC; use base 'Perl6::Perldoc::Semantic';
  55         77  
  55         14029  
1873 0     0   0 sub title { return 'Table of Contents'; }
1874              
1875 55     55   267 package Perl6::Perldoc::Block::TOCS; use base 'Perl6::Perldoc::Semantic';
  55         68  
  55         14323  
1876 0     0   0 sub title { return 'Tables of Contents'; }
1877              
1878 55     55   266 package Perl6::Perldoc::Block::SEEALSO; use base 'Perl6::Perldoc::Semantic';
  55         102  
  55         14405  
1879 0     0   0 sub title { return 'See Also'; }
1880              
1881 55     55   290 package Perl6::Perldoc::Block::SEEALSOS; use base 'Perl6::Perldoc::Semantic';
  55         100  
  55         14350  
1882 0     0   0 sub title { return 'See Also'; }
1883              
1884             # Base class for formatting codes...
1885             package Perl6::Perldoc::FormattingCode;
1886 55     55   272 use base 'Perl6::Perldoc::Root';
  55         83  
  55         15972  
1887              
1888             # Basis text formatter...
1889             package Perl6::Perldoc::FormattingCode::B;
1890 55     55   293 use base 'Perl6::Perldoc::FormattingCode';
  55         74  
  55         15645  
1891              
1892             # Code formatter...
1893             package Perl6::Perldoc::FormattingCode::C;
1894 55     55   286 use base 'Perl6::Perldoc::FormattingCode';
  55         84  
  55         13363  
1895              
1896             # Definition formatter...
1897             package Perl6::Perldoc::FormattingCode::D;
1898 55     55   281 use base 'Perl6::Perldoc::FormattingCode';
  55         78  
  55         22350  
1899              
1900             # The "definition" formatting code must extract its synonyms...
1901             sub new {
1902 2     2   3 my ($classname, $data_ref) = @_;
1903              
1904 2 50       12 if (my $synonyms = delete $data_ref->{target}) {
1905 2         9 $data_ref->{synonyms} = [split /;/, $synonyms];
1906             }
1907              
1908 2         11 return $classname->SUPER::new($data_ref);
1909             }
1910              
1911             sub synonyms {
1912 0     0   0 my ($self) = @_;
1913 0         0 my $vals_ref = $self->{synonyms};
1914 0 0       0 if (!wantarray) {
1915 0 0       0 if (@{ $vals_ref } > 1) {
  0         0  
1916 0 0       0 require Carp and Carp::carp(
1917             "Multivalued accessor synonyms() called in scalar context"
1918             );
1919             }
1920 0         0 return $vals_ref->[0];
1921             }
1922 0         0 return @{ $vals_ref };
  0         0  
1923             }
1924              
1925              
1926             # Entity formatter...
1927             package Perl6::Perldoc::FormattingCode::E;
1928 55     55   280 use base 'Perl6::Perldoc::FormattingCode';
  55         75  
  55         13706  
1929              
1930             # Important text formatter...
1931             package Perl6::Perldoc::FormattingCode::I;
1932 55     55   268 use base 'Perl6::Perldoc::FormattingCode';
  55         73  
  55         13393  
1933              
1934             # Keyboard input formatter...
1935             package Perl6::Perldoc::FormattingCode::K;
1936 55     55   277 use base 'Perl6::Perldoc::FormattingCode';
  55         70  
  55         13281  
1937              
1938             # Link formatter...
1939             package Perl6::Perldoc::FormattingCode::L;
1940 55     55   281 use base 'Perl6::Perldoc::FormattingCode';
  55         78  
  55         12881  
1941              
1942             # Flatten a hierarchical data structure into a suitable link target...
1943 55     55   295 use Scalar::Util qw< reftype >;
  55         82  
  55         21533  
1944             sub _flatten {
1945 0     0   0 my $flat_version = _flatten_recursive(@_);
1946 0         0 $flat_version =~ s{\n}{ }gxms;
1947 0         0 $flat_version =~ s{\A \s+ | \s+ \z}{}gxms;
1948 0         0 return $flat_version;
1949             }
1950              
1951             sub _flatten_recursive {
1952 0     0   0 my ($data) = @_;
1953 0   0     0 my $class = ref($data) || q{};
1954 0         0 $class =~ s{.*::}{}xms;
1955 0   0     0 my $type = reftype($data) || q{};
1956 0 0       0 if ($type eq 'HASH') {
    0          
1957 0 0       0 return q{} if $data->{ignore_toc};
1958 0         0 return "$class<" . _flatten_recursive($data->{content}) . '>';
1959             }
1960             elsif ($type eq 'ARRAY') {
1961 0         0 return join q{}, map {_flatten_recursive($_)} @{$data};
  0         0  
  0         0  
1962             }
1963             else {
1964 0   0     0 return $data || q{};
1965             }
1966             }
1967              
1968             # The content of a link is its default target...
1969             sub new {
1970 1     1   2 my ($classname, $data_ref) = @_;
1971 1         5 my $self = $classname->SUPER::new($data_ref);
1972              
1973 1 50       7 if (!$self->{target}) {
1974 0         0 $self->{target} = _flatten($self->{content});
1975 0         0 $self->{has_no_text} = 1;
1976             }
1977              
1978 1         3 return $self;
1979             }
1980              
1981             sub has_distinct_text {
1982 0     0   0 my ($self) = @_;
1983 0         0 return !$self->{has_no_text};
1984             }
1985              
1986             # Meta-formatter...
1987             package Perl6::Perldoc::FormattingCode::Named;
1988 55     55   287 use base 'Perl6::Perldoc::FormattingCode';
  55         94  
  55         13851  
1989              
1990             package Perl6::Perldoc::FormattingCode::M;
1991 55     55   299 use base 'Perl6::Perldoc::FormattingCode';
  55         93  
  55         16088  
1992              
1993             # The user-defined formatting code is open ended...
1994             sub new {
1995 2     2   6 my ($classname, $data_ref, $opt_ref) = @_;
1996            
1997 2 50       11 my $content_ref
1998             = defined $data_ref->{content} ? $data_ref->{content} : q{};
1999            
2000             # Install the necessary class to support this user-defined code...
2001 2 100       1349 if ($content_ref->[0] =~ s{\A \s* ($QUAL_IDENT) \s* :}{}xms) {
2002 1         4 $classname = "Perl6::Perldoc::FormattingCode::Named::$1";
2003 55     55   308 no strict qw< refs >;
  55         87  
  55         5883  
2004 1         1 push @{"${classname}::ISA"}, "Perl6::Perldoc::FormattingCode::Named";
  1         18  
2005             }
2006             # If there's no class specified, it's an error...
2007             else {
2008 1         5 Perl6::Perldoc::Parser::_err_missing_M_scheme(
2009             $data_ref->{range}, $opt_ref->{errors}
2010             );
2011             }
2012 2         41 return $classname->SUPER::new($data_ref);
2013             }
2014              
2015             # Note formatter...
2016             package Perl6::Perldoc::FormattingCode::N;
2017 55     55   261 use base 'Perl6::Perldoc::FormattingCode';
  55         84  
  55         13599  
2018              
2019             # Placement link formatter...
2020             package Perl6::Perldoc::FormattingCode::P;
2021 55     55   281 use base 'Perl6::Perldoc::FormattingCode';
  55         79  
  55         16382  
2022              
2023             # The content of a link is always its target...
2024             sub new {
2025 2     2   5 my ($classname, $data_ref) = @_;
2026 2         9 my $self = $classname->SUPER::new($data_ref);
2027              
2028 2         4 $self->{target} = join q{}, @{$self->{content}};
  2         15  
2029              
2030 2         5 return $self;
2031             }
2032              
2033              
2034             # Replacable item formatter...
2035             package Perl6::Perldoc::FormattingCode::R;
2036 55     55   294 use base 'Perl6::Perldoc::FormattingCode';
  55         93  
  55         13856  
2037              
2038             # Space-preserving formatter...
2039             package Perl6::Perldoc::FormattingCode::S;
2040 55     55   276 use base 'Perl6::Perldoc::FormattingCode';
  55         76  
  55         13462  
2041              
2042             # Terminal output formatter...
2043             package Perl6::Perldoc::FormattingCode::T;
2044 55     55   277 use base 'Perl6::Perldoc::FormattingCode';
  55         82  
  55         13579  
2045              
2046             # Unusual text formatter...
2047             package Perl6::Perldoc::FormattingCode::U;
2048 55     55   267 use base 'Perl6::Perldoc::FormattingCode';
  55         81  
  55         14484  
2049              
2050             # Verbatim formatter...
2051             package Perl6::Perldoc::FormattingCode::V;
2052 55     55   303 use base 'Perl6::Perldoc::FormattingCode';
  55         87  
  55         14291  
2053              
2054             # indeX formatter...
2055             package Perl6::Perldoc::FormattingCode::X;
2056 55     55   286 use base 'Perl6::Perldoc::FormattingCode';
  55         90  
  55         23864  
2057              
2058             # Index entries have to be extracted from the index target (or index content)...
2059             sub new {
2060 1     1   2 my ($classname, $data_ref) = @_;
2061              
2062 1 50       4 if (my $entries = delete $data_ref->{target}) {
2063 1         5 $data_ref->{entries} = [split /;/, $entries];
2064             }
2065             else { # No target --> content is target...
2066 0 0       0 $data_ref->{entries} = @{ $data_ref->{content} || [] } <= 1
  0         0  
2067             ? [ $data_ref->{content}[0] ]
2068 0 0       0 : [ [ @{ $data_ref->{content} } ] ]
2069             }
2070              
2071 1         6 return $classname->SUPER::new($data_ref);
2072             }
2073              
2074             sub entries {
2075 0     0   0 my ($self) = @_;
2076 0         0 my $vals_ref = $self->{entries};
2077 0 0       0 if (!wantarray) {
2078 0 0       0 if (@{ $vals_ref } > 1) {
  0         0  
2079 0 0       0 require Carp and Carp::carp(
2080             "Multivalued accessor entries() called in scalar context"
2081             );
2082             }
2083 0         0 return $vals_ref->[0];
2084             }
2085 0         0 return @{ $vals_ref };
  0         0  
2086             }
2087              
2088              
2089             # Zero-width formatter...
2090             package Perl6::Perldoc::FormattingCode::Z;
2091 55     55   366 use base 'Perl6::Perldoc::FormattingCode';
  55         96  
  55         14261  
2092              
2093              
2094             # Standard =table block...
2095             package Perl6::Perldoc::Block::table;
2096 55     55   277 use base 'Perl6::Perldoc::Block';
  55         80  
  55         101900  
2097              
2098             # A table's caption is its title...
2099             sub title {
2100 0     0   0 my ($self) = @_;
2101 0 0       0 if (my $title = $self->caption({ as_objects => 1 })) {
2102 0         0 return $title;
2103             }
2104 0         0 return;
2105             }
2106              
2107             # Rows accessor...
2108             sub rows {
2109 7     7   5199 my ($self) = @_;
2110 7         17 my $vals_ref = $self->{rows};
2111 7 50       27 if (!wantarray) {
2112 0 0       0 if (@{ $vals_ref } > 1) {
  0         0  
2113 0 0       0 require Carp and Carp::carp(
2114             "Multivalued accessor rows() called in scalar context"
2115             );
2116             }
2117 0         0 return $vals_ref->[0];
2118             }
2119 7         10 return @{ $vals_ref };
  7         30  
2120             }
2121              
2122             # Ctor needs to build table by parsing raw contents of block...
2123             sub new {
2124 7     7   14 my ($classname, $data, $opt_ref) = @_;
2125 7         40 $data->{rows} = _build_table(
2126             $data->{content}[0],
2127             $data->{allow},
2128             $data->{config_stack},
2129             );
2130              
2131 7         62 return $classname->SUPER::new($data);
2132             }
2133              
2134             # Regexes to help with table parsing...
2135             my $HWS = qr{ [ \t] }xms;
2136             my $ROW_SEP_LINE = qr{ ^ [-=_ \t|+]* \n }xms;
2137             my $NWS_ROW_SEP = qr{ [-=_+] }xms;
2138              
2139             # Utility maximum routine:
2140              
2141             sub _max {
2142 7     7   19 my $max = shift;
2143              
2144 7         18 for my $next (@_) {
2145 28 100       61 if ($next > $max) {
2146 7         11 $max = $next;
2147             }
2148             }
2149              
2150 7         18 return $max;
2151             }
2152              
2153             # Build an unpack template of the table column layout...
2154             sub _column_template {
2155 7     7   32 my @lines = split /\n/, shift;
2156              
2157 7         17 my $max_width = _max(map {length} @lines);
  35         54  
2158              
2159             # Compute the vector of column separator positions
2160 7         54 my $zvec = pack("b*", 0 x $max_width);
2161 7         23 my $rvec = pack("b*", 1 x $max_width);
2162 7         13 for my $line (@lines) {
2163             # Skip row separators...
2164 35 100       105 next if $line =~ /^[\s\-=_+|]*$/;
2165 30         55 $line .= q{ } x ($max_width - length $line);
2166 30         29 my $lvec = $zvec;
2167             # Mark column separators
2168 30         116 while ($line =~ /(\s+[+|\s]\s+)/g) {
2169 80         120 my $pos = pos($line)--;
2170 80         141 for my $p ($pos - length($1) .. $pos - 1) {
2171 797         1092 vec($lvec, $p, 1) = 1;
2172             }
2173             }
2174             # The result vector must match the line vector
2175 30         49 $rvec &= $lvec;
2176             }
2177 7         44 my $template = substr(join("", unpack("b*", $rvec)), 0, $max_width);
2178              
2179             # Add any missing external boundaries...
2180 7 100       40 my $prefix = $template =~ /^0/ ? 'A0' : q{};
2181 7 100       40 my $postfix = $template =~ /0$/ ? 'A0' : q{};
2182              
2183             # Convert bitmap to an 'unpack' extractor...
2184 7         35 $template =~ s{ (1+ | 0+) }{ 'A'.length($1) }egxms;
  38         93  
2185              
2186             # Return extractor...
2187 7         39 return $prefix.$template.$postfix;
2188             }
2189              
2190             # Build list of individual table rows for given separators...
2191             sub _build_table_rows {
2192 7     7   15 my ($text, $has_head, $cells_ref, $seps_ref, $allow_ref, $config_stack_ref)
2193             = @_;
2194              
2195             # Get extract template and subdivide cells:
2196 7         23 my $extractor = _column_template($text);
2197              
2198             # Parse rows and build representations...
2199 7         11 my @rows;
2200 7         14 for my $row_index (0..$#{$cells_ref}) {
  7         22  
2201             # Extract top and bottom row separators...
2202 50         245 my ($pre_sep, $post_sep)
2203 25         49 = map { [ unpack $extractor, $_ ] }
2204 25         46 @{$seps_ref}[$row_index, $row_index+1];
2205              
2206             # Extract cells themselves...
2207 25         30 my @cells;
2208 25         87 for my $line (split /\n/, $cells_ref->[$row_index]) {
2209 30         123 my @cols = unpack $extractor, $line;
2210 30         63 for my $col_index (0..$#cols) {
2211 186         128 push @{$cells[$col_index]}, $cols[$col_index];
  186         317  
2212             }
2213             }
2214              
2215             # Recombine the cells...
2216 25         27 my @cell_objs;
2217 25         36 my $left_sep = shift @cells;
2218 25         24 shift @{$pre_sep};
  25         31  
2219 25         30 shift @{$post_sep};
  25         30  
2220              
2221             CELL:
2222 25         47 while (@cells) {
2223 63         105 my ($cell, $right_sep) = splice(@cells, 0, 2);
2224              
2225 63 50       55 next CELL if @{$cell} == grep /\A (\s* \|) \s* \Z/xms, @{$cell};
  63         67  
  63         208  
2226              
2227 63         59 my ($top) = splice(@{$pre_sep}, 0, 2);
  63         88  
2228 63         62 my ($bottom) = splice(@{$post_sep}, 0, 2);
  63         77  
2229              
2230 63         68 my $content = join("\n", @{$cell});
  63         106  
2231              
2232             # Remove common horizontal whitespace prefix...
2233 63 50       233 if ($content =~ m{\A ([^\S\n]+)}xms) {
2234 0         0 my $prefix = $1;
2235 0         0 $content =~ s{^$prefix}{}gms; # No /x so whitespace significant
2236             }
2237              
2238 63 50       553 open my $fh, '<', \$content
2239             or die "Internal error: could not parse table content";
2240              
2241             # Recursively parse content as Pod...
2242 63         510 $content
2243             = Perl6::Perldoc::Parser->parse($fh, {
2244             all_pod=>1,
2245             allow=>$allow_ref,
2246             config_stack=>$config_stack_ref,
2247             })->{tree}->{content};
2248              
2249             # Add cell to list for row...
2250 63         107 push @cell_objs, bless {
2251             content => $content,
2252 63         403 left => join("\n", @{$left_sep}),
2253 63   100     245 right => join("\n", @{$right_sep}),
2254             top => $top,
2255             bottom => $bottom,
2256             header => $has_head && $row_index == 0,
2257             }, 'Perl6::Perldoc::Block::table::Cell';
2258              
2259             # Move left (right separator becomes left separator)
2260 63         358 $left_sep = $right_sep;
2261             }
2262              
2263             # Add the new row object...
2264 25         65 push @rows, bless {
2265             cells => \@cell_objs,
2266             }, 'Perl6::Perldoc::Block::table::Row';
2267              
2268             # Move downwards...
2269 25         56 $pre_sep = $post_sep;
2270             }
2271              
2272 7         41 return \@rows;
2273             }
2274              
2275             # Build entire table...
2276             sub _build_table {
2277 7     7   20 my ($text, $allow_ref, $config_stack_ref) = @_;
2278              
2279             # Remove surrounding blank lines...
2280 7         571 $text =~ s{\A ($HWS* \n)+ | (^ $HWS* \n?)+ \z}{}gxms;
2281              
2282             # Remove top/bottom border...
2283 7   50     181 $text =~ s{\A ($ROW_SEP_LINE)}{}xms; my $top_sep = $1 || q{};
  7         56  
2284 7   50     121 $text =~ s{\n ($ROW_SEP_LINE) \Z}{}xms; my $bottom_sep = $1 || q{};
  7         47  
2285              
2286             # Decompose into separated rows...
2287 7         156 my ($first_row, $first_sep, @rest) = split m{($ROW_SEP_LINE)}xms, $text;
2288 7   100     48 my $has_head = @rest != 0 && $first_sep =~ $NWS_ROW_SEP;
2289              
2290 7 100 66     67 my @rows = @rest == 0 ? (split m{(\n)}xms, $text)
    100          
2291             : @rest == 1 && !$bottom_sep ?
2292             ($first_row, $first_sep, split m{(\n)}xms, $rest[0])
2293             : ($first_row, $first_sep, @rest)
2294             ;
2295              
2296 7         27 my @separators = ($top_sep, @rows[grep {$_%2!=0} 0..$#rows], $bottom_sep);
  48         84  
2297 7         20 my @cells = @rows[grep {$_%2==0} 0..$#rows];
  48         71  
2298              
2299 7         37 return _build_table_rows(
2300             $text, $has_head, \@cells, \@separators, $allow_ref, $config_stack_ref
2301             );
2302             }
2303              
2304             # Class to represent individual table row...
2305             package Perl6::Perldoc::Block::table::Row;
2306              
2307             # Read-only accessor for individual cells...
2308             sub cells {
2309 25     25   25931 my ($self) = @_;
2310 25         60 my $vals_ref = $self->{cells};
2311 25 50       83 if (!wantarray) {
2312 0 0       0 if (@{ $vals_ref } > 1) {
  0         0  
2313 0 0       0 require Carp and Carp::carp(
2314             "Multivalued accessor cells() called in scalar context"
2315             );
2316             }
2317 0         0 return $vals_ref->[0];
2318             }
2319 25         34 return @{ $vals_ref };
  25         134  
2320             }
2321              
2322             # Class to represent individual table cell...
2323             package Perl6::Perldoc::Block::table::Cell;
2324              
2325             # Read-only content accessor...
2326             sub content {
2327 63     63   60283 my ($self) = @_;
2328 63         138 my $vals_ref = $self->{content};
2329 63 50       166 if (!wantarray) {
2330 0 0       0 if (@{ $vals_ref } > 1) {
  0         0  
2331 0 0       0 require Carp and Carp::carp(
2332             "Multivalued accessor content() called in scalar context"
2333             );
2334             }
2335 0         0 return $vals_ref->[0];
2336             }
2337 63         59 return @{ $vals_ref };
  63         275  
2338             }
2339              
2340             # Is this a header row?
2341             sub is_header {
2342 0     0   0 my ($self) = @_;
2343 0         0 return $self->{header};
2344             }
2345              
2346              
2347             1;
2348              
2349             __END__