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