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