scannerc.go raw

   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  }
3039