74
|
1 //
|
|
2 // Copyright (c) 2011-2019 Canonical Ltd
|
|
3 // Copyright (c) 2006-2010 Kirill Simonov
|
|
4 //
|
|
5 // Permission is hereby granted, free of charge, to any person obtaining a copy of
|
|
6 // this software and associated documentation files (the "Software"), to deal in
|
|
7 // the Software without restriction, including without limitation the rights to
|
|
8 // use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies
|
|
9 // of the Software, and to permit persons to whom the Software is furnished to do
|
|
10 // so, subject to the following conditions:
|
|
11 //
|
|
12 // The above copyright notice and this permission notice shall be included in all
|
|
13 // copies or substantial portions of the Software.
|
|
14 //
|
|
15 // THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
|
16 // IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
|
17 // FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
|
18 // AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
|
19 // LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
|
20 // OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
|
21 // SOFTWARE.
|
|
22
|
|
23 package yaml
|
|
24
|
|
25 import (
|
|
26 "bytes"
|
|
27 "fmt"
|
|
28 )
|
|
29
|
|
30 // Introduction
|
|
31 // ************
|
|
32 //
|
|
33 // The following notes assume that you are familiar with the YAML specification
|
|
34 // (http://yaml.org/spec/1.2/spec.html). We mostly follow it, although in
|
|
35 // some cases we are less restrictive that it requires.
|
|
36 //
|
|
37 // The process of transforming a YAML stream into a sequence of events is
|
|
38 // divided on two steps: Scanning and Parsing.
|
|
39 //
|
|
40 // The Scanner transforms the input stream into a sequence of tokens, while the
|
|
41 // parser transform the sequence of tokens produced by the Scanner into a
|
|
42 // sequence of parsing events.
|
|
43 //
|
|
44 // The Scanner is rather clever and complicated. The Parser, on the contrary,
|
|
45 // is a straightforward implementation of a recursive-descendant parser (or,
|
|
46 // LL(1) parser, as it is usually called).
|
|
47 //
|
|
48 // Actually there are two issues of Scanning that might be called "clever", the
|
|
49 // rest is quite straightforward. The issues are "block collection start" and
|
|
50 // "simple keys". Both issues are explained below in details.
|
|
51 //
|
|
52 // Here the Scanning step is explained and implemented. We start with the list
|
|
53 // of all the tokens produced by the Scanner together with short descriptions.
|
|
54 //
|
|
55 // Now, tokens:
|
|
56 //
|
|
57 // STREAM-START(encoding) # The stream start.
|
|
58 // STREAM-END # The stream end.
|
|
59 // VERSION-DIRECTIVE(major,minor) # The '%YAML' directive.
|
|
60 // TAG-DIRECTIVE(handle,prefix) # The '%TAG' directive.
|
|
61 // DOCUMENT-START # '---'
|
|
62 // DOCUMENT-END # '...'
|
|
63 // BLOCK-SEQUENCE-START # Indentation increase denoting a block
|
|
64 // BLOCK-MAPPING-START # sequence or a block mapping.
|
|
65 // BLOCK-END # Indentation decrease.
|
|
66 // FLOW-SEQUENCE-START # '['
|
|
67 // FLOW-SEQUENCE-END # ']'
|
|
68 // BLOCK-SEQUENCE-START # '{'
|
|
69 // BLOCK-SEQUENCE-END # '}'
|
|
70 // BLOCK-ENTRY # '-'
|
|
71 // FLOW-ENTRY # ','
|
|
72 // KEY # '?' or nothing (simple keys).
|
|
73 // VALUE # ':'
|
|
74 // ALIAS(anchor) # '*anchor'
|
|
75 // ANCHOR(anchor) # '&anchor'
|
|
76 // TAG(handle,suffix) # '!handle!suffix'
|
|
77 // SCALAR(value,style) # A scalar.
|
|
78 //
|
|
79 // The following two tokens are "virtual" tokens denoting the beginning and the
|
|
80 // end of the stream:
|
|
81 //
|
|
82 // STREAM-START(encoding)
|
|
83 // STREAM-END
|
|
84 //
|
|
85 // We pass the information about the input stream encoding with the
|
|
86 // STREAM-START token.
|
|
87 //
|
|
88 // The next two tokens are responsible for tags:
|
|
89 //
|
|
90 // VERSION-DIRECTIVE(major,minor)
|
|
91 // TAG-DIRECTIVE(handle,prefix)
|
|
92 //
|
|
93 // Example:
|
|
94 //
|
|
95 // %YAML 1.1
|
|
96 // %TAG ! !foo
|
|
97 // %TAG !yaml! tag:yaml.org,2002:
|
|
98 // ---
|
|
99 //
|
|
100 // The correspoding sequence of tokens:
|
|
101 //
|
|
102 // STREAM-START(utf-8)
|
|
103 // VERSION-DIRECTIVE(1,1)
|
|
104 // TAG-DIRECTIVE("!","!foo")
|
|
105 // TAG-DIRECTIVE("!yaml","tag:yaml.org,2002:")
|
|
106 // DOCUMENT-START
|
|
107 // STREAM-END
|
|
108 //
|
|
109 // Note that the VERSION-DIRECTIVE and TAG-DIRECTIVE tokens occupy a whole
|
|
110 // line.
|
|
111 //
|
|
112 // The document start and end indicators are represented by:
|
|
113 //
|
|
114 // DOCUMENT-START
|
|
115 // DOCUMENT-END
|
|
116 //
|
|
117 // Note that if a YAML stream contains an implicit document (without '---'
|
|
118 // and '...' indicators), no DOCUMENT-START and DOCUMENT-END tokens will be
|
|
119 // produced.
|
|
120 //
|
|
121 // In the following examples, we present whole documents together with the
|
|
122 // produced tokens.
|
|
123 //
|
|
124 // 1. An implicit document:
|
|
125 //
|
|
126 // 'a scalar'
|
|
127 //
|
|
128 // Tokens:
|
|
129 //
|
|
130 // STREAM-START(utf-8)
|
|
131 // SCALAR("a scalar",single-quoted)
|
|
132 // STREAM-END
|
|
133 //
|
|
134 // 2. An explicit document:
|
|
135 //
|
|
136 // ---
|
|
137 // 'a scalar'
|
|
138 // ...
|
|
139 //
|
|
140 // Tokens:
|
|
141 //
|
|
142 // STREAM-START(utf-8)
|
|
143 // DOCUMENT-START
|
|
144 // SCALAR("a scalar",single-quoted)
|
|
145 // DOCUMENT-END
|
|
146 // STREAM-END
|
|
147 //
|
|
148 // 3. Several documents in a stream:
|
|
149 //
|
|
150 // 'a scalar'
|
|
151 // ---
|
|
152 // 'another scalar'
|
|
153 // ---
|
|
154 // 'yet another scalar'
|
|
155 //
|
|
156 // Tokens:
|
|
157 //
|
|
158 // STREAM-START(utf-8)
|
|
159 // SCALAR("a scalar",single-quoted)
|
|
160 // DOCUMENT-START
|
|
161 // SCALAR("another scalar",single-quoted)
|
|
162 // DOCUMENT-START
|
|
163 // SCALAR("yet another scalar",single-quoted)
|
|
164 // STREAM-END
|
|
165 //
|
|
166 // We have already introduced the SCALAR token above. The following tokens are
|
|
167 // used to describe aliases, anchors, tag, and scalars:
|
|
168 //
|
|
169 // ALIAS(anchor)
|
|
170 // ANCHOR(anchor)
|
|
171 // TAG(handle,suffix)
|
|
172 // SCALAR(value,style)
|
|
173 //
|
|
174 // The following series of examples illustrate the usage of these tokens:
|
|
175 //
|
|
176 // 1. A recursive sequence:
|
|
177 //
|
|
178 // &A [ *A ]
|
|
179 //
|
|
180 // Tokens:
|
|
181 //
|
|
182 // STREAM-START(utf-8)
|
|
183 // ANCHOR("A")
|
|
184 // FLOW-SEQUENCE-START
|
|
185 // ALIAS("A")
|
|
186 // FLOW-SEQUENCE-END
|
|
187 // STREAM-END
|
|
188 //
|
|
189 // 2. A tagged scalar:
|
|
190 //
|
|
191 // !!float "3.14" # A good approximation.
|
|
192 //
|
|
193 // Tokens:
|
|
194 //
|
|
195 // STREAM-START(utf-8)
|
|
196 // TAG("!!","float")
|
|
197 // SCALAR("3.14",double-quoted)
|
|
198 // STREAM-END
|
|
199 //
|
|
200 // 3. Various scalar styles:
|
|
201 //
|
|
202 // --- # Implicit empty plain scalars do not produce tokens.
|
|
203 // --- a plain scalar
|
|
204 // --- 'a single-quoted scalar'
|
|
205 // --- "a double-quoted scalar"
|
|
206 // --- |-
|
|
207 // a literal scalar
|
|
208 // --- >-
|
|
209 // a folded
|
|
210 // scalar
|
|
211 //
|
|
212 // Tokens:
|
|
213 //
|
|
214 // STREAM-START(utf-8)
|
|
215 // DOCUMENT-START
|
|
216 // DOCUMENT-START
|
|
217 // SCALAR("a plain scalar",plain)
|
|
218 // DOCUMENT-START
|
|
219 // SCALAR("a single-quoted scalar",single-quoted)
|
|
220 // DOCUMENT-START
|
|
221 // SCALAR("a double-quoted scalar",double-quoted)
|
|
222 // DOCUMENT-START
|
|
223 // SCALAR("a literal scalar",literal)
|
|
224 // DOCUMENT-START
|
|
225 // SCALAR("a folded scalar",folded)
|
|
226 // STREAM-END
|
|
227 //
|
|
228 // Now it's time to review collection-related tokens. We will start with
|
|
229 // flow collections:
|
|
230 //
|
|
231 // FLOW-SEQUENCE-START
|
|
232 // FLOW-SEQUENCE-END
|
|
233 // FLOW-MAPPING-START
|
|
234 // FLOW-MAPPING-END
|
|
235 // FLOW-ENTRY
|
|
236 // KEY
|
|
237 // VALUE
|
|
238 //
|
|
239 // The tokens FLOW-SEQUENCE-START, FLOW-SEQUENCE-END, FLOW-MAPPING-START, and
|
|
240 // FLOW-MAPPING-END represent the indicators '[', ']', '{', and '}'
|
|
241 // correspondingly. FLOW-ENTRY represent the ',' indicator. Finally the
|
|
242 // indicators '?' and ':', which are used for denoting mapping keys and values,
|
|
243 // are represented by the KEY and VALUE tokens.
|
|
244 //
|
|
245 // The following examples show flow collections:
|
|
246 //
|
|
247 // 1. A flow sequence:
|
|
248 //
|
|
249 // [item 1, item 2, item 3]
|
|
250 //
|
|
251 // Tokens:
|
|
252 //
|
|
253 // STREAM-START(utf-8)
|
|
254 // FLOW-SEQUENCE-START
|
|
255 // SCALAR("item 1",plain)
|
|
256 // FLOW-ENTRY
|
|
257 // SCALAR("item 2",plain)
|
|
258 // FLOW-ENTRY
|
|
259 // SCALAR("item 3",plain)
|
|
260 // FLOW-SEQUENCE-END
|
|
261 // STREAM-END
|
|
262 //
|
|
263 // 2. A flow mapping:
|
|
264 //
|
|
265 // {
|
|
266 // a simple key: a value, # Note that the KEY token is produced.
|
|
267 // ? a complex key: another value,
|
|
268 // }
|
|
269 //
|
|
270 // Tokens:
|
|
271 //
|
|
272 // STREAM-START(utf-8)
|
|
273 // FLOW-MAPPING-START
|
|
274 // KEY
|
|
275 // SCALAR("a simple key",plain)
|
|
276 // VALUE
|
|
277 // SCALAR("a value",plain)
|
|
278 // FLOW-ENTRY
|
|
279 // KEY
|
|
280 // SCALAR("a complex key",plain)
|
|
281 // VALUE
|
|
282 // SCALAR("another value",plain)
|
|
283 // FLOW-ENTRY
|
|
284 // FLOW-MAPPING-END
|
|
285 // STREAM-END
|
|
286 //
|
|
287 // A simple key is a key which is not denoted by the '?' indicator. Note that
|
|
288 // the Scanner still produce the KEY token whenever it encounters a simple key.
|
|
289 //
|
|
290 // For scanning block collections, the following tokens are used (note that we
|
|
291 // repeat KEY and VALUE here):
|
|
292 //
|
|
293 // BLOCK-SEQUENCE-START
|
|
294 // BLOCK-MAPPING-START
|
|
295 // BLOCK-END
|
|
296 // BLOCK-ENTRY
|
|
297 // KEY
|
|
298 // VALUE
|
|
299 //
|
|
300 // The tokens BLOCK-SEQUENCE-START and BLOCK-MAPPING-START denote indentation
|
|
301 // increase that precedes a block collection (cf. the INDENT token in Python).
|
|
302 // The token BLOCK-END denote indentation decrease that ends a block collection
|
|
303 // (cf. the DEDENT token in Python). However YAML has some syntax pecularities
|
|
304 // that makes detections of these tokens more complex.
|
|
305 //
|
|
306 // The tokens BLOCK-ENTRY, KEY, and VALUE are used to represent the indicators
|
|
307 // '-', '?', and ':' correspondingly.
|
|
308 //
|
|
309 // The following examples show how the tokens BLOCK-SEQUENCE-START,
|
|
310 // BLOCK-MAPPING-START, and BLOCK-END are emitted by the Scanner:
|
|
311 //
|
|
312 // 1. Block sequences:
|
|
313 //
|
|
314 // - item 1
|
|
315 // - item 2
|
|
316 // -
|
|
317 // - item 3.1
|
|
318 // - item 3.2
|
|
319 // -
|
|
320 // key 1: value 1
|
|
321 // key 2: value 2
|
|
322 //
|
|
323 // Tokens:
|
|
324 //
|
|
325 // STREAM-START(utf-8)
|
|
326 // BLOCK-SEQUENCE-START
|
|
327 // BLOCK-ENTRY
|
|
328 // SCALAR("item 1",plain)
|
|
329 // BLOCK-ENTRY
|
|
330 // SCALAR("item 2",plain)
|
|
331 // BLOCK-ENTRY
|
|
332 // BLOCK-SEQUENCE-START
|
|
333 // BLOCK-ENTRY
|
|
334 // SCALAR("item 3.1",plain)
|
|
335 // BLOCK-ENTRY
|
|
336 // SCALAR("item 3.2",plain)
|
|
337 // BLOCK-END
|
|
338 // BLOCK-ENTRY
|
|
339 // BLOCK-MAPPING-START
|
|
340 // KEY
|
|
341 // SCALAR("key 1",plain)
|
|
342 // VALUE
|
|
343 // SCALAR("value 1",plain)
|
|
344 // KEY
|
|
345 // SCALAR("key 2",plain)
|
|
346 // VALUE
|
|
347 // SCALAR("value 2",plain)
|
|
348 // BLOCK-END
|
|
349 // BLOCK-END
|
|
350 // STREAM-END
|
|
351 //
|
|
352 // 2. Block mappings:
|
|
353 //
|
|
354 // a simple key: a value # The KEY token is produced here.
|
|
355 // ? a complex key
|
|
356 // : another value
|
|
357 // a mapping:
|
|
358 // key 1: value 1
|
|
359 // key 2: value 2
|
|
360 // a sequence:
|
|
361 // - item 1
|
|
362 // - item 2
|
|
363 //
|
|
364 // Tokens:
|
|
365 //
|
|
366 // STREAM-START(utf-8)
|
|
367 // BLOCK-MAPPING-START
|
|
368 // KEY
|
|
369 // SCALAR("a simple key",plain)
|
|
370 // VALUE
|
|
371 // SCALAR("a value",plain)
|
|
372 // KEY
|
|
373 // SCALAR("a complex key",plain)
|
|
374 // VALUE
|
|
375 // SCALAR("another value",plain)
|
|
376 // KEY
|
|
377 // SCALAR("a mapping",plain)
|
|
378 // BLOCK-MAPPING-START
|
|
379 // KEY
|
|
380 // SCALAR("key 1",plain)
|
|
381 // VALUE
|
|
382 // SCALAR("value 1",plain)
|
|
383 // KEY
|
|
384 // SCALAR("key 2",plain)
|
|
385 // VALUE
|
|
386 // SCALAR("value 2",plain)
|
|
387 // BLOCK-END
|
|
388 // KEY
|
|
389 // SCALAR("a sequence",plain)
|
|
390 // VALUE
|
|
391 // BLOCK-SEQUENCE-START
|
|
392 // BLOCK-ENTRY
|
|
393 // SCALAR("item 1",plain)
|
|
394 // BLOCK-ENTRY
|
|
395 // SCALAR("item 2",plain)
|
|
396 // BLOCK-END
|
|
397 // BLOCK-END
|
|
398 // STREAM-END
|
|
399 //
|
|
400 // YAML does not always require to start a new block collection from a new
|
|
401 // line. If the current line contains only '-', '?', and ':' indicators, a new
|
|
402 // block collection may start at the current line. The following examples
|
|
403 // illustrate this case:
|
|
404 //
|
|
405 // 1. Collections in a sequence:
|
|
406 //
|
|
407 // - - item 1
|
|
408 // - item 2
|
|
409 // - key 1: value 1
|
|
410 // key 2: value 2
|
|
411 // - ? complex key
|
|
412 // : complex value
|
|
413 //
|
|
414 // Tokens:
|
|
415 //
|
|
416 // STREAM-START(utf-8)
|
|
417 // BLOCK-SEQUENCE-START
|
|
418 // BLOCK-ENTRY
|
|
419 // BLOCK-SEQUENCE-START
|
|
420 // BLOCK-ENTRY
|
|
421 // SCALAR("item 1",plain)
|
|
422 // BLOCK-ENTRY
|
|
423 // SCALAR("item 2",plain)
|
|
424 // BLOCK-END
|
|
425 // BLOCK-ENTRY
|
|
426 // BLOCK-MAPPING-START
|
|
427 // KEY
|
|
428 // SCALAR("key 1",plain)
|
|
429 // VALUE
|
|
430 // SCALAR("value 1",plain)
|
|
431 // KEY
|
|
432 // SCALAR("key 2",plain)
|
|
433 // VALUE
|
|
434 // SCALAR("value 2",plain)
|
|
435 // BLOCK-END
|
|
436 // BLOCK-ENTRY
|
|
437 // BLOCK-MAPPING-START
|
|
438 // KEY
|
|
439 // SCALAR("complex key")
|
|
440 // VALUE
|
|
441 // SCALAR("complex value")
|
|
442 // BLOCK-END
|
|
443 // BLOCK-END
|
|
444 // STREAM-END
|
|
445 //
|
|
446 // 2. Collections in a mapping:
|
|
447 //
|
|
448 // ? a sequence
|
|
449 // : - item 1
|
|
450 // - item 2
|
|
451 // ? a mapping
|
|
452 // : key 1: value 1
|
|
453 // key 2: value 2
|
|
454 //
|
|
455 // Tokens:
|
|
456 //
|
|
457 // STREAM-START(utf-8)
|
|
458 // BLOCK-MAPPING-START
|
|
459 // KEY
|
|
460 // SCALAR("a sequence",plain)
|
|
461 // VALUE
|
|
462 // BLOCK-SEQUENCE-START
|
|
463 // BLOCK-ENTRY
|
|
464 // SCALAR("item 1",plain)
|
|
465 // BLOCK-ENTRY
|
|
466 // SCALAR("item 2",plain)
|
|
467 // BLOCK-END
|
|
468 // KEY
|
|
469 // SCALAR("a mapping",plain)
|
|
470 // VALUE
|
|
471 // BLOCK-MAPPING-START
|
|
472 // KEY
|
|
473 // SCALAR("key 1",plain)
|
|
474 // VALUE
|
|
475 // SCALAR("value 1",plain)
|
|
476 // KEY
|
|
477 // SCALAR("key 2",plain)
|
|
478 // VALUE
|
|
479 // SCALAR("value 2",plain)
|
|
480 // BLOCK-END
|
|
481 // BLOCK-END
|
|
482 // STREAM-END
|
|
483 //
|
|
484 // YAML also permits non-indented sequences if they are included into a block
|
|
485 // mapping. In this case, the token BLOCK-SEQUENCE-START is not produced:
|
|
486 //
|
|
487 // key:
|
|
488 // - item 1 # BLOCK-SEQUENCE-START is NOT produced here.
|
|
489 // - item 2
|
|
490 //
|
|
491 // Tokens:
|
|
492 //
|
|
493 // STREAM-START(utf-8)
|
|
494 // BLOCK-MAPPING-START
|
|
495 // KEY
|
|
496 // SCALAR("key",plain)
|
|
497 // VALUE
|
|
498 // BLOCK-ENTRY
|
|
499 // SCALAR("item 1",plain)
|
|
500 // BLOCK-ENTRY
|
|
501 // SCALAR("item 2",plain)
|
|
502 // BLOCK-END
|
|
503 //
|
|
504
|
|
505 // Ensure that the buffer contains the required number of characters.
|
|
506 // Return true on success, false on failure (reader error or memory error).
|
|
507 func cache(parser *yaml_parser_t, length int) bool {
|
|
508 // [Go] This was inlined: !cache(A, B) -> unread < B && !update(A, B)
|
|
509 return parser.unread >= length || yaml_parser_update_buffer(parser, length)
|
|
510 }
|
|
511
|
|
512 // Advance the buffer pointer.
|
|
513 func skip(parser *yaml_parser_t) {
|
|
514 if !is_blank(parser.buffer, parser.buffer_pos) {
|
|
515 parser.newlines = 0
|
|
516 }
|
|
517 parser.mark.index++
|
|
518 parser.mark.column++
|
|
519 parser.unread--
|
|
520 parser.buffer_pos += width(parser.buffer[parser.buffer_pos])
|
|
521 }
|
|
522
|
|
523 func skip_line(parser *yaml_parser_t) {
|
|
524 if is_crlf(parser.buffer, parser.buffer_pos) {
|
|
525 parser.mark.index += 2
|
|
526 parser.mark.column = 0
|
|
527 parser.mark.line++
|
|
528 parser.unread -= 2
|
|
529 parser.buffer_pos += 2
|
|
530 parser.newlines++
|
|
531 } else if is_break(parser.buffer, parser.buffer_pos) {
|
|
532 parser.mark.index++
|
|
533 parser.mark.column = 0
|
|
534 parser.mark.line++
|
|
535 parser.unread--
|
|
536 parser.buffer_pos += width(parser.buffer[parser.buffer_pos])
|
|
537 parser.newlines++
|
|
538 }
|
|
539 }
|
|
540
|
|
541 // Copy a character to a string buffer and advance pointers.
|
|
542 func read(parser *yaml_parser_t, s []byte) []byte {
|
|
543 if !is_blank(parser.buffer, parser.buffer_pos) {
|
|
544 parser.newlines = 0
|
|
545 }
|
|
546 w := width(parser.buffer[parser.buffer_pos])
|
|
547 if w == 0 {
|
|
548 panic("invalid character sequence")
|
|
549 }
|
|
550 if len(s) == 0 {
|
|
551 s = make([]byte, 0, 32)
|
|
552 }
|
|
553 if w == 1 && len(s)+w <= cap(s) {
|
|
554 s = s[:len(s)+1]
|
|
555 s[len(s)-1] = parser.buffer[parser.buffer_pos]
|
|
556 parser.buffer_pos++
|
|
557 } else {
|
|
558 s = append(s, parser.buffer[parser.buffer_pos:parser.buffer_pos+w]...)
|
|
559 parser.buffer_pos += w
|
|
560 }
|
|
561 parser.mark.index++
|
|
562 parser.mark.column++
|
|
563 parser.unread--
|
|
564 return s
|
|
565 }
|
|
566
|
|
567 // Copy a line break character to a string buffer and advance pointers.
|
|
568 func read_line(parser *yaml_parser_t, s []byte) []byte {
|
|
569 buf := parser.buffer
|
|
570 pos := parser.buffer_pos
|
|
571 switch {
|
|
572 case buf[pos] == '\r' && buf[pos+1] == '\n':
|
|
573 // CR LF . LF
|
|
574 s = append(s, '\n')
|
|
575 parser.buffer_pos += 2
|
|
576 parser.mark.index++
|
|
577 parser.unread--
|
|
578 case buf[pos] == '\r' || buf[pos] == '\n':
|
|
579 // CR|LF . LF
|
|
580 s = append(s, '\n')
|
|
581 parser.buffer_pos += 1
|
|
582 case buf[pos] == '\xC2' && buf[pos+1] == '\x85':
|
|
583 // NEL . LF
|
|
584 s = append(s, '\n')
|
|
585 parser.buffer_pos += 2
|
|
586 case buf[pos] == '\xE2' && buf[pos+1] == '\x80' && (buf[pos+2] == '\xA8' || buf[pos+2] == '\xA9'):
|
|
587 // LS|PS . LS|PS
|
|
588 s = append(s, buf[parser.buffer_pos:pos+3]...)
|
|
589 parser.buffer_pos += 3
|
|
590 default:
|
|
591 return s
|
|
592 }
|
|
593 parser.mark.index++
|
|
594 parser.mark.column = 0
|
|
595 parser.mark.line++
|
|
596 parser.unread--
|
|
597 parser.newlines++
|
|
598 return s
|
|
599 }
|
|
600
|
|
601 // Get the next token.
|
|
602 func yaml_parser_scan(parser *yaml_parser_t, token *yaml_token_t) bool {
|
|
603 // Erase the token object.
|
|
604 *token = yaml_token_t{} // [Go] Is this necessary?
|
|
605
|
|
606 // No tokens after STREAM-END or error.
|
|
607 if parser.stream_end_produced || parser.error != yaml_NO_ERROR {
|
|
608 return true
|
|
609 }
|
|
610
|
|
611 // Ensure that the tokens queue contains enough tokens.
|
|
612 if !parser.token_available {
|
|
613 if !yaml_parser_fetch_more_tokens(parser) {
|
|
614 return false
|
|
615 }
|
|
616 }
|
|
617
|
|
618 // Fetch the next token from the queue.
|
|
619 *token = parser.tokens[parser.tokens_head]
|
|
620 parser.tokens_head++
|
|
621 parser.tokens_parsed++
|
|
622 parser.token_available = false
|
|
623
|
|
624 if token.typ == yaml_STREAM_END_TOKEN {
|
|
625 parser.stream_end_produced = true
|
|
626 }
|
|
627 return true
|
|
628 }
|
|
629
|
|
630 // Set the scanner error and return false.
|
|
631 func yaml_parser_set_scanner_error(parser *yaml_parser_t, context string, context_mark yaml_mark_t, problem string) bool {
|
|
632 parser.error = yaml_SCANNER_ERROR
|
|
633 parser.context = context
|
|
634 parser.context_mark = context_mark
|
|
635 parser.problem = problem
|
|
636 parser.problem_mark = parser.mark
|
|
637 return false
|
|
638 }
|
|
639
|
|
640 func yaml_parser_set_scanner_tag_error(parser *yaml_parser_t, directive bool, context_mark yaml_mark_t, problem string) bool {
|
|
641 context := "while parsing a tag"
|
|
642 if directive {
|
|
643 context = "while parsing a %TAG directive"
|
|
644 }
|
|
645 return yaml_parser_set_scanner_error(parser, context, context_mark, problem)
|
|
646 }
|
|
647
|
|
648 func trace(args ...interface{}) func() {
|
|
649 pargs := append([]interface{}{"+++"}, args...)
|
|
650 fmt.Println(pargs...)
|
|
651 pargs = append([]interface{}{"---"}, args...)
|
|
652 return func() { fmt.Println(pargs...) }
|
|
653 }
|
|
654
|
|
655 // Ensure that the tokens queue contains at least one token which can be
|
|
656 // returned to the Parser.
|
|
657 func yaml_parser_fetch_more_tokens(parser *yaml_parser_t) bool {
|
|
658 // While we need more tokens to fetch, do it.
|
|
659 for {
|
|
660 // [Go] The comment parsing logic requires a lookahead of two tokens
|
|
661 // so that foot comments may be parsed in time of associating them
|
|
662 // with the tokens that are parsed before them, and also for line
|
|
663 // comments to be transformed into head comments in some edge cases.
|
|
664 if parser.tokens_head < len(parser.tokens)-2 {
|
|
665 // If a potential simple key is at the head position, we need to fetch
|
|
666 // the next token to disambiguate it.
|
|
667 head_tok_idx, ok := parser.simple_keys_by_tok[parser.tokens_parsed]
|
|
668 if !ok {
|
|
669 break
|
|
670 } else if valid, ok := yaml_simple_key_is_valid(parser, &parser.simple_keys[head_tok_idx]); !ok {
|
|
671 return false
|
|
672 } else if !valid {
|
|
673 break
|
|
674 }
|
|
675 }
|
|
676 // Fetch the next token.
|
|
677 if !yaml_parser_fetch_next_token(parser) {
|
|
678 return false
|
|
679 }
|
|
680 }
|
|
681
|
|
682 parser.token_available = true
|
|
683 return true
|
|
684 }
|
|
685
|
|
686 // The dispatcher for token fetchers.
|
|
687 func yaml_parser_fetch_next_token(parser *yaml_parser_t) (ok bool) {
|
|
688 // Ensure that the buffer is initialized.
|
|
689 if parser.unread < 1 && !yaml_parser_update_buffer(parser, 1) {
|
|
690 return false
|
|
691 }
|
|
692
|
|
693 // Check if we just started scanning. Fetch STREAM-START then.
|
|
694 if !parser.stream_start_produced {
|
|
695 return yaml_parser_fetch_stream_start(parser)
|
|
696 }
|
|
697
|
|
698 scan_mark := parser.mark
|
|
699
|
|
700 // Eat whitespaces and comments until we reach the next token.
|
|
701 if !yaml_parser_scan_to_next_token(parser) {
|
|
702 return false
|
|
703 }
|
|
704
|
|
705 // [Go] While unrolling indents, transform the head comments of prior
|
|
706 // indentation levels observed after scan_start into foot comments at
|
|
707 // the respective indexes.
|
|
708
|
|
709 // Check the indentation level against the current column.
|
|
710 if !yaml_parser_unroll_indent(parser, parser.mark.column, scan_mark) {
|
|
711 return false
|
|
712 }
|
|
713
|
|
714 // Ensure that the buffer contains at least 4 characters. 4 is the length
|
|
715 // of the longest indicators ('--- ' and '... ').
|
|
716 if parser.unread < 4 && !yaml_parser_update_buffer(parser, 4) {
|
|
717 return false
|
|
718 }
|
|
719
|
|
720 // Is it the end of the stream?
|
|
721 if is_z(parser.buffer, parser.buffer_pos) {
|
|
722 return yaml_parser_fetch_stream_end(parser)
|
|
723 }
|
|
724
|
|
725 // Is it a directive?
|
|
726 if parser.mark.column == 0 && parser.buffer[parser.buffer_pos] == '%' {
|
|
727 return yaml_parser_fetch_directive(parser)
|
|
728 }
|
|
729
|
|
730 buf := parser.buffer
|
|
731 pos := parser.buffer_pos
|
|
732
|
|
733 // Is it the document start indicator?
|
|
734 if parser.mark.column == 0 && buf[pos] == '-' && buf[pos+1] == '-' && buf[pos+2] == '-' && is_blankz(buf, pos+3) {
|
|
735 return yaml_parser_fetch_document_indicator(parser, yaml_DOCUMENT_START_TOKEN)
|
|
736 }
|
|
737
|
|
738 // Is it the document end indicator?
|
|
739 if parser.mark.column == 0 && buf[pos] == '.' && buf[pos+1] == '.' && buf[pos+2] == '.' && is_blankz(buf, pos+3) {
|
|
740 return yaml_parser_fetch_document_indicator(parser, yaml_DOCUMENT_END_TOKEN)
|
|
741 }
|
|
742
|
|
743 comment_mark := parser.mark
|
|
744 if len(parser.tokens) > 0 && (parser.flow_level == 0 && buf[pos] == ':' || parser.flow_level > 0 && buf[pos] == ',') {
|
|
745 // Associate any following comments with the prior token.
|
|
746 comment_mark = parser.tokens[len(parser.tokens)-1].start_mark
|
|
747 }
|
|
748 defer func() {
|
|
749 if !ok {
|
|
750 return
|
|
751 }
|
|
752 if len(parser.tokens) > 0 && parser.tokens[len(parser.tokens)-1].typ == yaml_BLOCK_ENTRY_TOKEN {
|
|
753 // Sequence indicators alone have no line comments. It becomes
|
|
754 // a head comment for whatever follows.
|
|
755 return
|
|
756 }
|
|
757 if !yaml_parser_scan_line_comment(parser, comment_mark) {
|
|
758 ok = false
|
|
759 return
|
|
760 }
|
|
761 }()
|
|
762
|
|
763 // Is it the flow sequence start indicator?
|
|
764 if buf[pos] == '[' {
|
|
765 return yaml_parser_fetch_flow_collection_start(parser, yaml_FLOW_SEQUENCE_START_TOKEN)
|
|
766 }
|
|
767
|
|
768 // Is it the flow mapping start indicator?
|
|
769 if parser.buffer[parser.buffer_pos] == '{' {
|
|
770 return yaml_parser_fetch_flow_collection_start(parser, yaml_FLOW_MAPPING_START_TOKEN)
|
|
771 }
|
|
772
|
|
773 // Is it the flow sequence end indicator?
|
|
774 if parser.buffer[parser.buffer_pos] == ']' {
|
|
775 return yaml_parser_fetch_flow_collection_end(parser,
|
|
776 yaml_FLOW_SEQUENCE_END_TOKEN)
|
|
777 }
|
|
778
|
|
779 // Is it the flow mapping end indicator?
|
|
780 if parser.buffer[parser.buffer_pos] == '}' {
|
|
781 return yaml_parser_fetch_flow_collection_end(parser,
|
|
782 yaml_FLOW_MAPPING_END_TOKEN)
|
|
783 }
|
|
784
|
|
785 // Is it the flow entry indicator?
|
|
786 if parser.buffer[parser.buffer_pos] == ',' {
|
|
787 return yaml_parser_fetch_flow_entry(parser)
|
|
788 }
|
|
789
|
|
790 // Is it the block entry indicator?
|
|
791 if parser.buffer[parser.buffer_pos] == '-' && is_blankz(parser.buffer, parser.buffer_pos+1) {
|
|
792 return yaml_parser_fetch_block_entry(parser)
|
|
793 }
|
|
794
|
|
795 // Is it the key indicator?
|
|
796 if parser.buffer[parser.buffer_pos] == '?' && (parser.flow_level > 0 || is_blankz(parser.buffer, parser.buffer_pos+1)) {
|
|
797 return yaml_parser_fetch_key(parser)
|
|
798 }
|
|
799
|
|
800 // Is it the value indicator?
|
|
801 if parser.buffer[parser.buffer_pos] == ':' && (parser.flow_level > 0 || is_blankz(parser.buffer, parser.buffer_pos+1)) {
|
|
802 return yaml_parser_fetch_value(parser)
|
|
803 }
|
|
804
|
|
805 // Is it an alias?
|
|
806 if parser.buffer[parser.buffer_pos] == '*' {
|
|
807 return yaml_parser_fetch_anchor(parser, yaml_ALIAS_TOKEN)
|
|
808 }
|
|
809
|
|
810 // Is it an anchor?
|
|
811 if parser.buffer[parser.buffer_pos] == '&' {
|
|
812 return yaml_parser_fetch_anchor(parser, yaml_ANCHOR_TOKEN)
|
|
813 }
|
|
814
|
|
815 // Is it a tag?
|
|
816 if parser.buffer[parser.buffer_pos] == '!' {
|
|
817 return yaml_parser_fetch_tag(parser)
|
|
818 }
|
|
819
|
|
820 // Is it a literal scalar?
|
|
821 if parser.buffer[parser.buffer_pos] == '|' && parser.flow_level == 0 {
|
|
822 return yaml_parser_fetch_block_scalar(parser, true)
|
|
823 }
|
|
824
|
|
825 // Is it a folded scalar?
|
|
826 if parser.buffer[parser.buffer_pos] == '>' && parser.flow_level == 0 {
|
|
827 return yaml_parser_fetch_block_scalar(parser, false)
|
|
828 }
|
|
829
|
|
830 // Is it a single-quoted scalar?
|
|
831 if parser.buffer[parser.buffer_pos] == '\'' {
|
|
832 return yaml_parser_fetch_flow_scalar(parser, true)
|
|
833 }
|
|
834
|
|
835 // Is it a double-quoted scalar?
|
|
836 if parser.buffer[parser.buffer_pos] == '"' {
|
|
837 return yaml_parser_fetch_flow_scalar(parser, false)
|
|
838 }
|
|
839
|
|
840 // Is it a plain scalar?
|
|
841 //
|
|
842 // A plain scalar may start with any non-blank characters except
|
|
843 //
|
|
844 // '-', '?', ':', ',', '[', ']', '{', '}',
|
|
845 // '#', '&', '*', '!', '|', '>', '\'', '\"',
|
|
846 // '%', '@', '`'.
|
|
847 //
|
|
848 // In the block context (and, for the '-' indicator, in the flow context
|
|
849 // too), it may also start with the characters
|
|
850 //
|
|
851 // '-', '?', ':'
|
|
852 //
|
|
853 // if it is followed by a non-space character.
|
|
854 //
|
|
855 // The last rule is more restrictive than the specification requires.
|
|
856 // [Go] TODO Make this logic more reasonable.
|
|
857 //switch parser.buffer[parser.buffer_pos] {
|
|
858 //case '-', '?', ':', ',', '?', '-', ',', ':', ']', '[', '}', '{', '&', '#', '!', '*', '>', '|', '"', '\'', '@', '%', '-', '`':
|
|
859 //}
|
|
860 if !(is_blankz(parser.buffer, parser.buffer_pos) || parser.buffer[parser.buffer_pos] == '-' ||
|
|
861 parser.buffer[parser.buffer_pos] == '?' || parser.buffer[parser.buffer_pos] == ':' ||
|
|
862 parser.buffer[parser.buffer_pos] == ',' || parser.buffer[parser.buffer_pos] == '[' ||
|
|
863 parser.buffer[parser.buffer_pos] == ']' || parser.buffer[parser.buffer_pos] == '{' ||
|
|
864 parser.buffer[parser.buffer_pos] == '}' || parser.buffer[parser.buffer_pos] == '#' ||
|
|
865 parser.buffer[parser.buffer_pos] == '&' || parser.buffer[parser.buffer_pos] == '*' ||
|
|
866 parser.buffer[parser.buffer_pos] == '!' || parser.buffer[parser.buffer_pos] == '|' ||
|
|
867 parser.buffer[parser.buffer_pos] == '>' || parser.buffer[parser.buffer_pos] == '\'' ||
|
|
868 parser.buffer[parser.buffer_pos] == '"' || parser.buffer[parser.buffer_pos] == '%' ||
|
|
869 parser.buffer[parser.buffer_pos] == '@' || parser.buffer[parser.buffer_pos] == '`') ||
|
|
870 (parser.buffer[parser.buffer_pos] == '-' && !is_blank(parser.buffer, parser.buffer_pos+1)) ||
|
|
871 (parser.flow_level == 0 &&
|
|
872 (parser.buffer[parser.buffer_pos] == '?' || parser.buffer[parser.buffer_pos] == ':') &&
|
|
873 !is_blankz(parser.buffer, parser.buffer_pos+1)) {
|
|
874 return yaml_parser_fetch_plain_scalar(parser)
|
|
875 }
|
|
876
|
|
877 // If we don't determine the token type so far, it is an error.
|
|
878 return yaml_parser_set_scanner_error(parser,
|
|
879 "while scanning for the next token", parser.mark,
|
|
880 "found character that cannot start any token")
|
|
881 }
|
|
882
|
|
883 func yaml_simple_key_is_valid(parser *yaml_parser_t, simple_key *yaml_simple_key_t) (valid, ok bool) {
|
|
884 if !simple_key.possible {
|
|
885 return false, true
|
|
886 }
|
|
887
|
|
888 // The 1.2 specification says:
|
|
889 //
|
|
890 // "If the ? indicator is omitted, parsing needs to see past the
|
|
891 // implicit key to recognize it as such. To limit the amount of
|
|
892 // lookahead required, the “:” indicator must appear at most 1024
|
|
893 // Unicode characters beyond the start of the key. In addition, the key
|
|
894 // is restricted to a single line."
|
|
895 //
|
|
896 if simple_key.mark.line < parser.mark.line || simple_key.mark.index+1024 < parser.mark.index {
|
|
897 // Check if the potential simple key to be removed is required.
|
|
898 if simple_key.required {
|
|
899 return false, yaml_parser_set_scanner_error(parser,
|
|
900 "while scanning a simple key", simple_key.mark,
|
|
901 "could not find expected ':'")
|
|
902 }
|
|
903 simple_key.possible = false
|
|
904 return false, true
|
|
905 }
|
|
906 return true, true
|
|
907 }
|
|
908
|
|
909 // Check if a simple key may start at the current position and add it if
|
|
910 // needed.
|
|
911 func yaml_parser_save_simple_key(parser *yaml_parser_t) bool {
|
|
912 // A simple key is required at the current position if the scanner is in
|
|
913 // the block context and the current column coincides with the indentation
|
|
914 // level.
|
|
915
|
|
916 required := parser.flow_level == 0 && parser.indent == parser.mark.column
|
|
917
|
|
918 //
|
|
919 // If the current position may start a simple key, save it.
|
|
920 //
|
|
921 if parser.simple_key_allowed {
|
|
922 simple_key := yaml_simple_key_t{
|
|
923 possible: true,
|
|
924 required: required,
|
|
925 token_number: parser.tokens_parsed + (len(parser.tokens) - parser.tokens_head),
|
|
926 mark: parser.mark,
|
|
927 }
|
|
928
|
|
929 if !yaml_parser_remove_simple_key(parser) {
|
|
930 return false
|
|
931 }
|
|
932 parser.simple_keys[len(parser.simple_keys)-1] = simple_key
|
|
933 parser.simple_keys_by_tok[simple_key.token_number] = len(parser.simple_keys) - 1
|
|
934 }
|
|
935 return true
|
|
936 }
|
|
937
|
|
938 // Remove a potential simple key at the current flow level.
|
|
939 func yaml_parser_remove_simple_key(parser *yaml_parser_t) bool {
|
|
940 i := len(parser.simple_keys) - 1
|
|
941 if parser.simple_keys[i].possible {
|
|
942 // If the key is required, it is an error.
|
|
943 if parser.simple_keys[i].required {
|
|
944 return yaml_parser_set_scanner_error(parser,
|
|
945 "while scanning a simple key", parser.simple_keys[i].mark,
|
|
946 "could not find expected ':'")
|
|
947 }
|
|
948 // Remove the key from the stack.
|
|
949 parser.simple_keys[i].possible = false
|
|
950 delete(parser.simple_keys_by_tok, parser.simple_keys[i].token_number)
|
|
951 }
|
|
952 return true
|
|
953 }
|
|
954
|
|
955 // max_flow_level limits the flow_level
|
|
956 const max_flow_level = 10000
|
|
957
|
|
958 // Increase the flow level and resize the simple key list if needed.
|
|
959 func yaml_parser_increase_flow_level(parser *yaml_parser_t) bool {
|
|
960 // Reset the simple key on the next level.
|
|
961 parser.simple_keys = append(parser.simple_keys, yaml_simple_key_t{
|
|
962 possible: false,
|
|
963 required: false,
|
|
964 token_number: parser.tokens_parsed + (len(parser.tokens) - parser.tokens_head),
|
|
965 mark: parser.mark,
|
|
966 })
|
|
967
|
|
968 // Increase the flow level.
|
|
969 parser.flow_level++
|
|
970 if parser.flow_level > max_flow_level {
|
|
971 return yaml_parser_set_scanner_error(parser,
|
|
972 "while increasing flow level", parser.simple_keys[len(parser.simple_keys)-1].mark,
|
|
973 fmt.Sprintf("exceeded max depth of %d", max_flow_level))
|
|
974 }
|
|
975 return true
|
|
976 }
|
|
977
|
|
978 // Decrease the flow level.
|
|
979 func yaml_parser_decrease_flow_level(parser *yaml_parser_t) bool {
|
|
980 if parser.flow_level > 0 {
|
|
981 parser.flow_level--
|
|
982 last := len(parser.simple_keys) - 1
|
|
983 delete(parser.simple_keys_by_tok, parser.simple_keys[last].token_number)
|
|
984 parser.simple_keys = parser.simple_keys[:last]
|
|
985 }
|
|
986 return true
|
|
987 }
|
|
988
|
|
989 // max_indents limits the indents stack size
|
|
990 const max_indents = 10000
|
|
991
|
|
992 // Push the current indentation level to the stack and set the new level
|
|
993 // the current column is greater than the indentation level. In this case,
|
|
994 // append or insert the specified token into the token queue.
|
|
995 func yaml_parser_roll_indent(parser *yaml_parser_t, column, number int, typ yaml_token_type_t, mark yaml_mark_t) bool {
|
|
996 // In the flow context, do nothing.
|
|
997 if parser.flow_level > 0 {
|
|
998 return true
|
|
999 }
|
|
1000
|
|
1001 if parser.indent < column {
|
|
1002 // Push the current indentation level to the stack and set the new
|
|
1003 // indentation level.
|
|
1004 parser.indents = append(parser.indents, parser.indent)
|
|
1005 parser.indent = column
|
|
1006 if len(parser.indents) > max_indents {
|
|
1007 return yaml_parser_set_scanner_error(parser,
|
|
1008 "while increasing indent level", parser.simple_keys[len(parser.simple_keys)-1].mark,
|
|
1009 fmt.Sprintf("exceeded max depth of %d", max_indents))
|
|
1010 }
|
|
1011
|
|
1012 // Create a token and insert it into the queue.
|
|
1013 token := yaml_token_t{
|
|
1014 typ: typ,
|
|
1015 start_mark: mark,
|
|
1016 end_mark: mark,
|
|
1017 }
|
|
1018 if number > -1 {
|
|
1019 number -= parser.tokens_parsed
|
|
1020 }
|
|
1021 yaml_insert_token(parser, number, &token)
|
|
1022 }
|
|
1023 return true
|
|
1024 }
|
|
1025
|
|
1026 // Pop indentation levels from the indents stack until the current level
|
|
1027 // becomes less or equal to the column. For each indentation level, append
|
|
1028 // the BLOCK-END token.
|
|
1029 func yaml_parser_unroll_indent(parser *yaml_parser_t, column int, scan_mark yaml_mark_t) bool {
|
|
1030 // In the flow context, do nothing.
|
|
1031 if parser.flow_level > 0 {
|
|
1032 return true
|
|
1033 }
|
|
1034
|
|
1035 block_mark := scan_mark
|
|
1036 block_mark.index--
|
|
1037
|
|
1038 // Loop through the indentation levels in the stack.
|
|
1039 for parser.indent > column {
|
|
1040
|
|
1041 // [Go] Reposition the end token before potential following
|
|
1042 // foot comments of parent blocks. For that, search
|
|
1043 // backwards for recent comments that were at the same
|
|
1044 // indent as the block that is ending now.
|
|
1045 stop_index := block_mark.index
|
|
1046 for i := len(parser.comments) - 1; i >= 0; i-- {
|
|
1047 comment := &parser.comments[i]
|
|
1048
|
|
1049 if comment.end_mark.index < stop_index {
|
|
1050 // Don't go back beyond the start of the comment/whitespace scan, unless column < 0.
|
|
1051 // If requested indent column is < 0, then the document is over and everything else
|
|
1052 // is a foot anyway.
|
|
1053 break
|
|
1054 }
|
|
1055 if comment.start_mark.column == parser.indent+1 {
|
|
1056 // This is a good match. But maybe there's a former comment
|
|
1057 // at that same indent level, so keep searching.
|
|
1058 block_mark = comment.start_mark
|
|
1059 }
|
|
1060
|
|
1061 // While the end of the former comment matches with
|
|
1062 // the start of the following one, we know there's
|
|
1063 // nothing in between and scanning is still safe.
|
|
1064 stop_index = comment.scan_mark.index
|
|
1065 }
|
|
1066
|
|
1067 // Create a token and append it to the queue.
|
|
1068 token := yaml_token_t{
|
|
1069 typ: yaml_BLOCK_END_TOKEN,
|
|
1070 start_mark: block_mark,
|
|
1071 end_mark: block_mark,
|
|
1072 }
|
|
1073 yaml_insert_token(parser, -1, &token)
|
|
1074
|
|
1075 // Pop the indentation level.
|
|
1076 parser.indent = parser.indents[len(parser.indents)-1]
|
|
1077 parser.indents = parser.indents[:len(parser.indents)-1]
|
|
1078 }
|
|
1079 return true
|
|
1080 }
|
|
1081
|
|
1082 // Initialize the scanner and produce the STREAM-START token.
|
|
1083 func yaml_parser_fetch_stream_start(parser *yaml_parser_t) bool {
|
|
1084
|
|
1085 // Set the initial indentation.
|
|
1086 parser.indent = -1
|
|
1087
|
|
1088 // Initialize the simple key stack.
|
|
1089 parser.simple_keys = append(parser.simple_keys, yaml_simple_key_t{})
|
|
1090
|
|
1091 parser.simple_keys_by_tok = make(map[int]int)
|
|
1092
|
|
1093 // A simple key is allowed at the beginning of the stream.
|
|
1094 parser.simple_key_allowed = true
|
|
1095
|
|
1096 // We have started.
|
|
1097 parser.stream_start_produced = true
|
|
1098
|
|
1099 // Create the STREAM-START token and append it to the queue.
|
|
1100 token := yaml_token_t{
|
|
1101 typ: yaml_STREAM_START_TOKEN,
|
|
1102 start_mark: parser.mark,
|
|
1103 end_mark: parser.mark,
|
|
1104 encoding: parser.encoding,
|
|
1105 }
|
|
1106 yaml_insert_token(parser, -1, &token)
|
|
1107 return true
|
|
1108 }
|
|
1109
|
|
1110 // Produce the STREAM-END token and shut down the scanner.
|
|
1111 func yaml_parser_fetch_stream_end(parser *yaml_parser_t) bool {
|
|
1112
|
|
1113 // Force new line.
|
|
1114 if parser.mark.column != 0 {
|
|
1115 parser.mark.column = 0
|
|
1116 parser.mark.line++
|
|
1117 }
|
|
1118
|
|
1119 // Reset the indentation level.
|
|
1120 if !yaml_parser_unroll_indent(parser, -1, parser.mark) {
|
|
1121 return false
|
|
1122 }
|
|
1123
|
|
1124 // Reset simple keys.
|
|
1125 if !yaml_parser_remove_simple_key(parser) {
|
|
1126 return false
|
|
1127 }
|
|
1128
|
|
1129 parser.simple_key_allowed = false
|
|
1130
|
|
1131 // Create the STREAM-END token and append it to the queue.
|
|
1132 token := yaml_token_t{
|
|
1133 typ: yaml_STREAM_END_TOKEN,
|
|
1134 start_mark: parser.mark,
|
|
1135 end_mark: parser.mark,
|
|
1136 }
|
|
1137 yaml_insert_token(parser, -1, &token)
|
|
1138 return true
|
|
1139 }
|
|
1140
|
|
1141 // Produce a VERSION-DIRECTIVE or TAG-DIRECTIVE token.
|
|
1142 func yaml_parser_fetch_directive(parser *yaml_parser_t) bool {
|
|
1143 // Reset the indentation level.
|
|
1144 if !yaml_parser_unroll_indent(parser, -1, parser.mark) {
|
|
1145 return false
|
|
1146 }
|
|
1147
|
|
1148 // Reset simple keys.
|
|
1149 if !yaml_parser_remove_simple_key(parser) {
|
|
1150 return false
|
|
1151 }
|
|
1152
|
|
1153 parser.simple_key_allowed = false
|
|
1154
|
|
1155 // Create the YAML-DIRECTIVE or TAG-DIRECTIVE token.
|
|
1156 token := yaml_token_t{}
|
|
1157 if !yaml_parser_scan_directive(parser, &token) {
|
|
1158 return false
|
|
1159 }
|
|
1160 // Append the token to the queue.
|
|
1161 yaml_insert_token(parser, -1, &token)
|
|
1162 return true
|
|
1163 }
|
|
1164
|
|
1165 // Produce the DOCUMENT-START or DOCUMENT-END token.
|
|
1166 func yaml_parser_fetch_document_indicator(parser *yaml_parser_t, typ yaml_token_type_t) bool {
|
|
1167 // Reset the indentation level.
|
|
1168 if !yaml_parser_unroll_indent(parser, -1, parser.mark) {
|
|
1169 return false
|
|
1170 }
|
|
1171
|
|
1172 // Reset simple keys.
|
|
1173 if !yaml_parser_remove_simple_key(parser) {
|
|
1174 return false
|
|
1175 }
|
|
1176
|
|
1177 parser.simple_key_allowed = false
|
|
1178
|
|
1179 // Consume the token.
|
|
1180 start_mark := parser.mark
|
|
1181
|
|
1182 skip(parser)
|
|
1183 skip(parser)
|
|
1184 skip(parser)
|
|
1185
|
|
1186 end_mark := parser.mark
|
|
1187
|
|
1188 // Create the DOCUMENT-START or DOCUMENT-END token.
|
|
1189 token := yaml_token_t{
|
|
1190 typ: typ,
|
|
1191 start_mark: start_mark,
|
|
1192 end_mark: end_mark,
|
|
1193 }
|
|
1194 // Append the token to the queue.
|
|
1195 yaml_insert_token(parser, -1, &token)
|
|
1196 return true
|
|
1197 }
|
|
1198
|
|
1199 // Produce the FLOW-SEQUENCE-START or FLOW-MAPPING-START token.
|
|
1200 func yaml_parser_fetch_flow_collection_start(parser *yaml_parser_t, typ yaml_token_type_t) bool {
|
|
1201
|
|
1202 // The indicators '[' and '{' may start a simple key.
|
|
1203 if !yaml_parser_save_simple_key(parser) {
|
|
1204 return false
|
|
1205 }
|
|
1206
|
|
1207 // Increase the flow level.
|
|
1208 if !yaml_parser_increase_flow_level(parser) {
|
|
1209 return false
|
|
1210 }
|
|
1211
|
|
1212 // A simple key may follow the indicators '[' and '{'.
|
|
1213 parser.simple_key_allowed = true
|
|
1214
|
|
1215 // Consume the token.
|
|
1216 start_mark := parser.mark
|
|
1217 skip(parser)
|
|
1218 end_mark := parser.mark
|
|
1219
|
|
1220 // Create the FLOW-SEQUENCE-START of FLOW-MAPPING-START token.
|
|
1221 token := yaml_token_t{
|
|
1222 typ: typ,
|
|
1223 start_mark: start_mark,
|
|
1224 end_mark: end_mark,
|
|
1225 }
|
|
1226 // Append the token to the queue.
|
|
1227 yaml_insert_token(parser, -1, &token)
|
|
1228 return true
|
|
1229 }
|
|
1230
|
|
1231 // Produce the FLOW-SEQUENCE-END or FLOW-MAPPING-END token.
|
|
1232 func yaml_parser_fetch_flow_collection_end(parser *yaml_parser_t, typ yaml_token_type_t) bool {
|
|
1233 // Reset any potential simple key on the current flow level.
|
|
1234 if !yaml_parser_remove_simple_key(parser) {
|
|
1235 return false
|
|
1236 }
|
|
1237
|
|
1238 // Decrease the flow level.
|
|
1239 if !yaml_parser_decrease_flow_level(parser) {
|
|
1240 return false
|
|
1241 }
|
|
1242
|
|
1243 // No simple keys after the indicators ']' and '}'.
|
|
1244 parser.simple_key_allowed = false
|
|
1245
|
|
1246 // Consume the token.
|
|
1247
|
|
1248 start_mark := parser.mark
|
|
1249 skip(parser)
|
|
1250 end_mark := parser.mark
|
|
1251
|
|
1252 // Create the FLOW-SEQUENCE-END of FLOW-MAPPING-END token.
|
|
1253 token := yaml_token_t{
|
|
1254 typ: typ,
|
|
1255 start_mark: start_mark,
|
|
1256 end_mark: end_mark,
|
|
1257 }
|
|
1258 // Append the token to the queue.
|
|
1259 yaml_insert_token(parser, -1, &token)
|
|
1260 return true
|
|
1261 }
|
|
1262
|
|
1263 // Produce the FLOW-ENTRY token.
|
|
1264 func yaml_parser_fetch_flow_entry(parser *yaml_parser_t) bool {
|
|
1265 // Reset any potential simple keys on the current flow level.
|
|
1266 if !yaml_parser_remove_simple_key(parser) {
|
|
1267 return false
|
|
1268 }
|
|
1269
|
|
1270 // Simple keys are allowed after ','.
|
|
1271 parser.simple_key_allowed = true
|
|
1272
|
|
1273 // Consume the token.
|
|
1274 start_mark := parser.mark
|
|
1275 skip(parser)
|
|
1276 end_mark := parser.mark
|
|
1277
|
|
1278 // Create the FLOW-ENTRY token and append it to the queue.
|
|
1279 token := yaml_token_t{
|
|
1280 typ: yaml_FLOW_ENTRY_TOKEN,
|
|
1281 start_mark: start_mark,
|
|
1282 end_mark: end_mark,
|
|
1283 }
|
|
1284 yaml_insert_token(parser, -1, &token)
|
|
1285 return true
|
|
1286 }
|
|
1287
|
|
1288 // Produce the BLOCK-ENTRY token.
|
|
1289 func yaml_parser_fetch_block_entry(parser *yaml_parser_t) bool {
|
|
1290 // Check if the scanner is in the block context.
|
|
1291 if parser.flow_level == 0 {
|
|
1292 // Check if we are allowed to start a new entry.
|
|
1293 if !parser.simple_key_allowed {
|
|
1294 return yaml_parser_set_scanner_error(parser, "", parser.mark,
|
|
1295 "block sequence entries are not allowed in this context")
|
|
1296 }
|
|
1297 // Add the BLOCK-SEQUENCE-START token if needed.
|
|
1298 if !yaml_parser_roll_indent(parser, parser.mark.column, -1, yaml_BLOCK_SEQUENCE_START_TOKEN, parser.mark) {
|
|
1299 return false
|
|
1300 }
|
|
1301 } else {
|
|
1302 // It is an error for the '-' indicator to occur in the flow context,
|
|
1303 // but we let the Parser detect and report about it because the Parser
|
|
1304 // is able to point to the context.
|
|
1305 }
|
|
1306
|
|
1307 // Reset any potential simple keys on the current flow level.
|
|
1308 if !yaml_parser_remove_simple_key(parser) {
|
|
1309 return false
|
|
1310 }
|
|
1311
|
|
1312 // Simple keys are allowed after '-'.
|
|
1313 parser.simple_key_allowed = true
|
|
1314
|
|
1315 // Consume the token.
|
|
1316 start_mark := parser.mark
|
|
1317 skip(parser)
|
|
1318 end_mark := parser.mark
|
|
1319
|
|
1320 // Create the BLOCK-ENTRY token and append it to the queue.
|
|
1321 token := yaml_token_t{
|
|
1322 typ: yaml_BLOCK_ENTRY_TOKEN,
|
|
1323 start_mark: start_mark,
|
|
1324 end_mark: end_mark,
|
|
1325 }
|
|
1326 yaml_insert_token(parser, -1, &token)
|
|
1327 return true
|
|
1328 }
|
|
1329
|
|
1330 // Produce the KEY token.
|
|
1331 func yaml_parser_fetch_key(parser *yaml_parser_t) bool {
|
|
1332
|
|
1333 // In the block context, additional checks are required.
|
|
1334 if parser.flow_level == 0 {
|
|
1335 // Check if we are allowed to start a new key (not nessesary simple).
|
|
1336 if !parser.simple_key_allowed {
|
|
1337 return yaml_parser_set_scanner_error(parser, "", parser.mark,
|
|
1338 "mapping keys are not allowed in this context")
|
|
1339 }
|
|
1340 // Add the BLOCK-MAPPING-START token if needed.
|
|
1341 if !yaml_parser_roll_indent(parser, parser.mark.column, -1, yaml_BLOCK_MAPPING_START_TOKEN, parser.mark) {
|
|
1342 return false
|
|
1343 }
|
|
1344 }
|
|
1345
|
|
1346 // Reset any potential simple keys on the current flow level.
|
|
1347 if !yaml_parser_remove_simple_key(parser) {
|
|
1348 return false
|
|
1349 }
|
|
1350
|
|
1351 // Simple keys are allowed after '?' in the block context.
|
|
1352 parser.simple_key_allowed = parser.flow_level == 0
|
|
1353
|
|
1354 // Consume the token.
|
|
1355 start_mark := parser.mark
|
|
1356 skip(parser)
|
|
1357 end_mark := parser.mark
|
|
1358
|
|
1359 // Create the KEY token and append it to the queue.
|
|
1360 token := yaml_token_t{
|
|
1361 typ: yaml_KEY_TOKEN,
|
|
1362 start_mark: start_mark,
|
|
1363 end_mark: end_mark,
|
|
1364 }
|
|
1365 yaml_insert_token(parser, -1, &token)
|
|
1366 return true
|
|
1367 }
|
|
1368
|
|
1369 // Produce the VALUE token.
|
|
1370 func yaml_parser_fetch_value(parser *yaml_parser_t) bool {
|
|
1371
|
|
1372 simple_key := &parser.simple_keys[len(parser.simple_keys)-1]
|
|
1373
|
|
1374 // Have we found a simple key?
|
|
1375 if valid, ok := yaml_simple_key_is_valid(parser, simple_key); !ok {
|
|
1376 return false
|
|
1377
|
|
1378 } else if valid {
|
|
1379
|
|
1380 // Create the KEY token and insert it into the queue.
|
|
1381 token := yaml_token_t{
|
|
1382 typ: yaml_KEY_TOKEN,
|
|
1383 start_mark: simple_key.mark,
|
|
1384 end_mark: simple_key.mark,
|
|
1385 }
|
|
1386 yaml_insert_token(parser, simple_key.token_number-parser.tokens_parsed, &token)
|
|
1387
|
|
1388 // In the block context, we may need to add the BLOCK-MAPPING-START token.
|
|
1389 if !yaml_parser_roll_indent(parser, simple_key.mark.column,
|
|
1390 simple_key.token_number,
|
|
1391 yaml_BLOCK_MAPPING_START_TOKEN, simple_key.mark) {
|
|
1392 return false
|
|
1393 }
|
|
1394
|
|
1395 // Remove the simple key.
|
|
1396 simple_key.possible = false
|
|
1397 delete(parser.simple_keys_by_tok, simple_key.token_number)
|
|
1398
|
|
1399 // A simple key cannot follow another simple key.
|
|
1400 parser.simple_key_allowed = false
|
|
1401
|
|
1402 } else {
|
|
1403 // The ':' indicator follows a complex key.
|
|
1404
|
|
1405 // In the block context, extra checks are required.
|
|
1406 if parser.flow_level == 0 {
|
|
1407
|
|
1408 // Check if we are allowed to start a complex value.
|
|
1409 if !parser.simple_key_allowed {
|
|
1410 return yaml_parser_set_scanner_error(parser, "", parser.mark,
|
|
1411 "mapping values are not allowed in this context")
|
|
1412 }
|
|
1413
|
|
1414 // Add the BLOCK-MAPPING-START token if needed.
|
|
1415 if !yaml_parser_roll_indent(parser, parser.mark.column, -1, yaml_BLOCK_MAPPING_START_TOKEN, parser.mark) {
|
|
1416 return false
|
|
1417 }
|
|
1418 }
|
|
1419
|
|
1420 // Simple keys after ':' are allowed in the block context.
|
|
1421 parser.simple_key_allowed = parser.flow_level == 0
|
|
1422 }
|
|
1423
|
|
1424 // Consume the token.
|
|
1425 start_mark := parser.mark
|
|
1426 skip(parser)
|
|
1427 end_mark := parser.mark
|
|
1428
|
|
1429 // Create the VALUE token and append it to the queue.
|
|
1430 token := yaml_token_t{
|
|
1431 typ: yaml_VALUE_TOKEN,
|
|
1432 start_mark: start_mark,
|
|
1433 end_mark: end_mark,
|
|
1434 }
|
|
1435 yaml_insert_token(parser, -1, &token)
|
|
1436 return true
|
|
1437 }
|
|
1438
|
|
1439 // Produce the ALIAS or ANCHOR token.
|
|
1440 func yaml_parser_fetch_anchor(parser *yaml_parser_t, typ yaml_token_type_t) bool {
|
|
1441 // An anchor or an alias could be a simple key.
|
|
1442 if !yaml_parser_save_simple_key(parser) {
|
|
1443 return false
|
|
1444 }
|
|
1445
|
|
1446 // A simple key cannot follow an anchor or an alias.
|
|
1447 parser.simple_key_allowed = false
|
|
1448
|
|
1449 // Create the ALIAS or ANCHOR token and append it to the queue.
|
|
1450 var token yaml_token_t
|
|
1451 if !yaml_parser_scan_anchor(parser, &token, typ) {
|
|
1452 return false
|
|
1453 }
|
|
1454 yaml_insert_token(parser, -1, &token)
|
|
1455 return true
|
|
1456 }
|
|
1457
|
|
1458 // Produce the TAG token.
|
|
1459 func yaml_parser_fetch_tag(parser *yaml_parser_t) bool {
|
|
1460 // A tag could be a simple key.
|
|
1461 if !yaml_parser_save_simple_key(parser) {
|
|
1462 return false
|
|
1463 }
|
|
1464
|
|
1465 // A simple key cannot follow a tag.
|
|
1466 parser.simple_key_allowed = false
|
|
1467
|
|
1468 // Create the TAG token and append it to the queue.
|
|
1469 var token yaml_token_t
|
|
1470 if !yaml_parser_scan_tag(parser, &token) {
|
|
1471 return false
|
|
1472 }
|
|
1473 yaml_insert_token(parser, -1, &token)
|
|
1474 return true
|
|
1475 }
|
|
1476
|
|
1477 // Produce the SCALAR(...,literal) or SCALAR(...,folded) tokens.
|
|
1478 func yaml_parser_fetch_block_scalar(parser *yaml_parser_t, literal bool) bool {
|
|
1479 // Remove any potential simple keys.
|
|
1480 if !yaml_parser_remove_simple_key(parser) {
|
|
1481 return false
|
|
1482 }
|
|
1483
|
|
1484 // A simple key may follow a block scalar.
|
|
1485 parser.simple_key_allowed = true
|
|
1486
|
|
1487 // Create the SCALAR token and append it to the queue.
|
|
1488 var token yaml_token_t
|
|
1489 if !yaml_parser_scan_block_scalar(parser, &token, literal) {
|
|
1490 return false
|
|
1491 }
|
|
1492 yaml_insert_token(parser, -1, &token)
|
|
1493 return true
|
|
1494 }
|
|
1495
|
|
1496 // Produce the SCALAR(...,single-quoted) or SCALAR(...,double-quoted) tokens.
|
|
1497 func yaml_parser_fetch_flow_scalar(parser *yaml_parser_t, single bool) bool {
|
|
1498 // A plain scalar could be a simple key.
|
|
1499 if !yaml_parser_save_simple_key(parser) {
|
|
1500 return false
|
|
1501 }
|
|
1502
|
|
1503 // A simple key cannot follow a flow scalar.
|
|
1504 parser.simple_key_allowed = false
|
|
1505
|
|
1506 // Create the SCALAR token and append it to the queue.
|
|
1507 var token yaml_token_t
|
|
1508 if !yaml_parser_scan_flow_scalar(parser, &token, single) {
|
|
1509 return false
|
|
1510 }
|
|
1511 yaml_insert_token(parser, -1, &token)
|
|
1512 return true
|
|
1513 }
|
|
1514
|
|
1515 // Produce the SCALAR(...,plain) token.
|
|
1516 func yaml_parser_fetch_plain_scalar(parser *yaml_parser_t) bool {
|
|
1517 // A plain scalar could be a simple key.
|
|
1518 if !yaml_parser_save_simple_key(parser) {
|
|
1519 return false
|
|
1520 }
|
|
1521
|
|
1522 // A simple key cannot follow a flow scalar.
|
|
1523 parser.simple_key_allowed = false
|
|
1524
|
|
1525 // Create the SCALAR token and append it to the queue.
|
|
1526 var token yaml_token_t
|
|
1527 if !yaml_parser_scan_plain_scalar(parser, &token) {
|
|
1528 return false
|
|
1529 }
|
|
1530 yaml_insert_token(parser, -1, &token)
|
|
1531 return true
|
|
1532 }
|
|
1533
|
|
1534 // Eat whitespaces and comments until the next token is found.
|
|
1535 func yaml_parser_scan_to_next_token(parser *yaml_parser_t) bool {
|
|
1536
|
|
1537 scan_mark := parser.mark
|
|
1538
|
|
1539 // Until the next token is not found.
|
|
1540 for {
|
|
1541 // Allow the BOM mark to start a line.
|
|
1542 if parser.unread < 1 && !yaml_parser_update_buffer(parser, 1) {
|
|
1543 return false
|
|
1544 }
|
|
1545 if parser.mark.column == 0 && is_bom(parser.buffer, parser.buffer_pos) {
|
|
1546 skip(parser)
|
|
1547 }
|
|
1548
|
|
1549 // Eat whitespaces.
|
|
1550 // Tabs are allowed:
|
|
1551 // - in the flow context
|
|
1552 // - in the block context, but not at the beginning of the line or
|
|
1553 // after '-', '?', or ':' (complex value).
|
|
1554 if parser.unread < 1 && !yaml_parser_update_buffer(parser, 1) {
|
|
1555 return false
|
|
1556 }
|
|
1557
|
|
1558 for parser.buffer[parser.buffer_pos] == ' ' || ((parser.flow_level > 0 || !parser.simple_key_allowed) && parser.buffer[parser.buffer_pos] == '\t') {
|
|
1559 skip(parser)
|
|
1560 if parser.unread < 1 && !yaml_parser_update_buffer(parser, 1) {
|
|
1561 return false
|
|
1562 }
|
|
1563 }
|
|
1564
|
|
1565 // Check if we just had a line comment under a sequence entry that
|
|
1566 // looks more like a header to the following content. Similar to this:
|
|
1567 //
|
|
1568 // - # The comment
|
|
1569 // - Some data
|
|
1570 //
|
|
1571 // If so, transform the line comment to a head comment and reposition.
|
|
1572 if len(parser.comments) > 0 && len(parser.tokens) > 1 {
|
|
1573 tokenA := parser.tokens[len(parser.tokens)-2]
|
|
1574 tokenB := parser.tokens[len(parser.tokens)-1]
|
|
1575 comment := &parser.comments[len(parser.comments)-1]
|
|
1576 if tokenA.typ == yaml_BLOCK_SEQUENCE_START_TOKEN && tokenB.typ == yaml_BLOCK_ENTRY_TOKEN && len(comment.line) > 0 && !is_break(parser.buffer, parser.buffer_pos) {
|
|
1577 // If it was in the prior line, reposition so it becomes a
|
|
1578 // header of the follow up token. Otherwise, keep it in place
|
|
1579 // so it becomes a header of the former.
|
|
1580 comment.head = comment.line
|
|
1581 comment.line = nil
|
|
1582 if comment.start_mark.line == parser.mark.line-1 {
|
|
1583 comment.token_mark = parser.mark
|
|
1584 }
|
|
1585 }
|
|
1586 }
|
|
1587
|
|
1588 // Eat a comment until a line break.
|
|
1589 if parser.buffer[parser.buffer_pos] == '#' {
|
|
1590 if !yaml_parser_scan_comments(parser, scan_mark) {
|
|
1591 return false
|
|
1592 }
|
|
1593 }
|
|
1594
|
|
1595 // If it is a line break, eat it.
|
|
1596 if is_break(parser.buffer, parser.buffer_pos) {
|
|
1597 if parser.unread < 2 && !yaml_parser_update_buffer(parser, 2) {
|
|
1598 return false
|
|
1599 }
|
|
1600 skip_line(parser)
|
|
1601
|
|
1602 // In the block context, a new line may start a simple key.
|
|
1603 if parser.flow_level == 0 {
|
|
1604 parser.simple_key_allowed = true
|
|
1605 }
|
|
1606 } else {
|
|
1607 break // We have found a token.
|
|
1608 }
|
|
1609 }
|
|
1610
|
|
1611 return true
|
|
1612 }
|
|
1613
|
|
1614 // Scan a YAML-DIRECTIVE or TAG-DIRECTIVE token.
|
|
1615 //
|
|
1616 // Scope:
|
|
1617 // %YAML 1.1 # a comment \n
|
|
1618 // ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
|
|
1619 // %TAG !yaml! tag:yaml.org,2002: \n
|
|
1620 // ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
|
|
1621 //
|
|
1622 func yaml_parser_scan_directive(parser *yaml_parser_t, token *yaml_token_t) bool {
|
|
1623 // Eat '%'.
|
|
1624 start_mark := parser.mark
|
|
1625 skip(parser)
|
|
1626
|
|
1627 // Scan the directive name.
|
|
1628 var name []byte
|
|
1629 if !yaml_parser_scan_directive_name(parser, start_mark, &name) {
|
|
1630 return false
|
|
1631 }
|
|
1632
|
|
1633 // Is it a YAML directive?
|
|
1634 if bytes.Equal(name, []byte("YAML")) {
|
|
1635 // Scan the VERSION directive value.
|
|
1636 var major, minor int8
|
|
1637 if !yaml_parser_scan_version_directive_value(parser, start_mark, &major, &minor) {
|
|
1638 return false
|
|
1639 }
|
|
1640 end_mark := parser.mark
|
|
1641
|
|
1642 // Create a VERSION-DIRECTIVE token.
|
|
1643 *token = yaml_token_t{
|
|
1644 typ: yaml_VERSION_DIRECTIVE_TOKEN,
|
|
1645 start_mark: start_mark,
|
|
1646 end_mark: end_mark,
|
|
1647 major: major,
|
|
1648 minor: minor,
|
|
1649 }
|
|
1650
|
|
1651 // Is it a TAG directive?
|
|
1652 } else if bytes.Equal(name, []byte("TAG")) {
|
|
1653 // Scan the TAG directive value.
|
|
1654 var handle, prefix []byte
|
|
1655 if !yaml_parser_scan_tag_directive_value(parser, start_mark, &handle, &prefix) {
|
|
1656 return false
|
|
1657 }
|
|
1658 end_mark := parser.mark
|
|
1659
|
|
1660 // Create a TAG-DIRECTIVE token.
|
|
1661 *token = yaml_token_t{
|
|
1662 typ: yaml_TAG_DIRECTIVE_TOKEN,
|
|
1663 start_mark: start_mark,
|
|
1664 end_mark: end_mark,
|
|
1665 value: handle,
|
|
1666 prefix: prefix,
|
|
1667 }
|
|
1668
|
|
1669 // Unknown directive.
|
|
1670 } else {
|
|
1671 yaml_parser_set_scanner_error(parser, "while scanning a directive",
|
|
1672 start_mark, "found unknown directive name")
|
|
1673 return false
|
|
1674 }
|
|
1675
|
|
1676 // Eat the rest of the line including any comments.
|
|
1677 if parser.unread < 1 && !yaml_parser_update_buffer(parser, 1) {
|
|
1678 return false
|
|
1679 }
|
|
1680
|
|
1681 for is_blank(parser.buffer, parser.buffer_pos) {
|
|
1682 skip(parser)
|
|
1683 if parser.unread < 1 && !yaml_parser_update_buffer(parser, 1) {
|
|
1684 return false
|
|
1685 }
|
|
1686 }
|
|
1687
|
|
1688 if parser.buffer[parser.buffer_pos] == '#' {
|
|
1689 // [Go] Discard this inline comment for the time being.
|
|
1690 //if !yaml_parser_scan_line_comment(parser, start_mark) {
|
|
1691 // return false
|
|
1692 //}
|
|
1693 for !is_breakz(parser.buffer, parser.buffer_pos) {
|
|
1694 skip(parser)
|
|
1695 if parser.unread < 1 && !yaml_parser_update_buffer(parser, 1) {
|
|
1696 return false
|
|
1697 }
|
|
1698 }
|
|
1699 }
|
|
1700
|
|
1701 // Check if we are at the end of the line.
|
|
1702 if !is_breakz(parser.buffer, parser.buffer_pos) {
|
|
1703 yaml_parser_set_scanner_error(parser, "while scanning a directive",
|
|
1704 start_mark, "did not find expected comment or line break")
|
|
1705 return false
|
|
1706 }
|
|
1707
|
|
1708 // Eat a line break.
|
|
1709 if is_break(parser.buffer, parser.buffer_pos) {
|
|
1710 if parser.unread < 2 && !yaml_parser_update_buffer(parser, 2) {
|
|
1711 return false
|
|
1712 }
|
|
1713 skip_line(parser)
|
|
1714 }
|
|
1715
|
|
1716 return true
|
|
1717 }
|
|
1718
|
|
1719 // Scan the directive name.
|
|
1720 //
|
|
1721 // Scope:
|
|
1722 // %YAML 1.1 # a comment \n
|
|
1723 // ^^^^
|
|
1724 // %TAG !yaml! tag:yaml.org,2002: \n
|
|
1725 // ^^^
|
|
1726 //
|
|
1727 func yaml_parser_scan_directive_name(parser *yaml_parser_t, start_mark yaml_mark_t, name *[]byte) bool {
|
|
1728 // Consume the directive name.
|
|
1729 if parser.unread < 1 && !yaml_parser_update_buffer(parser, 1) {
|
|
1730 return false
|
|
1731 }
|
|
1732
|
|
1733 var s []byte
|
|
1734 for is_alpha(parser.buffer, parser.buffer_pos) {
|
|
1735 s = read(parser, s)
|
|
1736 if parser.unread < 1 && !yaml_parser_update_buffer(parser, 1) {
|
|
1737 return false
|
|
1738 }
|
|
1739 }
|
|
1740
|
|
1741 // Check if the name is empty.
|
|
1742 if len(s) == 0 {
|
|
1743 yaml_parser_set_scanner_error(parser, "while scanning a directive",
|
|
1744 start_mark, "could not find expected directive name")
|
|
1745 return false
|
|
1746 }
|
|
1747
|
|
1748 // Check for an blank character after the name.
|
|
1749 if !is_blankz(parser.buffer, parser.buffer_pos) {
|
|
1750 yaml_parser_set_scanner_error(parser, "while scanning a directive",
|
|
1751 start_mark, "found unexpected non-alphabetical character")
|
|
1752 return false
|
|
1753 }
|
|
1754 *name = s
|
|
1755 return true
|
|
1756 }
|
|
1757
|
|
1758 // Scan the value of VERSION-DIRECTIVE.
|
|
1759 //
|
|
1760 // Scope:
|
|
1761 // %YAML 1.1 # a comment \n
|
|
1762 // ^^^^^^
|
|
1763 func yaml_parser_scan_version_directive_value(parser *yaml_parser_t, start_mark yaml_mark_t, major, minor *int8) bool {
|
|
1764 // Eat whitespaces.
|
|
1765 if parser.unread < 1 && !yaml_parser_update_buffer(parser, 1) {
|
|
1766 return false
|
|
1767 }
|
|
1768 for is_blank(parser.buffer, parser.buffer_pos) {
|
|
1769 skip(parser)
|
|
1770 if parser.unread < 1 && !yaml_parser_update_buffer(parser, 1) {
|
|
1771 return false
|
|
1772 }
|
|
1773 }
|
|
1774
|
|
1775 // Consume the major version number.
|
|
1776 if !yaml_parser_scan_version_directive_number(parser, start_mark, major) {
|
|
1777 return false
|
|
1778 }
|
|
1779
|
|
1780 // Eat '.'.
|
|
1781 if parser.buffer[parser.buffer_pos] != '.' {
|
|
1782 return yaml_parser_set_scanner_error(parser, "while scanning a %YAML directive",
|
|
1783 start_mark, "did not find expected digit or '.' character")
|
|
1784 }
|
|
1785
|
|
1786 skip(parser)
|
|
1787
|
|
1788 // Consume the minor version number.
|
|
1789 if !yaml_parser_scan_version_directive_number(parser, start_mark, minor) {
|
|
1790 return false
|
|
1791 }
|
|
1792 return true
|
|
1793 }
|
|
1794
|
|
1795 const max_number_length = 2
|
|
1796
|
|
1797 // Scan the version number of VERSION-DIRECTIVE.
|
|
1798 //
|
|
1799 // Scope:
|
|
1800 // %YAML 1.1 # a comment \n
|
|
1801 // ^
|
|
1802 // %YAML 1.1 # a comment \n
|
|
1803 // ^
|
|
1804 func yaml_parser_scan_version_directive_number(parser *yaml_parser_t, start_mark yaml_mark_t, number *int8) bool {
|
|
1805
|
|
1806 // Repeat while the next character is digit.
|
|
1807 if parser.unread < 1 && !yaml_parser_update_buffer(parser, 1) {
|
|
1808 return false
|
|
1809 }
|
|
1810 var value, length int8
|
|
1811 for is_digit(parser.buffer, parser.buffer_pos) {
|
|
1812 // Check if the number is too long.
|
|
1813 length++
|
|
1814 if length > max_number_length {
|
|
1815 return yaml_parser_set_scanner_error(parser, "while scanning a %YAML directive",
|
|
1816 start_mark, "found extremely long version number")
|
|
1817 }
|
|
1818 value = value*10 + int8(as_digit(parser.buffer, parser.buffer_pos))
|
|
1819 skip(parser)
|
|
1820 if parser.unread < 1 && !yaml_parser_update_buffer(parser, 1) {
|
|
1821 return false
|
|
1822 }
|
|
1823 }
|
|
1824
|
|
1825 // Check if the number was present.
|
|
1826 if length == 0 {
|
|
1827 return yaml_parser_set_scanner_error(parser, "while scanning a %YAML directive",
|
|
1828 start_mark, "did not find expected version number")
|
|
1829 }
|
|
1830 *number = value
|
|
1831 return true
|
|
1832 }
|
|
1833
|
|
1834 // Scan the value of a TAG-DIRECTIVE token.
|
|
1835 //
|
|
1836 // Scope:
|
|
1837 // %TAG !yaml! tag:yaml.org,2002: \n
|
|
1838 // ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
|
|
1839 //
|
|
1840 func yaml_parser_scan_tag_directive_value(parser *yaml_parser_t, start_mark yaml_mark_t, handle, prefix *[]byte) bool {
|
|
1841 var handle_value, prefix_value []byte
|
|
1842
|
|
1843 // Eat whitespaces.
|
|
1844 if parser.unread < 1 && !yaml_parser_update_buffer(parser, 1) {
|
|
1845 return false
|
|
1846 }
|
|
1847
|
|
1848 for is_blank(parser.buffer, parser.buffer_pos) {
|
|
1849 skip(parser)
|
|
1850 if parser.unread < 1 && !yaml_parser_update_buffer(parser, 1) {
|
|
1851 return false
|
|
1852 }
|
|
1853 }
|
|
1854
|
|
1855 // Scan a handle.
|
|
1856 if !yaml_parser_scan_tag_handle(parser, true, start_mark, &handle_value) {
|
|
1857 return false
|
|
1858 }
|
|
1859
|
|
1860 // Expect a whitespace.
|
|
1861 if parser.unread < 1 && !yaml_parser_update_buffer(parser, 1) {
|
|
1862 return false
|
|
1863 }
|
|
1864 if !is_blank(parser.buffer, parser.buffer_pos) {
|
|
1865 yaml_parser_set_scanner_error(parser, "while scanning a %TAG directive",
|
|
1866 start_mark, "did not find expected whitespace")
|
|
1867 return false
|
|
1868 }
|
|
1869
|
|
1870 // Eat whitespaces.
|
|
1871 for is_blank(parser.buffer, parser.buffer_pos) {
|
|
1872 skip(parser)
|
|
1873 if parser.unread < 1 && !yaml_parser_update_buffer(parser, 1) {
|
|
1874 return false
|
|
1875 }
|
|
1876 }
|
|
1877
|
|
1878 // Scan a prefix.
|
|
1879 if !yaml_parser_scan_tag_uri(parser, true, nil, start_mark, &prefix_value) {
|
|
1880 return false
|
|
1881 }
|
|
1882
|
|
1883 // Expect a whitespace or line break.
|
|
1884 if parser.unread < 1 && !yaml_parser_update_buffer(parser, 1) {
|
|
1885 return false
|
|
1886 }
|
|
1887 if !is_blankz(parser.buffer, parser.buffer_pos) {
|
|
1888 yaml_parser_set_scanner_error(parser, "while scanning a %TAG directive",
|
|
1889 start_mark, "did not find expected whitespace or line break")
|
|
1890 return false
|
|
1891 }
|
|
1892
|
|
1893 *handle = handle_value
|
|
1894 *prefix = prefix_value
|
|
1895 return true
|
|
1896 }
|
|
1897
|
|
1898 func yaml_parser_scan_anchor(parser *yaml_parser_t, token *yaml_token_t, typ yaml_token_type_t) bool {
|
|
1899 var s []byte
|
|
1900
|
|
1901 // Eat the indicator character.
|
|
1902 start_mark := parser.mark
|
|
1903 skip(parser)
|
|
1904
|
|
1905 // Consume the value.
|
|
1906 if parser.unread < 1 && !yaml_parser_update_buffer(parser, 1) {
|
|
1907 return false
|
|
1908 }
|
|
1909
|
|
1910 for is_alpha(parser.buffer, parser.buffer_pos) {
|
|
1911 s = read(parser, s)
|
|
1912 if parser.unread < 1 && !yaml_parser_update_buffer(parser, 1) {
|
|
1913 return false
|
|
1914 }
|
|
1915 }
|
|
1916
|
|
1917 end_mark := parser.mark
|
|
1918
|
|
1919 /*
|
|
1920 * Check if length of the anchor is greater than 0 and it is followed by
|
|
1921 * a whitespace character or one of the indicators:
|
|
1922 *
|
|
1923 * '?', ':', ',', ']', '}', '%', '@', '`'.
|
|
1924 */
|
|
1925
|
|
1926 if len(s) == 0 ||
|
|
1927 !(is_blankz(parser.buffer, parser.buffer_pos) || parser.buffer[parser.buffer_pos] == '?' ||
|
|
1928 parser.buffer[parser.buffer_pos] == ':' || parser.buffer[parser.buffer_pos] == ',' ||
|
|
1929 parser.buffer[parser.buffer_pos] == ']' || parser.buffer[parser.buffer_pos] == '}' ||
|
|
1930 parser.buffer[parser.buffer_pos] == '%' || parser.buffer[parser.buffer_pos] == '@' ||
|
|
1931 parser.buffer[parser.buffer_pos] == '`') {
|
|
1932 context := "while scanning an alias"
|
|
1933 if typ == yaml_ANCHOR_TOKEN {
|
|
1934 context = "while scanning an anchor"
|
|
1935 }
|
|
1936 yaml_parser_set_scanner_error(parser, context, start_mark,
|
|
1937 "did not find expected alphabetic or numeric character")
|
|
1938 return false
|
|
1939 }
|
|
1940
|
|
1941 // Create a token.
|
|
1942 *token = yaml_token_t{
|
|
1943 typ: typ,
|
|
1944 start_mark: start_mark,
|
|
1945 end_mark: end_mark,
|
|
1946 value: s,
|
|
1947 }
|
|
1948
|
|
1949 return true
|
|
1950 }
|
|
1951
|
|
1952 /*
|
|
1953 * Scan a TAG token.
|
|
1954 */
|
|
1955
|
|
1956 func yaml_parser_scan_tag(parser *yaml_parser_t, token *yaml_token_t) bool {
|
|
1957 var handle, suffix []byte
|
|
1958
|
|
1959 start_mark := parser.mark
|
|
1960
|
|
1961 // Check if the tag is in the canonical form.
|
|
1962 if parser.unread < 2 && !yaml_parser_update_buffer(parser, 2) {
|
|
1963 return false
|
|
1964 }
|
|
1965
|
|
1966 if parser.buffer[parser.buffer_pos+1] == '<' {
|
|
1967 // Keep the handle as ''
|
|
1968
|
|
1969 // Eat '!<'
|
|
1970 skip(parser)
|
|
1971 skip(parser)
|
|
1972
|
|
1973 // Consume the tag value.
|
|
1974 if !yaml_parser_scan_tag_uri(parser, false, nil, start_mark, &suffix) {
|
|
1975 return false
|
|
1976 }
|
|
1977
|
|
1978 // Check for '>' and eat it.
|
|
1979 if parser.buffer[parser.buffer_pos] != '>' {
|
|
1980 yaml_parser_set_scanner_error(parser, "while scanning a tag",
|
|
1981 start_mark, "did not find the expected '>'")
|
|
1982 return false
|
|
1983 }
|
|
1984
|
|
1985 skip(parser)
|
|
1986 } else {
|
|
1987 // The tag has either the '!suffix' or the '!handle!suffix' form.
|
|
1988
|
|
1989 // First, try to scan a handle.
|
|
1990 if !yaml_parser_scan_tag_handle(parser, false, start_mark, &handle) {
|
|
1991 return false
|
|
1992 }
|
|
1993
|
|
1994 // Check if it is, indeed, handle.
|
|
1995 if handle[0] == '!' && len(handle) > 1 && handle[len(handle)-1] == '!' {
|
|
1996 // Scan the suffix now.
|
|
1997 if !yaml_parser_scan_tag_uri(parser, false, nil, start_mark, &suffix) {
|
|
1998 return false
|
|
1999 }
|
|
2000 } else {
|
|
2001 // It wasn't a handle after all. Scan the rest of the tag.
|
|
2002 if !yaml_parser_scan_tag_uri(parser, false, handle, start_mark, &suffix) {
|
|
2003 return false
|
|
2004 }
|
|
2005
|
|
2006 // Set the handle to '!'.
|
|
2007 handle = []byte{'!'}
|
|
2008
|
|
2009 // A special case: the '!' tag. Set the handle to '' and the
|
|
2010 // suffix to '!'.
|
|
2011 if len(suffix) == 0 {
|
|
2012 handle, suffix = suffix, handle
|
|
2013 }
|
|
2014 }
|
|
2015 }
|
|
2016
|
|
2017 // Check the character which ends the tag.
|
|
2018 if parser.unread < 1 && !yaml_parser_update_buffer(parser, 1) {
|
|
2019 return false
|
|
2020 }
|
|
2021 if !is_blankz(parser.buffer, parser.buffer_pos) {
|
|
2022 yaml_parser_set_scanner_error(parser, "while scanning a tag",
|
|
2023 start_mark, "did not find expected whitespace or line break")
|
|
2024 return false
|
|
2025 }
|
|
2026
|
|
2027 end_mark := parser.mark
|
|
2028
|
|
2029 // Create a token.
|
|
2030 *token = yaml_token_t{
|
|
2031 typ: yaml_TAG_TOKEN,
|
|
2032 start_mark: start_mark,
|
|
2033 end_mark: end_mark,
|
|
2034 value: handle,
|
|
2035 suffix: suffix,
|
|
2036 }
|
|
2037 return true
|
|
2038 }
|
|
2039
|
|
2040 // Scan a tag handle.
|
|
2041 func yaml_parser_scan_tag_handle(parser *yaml_parser_t, directive bool, start_mark yaml_mark_t, handle *[]byte) bool {
|
|
2042 // Check the initial '!' character.
|
|
2043 if parser.unread < 1 && !yaml_parser_update_buffer(parser, 1) {
|
|
2044 return false
|
|
2045 }
|
|
2046 if parser.buffer[parser.buffer_pos] != '!' {
|
|
2047 yaml_parser_set_scanner_tag_error(parser, directive,
|
|
2048 start_mark, "did not find expected '!'")
|
|
2049 return false
|
|
2050 }
|
|
2051
|
|
2052 var s []byte
|
|
2053
|
|
2054 // Copy the '!' character.
|
|
2055 s = read(parser, s)
|
|
2056
|
|
2057 // Copy all subsequent alphabetical and numerical characters.
|
|
2058 if parser.unread < 1 && !yaml_parser_update_buffer(parser, 1) {
|
|
2059 return false
|
|
2060 }
|
|
2061 for is_alpha(parser.buffer, parser.buffer_pos) {
|
|
2062 s = read(parser, s)
|
|
2063 if parser.unread < 1 && !yaml_parser_update_buffer(parser, 1) {
|
|
2064 return false
|
|
2065 }
|
|
2066 }
|
|
2067
|
|
2068 // Check if the trailing character is '!' and copy it.
|
|
2069 if parser.buffer[parser.buffer_pos] == '!' {
|
|
2070 s = read(parser, s)
|
|
2071 } else {
|
|
2072 // It's either the '!' tag or not really a tag handle. If it's a %TAG
|
|
2073 // directive, it's an error. If it's a tag token, it must be a part of URI.
|
|
2074 if directive && string(s) != "!" {
|
|
2075 yaml_parser_set_scanner_tag_error(parser, directive,
|
|
2076 start_mark, "did not find expected '!'")
|
|
2077 return false
|
|
2078 }
|
|
2079 }
|
|
2080
|
|
2081 *handle = s
|
|
2082 return true
|
|
2083 }
|
|
2084
|
|
2085 // Scan a tag.
|
|
2086 func yaml_parser_scan_tag_uri(parser *yaml_parser_t, directive bool, head []byte, start_mark yaml_mark_t, uri *[]byte) bool {
|
|
2087 //size_t length = head ? strlen((char *)head) : 0
|
|
2088 var s []byte
|
|
2089 hasTag := len(head) > 0
|
|
2090
|
|
2091 // Copy the head if needed.
|
|
2092 //
|
|
2093 // Note that we don't copy the leading '!' character.
|
|
2094 if len(head) > 1 {
|
|
2095 s = append(s, head[1:]...)
|
|
2096 }
|
|
2097
|
|
2098 // Scan the tag.
|
|
2099 if parser.unread < 1 && !yaml_parser_update_buffer(parser, 1) {
|
|
2100 return false
|
|
2101 }
|
|
2102
|
|
2103 // The set of characters that may appear in URI is as follows:
|
|
2104 //
|
|
2105 // '0'-'9', 'A'-'Z', 'a'-'z', '_', '-', ';', '/', '?', ':', '@', '&',
|
|
2106 // '=', '+', '$', ',', '.', '!', '~', '*', '\'', '(', ')', '[', ']',
|
|
2107 // '%'.
|
|
2108 // [Go] TODO Convert this into more reasonable logic.
|
|
2109 for is_alpha(parser.buffer, parser.buffer_pos) || parser.buffer[parser.buffer_pos] == ';' ||
|
|
2110 parser.buffer[parser.buffer_pos] == '/' || parser.buffer[parser.buffer_pos] == '?' ||
|
|
2111 parser.buffer[parser.buffer_pos] == ':' || parser.buffer[parser.buffer_pos] == '@' ||
|
|
2112 parser.buffer[parser.buffer_pos] == '&' || parser.buffer[parser.buffer_pos] == '=' ||
|
|
2113 parser.buffer[parser.buffer_pos] == '+' || parser.buffer[parser.buffer_pos] == '$' ||
|
|
2114 parser.buffer[parser.buffer_pos] == ',' || parser.buffer[parser.buffer_pos] == '.' ||
|
|
2115 parser.buffer[parser.buffer_pos] == '!' || parser.buffer[parser.buffer_pos] == '~' ||
|
|
2116 parser.buffer[parser.buffer_pos] == '*' || parser.buffer[parser.buffer_pos] == '\'' ||
|
|
2117 parser.buffer[parser.buffer_pos] == '(' || parser.buffer[parser.buffer_pos] == ')' ||
|
|
2118 parser.buffer[parser.buffer_pos] == '[' || parser.buffer[parser.buffer_pos] == ']' ||
|
|
2119 parser.buffer[parser.buffer_pos] == '%' {
|
|
2120 // Check if it is a URI-escape sequence.
|
|
2121 if parser.buffer[parser.buffer_pos] == '%' {
|
|
2122 if !yaml_parser_scan_uri_escapes(parser, directive, start_mark, &s) {
|
|
2123 return false
|
|
2124 }
|
|
2125 } else {
|
|
2126 s = read(parser, s)
|
|
2127 }
|
|
2128 if parser.unread < 1 && !yaml_parser_update_buffer(parser, 1) {
|
|
2129 return false
|
|
2130 }
|
|
2131 hasTag = true
|
|
2132 }
|
|
2133
|
|
2134 if !hasTag {
|
|
2135 yaml_parser_set_scanner_tag_error(parser, directive,
|
|
2136 start_mark, "did not find expected tag URI")
|
|
2137 return false
|
|
2138 }
|
|
2139 *uri = s
|
|
2140 return true
|
|
2141 }
|
|
2142
|
|
2143 // Decode an URI-escape sequence corresponding to a single UTF-8 character.
|
|
2144 func yaml_parser_scan_uri_escapes(parser *yaml_parser_t, directive bool, start_mark yaml_mark_t, s *[]byte) bool {
|
|
2145
|
|
2146 // Decode the required number of characters.
|
|
2147 w := 1024
|
|
2148 for w > 0 {
|
|
2149 // Check for a URI-escaped octet.
|
|
2150 if parser.unread < 3 && !yaml_parser_update_buffer(parser, 3) {
|
|
2151 return false
|
|
2152 }
|
|
2153
|
|
2154 if !(parser.buffer[parser.buffer_pos] == '%' &&
|
|
2155 is_hex(parser.buffer, parser.buffer_pos+1) &&
|
|
2156 is_hex(parser.buffer, parser.buffer_pos+2)) {
|
|
2157 return yaml_parser_set_scanner_tag_error(parser, directive,
|
|
2158 start_mark, "did not find URI escaped octet")
|
|
2159 }
|
|
2160
|
|
2161 // Get the octet.
|
|
2162 octet := byte((as_hex(parser.buffer, parser.buffer_pos+1) << 4) + as_hex(parser.buffer, parser.buffer_pos+2))
|
|
2163
|
|
2164 // If it is the leading octet, determine the length of the UTF-8 sequence.
|
|
2165 if w == 1024 {
|
|
2166 w = width(octet)
|
|
2167 if w == 0 {
|
|
2168 return yaml_parser_set_scanner_tag_error(parser, directive,
|
|
2169 start_mark, "found an incorrect leading UTF-8 octet")
|
|
2170 }
|
|
2171 } else {
|
|
2172 // Check if the trailing octet is correct.
|
|
2173 if octet&0xC0 != 0x80 {
|
|
2174 return yaml_parser_set_scanner_tag_error(parser, directive,
|
|
2175 start_mark, "found an incorrect trailing UTF-8 octet")
|
|
2176 }
|
|
2177 }
|
|
2178
|
|
2179 // Copy the octet and move the pointers.
|
|
2180 *s = append(*s, octet)
|
|
2181 skip(parser)
|
|
2182 skip(parser)
|
|
2183 skip(parser)
|
|
2184 w--
|
|
2185 }
|
|
2186 return true
|
|
2187 }
|
|
2188
|
|
2189 // Scan a block scalar.
|
|
2190 func yaml_parser_scan_block_scalar(parser *yaml_parser_t, token *yaml_token_t, literal bool) bool {
|
|
2191 // Eat the indicator '|' or '>'.
|
|
2192 start_mark := parser.mark
|
|
2193 skip(parser)
|
|
2194
|
|
2195 // Scan the additional block scalar indicators.
|
|
2196 if parser.unread < 1 && !yaml_parser_update_buffer(parser, 1) {
|
|
2197 return false
|
|
2198 }
|
|
2199
|
|
2200 // Check for a chomping indicator.
|
|
2201 var chomping, increment int
|
|
2202 if parser.buffer[parser.buffer_pos] == '+' || parser.buffer[parser.buffer_pos] == '-' {
|
|
2203 // Set the chomping method and eat the indicator.
|
|
2204 if parser.buffer[parser.buffer_pos] == '+' {
|
|
2205 chomping = +1
|
|
2206 } else {
|
|
2207 chomping = -1
|
|
2208 }
|
|
2209 skip(parser)
|
|
2210
|
|
2211 // Check for an indentation indicator.
|
|
2212 if parser.unread < 1 && !yaml_parser_update_buffer(parser, 1) {
|
|
2213 return false
|
|
2214 }
|
|
2215 if is_digit(parser.buffer, parser.buffer_pos) {
|
|
2216 // Check that the indentation is greater than 0.
|
|
2217 if parser.buffer[parser.buffer_pos] == '0' {
|
|
2218 yaml_parser_set_scanner_error(parser, "while scanning a block scalar",
|
|
2219 start_mark, "found an indentation indicator equal to 0")
|
|
2220 return false
|
|
2221 }
|
|
2222
|
|
2223 // Get the indentation level and eat the indicator.
|
|
2224 increment = as_digit(parser.buffer, parser.buffer_pos)
|
|
2225 skip(parser)
|
|
2226 }
|
|
2227
|
|
2228 } else if is_digit(parser.buffer, parser.buffer_pos) {
|
|
2229 // Do the same as above, but in the opposite order.
|
|
2230
|
|
2231 if parser.buffer[parser.buffer_pos] == '0' {
|
|
2232 yaml_parser_set_scanner_error(parser, "while scanning a block scalar",
|
|
2233 start_mark, "found an indentation indicator equal to 0")
|
|
2234 return false
|
|
2235 }
|
|
2236 increment = as_digit(parser.buffer, parser.buffer_pos)
|
|
2237 skip(parser)
|
|
2238
|
|
2239 if parser.unread < 1 && !yaml_parser_update_buffer(parser, 1) {
|
|
2240 return false
|
|
2241 }
|
|
2242 if parser.buffer[parser.buffer_pos] == '+' || parser.buffer[parser.buffer_pos] == '-' {
|
|
2243 if parser.buffer[parser.buffer_pos] == '+' {
|
|
2244 chomping = +1
|
|
2245 } else {
|
|
2246 chomping = -1
|
|
2247 }
|
|
2248 skip(parser)
|
|
2249 }
|
|
2250 }
|
|
2251
|
|
2252 // Eat whitespaces and comments to the end of the line.
|
|
2253 if parser.unread < 1 && !yaml_parser_update_buffer(parser, 1) {
|
|
2254 return false
|
|
2255 }
|
|
2256 for is_blank(parser.buffer, parser.buffer_pos) {
|
|
2257 skip(parser)
|
|
2258 if parser.unread < 1 && !yaml_parser_update_buffer(parser, 1) {
|
|
2259 return false
|
|
2260 }
|
|
2261 }
|
|
2262 if parser.buffer[parser.buffer_pos] == '#' {
|
|
2263 if !yaml_parser_scan_line_comment(parser, start_mark) {
|
|
2264 return false
|
|
2265 }
|
|
2266 for !is_breakz(parser.buffer, parser.buffer_pos) {
|
|
2267 skip(parser)
|
|
2268 if parser.unread < 1 && !yaml_parser_update_buffer(parser, 1) {
|
|
2269 return false
|
|
2270 }
|
|
2271 }
|
|
2272 }
|
|
2273
|
|
2274 // Check if we are at the end of the line.
|
|
2275 if !is_breakz(parser.buffer, parser.buffer_pos) {
|
|
2276 yaml_parser_set_scanner_error(parser, "while scanning a block scalar",
|
|
2277 start_mark, "did not find expected comment or line break")
|
|
2278 return false
|
|
2279 }
|
|
2280
|
|
2281 // Eat a line break.
|
|
2282 if is_break(parser.buffer, parser.buffer_pos) {
|
|
2283 if parser.unread < 2 && !yaml_parser_update_buffer(parser, 2) {
|
|
2284 return false
|
|
2285 }
|
|
2286 skip_line(parser)
|
|
2287 }
|
|
2288
|
|
2289 end_mark := parser.mark
|
|
2290
|
|
2291 // Set the indentation level if it was specified.
|
|
2292 var indent int
|
|
2293 if increment > 0 {
|
|
2294 if parser.indent >= 0 {
|
|
2295 indent = parser.indent + increment
|
|
2296 } else {
|
|
2297 indent = increment
|
|
2298 }
|
|
2299 }
|
|
2300
|
|
2301 // Scan the leading line breaks and determine the indentation level if needed.
|
|
2302 var s, leading_break, trailing_breaks []byte
|
|
2303 if !yaml_parser_scan_block_scalar_breaks(parser, &indent, &trailing_breaks, start_mark, &end_mark) {
|
|
2304 return false
|
|
2305 }
|
|
2306
|
|
2307 // Scan the block scalar content.
|
|
2308 if parser.unread < 1 && !yaml_parser_update_buffer(parser, 1) {
|
|
2309 return false
|
|
2310 }
|
|
2311 var leading_blank, trailing_blank bool
|
|
2312 for parser.mark.column == indent && !is_z(parser.buffer, parser.buffer_pos) {
|
|
2313 // We are at the beginning of a non-empty line.
|
|
2314
|
|
2315 // Is it a trailing whitespace?
|
|
2316 trailing_blank = is_blank(parser.buffer, parser.buffer_pos)
|
|
2317
|
|
2318 // Check if we need to fold the leading line break.
|
|
2319 if !literal && !leading_blank && !trailing_blank && len(leading_break) > 0 && leading_break[0] == '\n' {
|
|
2320 // Do we need to join the lines by space?
|
|
2321 if len(trailing_breaks) == 0 {
|
|
2322 s = append(s, ' ')
|
|
2323 }
|
|
2324 } else {
|
|
2325 s = append(s, leading_break...)
|
|
2326 }
|
|
2327 leading_break = leading_break[:0]
|
|
2328
|
|
2329 // Append the remaining line breaks.
|
|
2330 s = append(s, trailing_breaks...)
|
|
2331 trailing_breaks = trailing_breaks[:0]
|
|
2332
|
|
2333 // Is it a leading whitespace?
|
|
2334 leading_blank = is_blank(parser.buffer, parser.buffer_pos)
|
|
2335
|
|
2336 // Consume the current line.
|
|
2337 for !is_breakz(parser.buffer, parser.buffer_pos) {
|
|
2338 s = read(parser, s)
|
|
2339 if parser.unread < 1 && !yaml_parser_update_buffer(parser, 1) {
|
|
2340 return false
|
|
2341 }
|
|
2342 }
|
|
2343
|
|
2344 // Consume the line break.
|
|
2345 if parser.unread < 2 && !yaml_parser_update_buffer(parser, 2) {
|
|
2346 return false
|
|
2347 }
|
|
2348
|
|
2349 leading_break = read_line(parser, leading_break)
|
|
2350
|
|
2351 // Eat the following indentation spaces and line breaks.
|
|
2352 if !yaml_parser_scan_block_scalar_breaks(parser, &indent, &trailing_breaks, start_mark, &end_mark) {
|
|
2353 return false
|
|
2354 }
|
|
2355 }
|
|
2356
|
|
2357 // Chomp the tail.
|
|
2358 if chomping != -1 {
|
|
2359 s = append(s, leading_break...)
|
|
2360 }
|
|
2361 if chomping == 1 {
|
|
2362 s = append(s, trailing_breaks...)
|
|
2363 }
|
|
2364
|
|
2365 // Create a token.
|
|
2366 *token = yaml_token_t{
|
|
2367 typ: yaml_SCALAR_TOKEN,
|
|
2368 start_mark: start_mark,
|
|
2369 end_mark: end_mark,
|
|
2370 value: s,
|
|
2371 style: yaml_LITERAL_SCALAR_STYLE,
|
|
2372 }
|
|
2373 if !literal {
|
|
2374 token.style = yaml_FOLDED_SCALAR_STYLE
|
|
2375 }
|
|
2376 return true
|
|
2377 }
|
|
2378
|
|
2379 // Scan indentation spaces and line breaks for a block scalar. Determine the
|
|
2380 // indentation level if needed.
|
|
2381 func yaml_parser_scan_block_scalar_breaks(parser *yaml_parser_t, indent *int, breaks *[]byte, start_mark yaml_mark_t, end_mark *yaml_mark_t) bool {
|
|
2382 *end_mark = parser.mark
|
|
2383
|
|
2384 // Eat the indentation spaces and line breaks.
|
|
2385 max_indent := 0
|
|
2386 for {
|
|
2387 // Eat the indentation spaces.
|
|
2388 if parser.unread < 1 && !yaml_parser_update_buffer(parser, 1) {
|
|
2389 return false
|
|
2390 }
|
|
2391 for (*indent == 0 || parser.mark.column < *indent) && is_space(parser.buffer, parser.buffer_pos) {
|
|
2392 skip(parser)
|
|
2393 if parser.unread < 1 && !yaml_parser_update_buffer(parser, 1) {
|
|
2394 return false
|
|
2395 }
|
|
2396 }
|
|
2397 if parser.mark.column > max_indent {
|
|
2398 max_indent = parser.mark.column
|
|
2399 }
|
|
2400
|
|
2401 // Check for a tab character messing the indentation.
|
|
2402 if (*indent == 0 || parser.mark.column < *indent) && is_tab(parser.buffer, parser.buffer_pos) {
|
|
2403 return yaml_parser_set_scanner_error(parser, "while scanning a block scalar",
|
|
2404 start_mark, "found a tab character where an indentation space is expected")
|
|
2405 }
|
|
2406
|
|
2407 // Have we found a non-empty line?
|
|
2408 if !is_break(parser.buffer, parser.buffer_pos) {
|
|
2409 break
|
|
2410 }
|
|
2411
|
|
2412 // Consume the line break.
|
|
2413 if parser.unread < 2 && !yaml_parser_update_buffer(parser, 2) {
|
|
2414 return false
|
|
2415 }
|
|
2416 // [Go] Should really be returning breaks instead.
|
|
2417 *breaks = read_line(parser, *breaks)
|
|
2418 *end_mark = parser.mark
|
|
2419 }
|
|
2420
|
|
2421 // Determine the indentation level if needed.
|
|
2422 if *indent == 0 {
|
|
2423 *indent = max_indent
|
|
2424 if *indent < parser.indent+1 {
|
|
2425 *indent = parser.indent + 1
|
|
2426 }
|
|
2427 if *indent < 1 {
|
|
2428 *indent = 1
|
|
2429 }
|
|
2430 }
|
|
2431 return true
|
|
2432 }
|
|
2433
|
|
2434 // Scan a quoted scalar.
|
|
2435 func yaml_parser_scan_flow_scalar(parser *yaml_parser_t, token *yaml_token_t, single bool) bool {
|
|
2436 // Eat the left quote.
|
|
2437 start_mark := parser.mark
|
|
2438 skip(parser)
|
|
2439
|
|
2440 // Consume the content of the quoted scalar.
|
|
2441 var s, leading_break, trailing_breaks, whitespaces []byte
|
|
2442 for {
|
|
2443 // Check that there are no document indicators at the beginning of the line.
|
|
2444 if parser.unread < 4 && !yaml_parser_update_buffer(parser, 4) {
|
|
2445 return false
|
|
2446 }
|
|
2447
|
|
2448 if parser.mark.column == 0 &&
|
|
2449 ((parser.buffer[parser.buffer_pos+0] == '-' &&
|
|
2450 parser.buffer[parser.buffer_pos+1] == '-' &&
|
|
2451 parser.buffer[parser.buffer_pos+2] == '-') ||
|
|
2452 (parser.buffer[parser.buffer_pos+0] == '.' &&
|
|
2453 parser.buffer[parser.buffer_pos+1] == '.' &&
|
|
2454 parser.buffer[parser.buffer_pos+2] == '.')) &&
|
|
2455 is_blankz(parser.buffer, parser.buffer_pos+3) {
|
|
2456 yaml_parser_set_scanner_error(parser, "while scanning a quoted scalar",
|
|
2457 start_mark, "found unexpected document indicator")
|
|
2458 return false
|
|
2459 }
|
|
2460
|
|
2461 // Check for EOF.
|
|
2462 if is_z(parser.buffer, parser.buffer_pos) {
|
|
2463 yaml_parser_set_scanner_error(parser, "while scanning a quoted scalar",
|
|
2464 start_mark, "found unexpected end of stream")
|
|
2465 return false
|
|
2466 }
|
|
2467
|
|
2468 // Consume non-blank characters.
|
|
2469 leading_blanks := false
|
|
2470 for !is_blankz(parser.buffer, parser.buffer_pos) {
|
|
2471 if single && parser.buffer[parser.buffer_pos] == '\'' && parser.buffer[parser.buffer_pos+1] == '\'' {
|
|
2472 // Is is an escaped single quote.
|
|
2473 s = append(s, '\'')
|
|
2474 skip(parser)
|
|
2475 skip(parser)
|
|
2476
|
|
2477 } else if single && parser.buffer[parser.buffer_pos] == '\'' {
|
|
2478 // It is a right single quote.
|
|
2479 break
|
|
2480 } else if !single && parser.buffer[parser.buffer_pos] == '"' {
|
|
2481 // It is a right double quote.
|
|
2482 break
|
|
2483
|
|
2484 } else if !single && parser.buffer[parser.buffer_pos] == '\\' && is_break(parser.buffer, parser.buffer_pos+1) {
|
|
2485 // It is an escaped line break.
|
|
2486 if parser.unread < 3 && !yaml_parser_update_buffer(parser, 3) {
|
|
2487 return false
|
|
2488 }
|
|
2489 skip(parser)
|
|
2490 skip_line(parser)
|
|
2491 leading_blanks = true
|
|
2492 break
|
|
2493
|
|
2494 } else if !single && parser.buffer[parser.buffer_pos] == '\\' {
|
|
2495 // It is an escape sequence.
|
|
2496 code_length := 0
|
|
2497
|
|
2498 // Check the escape character.
|
|
2499 switch parser.buffer[parser.buffer_pos+1] {
|
|
2500 case '0':
|
|
2501 s = append(s, 0)
|
|
2502 case 'a':
|
|
2503 s = append(s, '\x07')
|
|
2504 case 'b':
|
|
2505 s = append(s, '\x08')
|
|
2506 case 't', '\t':
|
|
2507 s = append(s, '\x09')
|
|
2508 case 'n':
|
|
2509 s = append(s, '\x0A')
|
|
2510 case 'v':
|
|
2511 s = append(s, '\x0B')
|
|
2512 case 'f':
|
|
2513 s = append(s, '\x0C')
|
|
2514 case 'r':
|
|
2515 s = append(s, '\x0D')
|
|
2516 case 'e':
|
|
2517 s = append(s, '\x1B')
|
|
2518 case ' ':
|
|
2519 s = append(s, '\x20')
|
|
2520 case '"':
|
|
2521 s = append(s, '"')
|
|
2522 case '\'':
|
|
2523 s = append(s, '\'')
|
|
2524 case '\\':
|
|
2525 s = append(s, '\\')
|
|
2526 case 'N': // NEL (#x85)
|
|
2527 s = append(s, '\xC2')
|
|
2528 s = append(s, '\x85')
|
|
2529 case '_': // #xA0
|
|
2530 s = append(s, '\xC2')
|
|
2531 s = append(s, '\xA0')
|
|
2532 case 'L': // LS (#x2028)
|
|
2533 s = append(s, '\xE2')
|
|
2534 s = append(s, '\x80')
|
|
2535 s = append(s, '\xA8')
|
|
2536 case 'P': // PS (#x2029)
|
|
2537 s = append(s, '\xE2')
|
|
2538 s = append(s, '\x80')
|
|
2539 s = append(s, '\xA9')
|
|
2540 case 'x':
|
|
2541 code_length = 2
|
|
2542 case 'u':
|
|
2543 code_length = 4
|
|
2544 case 'U':
|
|
2545 code_length = 8
|
|
2546 default:
|
|
2547 yaml_parser_set_scanner_error(parser, "while parsing a quoted scalar",
|
|
2548 start_mark, "found unknown escape character")
|
|
2549 return false
|
|
2550 }
|
|
2551
|
|
2552 skip(parser)
|
|
2553 skip(parser)
|
|
2554
|
|
2555 // Consume an arbitrary escape code.
|
|
2556 if code_length > 0 {
|
|
2557 var value int
|
|
2558
|
|
2559 // Scan the character value.
|
|
2560 if parser.unread < code_length && !yaml_parser_update_buffer(parser, code_length) {
|
|
2561 return false
|
|
2562 }
|
|
2563 for k := 0; k < code_length; k++ {
|
|
2564 if !is_hex(parser.buffer, parser.buffer_pos+k) {
|
|
2565 yaml_parser_set_scanner_error(parser, "while parsing a quoted scalar",
|
|
2566 start_mark, "did not find expected hexdecimal number")
|
|
2567 return false
|
|
2568 }
|
|
2569 value = (value << 4) + as_hex(parser.buffer, parser.buffer_pos+k)
|
|
2570 }
|
|
2571
|
|
2572 // Check the value and write the character.
|
|
2573 if (value >= 0xD800 && value <= 0xDFFF) || value > 0x10FFFF {
|
|
2574 yaml_parser_set_scanner_error(parser, "while parsing a quoted scalar",
|
|
2575 start_mark, "found invalid Unicode character escape code")
|
|
2576 return false
|
|
2577 }
|
|
2578 if value <= 0x7F {
|
|
2579 s = append(s, byte(value))
|
|
2580 } else if value <= 0x7FF {
|
|
2581 s = append(s, byte(0xC0+(value>>6)))
|
|
2582 s = append(s, byte(0x80+(value&0x3F)))
|
|
2583 } else if value <= 0xFFFF {
|
|
2584 s = append(s, byte(0xE0+(value>>12)))
|
|
2585 s = append(s, byte(0x80+((value>>6)&0x3F)))
|
|
2586 s = append(s, byte(0x80+(value&0x3F)))
|
|
2587 } else {
|
|
2588 s = append(s, byte(0xF0+(value>>18)))
|
|
2589 s = append(s, byte(0x80+((value>>12)&0x3F)))
|
|
2590 s = append(s, byte(0x80+((value>>6)&0x3F)))
|
|
2591 s = append(s, byte(0x80+(value&0x3F)))
|
|
2592 }
|
|
2593
|
|
2594 // Advance the pointer.
|
|
2595 for k := 0; k < code_length; k++ {
|
|
2596 skip(parser)
|
|
2597 }
|
|
2598 }
|
|
2599 } else {
|
|
2600 // It is a non-escaped non-blank character.
|
|
2601 s = read(parser, s)
|
|
2602 }
|
|
2603 if parser.unread < 2 && !yaml_parser_update_buffer(parser, 2) {
|
|
2604 return false
|
|
2605 }
|
|
2606 }
|
|
2607
|
|
2608 if parser.unread < 1 && !yaml_parser_update_buffer(parser, 1) {
|
|
2609 return false
|
|
2610 }
|
|
2611
|
|
2612 // Check if we are at the end of the scalar.
|
|
2613 if single {
|
|
2614 if parser.buffer[parser.buffer_pos] == '\'' {
|
|
2615 break
|
|
2616 }
|
|
2617 } else {
|
|
2618 if parser.buffer[parser.buffer_pos] == '"' {
|
|
2619 break
|
|
2620 }
|
|
2621 }
|
|
2622
|
|
2623 // Consume blank characters.
|
|
2624 for is_blank(parser.buffer, parser.buffer_pos) || is_break(parser.buffer, parser.buffer_pos) {
|
|
2625 if is_blank(parser.buffer, parser.buffer_pos) {
|
|
2626 // Consume a space or a tab character.
|
|
2627 if !leading_blanks {
|
|
2628 whitespaces = read(parser, whitespaces)
|
|
2629 } else {
|
|
2630 skip(parser)
|
|
2631 }
|
|
2632 } else {
|
|
2633 if parser.unread < 2 && !yaml_parser_update_buffer(parser, 2) {
|
|
2634 return false
|
|
2635 }
|
|
2636
|
|
2637 // Check if it is a first line break.
|
|
2638 if !leading_blanks {
|
|
2639 whitespaces = whitespaces[:0]
|
|
2640 leading_break = read_line(parser, leading_break)
|
|
2641 leading_blanks = true
|
|
2642 } else {
|
|
2643 trailing_breaks = read_line(parser, trailing_breaks)
|
|
2644 }
|
|
2645 }
|
|
2646 if parser.unread < 1 && !yaml_parser_update_buffer(parser, 1) {
|
|
2647 return false
|
|
2648 }
|
|
2649 }
|
|
2650
|
|
2651 // Join the whitespaces or fold line breaks.
|
|
2652 if leading_blanks {
|
|
2653 // Do we need to fold line breaks?
|
|
2654 if len(leading_break) > 0 && leading_break[0] == '\n' {
|
|
2655 if len(trailing_breaks) == 0 {
|
|
2656 s = append(s, ' ')
|
|
2657 } else {
|
|
2658 s = append(s, trailing_breaks...)
|
|
2659 }
|
|
2660 } else {
|
|
2661 s = append(s, leading_break...)
|
|
2662 s = append(s, trailing_breaks...)
|
|
2663 }
|
|
2664 trailing_breaks = trailing_breaks[:0]
|
|
2665 leading_break = leading_break[:0]
|
|
2666 } else {
|
|
2667 s = append(s, whitespaces...)
|
|
2668 whitespaces = whitespaces[:0]
|
|
2669 }
|
|
2670 }
|
|
2671
|
|
2672 // Eat the right quote.
|
|
2673 skip(parser)
|
|
2674 end_mark := parser.mark
|
|
2675
|
|
2676 // Create a token.
|
|
2677 *token = yaml_token_t{
|
|
2678 typ: yaml_SCALAR_TOKEN,
|
|
2679 start_mark: start_mark,
|
|
2680 end_mark: end_mark,
|
|
2681 value: s,
|
|
2682 style: yaml_SINGLE_QUOTED_SCALAR_STYLE,
|
|
2683 }
|
|
2684 if !single {
|
|
2685 token.style = yaml_DOUBLE_QUOTED_SCALAR_STYLE
|
|
2686 }
|
|
2687 return true
|
|
2688 }
|
|
2689
|
|
2690 // Scan a plain scalar.
|
|
2691 func yaml_parser_scan_plain_scalar(parser *yaml_parser_t, token *yaml_token_t) bool {
|
|
2692
|
|
2693 var s, leading_break, trailing_breaks, whitespaces []byte
|
|
2694 var leading_blanks bool
|
|
2695 var indent = parser.indent + 1
|
|
2696
|
|
2697 start_mark := parser.mark
|
|
2698 end_mark := parser.mark
|
|
2699
|
|
2700 // Consume the content of the plain scalar.
|
|
2701 for {
|
|
2702 // Check for a document indicator.
|
|
2703 if parser.unread < 4 && !yaml_parser_update_buffer(parser, 4) {
|
|
2704 return false
|
|
2705 }
|
|
2706 if parser.mark.column == 0 &&
|
|
2707 ((parser.buffer[parser.buffer_pos+0] == '-' &&
|
|
2708 parser.buffer[parser.buffer_pos+1] == '-' &&
|
|
2709 parser.buffer[parser.buffer_pos+2] == '-') ||
|
|
2710 (parser.buffer[parser.buffer_pos+0] == '.' &&
|
|
2711 parser.buffer[parser.buffer_pos+1] == '.' &&
|
|
2712 parser.buffer[parser.buffer_pos+2] == '.')) &&
|
|
2713 is_blankz(parser.buffer, parser.buffer_pos+3) {
|
|
2714 break
|
|
2715 }
|
|
2716
|
|
2717 // Check for a comment.
|
|
2718 if parser.buffer[parser.buffer_pos] == '#' {
|
|
2719 break
|
|
2720 }
|
|
2721
|
|
2722 // Consume non-blank characters.
|
|
2723 for !is_blankz(parser.buffer, parser.buffer_pos) {
|
|
2724
|
|
2725 // Check for indicators that may end a plain scalar.
|
|
2726 if (parser.buffer[parser.buffer_pos] == ':' && is_blankz(parser.buffer, parser.buffer_pos+1)) ||
|
|
2727 (parser.flow_level > 0 &&
|
|
2728 (parser.buffer[parser.buffer_pos] == ',' ||
|
|
2729 parser.buffer[parser.buffer_pos] == '?' || parser.buffer[parser.buffer_pos] == '[' ||
|
|
2730 parser.buffer[parser.buffer_pos] == ']' || parser.buffer[parser.buffer_pos] == '{' ||
|
|
2731 parser.buffer[parser.buffer_pos] == '}')) {
|
|
2732 break
|
|
2733 }
|
|
2734
|
|
2735 // Check if we need to join whitespaces and breaks.
|
|
2736 if leading_blanks || len(whitespaces) > 0 {
|
|
2737 if leading_blanks {
|
|
2738 // Do we need to fold line breaks?
|
|
2739 if leading_break[0] == '\n' {
|
|
2740 if len(trailing_breaks) == 0 {
|
|
2741 s = append(s, ' ')
|
|
2742 } else {
|
|
2743 s = append(s, trailing_breaks...)
|
|
2744 }
|
|
2745 } else {
|
|
2746 s = append(s, leading_break...)
|
|
2747 s = append(s, trailing_breaks...)
|
|
2748 }
|
|
2749 trailing_breaks = trailing_breaks[:0]
|
|
2750 leading_break = leading_break[:0]
|
|
2751 leading_blanks = false
|
|
2752 } else {
|
|
2753 s = append(s, whitespaces...)
|
|
2754 whitespaces = whitespaces[:0]
|
|
2755 }
|
|
2756 }
|
|
2757
|
|
2758 // Copy the character.
|
|
2759 s = read(parser, s)
|
|
2760
|
|
2761 end_mark = parser.mark
|
|
2762 if parser.unread < 2 && !yaml_parser_update_buffer(parser, 2) {
|
|
2763 return false
|
|
2764 }
|
|
2765 }
|
|
2766
|
|
2767 // Is it the end?
|
|
2768 if !(is_blank(parser.buffer, parser.buffer_pos) || is_break(parser.buffer, parser.buffer_pos)) {
|
|
2769 break
|
|
2770 }
|
|
2771
|
|
2772 // Consume blank characters.
|
|
2773 if parser.unread < 1 && !yaml_parser_update_buffer(parser, 1) {
|
|
2774 return false
|
|
2775 }
|
|
2776
|
|
2777 for is_blank(parser.buffer, parser.buffer_pos) || is_break(parser.buffer, parser.buffer_pos) {
|
|
2778 if is_blank(parser.buffer, parser.buffer_pos) {
|
|
2779
|
|
2780 // Check for tab characters that abuse indentation.
|
|
2781 if leading_blanks && parser.mark.column < indent && is_tab(parser.buffer, parser.buffer_pos) {
|
|
2782 yaml_parser_set_scanner_error(parser, "while scanning a plain scalar",
|
|
2783 start_mark, "found a tab character that violates indentation")
|
|
2784 return false
|
|
2785 }
|
|
2786
|
|
2787 // Consume a space or a tab character.
|
|
2788 if !leading_blanks {
|
|
2789 whitespaces = read(parser, whitespaces)
|
|
2790 } else {
|
|
2791 skip(parser)
|
|
2792 }
|
|
2793 } else {
|
|
2794 if parser.unread < 2 && !yaml_parser_update_buffer(parser, 2) {
|
|
2795 return false
|
|
2796 }
|
|
2797
|
|
2798 // Check if it is a first line break.
|
|
2799 if !leading_blanks {
|
|
2800 whitespaces = whitespaces[:0]
|
|
2801 leading_break = read_line(parser, leading_break)
|
|
2802 leading_blanks = true
|
|
2803 } else {
|
|
2804 trailing_breaks = read_line(parser, trailing_breaks)
|
|
2805 }
|
|
2806 }
|
|
2807 if parser.unread < 1 && !yaml_parser_update_buffer(parser, 1) {
|
|
2808 return false
|
|
2809 }
|
|
2810 }
|
|
2811
|
|
2812 // Check indentation level.
|
|
2813 if parser.flow_level == 0 && parser.mark.column < indent {
|
|
2814 break
|
|
2815 }
|
|
2816 }
|
|
2817
|
|
2818 // Create a token.
|
|
2819 *token = yaml_token_t{
|
|
2820 typ: yaml_SCALAR_TOKEN,
|
|
2821 start_mark: start_mark,
|
|
2822 end_mark: end_mark,
|
|
2823 value: s,
|
|
2824 style: yaml_PLAIN_SCALAR_STYLE,
|
|
2825 }
|
|
2826
|
|
2827 // Note that we change the 'simple_key_allowed' flag.
|
|
2828 if leading_blanks {
|
|
2829 parser.simple_key_allowed = true
|
|
2830 }
|
|
2831 return true
|
|
2832 }
|
|
2833
|
|
2834 func yaml_parser_scan_line_comment(parser *yaml_parser_t, token_mark yaml_mark_t) bool {
|
|
2835 if parser.newlines > 0 {
|
|
2836 return true
|
|
2837 }
|
|
2838
|
|
2839 var start_mark yaml_mark_t
|
|
2840 var text []byte
|
|
2841
|
|
2842 for peek := 0; peek < 512; peek++ {
|
|
2843 if parser.unread < peek+1 && !yaml_parser_update_buffer(parser, peek+1) {
|
|
2844 break
|
|
2845 }
|
|
2846 if is_blank(parser.buffer, parser.buffer_pos+peek) {
|
|
2847 continue
|
|
2848 }
|
|
2849 if parser.buffer[parser.buffer_pos+peek] == '#' {
|
|
2850 seen := parser.mark.index+peek
|
|
2851 for {
|
|
2852 if parser.unread < 1 && !yaml_parser_update_buffer(parser, 1) {
|
|
2853 return false
|
|
2854 }
|
|
2855 if is_breakz(parser.buffer, parser.buffer_pos) {
|
|
2856 if parser.mark.index >= seen {
|
|
2857 break
|
|
2858 }
|
|
2859 if parser.unread < 2 && !yaml_parser_update_buffer(parser, 2) {
|
|
2860 return false
|
|
2861 }
|
|
2862 skip_line(parser)
|
|
2863 } else if parser.mark.index >= seen {
|
|
2864 if len(text) == 0 {
|
|
2865 start_mark = parser.mark
|
|
2866 }
|
|
2867 text = read(parser, text)
|
|
2868 } else {
|
|
2869 skip(parser)
|
|
2870 }
|
|
2871 }
|
|
2872 }
|
|
2873 break
|
|
2874 }
|
|
2875 if len(text) > 0 {
|
|
2876 parser.comments = append(parser.comments, yaml_comment_t{
|
|
2877 token_mark: token_mark,
|
|
2878 start_mark: start_mark,
|
|
2879 line: text,
|
|
2880 })
|
|
2881 }
|
|
2882 return true
|
|
2883 }
|
|
2884
|
|
2885 func yaml_parser_scan_comments(parser *yaml_parser_t, scan_mark yaml_mark_t) bool {
|
|
2886 token := parser.tokens[len(parser.tokens)-1]
|
|
2887
|
|
2888 if token.typ == yaml_FLOW_ENTRY_TOKEN && len(parser.tokens) > 1 {
|
|
2889 token = parser.tokens[len(parser.tokens)-2]
|
|
2890 }
|
|
2891
|
|
2892 var token_mark = token.start_mark
|
|
2893 var start_mark yaml_mark_t
|
|
2894 var next_indent = parser.indent
|
|
2895 if next_indent < 0 {
|
|
2896 next_indent = 0
|
|
2897 }
|
|
2898
|
|
2899 var recent_empty = false
|
|
2900 var first_empty = parser.newlines <= 1
|
|
2901
|
|
2902 var line = parser.mark.line
|
|
2903 var column = parser.mark.column
|
|
2904
|
|
2905 var text []byte
|
|
2906
|
|
2907 // The foot line is the place where a comment must start to
|
|
2908 // still be considered as a foot of the prior content.
|
|
2909 // If there's some content in the currently parsed line, then
|
|
2910 // the foot is the line below it.
|
|
2911 var foot_line = -1
|
|
2912 if scan_mark.line > 0 {
|
|
2913 foot_line = parser.mark.line-parser.newlines+1
|
|
2914 if parser.newlines == 0 && parser.mark.column > 1 {
|
|
2915 foot_line++
|
|
2916 }
|
|
2917 }
|
|
2918
|
|
2919 var peek = 0
|
|
2920 for ; peek < 512; peek++ {
|
|
2921 if parser.unread < peek+1 && !yaml_parser_update_buffer(parser, peek+1) {
|
|
2922 break
|
|
2923 }
|
|
2924 column++
|
|
2925 if is_blank(parser.buffer, parser.buffer_pos+peek) {
|
|
2926 continue
|
|
2927 }
|
|
2928 c := parser.buffer[parser.buffer_pos+peek]
|
|
2929 var close_flow = parser.flow_level > 0 && (c == ']' || c == '}')
|
|
2930 if close_flow || is_breakz(parser.buffer, parser.buffer_pos+peek) {
|
|
2931 // Got line break or terminator.
|
|
2932 if close_flow || !recent_empty {
|
|
2933 if close_flow || first_empty && (start_mark.line == foot_line && token.typ != yaml_VALUE_TOKEN || start_mark.column-1 < next_indent) {
|
|
2934 // This is the first empty line and there were no empty lines before,
|
|
2935 // so this initial part of the comment is a foot of the prior token
|
|
2936 // instead of being a head for the following one. Split it up.
|
|
2937 // Alternatively, this might also be the last comment inside a flow
|
|
2938 // scope, so it must be a footer.
|
|
2939 if len(text) > 0 {
|
|
2940 if start_mark.column-1 < next_indent {
|
|
2941 // If dedented it's unrelated to the prior token.
|
|
2942 token_mark = start_mark
|
|
2943 }
|
|
2944 parser.comments = append(parser.comments, yaml_comment_t{
|
|
2945 scan_mark: scan_mark,
|
|
2946 token_mark: token_mark,
|
|
2947 start_mark: start_mark,
|
|
2948 end_mark: yaml_mark_t{parser.mark.index + peek, line, column},
|
|
2949 foot: text,
|
|
2950 })
|
|
2951 scan_mark = yaml_mark_t{parser.mark.index + peek, line, column}
|
|
2952 token_mark = scan_mark
|
|
2953 text = nil
|
|
2954 }
|
|
2955 } else {
|
|
2956 if len(text) > 0 && parser.buffer[parser.buffer_pos+peek] != 0 {
|
|
2957 text = append(text, '\n')
|
|
2958 }
|
|
2959 }
|
|
2960 }
|
|
2961 if !is_break(parser.buffer, parser.buffer_pos+peek) {
|
|
2962 break
|
|
2963 }
|
|
2964 first_empty = false
|
|
2965 recent_empty = true
|
|
2966 column = 0
|
|
2967 line++
|
|
2968 continue
|
|
2969 }
|
|
2970
|
|
2971 if len(text) > 0 && (close_flow || column-1 < next_indent && column != start_mark.column) {
|
|
2972 // The comment at the different indentation is a foot of the
|
|
2973 // preceding data rather than a head of the upcoming one.
|
|
2974 parser.comments = append(parser.comments, yaml_comment_t{
|
|
2975 scan_mark: scan_mark,
|
|
2976 token_mark: token_mark,
|
|
2977 start_mark: start_mark,
|
|
2978 end_mark: yaml_mark_t{parser.mark.index + peek, line, column},
|
|
2979 foot: text,
|
|
2980 })
|
|
2981 scan_mark = yaml_mark_t{parser.mark.index + peek, line, column}
|
|
2982 token_mark = scan_mark
|
|
2983 text = nil
|
|
2984 }
|
|
2985
|
|
2986 if parser.buffer[parser.buffer_pos+peek] != '#' {
|
|
2987 break
|
|
2988 }
|
|
2989
|
|
2990 if len(text) == 0 {
|
|
2991 start_mark = yaml_mark_t{parser.mark.index + peek, line, column}
|
|
2992 } else {
|
|
2993 text = append(text, '\n')
|
|
2994 }
|
|
2995
|
|
2996 recent_empty = false
|
|
2997
|
|
2998 // Consume until after the consumed comment line.
|
|
2999 seen := parser.mark.index+peek
|
|
3000 for {
|
|
3001 if parser.unread < 1 && !yaml_parser_update_buffer(parser, 1) {
|
|
3002 return false
|
|
3003 }
|
|
3004 if is_breakz(parser.buffer, parser.buffer_pos) {
|
|
3005 if parser.mark.index >= seen {
|
|
3006 break
|
|
3007 }
|
|
3008 if parser.unread < 2 && !yaml_parser_update_buffer(parser, 2) {
|
|
3009 return false
|
|
3010 }
|
|
3011 skip_line(parser)
|
|
3012 } else if parser.mark.index >= seen {
|
|
3013 text = read(parser, text)
|
|
3014 } else {
|
|
3015 skip(parser)
|
|
3016 }
|
|
3017 }
|
|
3018
|
|
3019 peek = 0
|
|
3020 column = 0
|
|
3021 line = parser.mark.line
|
|
3022 next_indent = parser.indent
|
|
3023 if next_indent < 0 {
|
|
3024 next_indent = 0
|
|
3025 }
|
|
3026 }
|
|
3027
|
|
3028 if len(text) > 0 {
|
|
3029 parser.comments = append(parser.comments, yaml_comment_t{
|
|
3030 scan_mark: scan_mark,
|
|
3031 token_mark: start_mark,
|
|
3032 start_mark: start_mark,
|
|
3033 end_mark: yaml_mark_t{parser.mark.index + peek - 1, line, column},
|
|
3034 head: text,
|
|
3035 })
|
|
3036 }
|
|
3037 return true
|
|
3038 }
|