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