File Coverage

blib/lib/YAML/Old/Loader.pm
Criterion Covered Total %
statement 401 440 91.1
branch 201 238 84.4
condition 73 82 89.0
subroutine 27 27 100.0
pod 0 1 0.0
total 702 788 89.0


line stmt bran cond sub pod time code
1             package YAML::Old::Loader;
2              
3 26     26   3196 use YAML::Old::Mo;
  26         50  
  26         205  
4             extends 'YAML::Old::Loader::Base';
5              
6 26     26   39893 use YAML::Old::Loader::Base;
  26         85  
  26         1048  
7 26     26   7532 use YAML::Old::Types;
  26         64  
  26         946  
8              
9             # Context constants
10 26     26   147 use constant LEAF => 1;
  26         44  
  26         1782  
11 26     26   137 use constant COLLECTION => 2;
  26         615  
  26         1566  
12 26     26   129 use constant VALUE => "\x07YAML\x07VALUE\x07";
  26         48  
  26         1459  
13 26     26   131 use constant COMMENT => "\x07YAML\x07COMMENT\x07";
  26         57  
  26         90729  
14              
15             # Common YAML character sets
16             my $ESCAPE_CHAR = '[\\x00-\\x08\\x0b-\\x0d\\x0e-\\x1f]';
17             my $FOLD_CHAR = '>';
18             my $LIT_CHAR = '|';
19             my $LIT_CHAR_RX = "\\$LIT_CHAR";
20              
21             sub load {
22 258     258 0 431 my $self = shift;
23 258   50     1709 $self->stream($_[0] || '');
24 258         1006 return $self->_parse();
25             }
26              
27             # Top level function for parsing. Parse each document in order and
28             # handle processing for YAML headers.
29             sub _parse {
30 258     258   425 my $self = shift;
31 258         426 my (%directives, $preface);
32 258         3265 $self->{stream} =~ s|\015\012|\012|g;
33 258         3234 $self->{stream} =~ s|\015|\012|g;
34 258         1232 $self->line(0);
35 258 100       960 $self->die('YAML_PARSE_ERR_BAD_CHARS')
36             if $self->stream =~ /$ESCAPE_CHAR/;
37 257 100 66     882 $self->die('YAML_PARSE_ERR_NO_FINAL_NEWLINE')
38             if length($self->stream) and
39             $self->{stream} !~ s/(.)\n\Z/$1/s;
40 256         1248 $self->lines([split /\x0a/, $self->stream, -1]);
41 256         2202 $self->line(1);
42             # Throw away any comments or blanks before the header (or start of
43             # content for headerless streams)
44 256         836 $self->_parse_throwaway_comments();
45 256         1669 $self->document(0);
46 256         1021 $self->documents([]);
47             # Add an "assumed" header if there is no header and the stream is
48             # not empty (after initial throwaways).
49 256 100       768 if (not $self->eos) {
50 218 100       653 if ($self->lines->[0] !~ /^---(\s|$)/) {
51 21         34 unshift @{$self->lines}, '---';
  21         63  
52 21         145 $self->{line}--;
53             }
54             }
55              
56             # Main Loop. Parse out all the top level nodes and return them.
57 256         905 while (not $self->eos) {
58 256         1241 $self->anchor2node({});
59 256         695 $self->{document}++;
60 256         914 $self->done(0);
61 256         915 $self->level(0);
62 256         945 $self->offset->[0] = -1;
63              
64 256 50       835 if ($self->lines->[0] =~ /^---\s*(.*)$/) {
65 256         154552 my @words = split /\s+/, $1;
66 256         10618 %directives = ();
67 256   100     1480 while (@words && $words[0] =~ /^#(\w+):(\S.*)$/) {
68 17         56 my ($key, $value) = ($1, $2);
69 17         25 shift(@words);
70 17 100       54 if (defined $directives{$key}) {
71 2         8 $self->warn('YAML_PARSE_WARN_MULTIPLE_DIRECTIVES',
72             $key, $self->document);
73 2         1529 next;
74             }
75 15         80 $directives{$key} = $value;
76             }
77 256         40604 $self->preface(join ' ', @words);
78             }
79             else {
80 0         0 $self->die('YAML_PARSE_ERR_NO_SEPARATOR');
81             }
82              
83 256 50       902 if (not $self->done) {
84 256         965 $self->_parse_next_line(COLLECTION);
85             }
86 254 100       916 if ($self->done) {
87 50         118 $self->{indent} = -1;
88 50         166 $self->content('');
89             }
90              
91 254   100     2009 $directives{YAML} ||= '1.0';
92 254   100     1713 $directives{TAB} ||= 'NONE';
93 254         1426 ($self->{major_version}, $self->{minor_version}) =
94             split /\./, $directives{YAML}, 2;
95 254 100       1064 $self->die('YAML_PARSE_ERR_BAD_MAJOR_VERSION', $directives{YAML})
96             if $self->major_version ne '1';
97 253 100       992 $self->warn('YAML_PARSE_WARN_BAD_MINOR_VERSION', $directives{YAML})
98             if $self->minor_version ne '0';
99 253 100       2631 $self->die('Unrecognized TAB policy')
100             unless $directives{TAB} =~ /^(NONE|\d+)(:HARD)?$/;
101              
102 252         354 push @{$self->documents}, $self->_parse_node();
  252         2956  
103             }
104 229 100       828 return wantarray ? @{$self->documents} : $self->documents->[-1];
  116         356  
105             }
106              
107             # This function is the dispatcher for parsing each node. Every node
108             # recurses back through here. (Inlines are an exception as they have
109             # their own sub-parser.)
110             sub _parse_node {
111 1827     1827   2751 my $self = shift;
112 1827         4215 my $preface = $self->preface;
113 1827         4780 $self->preface('');
114 1827         4575 my ($node, $type, $indicator, $escape, $chomp) = ('') x 5;
115 1827         3285 my ($anchor, $alias, $explicit, $implicit, $class) = ('') x 5;
116 1827         3986 ($anchor, $alias, $explicit, $implicit, $preface) =
117             $self->_parse_qualifiers($preface);
118 1820 100       5502 if ($anchor) {
119 16         110 $self->anchor2node->{$anchor} = CORE::bless [], 'YAML-anchor2node';
120             }
121 1820         5190 $self->inline('');
122 1820         5312 while (length $preface) {
123 1228         3215 my $line = $self->line - 1;
124 1228 100       9183 if ($preface =~ s/^($FOLD_CHAR|$LIT_CHAR_RX)(-|\+)?\d*\s*//) {
125 56         216 $indicator = $1;
126 56 100       301 $chomp = $2 if defined($2);
127             }
128             else {
129 1172 100       2846 $self->die('YAML_PARSE_ERR_TEXT_AFTER_INDICATOR') if $indicator;
130 1171         3385 $self->inline($preface);
131 1171         4457 $preface = '';
132             }
133             }
134 1819 100       6769 if ($alias) {
    100          
    100          
    100          
135 17 100       56 $self->die('YAML_PARSE_ERR_NO_ANCHOR', $alias)
136             unless defined $self->anchor2node->{$alias};
137 16 50       75 if (ref($self->anchor2node->{$alias}) ne 'YAML-anchor2node') {
138 16         47 $node = $self->anchor2node->{$alias};
139             }
140             else {
141 0         0 $node = do {my $sv = "*$alias"};
  0         0  
142 0         0 push @{$self->anchor2node->{$alias}}, [\$node, $self->line];
  0         0  
143             }
144             }
145             elsif (length $self->inline) {
146 1171         2940 $node = $self->_parse_inline(1, $implicit, $explicit);
147 1165 100       3134 if (length $self->inline) {
148 1         7 $self->die('YAML_PARSE_ERR_SINGLE_LINE');
149             }
150             }
151             elsif ($indicator eq $LIT_CHAR) {
152 38         71 $self->{level}++;
153 38         203 $node = $self->_parse_block($chomp);
154 38 50       197 $node = $self->_parse_implicit($node) if $implicit;
155 38         179 $self->{level}--;
156             }
157             elsif ($indicator eq $FOLD_CHAR) {
158 17         34 $self->{level}++;
159 17         61 $node = $self->_parse_unfold($chomp);
160 17 100       133 $node = $self->_parse_implicit($node) if $implicit;
161 16         31 $self->{level}--;
162             }
163             else {
164 576         924 $self->{level}++;
165 576   100     1487 $self->offset->[$self->level] ||= 0;
166 576 100       1886 if ($self->indent == $self->offset->[$self->level]) {
167 569 100       1513 if ($self->content =~ /^-( |$)/) {
    50          
    0          
168 133         472 $node = $self->_parse_seq($anchor);
169             }
170             elsif ($self->content =~ /(^\?|\:( |$))/) {
171 436         1418 $node = $self->_parse_mapping($anchor);
172             }
173             elsif ($preface =~ /^\s*$/) {
174 0         0 $node = $self->_parse_implicit('');
175             }
176             else {
177 0         0 $self->die('YAML_PARSE_ERR_BAD_NODE');
178             }
179             }
180             else {
181 7         17 $node = undef;
182             }
183 555         2594 $self->{level}--;
184             }
185 1789         5612 $#{$self->offset} = $self->level;
  1789         4498  
186              
187 1789 100       4494 if ($explicit) {
188 66 50       167 if ($class) {
189 0 0       0 if (not ref $node) {
190 0         0 my $copy = $node;
191 0         0 undef $node;
192 0         0 $node = \$copy;
193             }
194 0         0 CORE::bless $node, $class;
195             }
196             else {
197 66         215 $node = $self->_parse_explicit($node, $explicit);
198             }
199             }
200 1788 100       4190 if ($anchor) {
201 16 100       56 if (ref($self->anchor2node->{$anchor}) eq 'YAML-anchor2node') {
202             # XXX Can't remember what this code actually does
203 6         11 for my $ref (@{$self->anchor2node->{$anchor}}) {
  6         103  
204 0         0 ${$ref->[0]} = $node;
  0         0  
205 0         0 $self->warn('YAML_LOAD_WARN_UNRESOLVED_ALIAS',
206             $anchor, $ref->[1]);
207             }
208             }
209 16         57 $self->anchor2node->{$anchor} = $node;
210             }
211 1788         17866 return $node;
212             }
213              
214             # Preprocess the qualifiers that may be attached to any node.
215             sub _parse_qualifiers {
216 4359     4359   5429 my $self = shift;
217 4359         5731 my ($preface) = @_;
218 4359         7740 my ($anchor, $alias, $explicit, $implicit, $token) = ('') x 5;
219 4359         18651 $self->inline('');
220 4359         13887 while ($preface =~ /^[&*!]/) {
221 116         371 my $line = $self->line - 1;
222 116 100       844 if ($preface =~ s/^\!(\S+)\s*//) {
    100          
    100          
    50          
223 70 100       187 $self->die('YAML_PARSE_ERR_MANY_EXPLICIT') if $explicit;
224 69         289 $explicit = $1;
225             }
226             elsif ($preface =~ s/^\!\s*//) {
227 5 100       19 $self->die('YAML_PARSE_ERR_MANY_IMPLICIT') if $implicit;
228 4         17 $implicit = 1;
229             }
230             elsif ($preface =~ s/^\&([^ ,:]+)\s*//) {
231 20         51 $token = $1;
232 20 100       100 $self->die('YAML_PARSE_ERR_BAD_ANCHOR')
233             unless $token =~ /^[a-zA-Z0-9]+$/;
234 19 100       54 $self->die('YAML_PARSE_ERR_MANY_ANCHOR') if $anchor;
235 18 50       54 $self->die('YAML_PARSE_ERR_ANCHOR_ALIAS') if $alias;
236 18         62 $anchor = $token;
237             }
238             elsif ($preface =~ s/^\*([^ ,:]+)\s*//) {
239 21         237 $token = $1;
240 21 100       121 $self->die('YAML_PARSE_ERR_BAD_ALIAS')
241             unless $token =~ /^[a-zA-Z0-9]+$/;
242 20 100       58 $self->die('YAML_PARSE_ERR_MANY_ALIAS') if $alias;
243 19 100       54 $self->die('YAML_PARSE_ERR_ANCHOR_ALIAS') if $anchor;
244 18         58 $alias = $token;
245             }
246             }
247 4352         21349 return ($anchor, $alias, $explicit, $implicit, $preface);
248             }
249              
250             # Morph a node to it's explicit type
251             sub _parse_explicit {
252 83     83   138 my $self = shift;
253 83         135 my ($node, $explicit) = @_;
254 83         112 my ($type, $class);
255 83 100       599 if ($explicit =~ /^\!?perl\/(hash|array|ref|scalar)(?:\:(\w(\w|\:\:)*)?)?$/) {
256 47   50     385 ($type, $class) = (($1 || ''), ($2 || ''));
      100        
257              
258             # FIXME # die unless uc($type) eq ref($node) ?
259              
260 47 100       137 if ( $type eq "ref" ) {
261 21 100 66     150 $self->die('YAML_LOAD_ERR_NO_DEFAULT_VALUE', 'XXX', $explicit)
262             unless exists $node->{VALUE()} and scalar(keys %$node) == 1;
263              
264 20         40 my $value = $node->{VALUE()};
265 20         34 $node = \$value;
266             }
267              
268 46 100 100     295 if ( $type eq "scalar" and length($class) and !ref($node) ) {
      100        
269 3         8 my $value = $node;
270 3         7 $node = \$value;
271             }
272              
273 46 100       112 if ( length($class) ) {
274 20         57 CORE::bless($node, $class);
275             }
276              
277 46         120 return $node;
278             }
279 36 100 100     393 if ($explicit =~ m{^!?perl/(glob|regexp|code)(?:\:(\w(\w|\:\:)*)?)?$}) {
    100          
    100          
280 14   50     120 ($type, $class) = (($1 || ''), ($2 || ''));
      100        
281 14         34 my $type_class = "YAML::Old::Type::$type";
282 26     26   232 no strict 'refs';
  26         64  
  26         151484  
283 14 50       182 if ($type_class->can('yaml_load')) {
284 14         67 return $type_class->yaml_load($node, $class, $self);
285             }
286             else {
287 0         0 $self->die('YAML_LOAD_ERR_NO_CONVERT', 'XXX', $explicit);
288             }
289             }
290             # This !perl/@Foo and !perl/$Foo are deprecated but still parsed
291             elsif ($YAML::Old::TagClass->{$explicit} ||
292             $explicit =~ m{^perl/(\@|\$)?([a-zA-Z](\w|::)+)$}
293             ) {
294 13   66     57 $class = $YAML::Old::TagClass->{$explicit} || $2;
295 13 100       202 if ($class->can('yaml_load')) {
296 4         43 require YAML::Old::Node;
297 4         36 return $class->yaml_load(YAML::Old::Node->new($node, $explicit));
298             }
299             else {
300 9 50       27 if (ref $node) {
301 9         128 return CORE::bless $node, $class;
302             }
303             else {
304 0         0 return CORE::bless \$node, $class;
305             }
306             }
307             }
308             elsif (ref $node) {
309 5         36 require YAML::Old::Node;
310 5         34 return YAML::Old::Node->new($node, $explicit);
311             }
312             else {
313             # XXX This is likely wrong. Failing test:
314             # --- !unknown 'scalar value'
315 4         13 return $node;
316             }
317             }
318              
319             # Parse a YAML mapping into a Perl hash
320             sub _parse_mapping {
321 469     469   848 my $self = shift;
322 469         674 my ($anchor) = @_;
323 469         790 my $mapping = {};
324 469         1353 $self->anchor2node->{$anchor} = $mapping;
325 469         773 my $key;
326 469   100     1291 while (not $self->done and $self->indent == $self->offset->[$self->level]) {
327             # If structured key:
328 1291 100       6542 if ($self->{content} =~ s/^\?\s*//) {
    100          
    50          
329 4         11 $self->preface($self->content);
330 4         11 $self->_parse_next_line(COLLECTION);
331 4         15 $key = $self->_parse_node();
332 4         11 $key = "$key";
333             }
334             # If "default" key (equals sign)
335             elsif ($self->{content} =~ s/^\=\s*//) {
336 22         76 $key = VALUE;
337             }
338             # If "comment" key (slash slash)
339             elsif ($self->{content} =~ s/^\=\s*//) {
340 0         0 $key = COMMENT;
341             }
342             # Regular scalar key:
343             else {
344 1265         3166 $self->inline($self->content);
345 1265         19037 $key = $self->_parse_inline();
346 1265         1867 $key = "$key";
347 1265         3536 $self->content($self->inline);
348 1265         3523 $self->inline('');
349             }
350              
351 1291 100       8311 unless ($self->{content} =~ s/^:\s*//) {
352 1         5 $self->die('YAML_LOAD_ERR_BAD_MAP_ELEMENT');
353             }
354 1290         3533 $self->preface($self->content);
355 1290         3393 my $line = $self->line;
356 1290         2754 $self->_parse_next_line(COLLECTION);
357 1289         4402 my $value = $self->_parse_node();
358 1289 100       4653 if (exists $mapping->{$key}) {
359 1         7 $self->warn('YAML_LOAD_WARN_DUPLICATE_KEY');
360             }
361             else {
362 1288         6989 $mapping->{$key} = $value;
363             }
364             }
365 467         1492 return $mapping;
366             }
367              
368             # Parse a YAML sequence into a Perl array
369             sub _parse_seq {
370 133     133   294 my $self = shift;
371 133         300 my ($anchor) = @_;
372 133         267 my $seq = [];
373 133         571 $self->anchor2node->{$anchor} = $seq;
374 133   100     475 while (not $self->done and $self->indent == $self->offset->[$self->level]) {
375 318 100       1035 if ($self->content =~ /^-(?: (.*))?$/) {
376 317 100       1337 $self->preface(defined($1) ? $1 : '');
377             }
378             else {
379 1         5 $self->die('YAML_LOAD_ERR_BAD_SEQ_ELEMENT');
380             }
381 317 100       2181 if ($self->preface =~ /^(\s*)(\w.*\:(?: |$).*)$/) {
382 33         101 $self->indent($self->offset->[$self->level] + 2 + length($1));
383 33         100 $self->content($2);
384 33         105 $self->level($self->level + 1);
385 33         97 $self->offset->[$self->level] = $self->indent;
386 33         110 $self->preface('');
387 33         103 push @$seq, $self->_parse_mapping('');
388 33         59 $self->{level}--;
389 33         87 $#{$self->offset} = $self->level;
  33         86  
390             }
391             else {
392 284         902 $self->_parse_next_line(COLLECTION);
393 282         1210 push @$seq, $self->_parse_node();
394             }
395             }
396 114         352 return $seq;
397             }
398              
399             # Parse an inline value. Since YAML supports inline collections, this is
400             # the top level of a sub parsing.
401             sub _parse_inline {
402 2532     2532   3461 my $self = shift;
403 2532         4241 my ($top, $top_implicit, $top_explicit) = (@_, '', '', '');
404 2532         43977 $self->{inline} =~ s/^\s*(.*)\s*$/$1/; # OUCH - mugwump
405 2532         6017 my ($node, $anchor, $alias, $explicit, $implicit) = ('') x 5;
406 2532         7105 ($anchor, $alias, $explicit, $implicit, $self->{inline}) =
407             $self->_parse_qualifiers($self->inline);
408 2532 50       7197 if ($anchor) {
409 0         0 $self->anchor2node->{$anchor} = CORE::bless [], 'YAML-anchor2node';
410             }
411 2532   66     8637 $implicit ||= $top_implicit;
412 2532   100     14901 $explicit ||= $top_explicit;
413 2532         3791 ($top_implicit, $top_explicit) = ('', '');
414 2532 50       8412 if ($alias) {
    100          
    100          
    100          
    100          
415 0 0       0 $self->die('YAML_PARSE_ERR_NO_ANCHOR', $alias)
416             unless defined $self->anchor2node->{$alias};
417 0 0       0 if (ref($self->anchor2node->{$alias}) ne 'YAML-anchor2node') {
418 0         0 $node = $self->anchor2node->{$alias};
419             }
420             else {
421 0         0 $node = do {my $sv = "*$alias"};
  0         0  
422 0         0 push @{$self->anchor2node->{$alias}}, [\$node, $self->line];
  0         0  
423             }
424             }
425             elsif ($self->inline =~ /^\{/) {
426 23         83 $node = $self->_parse_inline_mapping($anchor);
427             }
428             elsif ($self->inline =~ /^\[/) {
429 27         88 $node = $self->_parse_inline_seq($anchor);
430             }
431             elsif ($self->inline =~ /^"/) {
432 21         86 $node = $self->_parse_inline_double_quoted();
433 20         105 $node = $self->_unescape($node);
434 20 100       88 $node = $self->_parse_implicit($node) if $implicit;
435             }
436             elsif ($self->inline =~ /^'/) {
437 48         167 $node = $self->_parse_inline_single_quoted();
438 47 50       149 $node = $self->_parse_implicit($node) if $implicit;
439             }
440             else {
441 2413 100       4085 if ($top) {
442 1079         2663 $node = $self->inline;
443 1079         3285 $self->inline('');
444             }
445             else {
446 1334         2711 $node = $self->_parse_inline_simple();
447             }
448 2412 100       9903 $node = $self->_parse_implicit($node) unless $explicit;
449             }
450 2525 100       7859 if ($explicit) {
451 17         63 $node = $self->_parse_explicit($node, $explicit);
452             }
453 2525 50       12061 if ($anchor) {
454 0 0       0 if (ref($self->anchor2node->{$anchor}) eq 'YAML-anchor2node') {
455 0         0 for my $ref (@{$self->anchor2node->{$anchor}}) {
  0         0  
456 0         0 ${$ref->[0]} = $node;
  0         0  
457 0         0 $self->warn('YAML_LOAD_WARN_UNRESOLVED_ALIAS',
458             $anchor, $ref->[1]);
459             }
460             }
461 0         0 $self->anchor2node->{$anchor} = $node;
462             }
463 2525         9800 return $node;
464             }
465              
466             # Parse the inline YAML mapping into a Perl hash
467             sub _parse_inline_mapping {
468 23     23   34 my $self = shift;
469 23         36 my ($anchor) = @_;
470 23         39 my $node = {};
471 23         73 $self->anchor2node->{$anchor} = $node;
472              
473 23 50       176 $self->die('YAML_PARSE_ERR_INLINE_MAP')
474             unless $self->{inline} =~ s/^\{\s*//;
475 23         226 while (not $self->{inline} =~ s/^\s*\}//) {
476 23         65 my $key = $self->_parse_inline();
477 23 100       148 $self->die('YAML_PARSE_ERR_INLINE_MAP')
478             unless $self->{inline} =~ s/^\: \s*//;
479 22         112 my $value = $self->_parse_inline();
480 22 50       57 if (exists $node->{$key}) {
481 0         0 $self->warn('YAML_LOAD_WARN_DUPLICATE_KEY');
482             }
483             else {
484 22         67 $node->{$key} = $value;
485             }
486 22 100       66 next if $self->inline =~ /^\s*\}/;
487 9 50       70 $self->die('YAML_PARSE_ERR_INLINE_MAP')
488             unless $self->{inline} =~ s/^\,\s*//;
489             }
490 22         129 return $node;
491             }
492              
493             # Parse the inline YAML sequence into a Perl array
494             sub _parse_inline_seq {
495 27     27   45 my $self = shift;
496 27         39 my ($anchor) = @_;
497 27         52 my $node = [];
498 27         85 $self->anchor2node->{$anchor} = $node;
499              
500 27 50       165 $self->die('YAML_PARSE_ERR_INLINE_SEQUENCE')
501             unless $self->{inline} =~ s/^\[\s*//;
502 27         138 while (not $self->{inline} =~ s/^\s*\]//) {
503 51         149 my $value = $self->_parse_inline();
504 50         100 push @$node, $value;
505 50 100       130 next if $self->inline =~ /^\s*\]/;
506 33 100       236 $self->die('YAML_PARSE_ERR_INLINE_SEQUENCE')
507             unless $self->{inline} =~ s/^\,\s*//;
508             }
509 25         58 return $node;
510             }
511              
512             # Parse the inline double quoted string.
513             sub _parse_inline_double_quoted {
514 21     21   39 my $self = shift;
515 21         100 my $node;
516             # https://rt.cpan.org/Public/Bug/Display.html?id=90593
517 21 100       75 if ($self->inline =~ /^"((?:(?:\\"|[^"]){0,32766}){0,32766})"\s*(.*)$/) {
518 20         921 $node = $1;
519 20         104 $self->inline($2);
520 20         17154 $node =~ s/\\"/"/g;
521             }
522             else {
523 1         4 $self->die('YAML_PARSE_ERR_BAD_DOUBLE');
524             }
525 20         1038 return $node;
526             }
527              
528              
529             # Parse the inline single quoted string.
530             sub _parse_inline_single_quoted {
531 48     48   94 my $self = shift;
532 48         85 my $node;
533 48 100       147 if ($self->inline =~ /^'((?:(?:''|[^']){0,32766}){0,32766})'\s*(.*)$/) {
534 47         120 $node = $1;
535 47         156 $self->inline($2);
536 47         196 $node =~ s/''/'/g;
537             }
538             else {
539 1         4 $self->die('YAML_PARSE_ERR_BAD_SINGLE');
540             }
541 47         144 return $node;
542             }
543              
544             # Parse the inline unquoted string and do implicit typing.
545             sub _parse_inline_simple {
546 1334     1334   1528 my $self = shift;
547 1334         1322 my $value;
548 1334 100       3366 if ($self->inline =~ /^(|[^!@#%^&*].*?)(?=[\[\]\{\},]|, |: |- |:\s*$|$)/) {
549 1333         2696 $value = $1;
550 1333         5799 substr($self->{inline}, 0, length($1)) = '';
551             }
552             else {
553 1         3 $self->die('YAML_PARSE_ERR_BAD_INLINE_IMPLICIT', $value);
554             }
555 1333         3569 return $value;
556             }
557              
558             sub _parse_implicit {
559 2407     2407   3087 my $self = shift;
560 2407         3698 my ($value) = @_;
561 2407         11944 $value =~ s/\s*$//;
562 2407 100       5806 return $value if $value eq '';
563 2403 100       5236 return undef if $value =~ /^~$/;
564 2400 100 100     15284 return $value
565             unless $value =~ /^[\@\`\^]/ or
566             $value =~ /^[\-\?]\s/;
567 2         8 $self->die('YAML_PARSE_ERR_BAD_IMPLICIT', $value);
568             }
569              
570             # Unfold a YAML multiline scalar into a single string.
571             sub _parse_unfold {
572 17     17   30 my $self = shift;
573 17         29 my ($chomp) = @_;
574 17         115 my $node = '';
575 17         27 my $space = 0;
576 17   100     64 while (not $self->done and $self->indent == $self->offset->[$self->level]) {
577 54         179 $node .= $self->content. "\n";
578 54         190 $self->_parse_next_line(LEAF);
579             }
580 17         243 $node =~ s/^(\S.*)\n(?=\S)/$1 /gm;
581 17         53 $node =~ s/^(\S.*)\n(\n+\S)/$1$2/gm;
582 17 100       274 $node =~ s/\n*\Z// unless $chomp eq '+';
583 17 100       54 $node .= "\n" unless $chomp;
584 17         103 return $node;
585             }
586              
587             # Parse a YAML block style scalar. This is like a Perl here-document.
588             sub _parse_block {
589 38     38   65 my $self = shift;
590 38         55 my ($chomp) = @_;
591 38         64 my $node = '';
592 38   100     108 while (not $self->done and $self->indent == $self->offset->[$self->level]) {
593 130         564 $node .= $self->content . "\n";
594 130         337 $self->_parse_next_line(LEAF);
595             }
596 38 100       138 return $node if '+' eq $chomp;
597 35         624 $node =~ s/\n*\Z/\n/;
598 35 100       139 $node =~ s/\n\Z// if $chomp eq '-';
599 35         99 return $node;
600             }
601              
602             # Handle Perl style '#' comments. Comments must be at the same indentation
603             # level as the collection line following them.
604             sub _parse_throwaway_comments {
605 2433     2433   3339 my $self = shift;
606 2433   100     2651 while (@{$self->lines} and
  2960         6954  
607             $self->lines->[0] =~ m{^\s*(\#|$)}
608             ) {
609 527         809 shift @{$self->lines};
  527         1235  
610 527         996 $self->{line}++;
611             }
612 2433         3684 $self->eos($self->{done} = not @{$self->lines});
  2433         6791  
613             }
614              
615             # This is the routine that controls what line is being parsed. It gets called
616             # once for each line in the YAML stream.
617             #
618             # This routine must:
619             # 1) Skip past the current line
620             # 2) Determine the indentation offset for a new level
621             # 3) Find the next _content_ line
622             # A) Skip over any throwaways (Comments/blanks)
623             # B) Set $self->indent, $self->content, $self->line
624             # 4) Expand tabs appropriately
625             sub _parse_next_line {
626 2018     2018   2891 my $self = shift;
627 2018         2706 my ($type) = @_;
628 2018         4710 my $level = $self->level;
629 2018         5126 my $offset = $self->offset->[$level];
630 2018 50       5571 $self->die('YAML_EMIT_ERR_BAD_LEVEL') unless defined $offset;
631 2018         3345 shift @{$self->lines};
  2018         5070  
632 2018         3205 $self->eos($self->{done} = not @{$self->lines});
  2018         4930  
633 2018 100       5166 return if $self->eos;
634 1818         3792 $self->{line}++;
635              
636             # Determine the offset for a new leaf node
637 1818 100 100     4186 if ($self->preface =~
    100          
638             qr/(?:^|\s)(?:$FOLD_CHAR|$LIT_CHAR_RX)(?:-|\+)?(\d*)\s*$/
639             ) {
640 56 100 100     264 $self->die('YAML_PARSE_ERR_ZERO_INDENT')
641             if length($1) and $1 == 0;
642 55         89 $type = LEAF;
643 55 100       140 if (length($1)) {
644 4         15 $self->offset->[$level + 1] = $offset + $1;
645             }
646             else {
647             # First get rid of any comments.
648 51   66     81 while (@{$self->lines} && ($self->lines->[0] =~ /^\s*#/)) {
  51         165  
649 1 50       6 $self->lines->[0] =~ /^( *)/ or die;
650 1 50       13 last unless length($1) <= $offset;
651 0         0 shift @{$self->lines};
  0         0  
652 0         0 $self->{line}++;
653             }
654 51         104 $self->eos($self->{done} = not @{$self->lines});
  51         147  
655 51 50       145 return if $self->eos;
656 51 100 66     160 if ($self->lines->[0] =~ /^( *)\S/ and length($1) > $offset) {
657 50         187 $self->offset->[$level+1] = length($1);
658             }
659             else {
660 1         6 $self->offset->[$level+1] = $offset + 1;
661             }
662             }
663 55         251 $offset = $self->offset->[++$level];
664             }
665             # Determine the offset for a new collection level
666             elsif ($type == COLLECTION and
667             $self->preface =~ /^(\s*(\!\S*|\&\S+))*\s*$/) {
668 576         1232 $self->_parse_throwaway_comments();
669 576 50       1811 if ($self->eos) {
670 0         0 $self->offset->[$level+1] = $offset + 1;
671 0         0 return;
672             }
673             else {
674 576 50       1413 $self->lines->[0] =~ /^( *)\S/ or die;
675 576 100       1639 if (length($1) > $offset) {
676 574         1717 $self->offset->[$level+1] = length($1);
677             }
678             else {
679 2         8 $self->offset->[$level+1] = $offset + 1;
680             }
681             }
682 576         1897 $offset = $self->offset->[++$level];
683             }
684              
685 1817 100       5681 if ($type == LEAF) {
686 216   100     251 while (@{$self->lines} and
  227   100     598  
687             $self->lines->[0] =~ m{^( *)(\#)} and
688             length($1) < $offset
689             ) {
690 11         16 shift @{$self->lines};
  11         112  
691 11         23 $self->{line}++;
692             }
693 216         415 $self->eos($self->{done} = not @{$self->lines});
  216         488  
694             }
695             else {
696 1601         3046 $self->_parse_throwaway_comments();
697             }
698 1817 100       5151 return if $self->eos;
699              
700 1810 100       6211 if ($self->lines->[0] =~ /^---(\s|$)/) {
701 38         113 $self->done(1);
702 38         110 return;
703             }
704 1772 100 100     7680 if ($type == LEAF and
    100          
705             $self->lines->[0] =~ /^ {$offset}(.*)$/
706             ) {
707 169         483 $self->indent($offset);
708 169         456 $self->content($1);
709             }
710             elsif ($self->lines->[0] =~ /^\s*$/) {
711 15         43 $self->indent($offset);
712 15         37 $self->content('');
713             }
714             else {
715 1588         4067 $self->lines->[0] =~ /^( *)(\S.*)$/;
716 1588         10328 while ($self->offset->[$level] > length($1)) {
717 378         1039 $level--;
718             }
719 1588 100       4428 $self->die('YAML_PARSE_ERR_INCONSISTENT_INDENTATION')
720             if $self->offset->[$level] != length($1);
721 1584         4902 $self->indent(length($1));
722 1584         5342 $self->content($2);
723             }
724 1768 50       5420 $self->die('YAML_PARSE_ERR_INDENTATION')
725             if $self->indent - $offset > 1;
726             }
727              
728             #==============================================================================
729             # Utility subroutines.
730             #==============================================================================
731              
732             # Printable characters for escapes
733             my %unescapes = (
734             0 => "\x00",
735             a => "\x07",
736             t => "\x09",
737             n => "\x0a",
738             'v' => "\x0b", # Potential v-string error on 5.6.2 if not quoted
739             f => "\x0c",
740             r => "\x0d",
741             e => "\x1b",
742             '\\' => '\\',
743             );
744              
745             # Transform all the backslash style escape characters to their literal meaning
746             sub _unescape {
747 20     20   49 my $self = shift;
748 20         47 my ($node) = @_;
749 20         3209 $node =~ s/\\([never\\fart0]|x([0-9a-fA-F]{2}))/
750 17 50       113 (length($1)>1)?pack("H2",$2):$unescapes{$1}/gex;
751 20         60 return $node;
752             }
753              
754             1;