scannerc.go

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