File Coverage

blib/lib/YAML/Old/Loader.pm
Criterion Covered Total %
statement 409 448 91.2
branch 203 238 85.2
condition 83 97 85.5
subroutine 28 28 100.0
pod 0 1 0.0
total 723 812 89.0


line stmt bran cond sub pod time code
1             package YAML::Old::Loader;
2              
3 32     32   2487 use YAML::Old::Mo;
  32         64  
  32         182  
4             extends 'YAML::Old::Loader::Base';
5              
6 32     32   10678 use YAML::Old::Loader::Base;
  32         88  
  32         873  
7 32     32   5740 use YAML::Old::Types;
  32         78  
  32         668  
8 32     32   163 use YAML::Old::Node;
  32         90  
  32         1463  
9              
10             # Context constants
11 32     32   174 use constant LEAF => 1;
  32         58  
  32         1483  
12 32     32   175 use constant COLLECTION => 2;
  32         67  
  32         1471  
13 32     32   166 use constant VALUE => "\x07YAML\x07VALUE\x07";
  32         60  
  32         1351  
14 32     32   162 use constant COMMENT => "\x07YAML\x07COMMENT\x07";
  32         62  
  32         48846  
15              
16             # Common YAML character sets
17             my $ESCAPE_CHAR = '[\\x00-\\x08\\x0b-\\x0d\\x0e-\\x1f]';
18             my $FOLD_CHAR = '>';
19             my $LIT_CHAR = '|';
20             my $LIT_CHAR_RX = "\\$LIT_CHAR";
21              
22             sub load {
23 277     277 0 496 my $self = shift;
24 277   50     1169 $self->stream($_[0] || '');
25 277         661 return $self->_parse();
26             }
27              
28             # Top level function for parsing. Parse each document in order and
29             # handle processing for YAML headers.
30             sub _parse {
31 277     277   464 my $self = shift;
32 277         471 my (%directives, $preface);
33 277         902 $self->{stream} =~ s|\015\012|\012|g;
34 277         763 $self->{stream} =~ s|\015|\012|g;
35 277         917 $self->line(0);
36 277 100       680 $self->die('YAML_PARSE_ERR_BAD_CHARS')
37             if $self->stream =~ /$ESCAPE_CHAR/;
38 276         2408 $self->{stream} =~ s/(.)\n\Z/$1/s;
39 276         842 $self->lines([split /\x0a/, $self->stream, -1]);
40 276         955 $self->line(1);
41             # Throw away any comments or blanks before the header (or start of
42             # content for headerless streams)
43 276         757 $self->_parse_throwaway_comments();
44 276         855 $self->document(0);
45 276         929 $self->documents([]);
46             # Add an "assumed" header if there is no header and the stream is
47             # not empty (after initial throwaways).
48 276 100       656 if (not $self->eos) {
49 238 100       573 if ($self->lines->[0] !~ /^---(\s|$)/) {
50 31         53 unshift @{$self->lines}, '---';
  31         76  
51 31         62 $self->{line}--;
52             }
53             }
54              
55             # Main Loop. Parse out all the top level nodes and return them.
56 276         739 while (not $self->eos) {
57 276         920 $self->anchor2node({});
58 276         507 $self->{document}++;
59 276         816 $self->done(0);
60 276         770 $self->level(0);
61 276         690 $self->offset->[0] = -1;
62              
63 276 50       627 if ($self->lines->[0] =~ /^---\s*(.*)$/) {
64 276         58042 my @words = split /\s+/, $1;
65 276         618 %directives = ();
66 276   100     1131 while (@words && $words[0] =~ /^#(\w+):(\S.*)$/) {
67 17         55 my ($key, $value) = ($1, $2);
68 17         35 shift(@words);
69 17 100       50 if (defined $directives{$key}) {
70 2         6 $self->warn('YAML_PARSE_WARN_MULTIPLE_DIRECTIVES',
71             $key, $self->document);
72 2         778 next;
73             }
74 15         68 $directives{$key} = $value;
75             }
76 276         11239 $self->preface(join ' ', @words);
77             }
78             else {
79 0         0 $self->die('YAML_PARSE_ERR_NO_SEPARATOR');
80             }
81              
82 276 50       761 if (not $self->done) {
83 276         629 $self->_parse_next_line(COLLECTION);
84             }
85 274 100       684 if ($self->done) {
86 53         105 $self->{indent} = -1;
87 53         144 $self->content('');
88             }
89              
90 274   100     1413 $directives{YAML} ||= '1.0';
91 274   100     1189 $directives{TAB} ||= 'NONE';
92             ($self->{major_version}, $self->{minor_version}) =
93 274         958 split /\./, $directives{YAML}, 2;
94             $self->die('YAML_PARSE_ERR_BAD_MAJOR_VERSION', $directives{YAML})
95 274 100       810 if $self->major_version ne '1';
96             $self->warn('YAML_PARSE_WARN_BAD_MINOR_VERSION', $directives{YAML})
97 273 100       803 if $self->minor_version ne '0';
98             $self->die('Unrecognized TAB policy')
99 273 100       1641 unless $directives{TAB} =~ /^(NONE|\d+)(:HARD)?$/;
100              
101 272         460 push @{$self->documents}, $self->_parse_node();
  272         650  
102             }
103 246 100       693 return wantarray ? @{$self->documents} : $self->documents->[-1];
  121         292  
104             }
105              
106             # This function is the dispatcher for parsing each node. Every node
107             # recurses back through here. (Inlines are an exception as they have
108             # their own sub-parser.)
109             sub _parse_node {
110 1902     1902   2988 my $self = shift;
111 1902         4038 my $preface = $self->preface;
112 1902         4948 $self->preface('');
113 1902         4599 my ($node, $type, $indicator, $escape, $chomp) = ('') x 5;
114 1902         3817 my ($anchor, $alias, $explicit, $implicit, $class) = ('') x 5;
115 1902         3987 ($anchor, $alias, $explicit, $implicit, $preface) =
116             $self->_parse_qualifiers($preface);
117 1893 100       4504 if ($anchor) {
118 16         90 $self->anchor2node->{$anchor} = CORE::bless [], 'YAML-anchor2node';
119             }
120 1893         4855 $self->inline('');
121 1893         4726 while (length $preface) {
122 1281         2898 my $line = $self->line - 1;
123 1281 100       6211 if ($preface =~ s/^($FOLD_CHAR|$LIT_CHAR_RX)(-|\+)?\d*\s*//) {
124 56         138 $indicator = $1;
125 56 100       255 $chomp = $2 if defined($2);
126             }
127             else {
128 1225 100       2953 $self->die('YAML_PARSE_ERR_TEXT_AFTER_INDICATOR') if $indicator;
129 1224         3348 $self->inline($preface);
130 1224         3479 $preface = '';
131             }
132             }
133 1892 100       4883 if ($alias) {
    100          
    100          
    100          
134             $self->die('YAML_PARSE_ERR_NO_ANCHOR', $alias)
135 17 100       55 unless defined $self->anchor2node->{$alias};
136 16 50       40 if (ref($self->anchor2node->{$alias}) ne 'YAML-anchor2node') {
137 16         40 $node = $self->anchor2node->{$alias};
138             }
139             else {
140 0         0 $node = do {my $sv = "*$alias"};
  0         0  
141 0         0 push @{$self->anchor2node->{$alias}}, [\$node, $self->line];
  0         0  
142             }
143             }
144             elsif (length $self->inline) {
145 1224         2657 $node = $self->_parse_inline(1, $implicit, $explicit);
146 1218 100       2978 if (length $self->inline) {
147 1         3 $self->die('YAML_PARSE_ERR_SINGLE_LINE');
148             }
149             }
150             elsif ($indicator eq $LIT_CHAR) {
151 38         75 $self->{level}++;
152 38         96 $node = $self->_parse_block($chomp);
153 38 50       97 $node = $self->_parse_implicit($node) if $implicit;
154 38         69 $self->{level}--;
155             }
156             elsif ($indicator eq $FOLD_CHAR) {
157 17         33 $self->{level}++;
158 17         47 $node = $self->_parse_unfold($chomp);
159 17 100       85 $node = $self->_parse_implicit($node) if $implicit;
160 16         33 $self->{level}--;
161             }
162             else {
163 596         1040 $self->{level}++;
164 596   100     1272 $self->offset->[$self->level] ||= 0;
165 596 100       1435 if ($self->indent == $self->offset->[$self->level]) {
166 587 100       1342 if ($self->content =~ /^-( |$)/) {
    50          
    0          
167 139         384 $node = $self->_parse_seq($anchor);
168             }
169             elsif ($self->content =~ /(^\?|\:( |$))/) {
170 448         1230 $node = $self->_parse_mapping($anchor);
171             }
172             elsif ($preface =~ /^\s*$/) {
173 0         0 $node = $self->_parse_implicit('');
174             }
175             else {
176 0         0 $self->die('YAML_PARSE_ERR_BAD_NODE');
177             }
178             }
179             else {
180 9         19 $node = undef;
181             }
182 572         1090 $self->{level}--;
183             }
184 1859         4483 $#{$self->offset} = $self->level;
  1859         3954  
185              
186 1859 100       4108 if ($explicit) {
187 66 50       152 if ($class) {
188 0 0       0 if (not ref $node) {
189 0         0 my $copy = $node;
190 0         0 undef $node;
191 0         0 $node = \$copy;
192             }
193 0         0 CORE::bless $node, $class;
194             }
195             else {
196 66         179 $node = $self->_parse_explicit($node, $explicit);
197             }
198             }
199 1858 100       3795 if ($anchor) {
200 16 100       51 if (ref($self->anchor2node->{$anchor}) eq 'YAML-anchor2node') {
201             # XXX Can't remember what this code actually does
202 6         19 for my $ref (@{$self->anchor2node->{$anchor}}) {
  6         18  
203 0         0 ${$ref->[0]} = $node;
  0         0  
204 0         0 $self->warn('YAML_LOAD_WARN_UNRESOLVED_ALIAS',
205             $anchor, $ref->[1]);
206             }
207             }
208 16         46 $self->anchor2node->{$anchor} = $node;
209             }
210 1858         4858 return $node;
211             }
212              
213             # Preprocess the qualifiers that may be attached to any node.
214             sub _parse_qualifiers {
215 4542     4542   6739 my $self = shift;
216 4542         7933 my ($preface) = @_;
217 4542         8506 my ($anchor, $alias, $explicit, $implicit, $token) = ('') x 5;
218 4542         10954 $self->inline('');
219 4542         13045 while ($preface =~ /^[&*!]/) {
220 118         318 my $line = $self->line - 1;
221 118 100       635 if ($preface =~ s/^\!(\S+)\s*//) {
    100          
    100          
    50          
222 70 100       226 $self->die('YAML_PARSE_ERR_MANY_EXPLICIT') if $explicit;
223 69         244 $explicit = $1;
224             }
225             elsif ($preface =~ s/^\!\s*//) {
226 5 100       17 $self->die('YAML_PARSE_ERR_MANY_IMPLICIT') if $implicit;
227 4         12 $implicit = 1;
228             }
229             elsif ($preface =~ s/^\&([^ ,:]*)\s*//) {
230 21         54 $token = $1;
231 21 100       101 $self->die('YAML_PARSE_ERR_BAD_ANCHOR')
232             unless $token =~ /^[a-zA-Z0-9]+$/;
233 19 100       59 $self->die('YAML_PARSE_ERR_MANY_ANCHOR') if $anchor;
234 18 50       52 $self->die('YAML_PARSE_ERR_ANCHOR_ALIAS') if $alias;
235 18         60 $anchor = $token;
236             }
237             elsif ($preface =~ s/^\*([^ ,:]*)\s*//) {
238 22         51 $token = $1;
239 22 100       84 $self->die('YAML_PARSE_ERR_BAD_ALIAS')
240             unless $token =~ /^[a-zA-Z0-9]+$/;
241 20 100       57 $self->die('YAML_PARSE_ERR_MANY_ALIAS') if $alias;
242 19 100       62 $self->die('YAML_PARSE_ERR_ANCHOR_ALIAS') if $anchor;
243 18         50 $alias = $token;
244             }
245             }
246 4533         14291 return ($anchor, $alias, $explicit, $implicit, $preface);
247             }
248              
249             # Morph a node to it's explicit type
250             sub _parse_explicit {
251 83     83   215 my $self = shift;
252 83         184 my ($node, $explicit) = @_;
253 83         146 my ($type, $class);
254 83 100       459 if ($explicit =~ /^\!?perl\/(hash|array|ref|scalar)(?:\:(\w(\w|\:\:)*)?)?$/) {
255 47   50     278 ($type, $class) = (($1 || ''), ($2 || ''));
      100        
256              
257             # FIXME # die unless uc($type) eq ref($node) ?
258              
259 47 100       141 if ( $type eq "ref" ) {
260             $self->die('YAML_LOAD_ERR_NO_DEFAULT_VALUE', 'XXX', $explicit)
261 21 100 66     127 unless exists $node->{VALUE()} and scalar(keys %$node) == 1;
262              
263 20         44 my $value = $node->{VALUE()};
264 20         40 $node = \$value;
265             }
266              
267 46 100 100     174 if ( $type eq "scalar" and length($class) and !ref($node) ) {
      100        
268 3         85 my $value = $node;
269 3         8 $node = \$value;
270             }
271              
272 46 100       116 if ( length($class) ) {
273 20         49 CORE::bless($node, $class);
274             }
275              
276 46         107 return $node;
277             }
278 36 100 100     344 if ($explicit =~ m{^!?perl/(glob|regexp|code)(?:\:(\w(\w|\:\:)*)?)?$}) {
    100          
    100          
279 14   50     89 ($type, $class) = (($1 || ''), ($2 || ''));
      100        
280 14         30 my $type_class = "YAML::Old::Type::$type";
281 32     32   248 no strict 'refs';
  32         71  
  32         90639  
282 14 50       99 if ($type_class->can('yaml_load')) {
283 14         52 return $type_class->yaml_load($node, $class, $self);
284             }
285             else {
286 0         0 $self->die('YAML_LOAD_ERR_NO_CONVERT', 'XXX', $explicit);
287             }
288             }
289             # This !perl/@Foo and !perl/$Foo are deprecated but still parsed
290             elsif ($YAML::TagClass->{$explicit} ||
291             $explicit =~ m{^perl/(\@|\$)?([a-zA-Z](\w|::)+)$}
292             ) {
293 13   66     56 $class = $YAML::TagClass->{$explicit} || $2;
294 13 100       126 if ($class->can('yaml_load')) {
295 4         28 require YAML::Old::Node;
296 4         21 return $class->yaml_load(YAML::Old::Node->new($node, $explicit));
297             }
298             else {
299 9 50       26 if (ref $node) {
300 9         38 return CORE::bless $node, $class;
301             }
302             else {
303 0         0 return CORE::bless \$node, $class;
304             }
305             }
306             }
307             elsif (ref $node) {
308 5         34 require YAML::Old::Node;
309 5         29 return YAML::Old::Node->new($node, $explicit);
310             }
311             else {
312             # XXX This is likely wrong. Failing test:
313             # --- !unknown 'scalar value'
314 4         8 return $node;
315             }
316             }
317              
318             # Parse a YAML mapping into a Perl hash
319             sub _parse_mapping {
320 484     484   805 my $self = shift;
321 484         855 my ($anchor) = @_;
322 484 100       1211 my $mapping = $self->preserve ? YAML::Old::Node->new({}) : {};
323 484         1173 $self->anchor2node->{$anchor} = $mapping;
324 484         774 my $key;
325 484   100     1089 while (not $self->done and $self->indent == $self->offset->[$self->level]) {
326             # If structured key:
327 1343 100       5272 if ($self->{content} =~ s/^\?\s*//) {
    100          
    50          
328 4         15 $self->preface($self->content);
329 4         13 $self->_parse_next_line(COLLECTION);
330 4         13 $key = $self->_parse_node();
331 4         12 $key = "$key";
332             }
333             # If "default" key (equals sign)
334             elsif ($self->{content} =~ s/^\=\s*//) {
335 22         54 $key = VALUE;
336             }
337             # If "comment" key (slash slash)
338             elsif ($self->{content} =~ s/^\=\s*//) {
339 0         0 $key = COMMENT;
340             }
341             # Regular scalar key:
342             else {
343 1317         3067 $self->inline($self->content);
344 1317         2775 $key = $self->_parse_inline();
345 1317         2202 $key = "$key";
346 1317         3018 $self->content($self->inline);
347 1317         3009 $self->inline('');
348             }
349              
350 1343 100       6364 unless ($self->{content} =~ s/^:\s*//) {
351 1         3 $self->die('YAML_LOAD_ERR_BAD_MAP_ELEMENT');
352             }
353 1342         3539 $self->preface($self->content);
354 1342         3285 my $line = $self->line;
355 1342         3328 $self->_parse_next_line(COLLECTION);
356 1340         3561 my $value = $self->_parse_node();
357 1340 100       3167 if (exists $mapping->{$key}) {
358 2         7 $self->warn('YAML_LOAD_WARN_DUPLICATE_KEY', $key);
359             }
360             else {
361 1338         4591 $mapping->{$key} = $value;
362             }
363             }
364 481         1130 return $mapping;
365             }
366              
367             # Parse a YAML sequence into a Perl array
368             sub _parse_seq {
369 139     139   298 my $self = shift;
370 139         263 my ($anchor) = @_;
371 139         269 my $seq = [];
372 139         377 $self->anchor2node->{$anchor} = $seq;
373 139   100     367 while (not $self->done and $self->indent == $self->offset->[$self->level]) {
374 325 100       828 if ($self->content =~ /^-(?: (.*))?$/) {
375 324 100       1169 $self->preface(defined($1) ? $1 : '');
376             }
377             else {
378 1         3 $self->die('YAML_LOAD_ERR_BAD_SEQ_ELEMENT');
379             }
380              
381             # Check whether the preface looks like a YAML mapping ("key: value").
382             # This is complicated because it has to account for the possibility
383             # that a key is a quoted string, which itself may contain escaped
384             # quotes.
385 324         748 my $preface = $self->preface;
386 324 100 100     2164 if ( $preface =~ /^ (\s*) ( \w .*? \: (?:\ |$).*) $/x or
      66        
387             $preface =~ /^ (\s*) ((') (?:''|[^'])*? ' \s* \: (?:\ |$).*) $/x or
388             $preface =~ /^ (\s*) ((") (?:\\\\|[^"])*? " \s* \: (?:\ |$).*) $/x
389             ) {
390 36         101 $self->indent($self->offset->[$self->level] + 2 + length($1));
391 36         107 $self->content($2);
392 36         125 $self->level($self->level + 1);
393 36         93 $self->offset->[$self->level] = $self->indent;
394 36         93 $self->preface('');
395 36         97 push @$seq, $self->_parse_mapping('');
396 36         64 $self->{level}--;
397 36         78 $#{$self->offset} = $self->level;
  36         109  
398             }
399             else {
400 288         711 $self->_parse_next_line(COLLECTION);
401 286         1052 push @$seq, $self->_parse_node();
402             }
403             }
404 118         278 return $seq;
405             }
406              
407             # Parse an inline value. Since YAML supports inline collections, this is
408             # the top level of a sub parsing.
409             sub _parse_inline {
410 2640     2640   4141 my $self = shift;
411 2640         5595 my ($top, $top_implicit, $top_explicit) = (@_, '', '', '');
412 2640         17461 $self->{inline} =~ s/^\s*(.*)\s*$/$1/; # OUCH - mugwump
413 2640         6733 my ($node, $anchor, $alias, $explicit, $implicit) = ('') x 5;
414 2640         6283 ($anchor, $alias, $explicit, $implicit, $self->{inline}) =
415             $self->_parse_qualifiers($self->inline);
416 2640 50       6275 if ($anchor) {
417 0         0 $self->anchor2node->{$anchor} = CORE::bless [], 'YAML-anchor2node';
418             }
419 2640   66     10997 $implicit ||= $top_implicit;
420 2640   100     9627 $explicit ||= $top_explicit;
421 2640         4540 ($top_implicit, $top_explicit) = ('', '');
422 2640 50       7092 if ($alias) {
    100          
    100          
    100          
    100          
423             $self->die('YAML_PARSE_ERR_NO_ANCHOR', $alias)
424 0 0       0 unless defined $self->anchor2node->{$alias};
425 0 0       0 if (ref($self->anchor2node->{$alias}) ne 'YAML-anchor2node') {
426 0         0 $node = $self->anchor2node->{$alias};
427             }
428             else {
429 0         0 $node = do {my $sv = "*$alias"};
  0         0  
430 0         0 push @{$self->anchor2node->{$alias}}, [\$node, $self->line];
  0         0  
431             }
432             }
433             elsif ($self->inline =~ /^\{/) {
434 24         76 $node = $self->_parse_inline_mapping($anchor);
435             }
436             elsif ($self->inline =~ /^\[/) {
437 28         83 $node = $self->_parse_inline_seq($anchor);
438             }
439             elsif ($self->inline =~ /^"/) {
440 22         80 $node = $self->_parse_inline_double_quoted();
441 21         68 $node = $self->_unescape($node);
442 21 100       69 $node = $self->_parse_implicit($node) if $implicit;
443             }
444             elsif ($self->inline =~ /^'/) {
445 52         157 $node = $self->_parse_inline_single_quoted();
446 51 50       148 $node = $self->_parse_implicit($node) if $implicit;
447             }
448             else {
449 2514 100       4652 if ($top) {
450 1130         2330 $node = $self->inline;
451 1130         2560 $self->inline('');
452             }
453             else {
454 1384         2636 $node = $self->_parse_inline_simple();
455             }
456 2513 100       7183 $node = $self->_parse_implicit($node) unless $explicit;
457              
458 2512 100 66     6519 if ($self->numify and defined $node and not ref $node and length $node
      66        
      33        
      66        
459             and $node =~ m/\A-?(?:0|[1-9][0-9]*)?(?:\.[0-9]*)?(?:[eE][+-]?[0-9]+)?\z/) {
460 3         10 $node += 0;
461             }
462             }
463 2633 100       6102 if ($explicit) {
464 17         45 $node = $self->_parse_explicit($node, $explicit);
465             }
466 2633 50       5280 if ($anchor) {
467 0 0       0 if (ref($self->anchor2node->{$anchor}) eq 'YAML-anchor2node') {
468 0         0 for my $ref (@{$self->anchor2node->{$anchor}}) {
  0         0  
469 0         0 ${$ref->[0]} = $node;
  0         0  
470 0         0 $self->warn('YAML_LOAD_WARN_UNRESOLVED_ALIAS',
471             $anchor, $ref->[1]);
472             }
473             }
474 0         0 $self->anchor2node->{$anchor} = $node;
475             }
476 2633         5712 return $node;
477             }
478              
479             # Parse the inline YAML mapping into a Perl hash
480             sub _parse_inline_mapping {
481 24     24   42 my $self = shift;
482 24         50 my ($anchor) = @_;
483 24         46 my $node = {};
484 24         95 $self->anchor2node->{$anchor} = $node;
485              
486             $self->die('YAML_PARSE_ERR_INLINE_MAP')
487 24 50       115 unless $self->{inline} =~ s/^\{\s*//;
488 24         127 while (not $self->{inline} =~ s/^\s*\}\s*//) {
489 24         68 my $key = $self->_parse_inline();
490             $self->die('YAML_PARSE_ERR_INLINE_MAP')
491 24 100       92 unless $self->{inline} =~ s/^\: \s*//;
492 23         52 my $value = $self->_parse_inline();
493 23 50       56 if (exists $node->{$key}) {
494 0         0 $self->warn('YAML_LOAD_WARN_DUPLICATE_KEY', $key);
495             }
496             else {
497 23         65 $node->{$key} = $value;
498             }
499 23 100       85 next if $self->inline =~ /^\s*\}/;
500             $self->die('YAML_PARSE_ERR_INLINE_MAP')
501 9 50       56 unless $self->{inline} =~ s/^\,\s*//;
502             }
503 23         57 return $node;
504             }
505              
506             # Parse the inline YAML sequence into a Perl array
507             sub _parse_inline_seq {
508 28     28   50 my $self = shift;
509 28         57 my ($anchor) = @_;
510 28         54 my $node = [];
511 28         86 $self->anchor2node->{$anchor} = $node;
512              
513             $self->die('YAML_PARSE_ERR_INLINE_SEQUENCE')
514 28 50       134 unless $self->{inline} =~ s/^\[\s*//;
515 28         117 while (not $self->{inline} =~ s/^\s*\]\s*//) {
516 52         133 my $value = $self->_parse_inline();
517 51         100 push @$node, $value;
518 51 100       115 next if $self->inline =~ /^\s*\]/;
519             $self->die('YAML_PARSE_ERR_INLINE_SEQUENCE')
520 33 100       171 unless $self->{inline} =~ s/^\,\s*//;
521             }
522 26         63 return $node;
523             }
524              
525             # Parse the inline double quoted string.
526             sub _parse_inline_double_quoted {
527 22     22   54 my $self = shift;
528 22         36 my $node;
529             # https://rt.cpan.org/Public/Bug/Display.html?id=90593
530 22 100       62 if ($self->inline =~ /^"((?:(?:\\"|[^"]){0,32766}){0,32766})"\s*(.*)$/) {
531 21         539 $node = $1;
532 21         125 $self->inline($2);
533 21         8732 $node =~ s/\\"/"/g;
534             }
535             else {
536 1         4 $self->die('YAML_PARSE_ERR_BAD_DOUBLE');
537             }
538 21         387 return $node;
539             }
540              
541              
542             # Parse the inline single quoted string.
543             sub _parse_inline_single_quoted {
544 52     52   100 my $self = shift;
545 52         90 my $node;
546 52 100       127 if ($self->inline =~ /^'((?:(?:''|[^']){0,32766}){0,32766})'\s*(.*)$/) {
547 51         134 $node = $1;
548 51         167 $self->inline($2);
549 51         119 $node =~ s/''/'/g;
550             }
551             else {
552 1         5 $self->die('YAML_PARSE_ERR_BAD_SINGLE');
553             }
554 51         162 return $node;
555             }
556              
557             # Parse the inline unquoted string and do implicit typing.
558             sub _parse_inline_simple {
559 1384     1384   2457 my $self = shift;
560 1384         2210 my $value;
561 1384 100       2890 if ($self->inline =~ /^(|[^!@#%^&*].*?)(?=[\[\]\{\},]|, |: |- |:\s*$|$)/) {
562 1383         3057 $value = $1;
563 1383         4821 substr($self->{inline}, 0, length($1)) = '';
564             }
565             else {
566 1         4 $self->die('YAML_PARSE_ERR_BAD_INLINE_IMPLICIT', $value);
567             }
568 1383         2997 return $value;
569             }
570              
571             sub _parse_implicit {
572 2508     2508   3793 my $self = shift;
573 2508         4342 my ($value) = @_;
574 2508         10558 $value =~ s/\s*$//;
575 2508 100       6380 return $value if $value eq '';
576 2504 100       5579 return undef if $value =~ /^~$/;
577 2500 100 100     12162 return $value
578             unless $value =~ /^[\@\`]/ or
579             $value =~ /^[\-\?]\s/;
580 2         7 $self->die('YAML_PARSE_ERR_BAD_IMPLICIT', $value);
581             }
582              
583             # Unfold a YAML multiline scalar into a single string.
584             sub _parse_unfold {
585 17     17   32 my $self = shift;
586 17         31 my ($chomp) = @_;
587 17         31 my $node = '';
588 17         31 my $space = 0;
589 17   100     51 while (not $self->done and $self->indent == $self->offset->[$self->level]) {
590 54         131 $node .= $self->content. "\n";
591 54         111 $self->_parse_next_line(LEAF);
592             }
593 17         137 $node =~ s/^(\S.*)\n(?=\S)/$1 /gm;
594 17         49 $node =~ s/^(\S.*)\n(\n+\S)/$1$2/gm;
595 17 100       167 $node =~ s/\n*\Z// unless $chomp eq '+';
596 17 100       55 $node .= "\n" unless $chomp;
597 17         46 return $node;
598             }
599              
600             # Parse a YAML block style scalar. This is like a Perl here-document.
601             sub _parse_block {
602 38     38   68 my $self = shift;
603 38         76 my ($chomp) = @_;
604 38         64 my $node = '';
605 38   100     93 while (not $self->done and $self->indent == $self->offset->[$self->level]) {
606 130         304 $node .= $self->content . "\n";
607 130         259 $self->_parse_next_line(LEAF);
608             }
609 38 100       116 return $node if '+' eq $chomp;
610 35         353 $node =~ s/\n*\Z/\n/;
611 35 100       134 $node =~ s/\n\Z// if $chomp eq '-';
612 35         86 return $node;
613             }
614              
615             # Handle Perl style '#' comments. Comments must be at the same indentation
616             # level as the collection line following them.
617             sub _parse_throwaway_comments {
618 2529     2529   3879 my $self = shift;
619 2529   100     3504 while (@{$self->lines} and
  3056         6369  
620             $self->lines->[0] =~ m{^\s*(\#|$)}
621             ) {
622 527         808 shift @{$self->lines};
  527         1024  
623 527         895 $self->{line}++;
624             }
625 2529         4273 $self->eos($self->{done} = not @{$self->lines});
  2529         5274  
626             }
627              
628             # This is the routine that controls what line is being parsed. It gets called
629             # once for each line in the YAML stream.
630             #
631             # This routine must:
632             # 1) Skip past the current line
633             # 2) Determine the indentation offset for a new level
634             # 3) Find the next _content_ line
635             # A) Skip over any throwaways (Comments/blanks)
636             # B) Set $self->indent, $self->content, $self->line
637             # 4) Expand tabs appropriately
638             sub _parse_next_line {
639 2094     2094   3149 my $self = shift;
640 2094         3607 my ($type) = @_;
641 2094         4466 my $level = $self->level;
642 2094         4562 my $offset = $self->offset->[$level];
643 2094 50       4819 $self->die('YAML_EMIT_ERR_BAD_LEVEL') unless defined $offset;
644 2094         2912 shift @{$self->lines};
  2094         4592  
645 2094         3218 $self->eos($self->{done} = not @{$self->lines});
  2094         4466  
646 2094 100       4456 if ($self->eos) {
647 219         553 $self->offset->[$level + 1] = $offset + 1;
648 219         498 return;
649             }
650 1875         3239 $self->{line}++;
651              
652             # Determine the offset for a new leaf node
653 1875 100 100     4007 if ($self->preface =~
    100          
654             qr/(?:^|\s)(?:$FOLD_CHAR|$LIT_CHAR_RX)(?:-|\+)?(\d*)\s*$/
655             ) {
656 56 100 100     261 $self->die('YAML_PARSE_ERR_ZERO_INDENT')
657             if length($1) and $1 == 0;
658 55         94 $type = LEAF;
659 55 100       124 if (length($1)) {
660 4         12 $self->offset->[$level + 1] = $offset + $1;
661             }
662             else {
663             # First get rid of any comments.
664 51   66     90 while (@{$self->lines} && ($self->lines->[0] =~ /^\s*#/)) {
  51         122  
665 1         5 $self->lines->[0] =~ /^( *)/;
666 1 50       5 last unless length($1) <= $offset;
667 0         0 shift @{$self->lines};
  0         0  
668 0         0 $self->{line}++;
669             }
670 51         120 $self->eos($self->{done} = not @{$self->lines});
  51         113  
671 51 50       115 return if $self->eos;
672 51 100 66     127 if ($self->lines->[0] =~ /^( *)\S/ and length($1) > $offset) {
673 50         139 $self->offset->[$level+1] = length($1);
674             }
675             else {
676 1         4 $self->offset->[$level+1] = $offset + 1;
677             }
678             }
679 55         132 $offset = $self->offset->[++$level];
680             }
681             # Determine the offset for a new collection level
682             elsif ($type == COLLECTION and
683             $self->preface =~ /^(\s*(\!\S*|\&\S+))*\s*$/) {
684 596         1615 $self->_parse_throwaway_comments();
685 596 50       1352 if ($self->eos) {
686 0         0 $self->offset->[$level+1] = $offset + 1;
687 0         0 return;
688             }
689             else {
690 596 100       1302 $self->lines->[0] =~ /^( *)\S/ or
691             $self->die('YAML_PARSE_ERR_NONSPACE_INDENTATION');
692 595 100       1746 if (length($1) > $offset) {
693 592         1501 $self->offset->[$level+1] = length($1);
694             }
695             else {
696 3         10 $self->offset->[$level+1] = $offset + 1;
697             }
698             }
699 595         1428 $offset = $self->offset->[++$level];
700             }
701              
702 1873 100       5233 if ($type == LEAF) {
703 216   100     320 while (@{$self->lines} and
  227   100     468  
704             $self->lines->[0] =~ m{^( *)(\#)} and
705             length($1) < $offset
706             ) {
707 11         19 shift @{$self->lines};
  11         26  
708 11         19 $self->{line}++;
709             }
710 216         326 $self->eos($self->{done} = not @{$self->lines});
  216         458  
711             }
712             else {
713 1657         3391 $self->_parse_throwaway_comments();
714             }
715 1873 100       4033 return if $self->eos;
716              
717 1866 100       4227 if ($self->lines->[0] =~ /^---(\s|$)/) {
718 38         112 $self->done(1);
719 38         85 return;
720             }
721 1828 100 100     6211 if ($type == LEAF and
    100          
722             $self->lines->[0] =~ /^ {$offset}(.*)$/
723             ) {
724 169         502 $self->indent($offset);
725 169         400 $self->content($1);
726             }
727             elsif ($self->lines->[0] =~ /^\s*$/) {
728 15         44 $self->indent($offset);
729 15         34 $self->content('');
730             }
731             else {
732 1644         3681 $self->lines->[0] =~ /^( *)(\S.*)$/;
733 1644         4112 while ($self->offset->[$level] > length($1)) {
734 380         884 $level--;
735             }
736 1644 100       3849 $self->die('YAML_PARSE_ERR_INCONSISTENT_INDENTATION')
737             if $self->offset->[$level] != length($1);
738 1640         5126 $self->indent(length($1));
739 1640         3836 $self->content($2);
740             }
741 1824 50       4354 $self->die('YAML_PARSE_ERR_INDENTATION')
742             if $self->indent - $offset > 1;
743             }
744              
745             #==============================================================================
746             # Utility subroutines.
747             #==============================================================================
748              
749             # Printable characters for escapes
750             my %unescapes = (
751             0 => "\x00",
752             a => "\x07",
753             t => "\x09",
754             n => "\x0a",
755             'v' => "\x0b", # Potential v-string error on 5.6.2 if not quoted
756             f => "\x0c",
757             r => "\x0d",
758             e => "\x1b",
759             '\\' => '\\',
760             );
761              
762             # Transform all the backslash style escape characters to their literal meaning
763             sub _unescape {
764 21     21   40 my $self = shift;
765 21         48 my ($node) = @_;
766 21         162 $node =~ s/\\([never\\fart0]|x([0-9a-fA-F]{2}))/
767 18 50       91 (length($1)>1)?pack("H2",$2):$unescapes{$1}/gex;
768 21         53 return $node;
769             }
770              
771             1;