Filename | /usr/share/perl5/YAML/Loader.pm |
Statements | Executed 838 statements in 11.2ms |
Calls | P | F | Exclusive Time |
Inclusive Time |
Subroutine |
---|---|---|---|---|---|
32 | 1 | 1 | 3.39ms | 10.3ms | _parse | YAML::Loader::
1 | 1 | 1 | 2.12ms | 54.3ms | BEGIN@7 | YAML::Loader::
32 | 1 | 1 | 1.81ms | 3.48ms | _parse_throwaway_comments | YAML::Loader::
1 | 1 | 1 | 767µs | 4.29ms | BEGIN@6 | YAML::Loader::
32 | 1 | 1 | 522µs | 11.1ms | load | YAML::Loader::
96 | 3 | 1 | 475µs | 475µs | CORE:subst (opcode) | YAML::Loader::
96 | 3 | 1 | 402µs | 402µs | CORE:match (opcode) | YAML::Loader::
64 | 1 | 1 | 205µs | 205µs | CORE:substcont (opcode) | YAML::Loader::
32 | 1 | 1 | 71µs | 71µs | CORE:regcomp (opcode) | YAML::Loader::
1 | 1 | 1 | 34µs | 44µs | BEGIN@3 | YAML::Loader::
1 | 1 | 1 | 21µs | 55µs | BEGIN@4 | YAML::Loader::
1 | 1 | 1 | 20µs | 112µs | BEGIN@5 | YAML::Loader::
1 | 1 | 1 | 18µs | 43µs | BEGIN@285 | YAML::Loader::
1 | 1 | 1 | 16µs | 80µs | BEGIN@13 | YAML::Loader::
1 | 1 | 1 | 12µs | 53µs | BEGIN@14 | YAML::Loader::
1 | 1 | 1 | 10µs | 47µs | BEGIN@15 | YAML::Loader::
1 | 1 | 1 | 9µs | 40µs | BEGIN@16 | YAML::Loader::
0 | 0 | 0 | 0s | 0s | _parse_block | YAML::Loader::
0 | 0 | 0 | 0s | 0s | _parse_explicit | YAML::Loader::
0 | 0 | 0 | 0s | 0s | _parse_implicit | YAML::Loader::
0 | 0 | 0 | 0s | 0s | _parse_inline | YAML::Loader::
0 | 0 | 0 | 0s | 0s | _parse_inline_double_quoted | YAML::Loader::
0 | 0 | 0 | 0s | 0s | _parse_inline_mapping | YAML::Loader::
0 | 0 | 0 | 0s | 0s | _parse_inline_seq | YAML::Loader::
0 | 0 | 0 | 0s | 0s | _parse_inline_simple | YAML::Loader::
0 | 0 | 0 | 0s | 0s | _parse_inline_single_quoted | YAML::Loader::
0 | 0 | 0 | 0s | 0s | _parse_mapping | YAML::Loader::
0 | 0 | 0 | 0s | 0s | _parse_next_line | YAML::Loader::
0 | 0 | 0 | 0s | 0s | _parse_node | YAML::Loader::
0 | 0 | 0 | 0s | 0s | _parse_qualifiers | YAML::Loader::
0 | 0 | 0 | 0s | 0s | _parse_seq | YAML::Loader::
0 | 0 | 0 | 0s | 0s | _parse_unfold | YAML::Loader::
0 | 0 | 0 | 0s | 0s | _unescape | YAML::Loader::
Line | State ments |
Time on line |
Calls | Time in subs |
Code |
---|---|---|---|---|---|
1 | package YAML::Loader; | ||||
2 | |||||
3 | 3 | 50µs | 2 | 53µs | # spent 44µs (34+9) within YAML::Loader::BEGIN@3 which was called:
# once (34µs+9µs) by YAML::init_action_object at line 3 # spent 44µs making 1 call to YAML::Loader::BEGIN@3
# spent 9µs making 1 call to strict::import |
4 | 3 | 58µs | 2 | 88µs | # spent 55µs (21+33) within YAML::Loader::BEGIN@4 which was called:
# once (21µs+33µs) by YAML::init_action_object at line 4 # spent 55µs making 1 call to YAML::Loader::BEGIN@4
# spent 33µs making 1 call to warnings::import |
5 | 3 | 49µs | 2 | 205µs | # spent 112µs (20+93) within YAML::Loader::BEGIN@5 which was called:
# once (20µs+93µs) by YAML::init_action_object at line 5 # spent 112µs making 1 call to YAML::Loader::BEGIN@5
# spent 93µs making 1 call to Exporter::import |
6 | 3 | 180µs | 2 | 4.35ms | # spent 4.29ms (767µs+3.52) within YAML::Loader::BEGIN@6 which was called:
# once (767µs+3.52ms) by YAML::init_action_object at line 6 # spent 4.29ms making 1 call to YAML::Loader::BEGIN@6
# spent 61µs making 1 call to Exporter::import |
7 | 3 | 211µs | 2 | 54.3ms | # spent 54.3ms (2.12+52.2) within YAML::Loader::BEGIN@7 which was called:
# once (2.12ms+52.2ms) by YAML::init_action_object at line 7 # spent 54.3ms making 1 call to YAML::Loader::BEGIN@7
# spent 47µs making 1 call to Exporter::import |
8 | |||||
9 | 1 | 2µs | our $VERSION = '0.71'; | ||
10 | 1 | 25µs | our @ISA = 'YAML::Loader::Base'; | ||
11 | |||||
12 | # Context constants | ||||
13 | 3 | 55µs | 2 | 143µs | # spent 80µs (16+64) within YAML::Loader::BEGIN@13 which was called:
# once (16µs+64µs) by YAML::init_action_object at line 13 # spent 80µs making 1 call to YAML::Loader::BEGIN@13
# spent 64µs making 1 call to constant::import |
14 | 3 | 41µs | 2 | 93µs | # spent 53µs (12+40) within YAML::Loader::BEGIN@14 which was called:
# once (12µs+40µs) by YAML::init_action_object at line 14 # spent 53µs making 1 call to YAML::Loader::BEGIN@14
# spent 40µs making 1 call to constant::import |
15 | 3 | 34µs | 2 | 85µs | # spent 47µs (10+37) within YAML::Loader::BEGIN@15 which was called:
# once (10µs+37µs) by YAML::init_action_object at line 15 # spent 47µs making 1 call to YAML::Loader::BEGIN@15
# spent 37µs making 1 call to constant::import |
16 | 3 | 1.68ms | 2 | 72µs | # spent 40µs (9+32) within YAML::Loader::BEGIN@16 which was called:
# once (9µs+32µs) by YAML::init_action_object at line 16 # spent 40µs making 1 call to YAML::Loader::BEGIN@16
# spent 32µs making 1 call to constant::import |
17 | |||||
18 | # Common YAML character sets | ||||
19 | 1 | 900ns | my $ESCAPE_CHAR = '[\\x00-\\x08\\x0b-\\x0d\\x0e-\\x1f]'; | ||
20 | 1 | 500ns | my $FOLD_CHAR = '>'; | ||
21 | 1 | 600ns | my $LIT_CHAR = '|'; | ||
22 | 1 | 1µs | my $LIT_CHAR_RX = "\\$LIT_CHAR"; | ||
23 | |||||
24 | # spent 11.1ms (522µs+10.6) within YAML::Loader::load which was called 32 times, avg 348µs/call:
# 32 times (522µs+10.6ms) by YAML::Load at line 36 of YAML.pm, avg 348µs/call | ||||
25 | 96 | 501µs | my $self = shift; | ||
26 | 32 | 359µs | $self->stream($_[0] || ''); # spent 359µs making 32 calls to YAML::Base::__ANON__[(eval 1057)[YAML/Base.pm:73]:7], avg 11µs/call | ||
27 | 32 | 10.3ms | return $self->_parse(); # spent 10.3ms making 32 calls to YAML::Loader::_parse, avg 320µs/call | ||
28 | } | ||||
29 | |||||
30 | # Top level function for parsing. Parse each document in order and | ||||
31 | # handle processing for YAML headers. | ||||
32 | # spent 10.3ms (3.39+6.87) within YAML::Loader::_parse which was called 32 times, avg 320µs/call:
# 32 times (3.39ms+6.87ms) by YAML::Loader::load at line 27, avg 320µs/call | ||||
33 | 480 | 3.78ms | my $self = shift; | ||
34 | my (%directives, $preface); | ||||
35 | 32 | 161µs | $self->{stream} =~ s|\015\012|\012|g; # spent 161µs making 32 calls to YAML::Loader::CORE:subst, avg 5µs/call | ||
36 | 32 | 39µs | $self->{stream} =~ s|\015|\012|g; # spent 39µs making 32 calls to YAML::Loader::CORE:subst, avg 1µs/call | ||
37 | 32 | 382µs | $self->line(0); # spent 382µs making 32 calls to YAML::Base::__ANON__[(eval 1059)[YAML/Base.pm:73]:7], avg 12µs/call | ||
38 | 96 | 335µs | $self->die('YAML_PARSE_ERR_BAD_CHARS') # spent 139µs making 32 calls to YAML::Base::__ANON__[(eval 1057)[YAML/Base.pm:73]:7], avg 4µs/call
# spent 126µs making 32 calls to YAML::Loader::CORE:match, avg 4µs/call
# spent 71µs making 32 calls to YAML::Loader::CORE:regcomp, avg 2µs/call | ||
39 | if $self->stream =~ /$ESCAPE_CHAR/; | ||||
40 | 128 | 617µs | $self->die('YAML_PARSE_ERR_NO_FINAL_NEWLINE') # spent 275µs making 32 calls to YAML::Loader::CORE:subst, avg 9µs/call
# spent 205µs making 64 calls to YAML::Loader::CORE:substcont, avg 3µs/call
# spent 137µs making 32 calls to YAML::Base::__ANON__[(eval 1057)[YAML/Base.pm:73]:7], avg 4µs/call | ||
41 | if length($self->stream) and | ||||
42 | $self->{stream} !~ s/(.)\n\Z/$1/s; | ||||
43 | 64 | 563µs | $self->lines([split /\x0a/, $self->stream, -1]); # spent 362µs making 32 calls to YAML::Base::__ANON__[(eval 1061)[YAML/Base.pm:73]:7], avg 11µs/call
# spent 201µs making 32 calls to YAML::Base::__ANON__[(eval 1057)[YAML/Base.pm:73]:7], avg 6µs/call | ||
44 | 32 | 150µs | $self->line(1); # spent 150µs making 32 calls to YAML::Base::__ANON__[(eval 1059)[YAML/Base.pm:73]:7], avg 5µs/call | ||
45 | # Throw away any comments or blanks before the header (or start of | ||||
46 | # content for headerless streams) | ||||
47 | 32 | 3.48ms | $self->_parse_throwaway_comments(); # spent 3.48ms making 32 calls to YAML::Loader::_parse_throwaway_comments, avg 109µs/call | ||
48 | 32 | 343µs | $self->document(0); # spent 343µs making 32 calls to YAML::Base::__ANON__[(eval 1058)[YAML/Base.pm:73]:7], avg 11µs/call | ||
49 | 32 | 326µs | $self->documents([]); # spent 326µs making 32 calls to YAML::Base::__ANON__[(eval 1060)[YAML/Base.pm:73]:7], avg 10µs/call | ||
50 | # Add an "assumed" header if there is no header and the stream is | ||||
51 | # not empty (after initial throwaways). | ||||
52 | 32 | 194µs | if (not $self->eos) { # spent 194µs making 32 calls to YAML::Base::__ANON__[(eval 1062)[YAML/Base.pm:73]:7], avg 6µs/call | ||
53 | if ($self->lines->[0] !~ /^---(\s|$)/) { | ||||
54 | unshift @{$self->lines}, '---'; | ||||
55 | $self->{line}--; | ||||
56 | } | ||||
57 | } | ||||
58 | |||||
59 | # Main Loop. Parse out all the top level nodes and return them. | ||||
60 | 32 | 130µs | while (not $self->eos) { # spent 130µs making 32 calls to YAML::Base::__ANON__[(eval 1062)[YAML/Base.pm:73]:7], avg 4µs/call | ||
61 | 1 | 24µs | $self->anchor2node({}); | ||
62 | $self->{document}++; | ||||
63 | $self->done(0); | ||||
64 | $self->level(0); | ||||
65 | $self->offset->[0] = -1; | ||||
66 | |||||
67 | if ($self->lines->[0] =~ /^---\s*(.*)$/) { | ||||
68 | my @words = split /\s+/, $1; | ||||
69 | %directives = (); | ||||
70 | while (@words && $words[0] =~ /^#(\w+):(\S.*)$/) { | ||||
71 | my ($key, $value) = ($1, $2); | ||||
72 | shift(@words); | ||||
73 | if (defined $directives{$key}) { | ||||
74 | $self->warn('YAML_PARSE_WARN_MULTIPLE_DIRECTIVES', | ||||
75 | $key, $self->document); | ||||
76 | next; | ||||
77 | } | ||||
78 | $directives{$key} = $value; | ||||
79 | } | ||||
80 | $self->preface(join ' ', @words); | ||||
81 | } | ||||
82 | else { | ||||
83 | $self->die('YAML_PARSE_ERR_NO_SEPARATOR'); | ||||
84 | } | ||||
85 | |||||
86 | if (not $self->done) { | ||||
87 | $self->_parse_next_line(COLLECTION); | ||||
88 | } | ||||
89 | if ($self->done) { | ||||
90 | $self->{indent} = -1; | ||||
91 | $self->content(''); | ||||
92 | } | ||||
93 | |||||
94 | $directives{YAML} ||= '1.0'; | ||||
95 | $directives{TAB} ||= 'NONE'; | ||||
96 | ($self->{major_version}, $self->{minor_version}) = | ||||
97 | split /\./, $directives{YAML}, 2; | ||||
98 | $self->die('YAML_PARSE_ERR_BAD_MAJOR_VERSION', $directives{YAML}) | ||||
99 | if $self->major_version ne '1'; | ||||
100 | $self->warn('YAML_PARSE_WARN_BAD_MINOR_VERSION', $directives{YAML}) | ||||
101 | if $self->minor_version ne '0'; | ||||
102 | $self->die('Unrecognized TAB policy') | ||||
103 | unless $directives{TAB} =~ /^(NONE|\d+)(:HARD)?$/; | ||||
104 | |||||
105 | push @{$self->documents}, $self->_parse_node(); | ||||
106 | } | ||||
107 | 32 | 147µs | return wantarray ? @{$self->documents} : $self->documents->[-1]; # spent 147µs making 32 calls to YAML::Base::__ANON__[(eval 1060)[YAML/Base.pm:73]:7], avg 5µs/call | ||
108 | } | ||||
109 | |||||
110 | # This function is the dispatcher for parsing each node. Every node | ||||
111 | # recurses back through here. (Inlines are an exception as they have | ||||
112 | # their own sub-parser.) | ||||
113 | sub _parse_node { | ||||
114 | my $self = shift; | ||||
115 | my $preface = $self->preface; | ||||
116 | $self->preface(''); | ||||
117 | my ($node, $type, $indicator, $escape, $chomp) = ('') x 5; | ||||
118 | my ($anchor, $alias, $explicit, $implicit, $class) = ('') x 5; | ||||
119 | ($anchor, $alias, $explicit, $implicit, $preface) = | ||||
120 | $self->_parse_qualifiers($preface); | ||||
121 | if ($anchor) { | ||||
122 | $self->anchor2node->{$anchor} = CORE::bless [], 'YAML-anchor2node'; | ||||
123 | } | ||||
124 | $self->inline(''); | ||||
125 | while (length $preface) { | ||||
126 | my $line = $self->line - 1; | ||||
127 | if ($preface =~ s/^($FOLD_CHAR|$LIT_CHAR_RX)(-|\+)?\d*\s*//) { | ||||
128 | $indicator = $1; | ||||
129 | $chomp = $2 if defined($2); | ||||
130 | } | ||||
131 | else { | ||||
132 | $self->die('YAML_PARSE_ERR_TEXT_AFTER_INDICATOR') if $indicator; | ||||
133 | $self->inline($preface); | ||||
134 | $preface = ''; | ||||
135 | } | ||||
136 | } | ||||
137 | if ($alias) { | ||||
138 | $self->die('YAML_PARSE_ERR_NO_ANCHOR', $alias) | ||||
139 | unless defined $self->anchor2node->{$alias}; | ||||
140 | if (ref($self->anchor2node->{$alias}) ne 'YAML-anchor2node') { | ||||
141 | $node = $self->anchor2node->{$alias}; | ||||
142 | } | ||||
143 | else { | ||||
144 | $node = do {my $sv = "*$alias"}; | ||||
145 | push @{$self->anchor2node->{$alias}}, [\$node, $self->line]; | ||||
146 | } | ||||
147 | } | ||||
148 | elsif (length $self->inline) { | ||||
149 | $node = $self->_parse_inline(1, $implicit, $explicit); | ||||
150 | if (length $self->inline) { | ||||
151 | $self->die('YAML_PARSE_ERR_SINGLE_LINE'); | ||||
152 | } | ||||
153 | } | ||||
154 | elsif ($indicator eq $LIT_CHAR) { | ||||
155 | $self->{level}++; | ||||
156 | $node = $self->_parse_block($chomp); | ||||
157 | $node = $self->_parse_implicit($node) if $implicit; | ||||
158 | $self->{level}--; | ||||
159 | } | ||||
160 | elsif ($indicator eq $FOLD_CHAR) { | ||||
161 | $self->{level}++; | ||||
162 | $node = $self->_parse_unfold($chomp); | ||||
163 | $node = $self->_parse_implicit($node) if $implicit; | ||||
164 | $self->{level}--; | ||||
165 | } | ||||
166 | else { | ||||
167 | $self->{level}++; | ||||
168 | $self->offset->[$self->level] ||= 0; | ||||
169 | if ($self->indent == $self->offset->[$self->level]) { | ||||
170 | if ($self->content =~ /^-( |$)/) { | ||||
171 | $node = $self->_parse_seq($anchor); | ||||
172 | } | ||||
173 | elsif ($self->content =~ /(^\?|\:( |$))/) { | ||||
174 | $node = $self->_parse_mapping($anchor); | ||||
175 | } | ||||
176 | elsif ($preface =~ /^\s*$/) { | ||||
177 | $node = $self->_parse_implicit(''); | ||||
178 | } | ||||
179 | else { | ||||
180 | $self->die('YAML_PARSE_ERR_BAD_NODE'); | ||||
181 | } | ||||
182 | } | ||||
183 | else { | ||||
184 | $node = undef; | ||||
185 | } | ||||
186 | $self->{level}--; | ||||
187 | } | ||||
188 | $#{$self->offset} = $self->level; | ||||
189 | |||||
190 | if ($explicit) { | ||||
191 | if ($class) { | ||||
192 | if (not ref $node) { | ||||
193 | my $copy = $node; | ||||
194 | undef $node; | ||||
195 | $node = \$copy; | ||||
196 | } | ||||
197 | CORE::bless $node, $class; | ||||
198 | } | ||||
199 | else { | ||||
200 | $node = $self->_parse_explicit($node, $explicit); | ||||
201 | } | ||||
202 | } | ||||
203 | if ($anchor) { | ||||
204 | if (ref($self->anchor2node->{$anchor}) eq 'YAML-anchor2node') { | ||||
205 | # XXX Can't remember what this code actually does | ||||
206 | for my $ref (@{$self->anchor2node->{$anchor}}) { | ||||
207 | ${$ref->[0]} = $node; | ||||
208 | $self->warn('YAML_LOAD_WARN_UNRESOLVED_ALIAS', | ||||
209 | $anchor, $ref->[1]); | ||||
210 | } | ||||
211 | } | ||||
212 | $self->anchor2node->{$anchor} = $node; | ||||
213 | } | ||||
214 | return $node; | ||||
215 | } | ||||
216 | |||||
217 | # Preprocess the qualifiers that may be attached to any node. | ||||
218 | sub _parse_qualifiers { | ||||
219 | my $self = shift; | ||||
220 | my ($preface) = @_; | ||||
221 | my ($anchor, $alias, $explicit, $implicit, $token) = ('') x 5; | ||||
222 | $self->inline(''); | ||||
223 | while ($preface =~ /^[&*!]/) { | ||||
224 | my $line = $self->line - 1; | ||||
225 | if ($preface =~ s/^\!(\S+)\s*//) { | ||||
226 | $self->die('YAML_PARSE_ERR_MANY_EXPLICIT') if $explicit; | ||||
227 | $explicit = $1; | ||||
228 | } | ||||
229 | elsif ($preface =~ s/^\!\s*//) { | ||||
230 | $self->die('YAML_PARSE_ERR_MANY_IMPLICIT') if $implicit; | ||||
231 | $implicit = 1; | ||||
232 | } | ||||
233 | elsif ($preface =~ s/^\&([^ ,:]+)\s*//) { | ||||
234 | $token = $1; | ||||
235 | $self->die('YAML_PARSE_ERR_BAD_ANCHOR') | ||||
236 | unless $token =~ /^[a-zA-Z0-9]+$/; | ||||
237 | $self->die('YAML_PARSE_ERR_MANY_ANCHOR') if $anchor; | ||||
238 | $self->die('YAML_PARSE_ERR_ANCHOR_ALIAS') if $alias; | ||||
239 | $anchor = $token; | ||||
240 | } | ||||
241 | elsif ($preface =~ s/^\*([^ ,:]+)\s*//) { | ||||
242 | $token = $1; | ||||
243 | $self->die('YAML_PARSE_ERR_BAD_ALIAS') | ||||
244 | unless $token =~ /^[a-zA-Z0-9]+$/; | ||||
245 | $self->die('YAML_PARSE_ERR_MANY_ALIAS') if $alias; | ||||
246 | $self->die('YAML_PARSE_ERR_ANCHOR_ALIAS') if $anchor; | ||||
247 | $alias = $token; | ||||
248 | } | ||||
249 | } | ||||
250 | return ($anchor, $alias, $explicit, $implicit, $preface); | ||||
251 | } | ||||
252 | |||||
253 | # Morph a node to it's explicit type | ||||
254 | sub _parse_explicit { | ||||
255 | my $self = shift; | ||||
256 | my ($node, $explicit) = @_; | ||||
257 | my ($type, $class); | ||||
258 | if ($explicit =~ /^\!?perl\/(hash|array|ref|scalar)(?:\:(\w(\w|\:\:)*)?)?$/) { | ||||
259 | ($type, $class) = (($1 || ''), ($2 || '')); | ||||
260 | |||||
261 | # FIXME # die unless uc($type) eq ref($node) ? | ||||
262 | |||||
263 | if ( $type eq "ref" ) { | ||||
264 | $self->die('YAML_LOAD_ERR_NO_DEFAULT_VALUE', 'XXX', $explicit) | ||||
265 | unless exists $node->{VALUE()} and scalar(keys %$node) == 1; | ||||
266 | |||||
267 | my $value = $node->{VALUE()}; | ||||
268 | $node = \$value; | ||||
269 | } | ||||
270 | |||||
271 | if ( $type eq "scalar" and length($class) and !ref($node) ) { | ||||
272 | my $value = $node; | ||||
273 | $node = \$value; | ||||
274 | } | ||||
275 | |||||
276 | if ( length($class) ) { | ||||
277 | CORE::bless($node, $class); | ||||
278 | } | ||||
279 | |||||
280 | return $node; | ||||
281 | } | ||||
282 | if ($explicit =~ m{^!?perl/(glob|regexp|code)(?:\:(\w(\w|\:\:)*)?)?$}) { | ||||
283 | ($type, $class) = (($1 || ''), ($2 || '')); | ||||
284 | my $type_class = "YAML::Type::$type"; | ||||
285 | 3 | 2.79ms | 2 | 68µs | # spent 43µs (18+25) within YAML::Loader::BEGIN@285 which was called:
# once (18µs+25µs) by YAML::init_action_object at line 285 # spent 43µs making 1 call to YAML::Loader::BEGIN@285
# spent 25µs making 1 call to strict::unimport |
286 | if ($type_class->can('yaml_load')) { | ||||
287 | return $type_class->yaml_load($node, $class, $self); | ||||
288 | } | ||||
289 | else { | ||||
290 | $self->die('YAML_LOAD_ERR_NO_CONVERT', 'XXX', $explicit); | ||||
291 | } | ||||
292 | } | ||||
293 | # This !perl/@Foo and !perl/$Foo are deprecated but still parsed | ||||
294 | elsif ($YAML::TagClass->{$explicit} || | ||||
295 | $explicit =~ m{^perl/(\@|\$)?([a-zA-Z](\w|::)+)$} | ||||
296 | ) { | ||||
297 | $class = $YAML::TagClass->{$explicit} || $2; | ||||
298 | if ($class->can('yaml_load')) { | ||||
299 | require YAML::Node; | ||||
300 | return $class->yaml_load(YAML::Node->new($node, $explicit)); | ||||
301 | } | ||||
302 | else { | ||||
303 | if (ref $node) { | ||||
304 | return CORE::bless $node, $class; | ||||
305 | } | ||||
306 | else { | ||||
307 | return CORE::bless \$node, $class; | ||||
308 | } | ||||
309 | } | ||||
310 | } | ||||
311 | elsif (ref $node) { | ||||
312 | require YAML::Node; | ||||
313 | return YAML::Node->new($node, $explicit); | ||||
314 | } | ||||
315 | else { | ||||
316 | # XXX This is likely wrong. Failing test: | ||||
317 | # --- !unknown 'scalar value' | ||||
318 | return $node; | ||||
319 | } | ||||
320 | } | ||||
321 | |||||
322 | # Parse a YAML mapping into a Perl hash | ||||
323 | sub _parse_mapping { | ||||
324 | my $self = shift; | ||||
325 | my ($anchor) = @_; | ||||
326 | my $mapping = {}; | ||||
327 | $self->anchor2node->{$anchor} = $mapping; | ||||
328 | my $key; | ||||
329 | while (not $self->done and $self->indent == $self->offset->[$self->level]) { | ||||
330 | # If structured key: | ||||
331 | if ($self->{content} =~ s/^\?\s*//) { | ||||
332 | $self->preface($self->content); | ||||
333 | $self->_parse_next_line(COLLECTION); | ||||
334 | $key = $self->_parse_node(); | ||||
335 | $key = "$key"; | ||||
336 | } | ||||
337 | # If "default" key (equals sign) | ||||
338 | elsif ($self->{content} =~ s/^\=\s*//) { | ||||
339 | $key = VALUE; | ||||
340 | } | ||||
341 | # If "comment" key (slash slash) | ||||
342 | elsif ($self->{content} =~ s/^\=\s*//) { | ||||
343 | $key = COMMENT; | ||||
344 | } | ||||
345 | # Regular scalar key: | ||||
346 | else { | ||||
347 | $self->inline($self->content); | ||||
348 | $key = $self->_parse_inline(); | ||||
349 | $key = "$key"; | ||||
350 | $self->content($self->inline); | ||||
351 | $self->inline(''); | ||||
352 | } | ||||
353 | |||||
354 | unless ($self->{content} =~ s/^:\s*//) { | ||||
355 | $self->die('YAML_LOAD_ERR_BAD_MAP_ELEMENT'); | ||||
356 | } | ||||
357 | $self->preface($self->content); | ||||
358 | my $line = $self->line; | ||||
359 | $self->_parse_next_line(COLLECTION); | ||||
360 | my $value = $self->_parse_node(); | ||||
361 | if (exists $mapping->{$key}) { | ||||
362 | $self->warn('YAML_LOAD_WARN_DUPLICATE_KEY'); | ||||
363 | } | ||||
364 | else { | ||||
365 | $mapping->{$key} = $value; | ||||
366 | } | ||||
367 | } | ||||
368 | return $mapping; | ||||
369 | } | ||||
370 | |||||
371 | # Parse a YAML sequence into a Perl array | ||||
372 | sub _parse_seq { | ||||
373 | my $self = shift; | ||||
374 | my ($anchor) = @_; | ||||
375 | my $seq = []; | ||||
376 | $self->anchor2node->{$anchor} = $seq; | ||||
377 | while (not $self->done and $self->indent == $self->offset->[$self->level]) { | ||||
378 | if ($self->content =~ /^-(?: (.*))?$/) { | ||||
379 | $self->preface(defined($1) ? $1 : ''); | ||||
380 | } | ||||
381 | else { | ||||
382 | $self->die('YAML_LOAD_ERR_BAD_SEQ_ELEMENT'); | ||||
383 | } | ||||
384 | if ($self->preface =~ /^(\s*)(\w.*\:(?: |$).*)$/) { | ||||
385 | $self->indent($self->offset->[$self->level] + 2 + length($1)); | ||||
386 | $self->content($2); | ||||
387 | $self->level($self->level + 1); | ||||
388 | $self->offset->[$self->level] = $self->indent; | ||||
389 | $self->preface(''); | ||||
390 | push @$seq, $self->_parse_mapping(''); | ||||
391 | $self->{level}--; | ||||
392 | $#{$self->offset} = $self->level; | ||||
393 | } | ||||
394 | else { | ||||
395 | $self->_parse_next_line(COLLECTION); | ||||
396 | push @$seq, $self->_parse_node(); | ||||
397 | } | ||||
398 | } | ||||
399 | return $seq; | ||||
400 | } | ||||
401 | |||||
402 | # Parse an inline value. Since YAML supports inline collections, this is | ||||
403 | # the top level of a sub parsing. | ||||
404 | sub _parse_inline { | ||||
405 | my $self = shift; | ||||
406 | my ($top, $top_implicit, $top_explicit) = (@_, '', '', ''); | ||||
407 | $self->{inline} =~ s/^\s*(.*)\s*$/$1/; # OUCH - mugwump | ||||
408 | my ($node, $anchor, $alias, $explicit, $implicit) = ('') x 5; | ||||
409 | ($anchor, $alias, $explicit, $implicit, $self->{inline}) = | ||||
410 | $self->_parse_qualifiers($self->inline); | ||||
411 | if ($anchor) { | ||||
412 | $self->anchor2node->{$anchor} = CORE::bless [], 'YAML-anchor2node'; | ||||
413 | } | ||||
414 | $implicit ||= $top_implicit; | ||||
415 | $explicit ||= $top_explicit; | ||||
416 | ($top_implicit, $top_explicit) = ('', ''); | ||||
417 | if ($alias) { | ||||
418 | $self->die('YAML_PARSE_ERR_NO_ANCHOR', $alias) | ||||
419 | unless defined $self->anchor2node->{$alias}; | ||||
420 | if (ref($self->anchor2node->{$alias}) ne 'YAML-anchor2node') { | ||||
421 | $node = $self->anchor2node->{$alias}; | ||||
422 | } | ||||
423 | else { | ||||
424 | $node = do {my $sv = "*$alias"}; | ||||
425 | push @{$self->anchor2node->{$alias}}, [\$node, $self->line]; | ||||
426 | } | ||||
427 | } | ||||
428 | elsif ($self->inline =~ /^\{/) { | ||||
429 | $node = $self->_parse_inline_mapping($anchor); | ||||
430 | } | ||||
431 | elsif ($self->inline =~ /^\[/) { | ||||
432 | $node = $self->_parse_inline_seq($anchor); | ||||
433 | } | ||||
434 | elsif ($self->inline =~ /^"/) { | ||||
435 | $node = $self->_parse_inline_double_quoted(); | ||||
436 | $node = $self->_unescape($node); | ||||
437 | $node = $self->_parse_implicit($node) if $implicit; | ||||
438 | } | ||||
439 | elsif ($self->inline =~ /^'/) { | ||||
440 | $node = $self->_parse_inline_single_quoted(); | ||||
441 | $node = $self->_parse_implicit($node) if $implicit; | ||||
442 | } | ||||
443 | else { | ||||
444 | if ($top) { | ||||
445 | $node = $self->inline; | ||||
446 | $self->inline(''); | ||||
447 | } | ||||
448 | else { | ||||
449 | $node = $self->_parse_inline_simple(); | ||||
450 | } | ||||
451 | $node = $self->_parse_implicit($node) unless $explicit; | ||||
452 | } | ||||
453 | if ($explicit) { | ||||
454 | $node = $self->_parse_explicit($node, $explicit); | ||||
455 | } | ||||
456 | if ($anchor) { | ||||
457 | if (ref($self->anchor2node->{$anchor}) eq 'YAML-anchor2node') { | ||||
458 | for my $ref (@{$self->anchor2node->{$anchor}}) { | ||||
459 | ${$ref->[0]} = $node; | ||||
460 | $self->warn('YAML_LOAD_WARN_UNRESOLVED_ALIAS', | ||||
461 | $anchor, $ref->[1]); | ||||
462 | } | ||||
463 | } | ||||
464 | $self->anchor2node->{$anchor} = $node; | ||||
465 | } | ||||
466 | return $node; | ||||
467 | } | ||||
468 | |||||
469 | # Parse the inline YAML mapping into a Perl hash | ||||
470 | sub _parse_inline_mapping { | ||||
471 | my $self = shift; | ||||
472 | my ($anchor) = @_; | ||||
473 | my $node = {}; | ||||
474 | $self->anchor2node->{$anchor} = $node; | ||||
475 | |||||
476 | $self->die('YAML_PARSE_ERR_INLINE_MAP') | ||||
477 | unless $self->{inline} =~ s/^\{\s*//; | ||||
478 | while (not $self->{inline} =~ s/^\s*\}//) { | ||||
479 | my $key = $self->_parse_inline(); | ||||
480 | $self->die('YAML_PARSE_ERR_INLINE_MAP') | ||||
481 | unless $self->{inline} =~ s/^\: \s*//; | ||||
482 | my $value = $self->_parse_inline(); | ||||
483 | if (exists $node->{$key}) { | ||||
484 | $self->warn('YAML_LOAD_WARN_DUPLICATE_KEY'); | ||||
485 | } | ||||
486 | else { | ||||
487 | $node->{$key} = $value; | ||||
488 | } | ||||
489 | next if $self->inline =~ /^\s*\}/; | ||||
490 | $self->die('YAML_PARSE_ERR_INLINE_MAP') | ||||
491 | unless $self->{inline} =~ s/^\,\s*//; | ||||
492 | } | ||||
493 | return $node; | ||||
494 | } | ||||
495 | |||||
496 | # Parse the inline YAML sequence into a Perl array | ||||
497 | sub _parse_inline_seq { | ||||
498 | my $self = shift; | ||||
499 | my ($anchor) = @_; | ||||
500 | my $node = []; | ||||
501 | $self->anchor2node->{$anchor} = $node; | ||||
502 | |||||
503 | $self->die('YAML_PARSE_ERR_INLINE_SEQUENCE') | ||||
504 | unless $self->{inline} =~ s/^\[\s*//; | ||||
505 | while (not $self->{inline} =~ s/^\s*\]//) { | ||||
506 | my $value = $self->_parse_inline(); | ||||
507 | push @$node, $value; | ||||
508 | next if $self->inline =~ /^\s*\]/; | ||||
509 | $self->die('YAML_PARSE_ERR_INLINE_SEQUENCE') | ||||
510 | unless $self->{inline} =~ s/^\,\s*//; | ||||
511 | } | ||||
512 | return $node; | ||||
513 | } | ||||
514 | |||||
515 | # Parse the inline double quoted string. | ||||
516 | sub _parse_inline_double_quoted { | ||||
517 | my $self = shift; | ||||
518 | my $node; | ||||
519 | if ($self->inline =~ /^"((?:\\"|[^"])*)"\s*(.*)$/) { | ||||
520 | $node = $1; | ||||
521 | $self->inline($2); | ||||
522 | $node =~ s/\\"/"/g; | ||||
523 | } | ||||
524 | else { | ||||
525 | $self->die('YAML_PARSE_ERR_BAD_DOUBLE'); | ||||
526 | } | ||||
527 | return $node; | ||||
528 | } | ||||
529 | |||||
530 | |||||
531 | # Parse the inline single quoted string. | ||||
532 | sub _parse_inline_single_quoted { | ||||
533 | my $self = shift; | ||||
534 | my $node; | ||||
535 | if ($self->inline =~ /^'((?:''|[^'])*)'\s*(.*)$/) { | ||||
536 | $node = $1; | ||||
537 | $self->inline($2); | ||||
538 | $node =~ s/''/'/g; | ||||
539 | } | ||||
540 | else { | ||||
541 | $self->die('YAML_PARSE_ERR_BAD_SINGLE'); | ||||
542 | } | ||||
543 | return $node; | ||||
544 | } | ||||
545 | |||||
546 | # Parse the inline unquoted string and do implicit typing. | ||||
547 | sub _parse_inline_simple { | ||||
548 | my $self = shift; | ||||
549 | my $value; | ||||
550 | if ($self->inline =~ /^(|[^!@#%^&*].*?)(?=[\[\]\{\},]|, |: |- |:\s*$|$)/) { | ||||
551 | $value = $1; | ||||
552 | substr($self->{inline}, 0, length($1)) = ''; | ||||
553 | } | ||||
554 | else { | ||||
555 | $self->die('YAML_PARSE_ERR_BAD_INLINE_IMPLICIT', $value); | ||||
556 | } | ||||
557 | return $value; | ||||
558 | } | ||||
559 | |||||
560 | sub _parse_implicit { | ||||
561 | my $self = shift; | ||||
562 | my ($value) = @_; | ||||
563 | $value =~ s/\s*$//; | ||||
564 | return $value if $value eq ''; | ||||
565 | return undef if $value =~ /^~$/; | ||||
566 | return $value | ||||
567 | unless $value =~ /^[\@\`\^]/ or | ||||
568 | $value =~ /^[\-\?]\s/; | ||||
569 | $self->die('YAML_PARSE_ERR_BAD_IMPLICIT', $value); | ||||
570 | } | ||||
571 | |||||
572 | # Unfold a YAML multiline scalar into a single string. | ||||
573 | sub _parse_unfold { | ||||
574 | my $self = shift; | ||||
575 | my ($chomp) = @_; | ||||
576 | my $node = ''; | ||||
577 | my $space = 0; | ||||
578 | while (not $self->done and $self->indent == $self->offset->[$self->level]) { | ||||
579 | $node .= $self->content. "\n"; | ||||
580 | $self->_parse_next_line(LEAF); | ||||
581 | } | ||||
582 | $node =~ s/^(\S.*)\n(?=\S)/$1 /gm; | ||||
583 | $node =~ s/^(\S.*)\n(\n+\S)/$1$2/gm; | ||||
584 | $node =~ s/\n*\Z// unless $chomp eq '+'; | ||||
585 | $node .= "\n" unless $chomp; | ||||
586 | return $node; | ||||
587 | } | ||||
588 | |||||
589 | # Parse a YAML block style scalar. This is like a Perl here-document. | ||||
590 | sub _parse_block { | ||||
591 | my $self = shift; | ||||
592 | my ($chomp) = @_; | ||||
593 | my $node = ''; | ||||
594 | while (not $self->done and $self->indent == $self->offset->[$self->level]) { | ||||
595 | $node .= $self->content . "\n"; | ||||
596 | $self->_parse_next_line(LEAF); | ||||
597 | } | ||||
598 | return $node if '+' eq $chomp; | ||||
599 | $node =~ s/\n*\Z/\n/; | ||||
600 | $node =~ s/\n\Z// if $chomp eq '-'; | ||||
601 | return $node; | ||||
602 | } | ||||
603 | |||||
604 | # Handle Perl style '#' comments. Comments must be at the same indentation | ||||
605 | # level as the collection line following them. | ||||
606 | # spent 3.48ms (1.81+1.67) within YAML::Loader::_parse_throwaway_comments which was called 32 times, avg 109µs/call:
# 32 times (1.81ms+1.67ms) by YAML::Loader::_parse at line 47, avg 109µs/call | ||||
607 | 96 | 554µs | my $self = shift; | ||
608 | 96 | 412µs | while (@{$self->lines} and # spent 243µs making 64 calls to YAML::Base::__ANON__[(eval 1061)[YAML/Base.pm:73]:7], avg 4µs/call
# spent 168µs making 32 calls to YAML::Loader::CORE:match, avg 5µs/call | ||
609 | $self->lines->[0] =~ m{^\s*(\#|$)} | ||||
610 | ) { | ||||
611 | 128 | 1.15ms | 64 | 273µs | shift @{$self->lines}; # spent 273µs making 64 calls to YAML::Base::__ANON__[(eval 1061)[YAML/Base.pm:73]:7], avg 4µs/call |
612 | 128 | 454µs | $self->{line}++; # spent 346µs making 96 calls to YAML::Base::__ANON__[(eval 1061)[YAML/Base.pm:73]:7], avg 4µs/call
# spent 108µs making 32 calls to YAML::Loader::CORE:match, avg 3µs/call | ||
613 | } | ||||
614 | 64 | 533µs | $self->eos($self->{done} = not @{$self->lines}); # spent 419µs making 32 calls to YAML::Base::__ANON__[(eval 1062)[YAML/Base.pm:73]:7], avg 13µs/call
# spent 113µs making 32 calls to YAML::Base::__ANON__[(eval 1061)[YAML/Base.pm:73]:7], avg 4µs/call | ||
615 | } | ||||
616 | |||||
617 | # This is the routine that controls what line is being parsed. It gets called | ||||
618 | # once for each line in the YAML stream. | ||||
619 | # | ||||
620 | # This routine must: | ||||
621 | # 1) Skip past the current line | ||||
622 | # 2) Determine the indentation offset for a new level | ||||
623 | # 3) Find the next _content_ line | ||||
624 | # A) Skip over any throwaways (Comments/blanks) | ||||
625 | # B) Set $self->indent, $self->content, $self->line | ||||
626 | # 4) Expand tabs appropriately | ||||
627 | sub _parse_next_line { | ||||
628 | my $self = shift; | ||||
629 | my ($type) = @_; | ||||
630 | my $level = $self->level; | ||||
631 | my $offset = $self->offset->[$level]; | ||||
632 | $self->die('YAML_EMIT_ERR_BAD_LEVEL') unless defined $offset; | ||||
633 | shift @{$self->lines}; | ||||
634 | $self->eos($self->{done} = not @{$self->lines}); | ||||
635 | return if $self->eos; | ||||
636 | $self->{line}++; | ||||
637 | |||||
638 | # Determine the offset for a new leaf node | ||||
639 | if ($self->preface =~ | ||||
640 | qr/(?:^|\s)(?:$FOLD_CHAR|$LIT_CHAR_RX)(?:-|\+)?(\d*)\s*$/ | ||||
641 | ) { | ||||
642 | $self->die('YAML_PARSE_ERR_ZERO_INDENT') | ||||
643 | if length($1) and $1 == 0; | ||||
644 | $type = LEAF; | ||||
645 | if (length($1)) { | ||||
646 | $self->offset->[$level + 1] = $offset + $1; | ||||
647 | } | ||||
648 | else { | ||||
649 | # First get rid of any comments. | ||||
650 | while (@{$self->lines} && ($self->lines->[0] =~ /^\s*#/)) { | ||||
651 | $self->lines->[0] =~ /^( *)/ or die; | ||||
652 | last unless length($1) <= $offset; | ||||
653 | shift @{$self->lines}; | ||||
654 | $self->{line}++; | ||||
655 | } | ||||
656 | $self->eos($self->{done} = not @{$self->lines}); | ||||
657 | return if $self->eos; | ||||
658 | if ($self->lines->[0] =~ /^( *)\S/ and length($1) > $offset) { | ||||
659 | $self->offset->[$level+1] = length($1); | ||||
660 | } | ||||
661 | else { | ||||
662 | $self->offset->[$level+1] = $offset + 1; | ||||
663 | } | ||||
664 | } | ||||
665 | $offset = $self->offset->[++$level]; | ||||
666 | } | ||||
667 | # Determine the offset for a new collection level | ||||
668 | elsif ($type == COLLECTION and | ||||
669 | $self->preface =~ /^(\s*(\!\S*|\&\S+))*\s*$/) { | ||||
670 | $self->_parse_throwaway_comments(); | ||||
671 | if ($self->eos) { | ||||
672 | $self->offset->[$level+1] = $offset + 1; | ||||
673 | return; | ||||
674 | } | ||||
675 | else { | ||||
676 | $self->lines->[0] =~ /^( *)\S/ or die; | ||||
677 | if (length($1) > $offset) { | ||||
678 | $self->offset->[$level+1] = length($1); | ||||
679 | } | ||||
680 | else { | ||||
681 | $self->offset->[$level+1] = $offset + 1; | ||||
682 | } | ||||
683 | } | ||||
684 | $offset = $self->offset->[++$level]; | ||||
685 | } | ||||
686 | |||||
687 | if ($type == LEAF) { | ||||
688 | while (@{$self->lines} and | ||||
689 | $self->lines->[0] =~ m{^( *)(\#)} and | ||||
690 | length($1) < $offset | ||||
691 | ) { | ||||
692 | shift @{$self->lines}; | ||||
693 | $self->{line}++; | ||||
694 | } | ||||
695 | $self->eos($self->{done} = not @{$self->lines}); | ||||
696 | } | ||||
697 | else { | ||||
698 | $self->_parse_throwaway_comments(); | ||||
699 | } | ||||
700 | return if $self->eos; | ||||
701 | |||||
702 | if ($self->lines->[0] =~ /^---(\s|$)/) { | ||||
703 | $self->done(1); | ||||
704 | return; | ||||
705 | } | ||||
706 | if ($type == LEAF and | ||||
707 | $self->lines->[0] =~ /^ {$offset}(.*)$/ | ||||
708 | ) { | ||||
709 | $self->indent($offset); | ||||
710 | $self->content($1); | ||||
711 | } | ||||
712 | elsif ($self->lines->[0] =~ /^\s*$/) { | ||||
713 | $self->indent($offset); | ||||
714 | $self->content(''); | ||||
715 | } | ||||
716 | else { | ||||
717 | $self->lines->[0] =~ /^( *)(\S.*)$/; | ||||
718 | while ($self->offset->[$level] > length($1)) { | ||||
719 | $level--; | ||||
720 | } | ||||
721 | $self->die('YAML_PARSE_ERR_INCONSISTENT_INDENTATION') | ||||
722 | if $self->offset->[$level] != length($1); | ||||
723 | $self->indent(length($1)); | ||||
724 | $self->content($2); | ||||
725 | } | ||||
726 | $self->die('YAML_PARSE_ERR_INDENTATION') | ||||
727 | if $self->indent - $offset > 1; | ||||
728 | } | ||||
729 | |||||
730 | #============================================================================== | ||||
731 | # Utility subroutines. | ||||
732 | #============================================================================== | ||||
733 | |||||
734 | # Printable characters for escapes | ||||
735 | 1 | 9µs | my %unescapes = ( | ||
736 | 0 => "\x00", | ||||
737 | a => "\x07", | ||||
738 | t => "\x09", | ||||
739 | n => "\x0a", | ||||
740 | 'v' => "\x0b", # Potential v-string error on 5.6.2 if not quoted | ||||
741 | f => "\x0c", | ||||
742 | r => "\x0d", | ||||
743 | e => "\x1b", | ||||
744 | '\\' => '\\', | ||||
745 | ); | ||||
746 | |||||
747 | # Transform all the backslash style escape characters to their literal meaning | ||||
748 | sub _unescape { | ||||
749 | my $self = shift; | ||||
750 | my ($node) = @_; | ||||
751 | $node =~ s/\\([never\\fart0]|x([0-9a-fA-F]{2}))/ | ||||
752 | (length($1)>1)?pack("H2",$2):$unescapes{$1}/gex; | ||||
753 | return $node; | ||||
754 | } | ||||
755 | |||||
756 | 1 | 14µs | 1; | ||
757 | |||||
758 | __END__ | ||||
# spent 402µs within YAML::Loader::CORE:match which was called 96 times, avg 4µs/call:
# 32 times (168µs+0s) by YAML::Loader::_parse_throwaway_comments at line 608, avg 5µs/call
# 32 times (126µs+0s) by YAML::Loader::_parse at line 38, avg 4µs/call
# 32 times (108µs+0s) by YAML::Loader::_parse_throwaway_comments at line 612, avg 3µs/call | |||||
# spent 71µs within YAML::Loader::CORE:regcomp which was called 32 times, avg 2µs/call:
# 32 times (71µs+0s) by YAML::Loader::_parse at line 38, avg 2µs/call | |||||
sub YAML::Loader::CORE:subst; # opcode | |||||
# spent 205µs within YAML::Loader::CORE:substcont which was called 64 times, avg 3µs/call:
# 64 times (205µs+0s) by YAML::Loader::_parse at line 40, avg 3µs/call |