File Coverage

blib/lib/YAML/Perl/Scanner.pm
Criterion Covered Total %
statement 710 825 86.0
branch 189 280 67.5
condition 96 147 65.3
subroutine 79 81 97.5
pod 0 72 0.0
total 1074 1405 76.4


line stmt bran cond sub pod time code
1             # pyyaml/lib/yaml/scanner.py
2              
3             # Scanner produces tokens of the following types:
4             # STREAM-START
5             # STREAM-END
6             # DIRECTIVE(name, value)
7             # DOCUMENT-START
8             # DOCUMENT-END
9             # BLOCK-SEQUENCE-START
10             # BLOCK-MAPPING-START
11             # BLOCK-END
12             # FLOW-SEQUENCE-START
13             # FLOW-MAPPING-START
14             # FLOW-SEQUENCE-END
15             # FLOW-MAPPING-END
16             # BLOCK-ENTRY
17             # FLOW-ENTRY
18             # KEY
19             # VALUE
20             # ALIAS(value)
21             # ANCHOR(value)
22             # TAG(value)
23             # SCALAR(value, plain, style)
24             #
25             # Read comments in the Scanner code for more details.
26             #
27              
28             package YAML::Perl::Scanner;
29 8     8   1036 use strict;
  8         18  
  8         548  
30 8     8   48 use warnings;
  8         240  
  8         341  
31 8     8   1251 use YAML::Perl::Processor -base;
  8         20  
  8         83  
32              
33             field 'next_layer' => 'reader';
34              
35             field 'reader_class', -init => '"YAML::Perl::Reader"';
36             field 'reader', -init => '$self->create("reader")';
37              
38 8     8   709 use YAML::Perl::Error;
  8         25  
  8         66  
39 8     8   912 use YAML::Perl::Tokens;
  8         16  
  8         67  
40              
41             package YAML::Perl::Error::Scanner;
42 8     8   46 use YAML::Perl::Error::Marked -base;
  8         22  
  8         113  
43              
44             package YAML::Perl::Scanner::SimpleKey;
45 8     8   46 use YAML::Perl::Base -base;
  8         27  
  8         91  
46              
47             field 'token_number';
48             field 'required';
49             field 'index';
50             field 'line';
51             field 'column';
52             field 'mark';
53              
54             package YAML::Perl::Scanner;
55              
56             field done => False;
57              
58             field flow_level => 0;
59              
60             field tokens => [];
61              
62             sub open {
63 30     30 0 57 my $self = shift;
64 30         178 $self->SUPER::open(@_);
65 30         132 $self->fetch_stream_start();
66             }
67              
68             field tokens_taken => 0;
69              
70             field indent => -1;
71              
72             field indents => [];
73              
74             field allow_simple_key => True;
75              
76             field possible_simple_keys => {};
77              
78             sub scan {
79 0     0 0 0 my $self = shift;
80 0 0       0 if (wantarray) {
81 0         0 my @tokens = ();
82 0         0 while ($self->check_token()) {
83 0         0 push @tokens, $self->get_token();
84             }
85 0         0 return @tokens;
86             }
87             else {
88 0 0       0 return $self->check_token() ? $self->get_token() : ();
89             }
90             }
91              
92             # Public methods.
93              
94             sub check_token {
95 1040     1040 0 1473 my $self = shift;
96 1040         2100 my @choices = @_;
97 1040         2072 while ($self->need_more_tokens()) {
98 208         512 $self->fetch_more_tokens();
99             }
100 1040 50       1355 if (@{$self->tokens}) {
  1040         47730  
101 1040 50       2181 if (not @choices) {
102 0         0 return True;
103             }
104 1040         2002 for my $choice (@choices) {
105 1276 100       45100 if ($self->tokens->[0]->isa($choice)) {
106 314         1438 return True;
107             }
108             }
109             }
110 726         9193 return False;
111             }
112              
113             sub peek_token {
114 194     194 0 347 my $self = shift;
115 194         661 while ($self->need_more_tokens()) {
116 15         52 $self->fetch_more_tokens();
117             }
118 194 50       265 if (@{$self->tokens}) {
  194         4954  
119 194         4938 return $self->tokens->[0];
120             }
121 0         0 return;
122             }
123              
124             sub get_token {
125 315     315 0 453 my $self = shift;
126 315         663 while ($self->need_more_tokens()) {
127 0         0 $self->fetch_more_tokens();
128             }
129 315 50       479 if (@{$self->tokens}) {
  315         8290  
130 315         7776 $self->tokens_taken($self->tokens_taken + 1);
131 315         424 return shift @{$self->tokens};
  315         18151  
132             }
133 0         0 return;
134             }
135              
136             # Private methods.
137              
138             sub need_more_tokens {
139 1772     1772 0 2018 my $self = shift;
140 1772 100       45830 if ($self->done) {
141 253         809 return False;
142             }
143 1519 100       1846 if (not @{$self->tokens}) {
  1519         38512  
144 168         484 return True;
145             }
146 1351         3348 $self->stale_possible_simple_keys();
147 1351         3356 my $next = $self->next_possible_simple_key();
148 1351 100 100     13624 if (defined($next) and $next == $self->tokens_taken) {
149 55         168 return True;
150             }
151 1296         3366 return;
152             }
153              
154             sub fetch_more_tokens {
155 223     223 0 447 my $self = shift;
156              
157 223         699 $self->scan_to_next_token();
158              
159 223         620 $self->stale_possible_simple_keys();
160              
161 223         7432 $self->unwind_indent($self->reader->column);
162              
163 223         5511 my $ch = $self->reader->peek();
164              
165 223 100       12821 if ($ch eq "\0") {
166 29         131 return $self->fetch_stream_end();
167             }
168              
169 194 100 66     604 if ($ch eq "%" and $self->check_directive()) {
170 2         10 return $self->fetch_directive();
171             }
172              
173 192 100 100     679 if ($ch eq "-" and $self->check_document_start()) {
174 28         119 return $self->fetch_document_start;
175             }
176              
177 164 100 66     519 if ($ch eq "." and $self->check_document_end()) {
178 1         19 return $self->fetch_document_end;
179             }
180              
181 163 100       376 if ($ch eq "[") {
182 6         29 return $self->fetch_flow_sequence_start();
183             }
184              
185 157 100       365 if ($ch eq "{") {
186 4         19 return $self->fetch_flow_mapping_start();
187             }
188              
189 153 100       450 if ($ch eq "]") {
190 6         31 return $self->fetch_flow_sequence_end();
191             }
192              
193 147 100       397 if ($ch eq "}") {
194 4         16 return $self->fetch_flow_mapping_end();
195             }
196              
197 143 100       365 if ($ch eq ',') {
198 6         30 return $self->fetch_flow_entry();
199             }
200              
201 137 100 66     404 if ($ch eq '-' and $self->check_block_entry()) {
202 20         135 return $self->fetch_block_entry();
203             }
204              
205 117 100 66     300 if ($ch eq '?' and $self->check_key()) {
206 1         6 return $self->fetch_key();
207             }
208              
209 116 100 66     395 if ($ch eq ':' and $self->check_value()) {
210 27         136 return $self->fetch_value();
211             }
212              
213 89 100       447 if ($ch eq '*') {
214 3         14 return $self->fetch_alias();
215             }
216              
217 86 100       213 if ($ch eq '&') {
218 3         25 return $self->fetch_anchor();
219             }
220              
221 83 100       213 if ($ch eq '!') {
222 8         36 return $self->fetch_tag();
223             }
224              
225 75 100 66     438 if ($ch eq '|' and not $self->flow_level) {
226 3         17 return $self->fetch_literal();
227             }
228              
229 72 100 66     247 if ($ch eq '>' and not $self->flow_level) {
230 1         6 return $self->fetch_folded();
231             }
232              
233 71 100       167 if ($ch eq "'") {
234 4         18 return $self->fetch_single();
235             }
236              
237 67 100       145 if ($ch eq '"') {
238 3         18 return $self->fetch_double();
239             }
240              
241 64 50       280 if ($self->check_plain()) {
242 64         218 return $self->fetch_plain();
243             }
244              
245             throw YAML::Perl::Error::Scanner(
246 0         0 "while scanning for the next token found character '$ch' that cannot start any token"
247             );
248             }
249              
250             sub next_possible_simple_key {
251 1351     1351 0 1848 my $self = shift;
252 1351         1493 my $min_token_number = undef;
253 1351         1608 for my $level (keys %{$self->possible_simple_keys}) {
  1351         52359  
254 66         1652 my $key = $self->possible_simple_keys->{$level};
255 66 100 100     272 if (not defined $min_token_number or
256             $key->token_number < $min_token_number
257             ) {
258 65         1712 $min_token_number = $key->token_number;
259             }
260             }
261 1351         3185 return $min_token_number;
262             }
263              
264             sub stale_possible_simple_keys {
265 1574     1574 0 1995 my $self = shift;
266 1574         1761 for my $level (keys %{$self->possible_simple_keys}) {
  1574         55463  
267 141         3946 my $key = $self->possible_simple_keys->{$level};
268 141 100 66     8716 if ($key->line != $self->reader->line or
269             $self->reader->index - $key->index > 1024
270             ) {
271 24 50       589 if ($key->required) {
272 0         0 throw YAML::Perl::Error::Scanner(
273             "while scanning a simple key ", $key->mark,
274             "could not find expected ':' ", $self->get_mark()
275             );
276             }
277 24         593 delete $self->possible_simple_keys->{$level};
278             }
279             }
280             }
281              
282             sub save_possible_simple_key {
283 95     95 0 175 my $self = shift;
284 95   100     2560 my $required = (not $self->flow_level and $self->indent == $self->reader->column);
285 95   66     11928 assert($self->allow_simple_key or not $required);
286 95 100       2635 if ($self->allow_simple_key) {
287 56         179 $self->remove_possible_simple_key();
288 56         1478 my $token_number = $self->tokens_taken + @{$self->tokens};
  56         1629  
289 56         1464 my $key = YAML::Perl::Scanner::SimpleKey->new(
290             token_number => $token_number,
291             required => $required,
292             index => $self->reader->index,
293             line => $self->reader->line,
294             column => $self->reader->column,
295             mark => $self->reader->get_mark(),
296             );
297 56         1439 $self->possible_simple_keys->{$self->flow_level} = $key;
298             }
299             }
300              
301             sub remove_possible_simple_key {
302 129     129 0 249 my $self = shift;
303 129 100       3263 if (exists $self->possible_simple_keys->{$self->flow_level}) {
304 6         142 my $key = $self->possible_simple_keys->{$self->flow_level};
305              
306 6 50       159 if ($key->required) {
307 0         0 throw YAML::Perl::Scanner::Error->new(
308             "while scanning a simple key", $key->mark,
309             "could not find expected ':'", $self->get_mark()
310             );
311             }
312 6         146 delete $self->possible_simple_keys->{$self->flow_level};
313             }
314             }
315              
316             sub unwind_indent {
317 283     283 0 365 my $self = shift;
318 283         347 my $column = shift;
319 283 100       7106 if ($self->flow_level) {
320 40         82 return;
321             }
322 243         6236 while ($self->indent > $column) {
323 19         467 my $mark = $self->reader->get_mark();
324 19         53 $self->indent(pop @{$self->indents});
  19         514  
325 19         40 push @{$self->tokens}, YAML::Perl::Token::BlockEnd->new(
  19         454  
326             start_mark => $mark,
327             end_mark => $mark,
328             );
329             }
330             }
331              
332             sub add_indent {
333 42     42 0 89 my $self = shift;
334 42         70 my $column = shift;
335 42 100       1145 if ($self->indent < $column) {
336 21         45 push @{$self->indents}, $self->indent;
  21         581  
337 21         1006 $self->indent($column);
338 21         81 return True;
339             }
340 21         84 return False;
341             }
342              
343             sub fetch_stream_start {
344 30     30 0 108 my $self = shift;
345 30         814 my $mark = $self->reader->get_mark();
346 30         73 push @{$self->tokens}, YAML::Perl::Token::StreamStart->new(
  30         911  
347             start_mark => $mark,
348             end_mark => $mark,
349             encoding => $self->reader->encoding,
350             );
351             }
352              
353             sub fetch_stream_end {
354 29     29 0 55 my $self = shift;
355 29         96 $self->unwind_indent(-1);
356 29         786 $self->allow_simple_key(False);
357 29         765 $self->possible_simple_keys({});
358 29         714 my $mark = $self->reader->get_mark();
359 29         72 push @{$self->tokens}, YAML::Perl::Token::StreamEnd->new(
  29         774  
360             start_mark => $mark,
361             end_mark => $mark,
362             );
363 29         842 $self->done(True);
364             }
365              
366             sub fetch_directive {
367 2     2 0 5 my $self = shift;
368 2         6 $self->unwind_indent(-1);
369 2         8 $self->remove_possible_simple_key();
370 2         67 $self->allow_simple_key(False);
371 2         5 push @{$self->tokens}, $self->scan_directive();
  2         54  
372             }
373              
374             sub fetch_document_start {
375 28     28 0 51 my $self = shift;
376 28         121 $self->fetch_document_indicator('YAML::Perl::Token::DocumentStart');
377             }
378              
379             sub fetch_document_end {
380 1     1 0 2 my $self = shift;
381 1         5 $self->fetch_document_indicator('YAML::Perl::Token::DocumentEnd');
382             }
383              
384             sub fetch_document_indicator {
385 29     29 0 42 my $self = shift;
386 29         49 my $token_class = shift;
387 29         76 $self->unwind_indent(-1);
388 29         109 $self->remove_possible_simple_key();
389 29         815 $self->allow_simple_key(False);
390 29         748 my $start_mark = $self->reader->get_mark();
391 29         749 $self->reader->forward(3);
392 29         763 my $end_mark = $self->reader->get_mark();
393 29         76 push @{$self->tokens}, $token_class->new(
  29         718  
394             start_mark => $start_mark,
395             end_mark => $end_mark,
396             );
397             }
398              
399             sub fetch_flow_sequence_start {
400 6     6 0 11 my $self = shift;
401 6         26 $self->fetch_flow_collection_start('YAML::Perl::Token::FlowSequenceStart');
402             }
403              
404             sub fetch_flow_mapping_start {
405 4     4 0 11 my $self = shift;
406 4         22 $self->fetch_flow_collection_start('YAML::Perl::Token::FlowMappingStart');
407             }
408              
409             sub fetch_flow_collection_start {
410 10     10 0 22 my $self = shift;
411 10         19 my $token_class = shift;
412 10         38 $self->save_possible_simple_key();
413 10         243 $self->flow_level($self->flow_level + 1);
414 10         250 $self->allow_simple_key(True);
415 10         236 my $start_mark = $self->reader->get_mark();
416 10         242 $self->reader->forward();
417 10         241 my $end_mark = $self->reader->get_mark();
418 10         23 push @{$self->tokens}, $token_class->new(
  10         244  
419             start_mark => $start_mark,
420             end_mark => $end_mark,
421             );
422             }
423              
424             sub fetch_flow_sequence_end {
425 6     6 0 13 my $self = shift;
426 6         26 $self->fetch_flow_collection_end('YAML::Perl::Token::FlowSequenceEnd');
427             }
428              
429             sub fetch_flow_mapping_end {
430 4     4 0 17 my $self = shift;
431 4         24 $self->fetch_flow_collection_end('YAML::Perl::Token::FlowMappingEnd');
432             }
433              
434             sub fetch_flow_collection_end {
435 10     10 0 21 my $self = shift;
436 10         17 my $token_class = shift;
437 10         26 $self->remove_possible_simple_key();
438 10         241 $self->flow_level($self->flow_level - 1);
439 10         246 $self->allow_simple_key(False);
440 10         301 my $start_mark = $self->reader->get_mark();
441 10         243 $self->reader->forward();
442 10         249 my $end_mark = $self->reader->get_mark();
443 10         28 push @{$self->tokens}, $token_class->new(
  10         253  
444             start_mark => $start_mark,
445             end_mark => $end_mark,
446             );
447             }
448              
449             sub fetch_flow_entry {
450 6     6 0 11 my $self = shift;
451 6         148 $self->allow_simple_key(True);
452 6         19 $self->remove_possible_simple_key();
453 6         148 my $start_mark = $self->reader->get_mark();
454 6         151 $self->reader->forward();
455 6         161 my $end_mark = $self->reader->get_mark();
456 6         14 push @{$self->tokens}, YAML::Perl::Token::FlowEntry->new(
  6         144  
457             start_mark => $start_mark,
458             end_mark => $end_mark,
459             );
460             }
461              
462             sub fetch_block_entry {
463 20     20 0 36 my $self = shift;
464 20 50       526 if (not $self->flow_level) {
465 20 50       589 if (not $self->allow_simple_key) {
466 0         0 throw YAML::Perl::Error::Scanner(
467             undef, undef,
468             "sequence entries are not allowed here", $self->get_mark()
469             );
470             }
471 20 100       488 if ($self->add_indent($self->reader->column)) {
472 6         151 my $mark = $self->reader->get_mark();
473 6         19 push @{$self->tokens}, YAML::Perl::Token::BlockSequenceStart->new(
  6         173  
474             start_mark => $mark,
475             end_mark => $mark,
476             );
477             }
478             }
479 20         516 $self->allow_simple_key(True);
480 20         70 $self->remove_possible_simple_key();
481 20         501 my $start_mark = $self->reader->get_mark();
482 20         539 $self->reader->forward();
483 20         580 my $end_mark = $self->reader->get_mark();
484 20         79 push @{$self->tokens}, YAML::Perl::Token::BlockEntry->new(
  20         510  
485             start_mark => $start_mark,
486             end_mark => $end_mark,
487             );
488             }
489              
490             sub fetch_key {
491 1     1 0 2 my $self = shift;
492 1 50       24 if (not $self->flow_level) {
493 1 50       23 if (not $self->allow_simple_key) {
494 0         0 throw YAML::Perl::Error::Scanner(
495             undef, undef,
496             "mapping keys are not allowed here", $self->get_mark()
497             );
498             }
499 1 50       22 if ($self->add_indent($self->reader->column)) {
500 1         26 my $mark = $self->reader->get_mark();
501 1         3 push @{$self->tokens}, YAML::Perl::Token::BlockMappingStart->new(
  1         26  
502             start_mark=> $mark,
503             end_mark => $mark,
504             );
505             }
506             }
507 1         26 $self->allow_simple_key(not($self->flow_level));
508 1         4 $self->remove_possible_simple_key();
509 1         26 my $start_mark = $self->reader->get_mark();
510 1         27 $self->reader->forward();
511 1         29 my $end_mark = $self->reader->get_mark();
512 1         3 push @{$self->tokens}, YAML::Perl::Token::Key->new(
  1         26  
513             start_mark => $start_mark,
514             end_mark => $end_mark,
515             );
516             }
517              
518             sub fetch_value {
519 27     27 0 56 my $self = shift;
520              
521 27 100       673 if (exists $self->possible_simple_keys->{$self->flow_level}) {
522 26         605 my $key = $self->possible_simple_keys->{$self->flow_level};
523 26         621 delete $self->possible_simple_keys->{$self->flow_level};
524 26         65 splice @{$self->tokens},
  26         1746  
525             ($key->token_number - $self->tokens_taken), 0,
526             YAML::Perl::Token::Key->new(
527             start_mark => $key->mark,
528             end_mark => $key->mark,
529             );
530 26 100       833 if (not $self->flow_level) {
531 20 100       492 if ($self->add_indent($key->column)) {
532 14         26 splice @{$self->tokens},
  14         375  
533             ($key->token_number - $self->tokens_taken), 0,
534             YAML::Perl::Token::BlockMappingStart->new(
535             start_mark => $key->mark,
536             end_mark => $key->mark,
537             );
538             }
539             }
540 26         737 $self->allow_simple_key(False);
541             }
542             else {
543             # Block context needs additional checks.
544             # (Do we really need them? They will be catched by the parser
545             # anyway.)
546 1 50       26 if (not $self->flow_level) {
547              
548             # We are allowed to start a complex value if and only if
549             # we can start a simple key.
550 1 50       38 if (not $self->allow_simple_key) {
551 0         0 throw YAML::Perl::Error::Scanner(
552             undef,
553             undef,
554             "mapping values are not allowed here",
555             $self->reader->get_mark(),
556             );
557             }
558             }
559              
560             # If this value starts a new block mapping, we need to add
561             # BLOCK-MAPPING-START. It will be detected as an error later by
562             # the parser.
563 1 50       24 if (not $self->flow_level) {
564 1 50       27 if ($self->add_indent($self->reader->column)) {
565 0         0 my $mark = $self->reader->get_mark();
566 0         0 push @{$self->tokens},
  0         0  
567             YAML::Perl::Token::BlockMappingStart(
568             start_mark => $mark,
569             end_mark => $mark,
570             );
571             }
572             }
573              
574             # Simple keys are allowed after ':' in the block context.
575 1         155 $self->allow_simple_key(not $self->flow_level);
576              
577             # Reset possible simple key on the current level.
578 1         4 $self->remove_possible_simple_key();
579             }
580 27         1015 my $start_mark = $self->reader->get_mark();
581 27         833 $self->reader->forward();
582 27         780 my $end_mark = $self->reader->get_mark();
583 27         59 push @{$self->tokens},
  27         770  
584             YAML::Perl::Token::Value->new(
585             start_mark => $start_mark,
586             end_mark => $end_mark,
587             );
588             }
589              
590             sub fetch_alias {
591 3     3 0 9 my $self = shift;
592 3         13 $self->save_possible_simple_key();
593 3         71 $self->allow_simple_key(False);
594 3         5 push @{$self->tokens}, $self->scan_anchor('YAML::Perl::Token::Alias');
  3         72  
595             }
596              
597             sub fetch_anchor {
598 3     3 0 7 my $self = shift;
599 3         14 $self->save_possible_simple_key();
600 3         153 $self->allow_simple_key(False);
601 3         8 push @{$self->tokens}, $self->scan_anchor('YAML::Perl::Token::Anchor');
  3         96  
602             }
603              
604             sub fetch_tag {
605 8     8 0 15 my $self = shift;
606 8         29 $self->save_possible_simple_key();
607 8         199 $self->allow_simple_key(False);
608 8         32 push @{$self->tokens}, $self->scan_tag();
  8         199  
609             }
610              
611             sub fetch_literal {
612 3     3 0 8 my $self = shift;
613 3         18 $self->fetch_block_scalar('|');
614             }
615              
616             sub fetch_folded {
617 1     1 0 2 my $self = shift;
618 1         4 $self->fetch_block_scalar('>');
619             }
620              
621             sub fetch_block_scalar {
622 4     4 0 10 my $self = shift;
623 4         8 my $style = shift;
624              
625             # A simple key may follow a block scalar.
626 4         179 $self->allow_simple_key(True);
627              
628             # Reset possible simple key on the current level.
629 4         15 $self->remove_possible_simple_key();
630              
631             # Scan and add SCALAR.
632 4         10 push @{$self->tokens}, $self->scan_block_scalar($style);
  4         101  
633             }
634              
635             sub fetch_single {
636 4     4 0 6 my $self = shift;
637 4         17 $self->fetch_flow_scalar('\'');
638             }
639              
640             sub fetch_double {
641 3     3 0 7 my $self = shift;
642 3         16 $self->fetch_flow_scalar('"');
643             }
644              
645             sub fetch_flow_scalar {
646 7     7 0 14 my $self = shift;
647 7         12 my $style = shift;
648              
649             # A flow scalar could be a simple key.
650 7         30 $self->save_possible_simple_key();
651              
652             # No simple keys after flow scalars.
653 7         168 $self->allow_simple_key(False);
654              
655             # Scan and add SCALAR.
656 7         13 push @{$self->tokens}, $self->scan_flow_scalar($style);
  7         166  
657             }
658              
659             sub fetch_plain {
660 64     64 0 108 my $self = shift;
661 64         189 $self->save_possible_simple_key();
662 64         1595 $self->allow_simple_key(False);
663 64         98 push @{$self->tokens}, $self->scan_plain();
  64         2790  
664             }
665              
666             sub check_directive {
667 2     2 0 6 my $self = shift;
668 2 50       55 if ($self->reader->column == 0) {
669 2         12 return True;
670             }
671 0         0 return;
672             }
673              
674             sub check_document_start {
675 48     48 0 87 my $self = shift;
676 48 50       1614 if ($self->reader->column == 0) {
677 48 100 66     1136 if ($self->reader->prefix(3) eq '---' and
678             $self->reader->peek(3) =~ /^[\0\ \t\r\n\x85\x{2028}\x{2029}]$/
679             ) {
680 28         112 return True;
681             }
682             }
683 20         98 return;
684             }
685              
686             sub check_document_end {
687 1     1 0 3 my $self = shift;
688 1 50       23 if ($self->reader->column == 0) {
689 1 50 33     22 if ($self->reader->prefix(3) eq '...' and
690             $self->reader->peek(3) =~ /^[\0\ \t\r\n\x85\x{2028}\x{2029}]$/
691             ) {
692 1         8 return True;
693             }
694             }
695 0         0 return;
696             }
697              
698             sub check_block_entry {
699 20     20 0 37 my $self = shift;
700 20         491 return $self->reader->peek(1) =~ /^[\0\ \t\r\n\x85\x{2028}\x{2029}]$/;
701             }
702              
703             sub check_key {
704 1     1 0 3 my $self = shift;
705             # KEY(flow context): '?'
706 1 50       51 if ($self->flow_level) {
707 0         0 return True;
708             }
709              
710             # KEY(block context): '?' (' '|'\n')
711             else {
712 1         24 return ($self->reader->peek(1) =~ /^[\0\ \t\r\n\x85\x{2028}\x{2029}]$/);
713             }
714             }
715              
716             sub check_value {
717 27     27 0 46 my $self = shift;
718 27 100       819 if ($self->flow_level) {
719 6         31 return True;
720             }
721             else {
722 21 50       602 return ($self->reader->peek(1) =~ /^[\0\ \t\r\n]$/) ? True : False;
723             }
724             }
725              
726             sub check_plain {
727 64     64 0 99 my $self = shift;
728 64         1700 my $ch = $self->reader->peek();
729             return(
730 64   33     468 $ch !~ /^[\0\ \r\n\x85\x{2028}\x{2029}\-\?\:\,\[\]\{\}\#\&\*\!\|\>\'\"\%\@\`]$/ or
731             $self->reader->peek(1) !~ /^[\0\ \t\r\n\x85\x{2028}\x{2029}]$/ and
732             ($ch eq '-' or (not $self->flow_level and $ch =~ /^[\?\:]$/))
733             );
734             }
735              
736             sub scan_to_next_token {
737 223     223 0 314 my $self = shift;
738 223 50 66     6029 if ($self->reader->index == 0 and $self->reader->peek() eq "\uFEFF") {
739 0         0 $self->reader->forward();
740             }
741 223         405 my $found = False;
742 223         603 while (not $found) {
743 269         6779 $self->reader->forward()
744             while $self->reader->peek() eq ' ';
745 269 50       7130 if ($self->reader->peek() eq '#') {
746 0         0 while ($self->reader->peek() !~ /^[\0\r\n\x85]$/) {
747 0         0 $self->reader->forward();
748             }
749             }
750 269 100       882 if ($self->scan_line_break()) {
751 46 100       1360 if (not $self->flow_level) {
752 40         965 $self->allow_simple_key(True);
753             }
754             }
755             else {
756 223         705 $found = True;
757             }
758             }
759             }
760              
761             sub scan_directive {
762 2     2 0 6 my $self = shift;
763 2         55 my $start_mark = $self->reader->get_mark();
764 2         51 $self->reader->forward();
765 2         10 my $name = $self->scan_directive_name($start_mark);
766 2         4 my $value = undef;
767 2         3 my $end_mark;
768 2 100       10 if ($name eq 'YAML') {
    50          
769 1         5 $value = $self->scan_yaml_directive_value($start_mark);
770 1         31 $end_mark = $self->reader->get_mark();
771             }
772             elsif ($name eq 'TAG') {
773 1         5 $value = $self->scan_tag_directive_value($start_mark);
774 1         31 $end_mark = $self->reader->get_mark();
775             }
776             else {
777 0         0 $end_mark = $self->reader->get_mark();
778 0         0 while ($self->reader->peek() !~ /^[\0\r\n\x85\u2028\u2029]$/) {
779 0         0 $self->reader->forward();
780             }
781             }
782 2         13 $self->scan_directive_ignored_line($start_mark);
783 2         21 return YAML::Perl::Token::Directive->new(
784             name => $name,
785             value => $value,
786             start_mark => $start_mark,
787             end_mark => $end_mark
788             );
789             }
790              
791             sub scan_directive_name {
792 2     2 0 4 my $self = shift;
793 2         4 my $start_mark = shift;
794 2         2 my $length = 0;
795 2         54 my $ch = $self->reader->peek($length);
796 2         11 while ($ch =~ /^[0-9A-Za-z-_]$/) {
797 7         10 $length += 1;
798 7         172 $ch = $self->reader->peek($length);
799             }
800 2 50       6 if (not $length) {
801 0         0 throw YAML::Perl::Error::Scanner("while scanning a directive $start_mark "
802             . " expected alphabetic or numeric character, but found $ch ", $self->get_mark());
803             }
804 2         52 my $value = $self->reader->prefix($length);
805 2         50 $self->reader->forward($length);
806 2         51 $ch = $self->reader->peek();
807 2 50       11 if ($ch !~ /^[\0 \r\n\x85\u2028\u2029]$/) {
808 0         0 throw YAML::Perl::Error::Scanner("while scanning a directive $start_mark "
809             . " expected alphabetic or numeric character, but found $ch ", $self->get_mark());
810             }
811 2         7 return $value;
812             }
813              
814             sub scan_yaml_directive_value {
815 1     1 0 3 my $self = shift;
816 1         1 my $start_mark = shift;
817 1         26 while ($self->reader->peek() eq ' ') {
818 1         29 $self->reader->forward();
819             }
820 1         6 my $major = $self->scan_yaml_directive_number($start_mark);
821 1 50       28 if ($self->reader->peek() ne '.') {
822 0         0 throw YAML::Perl::Error::Scanner("while scanning a directive $start_mark "
823             . " expected a digit or '.' but found ", $self->reader->peek(), $self->reader->get_mark());
824             }
825 1         28 $self->reader->forward();
826 1         3 my $minor = $self->scan_yaml_directive_number($start_mark);
827 1 50       24 if ($self->reader->peek() !~ /^[\0 \r\n\x85\u2028\u2029]$/) {
828 0         0 throw YAML::Perl::Error::Scanner("while scanning a directive $start_mark "
829             . " expected alphabetic or numeric character, but found ", $self->reader->peek(),
830             $self->get_mark());
831             }
832 1         5 return "$major.$minor"; # XXX this is a tuple in python but...
833             }
834              
835             sub scan_yaml_directive_number {
836 2     2 0 3 my $self = shift;
837 2         3 my $start_mark = shift;
838 2         81 my $ch = $self->reader->peek();
839 2 50       10 if ($ch !~ /^[0-9]$/) {
840 0         0 throw YAML::Perl::Error::Scanner("while scanning a directive $start_mark "
841             . " expected a digit but found $ch", $self->reader->get_mark());
842             }
843 2         3 my $length = 0;
844 2         48 while ($self->reader->peek($length) =~ /^[0-9]$/) {
845 2         48 $length += 1;
846             }
847 2         49 my $value = int($self->reader->prefix($length));
848 2         48 $self->reader->forward($length);
849 2         4 return $value;
850             }
851              
852             sub scan_tag_directive_value {
853 1     1 0 3 my $self = shift;
854 1         1 my $start_mark = shift;
855 1         33 while ($self->reader->peek() eq ' ') {
856 1         26 $self->reader->forward();
857             }
858 1         7 my $handle = $self->scan_tag_directive_handle($start_mark);
859 1         27 while ($self->reader->peek() eq ' ') {
860 1         26 $self->reader->forward();
861             }
862 1         4 my $prefix = $self->scan_tag_directive_prefix($start_mark);
863 1         5 return [$handle, $prefix];
864             }
865              
866             sub scan_tag_directive_handle {
867 1     1 0 4 my $self = shift;
868 1         2 my $start_mark = shift;
869 1         6 my $value = $self->scan_tag_handle('directive', $start_mark);
870 1         48 my $ch = $self->reader->peek();
871 1 50       5 if ($ch ne ' ') {
872 0         0 throw YAML::Perl::Error::Scanner(
873             "while scanning a directive",
874             $start_mark,
875             "expected ' ', but found %r", $ch->encode('utf-8'),
876             $self->get_mark()
877             );
878             }
879 1         3 return $value;
880             }
881              
882             sub scan_tag_directive_prefix {
883 1     1 0 3 my $self = shift;
884 1         1 my $start_mark = shift;
885 1         4 my $value = $self->scan_tag_uri('directive', $start_mark);
886 1         30 my $ch = $self->reader->peek();
887 1 50       89 if ($ch !~ /^[\0\ \r\n\x85\x{2028}\x{2029}]$/) {
888 0         0 throw YAML::Perl::Error::Scanner(
889             "while scanning a directive",
890             $start_mark,
891             "expected ' ', but found %r", $ch->encode('utf-8'),
892             $self->get_mark()
893             );
894             }
895 1         5 return $value;
896             }
897              
898             sub scan_directive_ignored_line {
899 2     2 0 4 my $self = shift;
900 2         4 my $start_mark = shift;
901 2         50 while ($self->reader->peek() eq ' ') {
902 0         0 $self->reader->forward();
903             }
904 2 50       49 if ($self->reader->peek() eq '#') {
905 0         0 while ($self->reader->peek !~ /^[\0\r\n]$/) {
906 0         0 $self->reader->forward();
907             }
908             }
909 2         49 my $ch = $self->reader->peek();
910 2 50       10 if ($ch !~ /^[\0\r\n\x85\u2028\u2029]$/) {
911 0         0 throw YAML::Perl::Error::Scanner("while scanning a directive $start_mark "
912             . "expected a comment or a line break, but found $ch", $self->reader->get_mark());
913             }
914 2         13 return $self->scan_line_break();
915             }
916              
917             sub scan_anchor {
918 6     6 0 12 my $self = shift;
919 6         12 my $token_class = shift;
920 6         164 my $start_mark = $self->reader->get_mark();
921 6         148 my $indicator = $self->reader->peek();
922 6         13 my $name;
923 6 100       33 if ($indicator eq '*') {
924 3         7 $name = 'alias';
925             } else {
926 3         6 $name = 'anchor';
927             }
928 6         145 $self->reader->forward();
929 6         11 my $length = 0;
930 6         215 my $ch = $self->reader->peek($length);
931 6         32 while ($ch =~ /^[0-9A-Za-z-_]$/) {
932 18         25 $length += 1;
933 18         745 $ch = $self->reader->peek($length);
934             }
935 6 50       19 if (not $length) {
936 0         0 throw YAML::Perl::Error::Scanner("while scanning an $name $start_mark expected "
937             . "alphabetic or numeric character, but found " . $self->get_mark());
938             }
939 6         245 my $value = $self->reader->prefix($length);
940 6         150 $self->reader->forward($length);
941 6         227 $ch = $self->reader->peek();
942 6 50       33 if ($ch !~ /^[\0 \t\r\n\x85\u2028\u2029?:,\]}%@]$/) {
943 0         0 throw YAML::Perl::Error::Scanner("while scanning an $name $start_mark expected "
944             . "alphabetic or numeric character, but found " . $self->get_mark());
945             }
946 6         145 my $end_mark = $self->reader->get_mark();
947 6         113 return $token_class->new(value => $value, start_mark => $start_mark, end_mark => $end_mark);
948             }
949              
950             sub scan_tag {
951 8     8 0 17 my $self = shift;
952 8         197 my $start_mark = $self->reader->get_mark();
953 8         202 my $ch = $self->reader->peek(1);
954 8         17 my ($suffix, $handle);
955 8 50       99 if ($ch eq '<') {
    50          
956 0         0 my $handle = undef;
957 0         0 $self->forward(2);
958 0         0 $suffix = $self->scan_tag_uri('tag', $start_mark);
959 0 0       0 if ($self->reader->peek() ne '>') {
960 0         0 throw YAML::Perl::Error::Scanner(
961             "while parsing a tag",
962             $start_mark,
963             "expected '>', but found %r",
964             $self->peek()->encode('utf-8'),
965             $self->reader->get_mark(),
966             );
967             }
968 0         0 $self->forward();
969             }
970             elsif ($ch =~ /^[\0 \t\r\n\x85\x{2028}\x{2029}]$/) {
971 0         0 $handle = undef;
972 0         0 $suffix = '!';
973 0         0 $self->reader->forward();
974             }
975             else {
976 8         14 my $length = 1;
977 8         15 my $use_handle = False;
978 8         33 while ($ch !~ /^[\0 \r\n\x85\x{2028}\x{2029}]$/) {
979 8 50       24 if ($ch eq '!') {
980 8         17 $use_handle = True;
981 8         18 last;
982             }
983 0         0 $length += 1;
984 0         0 $ch = $self->reader->peek($length);
985             }
986 8         15 $handle = '!';
987 8 50       31 if ($use_handle) {
988 8         36 $handle = $self->scan_tag_handle('tag', $start_mark);
989             }
990             else {
991 0         0 $handle = '!';
992 0         0 $self->reader->forward();
993             }
994 8         31 $suffix = $self->scan_tag_uri('tag', $start_mark);
995             }
996 8         212 $ch = $self->reader->peek();
997 8 50       73 if ($ch !~ /^[\0 \r\n\x85\x{2028}\x{2029}]$/) {
998 0         0 throw YAML::Perl::Error::Scanner(
999             "while scanning a tag",
1000             $start_mark,
1001             "expected ' ', but found %r",
1002             $ch->encode('utf-8'),
1003             $self->reader->get_mark()
1004             );
1005             }
1006 8         39 my $value = [$handle, $suffix];
1007 8         201 my $end_mark = $self->reader->get_mark();
1008 8         80 return YAML::Perl::Token::Tag->new(
1009             value => $value,
1010             start_mark => $start_mark,
1011             end_mark => $end_mark,
1012             );
1013             }
1014              
1015             sub scan_block_scalar {
1016 4     4 0 9 my $self = shift;
1017 4         8 my $style = shift;
1018             # See the specification for details.
1019              
1020 4         6 my $folded;
1021 4 100       18 if ($style eq '>') {
1022 1         3 $folded = True;
1023             }
1024             else {
1025 3         7 $folded = False;
1026             }
1027              
1028 4         12 my $chunks = [];
1029 4         104 my $start_mark = $self->reader->get_mark();
1030              
1031             # Scan the header.
1032 4         111 $self->reader->forward();
1033 4         56 my ($chomping, $increment) = $self->scan_block_scalar_indicators($start_mark);
1034 4         20 $self->scan_block_scalar_ignored_line($start_mark);
1035              
1036             # Determine the indentation level and go to the first non-empty line.
1037 4         154 my $min_indent = $self->indent + 1;
1038 4 50       16 if ($min_indent < 1) {
1039 4         11 $min_indent = 1;
1040             }
1041 4         6 my ($breaks, $max_indent, $end_mark, $indent);
1042 4 100       41 if (not defined $increment) {
1043 2         7 ($breaks, $max_indent, $end_mark) = $self->scan_block_scalar_indentation();
1044 2 50       8 $indent = $min_indent > $max_indent ? $min_indent : $max_indent;
1045             }
1046             else {
1047 2         6 $indent = $min_indent + $increment - 1;
1048 2         9 ($breaks, $end_mark) = $self->scan_block_scalar_breaks($indent);
1049             }
1050 4         14 my $line_break = '';
1051              
1052             # Scan the inner part of the block scalar.
1053 4   33     94 while ($self->reader->column == $indent and $self->reader->peek() ne "\0") {
1054 12         28 push @$chunks, @$breaks;
1055 12         286 my $leading_non_space = ($self->reader->peek() !~ /^[\ \t]$/);
1056 12         16 my $length = 0;
1057 12         280 while ($self->reader->peek($length) !~ /^[\0\r\n\x85\x{2028}\x{2029}]$/) {
1058 37         1216 $length += 1;
1059             }
1060 12         285 push @$chunks, $self->reader->prefix($length);
1061 12         287 $self->reader->forward($length);
1062 12         33 $line_break = $self->scan_line_break();
1063 12         34 ($breaks, $end_mark) = $self->scan_block_scalar_breaks($indent);
1064 12 100 66     307 if ($self->reader->column == $indent and $self->reader->peek() ne "\0") {
1065              
1066             # Unfortunately, folding rules are ambiguous.
1067             #
1068             # This is the folding according to the specification:
1069            
1070 8 100 66     199 if ($folded and
      66        
      33        
1071             $line_break eq "\n" and
1072             $leading_non_space and
1073             $self->reader->peek() !~ /^[\ \t]$/
1074             ) {
1075 2 50       6 if (not @$breaks) {
1076 2         66 push @$chunks, ' ';
1077             }
1078             }
1079             else {
1080 6         165 push @$chunks, $line_break;
1081             }
1082            
1083             # This is Clark Evans's interpretation (also in the spec
1084             # examples):
1085             #
1086             #if folded and line_break == u'\n':
1087             # if not breaks:
1088             # if self.peek() not in ' \t':
1089             # chunks.append(u' ')
1090             # else:
1091             # chunks.append(line_break)
1092             #else:
1093             # chunks.append(line_break)
1094             }
1095             else {
1096 4         12 last;
1097             }
1098             }
1099              
1100             # Chomp the tail.
1101 4 50 33     22 if (not defined $chomping or $chomping == True) {
1102 4         12 push @$chunks, $line_break;
1103             }
1104 4 50 33     31 if (defined $chomping and $chomping == True) {
1105 0         0 push @$chunks, @$breaks;
1106             }
1107              
1108             # We are done.
1109 4         43 return YAML::Perl::Token::Scalar->new(
1110             value => join('', @$chunks),
1111             plain => False,
1112             start_mark => $start_mark,
1113             end_mark => $end_mark,
1114             style => $style,
1115             );
1116             }
1117              
1118             sub scan_block_scalar_indicators {
1119 4     4 0 8 my $self = shift;
1120 4         6 my $start_mark = shift;
1121              
1122             # See the specification for details.
1123 4         9 my $chomping = undef;
1124 4         7 my $increment = undef;
1125 4         249 my $ch = $self->reader->peek();
1126 4 50       36 if ($ch =~ /^[\+\-]$/) {
    100          
1127 0 0       0 if ($ch eq '+') {
1128 0         0 $chomping = True;
1129             }
1130             else {
1131 0         0 $chomping = False;
1132             }
1133 0         0 $self->reader->forward();
1134 0         0 $ch = $self->reader->peek();
1135 0 0       0 if ($ch =~ /^[0-9]$/) {
1136 0         0 $increment = $ch;
1137 0 0       0 if ($increment == 0) {
1138 0         0 throw YAML::Perl::Error::Scanner(
1139             "while scanning a block scalar",
1140             $start_mark,
1141             "expected indentation indicator in the range 1-9, but found 0",
1142             $self->reader->get_mark()
1143             );
1144             }
1145 0         0 $self->reader->forward();
1146             }
1147             }
1148             elsif ($ch =~ /^[0-9]$/) {
1149 2         5 $increment = $ch;
1150 2 50       56 if ($increment == 0) {
1151 0         0 raise ScannerError(
1152             "while scanning a block scalar",
1153             $start_mark,
1154             "expected indentation indicator in the range 1-9, but found 0",
1155             $self->reader->get_mark(),
1156             );
1157             }
1158 2         57 $self->reader->forward();
1159 2         62 $ch = $self->reader->peek();
1160 2 50       12 if ($ch =~ /^[\+\-]$/) {
1161 0 0       0 if ($ch eq '+') {
1162 0         0 $chomping = True;
1163             }
1164             else {
1165 0         0 $chomping = False;
1166             }
1167 0         0 $self->reader->forward();
1168             }
1169             }
1170 4         100 $ch = $self->reader->peek();
1171 4 50       23 if ($ch !~ /^[\0\ \r\n\x85\x{2028}\x{2029}]$/) {
1172 0         0 throw YAML::Perl::Error::Scanner(
1173             "while scanning a block scalar",
1174             $start_mark,
1175             "expected chomping or indentation indicators, but found %r",
1176             $ch, #.encode('utf-8'),
1177             $self->reader->get_mark(),
1178             );
1179             }
1180 4         19 return ($chomping, $increment);
1181             }
1182              
1183             sub scan_block_scalar_ignored_line {
1184 4     4 0 8 my $self= shift;
1185 4         8 my $start_mark = shift;
1186             # See the specification for details.
1187 4         105 while ($self->reader->peek() eq ' ') {
1188 0         0 $self->reader->forward();
1189             }
1190 4 50       103 if ($self->reader->peek() eq '#') {
1191 0         0 while ($self->reader->peek() !~ /^[\0\r\n\x85\x{2028}\x{2029}]$/) {
1192 0         0 $self->reader->forward();
1193             }
1194             }
1195 4         116 my $ch = $self->reader->peek();
1196 4 50       25 if ($ch !~ /^[\0\r\n\x85\x{2028}\x{2029}]$/) {
1197 0         0 throw YAML::Perl::Error::Scanner(
1198             "while scanning a block scalar",
1199             $start_mark,
1200             "expected a comment or a line break, but found %r",
1201             $ch, #.encode('utf-8'),
1202             $self->get_mark(),
1203             );
1204             }
1205 4         15 $self->scan_line_break();
1206             }
1207              
1208             sub scan_block_scalar_indentation {
1209 2     2 0 4 my $self = shift;
1210 2         3 my $chunks = [];
1211 2         3 my $max_indent = 0;
1212 2         48 my $end_mark = $self->reader->get_mark();
1213 2         49 while ($self->reader->peek() =~ /^[\ \r\n\x85\x{2028}\x{2029}]$/) {
1214 4 50       104 if ($self->reader->peek() ne ' ') {
1215 0         0 push @$chunks, $self->scan_line_break();
1216 0         0 $end_mark = $self->reader->get_mark();
1217             }
1218             else {
1219 4         94 $self->reader->forward();
1220 4 50       92 if ($self->reader->column > $max_indent) {
1221 4         88 $max_indent = $self->reader->column;
1222             }
1223             }
1224             }
1225 2         8 return $chunks, $max_indent, $end_mark;
1226             }
1227              
1228             sub scan_block_scalar_breaks {
1229 14     14 0 17 my $self = shift;
1230 14         20 my $indent = shift;
1231             # See the specification for details.
1232 14         21 my $chunks = [];
1233 14         349 my $end_mark = $self->reader->get_mark();
1234 14   100     342 while ($self->reader->column < $indent and $self->reader->peek() eq ' ') {
1235 20         534 $self->reader->forward();
1236             }
1237 14         340 while ($self->reader->peek() =~ /^[\r\n\x85\x{2028}\x{2029}]$/) {
1238 0         0 push @$chunks, $self->scan_line_break();
1239 0         0 $end_mark = $self->reader->get_mark();
1240 0   0     0 while ($self->reader->column < $indent and $self->reader->peek() eq ' ') {
1241 0         0 $self->reader->forward();
1242             }
1243             }
1244 14         44 return ($chunks, $end_mark)
1245              
1246             }
1247              
1248             sub scan_flow_scalar {
1249 7     7 0 15 my $self = shift;
1250 7         11 my $style = shift;
1251             # See the specification for details.
1252             # Note that we loose indentation rules for quoted scalars. Quoted
1253             # scalars don't need to adhere indentation because " and ' clearly
1254             # mark the beginning and the end of them. Therefore we are less
1255             # restrictive then the specification requires. We only need to check
1256             # that document separators are not included in scalars.
1257 7         12 my $double;
1258 7 100       22 if ($style eq '"') {
1259 3         7 $double = True;
1260             }
1261             else {
1262 4         9 $double = False;
1263             }
1264 7         15 my $chunks = [];
1265 7         182 my $start_mark = $self->reader->get_mark();
1266 7         184 my $quote = $self->reader->peek();
1267 7         182 $self->reader->forward();
1268 7         15 push @$chunks, @{$self->scan_flow_scalar_non_spaces($double, $start_mark)};
  7         31  
1269 7         265 while ($self->reader->peek() ne $quote) {
1270 12         23 push @$chunks, @{$self->scan_flow_scalar_spaces($double, $start_mark)};
  12         36  
1271 12         22 push @$chunks, @{$self->scan_flow_scalar_non_spaces($double, $start_mark)};
  12         29  
1272             }
1273 7         196 $self->reader->forward();
1274 7         184 my $end_mark = $self->reader->get_mark();
1275 7         125 return YAML::Perl::Token::Scalar->new(
1276             value => join('', @$chunks),
1277             plain => False,
1278             start_mark => $start_mark,
1279             end_mark => $end_mark,
1280             style => $style,
1281             );
1282             }
1283              
1284 8         1257 use constant ESCAPE_REPLACEMENTS => {
1285             '0' => "\0",
1286             'a' => "\x07",
1287             'b' => "\x08",
1288             't' => "\x09",
1289             '\t' => "\x09",
1290             'n' => "\x0A",
1291             'v' => "\x0B",
1292             'f' => "\x0C",
1293             'r' => "\x0D",
1294             'e' => "\x1B",
1295             ' ' => "\x20",
1296             '\"' => "\"",
1297             '\\' => "\\",
1298             'N' => "\x85",
1299             '_' => "\xA0",
1300             'L' => "\u2028",
1301             'P' => "\u2029",
1302 8     8   109 };
  8         19  
1303              
1304 8         22302 use constant ESCAPE_CODES => {
1305             'x' => 2,
1306             'u' => 4,
1307             'U' => 8,
1308 8     8   57 };
  8         287  
1309              
1310             sub scan_flow_scalar_non_spaces {
1311 19     19 0 28 my $self = shift;
1312 19         26 my $double = shift;
1313 19         21 my $start_mark = shift;
1314              
1315             # See the specification for details.
1316 19         32 my $chunks = [];
1317 19         35 while (True) {
1318 27         35 my $length = 0;
1319 27         688 while ($self->reader->peek($length) !~
1320             /^[\'\"\\\0\ \t\r\n\x85\x{2028}\x{2029}]$/
1321             ) {
1322 55         1973 $length += 1;
1323             }
1324 27 100       68 if ($length) {
1325 21         556 push @$chunks, $self->reader->prefix($length);
1326 21         642 $self->reader->forward($length);
1327             }
1328 27         928 my $ch = $self->reader->peek();
1329 27 100 100     492 if (not $double and $ch eq '\'' and $self->reader->peek(1) eq '\'') {
    100 100        
    100 66        
      100        
      33        
      100        
1330 2         6 push @$chunks, '\'';
1331 2         50 $self->reader->forward(2);
1332             }
1333             elsif (($double and $ch eq '\'') or (not $double and $ch =~ /^[\"\\]$/)) {
1334 2         6 push @$chunks, $ch;
1335 2         56 $self->reader->forward();
1336             }
1337             elsif ($double and $ch eq '\\') {
1338 4         102 $self->reader->forward();
1339 4         111 $ch = $self->reader->peek();
1340 4 100       22 if (exists ESCAPE_REPLACEMENTS->{$ch}) {
    50          
    0          
1341 3         10 push @$chunks, ESCAPE_REPLACEMENTS->{$ch};
1342 3         80 $self->reader->forward();
1343             }
1344             elsif (exists ESCAPE_CODES->{$ch}) {
1345 1         3 $length = ESCAPE_CODES->{$ch};
1346 1         26 $self->reader->forward();
1347 1         4 for my $k (0 .. ($length - 1)) {
1348 2 50       52 if ($self->reader->peek($k) !~ /^[0123456789ABCDEFabcdef]$/) {
1349 0         0 throw YAML::Perl::Error::Scanner(
1350             "while scanning a double-quoted scalar",
1351             $start_mark,
1352             "expected escape sequence of %d hexdecimal numbers, but found %r",
1353             ($length, $self->reader->peek($k)), #.encode('utf-8')),
1354             $self->get_mark(),
1355             );
1356             }
1357             }
1358             # XXX - Review this for multibyte and unicode
1359 1         26 my $code = ord(pack "H*", $self->reader->prefix($length));
1360 1         4 push @$chunks, chr($code);
1361              
1362 1         28 $self->reader->forward($length);
1363             }
1364             elsif ($ch =~ /^[\r\n\x85\x{2028}\x{2029}]$/) {
1365 0         0 $self->scan_line_break();
1366 0         0 push @$chunks,
1367 0         0 @{$self->scan_flow_scalar_breaks($double, $start_mark)};
1368             }
1369             else {
1370 0         0 throw YAML::Perl::Error::Scanner(
1371             "while scanning a double-quoted scalar",
1372             $start_mark,
1373             "found unknown escape character %r",
1374             $ch, #.encode('utf-8'),
1375             $self->reader->get_mark()
1376             );
1377             }
1378             }
1379             else {
1380 19         389 return $chunks
1381             }
1382             }
1383             }
1384              
1385             sub scan_flow_scalar_spaces {
1386 12     12 0 19 my $self = shift;
1387 12         17 my $double = shift;
1388 12         15 my $start_mark = shift;
1389              
1390             # See the specification for details.
1391 12         21 my $chunks = [];
1392 12         17 my $length = 0;
1393 12         344 while ($self->reader->peek($length) =~ /^[\ \t]$/) {
1394 8         199 $length += 1;
1395             }
1396 12         406 my $whitespaces = $self->reader->prefix($length);
1397 12         372 $self->reader->forward($length);
1398 12         519 my $ch = $self->reader->peek();
1399 12 50       57 if ($ch eq "\0") {
    100          
1400 0         0 throw YAML::Perl::Error::Scanner(
1401             "while scanning a quoted scalar",
1402             $start_mark,
1403             "found unexpected end of stream",
1404             $self->get_mark(),
1405             );
1406             }
1407             elsif ($ch =~ /^[\r\n\x85\x{2028}\x{2029}]$/) {
1408 8         21 my $line_break = $self->scan_line_break();
1409 8         27 my $breaks = $self->scan_flow_scalar_breaks($double, $start_mark);
1410 8 50       34 if ($line_break ne "\n") {
    100          
1411 0         0 push @$chunks, $line_break;
1412             }
1413             elsif (not @$breaks) {
1414 6         14 push @$chunks, ' ';
1415             }
1416 8         30 push @$chunks, @$breaks;
1417             }
1418             else {
1419 4         11 push @$chunks, $whitespaces;
1420             }
1421 12         44 return $chunks;
1422             }
1423              
1424             sub scan_flow_scalar_breaks {
1425 8     8 0 13 my $self = shift;
1426 8         11 my $double = shift;
1427 8         10 my $start_mark = shift;
1428              
1429             # See the specification for details.
1430 8         14 my $chunks = [];
1431 8         11 while (True) {
1432             # Instead of checking indentation, we check for document
1433             # separators.
1434 10         250 my $prefix = $self->reader->prefix(3);
1435 10 50 33     73 if (
      33        
1436             ($prefix eq '---' or $prefix eq '...') and
1437             $self->reader->peek(3) =~ /^[\0\ \t\r\n\x85\x{2028}\x{2029}]$/
1438             ) {
1439 0         0 throw YAML::Perl::Error::Scanner(
1440             "while scanning a quoted scalar",
1441             $start_mark,
1442             "found unexpected document separator",
1443             $self.get_mark()
1444             );
1445             }
1446 10         251 while ($self->reader->peek() =~ /^[\ \t]$/) {
1447 8         343 $self->reader->forward();
1448             }
1449 10 100       301 if ($self->reader->peek() =~ /^[\r\n\x85\x{2028}\x{2029}]$/) {
1450 2         76 push @$chunks, $self->scan_line_break();
1451             }
1452             else {
1453 8         18 return $chunks;
1454             }
1455             }
1456             }
1457              
1458             sub scan_plain {
1459 64     64 0 119 my $self = shift;
1460              
1461 64         148 my $chunks = [];
1462 64         1624 my $start_mark = $self->reader->get_mark();
1463 64         183 my $end_mark = $start_mark;
1464 64         1584 my $indent = $self->indent + 1;
1465              
1466 64         178 my $spaces = [];
1467              
1468 64         112 while (True) {
1469 66         113 my $length = 0;
1470 66 50       1697 if ($self->reader->peek() eq '#') {
1471 0         0 last;
1472             }
1473 66         135 my $ch;
1474 66         100 while (True) {
1475 192         5192 $ch = $self->reader->peek($length);
1476              
1477 192 100 100     5333 if (
      66        
      66        
      100        
      66        
1478             ($ch =~ /^[\0\ \t\r\n]$/) or
1479             (
1480             not $self->flow_level and $ch eq ':' and
1481             $self->reader->peek($length + 1) =~ /^[\0\ \t\r\n]$/
1482             ) or
1483             ($self->flow_level and $ch =~ /^[\,\:\?\[\]\{\}]$/)
1484             ) {
1485 66         169 last;
1486             }
1487 126         190 $length++;
1488             }
1489 66 50 100     1821 if ($self->flow_level and
      66        
1490             $ch eq ':' and
1491             $self->reader->peek($length + 1) !~ /^[\0\ \t\r\n\,\[\]\{\}]$/
1492             ) {
1493 0         0 $self->reader->forward($length);
1494 0         0 throw YAML::Perl::Error::Scanner(
1495             "while scanning a plain scalar", $start_mark,
1496             "found unexpected ':'", $self->reader->get_mark(),
1497             "Please check http://pyyaml.org/wiki/YAMLColonInFlowContext for details.",
1498             );
1499             }
1500 66 50       205 if ($length == 0) {
1501 0         0 last;
1502             }
1503 66         1778 $self->allow_simple_key(False);
1504 66         130 push @$chunks, @$spaces;
1505 66         1698 push @$chunks, $self->reader->prefix($length);
1506 66         1693 $self->reader->forward($length);
1507 66         1707 $end_mark = $self->reader->get_mark();
1508 66         417 $spaces = $self->scan_plain_spaces($indent, $start_mark);
1509 66 100 100     1211 if (not defined $spaces or not @$spaces or
      66        
      66        
      66        
1510             $self->reader->peek() eq '#' or
1511             (not $self->flow_level and $self->reader->column < $indent)
1512             ) {
1513 64         1405 last;
1514             }
1515             }
1516 64         680 return YAML::Perl::Token::Scalar->new(
1517             value => join('', @$chunks),
1518             plain => True,
1519             start_mark => $start_mark,
1520             end_mark => $end_mark,
1521             );
1522             }
1523              
1524             # ... ch in u'\r\n\x85\u2028\u2029':
1525             # XXX needs unicode linefeeds
1526             my $linefeed = qr/^[\r\n\x85]$/;
1527              
1528             sub scan_plain_spaces {
1529 66     66 0 119 my $self = shift;
1530 66         551 my $indent = shift;
1531 66         120 my $start_mark = shift;
1532              
1533 66         152 my $chunks = [];
1534 66         106 my $length = 0;
1535 66         1714 while ($self->reader->peek( $length ) eq ' ') {
1536 2         56 $length++;
1537             }
1538 66         2500 my $whitespaces = $self->reader->prefix($length);
1539 66         2042 $self->reader->forward($length);
1540 66         1725 my $ch = $self->reader->peek();
1541 66 100       8384 if ($ch =~ $linefeed) {
    100          
1542 28         109 my $line_break = $self->scan_line_break();
1543 28         771 $self->allow_simple_key(True);
1544 28         785 my $prefix = $self->reader->prefix(3);
1545 28 100 66     224 if (($prefix eq '---' or $prefix eq '...') and
      66        
1546             $self->reader->peek(3) =~ $linefeed
1547             ) {
1548 1         4 return;
1549             }
1550 27         96 my $breaks = [];
1551 27         708 while ($self->reader->peek() =~ $linefeed) {
1552 0 0       0 if ($self->reader->peek() eq ' ') {
1553 0         0 $self->reader->forward();
1554             }
1555             else {
1556 0         0 push @$breaks, $self->scan_line_break();
1557 0         0 my $prefix = $self->reader->prefix(3);
1558 0 0 0     0 if (($prefix eq '---' or $prefix eq '...') and
      0        
1559             $self->reader->peek(3) =~ $linefeed
1560             ) {
1561 0         0 return;
1562             }
1563             }
1564             }
1565 27 50       195 if ($line_break ne "\n") {
    50          
1566 0         0 push @$chunks, $line_break;
1567             }
1568             elsif (not @$breaks) {
1569 27         77 push @$chunks, ' ';
1570             }
1571 27         63 push @$chunks, @$breaks;
1572             }
1573             elsif ($whitespaces) {
1574 2         8 push @$chunks, $whitespaces;
1575             }
1576 65         208 return $chunks;
1577             }
1578              
1579             sub scan_tag_handle {
1580 9     9 0 23 my $self = shift;
1581 9         26 my $name = shift;
1582 9         15 my $start_mark = shift;
1583 9         222 my $ch = $self->reader->peek();
1584 9 50       32 if ($ch ne '!') {
1585 0         0 throw YAML::Perl::Error::Scanner(
1586             "while scanning a %s",
1587             $name,
1588             $start_mark,
1589             "expected '!', but found %r",
1590             $ch->encode('utf-8'),
1591             $self->get_mark(),
1592             );
1593             }
1594 9         19 my $length = 1;
1595 9         212 $ch = $self->reader->peek($length);
1596 9 50       33 if ($ch ne ' ') {
1597 9         39 while ($ch =~ /^[0-9A-Za-z\-\_]$/) {
1598 0         0 $length += 1;
1599 0         0 $ch = $self->reader->peek($length);
1600             }
1601 9 50       27 if ($ch ne '!') {
1602 0         0 $self->reader->forward($length);
1603 0         0 throw YAML::Perl::Error::Scanner(
1604             "while scanning a %s",
1605             $name,
1606             $start_mark,
1607             "expected '!', but found %r",
1608             $ch->encode('utf-8'),
1609             self->reader->get_mark(),
1610             );
1611             }
1612 9         18 $length += 1;
1613             }
1614 9         209 my $value = $self->reader->prefix($length);
1615 9         208 $self->reader->forward($length);
1616 9         30 return $value;
1617             }
1618              
1619             sub scan_tag_uri {
1620 9     9 0 23 my $self = shift;
1621 9         30 my $name = shift;
1622 9         14 my $start_mark = shift;
1623 9         21 my $chunks = [];
1624 9         13 my $length = 0;
1625 9         219 my $ch = $self->reader->peek($length);
1626 9         47 while ($ch =~ /^[0-9A-Za-z\-\;\/\?\:\@\&\=\+\$\,\_\.\!\~\*\'\(\)\[\]\%]$/) {
1627 110 50       206 if ($ch eq '%') {
1628 0         0 push @$chunks, $self->reader->prefix($length);
1629 0         0 $self->reader->forward($length);
1630 0         0 $length = 0;
1631 0         0 push @$chunks, $self->scan_uri_escapes($name, $start_mark);
1632             }
1633             else {
1634 110         135 $length += 1;
1635             }
1636 110         2663 $ch = $self->reader->peek($length);
1637             }
1638 9 50       38 if ($length) {
1639 9         219 push @$chunks, $self->reader->prefix($length);
1640 9         216 $self->reader->forward($length);
1641 9         20 $length = 0;
1642             }
1643 9 50       32 if (not @$chunks) {
1644 0         0 throw YAML::Perl::Error::Scanner("while parsing a %s",
1645             $name,
1646             $start_mark,
1647             "expected URI, but found %r",
1648             $ch->encode('utf-8'),
1649             $self->get_mark(),
1650             );
1651             }
1652 9         44 return join '', @$chunks;
1653             }
1654              
1655             sub scan_uri_escapes {
1656 0     0 0 0 my $self = shift;
1657 0         0 die "scan_uri_escapes";
1658             }
1659              
1660             sub scan_line_break {
1661 325     325 0 442 my $self = shift;
1662 325         8345 my $ch = $self->reader->peek();
1663 325 100       1296 if ($ch =~ /[\r\n]/) {
1664 102 50       2569 if ($self->reader->prefix(2) eq "\r\n") {
1665 0         0 $self->reader->forward(2);
1666             }
1667             else {
1668 102         3471 $self->reader->forward(1);
1669             }
1670 102         309 return "\n"
1671             }
1672 223         622 return '';
1673             }
1674              
1675             1;