gitee.com/sy_183/go-common@v1.0.5-0.20231205030221-958cfe129b47/yaml/scannerc.go (about)

     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  }