Decoding side builds.
diff --git a/api_c.go b/api_c.go
new file mode 100644
index 0000000..5d7a0f0
--- /dev/null
+++ b/api_c.go
@@ -0,0 +1,1164 @@
+package goyaml
+
+import (
+ "io"
+ "os"
+)
+
+///*
+// * Extend a string.
+// */
+//
+//YAML_DECLARE(int)
+//yaml_string_extend(yaml_char_t **start,
+// yaml_char_t **pointer, yaml_char_t **end)
+//{
+// yaml_char_t *new_start = yaml_realloc(*start, (*end - *start)*2);
+//
+// if (!new_start) return 0;
+//
+// memset(new_start + (*end - *start), 0, *end - *start);
+//
+// *pointer = new_start + (*pointer - *start);
+// *end = new_start + (*end - *start)*2;
+// *start = new_start;
+//
+// return 1;
+//}
+//
+///*
+// * Append a string B to a string A.
+// */
+//
+//YAML_DECLARE(int)
+//yaml_string_join(
+// yaml_char_t **a_start, yaml_char_t **a_pointer, yaml_char_t **a_end,
+// yaml_char_t **b_start, yaml_char_t **b_pointer, yaml_char_t **b_end)
+//{
+// if (*b_start == *b_pointer)
+// return 1;
+//
+// while (*a_end - *a_pointer <= *b_pointer - *b_start) {
+// if (!yaml_string_extend(a_start, a_pointer, a_end))
+// return 0;
+// }
+//
+// memcpy(*a_pointer, *b_start, *b_pointer - *b_start);
+// *a_pointer += *b_pointer - *b_start;
+//
+// return 1;
+//}
+//
+///*
+// * Extend a stack.
+// */
+//
+//YAML_DECLARE(int)
+//yaml_stack_extend(void **start, void **top, void **end)
+//{
+// void *new_start = yaml_realloc(*start, ((char *)*end - (char *)*start)*2);
+//
+// if (!new_start) return 0;
+//
+// *top = (char *)new_start + ((char *)*top - (char *)*start);
+// *end = (char *)new_start + ((char *)*end - (char *)*start)*2;
+// *start = new_start;
+//
+// return 1;
+//}
+
+func yaml_insert_token(parser *yaml_parser_t, pos int, token *yaml_token_t) {
+ // Check if we can move the queue at the beginning of the buffer.
+ if parser.tokens_head > 0 && len(parser.tokens) == cap(parser.tokens) {
+ if parser.tokens_head != len(parser.tokens) {
+ copy(parser.tokens, parser.tokens[parser.tokens_head:])
+ }
+ parser.tokens = parser.tokens[:len(parser.tokens)-parser.tokens_head]
+ parser.tokens_head = 0
+ }
+ parser.tokens = append(parser.tokens, yaml_token_t{})
+ if pos < 0 {
+ return
+ }
+ copy(parser.tokens[parser.tokens_head+pos+1:], parser.tokens[parser.tokens_head+pos:])
+ parser.tokens[pos] = *token
+}
+
+// Create a new parser object.
+func yaml_parser_initialize(parser *yaml_parser_t) bool {
+ // [Go] These should be initialized lazily, and probably start with smaller sizes.
+ parser.raw_buffer = make([]byte, 0, input_raw_buffer_size)
+ parser.buffer = make([]byte, 0, input_buffer_size)
+ parser.tokens = make([]yaml_token_t, 0, initial_queue_size)
+ parser.indents = make([]int, 0, initial_stack_size)
+ parser.simple_keys = make([]yaml_simple_key_t, 0, initial_stack_size)
+ parser.states = make([]yaml_parser_state_t, 0, initial_stack_size)
+ parser.marks = make([]yaml_mark_t, 0, initial_stack_size)
+ parser.tag_directives = make([]yaml_tag_directive_t, 0, initial_stack_size)
+ return true
+}
+
+// String read handler.
+func yaml_string_read_handler(parser *yaml_parser_t, buffer []byte) (n int, err error) {
+ if parser.input_pos == len(parser.input) {
+ return 0, io.EOF
+ }
+ n = copy(buffer, parser.input[parser.input_pos:])
+ parser.input_pos += n
+ return n, nil
+}
+
+// File read handler.
+func yaml_file_read_handler(parser *yaml_parser_t, buffer []byte) (n int, err error) {
+ return parser.input_file.Read(buffer)
+}
+
+// Set a string input.
+func yaml_parser_set_input_string(parser *yaml_parser_t, input []byte) {
+ if parser.read_handler != nil {
+ panic("must set the input source only once")
+ }
+ parser.read_handler = yaml_string_read_handler
+ parser.input = input
+ parser.input_pos = 0
+}
+
+// Set a file input.
+func yaml_parser_set_input_file(parser *yaml_parser_t, file *os.File) {
+ if parser.read_handler != nil {
+ panic("must set the input source only once")
+ }
+ parser.read_handler = yaml_file_read_handler
+ parser.input_file = file
+}
+
+///*
+// * Set the source encoding.
+// */
+//
+//YAML_DECLARE(void)
+//yaml_parser_set_encoding(yaml_parser_t *parser, yaml_encoding_t encoding)
+//{
+// assert(parser); // Non-NULL parser object expected.
+// assert(!parser.encoding); // Encoding is already set or detected.
+//
+// parser.encoding = encoding;
+//}
+//
+///*
+// * Create a new emitter object.
+// */
+//
+//YAML_DECLARE(int)
+//yaml_emitter_initialize(yaml_emitter_t *emitter)
+//{
+// assert(emitter); // Non-NULL emitter object expected.
+//
+// memset(emitter, 0, sizeof(yaml_emitter_t));
+// if (!BUFFER_INIT(emitter, emitter.buffer, OUTPUT_BUFFER_SIZE))
+// goto error;
+// if (!BUFFER_INIT(emitter, emitter.raw_buffer, OUTPUT_RAW_BUFFER_SIZE))
+// goto error;
+// if (!STACK_INIT(emitter, emitter.states, INITIAL_STACK_SIZE))
+// goto error;
+// if (!QUEUE_INIT(emitter, emitter.events, INITIAL_QUEUE_SIZE))
+// goto error;
+// if (!STACK_INIT(emitter, emitter.indents, INITIAL_STACK_SIZE))
+// goto error;
+// if (!STACK_INIT(emitter, emitter.tag_directives, INITIAL_STACK_SIZE))
+// goto error;
+//
+// return 1;
+//
+//error:
+//
+// BUFFER_DEL(emitter, emitter.buffer);
+// BUFFER_DEL(emitter, emitter.raw_buffer);
+// STACK_DEL(emitter, emitter.states);
+// QUEUE_DEL(emitter, emitter.events);
+// STACK_DEL(emitter, emitter.indents);
+// STACK_DEL(emitter, emitter.tag_directives);
+//
+// return 0;
+//}
+//
+///*
+// * Destroy an emitter object.
+// */
+//
+//YAML_DECLARE(void)
+//yaml_emitter_delete(yaml_emitter_t *emitter)
+//{
+// assert(emitter); // Non-NULL emitter object expected.
+//
+// BUFFER_DEL(emitter, emitter.buffer);
+// BUFFER_DEL(emitter, emitter.raw_buffer);
+// STACK_DEL(emitter, emitter.states);
+// while (!QUEUE_EMPTY(emitter, emitter.events)) {
+// yaml_event_delete(&DEQUEUE(emitter, emitter.events));
+// }
+// QUEUE_DEL(emitter, emitter.events);
+// STACK_DEL(emitter, emitter.indents);
+// while (!STACK_EMPTY(empty, emitter.tag_directives)) {
+// yaml_tag_directive_t tag_directive = POP(emitter, emitter.tag_directives);
+// yaml_free(tag_directive.handle);
+// yaml_free(tag_directive.prefix);
+// }
+// STACK_DEL(emitter, emitter.tag_directives);
+// yaml_free(emitter.anchors);
+//
+// memset(emitter, 0, sizeof(yaml_emitter_t));
+//}
+//
+///*
+// * String write handler.
+// */
+//
+//static int
+//yaml_string_write_handler(void *data, unsigned char *buffer, size_t size)
+//{
+// yaml_emitter_t *emitter = data;
+//
+// if (emitter.output.string.size + *emitter.output.string.size_written
+// < size) {
+// memcpy(emitter.output.string.buffer
+// + *emitter.output.string.size_written,
+// buffer,
+// emitter.output.string.size
+// - *emitter.output.string.size_written);
+// *emitter.output.string.size_written = emitter.output.string.size;
+// return 0;
+// }
+//
+// memcpy(emitter.output.string.buffer
+// + *emitter.output.string.size_written, buffer, size);
+// *emitter.output.string.size_written += size;
+// return 1;
+//}
+//
+///*
+// * File write handler.
+// */
+//
+//static int
+//yaml_file_write_handler(void *data, unsigned char *buffer, size_t size)
+//{
+// yaml_emitter_t *emitter = data;
+//
+// return (fwrite(buffer, 1, size, emitter.output.file) == size);
+//}
+///*
+// * Set a string output.
+// */
+//
+//YAML_DECLARE(void)
+//yaml_emitter_set_output_string(yaml_emitter_t *emitter,
+// unsigned char *output, size_t size, size_t *size_written)
+//{
+// assert(emitter); // Non-NULL emitter object expected.
+// assert(!emitter.write_handler); // You can set the output only once.
+// assert(output); // Non-NULL output string expected.
+//
+// emitter.write_handler = yaml_string_write_handler;
+// emitter.write_handler_data = emitter;
+//
+// emitter.output.string.buffer = output;
+// emitter.output.string.size = size;
+// emitter.output.string.size_written = size_written;
+// *size_written = 0;
+//}
+//
+///*
+// * Set a file output.
+// */
+//
+//YAML_DECLARE(void)
+//yaml_emitter_set_output_file(yaml_emitter_t *emitter, FILE *file)
+//{
+// assert(emitter); // Non-NULL emitter object expected.
+// assert(!emitter.write_handler); // You can set the output only once.
+// assert(file); // Non-NULL file object expected.
+//
+// emitter.write_handler = yaml_file_write_handler;
+// emitter.write_handler_data = emitter;
+//
+// emitter.output.file = file;
+//}
+//
+///*
+// * Set a generic output handler.
+// */
+//
+//YAML_DECLARE(void)
+//yaml_emitter_set_output(yaml_emitter_t *emitter,
+// yaml_write_handler_t *handler, void *data)
+//{
+// assert(emitter); // Non-NULL emitter object expected.
+// assert(!emitter.write_handler); // You can set the output only once.
+// assert(handler); // Non-NULL handler object expected.
+//
+// emitter.write_handler = handler;
+// emitter.write_handler_data = data;
+//}
+//
+///*
+// * Set the output encoding.
+// */
+//
+//YAML_DECLARE(void)
+//yaml_emitter_set_encoding(yaml_emitter_t *emitter, yaml_encoding_t encoding)
+//{
+// assert(emitter); // Non-NULL emitter object expected.
+// assert(!emitter.encoding); // You can set encoding only once.
+//
+// emitter.encoding = encoding;
+//}
+//
+///*
+// * Set the canonical output style.
+// */
+//
+//YAML_DECLARE(void)
+//yaml_emitter_set_canonical(yaml_emitter_t *emitter, int canonical)
+//{
+// assert(emitter); // Non-NULL emitter object expected.
+//
+// emitter.canonical = (canonical != 0);
+//}
+//
+///*
+// * Set the indentation increment.
+// */
+//
+//YAML_DECLARE(void)
+//yaml_emitter_set_indent(yaml_emitter_t *emitter, int indent)
+//{
+// assert(emitter); // Non-NULL emitter object expected.
+//
+// emitter.best_indent = (1 < indent && indent < 10) ? indent : 2;
+//}
+//
+///*
+// * Set the preferred line width.
+// */
+//
+//YAML_DECLARE(void)
+//yaml_emitter_set_width(yaml_emitter_t *emitter, int width)
+//{
+// assert(emitter); // Non-NULL emitter object expected.
+//
+// emitter.best_width = (width >= 0) ? width : -1;
+//}
+//
+///*
+// * Set if unescaped non-ASCII characters are allowed.
+// */
+//
+//YAML_DECLARE(void)
+//yaml_emitter_set_unicode(yaml_emitter_t *emitter, int unicode)
+//{
+// assert(emitter); // Non-NULL emitter object expected.
+//
+// emitter.unicode = (unicode != 0);
+//}
+//
+///*
+// * Set the preferred line break character.
+// */
+//
+//YAML_DECLARE(void)
+//yaml_emitter_set_break(yaml_emitter_t *emitter, yaml_break_t line_break)
+//{
+// assert(emitter); // Non-NULL emitter object expected.
+//
+// emitter.line_break = line_break;
+//}
+//
+///*
+// * Destroy a token object.
+// */
+//
+//YAML_DECLARE(void)
+//yaml_token_delete(yaml_token_t *token)
+//{
+// assert(token); // Non-NULL token object expected.
+//
+// switch (token.type)
+// {
+// case YAML_TAG_DIRECTIVE_TOKEN:
+// yaml_free(token.data.tag_directive.handle);
+// yaml_free(token.data.tag_directive.prefix);
+// break;
+//
+// case YAML_ALIAS_TOKEN:
+// yaml_free(token.data.alias.value);
+// break;
+//
+// case YAML_ANCHOR_TOKEN:
+// yaml_free(token.data.anchor.value);
+// break;
+//
+// case YAML_TAG_TOKEN:
+// yaml_free(token.data.tag.handle);
+// yaml_free(token.data.tag.suffix);
+// break;
+//
+// case YAML_SCALAR_TOKEN:
+// yaml_free(token.data.scalar.value);
+// break;
+//
+// default:
+// break;
+// }
+//
+// memset(token, 0, sizeof(yaml_token_t));
+//}
+//
+///*
+// * Check if a string is a valid UTF-8 sequence.
+// *
+// * Check 'reader.c' for more details on UTF-8 encoding.
+// */
+//
+//static int
+//yaml_check_utf8(yaml_char_t *start, size_t length)
+//{
+// yaml_char_t *end = start+length;
+// yaml_char_t *pointer = start;
+//
+// while (pointer < end) {
+// unsigned char octet;
+// unsigned int width;
+// unsigned int value;
+// size_t k;
+//
+// octet = pointer[0];
+// width = (octet & 0x80) == 0x00 ? 1 :
+// (octet & 0xE0) == 0xC0 ? 2 :
+// (octet & 0xF0) == 0xE0 ? 3 :
+// (octet & 0xF8) == 0xF0 ? 4 : 0;
+// value = (octet & 0x80) == 0x00 ? octet & 0x7F :
+// (octet & 0xE0) == 0xC0 ? octet & 0x1F :
+// (octet & 0xF0) == 0xE0 ? octet & 0x0F :
+// (octet & 0xF8) == 0xF0 ? octet & 0x07 : 0;
+// if (!width) return 0;
+// if (pointer+width > end) return 0;
+// for (k = 1; k < width; k ++) {
+// octet = pointer[k];
+// if ((octet & 0xC0) != 0x80) return 0;
+// value = (value << 6) + (octet & 0x3F);
+// }
+// if (!((width == 1) ||
+// (width == 2 && value >= 0x80) ||
+// (width == 3 && value >= 0x800) ||
+// (width == 4 && value >= 0x10000))) return 0;
+//
+// pointer += width;
+// }
+//
+// return 1;
+//}
+//
+///*
+// * Create STREAM-START.
+// */
+//
+//YAML_DECLARE(int)
+//yaml_stream_start_event_initialize(yaml_event_t *event,
+// yaml_encoding_t encoding)
+//{
+// yaml_mark_t mark = { 0, 0, 0 };
+//
+// assert(event); // Non-NULL event object is expected.
+//
+// STREAM_START_EVENT_INIT(*event, encoding, mark, mark);
+ //*event = yaml_event_t{
+ // typ: yaml_STREAM_START_EVENT,
+ // start_mark: mark,
+ // end_mark: mark,
+ //}
+ //event.stream_start.encoding = encoding
+//
+// return 1;
+//}
+//
+///*
+// * Create STREAM-END.
+// */
+//
+//YAML_DECLARE(int)
+//yaml_stream_end_event_initialize(yaml_event_t *event)
+//{
+// yaml_mark_t mark = { 0, 0, 0 };
+//
+// assert(event); // Non-NULL event object is expected.
+//
+// STREAM_END_EVENT_INIT(*event, mark, mark);
+ //*event = yaml_event_t{
+ // typ: yaml_STREAM_END_EVENT,
+ // start_mark: mark,
+ // end_mark: mark,
+ //}
+//
+// return 1;
+//}
+//
+///*
+// * Create DOCUMENT-START.
+// */
+//
+//YAML_DECLARE(int)
+//yaml_document_start_event_initialize(yaml_event_t *event,
+// yaml_version_directive_t *version_directive,
+// yaml_tag_directive_t *tag_directives_start,
+// yaml_tag_directive_t *tag_directives_end,
+// int implicit)
+//{
+// struct {
+// yaml_error_type_t error;
+// } context;
+// yaml_mark_t mark = { 0, 0, 0 };
+// yaml_version_directive_t *version_directive_copy = NULL;
+// struct {
+// yaml_tag_directive_t *start;
+// yaml_tag_directive_t *end;
+// yaml_tag_directive_t *top;
+// } tag_directives_copy = { NULL, NULL, NULL };
+// yaml_tag_directive_t value = { NULL, NULL };
+//
+// assert(event); // Non-NULL event object is expected.
+// assert((tag_directives_start && tag_directives_end) ||
+// (tag_directives_start == tag_directives_end));
+// // Valid tag directives are expected.
+//
+// if (version_directive) {
+// version_directive_copy = yaml_malloc(sizeof(yaml_version_directive_t));
+// if (!version_directive_copy) goto error;
+// version_directive_copy.major = version_directive.major;
+// version_directive_copy.minor = version_directive.minor;
+// }
+//
+// if (tag_directives_start != tag_directives_end) {
+// yaml_tag_directive_t *tag_directive;
+// if (!STACK_INIT(&context, tag_directives_copy, INITIAL_STACK_SIZE))
+// goto error;
+// for (tag_directive = tag_directives_start;
+// tag_directive != tag_directives_end; tag_directive ++) {
+// assert(tag_directive.handle);
+// assert(tag_directive.prefix);
+// if (!yaml_check_utf8(tag_directive.handle,
+// strlen((char *)tag_directive.handle)))
+// goto error;
+// if (!yaml_check_utf8(tag_directive.prefix,
+// strlen((char *)tag_directive.prefix)))
+// goto error;
+// value.handle = yaml_strdup(tag_directive.handle);
+// value.prefix = yaml_strdup(tag_directive.prefix);
+// if (!value.handle || !value.prefix) goto error;
+// if (!PUSH(&context, tag_directives_copy, value))
+// goto error;
+// value.handle = NULL;
+// value.prefix = NULL;
+// }
+// }
+//
+// DOCUMENT_START_EVENT_INIT(*event, version_directive_copy,
+// tag_directives_copy.start, tag_directives_copy.top,
+// implicit, mark, mark);
+ //*event = yaml_event_t{
+ // typ: yaml_DOCUMENT_START_EVENT,
+ // start_mark: mark,
+ // end_mark: mark,
+ //}
+ //event.document_start.version_directive = version_directive_copy
+ //event.document_start.tag_directives = tag_directives
+ //event.document_start.implicit = implicit
+//
+// return 1;
+//
+//error:
+// yaml_free(version_directive_copy);
+// while (!STACK_EMPTY(context, tag_directives_copy)) {
+// yaml_tag_directive_t value = POP(context, tag_directives_copy);
+// yaml_free(value.handle);
+// yaml_free(value.prefix);
+// }
+// STACK_DEL(context, tag_directives_copy);
+// yaml_free(value.handle);
+// yaml_free(value.prefix);
+//
+// return 0;
+//}
+//
+///*
+// * Create DOCUMENT-END.
+// */
+//
+//YAML_DECLARE(int)
+//yaml_document_end_event_initialize(yaml_event_t *event, int implicit)
+//{
+// yaml_mark_t mark = { 0, 0, 0 };
+//
+// assert(event); // Non-NULL emitter object is expected.
+//
+// DOCUMENT_END_EVENT_INIT(*event, implicit, mark, mark);
+//
+// return 1;
+//}
+//
+///*
+// * Create ALIAS.
+// */
+//
+//YAML_DECLARE(int)
+//yaml_alias_event_initialize(yaml_event_t *event, yaml_char_t *anchor)
+//{
+// yaml_mark_t mark = { 0, 0, 0 };
+// yaml_char_t *anchor_copy = NULL;
+//
+// assert(event); // Non-NULL event object is expected.
+// assert(anchor); // Non-NULL anchor is expected.
+//
+// if (!yaml_check_utf8(anchor, strlen((char *)anchor))) return 0;
+//
+// anchor_copy = yaml_strdup(anchor);
+// if (!anchor_copy)
+// return 0;
+//
+// ALIAS_EVENT_INIT(*event, anchor_copy, mark, mark);
+//
+// return 1;
+//}
+//
+///*
+// * Create SCALAR.
+// */
+//
+//YAML_DECLARE(int)
+//yaml_scalar_event_initialize(yaml_event_t *event,
+// yaml_char_t *anchor, yaml_char_t *tag,
+// yaml_char_t *value, int length,
+// int plain_implicit, int quoted_implicit,
+// yaml_scalar_style_t style)
+//{
+// yaml_mark_t mark = { 0, 0, 0 };
+// yaml_char_t *anchor_copy = NULL;
+// yaml_char_t *tag_copy = NULL;
+// yaml_char_t *value_copy = NULL;
+//
+// assert(event); // Non-NULL event object is expected.
+// assert(value); // Non-NULL anchor is expected.
+//
+// if (anchor) {
+// if (!yaml_check_utf8(anchor, strlen((char *)anchor))) goto error;
+// anchor_copy = yaml_strdup(anchor);
+// if (!anchor_copy) goto error;
+// }
+//
+// if (tag) {
+// if (!yaml_check_utf8(tag, strlen((char *)tag))) goto error;
+// tag_copy = yaml_strdup(tag);
+// if (!tag_copy) goto error;
+// }
+//
+// if (length < 0) {
+// length = strlen((char *)value);
+// }
+//
+// if (!yaml_check_utf8(value, length)) goto error;
+// value_copy = yaml_malloc(length+1);
+// if (!value_copy) goto error;
+// memcpy(value_copy, value, length);
+// value_copy[length] = '\0';
+//
+// SCALAR_EVENT_INIT(*event, anchor_copy, tag_copy, value_copy, length,
+// plain_implicit, quoted_implicit, style, mark, mark);
+//
+// return 1;
+//
+//error:
+// yaml_free(anchor_copy);
+// yaml_free(tag_copy);
+// yaml_free(value_copy);
+//
+// return 0;
+//}
+//
+///*
+// * Create SEQUENCE-START.
+// */
+//
+//YAML_DECLARE(int)
+//yaml_sequence_start_event_initialize(yaml_event_t *event,
+// yaml_char_t *anchor, yaml_char_t *tag, int implicit,
+// yaml_sequence_style_t style)
+//{
+// yaml_mark_t mark = { 0, 0, 0 };
+// yaml_char_t *anchor_copy = NULL;
+// yaml_char_t *tag_copy = NULL;
+//
+// assert(event); // Non-NULL event object is expected.
+//
+// if (anchor) {
+// if (!yaml_check_utf8(anchor, strlen((char *)anchor))) goto error;
+// anchor_copy = yaml_strdup(anchor);
+// if (!anchor_copy) goto error;
+// }
+//
+// if (tag) {
+// if (!yaml_check_utf8(tag, strlen((char *)tag))) goto error;
+// tag_copy = yaml_strdup(tag);
+// if (!tag_copy) goto error;
+// }
+//
+// SEQUENCE_START_EVENT_INIT(*event, anchor_copy, tag_copy,
+// implicit, style, mark, mark);
+//
+// return 1;
+//
+//error:
+// yaml_free(anchor_copy);
+// yaml_free(tag_copy);
+//
+// return 0;
+//}
+//
+///*
+// * Create SEQUENCE-END.
+// */
+//
+//YAML_DECLARE(int)
+//yaml_sequence_end_event_initialize(yaml_event_t *event)
+//{
+// yaml_mark_t mark = { 0, 0, 0 };
+//
+// assert(event); // Non-NULL event object is expected.
+//
+// SEQUENCE_END_EVENT_INIT(*event, mark, mark);
+//
+// return 1;
+//}
+//
+///*
+// * Create MAPPING-START.
+// */
+//
+//YAML_DECLARE(int)
+//yaml_mapping_start_event_initialize(yaml_event_t *event,
+// yaml_char_t *anchor, yaml_char_t *tag, int implicit,
+// yaml_mapping_style_t style)
+//{
+// yaml_mark_t mark = { 0, 0, 0 };
+// yaml_char_t *anchor_copy = NULL;
+// yaml_char_t *tag_copy = NULL;
+//
+// assert(event); // Non-NULL event object is expected.
+//
+// if (anchor) {
+// if (!yaml_check_utf8(anchor, strlen((char *)anchor))) goto error;
+// anchor_copy = yaml_strdup(anchor);
+// if (!anchor_copy) goto error;
+// }
+//
+// if (tag) {
+// if (!yaml_check_utf8(tag, strlen((char *)tag))) goto error;
+// tag_copy = yaml_strdup(tag);
+// if (!tag_copy) goto error;
+// }
+//
+// MAPPING_START_EVENT_INIT(*event, anchor_copy, tag_copy,
+// implicit, style, mark, mark);
+//
+// return 1;
+//
+//error:
+// yaml_free(anchor_copy);
+// yaml_free(tag_copy);
+//
+// return 0;
+//}
+//
+///*
+// * Create MAPPING-END.
+// */
+//
+//YAML_DECLARE(int)
+//yaml_mapping_end_event_initialize(yaml_event_t *event)
+//{
+// yaml_mark_t mark = { 0, 0, 0 };
+//
+// assert(event); // Non-NULL event object is expected.
+//
+// MAPPING_END_EVENT_INIT(*event, mark, mark);
+//
+// return 1;
+//}
+
+///*
+// * Create a document object.
+// */
+//
+//YAML_DECLARE(int)
+//yaml_document_initialize(yaml_document_t *document,
+// yaml_version_directive_t *version_directive,
+// yaml_tag_directive_t *tag_directives_start,
+// yaml_tag_directive_t *tag_directives_end,
+// int start_implicit, int end_implicit)
+//{
+// struct {
+// yaml_error_type_t error;
+// } context;
+// struct {
+// yaml_node_t *start;
+// yaml_node_t *end;
+// yaml_node_t *top;
+// } nodes = { NULL, NULL, NULL };
+// yaml_version_directive_t *version_directive_copy = NULL;
+// struct {
+// yaml_tag_directive_t *start;
+// yaml_tag_directive_t *end;
+// yaml_tag_directive_t *top;
+// } tag_directives_copy = { NULL, NULL, NULL };
+// yaml_tag_directive_t value = { NULL, NULL };
+// yaml_mark_t mark = { 0, 0, 0 };
+//
+// assert(document); // Non-NULL document object is expected.
+// assert((tag_directives_start && tag_directives_end) ||
+// (tag_directives_start == tag_directives_end));
+// // Valid tag directives are expected.
+//
+// if (!STACK_INIT(&context, nodes, INITIAL_STACK_SIZE)) goto error;
+//
+// if (version_directive) {
+// version_directive_copy = yaml_malloc(sizeof(yaml_version_directive_t));
+// if (!version_directive_copy) goto error;
+// version_directive_copy.major = version_directive.major;
+// version_directive_copy.minor = version_directive.minor;
+// }
+//
+// if (tag_directives_start != tag_directives_end) {
+// yaml_tag_directive_t *tag_directive;
+// if (!STACK_INIT(&context, tag_directives_copy, INITIAL_STACK_SIZE))
+// goto error;
+// for (tag_directive = tag_directives_start;
+// tag_directive != tag_directives_end; tag_directive ++) {
+// assert(tag_directive.handle);
+// assert(tag_directive.prefix);
+// if (!yaml_check_utf8(tag_directive.handle,
+// strlen((char *)tag_directive.handle)))
+// goto error;
+// if (!yaml_check_utf8(tag_directive.prefix,
+// strlen((char *)tag_directive.prefix)))
+// goto error;
+// value.handle = yaml_strdup(tag_directive.handle);
+// value.prefix = yaml_strdup(tag_directive.prefix);
+// if (!value.handle || !value.prefix) goto error;
+// if (!PUSH(&context, tag_directives_copy, value))
+// goto error;
+// value.handle = NULL;
+// value.prefix = NULL;
+// }
+// }
+//
+// DOCUMENT_INIT(*document, nodes.start, nodes.end, version_directive_copy,
+// tag_directives_copy.start, tag_directives_copy.top,
+// start_implicit, end_implicit, mark, mark);
+//
+// return 1;
+//
+//error:
+// STACK_DEL(&context, nodes);
+// yaml_free(version_directive_copy);
+// while (!STACK_EMPTY(&context, tag_directives_copy)) {
+// yaml_tag_directive_t value = POP(&context, tag_directives_copy);
+// yaml_free(value.handle);
+// yaml_free(value.prefix);
+// }
+// STACK_DEL(&context, tag_directives_copy);
+// yaml_free(value.handle);
+// yaml_free(value.prefix);
+//
+// return 0;
+//}
+//
+///*
+// * Destroy a document object.
+// */
+//
+//YAML_DECLARE(void)
+//yaml_document_delete(yaml_document_t *document)
+//{
+// struct {
+// yaml_error_type_t error;
+// } context;
+// yaml_tag_directive_t *tag_directive;
+//
+// context.error = YAML_NO_ERROR; // Eliminate a compliler warning.
+//
+// assert(document); // Non-NULL document object is expected.
+//
+// while (!STACK_EMPTY(&context, document.nodes)) {
+// yaml_node_t node = POP(&context, document.nodes);
+// yaml_free(node.tag);
+// switch (node.type) {
+// case YAML_SCALAR_NODE:
+// yaml_free(node.data.scalar.value);
+// break;
+// case YAML_SEQUENCE_NODE:
+// STACK_DEL(&context, node.data.sequence.items);
+// break;
+// case YAML_MAPPING_NODE:
+// STACK_DEL(&context, node.data.mapping.pairs);
+// break;
+// default:
+// assert(0); // Should not happen.
+// }
+// }
+// STACK_DEL(&context, document.nodes);
+//
+// yaml_free(document.version_directive);
+// for (tag_directive = document.tag_directives.start;
+// tag_directive != document.tag_directives.end;
+// tag_directive++) {
+// yaml_free(tag_directive.handle);
+// yaml_free(tag_directive.prefix);
+// }
+// yaml_free(document.tag_directives.start);
+//
+// memset(document, 0, sizeof(yaml_document_t));
+//}
+//
+///**
+// * Get a document node.
+// */
+//
+//YAML_DECLARE(yaml_node_t *)
+//yaml_document_get_node(yaml_document_t *document, int index)
+//{
+// assert(document); // Non-NULL document object is expected.
+//
+// if (index > 0 && document.nodes.start + index <= document.nodes.top) {
+// return document.nodes.start + index - 1;
+// }
+// return NULL;
+//}
+//
+///**
+// * Get the root object.
+// */
+//
+//YAML_DECLARE(yaml_node_t *)
+//yaml_document_get_root_node(yaml_document_t *document)
+//{
+// assert(document); // Non-NULL document object is expected.
+//
+// if (document.nodes.top != document.nodes.start) {
+// return document.nodes.start;
+// }
+// return NULL;
+//}
+//
+///*
+// * Add a scalar node to a document.
+// */
+//
+//YAML_DECLARE(int)
+//yaml_document_add_scalar(yaml_document_t *document,
+// yaml_char_t *tag, yaml_char_t *value, int length,
+// yaml_scalar_style_t style)
+//{
+// struct {
+// yaml_error_type_t error;
+// } context;
+// yaml_mark_t mark = { 0, 0, 0 };
+// yaml_char_t *tag_copy = NULL;
+// yaml_char_t *value_copy = NULL;
+// yaml_node_t node;
+//
+// assert(document); // Non-NULL document object is expected.
+// assert(value); // Non-NULL value is expected.
+//
+// if (!tag) {
+// tag = (yaml_char_t *)YAML_DEFAULT_SCALAR_TAG;
+// }
+//
+// if (!yaml_check_utf8(tag, strlen((char *)tag))) goto error;
+// tag_copy = yaml_strdup(tag);
+// if (!tag_copy) goto error;
+//
+// if (length < 0) {
+// length = strlen((char *)value);
+// }
+//
+// if (!yaml_check_utf8(value, length)) goto error;
+// value_copy = yaml_malloc(length+1);
+// if (!value_copy) goto error;
+// memcpy(value_copy, value, length);
+// value_copy[length] = '\0';
+//
+// SCALAR_NODE_INIT(node, tag_copy, value_copy, length, style, mark, mark);
+// if (!PUSH(&context, document.nodes, node)) goto error;
+//
+// return document.nodes.top - document.nodes.start;
+//
+//error:
+// yaml_free(tag_copy);
+// yaml_free(value_copy);
+//
+// return 0;
+//}
+//
+///*
+// * Add a sequence node to a document.
+// */
+//
+//YAML_DECLARE(int)
+//yaml_document_add_sequence(yaml_document_t *document,
+// yaml_char_t *tag, yaml_sequence_style_t style)
+//{
+// struct {
+// yaml_error_type_t error;
+// } context;
+// yaml_mark_t mark = { 0, 0, 0 };
+// yaml_char_t *tag_copy = NULL;
+// struct {
+// yaml_node_item_t *start;
+// yaml_node_item_t *end;
+// yaml_node_item_t *top;
+// } items = { NULL, NULL, NULL };
+// yaml_node_t node;
+//
+// assert(document); // Non-NULL document object is expected.
+//
+// if (!tag) {
+// tag = (yaml_char_t *)YAML_DEFAULT_SEQUENCE_TAG;
+// }
+//
+// if (!yaml_check_utf8(tag, strlen((char *)tag))) goto error;
+// tag_copy = yaml_strdup(tag);
+// if (!tag_copy) goto error;
+//
+// if (!STACK_INIT(&context, items, INITIAL_STACK_SIZE)) goto error;
+//
+// SEQUENCE_NODE_INIT(node, tag_copy, items.start, items.end,
+// style, mark, mark);
+// if (!PUSH(&context, document.nodes, node)) goto error;
+//
+// return document.nodes.top - document.nodes.start;
+//
+//error:
+// STACK_DEL(&context, items);
+// yaml_free(tag_copy);
+//
+// return 0;
+//}
+//
+///*
+// * Add a mapping node to a document.
+// */
+//
+//YAML_DECLARE(int)
+//yaml_document_add_mapping(yaml_document_t *document,
+// yaml_char_t *tag, yaml_mapping_style_t style)
+//{
+// struct {
+// yaml_error_type_t error;
+// } context;
+// yaml_mark_t mark = { 0, 0, 0 };
+// yaml_char_t *tag_copy = NULL;
+// struct {
+// yaml_node_pair_t *start;
+// yaml_node_pair_t *end;
+// yaml_node_pair_t *top;
+// } pairs = { NULL, NULL, NULL };
+// yaml_node_t node;
+//
+// assert(document); // Non-NULL document object is expected.
+//
+// if (!tag) {
+// tag = (yaml_char_t *)YAML_DEFAULT_MAPPING_TAG;
+// }
+//
+// if (!yaml_check_utf8(tag, strlen((char *)tag))) goto error;
+// tag_copy = yaml_strdup(tag);
+// if (!tag_copy) goto error;
+//
+// if (!STACK_INIT(&context, pairs, INITIAL_STACK_SIZE)) goto error;
+//
+// MAPPING_NODE_INIT(node, tag_copy, pairs.start, pairs.end,
+// style, mark, mark);
+// if (!PUSH(&context, document.nodes, node)) goto error;
+//
+// return document.nodes.top - document.nodes.start;
+//
+//error:
+// STACK_DEL(&context, pairs);
+// yaml_free(tag_copy);
+//
+// return 0;
+//}
+//
+///*
+// * Append an item to a sequence node.
+// */
+//
+//YAML_DECLARE(int)
+//yaml_document_append_sequence_item(yaml_document_t *document,
+// int sequence, int item)
+//{
+// struct {
+// yaml_error_type_t error;
+// } context;
+//
+// assert(document); // Non-NULL document is required.
+// assert(sequence > 0
+// && document.nodes.start + sequence <= document.nodes.top);
+// // Valid sequence id is required.
+// assert(document.nodes.start[sequence-1].type == YAML_SEQUENCE_NODE);
+// // A sequence node is required.
+// assert(item > 0 && document.nodes.start + item <= document.nodes.top);
+// // Valid item id is required.
+//
+// if (!PUSH(&context,
+// document.nodes.start[sequence-1].data.sequence.items, item))
+// return 0;
+//
+// return 1;
+//}
+//
+///*
+// * Append a pair of a key and a value to a mapping node.
+// */
+//
+//YAML_DECLARE(int)
+//yaml_document_append_mapping_pair(yaml_document_t *document,
+// int mapping, int key, int value)
+//{
+// struct {
+// yaml_error_type_t error;
+// } context;
+//
+// yaml_node_pair_t pair;
+//
+// assert(document); // Non-NULL document is required.
+// assert(mapping > 0
+// && document.nodes.start + mapping <= document.nodes.top);
+// // Valid mapping id is required.
+// assert(document.nodes.start[mapping-1].type == YAML_MAPPING_NODE);
+// // A mapping node is required.
+// assert(key > 0 && document.nodes.start + key <= document.nodes.top);
+// // Valid key id is required.
+// assert(value > 0 && document.nodes.start + value <= document.nodes.top);
+// // Valid value id is required.
+//
+// pair.key = key;
+// pair.value = value;
+//
+// if (!PUSH(&context,
+// document.nodes.start[mapping-1].data.mapping.pairs, pair))
+// return 0;
+//
+// return 1;
+//}
+//
+//
diff --git a/parser_c.go b/parser_c.go
new file mode 100644
index 0000000..c965594
--- /dev/null
+++ b/parser_c.go
@@ -0,0 +1,1096 @@
+package goyaml
+
+import (
+ "bytes"
+)
+
+// The parser implements the following grammar:
+//
+// stream ::= STREAM-START implicit_document? explicit_document* STREAM-END
+// implicit_document ::= block_node DOCUMENT-END*
+// explicit_document ::= DIRECTIVE* DOCUMENT-START block_node? DOCUMENT-END*
+// block_node_or_indentless_sequence ::=
+// ALIAS
+// | properties (block_content | indentless_block_sequence)?
+// | block_content
+// | indentless_block_sequence
+// block_node ::= ALIAS
+// | properties block_content?
+// | block_content
+// flow_node ::= ALIAS
+// | properties flow_content?
+// | flow_content
+// properties ::= TAG ANCHOR? | ANCHOR TAG?
+// block_content ::= block_collection | flow_collection | SCALAR
+// flow_content ::= flow_collection | SCALAR
+// block_collection ::= block_sequence | block_mapping
+// flow_collection ::= flow_sequence | flow_mapping
+// block_sequence ::= BLOCK-SEQUENCE-START (BLOCK-ENTRY block_node?)* BLOCK-END
+// indentless_sequence ::= (BLOCK-ENTRY block_node?)+
+// block_mapping ::= BLOCK-MAPPING_START
+// ((KEY block_node_or_indentless_sequence?)?
+// (VALUE block_node_or_indentless_sequence?)?)*
+// BLOCK-END
+// flow_sequence ::= FLOW-SEQUENCE-START
+// (flow_sequence_entry FLOW-ENTRY)*
+// flow_sequence_entry?
+// FLOW-SEQUENCE-END
+// flow_sequence_entry ::= flow_node | KEY flow_node? (VALUE flow_node?)?
+// flow_mapping ::= FLOW-MAPPING-START
+// (flow_mapping_entry FLOW-ENTRY)*
+// flow_mapping_entry?
+// FLOW-MAPPING-END
+// flow_mapping_entry ::= flow_node | KEY flow_node? (VALUE flow_node?)?
+
+// Peek the next token in the token queue.
+func peek_token(parser *yaml_parser_t) *yaml_token_t {
+ if parser.token_available || yaml_parser_fetch_more_tokens(parser) {
+ return &parser.tokens[parser.tokens_head]
+ }
+ return nil
+}
+
+// Remove the next token from the queue (must be called after peek_token).
+func skip_token(parser *yaml_parser_t) {
+ parser.token_available = false
+ parser.tokens_parsed++
+ parser.stream_end_produced = parser.tokens[parser.tokens_head].typ == yaml_STREAM_END_TOKEN
+ parser.tokens_head++
+}
+
+// Get the next event.
+func yaml_parser_parse(parser *yaml_parser_t, event *yaml_event_t) bool {
+ // Erase the event object.
+ *event = yaml_event_t{}
+
+ // No events after the end of the stream or error.
+ if parser.stream_end_produced || parser.error != yaml_NO_ERROR || parser.state == yaml_PARSE_END_STATE {
+ return true
+ }
+
+ // Generate the next event.
+ return yaml_parser_state_machine(parser, event)
+}
+
+// Set parser error.
+func yaml_parser_set_parser_error(parser *yaml_parser_t, problem string, problem_mark yaml_mark_t) bool {
+ parser.error = yaml_PARSER_ERROR
+ parser.problem = problem
+ parser.problem_mark = problem_mark
+ return false
+}
+
+func yaml_parser_set_parser_error_context(parser *yaml_parser_t, context string, context_mark yaml_mark_t, problem string, problem_mark yaml_mark_t) bool {
+ parser.error = yaml_PARSER_ERROR
+ parser.context = context
+ parser.context_mark = context_mark
+ parser.problem = problem
+ parser.problem_mark = problem_mark
+ return false
+}
+
+// State dispatcher.
+func yaml_parser_state_machine(parser *yaml_parser_t, event *yaml_event_t) bool {
+ switch parser.state {
+ case yaml_PARSE_STREAM_START_STATE:
+ return yaml_parser_parse_stream_start(parser, event)
+
+ case yaml_PARSE_IMPLICIT_DOCUMENT_START_STATE:
+ return yaml_parser_parse_document_start(parser, event, true)
+
+ case yaml_PARSE_DOCUMENT_START_STATE:
+ return yaml_parser_parse_document_start(parser, event, false)
+
+ case yaml_PARSE_DOCUMENT_CONTENT_STATE:
+ return yaml_parser_parse_document_content(parser, event)
+
+ case yaml_PARSE_DOCUMENT_END_STATE:
+ return yaml_parser_parse_document_end(parser, event)
+
+ case yaml_PARSE_BLOCK_NODE_STATE:
+ return yaml_parser_parse_node(parser, event, true, false)
+
+ case yaml_PARSE_BLOCK_NODE_OR_INDENTLESS_SEQUENCE_STATE:
+ return yaml_parser_parse_node(parser, event, true, true)
+
+ case yaml_PARSE_FLOW_NODE_STATE:
+ return yaml_parser_parse_node(parser, event, false, false)
+
+ case yaml_PARSE_BLOCK_SEQUENCE_FIRST_ENTRY_STATE:
+ return yaml_parser_parse_block_sequence_entry(parser, event, true)
+
+ case yaml_PARSE_BLOCK_SEQUENCE_ENTRY_STATE:
+ return yaml_parser_parse_block_sequence_entry(parser, event, false)
+
+ case yaml_PARSE_INDENTLESS_SEQUENCE_ENTRY_STATE:
+ return yaml_parser_parse_indentless_sequence_entry(parser, event)
+
+ case yaml_PARSE_BLOCK_MAPPING_FIRST_KEY_STATE:
+ return yaml_parser_parse_block_mapping_key(parser, event, true)
+
+ case yaml_PARSE_BLOCK_MAPPING_KEY_STATE:
+ return yaml_parser_parse_block_mapping_key(parser, event, false)
+
+ case yaml_PARSE_BLOCK_MAPPING_VALUE_STATE:
+ return yaml_parser_parse_block_mapping_value(parser, event)
+
+ case yaml_PARSE_FLOW_SEQUENCE_FIRST_ENTRY_STATE:
+ return yaml_parser_parse_flow_sequence_entry(parser, event, true)
+
+ case yaml_PARSE_FLOW_SEQUENCE_ENTRY_STATE:
+ return yaml_parser_parse_flow_sequence_entry(parser, event, false)
+
+ case yaml_PARSE_FLOW_SEQUENCE_ENTRY_MAPPING_KEY_STATE:
+ return yaml_parser_parse_flow_sequence_entry_mapping_key(parser, event)
+
+ case yaml_PARSE_FLOW_SEQUENCE_ENTRY_MAPPING_VALUE_STATE:
+ return yaml_parser_parse_flow_sequence_entry_mapping_value(parser, event)
+
+ case yaml_PARSE_FLOW_SEQUENCE_ENTRY_MAPPING_END_STATE:
+ return yaml_parser_parse_flow_sequence_entry_mapping_end(parser, event)
+
+ case yaml_PARSE_FLOW_MAPPING_FIRST_KEY_STATE:
+ return yaml_parser_parse_flow_mapping_key(parser, event, true)
+
+ case yaml_PARSE_FLOW_MAPPING_KEY_STATE:
+ return yaml_parser_parse_flow_mapping_key(parser, event, false)
+
+ case yaml_PARSE_FLOW_MAPPING_VALUE_STATE:
+ return yaml_parser_parse_flow_mapping_value(parser, event, false)
+
+ case yaml_PARSE_FLOW_MAPPING_EMPTY_VALUE_STATE:
+ return yaml_parser_parse_flow_mapping_value(parser, event, true)
+
+ default:
+ panic("invalid parser state")
+ }
+ return false
+}
+
+// Parse the production:
+// stream ::= STREAM-START implicit_document? explicit_document* STREAM-END
+// ************
+func yaml_parser_parse_stream_start(parser *yaml_parser_t, event *yaml_event_t) bool {
+ token := peek_token(parser)
+ if token == nil {
+ return false
+ }
+ if token.typ != yaml_STREAM_START_TOKEN {
+ return yaml_parser_set_parser_error(parser, "did not find expected <stream-start>", token.start_mark)
+ }
+ parser.state = yaml_PARSE_IMPLICIT_DOCUMENT_START_STATE
+ *event = yaml_event_t{
+ typ: yaml_STREAM_START_EVENT,
+ start_mark: token.start_mark,
+ end_mark: token.end_mark,
+ }
+ event.stream_start.encoding = token.stream_start.encoding
+ skip_token(parser)
+ return true
+}
+
+// Parse the productions:
+// implicit_document ::= block_node DOCUMENT-END*
+// *
+// explicit_document ::= DIRECTIVE* DOCUMENT-START block_node? DOCUMENT-END*
+// *************************
+func yaml_parser_parse_document_start(parser *yaml_parser_t, event *yaml_event_t, implicit bool) bool {
+ token := peek_token(parser)
+ if token == nil {
+ return false
+ }
+
+ // Parse extra document end indicators.
+ if !implicit {
+ for token.typ == yaml_DOCUMENT_END_TOKEN {
+ skip_token(parser)
+ token = peek_token(parser)
+ if token == nil {
+ return false
+ }
+ }
+ }
+
+ if implicit && token.typ != yaml_VERSION_DIRECTIVE_TOKEN &&
+ // Parse an implicit document.
+ token.typ != yaml_TAG_DIRECTIVE_TOKEN &&
+ token.typ != yaml_DOCUMENT_START_TOKEN &&
+ token.typ != yaml_STREAM_END_TOKEN {
+ if !yaml_parser_process_directives(parser, nil, nil) {
+ return false
+ }
+ parser.states = append(parser.states, yaml_PARSE_DOCUMENT_END_STATE)
+ parser.state = yaml_PARSE_BLOCK_NODE_STATE
+
+ *event = yaml_event_t{
+ typ: yaml_DOCUMENT_START_EVENT,
+ start_mark: token.start_mark,
+ end_mark: token.end_mark,
+ }
+
+ } else if token.typ != yaml_STREAM_END_TOKEN {
+ // Parse an explicit document.
+ var version_directive *yaml_version_directive_t
+ var tag_directives []yaml_tag_directive_t
+ start_mark := token.start_mark
+ if !yaml_parser_process_directives(parser, &version_directive, &tag_directives) {
+ return false
+ }
+ token = peek_token(parser)
+ if token == nil {
+ return false
+ }
+ if token.typ != yaml_DOCUMENT_START_TOKEN {
+ yaml_parser_set_parser_error(parser,
+ "did not find expected <document start>", token.start_mark)
+ return false
+ }
+ parser.states = append(parser.states, yaml_PARSE_DOCUMENT_END_STATE)
+ parser.state = yaml_PARSE_DOCUMENT_CONTENT_STATE
+ end_mark := token.end_mark
+
+ *event = yaml_event_t{
+ typ: yaml_DOCUMENT_START_EVENT,
+ start_mark: start_mark,
+ end_mark: end_mark,
+ }
+ event.document_start.version_directive = version_directive
+ event.document_start.tag_directives = tag_directives
+ event.document_start.implicit = false
+ skip_token(parser)
+
+ } else {
+ // Parse the stream end.
+ parser.state = yaml_PARSE_END_STATE
+ *event = yaml_event_t{
+ typ: yaml_STREAM_END_EVENT,
+ start_mark: token.start_mark,
+ end_mark: token.end_mark,
+ }
+ skip_token(parser)
+ }
+
+ return true
+}
+
+// Parse the productions:
+// explicit_document ::= DIRECTIVE* DOCUMENT-START block_node? DOCUMENT-END*
+// ***********
+//
+func yaml_parser_parse_document_content(parser *yaml_parser_t, event *yaml_event_t) bool {
+ token := peek_token(parser)
+ if token == nil {
+ return false
+ }
+ if token.typ == yaml_VERSION_DIRECTIVE_TOKEN ||
+ token.typ == yaml_TAG_DIRECTIVE_TOKEN ||
+ token.typ == yaml_DOCUMENT_START_TOKEN ||
+ token.typ == yaml_DOCUMENT_END_TOKEN ||
+ token.typ == yaml_STREAM_END_TOKEN {
+ parser.state = parser.states[len(parser.states)-1]
+ parser.states = parser.states[:len(parser.states)-1]
+ return yaml_parser_process_empty_scalar(parser, event,
+ token.start_mark)
+ } else {
+ return yaml_parser_parse_node(parser, event, true, false)
+ }
+}
+
+// Parse the productions:
+// implicit_document ::= block_node DOCUMENT-END*
+// *************
+// explicit_document ::= DIRECTIVE* DOCUMENT-START block_node? DOCUMENT-END*
+//
+func yaml_parser_parse_document_end(parser *yaml_parser_t, event *yaml_event_t) bool {
+ token := peek_token(parser)
+ if token == nil {
+ return false
+ }
+
+ start_mark := token.start_mark
+ end_mark := token.start_mark
+
+ implicit := true
+ if token.typ == yaml_DOCUMENT_END_TOKEN {
+ end_mark = token.end_mark
+ skip_token(parser)
+ implicit = false
+ }
+
+ parser.tag_directives = parser.tag_directives[:0]
+
+ parser.state = yaml_PARSE_DOCUMENT_START_STATE
+ *event = yaml_event_t{
+ typ: yaml_DOCUMENT_END_EVENT,
+ start_mark: start_mark,
+ end_mark: end_mark,
+ }
+ event.document_start.implicit = implicit
+ return true
+}
+
+// Parse the productions:
+// block_node_or_indentless_sequence ::=
+// ALIAS
+// *****
+// | properties (block_content | indentless_block_sequence)?
+// ********** *
+// | block_content | indentless_block_sequence
+// *
+// block_node ::= ALIAS
+// *****
+// | properties block_content?
+// ********** *
+// | block_content
+// *
+// flow_node ::= ALIAS
+// *****
+// | properties flow_content?
+// ********** *
+// | flow_content
+// *
+// properties ::= TAG ANCHOR? | ANCHOR TAG?
+// *************************
+// block_content ::= block_collection | flow_collection | SCALAR
+// ******
+// flow_content ::= flow_collection | SCALAR
+// ******
+func yaml_parser_parse_node(parser *yaml_parser_t, event *yaml_event_t, block, indentless_sequence bool) bool {
+ token := peek_token(parser)
+ if token == nil {
+ return false
+ }
+ if token.typ == yaml_ALIAS_TOKEN {
+ parser.state = parser.states[len(parser.states)-1]
+ parser.states = parser.states[:len(parser.states)-1]
+ *event = yaml_event_t{
+ typ: yaml_ALIAS_EVENT,
+ start_mark: token.start_mark,
+ end_mark: token.end_mark,
+ }
+ event.alias.anchor = token.alias.value
+ skip_token(parser)
+ return true
+ }
+
+ start_mark := token.start_mark
+ end_mark := token.start_mark
+
+ var tag_token bool
+ var tag_handle, tag_suffix, anchor []byte
+ var tag_mark yaml_mark_t
+ if token.typ == yaml_ANCHOR_TOKEN {
+ anchor = token.anchor.value
+ start_mark = token.start_mark
+ end_mark = token.end_mark
+ skip_token(parser)
+ token = peek_token(parser)
+ if token == nil {
+ return false
+ }
+ if token.typ == yaml_TAG_TOKEN {
+ tag_token = true
+ tag_handle = token.tag.handle
+ tag_suffix = token.tag.suffix
+ tag_mark = token.start_mark
+ end_mark = token.end_mark
+ skip_token(parser)
+ token = peek_token(parser)
+ if token == nil {
+ return false
+ }
+ }
+ } else if token.typ == yaml_TAG_TOKEN {
+ tag_token = true
+ tag_handle = token.tag.handle
+ tag_suffix = token.tag.suffix
+ start_mark = token.start_mark
+ tag_mark = token.start_mark
+ end_mark = token.end_mark
+ skip_token(parser)
+ token = peek_token(parser)
+ if token == nil {
+ return false
+ }
+ if token.typ == yaml_ANCHOR_TOKEN {
+ anchor = token.anchor.value
+ end_mark = token.end_mark
+ skip_token(parser)
+ token = peek_token(parser)
+ if token == nil {
+ return false
+ }
+ }
+ }
+
+ var tag []byte
+ if tag_token {
+ if len(tag_handle) == 0 {
+ tag = tag_suffix
+ tag_suffix = nil
+ } else {
+ for i := range parser.tag_directives {
+ if bytes.Equal(parser.tag_directives[i].handle, tag_handle) {
+ tag := append([]byte(nil), parser.tag_directives[i].prefix...)
+ tag = append(tag, tag_suffix...)
+ break
+ }
+ }
+ if len(tag) == 0 {
+ yaml_parser_set_parser_error_context(parser,
+ "while parsing a node", start_mark,
+ "found undefined tag handle", tag_mark)
+ return false
+ }
+ }
+ }
+
+ implicit := len(tag) == 0
+ if indentless_sequence && token.typ == yaml_BLOCK_ENTRY_TOKEN {
+ end_mark = token.end_mark
+ parser.state = yaml_PARSE_INDENTLESS_SEQUENCE_ENTRY_STATE
+ *event = yaml_event_t{
+ typ: yaml_SEQUENCE_START_EVENT,
+ start_mark: start_mark,
+ end_mark: end_mark,
+ }
+ event.sequence_start.anchor = anchor
+ event.sequence_start.tag = tag
+ event.sequence_start.implicit = implicit
+ event.sequence_start.style = yaml_BLOCK_SEQUENCE_STYLE
+ return true
+ }
+ if token.typ == yaml_SCALAR_TOKEN {
+ var plain_implicit, quoted_implicit bool
+ end_mark = token.end_mark
+ if (len(tag) == 0 && token.scalar.style == yaml_PLAIN_SCALAR_STYLE) || (len(tag) == 1 && tag[0] == '!') {
+ plain_implicit = true
+ } else if len(tag) == 0 {
+ quoted_implicit = true
+ }
+ parser.state = parser.states[len(parser.states)-1]
+ parser.states = parser.states[:len(parser.states)-1]
+
+ *event = yaml_event_t{
+ typ: yaml_SCALAR_EVENT,
+ start_mark: start_mark,
+ end_mark: end_mark,
+ }
+ event.scalar.anchor = anchor
+ event.scalar.tag = tag
+ event.scalar.value = token.scalar.value
+ event.scalar.plain_implicit = plain_implicit
+ event.scalar.quoted_implicit = quoted_implicit
+ event.scalar.style = token.scalar.style
+ skip_token(parser)
+ return true
+ }
+ if token.typ == yaml_FLOW_SEQUENCE_START_TOKEN {
+ // [Go] Some of the events below can be merged as they differ only on style.
+ end_mark = token.end_mark
+ parser.state = yaml_PARSE_FLOW_SEQUENCE_FIRST_ENTRY_STATE
+ *event = yaml_event_t{
+ typ: yaml_SEQUENCE_START_EVENT,
+ start_mark: start_mark,
+ end_mark: end_mark,
+ }
+ event.sequence_start.anchor = anchor
+ event.sequence_start.tag = tag
+ event.sequence_start.implicit = implicit
+ event.sequence_start.style = yaml_FLOW_SEQUENCE_STYLE
+ return true
+ }
+ if token.typ == yaml_FLOW_MAPPING_START_TOKEN {
+ end_mark = token.end_mark
+ parser.state = yaml_PARSE_FLOW_MAPPING_FIRST_KEY_STATE
+ *event = yaml_event_t{
+ typ: yaml_MAPPING_START_EVENT,
+ start_mark: start_mark,
+ end_mark: end_mark,
+ }
+ event.mapping_start.anchor = anchor
+ event.mapping_start.tag = tag
+ event.mapping_start.implicit = implicit
+ event.mapping_start.style = yaml_FLOW_MAPPING_STYLE
+ return true
+ }
+ if block && token.typ == yaml_BLOCK_SEQUENCE_START_TOKEN {
+ end_mark = token.end_mark
+ parser.state = yaml_PARSE_BLOCK_SEQUENCE_FIRST_ENTRY_STATE
+ *event = yaml_event_t{
+ typ: yaml_SEQUENCE_START_EVENT,
+ start_mark: start_mark,
+ end_mark: end_mark,
+ }
+ event.sequence_start.anchor = anchor
+ event.sequence_start.tag = tag
+ event.sequence_start.implicit = implicit
+ event.sequence_start.style = yaml_BLOCK_SEQUENCE_STYLE
+ return true
+ }
+ if block && token.typ == yaml_BLOCK_MAPPING_START_TOKEN {
+ end_mark = token.end_mark
+ parser.state = yaml_PARSE_BLOCK_MAPPING_FIRST_KEY_STATE
+ *event = yaml_event_t{
+ typ: yaml_MAPPING_START_EVENT,
+ start_mark: start_mark,
+ end_mark: end_mark,
+ }
+ event.mapping_start.anchor = anchor
+ event.mapping_start.tag = tag
+ event.mapping_start.implicit = implicit
+ event.mapping_start.style = yaml_BLOCK_MAPPING_STYLE
+ return true
+ }
+ if len(anchor) > 0 || len(tag) > 0 {
+ parser.state = parser.states[len(parser.states)-1]
+ parser.states = parser.states[:len(parser.states)-1]
+
+ *event = yaml_event_t{
+ typ: yaml_SCALAR_EVENT,
+ start_mark: start_mark,
+ end_mark: end_mark,
+ }
+ event.scalar.anchor = anchor
+ event.scalar.tag = tag
+ event.scalar.plain_implicit = implicit
+ event.scalar.quoted_implicit = false
+ event.scalar.style = yaml_PLAIN_SCALAR_STYLE
+ return true
+ }
+
+ context := "while parsing a flow node"
+ if block {
+ context = "while parsing a block node"
+ }
+ yaml_parser_set_parser_error_context(parser, context, start_mark,
+ "did not find expected node content", token.start_mark)
+ return false
+}
+
+// Parse the productions:
+// block_sequence ::= BLOCK-SEQUENCE-START (BLOCK-ENTRY block_node?)* BLOCK-END
+// ******************** *********** * *********
+//
+func yaml_parser_parse_block_sequence_entry(parser *yaml_parser_t, event *yaml_event_t, first bool) bool {
+ if first {
+ token := peek_token(parser)
+ parser.marks = append(parser.marks, token.start_mark)
+ skip_token(parser)
+ }
+
+ token := peek_token(parser)
+ if token == nil {
+ return false
+ }
+
+ if token.typ == yaml_BLOCK_ENTRY_TOKEN {
+ mark := token.end_mark
+ skip_token(parser)
+ token = peek_token(parser)
+ if token == nil {
+ return false
+ }
+ if token.typ != yaml_BLOCK_ENTRY_TOKEN && token.typ != yaml_BLOCK_END_TOKEN {
+ parser.states = append(parser.states, yaml_PARSE_BLOCK_SEQUENCE_ENTRY_STATE)
+ return yaml_parser_parse_node(parser, event, true, false)
+ } else {
+ parser.state = yaml_PARSE_BLOCK_SEQUENCE_ENTRY_STATE
+ return yaml_parser_process_empty_scalar(parser, event, mark)
+ }
+ }
+ if token.typ == yaml_BLOCK_END_TOKEN {
+ parser.state = parser.states[len(parser.states)-1]
+ parser.states = parser.states[:len(parser.states)-1]
+ parser.marks = parser.marks[:len(parser.marks)-1]
+
+ *event = yaml_event_t{
+ typ: yaml_SEQUENCE_END_EVENT,
+ start_mark: token.start_mark,
+ end_mark: token.end_mark,
+ }
+
+ skip_token(parser)
+ return true
+ }
+
+ context_mark := parser.marks[len(parser.marks)-1]
+ parser.marks = parser.marks[:len(parser.marks)-1]
+ return yaml_parser_set_parser_error_context(parser,
+ "while parsing a block collection", context_mark,
+ "did not find expected '-' indicator", token.start_mark)
+}
+
+// Parse the productions:
+// indentless_sequence ::= (BLOCK-ENTRY block_node?)+
+// *********** *
+func yaml_parser_parse_indentless_sequence_entry(parser *yaml_parser_t, event *yaml_event_t) bool {
+ token := peek_token(parser)
+ if token == nil {
+ return false
+ }
+
+ if token.typ == yaml_BLOCK_ENTRY_TOKEN {
+ mark := token.end_mark
+ skip_token(parser)
+ token = peek_token(parser)
+ if token == nil {
+ return false
+ }
+ if token.typ != yaml_BLOCK_ENTRY_TOKEN &&
+ token.typ != yaml_KEY_TOKEN &&
+ token.typ != yaml_VALUE_TOKEN &&
+ token.typ != yaml_BLOCK_END_TOKEN {
+ parser.states = append(parser.states, yaml_PARSE_INDENTLESS_SEQUENCE_ENTRY_STATE)
+ return yaml_parser_parse_node(parser, event, true, false)
+ } else {
+ parser.state = yaml_PARSE_INDENTLESS_SEQUENCE_ENTRY_STATE
+ return yaml_parser_process_empty_scalar(parser, event, mark)
+ }
+ } else {
+ parser.state = parser.states[len(parser.states)-1]
+ parser.states = parser.states[:len(parser.states)-1]
+
+ *event = yaml_event_t{
+ typ: yaml_SEQUENCE_END_EVENT,
+ start_mark: token.start_mark,
+ end_mark: token.start_mark, // [Go] Shouldn't this be token.end_mark?
+ }
+ return true
+ }
+}
+
+// Parse the productions:
+// block_mapping ::= BLOCK-MAPPING_START
+// *******************
+// ((KEY block_node_or_indentless_sequence?)?
+// *** *
+// (VALUE block_node_or_indentless_sequence?)?)*
+//
+// BLOCK-END
+// *********
+//
+func yaml_parser_parse_block_mapping_key(parser *yaml_parser_t, event *yaml_event_t, first bool) bool {
+ if first {
+ token := peek_token(parser)
+ parser.marks = append(parser.marks, token.start_mark)
+ skip_token(parser)
+ }
+
+ token := peek_token(parser)
+ if token == nil {
+ return false
+ }
+
+ if token.typ == yaml_KEY_TOKEN {
+ mark := token.end_mark
+ skip_token(parser)
+ token = peek_token(parser)
+ if token == nil {
+ return false
+ }
+ if token.typ != yaml_KEY_TOKEN &&
+ token.typ != yaml_VALUE_TOKEN &&
+ token.typ != yaml_BLOCK_END_TOKEN {
+ parser.states = append(parser.states, yaml_PARSE_BLOCK_MAPPING_VALUE_STATE)
+ return yaml_parser_parse_node(parser, event, true, true)
+ } else {
+ parser.state = yaml_PARSE_BLOCK_MAPPING_VALUE_STATE
+ return yaml_parser_process_empty_scalar(parser, event, mark)
+ }
+ } else if token.typ == yaml_BLOCK_END_TOKEN {
+ parser.state = parser.states[len(parser.states)-1]
+ parser.states = parser.states[:len(parser.states)-1]
+ parser.marks = parser.marks[:len(parser.marks)-1]
+ *event = yaml_event_t{
+ typ: yaml_MAPPING_END_EVENT,
+ start_mark: token.start_mark,
+ end_mark: token.end_mark,
+ }
+ skip_token(parser)
+ return true
+ }
+
+ context_mark := parser.marks[len(parser.marks)-1]
+ parser.marks = parser.marks[:len(parser.marks)-1]
+ return yaml_parser_set_parser_error_context(parser,
+ "while parsing a block mapping", context_mark,
+ "did not find expected key", token.start_mark)
+}
+
+// Parse the productions:
+// block_mapping ::= BLOCK-MAPPING_START
+//
+// ((KEY block_node_or_indentless_sequence?)?
+//
+// (VALUE block_node_or_indentless_sequence?)?)*
+// ***** *
+// BLOCK-END
+//
+//
+func yaml_parser_parse_block_mapping_value(parser *yaml_parser_t, event *yaml_event_t) bool {
+ token := peek_token(parser)
+ if token == nil {
+ return false
+ }
+ if token.typ == yaml_VALUE_TOKEN {
+ mark := token.end_mark
+ skip_token(parser)
+ token = peek_token(parser)
+ if token == nil {
+ return false
+ }
+ if token.typ != yaml_KEY_TOKEN &&
+ token.typ != yaml_VALUE_TOKEN &&
+ token.typ != yaml_BLOCK_END_TOKEN {
+ parser.states = append(parser.states, yaml_PARSE_BLOCK_MAPPING_KEY_STATE)
+ return yaml_parser_parse_node(parser, event, true, true)
+ } else {
+ parser.state = yaml_PARSE_BLOCK_MAPPING_KEY_STATE
+ return yaml_parser_process_empty_scalar(parser, event, mark)
+ }
+ } else {
+ parser.state = yaml_PARSE_BLOCK_MAPPING_KEY_STATE
+ return yaml_parser_process_empty_scalar(parser, event, token.start_mark)
+ }
+}
+
+// Parse the productions:
+// flow_sequence ::= FLOW-SEQUENCE-START
+// *******************
+// (flow_sequence_entry FLOW-ENTRY)*
+// * **********
+// flow_sequence_entry?
+// *
+// FLOW-SEQUENCE-END
+// *****************
+// flow_sequence_entry ::= flow_node | KEY flow_node? (VALUE flow_node?)?
+// *
+//
+func yaml_parser_parse_flow_sequence_entry(parser *yaml_parser_t, event *yaml_event_t, first bool) bool {
+ if first {
+ token := peek_token(parser)
+ parser.marks = append(parser.marks, token.start_mark)
+ skip_token(parser)
+ }
+ token := peek_token(parser)
+ if token == nil {
+ return false
+ }
+ if token.typ != yaml_FLOW_SEQUENCE_END_TOKEN {
+ if !first {
+ if token.typ == yaml_FLOW_ENTRY_TOKEN {
+ skip_token(parser)
+ token = peek_token(parser)
+ if token == nil {
+ return false
+ }
+ } else {
+ context_mark := parser.marks[len(parser.marks)-1]
+ parser.marks = parser.marks[:len(parser.marks)-1]
+ return yaml_parser_set_parser_error_context(parser,
+ "while parsing a flow sequence", context_mark,
+ "did not find expected ',' or ']'", token.start_mark)
+ }
+ }
+
+ if token.typ == yaml_KEY_TOKEN {
+ parser.state = yaml_PARSE_FLOW_SEQUENCE_ENTRY_MAPPING_KEY_STATE
+ *event = yaml_event_t{
+ typ: yaml_MAPPING_START_EVENT,
+ start_mark: token.start_mark,
+ end_mark: token.end_mark,
+ }
+ event.mapping_start.implicit = true
+ event.mapping_start.style = yaml_FLOW_MAPPING_STYLE
+ skip_token(parser)
+ return true
+ } else if token.typ != yaml_FLOW_SEQUENCE_END_TOKEN {
+ parser.states = append(parser.states, yaml_PARSE_FLOW_SEQUENCE_ENTRY_STATE)
+ return yaml_parser_parse_node(parser, event, false, false)
+ }
+ }
+
+ parser.state = parser.states[len(parser.states)-1]
+ parser.states = parser.states[:len(parser.states)-1]
+ parser.marks = parser.marks[:len(parser.marks)-1]
+
+ *event = yaml_event_t{
+ typ: yaml_SEQUENCE_END_EVENT,
+ start_mark: token.start_mark,
+ end_mark: token.end_mark,
+ }
+
+ skip_token(parser)
+ return true
+}
+
+//
+// Parse the productions:
+// flow_sequence_entry ::= flow_node | KEY flow_node? (VALUE flow_node?)?
+// *** *
+//
+func yaml_parser_parse_flow_sequence_entry_mapping_key(parser *yaml_parser_t, event *yaml_event_t) bool {
+ token := peek_token(parser)
+ if token == nil {
+ return false
+ }
+ if token.typ != yaml_VALUE_TOKEN &&
+ token.typ != yaml_FLOW_ENTRY_TOKEN &&
+ token.typ != yaml_FLOW_SEQUENCE_END_TOKEN {
+ parser.states = append(parser.states, yaml_PARSE_FLOW_SEQUENCE_ENTRY_MAPPING_VALUE_STATE)
+ return yaml_parser_parse_node(parser, event, false, false)
+ } else {
+ mark := token.end_mark
+ skip_token(parser)
+ parser.state = yaml_PARSE_FLOW_SEQUENCE_ENTRY_MAPPING_VALUE_STATE
+ return yaml_parser_process_empty_scalar(parser, event, mark)
+ }
+}
+
+// Parse the productions:
+// flow_sequence_entry ::= flow_node | KEY flow_node? (VALUE flow_node?)?
+// ***** *
+//
+func yaml_parser_parse_flow_sequence_entry_mapping_value(parser *yaml_parser_t, event *yaml_event_t) bool {
+ token := peek_token(parser)
+ if token == nil {
+ return false
+ }
+ if token.typ == yaml_VALUE_TOKEN {
+ skip_token(parser)
+ token := peek_token(parser)
+ if token == nil {
+ return false
+ }
+ if token.typ != yaml_FLOW_ENTRY_TOKEN && token.typ != yaml_FLOW_SEQUENCE_END_TOKEN {
+ parser.states = append(parser.states, yaml_PARSE_FLOW_SEQUENCE_ENTRY_MAPPING_END_STATE)
+ return yaml_parser_parse_node(parser, event, false, false)
+ }
+ }
+ parser.state = yaml_PARSE_FLOW_SEQUENCE_ENTRY_MAPPING_END_STATE
+ return yaml_parser_process_empty_scalar(parser, event, token.start_mark)
+}
+
+// Parse the productions:
+// flow_sequence_entry ::= flow_node | KEY flow_node? (VALUE flow_node?)?
+// *
+//
+func yaml_parser_parse_flow_sequence_entry_mapping_end(parser *yaml_parser_t, event *yaml_event_t) bool {
+ token := peek_token(parser)
+ if token == nil {
+ return false
+ }
+ parser.state = yaml_PARSE_FLOW_SEQUENCE_ENTRY_STATE
+ *event = yaml_event_t{
+ typ: yaml_MAPPING_END_EVENT,
+ start_mark: token.start_mark,
+ end_mark: token.start_mark, // [Go] Shouldn't this be end_mark?
+ }
+ return true
+}
+
+// Parse the productions:
+// flow_mapping ::= FLOW-MAPPING-START
+// ******************
+// (flow_mapping_entry FLOW-ENTRY)*
+// * **********
+// flow_mapping_entry?
+// ******************
+// FLOW-MAPPING-END
+// ****************
+// flow_mapping_entry ::= flow_node | KEY flow_node? (VALUE flow_node?)?
+// * *** *
+//
+func yaml_parser_parse_flow_mapping_key(parser *yaml_parser_t, event *yaml_event_t, first bool) bool {
+ if first {
+ token := peek_token(parser)
+ parser.marks = append(parser.marks, token.start_mark)
+ skip_token(parser)
+ }
+
+ token := peek_token(parser)
+ if token == nil {
+ return false
+ }
+
+ if token.typ != yaml_FLOW_MAPPING_END_TOKEN {
+ if !first {
+ if token.typ == yaml_FLOW_ENTRY_TOKEN {
+ skip_token(parser)
+ token = peek_token(parser)
+ if token == nil {
+ return false
+ }
+ } else {
+ context_mark := parser.marks[len(parser.marks)-1]
+ parser.marks = parser.marks[:len(parser.marks)-1]
+ return yaml_parser_set_parser_error_context(parser,
+ "while parsing a flow mapping", context_mark,
+ "did not find expected ',' or '}'", token.start_mark)
+ }
+ }
+
+ if token.typ == yaml_KEY_TOKEN {
+ skip_token(parser)
+ token = peek_token(parser)
+ if token == nil {
+ return false
+ }
+ if token.typ != yaml_VALUE_TOKEN &&
+ token.typ != yaml_FLOW_ENTRY_TOKEN &&
+ token.typ != yaml_FLOW_MAPPING_END_TOKEN {
+ parser.states = append(parser.states, yaml_PARSE_FLOW_MAPPING_VALUE_STATE)
+ return yaml_parser_parse_node(parser, event, false, false)
+ } else {
+ parser.state = yaml_PARSE_FLOW_MAPPING_VALUE_STATE
+ return yaml_parser_process_empty_scalar(parser, event, token.start_mark)
+ }
+ } else if token.typ != yaml_FLOW_MAPPING_END_TOKEN {
+ parser.states = append(parser.states, yaml_PARSE_FLOW_MAPPING_EMPTY_VALUE_STATE)
+ return yaml_parser_parse_node(parser, event, false, false)
+ }
+ }
+
+ parser.state = parser.states[len(parser.states)-1]
+ parser.states = parser.states[:len(parser.states)-1]
+ parser.marks = parser.marks[:len(parser.marks)-1]
+ *event = yaml_event_t{
+ typ: yaml_MAPPING_END_EVENT,
+ start_mark: token.start_mark,
+ end_mark: token.end_mark,
+ }
+ skip_token(parser)
+ return true
+}
+
+// Parse the productions:
+// flow_mapping_entry ::= flow_node | KEY flow_node? (VALUE flow_node?)?
+// * ***** *
+//
+func yaml_parser_parse_flow_mapping_value(parser *yaml_parser_t, event *yaml_event_t, empty bool) bool {
+ token := peek_token(parser)
+ if token == nil {
+ return false
+ }
+ if empty {
+ parser.state = yaml_PARSE_FLOW_MAPPING_KEY_STATE
+ return yaml_parser_process_empty_scalar(parser, event, token.start_mark)
+ }
+ if token.typ == yaml_VALUE_TOKEN {
+ skip_token(parser)
+ token = peek_token(parser)
+ if token == nil {
+ return false
+ }
+ if token.typ != yaml_FLOW_ENTRY_TOKEN && token.typ != yaml_FLOW_MAPPING_END_TOKEN {
+ parser.states = append(parser.states, yaml_PARSE_FLOW_MAPPING_KEY_STATE)
+ return yaml_parser_parse_node(parser, event, false, false)
+ }
+ }
+ parser.state = yaml_PARSE_FLOW_MAPPING_KEY_STATE
+ return yaml_parser_process_empty_scalar(parser, event, token.start_mark)
+}
+
+// Generate an empty scalar event.
+func yaml_parser_process_empty_scalar(parser *yaml_parser_t, event *yaml_event_t, mark yaml_mark_t) bool {
+ *event = yaml_event_t{
+ typ: yaml_SCALAR_EVENT,
+ start_mark: mark,
+ end_mark: mark,
+ }
+ event.scalar.plain_implicit = true
+ event.scalar.style = yaml_PLAIN_SCALAR_STYLE
+ // Empty means len(event.scalar.value) == 0
+ return true
+}
+
+var default_tag_directives = []yaml_tag_directive_t{
+ {[]byte("!"), []byte("!")},
+ {[]byte("!!"), []byte("tag:yaml.org,2002:")},
+}
+
+// Parse directives.
+func yaml_parser_process_directives(parser *yaml_parser_t,
+ version_directive_ref **yaml_version_directive_t,
+ tag_directives_ref *[]yaml_tag_directive_t) bool {
+
+ var version_directive *yaml_version_directive_t
+ var tag_directives []yaml_tag_directive_t
+
+ token := peek_token(parser)
+ if token == nil {
+ return false
+ }
+
+ for token.typ == yaml_VERSION_DIRECTIVE_TOKEN || token.typ == yaml_TAG_DIRECTIVE_TOKEN {
+ if token.typ == yaml_VERSION_DIRECTIVE_TOKEN {
+ if version_directive != nil {
+ yaml_parser_set_parser_error(parser,
+ "found duplicate %YAML directive", token.start_mark)
+ return false
+ }
+ if token.version_directive.major != 1 || token.version_directive.minor != 1 {
+ yaml_parser_set_parser_error(parser,
+ "found incompatible YAML document", token.start_mark)
+ return false
+ }
+ version_directive = &yaml_version_directive_t{
+ major: token.version_directive.major,
+ minor: token.version_directive.minor,
+ }
+ } else if token.typ == yaml_TAG_DIRECTIVE_TOKEN {
+ value := yaml_tag_directive_t{
+ handle: token.tag_directive.handle,
+ prefix: token.tag_directive.prefix,
+ }
+ if !yaml_parser_append_tag_directive(parser, value, false, token.start_mark) {
+ return false
+ }
+ tag_directives = append(tag_directives, value)
+ }
+
+ skip_token(parser)
+ token = peek_token(parser)
+ if token == nil {
+ return false
+ }
+ }
+
+ for i := range default_tag_directives {
+ if !yaml_parser_append_tag_directive(parser, default_tag_directives[i], true, token.start_mark) {
+ return false
+ }
+ }
+
+ if version_directive_ref != nil {
+ *version_directive_ref = version_directive
+ }
+ if tag_directives_ref != nil {
+ *tag_directives_ref = tag_directives
+ }
+ return true
+}
+
+// Append a tag directive to the directives stack.
+func yaml_parser_append_tag_directive(parser *yaml_parser_t, value yaml_tag_directive_t, allow_duplicates bool, mark yaml_mark_t) bool {
+ for i := range parser.tag_directives {
+ if bytes.Equal(value.handle, parser.tag_directives[i].handle) {
+ if allow_duplicates {
+ return true
+ }
+ return yaml_parser_set_parser_error(parser, "found duplicate %TAG directive", mark)
+ }
+ }
+
+ // [Go] I suspect the copy is unnecessary. This was likely done
+ // because there was no way to track ownership of the data.
+ value_copy := yaml_tag_directive_t{
+ handle: make([]byte, len(value.handle)),
+ prefix: make([]byte, len(value.prefix)),
+ }
+ copy(value_copy.handle, value.handle)
+ copy(value_copy.prefix, value.prefix)
+ parser.tag_directives = append(parser.tag_directives, value_copy)
+ return true
+}
diff --git a/reader_c.go b/reader_c.go
new file mode 100644
index 0000000..e3a8eae
--- /dev/null
+++ b/reader_c.go
@@ -0,0 +1,397 @@
+package goyaml
+
+import (
+ "io"
+)
+
+// Set the reader error and return 0.
+func yaml_parser_set_reader_error(parser *yaml_parser_t, problem string, offset int, value int) bool {
+ parser.error = yaml_READER_ERROR
+ parser.problem = problem
+ parser.problem_offset = offset
+ parser.problem_value = value
+ return false
+}
+
+// Byte order marks.
+const (
+ bom_UTF8 = "\xef\xbb\xbf"
+ bom_UTF16LE = "\xff\xfe"
+ bom_UTF16BE = "\xfe\xff"
+)
+
+// Determine the input stream encoding by checking the BOM symbol. If no BOM is
+// found, the UTF-8 encoding is assumed. Return 1 on success, 0 on failure.
+func yaml_parser_determine_encoding(parser *yaml_parser_t) bool {
+ // Ensure that we had enough bytes in the raw buffer.
+ for !parser.eof && len(parser.raw_buffer)-parser.raw_buffer_pos < 3 {
+ if !yaml_parser_update_raw_buffer(parser) {
+ return false
+ }
+ }
+
+ // Determine the encoding.
+ buf := parser.raw_buffer
+ pos := parser.raw_buffer_pos
+ avail := len(buf) - pos
+ if avail >= 2 && buf[pos] == bom_UTF16LE[0] && buf[pos+1] == bom_UTF16LE[1] {
+ parser.encoding = yaml_UTF16LE_ENCODING
+ parser.raw_buffer_pos += 2
+ parser.offset += 2
+ } else if avail >= 2 && buf[pos] == bom_UTF16BE[0] && buf[pos+1] == bom_UTF16BE[1] {
+ parser.encoding = yaml_UTF16BE_ENCODING
+ parser.raw_buffer_pos += 2
+ parser.offset += 2
+ } else if avail >= 3 && buf[pos] == bom_UTF8[0] && buf[pos+1] == bom_UTF8[1] && buf[pos+2] == bom_UTF8[2] {
+ parser.encoding = yaml_UTF8_ENCODING
+ parser.raw_buffer_pos += 3
+ parser.offset += 3
+ } else {
+ parser.encoding = yaml_UTF8_ENCODING
+ }
+ return true
+}
+
+// Update the raw buffer.
+func yaml_parser_update_raw_buffer(parser *yaml_parser_t) bool {
+ size_read := 0
+
+ // Return if the raw buffer is full.
+ if parser.raw_buffer_pos == 0 && len(parser.raw_buffer) == cap(parser.raw_buffer) {
+ return true
+ }
+
+ // Return on EOF.
+ if parser.eof {
+ return true
+ }
+
+ // Move the remaining bytes in the raw buffer to the beginning.
+ if parser.raw_buffer_pos > 0 && parser.raw_buffer_pos < len(parser.raw_buffer) {
+ copy(parser.raw_buffer, parser.raw_buffer[parser.raw_buffer_pos:])
+ }
+ parser.raw_buffer = parser.raw_buffer[:len(parser.raw_buffer)-parser.raw_buffer_pos]
+ parser.raw_buffer_pos = 0
+
+ // Call the read handler to fill the buffer.
+ size_read, err := parser.read_handler(parser, parser.raw_buffer[len(parser.raw_buffer):cap(parser.raw_buffer)])
+ parser.raw_buffer = parser.raw_buffer[:len(parser.raw_buffer)+size_read]
+ if err == io.EOF {
+ parser.eof = true
+ } else if err != nil {
+ return yaml_parser_set_reader_error(parser, "input error: "+err.Error(), parser.offset, -1)
+ }
+ return true
+}
+
+// Ensure that the buffer contains at least `length` characters.
+// Return true on success, false on failure.
+//
+// The length is supposed to be significantly less that the buffer size.
+func yaml_parser_update_buffer(parser *yaml_parser_t, length int) bool {
+ if parser.read_handler == nil {
+ panic("read handler must be set")
+ }
+
+ // If the EOF flag is set and the raw buffer is empty, do nothing.
+ if parser.eof && parser.raw_buffer_pos == len(parser.raw_buffer) {
+ return true
+ }
+
+ // Return if the buffer contains enough characters.
+ if parser.unread >= length {
+ return true
+ }
+
+ // Determine the input encoding if it is not known yet.
+ if parser.encoding == yaml_ANY_ENCODING {
+ if !yaml_parser_determine_encoding(parser) {
+ return false
+ }
+ }
+
+ // Move the unread characters to the beginning of the buffer.
+ if parser.buffer_pos > 0 && parser.buffer_pos < len(parser.buffer) {
+ size := len(parser.buffer) - parser.buffer_pos
+ copy(parser.buffer, parser.buffer[parser.buffer_pos:])
+ parser.buffer_pos = 0
+ parser.buffer = parser.buffer[:size]
+ } else if parser.buffer_pos == len(parser.buffer) {
+ parser.buffer_pos = 0
+ parser.buffer = parser.buffer[:0]
+ }
+
+ // Fill the buffer until it has enough characters.
+ first := true
+ for parser.unread < length {
+
+ // Fill the raw buffer if necessary.
+ if !first || parser.raw_buffer_pos == len(parser.raw_buffer) {
+ if !yaml_parser_update_raw_buffer(parser) {
+ return false
+ }
+ }
+ first = false
+
+ // Decode the raw buffer.
+ for parser.raw_buffer_pos != len(parser.raw_buffer) {
+ var value, value2 rune
+ var incomplete bool
+ var width int
+
+ raw_unread := len(parser.raw_buffer) - parser.raw_buffer_pos
+
+ // Decode the next character.
+ switch parser.encoding {
+ case yaml_UTF8_ENCODING:
+ // Decode a UTF-8 character. Check RFC 3629
+ // (http://www.ietf.org/rfc/rfc3629.txt) for more details.
+ //
+ // The following table (taken from the RFC) is used for
+ // decoding.
+ //
+ // Char. number range | UTF-8 octet sequence
+ // (hexadecimal) | (binary)
+ // --------------------+------------------------------------
+ // 0000 0000-0000 007F | 0xxxxxxx
+ // 0000 0080-0000 07FF | 110xxxxx 10xxxxxx
+ // 0000 0800-0000 FFFF | 1110xxxx 10xxxxxx 10xxxxxx
+ // 0001 0000-0010 FFFF | 11110xxx 10xxxxxx 10xxxxxx 10xxxxxx
+ //
+ // Additionally, the characters in the range 0xD800-0xDFFF
+ // are prohibited as they are reserved for use with UTF-16
+ // surrogate pairs.
+
+ // Determine the length of the UTF-8 sequence.
+ octet := parser.raw_buffer[parser.raw_buffer_pos]
+ switch {
+ case octet&0x80 == 0x00:
+ width = 1
+ case octet&0xE0 == 0xC0:
+ width = 2
+ case octet&0xF0 == 0xE0:
+ width = 3
+ case octet&0xF8 == 0xF0:
+ width = 4
+ default:
+ // The leading octet is invalid.
+ return yaml_parser_set_reader_error(parser,
+ "invalid leading UTF-8 octet",
+ parser.offset, int(octet))
+ }
+
+ // Check if the raw buffer contains an incomplete character.
+ if width > raw_unread {
+ if parser.eof {
+ return yaml_parser_set_reader_error(parser,
+ "incomplete UTF-8 octet sequence",
+ parser.offset, -1)
+ }
+ incomplete = true
+ break
+ }
+
+ // Decode the leading octet.
+ switch {
+ case octet&0x80 == 0x00:
+ value = rune(octet & 0x7F)
+ case octet&0xE0 == 0xC0:
+ value = rune(octet & 0x1F)
+ case octet&0xF0 == 0xE0:
+ value = rune(octet & 0x0F)
+ case octet&0xF8 == 0xF0:
+ value = rune(octet & 0x07)
+ default:
+ value = 0
+ }
+
+ // Check and decode the trailing octets.
+ for k := 1; k < width; k++ {
+ octet = parser.raw_buffer[parser.raw_buffer_pos+k]
+
+ // Check if the octet is valid.
+ if (octet & 0xC0) != 0x80 {
+ return yaml_parser_set_reader_error(parser,
+ "invalid trailing UTF-8 octet",
+ parser.offset+k, int(octet))
+ }
+
+ // Decode the octet.
+ value = (value << 6) + rune(octet&0x3F)
+ }
+
+ // Check the length of the sequence against the value.
+ switch {
+ case width == 1:
+ case width == 2 && value >= 0x80:
+ case width == 3 && value >= 0x800:
+ case width == 4 && value >= 0x10000:
+ default:
+ return yaml_parser_set_reader_error(parser,
+ "invalid length of a UTF-8 sequence",
+ parser.offset, -1)
+ }
+
+ // Check the range of the value.
+ if value >= 0xD800 && value <= 0xDFFF || value > 0x10FFFF {
+ return yaml_parser_set_reader_error(parser,
+ "invalid Unicode character",
+ parser.offset, int(value))
+ }
+
+ case yaml_UTF16LE_ENCODING, yaml_UTF16BE_ENCODING:
+ var low, high int
+ if parser.encoding == yaml_UTF16LE_ENCODING {
+ low, high = 0, 1
+ } else {
+ high, low = 1, 0
+ }
+
+ // The UTF-16 encoding is not as simple as one might
+ // naively think. Check RFC 2781
+ // (http://www.ietf.org/rfc/rfc2781.txt).
+ //
+ // Normally, two subsequent bytes describe a Unicode
+ // character. However a special technique (called a
+ // surrogate pair) is used for specifying character
+ // values larger than 0xFFFF.
+ //
+ // A surrogate pair consists of two pseudo-characters:
+ // high surrogate area (0xD800-0xDBFF)
+ // low surrogate area (0xDC00-0xDFFF)
+ //
+ // The following formulas are used for decoding
+ // and encoding characters using surrogate pairs:
+ //
+ // U = U' + 0x10000 (0x01 00 00 <= U <= 0x10 FF FF)
+ // U' = yyyyyyyyyyxxxxxxxxxx (0 <= U' <= 0x0F FF FF)
+ // W1 = 110110yyyyyyyyyy
+ // W2 = 110111xxxxxxxxxx
+ //
+ // where U is the character value, W1 is the high surrogate
+ // area, W2 is the low surrogate area.
+
+ // Check for incomplete UTF-16 character.
+ if raw_unread < 2 {
+ if parser.eof {
+ return yaml_parser_set_reader_error(parser,
+ "incomplete UTF-16 character",
+ parser.offset, -1)
+ }
+ incomplete = true
+ break
+ }
+
+ // Get the character.
+ value = rune(parser.raw_buffer[parser.raw_buffer_pos+low]) +
+ (rune(parser.raw_buffer[parser.raw_buffer_pos+high]) << 8)
+
+ // Check for unexpected low surrogate area.
+ if value&0xFC00 == 0xDC00 {
+ return yaml_parser_set_reader_error(parser,
+ "unexpected low surrogate area",
+ parser.offset, int(value))
+ }
+
+ // Check for a high surrogate area.
+ if value&0xFC00 == 0xD800 {
+ width = 4
+
+ // Check for incomplete surrogate pair.
+ if raw_unread < 4 {
+ if parser.eof {
+ return yaml_parser_set_reader_error(parser,
+ "incomplete UTF-16 surrogate pair",
+ parser.offset, -1)
+ }
+ incomplete = true
+ break
+ }
+
+ // Get the next character.
+ value2 = rune(parser.raw_buffer[parser.raw_buffer_pos+low+2]) +
+ (rune(parser.raw_buffer[parser.raw_buffer_pos+high+2]) << 8)
+
+ // Check for a low surrogate area.
+ if value2&0xFC00 != 0xDC00 {
+ return yaml_parser_set_reader_error(parser,
+ "expected low surrogate area",
+ parser.offset+2, int(value2))
+ }
+
+ // Generate the value of the surrogate pair.
+ value = 0x10000 + ((value & 0x3FF) << 10) + (value2 & 0x3FF)
+ } else {
+ width = 2
+ }
+
+ default:
+ panic("impossible")
+ }
+
+ // Check if the raw buffer contains enough bytes to form a character.
+ if incomplete {
+ break
+ }
+
+ // Check if the character is in the allowed range:
+ // #x9 | #xA | #xD | [#x20-#x7E] (8 bit)
+ // | #x85 | [#xA0-#xD7FF] | [#xE000-#xFFFD] (16 bit)
+ // | [#x10000-#x10FFFF] (32 bit)
+ switch {
+ case value == 0x09:
+ case value == 0x0A:
+ case value == 0x0D:
+ case value >= 0x20 && value <= 0x7E:
+ case value == 0x85:
+ case value >= 0xA0 && value <= 0xD7FF:
+ case value >= 0xE000 && value <= 0xFFFD:
+ case value >= 0x10000 && value <= 0x10FFFF:
+ default:
+ return yaml_parser_set_reader_error(parser,
+ "control characters are not allowed",
+ parser.offset, int(value))
+ }
+
+ // Move the raw pointers.
+ parser.raw_buffer_pos += width
+ parser.offset += width
+
+ pos := len(parser.buffer)
+ parser.buffer = parser.buffer[:pos+width]
+
+ // Finally put the character into the buffer.
+ if value <= 0x7F {
+ // 0000 0000-0000 007F . 0xxxxxxx
+ parser.buffer[pos+0] = byte(value)
+ } else if value <= 0x7FF {
+ // 0000 0080-0000 07FF . 110xxxxx 10xxxxxx
+ parser.buffer[pos+0] = byte(0xC0 + (value >> 6))
+ parser.buffer[pos+1] = byte(0x80 + (value & 0x3F))
+ } else if value <= 0xFFFF {
+ // 0000 0800-0000 FFFF . 1110xxxx 10xxxxxx 10xxxxxx
+ parser.buffer[pos+0] = byte(0xE0 + (value >> 12))
+ parser.buffer[pos+1] = byte(0x80 + ((value >> 6) & 0x3F))
+ parser.buffer[pos+2] = byte(0x80 + (value & 0x3F))
+ } else {
+ // 0001 0000-0010 FFFF . 11110xxx 10xxxxxx 10xxxxxx 10xxxxxx
+ parser.buffer[pos+0] = byte(0xF0 + (value >> 18))
+ parser.buffer[pos+1] = byte(0x80 + ((value >> 12) & 0x3F))
+ parser.buffer[pos+2] = byte(0x80 + ((value >> 6) & 0x3F))
+ parser.buffer[pos+3] = byte(0x80 + (value & 0x3F))
+ }
+
+ parser.unread++
+ }
+
+ // On EOF, put NUL into the buffer and return.
+ if parser.eof {
+ parser.buffer = parser.buffer[:len(parser.buffer)+1]
+ parser.buffer[len(parser.buffer)-1] = 0x00
+ parser.unread++
+ return true
+ }
+ }
+
+ return true
+}
diff --git a/scanner_c.go b/scanner_c.go
new file mode 100644
index 0000000..e926272
--- /dev/null
+++ b/scanner_c.go
@@ -0,0 +1,2728 @@
+package goyaml
+
+import (
+ "bytes"
+)
+
+// Introduction
+// ************
+//
+// The following notes assume that you are familiar with the YAML specification
+// (http://yaml.org/spec/cvs/current.html). We mostly follow it, although in
+// some cases we are less restrictive that it requires.
+//
+// The process of transforming a YAML stream into a sequence of events is
+// divided on two steps: Scanning and Parsing.
+//
+// The Scanner transforms the input stream into a sequence of tokens, while the
+// parser transform the sequence of tokens produced by the Scanner into a
+// sequence of parsing events.
+//
+// The Scanner is rather clever and complicated. The Parser, on the contrary,
+// is a straightforward implementation of a recursive-descendant parser (or,
+// LL(1) parser, as it is usually called).
+//
+// Actually there are two issues of Scanning that might be called "clever", the
+// rest is quite straightforward. The issues are "block collection start" and
+// "simple keys". Both issues are explained below in details.
+//
+// Here the Scanning step is explained and implemented. We start with the list
+// of all the tokens produced by the Scanner together with short descriptions.
+//
+// Now, tokens:
+//
+// STREAM-START(encoding) # The stream start.
+// STREAM-END # The stream end.
+// VERSION-DIRECTIVE(major,minor) # The '%YAML' directive.
+// TAG-DIRECTIVE(handle,prefix) # The '%TAG' directive.
+// DOCUMENT-START # '---'
+// DOCUMENT-END # '...'
+// BLOCK-SEQUENCE-START # Indentation increase denoting a block
+// BLOCK-MAPPING-START # sequence or a block mapping.
+// BLOCK-END # Indentation decrease.
+// FLOW-SEQUENCE-START # '['
+// FLOW-SEQUENCE-END # ']'
+// BLOCK-SEQUENCE-START # '{'
+// BLOCK-SEQUENCE-END # '}'
+// BLOCK-ENTRY # '-'
+// FLOW-ENTRY # ','
+// KEY # '?' or nothing (simple keys).
+// VALUE # ':'
+// ALIAS(anchor) # '*anchor'
+// ANCHOR(anchor) # '&anchor'
+// TAG(handle,suffix) # '!handle!suffix'
+// SCALAR(value,style) # A scalar.
+//
+// The following two tokens are "virtual" tokens denoting the beginning and the
+// end of the stream:
+//
+// STREAM-START(encoding)
+// STREAM-END
+//
+// We pass the information about the input stream encoding with the
+// STREAM-START token.
+//
+// The next two tokens are responsible for tags:
+//
+// VERSION-DIRECTIVE(major,minor)
+// TAG-DIRECTIVE(handle,prefix)
+//
+// Example:
+//
+// %YAML 1.1
+// %TAG ! !foo
+// %TAG !yaml! tag:yaml.org,2002:
+// ---
+//
+// The correspoding sequence of tokens:
+//
+// STREAM-START(utf-8)
+// VERSION-DIRECTIVE(1,1)
+// TAG-DIRECTIVE("!","!foo")
+// TAG-DIRECTIVE("!yaml","tag:yaml.org,2002:")
+// DOCUMENT-START
+// STREAM-END
+//
+// Note that the VERSION-DIRECTIVE and TAG-DIRECTIVE tokens occupy a whole
+// line.
+//
+// The document start and end indicators are represented by:
+//
+// DOCUMENT-START
+// DOCUMENT-END
+//
+// Note that if a YAML stream contains an implicit document (without '---'
+// and '...' indicators), no DOCUMENT-START and DOCUMENT-END tokens will be
+// produced.
+//
+// In the following examples, we present whole documents together with the
+// produced tokens.
+//
+// 1. An implicit document:
+//
+// 'a scalar'
+//
+// Tokens:
+//
+// STREAM-START(utf-8)
+// SCALAR("a scalar",single-quoted)
+// STREAM-END
+//
+// 2. An explicit document:
+//
+// ---
+// 'a scalar'
+// ...
+//
+// Tokens:
+//
+// STREAM-START(utf-8)
+// DOCUMENT-START
+// SCALAR("a scalar",single-quoted)
+// DOCUMENT-END
+// STREAM-END
+//
+// 3. Several documents in a stream:
+//
+// 'a scalar'
+// ---
+// 'another scalar'
+// ---
+// 'yet another scalar'
+//
+// Tokens:
+//
+// STREAM-START(utf-8)
+// SCALAR("a scalar",single-quoted)
+// DOCUMENT-START
+// SCALAR("another scalar",single-quoted)
+// DOCUMENT-START
+// SCALAR("yet another scalar",single-quoted)
+// STREAM-END
+//
+// We have already introduced the SCALAR token above. The following tokens are
+// used to describe aliases, anchors, tag, and scalars:
+//
+// ALIAS(anchor)
+// ANCHOR(anchor)
+// TAG(handle,suffix)
+// SCALAR(value,style)
+//
+// The following series of examples illustrate the usage of these tokens:
+//
+// 1. A recursive sequence:
+//
+// &A [ *A ]
+//
+// Tokens:
+//
+// STREAM-START(utf-8)
+// ANCHOR("A")
+// FLOW-SEQUENCE-START
+// ALIAS("A")
+// FLOW-SEQUENCE-END
+// STREAM-END
+//
+// 2. A tagged scalar:
+//
+// !!float "3.14" # A good approximation.
+//
+// Tokens:
+//
+// STREAM-START(utf-8)
+// TAG("!!","float")
+// SCALAR("3.14",double-quoted)
+// STREAM-END
+//
+// 3. Various scalar styles:
+//
+// --- # Implicit empty plain scalars do not produce tokens.
+// --- a plain scalar
+// --- 'a single-quoted scalar'
+// --- "a double-quoted scalar"
+// --- |-
+// a literal scalar
+// --- >-
+// a folded
+// scalar
+//
+// Tokens:
+//
+// STREAM-START(utf-8)
+// DOCUMENT-START
+// DOCUMENT-START
+// SCALAR("a plain scalar",plain)
+// DOCUMENT-START
+// SCALAR("a single-quoted scalar",single-quoted)
+// DOCUMENT-START
+// SCALAR("a double-quoted scalar",double-quoted)
+// DOCUMENT-START
+// SCALAR("a literal scalar",literal)
+// DOCUMENT-START
+// SCALAR("a folded scalar",folded)
+// STREAM-END
+//
+// Now it's time to review collection-related tokens. We will start with
+// flow collections:
+//
+// FLOW-SEQUENCE-START
+// FLOW-SEQUENCE-END
+// FLOW-MAPPING-START
+// FLOW-MAPPING-END
+// FLOW-ENTRY
+// KEY
+// VALUE
+//
+// The tokens FLOW-SEQUENCE-START, FLOW-SEQUENCE-END, FLOW-MAPPING-START, and
+// FLOW-MAPPING-END represent the indicators '[', ']', '{', and '}'
+// correspondingly. FLOW-ENTRY represent the ',' indicator. Finally the
+// indicators '?' and ':', which are used for denoting mapping keys and values,
+// are represented by the KEY and VALUE tokens.
+//
+// The following examples show flow collections:
+//
+// 1. A flow sequence:
+//
+// [item 1, item 2, item 3]
+//
+// Tokens:
+//
+// STREAM-START(utf-8)
+// FLOW-SEQUENCE-START
+// SCALAR("item 1",plain)
+// FLOW-ENTRY
+// SCALAR("item 2",plain)
+// FLOW-ENTRY
+// SCALAR("item 3",plain)
+// FLOW-SEQUENCE-END
+// STREAM-END
+//
+// 2. A flow mapping:
+//
+// {
+// a simple key: a value, # Note that the KEY token is produced.
+// ? a complex key: another value,
+// }
+//
+// Tokens:
+//
+// STREAM-START(utf-8)
+// FLOW-MAPPING-START
+// KEY
+// SCALAR("a simple key",plain)
+// VALUE
+// SCALAR("a value",plain)
+// FLOW-ENTRY
+// KEY
+// SCALAR("a complex key",plain)
+// VALUE
+// SCALAR("another value",plain)
+// FLOW-ENTRY
+// FLOW-MAPPING-END
+// STREAM-END
+//
+// A simple key is a key which is not denoted by the '?' indicator. Note that
+// the Scanner still produce the KEY token whenever it encounters a simple key.
+//
+// For scanning block collections, the following tokens are used (note that we
+// repeat KEY and VALUE here):
+//
+// BLOCK-SEQUENCE-START
+// BLOCK-MAPPING-START
+// BLOCK-END
+// BLOCK-ENTRY
+// KEY
+// VALUE
+//
+// The tokens BLOCK-SEQUENCE-START and BLOCK-MAPPING-START denote indentation
+// increase that precedes a block collection (cf. the INDENT token in Python).
+// The token BLOCK-END denote indentation decrease that ends a block collection
+// (cf. the DEDENT token in Python). However YAML has some syntax pecularities
+// that makes detections of these tokens more complex.
+//
+// The tokens BLOCK-ENTRY, KEY, and VALUE are used to represent the indicators
+// '-', '?', and ':' correspondingly.
+//
+// The following examples show how the tokens BLOCK-SEQUENCE-START,
+// BLOCK-MAPPING-START, and BLOCK-END are emitted by the Scanner:
+//
+// 1. Block sequences:
+//
+// - item 1
+// - item 2
+// -
+// - item 3.1
+// - item 3.2
+// -
+// key 1: value 1
+// key 2: value 2
+//
+// Tokens:
+//
+// STREAM-START(utf-8)
+// BLOCK-SEQUENCE-START
+// BLOCK-ENTRY
+// SCALAR("item 1",plain)
+// BLOCK-ENTRY
+// SCALAR("item 2",plain)
+// BLOCK-ENTRY
+// BLOCK-SEQUENCE-START
+// BLOCK-ENTRY
+// SCALAR("item 3.1",plain)
+// BLOCK-ENTRY
+// SCALAR("item 3.2",plain)
+// BLOCK-END
+// BLOCK-ENTRY
+// BLOCK-MAPPING-START
+// KEY
+// SCALAR("key 1",plain)
+// VALUE
+// SCALAR("value 1",plain)
+// KEY
+// SCALAR("key 2",plain)
+// VALUE
+// SCALAR("value 2",plain)
+// BLOCK-END
+// BLOCK-END
+// STREAM-END
+//
+// 2. Block mappings:
+//
+// a simple key: a value # The KEY token is produced here.
+// ? a complex key
+// : another value
+// a mapping:
+// key 1: value 1
+// key 2: value 2
+// a sequence:
+// - item 1
+// - item 2
+//
+// Tokens:
+//
+// STREAM-START(utf-8)
+// BLOCK-MAPPING-START
+// KEY
+// SCALAR("a simple key",plain)
+// VALUE
+// SCALAR("a value",plain)
+// KEY
+// SCALAR("a complex key",plain)
+// VALUE
+// SCALAR("another value",plain)
+// KEY
+// SCALAR("a mapping",plain)
+// BLOCK-MAPPING-START
+// KEY
+// SCALAR("key 1",plain)
+// VALUE
+// SCALAR("value 1",plain)
+// KEY
+// SCALAR("key 2",plain)
+// VALUE
+// SCALAR("value 2",plain)
+// BLOCK-END
+// KEY
+// SCALAR("a sequence",plain)
+// VALUE
+// BLOCK-SEQUENCE-START
+// BLOCK-ENTRY
+// SCALAR("item 1",plain)
+// BLOCK-ENTRY
+// SCALAR("item 2",plain)
+// BLOCK-END
+// BLOCK-END
+// STREAM-END
+//
+// YAML does not always require to start a new block collection from a new
+// line. If the current line contains only '-', '?', and ':' indicators, a new
+// block collection may start at the current line. The following examples
+// illustrate this case:
+//
+// 1. Collections in a sequence:
+//
+// - - item 1
+// - item 2
+// - key 1: value 1
+// key 2: value 2
+// - ? complex key
+// : complex value
+//
+// Tokens:
+//
+// STREAM-START(utf-8)
+// BLOCK-SEQUENCE-START
+// BLOCK-ENTRY
+// BLOCK-SEQUENCE-START
+// BLOCK-ENTRY
+// SCALAR("item 1",plain)
+// BLOCK-ENTRY
+// SCALAR("item 2",plain)
+// BLOCK-END
+// BLOCK-ENTRY
+// BLOCK-MAPPING-START
+// KEY
+// SCALAR("key 1",plain)
+// VALUE
+// SCALAR("value 1",plain)
+// KEY
+// SCALAR("key 2",plain)
+// VALUE
+// SCALAR("value 2",plain)
+// BLOCK-END
+// BLOCK-ENTRY
+// BLOCK-MAPPING-START
+// KEY
+// SCALAR("complex key")
+// VALUE
+// SCALAR("complex value")
+// BLOCK-END
+// BLOCK-END
+// STREAM-END
+//
+// 2. Collections in a mapping:
+//
+// ? a sequence
+// : - item 1
+// - item 2
+// ? a mapping
+// : key 1: value 1
+// key 2: value 2
+//
+// Tokens:
+//
+// STREAM-START(utf-8)
+// BLOCK-MAPPING-START
+// KEY
+// SCALAR("a sequence",plain)
+// VALUE
+// BLOCK-SEQUENCE-START
+// BLOCK-ENTRY
+// SCALAR("item 1",plain)
+// BLOCK-ENTRY
+// SCALAR("item 2",plain)
+// BLOCK-END
+// KEY
+// SCALAR("a mapping",plain)
+// VALUE
+// BLOCK-MAPPING-START
+// KEY
+// SCALAR("key 1",plain)
+// VALUE
+// SCALAR("value 1",plain)
+// KEY
+// SCALAR("key 2",plain)
+// VALUE
+// SCALAR("value 2",plain)
+// BLOCK-END
+// BLOCK-END
+// STREAM-END
+//
+// YAML also permits non-indented sequences if they are included into a block
+// mapping. In this case, the token BLOCK-SEQUENCE-START is not produced:
+//
+// key:
+// - item 1 # BLOCK-SEQUENCE-START is NOT produced here.
+// - item 2
+//
+// Tokens:
+//
+// STREAM-START(utf-8)
+// BLOCK-MAPPING-START
+// KEY
+// SCALAR("key",plain)
+// VALUE
+// BLOCK-ENTRY
+// SCALAR("item 1",plain)
+// BLOCK-ENTRY
+// SCALAR("item 2",plain)
+// BLOCK-END
+//
+
+// Ensure that the buffer contains the required number of characters.
+// Return 1 on success, 0 on failure (reader error or memory error).
+func cache(parser *yaml_parser_t, length int) bool {
+ return parser.unread >= length || yaml_parser_update_buffer(parser, length)
+}
+
+// Advance the buffer pointer.
+func skip(parser *yaml_parser_t) {
+ parser.mark.index++
+ parser.mark.column++
+ parser.unread--
+ parser.buffer_pos += width(parser.buffer[parser.buffer_pos])
+}
+
+func skip_line(parser *yaml_parser_t) {
+ if is_crlf(parser.buffer, parser.buffer_pos) {
+ parser.mark.index += 2
+ parser.mark.column = 0
+ parser.mark.line++
+ parser.unread -= 2
+ parser.buffer_pos += 2
+ } else if is_break(parser.buffer, parser.buffer_pos) {
+ parser.mark.index++
+ parser.mark.column = 0
+ parser.mark.line++
+ parser.unread--
+ parser.buffer_pos += width(parser.buffer[parser.buffer_pos])
+ }
+}
+
+// Copy a character to a string buffer and advance pointers.
+func read(parser *yaml_parser_t, s *[]byte) bool {
+ buf := parser.buffer
+ pos := parser.buffer_pos
+ w := width(buf[0])
+ *s = append(*s, buf[pos:pos+w]...)
+ parser.buffer_pos += w
+ parser.mark.index++
+ parser.mark.column++
+ parser.unread--
+ return true
+}
+
+// Copy a line break character to a string buffer and advance pointers.
+func read_line(parser *yaml_parser_t, s *[]byte) bool {
+ buf := parser.buffer
+ pos := parser.buffer_pos
+ switch {
+ case buf[pos] == '\r' && buf[pos+1] == '\n':
+ // CR LF . LF
+ *s = append(*s, '\n')
+ parser.buffer_pos += 2
+ parser.mark.index++
+ parser.unread--
+ case buf[pos] == '\r' || buf[pos+1] == '\n':
+ // CR|LF . LF
+ *s = append(*s, '\n')
+ parser.buffer_pos += 1
+ case buf[pos] == '\xC2' && buf[pos+1] == '\x85':
+ // NEL . LF
+ *s = append(*s, '\n')
+ parser.buffer_pos += 2
+ case buf[pos] == '\xE2' && buf[pos+1] == '\x80' && (buf[pos+2] == '\xA8' || buf[pos+2] == '\xA9'):
+ // LS|PS . LS|PS
+ *s = append(*s, buf[parser.buffer_pos:pos+3]...)
+ parser.buffer_pos += 3
+ default:
+ return false
+ }
+ parser.mark.index++
+ parser.mark.column = 0
+ parser.mark.line++
+ parser.unread--
+ return true
+}
+
+// Get the next token.
+func yaml_parser_scan(parser *yaml_parser_t, token *yaml_token_t) bool {
+ // Erase the token object.
+ *token = yaml_token_t{} // [Go] Is this necessary?
+
+ // No tokens after STREAM-END or error.
+ if parser.stream_end_produced || parser.error != yaml_NO_ERROR {
+ return true
+ }
+
+ // Ensure that the tokens queue contains enough tokens.
+ if !parser.token_available {
+ if !yaml_parser_fetch_more_tokens(parser) {
+ return false
+ }
+ }
+
+ // Fetch the next token from the queue.
+ *token = parser.tokens[parser.tokens_head]
+ parser.tokens_head++
+ parser.tokens_parsed++
+ parser.token_available = false
+
+ if token.typ == yaml_STREAM_END_TOKEN {
+ parser.stream_end_produced = true
+ }
+ return true
+}
+
+// Set the scanner error and return false.
+func yaml_parser_set_scanner_error(parser *yaml_parser_t, context string, context_mark yaml_mark_t, problem string) bool {
+ parser.error = yaml_SCANNER_ERROR
+ parser.context = context
+ parser.context_mark = context_mark
+ parser.problem = problem
+ parser.problem_mark = parser.mark
+ return false
+}
+
+func yaml_parser_set_scanner_tag_error(parser *yaml_parser_t, directive bool, context_mark yaml_mark_t, problem string) bool {
+ context := "while parsing a tag"
+ if directive {
+ context = "while parsing a %TAG directive"
+ }
+ return yaml_parser_set_scanner_error(parser, context, context_mark, "did not find URI escaped octet")
+}
+
+// Ensure that the tokens queue contains at least one token which can be
+// returned to the Parser.
+func yaml_parser_fetch_more_tokens(parser *yaml_parser_t) bool {
+ // While we need more tokens to fetch, do it.
+ for {
+ // Check if we really need to fetch more tokens.
+ need_more_tokens := false
+
+ if parser.tokens_head == len(parser.tokens) {
+ // Queue is empty.
+ need_more_tokens = true
+ } else {
+ // Check if any potential simple key may occupy the head position.
+ if !yaml_parser_stale_simple_keys(parser) {
+ return false
+ }
+
+ for _, simple_key := range parser.simple_keys {
+ if simple_key.possible && simple_key.token_number == parser.tokens_parsed {
+ need_more_tokens = true
+ break
+ }
+ }
+ }
+
+ // We are finished.
+ if !need_more_tokens {
+ break
+ }
+ // Fetch the next token.
+ if !yaml_parser_fetch_next_token(parser) {
+ return false
+ }
+ }
+
+ parser.token_available = true
+ return true
+}
+
+// The dispatcher for token fetchers.
+func yaml_parser_fetch_next_token(parser *yaml_parser_t) bool {
+
+ // Ensure that the buffer is initialized.
+ if !cache(parser, 1) {
+ return false
+ }
+
+ // Check if we just started scanning. Fetch STREAM-START then.
+ if !parser.stream_start_produced {
+ return yaml_parser_fetch_stream_start(parser)
+ }
+
+ // Eat whitespaces and comments until we reach the next token.
+ if !yaml_parser_scan_to_next_token(parser) {
+ return false
+ }
+
+ // Remove obsolete potential simple keys.
+ if !yaml_parser_stale_simple_keys(parser) {
+ return false
+ }
+
+ // Check the indentation level against the current column.
+ if !yaml_parser_unroll_indent(parser, parser.mark.column) {
+ return false
+ }
+
+ // Ensure that the buffer contains at least 4 characters. 4 is the length
+ // of the longest indicators ('--- ' and '... ').
+ if !cache(parser, 4) {
+ return false
+ }
+
+ // Is it the end of the stream?
+ if is_z(parser.buffer, parser.buffer_pos) {
+ return yaml_parser_fetch_stream_end(parser)
+ }
+
+ // Is it a directive?
+ if parser.mark.column == 0 && parser.buffer[parser.buffer_pos] == '%' {
+ return yaml_parser_fetch_directive(parser)
+ }
+
+ buf := parser.buffer
+ pos := parser.buffer_pos
+
+ // Is it the document start indicator?
+ if parser.mark.column == 0 && buf[pos] == '-' && buf[pos+1] == '-' && buf[pos+2] == '-' && is_blankz(buf, pos+3) {
+ return yaml_parser_fetch_document_indicator(parser, yaml_DOCUMENT_START_TOKEN)
+ }
+
+ // Is it the document end indicator?
+ if parser.mark.column == 0 && buf[pos] == '.' && buf[pos+1] == '.' && buf[pos+2] == '.' && is_blankz(buf, pos+3) {
+ return yaml_parser_fetch_document_indicator(parser, yaml_DOCUMENT_END_TOKEN)
+ }
+
+ // Is it the flow sequence start indicator?
+ if buf[pos] == '[' {
+ return yaml_parser_fetch_flow_collection_start(parser, yaml_FLOW_SEQUENCE_START_TOKEN)
+ }
+
+ // Is it the flow mapping start indicator?
+ if parser.buffer[parser.buffer_pos] == '{' {
+ return yaml_parser_fetch_flow_collection_start(parser, yaml_FLOW_MAPPING_START_TOKEN)
+ }
+
+ // Is it the flow sequence end indicator?
+ if parser.buffer[parser.buffer_pos] == ']' {
+ return yaml_parser_fetch_flow_collection_end(parser,
+ yaml_FLOW_SEQUENCE_END_TOKEN)
+ }
+
+ // Is it the flow mapping end indicator?
+ if parser.buffer[parser.buffer_pos] == '}' {
+ return yaml_parser_fetch_flow_collection_end(parser,
+ yaml_FLOW_MAPPING_END_TOKEN)
+ }
+
+ // Is it the flow entry indicator?
+ if parser.buffer[parser.buffer_pos] == ',' {
+ return yaml_parser_fetch_flow_entry(parser)
+ }
+
+ // Is it the block entry indicator?
+ if parser.buffer[parser.buffer_pos] == '-' && is_blankz(parser.buffer, parser.buffer_pos+1) {
+ return yaml_parser_fetch_block_entry(parser)
+ }
+
+ // Is it the key indicator?
+ if parser.buffer[parser.buffer_pos] == '?' && (parser.flow_level > 0 || is_blankz(parser.buffer, parser.buffer_pos+1)) {
+ return yaml_parser_fetch_key(parser)
+ }
+
+ // Is it the value indicator?
+ if parser.buffer[parser.buffer_pos] == ':' && (parser.flow_level > 0 || is_blankz(parser.buffer, parser.buffer_pos+1)) {
+ return yaml_parser_fetch_value(parser)
+ }
+
+ // Is it an alias?
+ if parser.buffer[parser.buffer_pos] == '*' {
+ return yaml_parser_fetch_anchor(parser, yaml_ALIAS_TOKEN)
+ }
+
+ // Is it an anchor?
+ if parser.buffer[parser.buffer_pos] == '&' {
+ return yaml_parser_fetch_anchor(parser, yaml_ANCHOR_TOKEN)
+ }
+
+ // Is it a tag?
+ if parser.buffer[parser.buffer_pos] == '!' {
+ return yaml_parser_fetch_tag(parser)
+ }
+
+ // Is it a literal scalar?
+ if parser.buffer[parser.buffer_pos] == '|' && parser.flow_level == 0 {
+ return yaml_parser_fetch_block_scalar(parser, true)
+ }
+
+ // Is it a folded scalar?
+ if parser.buffer[parser.buffer_pos] == '>' && parser.flow_level == 0 {
+ return yaml_parser_fetch_block_scalar(parser, false)
+ }
+
+ // Is it a single-quoted scalar?
+ if parser.buffer[parser.buffer_pos] == '\'' {
+ return yaml_parser_fetch_flow_scalar(parser, true)
+ }
+
+ // Is it a double-quoted scalar?
+ if parser.buffer[parser.buffer_pos] == '"' {
+ return yaml_parser_fetch_flow_scalar(parser, false)
+ }
+
+ // Is it a plain scalar?
+ //
+ // A plain scalar may start with any non-blank characters except
+ //
+ // '-', '?', ':', ',', '[', ']', '{', '}',
+ // '#', '&', '*', '!', '|', '>', '\'', '\"',
+ // '%', '@', '`'.
+ //
+ // In the block context (and, for the '-' indicator, in the flow context
+ // too), it may also start with the characters
+ //
+ // '-', '?', ':'
+ //
+ // if it is followed by a non-space character.
+ //
+ // The last rule is more restrictive than the specification requires.
+ // [Go] Make this logic more reasonable.
+ if !(is_blankz(parser.buffer, parser.buffer_pos) || parser.buffer[parser.buffer_pos] == '-' ||
+ parser.buffer[parser.buffer_pos] == '?' || parser.buffer[parser.buffer_pos] == ':' ||
+ parser.buffer[parser.buffer_pos] == ',' || parser.buffer[parser.buffer_pos] == '[' ||
+ parser.buffer[parser.buffer_pos] == ']' || parser.buffer[parser.buffer_pos] == '{' ||
+ parser.buffer[parser.buffer_pos] == '}' || parser.buffer[parser.buffer_pos] == '#' ||
+ parser.buffer[parser.buffer_pos] == '&' || parser.buffer[parser.buffer_pos] == '*' ||
+ parser.buffer[parser.buffer_pos] == '!' || parser.buffer[parser.buffer_pos] == '|' ||
+ parser.buffer[parser.buffer_pos] == '>' || parser.buffer[parser.buffer_pos] == '\'' ||
+ parser.buffer[parser.buffer_pos] == '"' || parser.buffer[parser.buffer_pos] == '%' ||
+ parser.buffer[parser.buffer_pos] == '@' || parser.buffer[parser.buffer_pos] == '`') ||
+ (parser.buffer[parser.buffer_pos] == '-' && !is_blank(parser.buffer, parser.buffer_pos+1)) ||
+ (parser.flow_level == 0 &&
+ (parser.buffer[parser.buffer_pos] == '?' || parser.buffer[parser.buffer_pos] == ':') &&
+ !is_blankz(parser.buffer, parser.buffer_pos+1)) {
+ return yaml_parser_fetch_plain_scalar(parser)
+ }
+
+ // If we don't determine the token type so far, it is an error.
+ return yaml_parser_set_scanner_error(parser,
+ "while scanning for the next token", parser.mark,
+ "found character that cannot start any token")
+}
+
+// Check the list of potential simple keys and remove the positions that
+// cannot contain simple keys anymore.
+func yaml_parser_stale_simple_keys(parser *yaml_parser_t) bool {
+ // Check for a potential simple key for each flow level.
+ for _, simple_key := range parser.simple_keys {
+
+ // The specification requires that a simple key
+ //
+ // - is limited to a single line,
+ // - is shorter than 1024 characters.
+ if simple_key.possible && (simple_key.mark.line < parser.mark.line || simple_key.mark.index+1024 < parser.mark.index) {
+
+ // Check if the potential simple key to be removed is required.
+ if simple_key.required {
+ return yaml_parser_set_scanner_error(parser,
+ "while scanning a simple key", simple_key.mark,
+ "could not find expected ':'")
+ }
+ simple_key.possible = false
+ }
+ }
+ return true
+}
+
+// Check if a simple key may start at the current position and add it if
+// needed.
+func yaml_parser_save_simple_key(parser *yaml_parser_t) bool {
+ // A simple key is required at the current position if the scanner is in
+ // the block context and the current column coincides with the indentation
+ // level.
+
+ required := parser.flow_level == 0 && parser.indent == parser.mark.column
+
+ // A simple key is required only when it is the first token in the current
+ // line. Therefore it is always allowed. But we add a check anyway.
+ if required && !parser.simple_key_allowed {
+ panic("should not happen")
+ }
+
+ //
+ // If the current position may start a simple key, save it.
+ //
+ if parser.simple_key_allowed {
+ simple_key := yaml_simple_key_t{
+ possible: true,
+ required: required,
+ token_number: parser.tokens_parsed + (len(parser.tokens) - parser.tokens_head),
+ }
+ simple_key.mark = parser.mark
+
+ if !yaml_parser_remove_simple_key(parser) {
+ return false
+ }
+ parser.simple_keys[len(parser.simple_keys)-1] = simple_key
+ }
+ return true
+}
+
+// Remove a potential simple key at the current flow level.
+func yaml_parser_remove_simple_key(parser *yaml_parser_t) bool {
+ i := len(parser.simple_keys) - 1
+ if parser.simple_keys[i].possible {
+ // If the key is required, it is an error.
+ if parser.simple_keys[i].required {
+ return yaml_parser_set_scanner_error(parser,
+ "while scanning a simple key", parser.simple_keys[i].mark,
+ "could not find expected ':'")
+ }
+ }
+ // Remove the key from the stack.
+ parser.simple_keys[i].possible = false
+ return true
+}
+
+// Increase the flow level and resize the simple key list if needed.
+func yaml_parser_increase_flow_level(parser *yaml_parser_t) bool {
+ // Reset the simple key on the next level.
+ parser.simple_keys = append(parser.simple_keys, yaml_simple_key_t{})
+
+ // Increase the flow level.
+ parser.flow_level++
+ return true
+}
+
+// Decrease the flow level.
+func yaml_parser_decrease_flow_level(parser *yaml_parser_t) bool {
+ if parser.flow_level > 0 {
+ parser.flow_level--
+ parser.simple_keys = parser.simple_keys[:len(parser.simple_keys)-1]
+ }
+ return true
+}
+
+// Push the current indentation level to the stack and set the new level
+// the current column is greater than the indentation level. In this case,
+// append or insert the specified token into the token queue.
+func yaml_parser_roll_indent(parser *yaml_parser_t, column, number int, typ yaml_token_type_t, mark yaml_mark_t) bool {
+ // In the flow context, do nothing.
+ if parser.flow_level > 0 {
+ return true
+ }
+
+ if parser.indent < column {
+ // Push the current indentation level to the stack and set the new
+ // indentation level.
+ parser.indents = append(parser.indents, parser.indent)
+ parser.indent = column
+
+ // Create a token and insert it into the queue.
+ token := yaml_token_t{
+ typ: typ,
+ start_mark: mark,
+ end_mark: mark,
+ }
+ if number > -1 {
+ number -= parser.tokens_parsed
+ }
+ yaml_insert_token(parser, number, &token)
+ }
+ return true
+}
+
+// Pop indentation levels from the indents stack until the current level
+// becomes less or equal to the column. For each intendation level, append
+// the BLOCK-END token.
+func yaml_parser_unroll_indent(parser *yaml_parser_t, column int) bool {
+ // In the flow context, do nothing.
+ if parser.flow_level > 0 {
+ return true
+ }
+
+ // Loop through the intendation levels in the stack.
+ for parser.indent > column {
+ // Create a token and append it to the queue.
+ token := yaml_token_t{
+ typ: yaml_BLOCK_END_TOKEN,
+ start_mark: parser.mark,
+ end_mark: parser.mark,
+ }
+ yaml_insert_token(parser, -1, &token)
+
+ // Pop the indentation level.
+ parser.indent = parser.indents[len(parser.indents)-1]
+ parser.indents = parser.indents[:len(parser.indents)-1]
+ }
+ return true
+}
+
+// Initialize the scanner and produce the STREAM-START token.
+func yaml_parser_fetch_stream_start(parser *yaml_parser_t) bool {
+ // Set the initial indentation.
+ parser.indent = -1
+
+ // Initialize the simple key stack.
+ parser.simple_keys = append(parser.simple_keys, yaml_simple_key_t{})
+
+ // A simple key is allowed at the beginning of the stream.
+ parser.simple_key_allowed = true
+
+ // We have started.
+ parser.stream_start_produced = true
+
+ // Create the STREAM-START token and append it to the queue.
+ token := yaml_token_t{
+ typ: yaml_STREAM_START_TOKEN,
+ start_mark: parser.mark,
+ end_mark: parser.mark,
+ }
+ token.stream_start.encoding = parser.encoding
+ yaml_insert_token(parser, -1, &token)
+ return true
+}
+
+// Produce the STREAM-END token and shut down the scanner.
+func yaml_parser_fetch_stream_end(parser *yaml_parser_t) bool {
+ // Force new line.
+ if parser.mark.column != 0 {
+ parser.mark.column = 0
+ parser.mark.line++
+ }
+
+ // Reset the indentation level.
+ if !yaml_parser_unroll_indent(parser, -1) {
+ return false
+ }
+
+ // Reset simple keys.
+ if !yaml_parser_remove_simple_key(parser) {
+ return false
+ }
+
+ parser.simple_key_allowed = false
+
+ // Create the STREAM-END token and append it to the queue.
+ token := yaml_token_t{
+ typ: yaml_STREAM_END_TOKEN,
+ start_mark: parser.mark,
+ end_mark: parser.mark,
+ }
+ yaml_insert_token(parser, -1, &token)
+ return true
+}
+
+// Produce a VERSION-DIRECTIVE or TAG-DIRECTIVE token.
+func yaml_parser_fetch_directive(parser *yaml_parser_t) bool {
+ // Reset the indentation level.
+ if !yaml_parser_unroll_indent(parser, -1) {
+ return false
+ }
+
+ // Reset simple keys.
+ if !yaml_parser_remove_simple_key(parser) {
+ return false
+ }
+
+ parser.simple_key_allowed = false
+
+ // Create the YAML-DIRECTIVE or TAG-DIRECTIVE token.
+ token := yaml_token_t{}
+ if !yaml_parser_scan_directive(parser, &token) {
+ return false
+ }
+ // Append the token to the queue.
+ yaml_insert_token(parser, -1, &token)
+ return true
+}
+
+// Produce the DOCUMENT-START or DOCUMENT-END token.
+func yaml_parser_fetch_document_indicator(parser *yaml_parser_t, typ yaml_token_type_t) bool {
+ // Reset the indentation level.
+ if !yaml_parser_unroll_indent(parser, -1) {
+ return false
+ }
+
+ // Reset simple keys.
+ if !yaml_parser_remove_simple_key(parser) {
+ return false
+ }
+
+ parser.simple_key_allowed = false
+
+ // Consume the token.
+ start_mark := parser.mark
+
+ skip(parser)
+ skip(parser)
+ skip(parser)
+
+ end_mark := parser.mark
+
+ // Create the DOCUMENT-START or DOCUMENT-END token.
+ token := yaml_token_t{
+ typ: typ,
+ start_mark: start_mark,
+ end_mark: end_mark,
+ }
+ // Append the token to the queue.
+ yaml_insert_token(parser, -1, &token)
+ return true
+}
+
+// Produce the FLOW-SEQUENCE-START or FLOW-MAPPING-START token.
+func yaml_parser_fetch_flow_collection_start(parser *yaml_parser_t, typ yaml_token_type_t) bool {
+ // The indicators '[' and '{' may start a simple key.
+ if !yaml_parser_save_simple_key(parser) {
+ return false
+ }
+
+ // Increase the flow level.
+ if !yaml_parser_increase_flow_level(parser) {
+ return false
+ }
+
+ // A simple key may follow the indicators '[' and '{'.
+ parser.simple_key_allowed = true
+
+ // Consume the token.
+ start_mark := parser.mark
+ skip(parser)
+ end_mark := parser.mark
+
+ // Create the FLOW-SEQUENCE-START of FLOW-MAPPING-START token.
+ token := yaml_token_t{
+ typ: typ,
+ start_mark: start_mark,
+ end_mark: end_mark,
+ }
+ // Append the token to the queue.
+ yaml_insert_token(parser, -1, &token)
+ return true
+}
+
+// Produce the FLOW-SEQUENCE-END or FLOW-MAPPING-END token.
+func yaml_parser_fetch_flow_collection_end(parser *yaml_parser_t, typ yaml_token_type_t) bool {
+ // Reset any potential simple key on the current flow level.
+ if !yaml_parser_remove_simple_key(parser) {
+ return false
+ }
+
+ // Decrease the flow level.
+ if !yaml_parser_decrease_flow_level(parser) {
+ return false
+ }
+
+ // No simple keys after the indicators ']' and '}'.
+ parser.simple_key_allowed = false
+
+ // Consume the token.
+
+ start_mark := parser.mark
+ skip(parser)
+ end_mark := parser.mark
+
+ // Create the FLOW-SEQUENCE-END of FLOW-MAPPING-END token.
+ token := yaml_token_t{
+ typ: typ,
+ start_mark: start_mark,
+ end_mark: end_mark,
+ }
+ // Append the token to the queue.
+ yaml_insert_token(parser, -1, &token)
+ return true
+}
+
+// Produce the FLOW-ENTRY token.
+func yaml_parser_fetch_flow_entry(parser *yaml_parser_t) bool {
+ // Reset any potential simple keys on the current flow level.
+ if !yaml_parser_remove_simple_key(parser) {
+ return false
+ }
+
+ // Simple keys are allowed after ','.
+ parser.simple_key_allowed = true
+
+ // Consume the token.
+ start_mark := parser.mark
+ skip(parser)
+ end_mark := parser.mark
+
+ // Create the FLOW-ENTRY token and append it to the queue.
+ token := yaml_token_t{
+ typ: yaml_FLOW_ENTRY_TOKEN,
+ start_mark: start_mark,
+ end_mark: end_mark,
+ }
+ yaml_insert_token(parser, -1, &token)
+ return true
+}
+
+// Produce the BLOCK-ENTRY token.
+func yaml_parser_fetch_block_entry(parser *yaml_parser_t) bool {
+ // Check if the scanner is in the block context.
+ if parser.flow_level == 0 {
+ // Check if we are allowed to start a new entry.
+ if !parser.simple_key_allowed {
+ return yaml_parser_set_scanner_error(parser, "", parser.mark,
+ "block sequence entries are not allowed in this context")
+ }
+ // Add the BLOCK-SEQUENCE-START token if needed.
+ if !yaml_parser_roll_indent(parser, parser.mark.column, -1, yaml_BLOCK_SEQUENCE_START_TOKEN, parser.mark) {
+ return false
+ }
+ } else {
+ // It is an error for the '-' indicator to occur in the flow context,
+ // but we let the Parser detect and report about it because the Parser
+ // is able to point to the context.
+ }
+
+ // Reset any potential simple keys on the current flow level.
+ if !yaml_parser_remove_simple_key(parser) {
+ return false
+ }
+
+ // Simple keys are allowed after '-'.
+ parser.simple_key_allowed = true
+
+ // Consume the token.
+ start_mark := parser.mark
+ skip(parser)
+ end_mark := parser.mark
+
+ // Create the BLOCK-ENTRY token and append it to the queue.
+ token := yaml_token_t{
+ typ: yaml_BLOCK_ENTRY_TOKEN,
+ start_mark: start_mark,
+ end_mark: end_mark,
+ }
+ yaml_insert_token(parser, -1, &token)
+ return true
+}
+
+// Produce the KEY token.
+func yaml_parser_fetch_key(parser *yaml_parser_t) bool {
+
+ // In the block context, additional checks are required.
+ if parser.flow_level == 0 {
+ // Check if we are allowed to start a new key (not nessesary simple).
+ if !parser.simple_key_allowed {
+ return yaml_parser_set_scanner_error(parser, "", parser.mark,
+ "mapping keys are not allowed in this context")
+ }
+ // Add the BLOCK-MAPPING-START token if needed.
+ if !yaml_parser_roll_indent(parser, parser.mark.column, -1, yaml_BLOCK_MAPPING_START_TOKEN, parser.mark) {
+ return false
+ }
+ }
+
+ // Reset any potential simple keys on the current flow level.
+ if !yaml_parser_remove_simple_key(parser) {
+ return false
+ }
+
+ // Simple keys are allowed after '?' in the block context.
+ parser.simple_key_allowed = parser.flow_level == 0
+
+ // Consume the token.
+ start_mark := parser.mark
+ skip(parser)
+ end_mark := parser.mark
+
+ // Create the KEY token and append it to the queue.
+ token := yaml_token_t{
+ typ: yaml_KEY_TOKEN,
+ start_mark: start_mark,
+ end_mark: end_mark,
+ }
+ yaml_insert_token(parser, -1, &token)
+ return true
+}
+
+// Produce the VALUE token.
+func yaml_parser_fetch_value(parser *yaml_parser_t) bool {
+
+ simple_key := &parser.simple_keys[len(parser.simple_keys)-1]
+
+ // Have we found a simple key?
+ if simple_key.possible {
+ // Create the KEY token and insert it into the queue.
+ token := yaml_token_t{
+ typ: yaml_KEY_TOKEN,
+ start_mark: simple_key.mark,
+ end_mark: simple_key.mark,
+ }
+ yaml_insert_token(parser, simple_key.token_number-parser.tokens_parsed, &token)
+
+ // In the block context, we may need to add the BLOCK-MAPPING-START token.
+ if !yaml_parser_roll_indent(parser, simple_key.mark.column,
+ simple_key.token_number,
+ yaml_BLOCK_MAPPING_START_TOKEN, simple_key.mark) {
+ return false
+ }
+
+ // Remove the simple key.
+ simple_key.possible = false
+
+ // A simple key cannot follow another simple key.
+ parser.simple_key_allowed = false
+
+ } else {
+ // The ':' indicator follows a complex key.
+
+ // In the block context, extra checks are required.
+ if parser.flow_level == 0 {
+
+ // Check if we are allowed to start a complex value.
+ if !parser.simple_key_allowed {
+ return yaml_parser_set_scanner_error(parser, "", parser.mark,
+ "mapping values are not allowed in this context")
+ }
+
+ // Add the BLOCK-MAPPING-START token if needed.
+ if !yaml_parser_roll_indent(parser, parser.mark.column, -1, yaml_BLOCK_MAPPING_START_TOKEN, parser.mark) {
+ return false
+ }
+ }
+
+ // Simple keys after ':' are allowed in the block context.
+ parser.simple_key_allowed = parser.flow_level == 0
+ }
+
+ // Consume the token.
+ start_mark := parser.mark
+ skip(parser)
+ end_mark := parser.mark
+
+ // Create the VALUE token and append it to the queue.
+ token := yaml_token_t{
+ typ: yaml_VALUE_TOKEN,
+ start_mark: start_mark,
+ end_mark: end_mark,
+ }
+ yaml_insert_token(parser, -1, &token)
+ return true
+}
+
+// Produce the ALIAS or ANCHOR token.
+func yaml_parser_fetch_anchor(parser *yaml_parser_t, typ yaml_token_type_t) bool {
+ // An anchor or an alias could be a simple key.
+ if !yaml_parser_save_simple_key(parser) {
+ return false
+ }
+
+ // A simple key cannot follow an anchor or an alias.
+ parser.simple_key_allowed = false
+
+ // Create the ALIAS or ANCHOR token and append it to the queue.
+ var token yaml_token_t
+ if !yaml_parser_scan_anchor(parser, &token, typ) {
+ return false
+ }
+ yaml_insert_token(parser, -1, &token)
+ return true
+}
+
+// Produce the TAG token.
+func yaml_parser_fetch_tag(parser *yaml_parser_t) bool {
+ // A tag could be a simple key.
+ if !yaml_parser_save_simple_key(parser) {
+ return false
+ }
+
+ // A simple key cannot follow a tag.
+ parser.simple_key_allowed = false
+
+ // Create the TAG token and append it to the queue.
+ var token yaml_token_t
+ if !yaml_parser_scan_tag(parser, &token) {
+ return false
+ }
+ yaml_insert_token(parser, -1, &token)
+ return true
+}
+
+// Produce the SCALAR(...,literal) or SCALAR(...,folded) tokens.
+func yaml_parser_fetch_block_scalar(parser *yaml_parser_t, literal bool) bool {
+ // Remove any potential simple keys.
+ if !yaml_parser_remove_simple_key(parser) {
+ return false
+ }
+
+ // A simple key may follow a block scalar.
+ parser.simple_key_allowed = true
+
+ // Create the SCALAR token and append it to the queue.
+ var token yaml_token_t
+ if !yaml_parser_scan_block_scalar(parser, &token, literal) {
+ return false
+ }
+ yaml_insert_token(parser, -1, &token)
+ return true
+}
+
+// Produce the SCALAR(...,single-quoted) or SCALAR(...,double-quoted) tokens.
+func yaml_parser_fetch_flow_scalar(parser *yaml_parser_t, single bool) bool {
+ // A plain scalar could be a simple key.
+ if !yaml_parser_save_simple_key(parser) {
+ return false
+ }
+
+ // A simple key cannot follow a flow scalar.
+ parser.simple_key_allowed = false
+
+ // Create the SCALAR token and append it to the queue.
+ var token yaml_token_t
+ if !yaml_parser_scan_flow_scalar(parser, &token, single) {
+ return false
+ }
+ yaml_insert_token(parser, -1, &token)
+ return true
+}
+
+// Produce the SCALAR(...,plain) token.
+func yaml_parser_fetch_plain_scalar(parser *yaml_parser_t) bool {
+ // A plain scalar could be a simple key.
+ if !yaml_parser_save_simple_key(parser) {
+ return false
+ }
+
+ // A simple key cannot follow a flow scalar.
+ parser.simple_key_allowed = false
+
+ // Create the SCALAR token and append it to the queue.
+ var token yaml_token_t
+ if !yaml_parser_scan_plain_scalar(parser, &token) {
+ return false
+ }
+ yaml_insert_token(parser, -1, &token)
+ return true
+}
+
+// Eat whitespaces and comments until the next token is found.
+func yaml_parser_scan_to_next_token(parser *yaml_parser_t) bool {
+
+ // Until the next token is not found.
+ for {
+ // Allow the BOM mark to start a line.
+ if !cache(parser, 1) {
+ return false
+ }
+ if parser.mark.column == 0 && is_bom(parser.buffer, parser.buffer_pos) {
+ skip(parser)
+ }
+
+ // Eat whitespaces.
+ // Tabs are allowed:
+ // - in the flow context
+ // - in the block context, but not at the beginning of the line or
+ // after '-', '?', or ':' (complex value).
+ if !cache(parser, 1) {
+ return false
+ }
+
+ for parser.buffer[parser.buffer_pos] == ' ' || ((parser.flow_level > 0 || !parser.simple_key_allowed) && parser.buffer[parser.buffer_pos] == '\t') {
+ skip(parser)
+ if !cache(parser, 1) {
+ return false
+ }
+ }
+
+ // Eat a comment until a line break.
+ if parser.buffer[parser.buffer_pos] == '#' {
+ for !is_breakz(parser.buffer, parser.buffer_pos) {
+ skip(parser)
+ if !cache(parser, 1) {
+ return false
+ }
+ }
+ }
+
+ // If it is a line break, eat it.
+ if is_break(parser.buffer, parser.buffer_pos) {
+ if !cache(parser, 2) {
+ return false
+ }
+ skip_line(parser)
+
+ // In the block context, a new line may start a simple key.
+ if parser.flow_level == 0 {
+ parser.simple_key_allowed = true
+ }
+ } else {
+ break // We have found a token.
+ }
+ }
+
+ return true
+}
+
+// Scan a YAML-DIRECTIVE or TAG-DIRECTIVE token.
+//
+// Scope:
+// %YAML 1.1 # a comment \n
+// ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
+// %TAG !yaml! tag:yaml.org,2002: \n
+// ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
+//
+func yaml_parser_scan_directive(parser *yaml_parser_t, token *yaml_token_t) bool {
+ // Eat '%'.
+ start_mark := parser.mark
+ skip(parser)
+
+ // Scan the directive name.
+ var name []byte
+ if !yaml_parser_scan_directive_name(parser, start_mark, &name) {
+ return false
+ }
+
+ // Is it a YAML directive?
+ if bytes.Equal(name, []byte("YAML")) {
+ // Scan the VERSION directive value.
+ var major, minor int
+ if !yaml_parser_scan_version_directive_value(parser, start_mark, &major, &minor) {
+ return false
+ }
+ end_mark := parser.mark
+
+ // Create a VERSION-DIRECTIVE token.
+ *token = yaml_token_t{
+ typ: yaml_VERSION_DIRECTIVE_TOKEN,
+ start_mark: start_mark,
+ end_mark: end_mark,
+ }
+ token.version_directive.major = major
+ token.version_directive.minor = minor
+
+ // Is it a TAG directive?
+ } else if bytes.Equal(name, []byte("TAG")) {
+ // Scan the TAG directive value.
+ var handle, prefix []byte
+ if !yaml_parser_scan_tag_directive_value(parser, start_mark, &handle, &prefix) {
+ return false
+ }
+ end_mark := parser.mark
+
+ // Create a TAG-DIRECTIVE token.
+ *token = yaml_token_t{
+ typ: yaml_TAG_DIRECTIVE_TOKEN,
+ start_mark: start_mark,
+ end_mark: end_mark,
+ }
+ token.tag_directive.handle = handle
+ token.tag_directive.prefix = prefix
+
+ // Unknown directive.
+ } else {
+ yaml_parser_set_scanner_error(parser, "while scanning a directive",
+ start_mark, "found uknown directive name")
+ return false
+ }
+
+ // Eat the rest of the line including any comments.
+ if !cache(parser, 1) {
+ return false
+ }
+
+ for is_blank(parser.buffer, parser.buffer_pos) {
+ skip(parser)
+ if !cache(parser, 1) {
+ return false
+ }
+ }
+
+ if parser.buffer[parser.buffer_pos] == '#' {
+ for !is_breakz(parser.buffer, parser.buffer_pos) {
+ skip(parser)
+ if !cache(parser, 1) {
+ return false
+ }
+ }
+ }
+
+ // Check if we are at the end of the line.
+ if !is_breakz(parser.buffer, parser.buffer_pos) {
+ yaml_parser_set_scanner_error(parser, "while scanning a directive",
+ start_mark, "did not find expected comment or line break")
+ return false
+ }
+
+ // Eat a line break.
+ if is_break(parser.buffer, parser.buffer_pos) {
+ if !cache(parser, 2) {
+ return false
+ }
+ skip_line(parser)
+ }
+
+ return true
+}
+
+// Scan the directive name.
+//
+// Scope:
+// %YAML 1.1 # a comment \n
+// ^^^^
+// %TAG !yaml! tag:yaml.org,2002: \n
+// ^^^
+//
+func yaml_parser_scan_directive_name(parser *yaml_parser_t, start_mark yaml_mark_t, name *[]byte) bool {
+ // Consume the directive name.
+ if !cache(parser, 1) {
+ return false
+ }
+
+ var s []byte
+ for is_alpha(parser.buffer, parser.buffer_pos) {
+ if !read(parser, &s) {
+ return false
+ }
+ if !cache(parser, 1) {
+ return false
+ }
+ }
+
+ // Check if the name is empty.
+ if len(s) == 0 {
+ yaml_parser_set_scanner_error(parser, "while scanning a directive",
+ start_mark, "could not find expected directive name")
+ return false
+ }
+
+ // Check for an blank character after the name.
+ if !is_blankz(parser.buffer, parser.buffer_pos) {
+ yaml_parser_set_scanner_error(parser, "while scanning a directive",
+ start_mark, "found unexpected non-alphabetical character")
+ return false
+ }
+ *name = s
+ return true
+}
+
+// Scan the value of VERSION-DIRECTIVE.
+//
+// Scope:
+// %YAML 1.1 # a comment \n
+// ^^^^^^
+func yaml_parser_scan_version_directive_value(parser *yaml_parser_t, start_mark yaml_mark_t, major, minor *int) bool {
+ // Eat whitespaces.
+ if !cache(parser, 1) {
+ return false
+ }
+ for is_blank(parser.buffer, parser.buffer_pos) {
+ skip(parser)
+ if !cache(parser, 1) {
+ return false
+ }
+ }
+
+ // Consume the major version number.
+ if !yaml_parser_scan_version_directive_number(parser, start_mark, major) {
+ return false
+ }
+
+ // Eat '.'.
+ if parser.buffer[parser.buffer_pos] != '.' {
+ return yaml_parser_set_scanner_error(parser, "while scanning a %YAML directive",
+ start_mark, "did not find expected digit or '.' character")
+ }
+
+ skip(parser)
+
+ // Consume the minor version number.
+ if !yaml_parser_scan_version_directive_number(parser, start_mark, minor) {
+ return false
+ }
+ return true
+}
+
+const max_number_length = 9
+
+// Scan the version number of VERSION-DIRECTIVE.
+//
+// Scope:
+// %YAML 1.1 # a comment \n
+// ^
+// %YAML 1.1 # a comment \n
+// ^
+func yaml_parser_scan_version_directive_number(parser *yaml_parser_t, start_mark yaml_mark_t, number *int) bool {
+
+ // Repeat while the next character is digit.
+ if !cache(parser, 1) {
+ return false
+ }
+ var value, length int
+ for is_digit(parser.buffer, parser.buffer_pos) {
+ // Check if the number is too long.
+ length++
+ if length > max_number_length {
+ return yaml_parser_set_scanner_error(parser, "while scanning a %YAML directive",
+ start_mark, "found extremely long version number")
+ }
+ value = value*10 + as_digit(parser.buffer, parser.buffer_pos)
+ skip(parser)
+ if !cache(parser, 1) {
+ return false
+ }
+ }
+
+ // Check if the number was present.
+ if length == 0 {
+ return yaml_parser_set_scanner_error(parser, "while scanning a %YAML directive",
+ start_mark, "did not find expected version number")
+ }
+ *number = value
+ return true
+}
+
+// Scan the value of a TAG-DIRECTIVE token.
+//
+// Scope:
+// %TAG !yaml! tag:yaml.org,2002: \n
+// ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
+//
+func yaml_parser_scan_tag_directive_value(parser *yaml_parser_t, start_mark yaml_mark_t, handle, prefix *[]byte) bool {
+ var handle_value, prefix_value []byte
+
+ // Eat whitespaces.
+ if !cache(parser, 1) {
+ return false
+ }
+
+ for is_blank(parser.buffer, parser.buffer_pos) {
+ skip(parser)
+ if !cache(parser, 1) {
+ return false
+ }
+ }
+
+ // Scan a handle.
+ if !yaml_parser_scan_tag_handle(parser, true, start_mark, &handle_value) {
+ return false
+ }
+
+ // Expect a whitespace.
+ if !cache(parser, 1) {
+ return false
+ }
+ if !is_blank(parser.buffer, parser.buffer_pos) {
+ yaml_parser_set_scanner_error(parser, "while scanning a %TAG directive",
+ start_mark, "did not find expected whitespace")
+ return false
+ }
+
+ // Eat whitespaces.
+ for is_blank(parser.buffer, parser.buffer_pos) {
+ skip(parser)
+ if !cache(parser, 1) {
+ return false
+ }
+ }
+
+ // Scan a prefix.
+ if !yaml_parser_scan_tag_uri(parser, true, nil, start_mark, &prefix_value) {
+ return false
+ }
+
+ // Expect a whitespace or line break.
+ if !cache(parser, 1) {
+ return false
+ }
+ if !is_blankz(parser.buffer, parser.buffer_pos) {
+ yaml_parser_set_scanner_error(parser, "while scanning a %TAG directive",
+ start_mark, "did not find expected whitespace or line break")
+ return false
+ }
+
+ *handle = handle_value
+ *prefix = prefix_value
+ return true
+}
+
+func yaml_parser_scan_anchor(parser *yaml_parser_t, token *yaml_token_t, typ yaml_token_type_t) bool {
+ var s []byte
+
+ // Eat the indicator character.
+ start_mark := parser.mark
+ skip(parser)
+
+ // Consume the value.
+ if !cache(parser, 1) {
+ return false
+ }
+
+ for is_alpha(parser.buffer, parser.buffer_pos) {
+ if !read(parser, &s) {
+ return false
+ }
+ if !cache(parser, 1) {
+ return false
+ }
+ }
+
+ end_mark := parser.mark
+
+ /*
+ * Check if length of the anchor is greater than 0 and it is followed by
+ * a whitespace character or one of the indicators:
+ *
+ * '?', ':', ',', ']', '}', '%', '@', '`'.
+ */
+
+ if len(s) == 0 ||
+ !(is_blankz(parser.buffer, parser.buffer_pos) || parser.buffer[parser.buffer_pos] == '?' ||
+ parser.buffer[parser.buffer_pos] == ':' || parser.buffer[parser.buffer_pos] == ',' ||
+ parser.buffer[parser.buffer_pos] == ']' || parser.buffer[parser.buffer_pos] == '}' ||
+ parser.buffer[parser.buffer_pos] == '%' || parser.buffer[parser.buffer_pos] == '@' ||
+ parser.buffer[parser.buffer_pos] == '`') {
+ context := "while scanning an alias"
+ if typ == yaml_ANCHOR_TOKEN {
+ context = "while scanning an anchor"
+ }
+ yaml_parser_set_scanner_error(parser, context, start_mark,
+ "did not find expected alphabetic or numeric character")
+ return false
+ }
+
+ // Create a token.
+ *token = yaml_token_t{
+ typ: typ,
+ start_mark: start_mark,
+ end_mark: end_mark,
+ }
+ // [Go] Just use a single field instead.
+ if typ == yaml_ANCHOR_TOKEN {
+ token.anchor.value = s
+ } else {
+ token.alias.value = s
+ }
+
+ return true
+}
+
+/*
+ * Scan a TAG token.
+ */
+
+func yaml_parser_scan_tag(parser *yaml_parser_t, token *yaml_token_t) bool {
+ var handle, suffix []byte
+
+ start_mark := parser.mark
+
+ // Check if the tag is in the canonical form.
+ if !cache(parser, 2) {
+ return false
+ }
+
+ if parser.buffer[parser.buffer_pos+1] == '<' {
+ // Keep the handle as ''
+
+ // Eat '!<'
+ skip(parser)
+ skip(parser)
+
+ // Consume the tag value.
+ if !yaml_parser_scan_tag_uri(parser, false, nil, start_mark, &suffix) {
+ return false
+ }
+
+ // Check for '>' and eat it.
+ if parser.buffer[parser.buffer_pos] != '>' {
+ yaml_parser_set_scanner_error(parser, "while scanning a tag",
+ start_mark, "did not find the expected '>'")
+ return false
+ }
+
+ skip(parser)
+ } else {
+ // The tag has either the '!suffix' or the '!handle!suffix' form.
+
+ // First, try to scan a handle.
+ if !yaml_parser_scan_tag_handle(parser, false, start_mark, &handle) {
+ return false
+ }
+
+ // Check if it is, indeed, handle.
+ if handle[0] == '!' && len(handle) > 1 && handle[len(handle)-1] == '!' {
+ // Scan the suffix now.
+ if !yaml_parser_scan_tag_uri(parser, false, nil, start_mark, &suffix) {
+ return false
+ }
+ } else {
+ // It wasn't a handle after all. Scan the rest of the tag.
+ if !yaml_parser_scan_tag_uri(parser, false, handle, start_mark, &suffix) {
+ return false
+ }
+
+ // Set the handle to '!'.
+ handle = []byte{'!'}
+
+ // A special case: the '!' tag. Set the handle to '' and the
+ // suffix to '!'.
+ if len(suffix) == 0 {
+ handle, suffix = suffix, handle
+ }
+ }
+ }
+
+ // Check the character which ends the tag.
+ if !cache(parser, 1) {
+ return false
+ }
+ if !is_blankz(parser.buffer, parser.buffer_pos) {
+ yaml_parser_set_scanner_error(parser, "while scanning a tag",
+ start_mark, "did not find expected whitespace or line break")
+ return false
+ }
+
+ end_mark := parser.mark
+
+ // Create a token.
+ *token = yaml_token_t{
+ typ: yaml_TAG_TOKEN,
+ start_mark: start_mark,
+ end_mark: end_mark,
+ }
+ token.tag.handle = handle
+ token.tag.suffix = suffix
+ return true
+}
+
+// Scan a tag handle.
+func yaml_parser_scan_tag_handle(parser *yaml_parser_t, directive bool, start_mark yaml_mark_t, handle *[]byte) bool {
+ // Check the initial '!' character.
+ if !cache(parser, 1) {
+ return false
+ }
+ if parser.buffer[parser.buffer_pos] != '!' {
+ yaml_parser_set_scanner_tag_error(parser, directive,
+ start_mark, "did not find expected '!'")
+ return false
+ }
+
+ var s []byte
+
+ // Copy the '!' character.
+ if !read(parser, &s) {
+ return false
+ }
+
+ // Copy all subsequent alphabetical and numerical characters.
+ if !cache(parser, 1) {
+ return false
+ }
+ for is_alpha(parser.buffer, parser.buffer_pos) {
+ if !read(parser, &s) {
+ return false
+ }
+ if !cache(parser, 1) {
+ return false
+ }
+ }
+
+ // Check if the trailing character is '!' and copy it.
+ if parser.buffer[parser.buffer_pos] == '!' {
+ if !read(parser, &s) {
+ return false
+ }
+ } else {
+ // It's either the '!' tag or not really a tag handle. If it's a %TAG
+ // directive, it's an error. If it's a tag token, it must be a part of URI.
+ if directive && !(s[0] == '!' && s[1] == 0) {
+ yaml_parser_set_scanner_tag_error(parser, directive,
+ start_mark, "did not find expected '!'")
+ return false
+ }
+ }
+
+ *handle = s
+ return true
+}
+
+// Scan a tag.
+func yaml_parser_scan_tag_uri(parser *yaml_parser_t, directive bool, head []byte, start_mark yaml_mark_t, uri *[]byte) bool {
+ //size_t length = head ? strlen((char *)head) : 0
+ var s []byte
+
+ // Copy the head if needed.
+ //
+ // Note that we don't copy the leading '!' character.
+ if len(head) > 1 {
+ s = append(s, head[1:]...)
+ }
+
+ // Scan the tag.
+ if !cache(parser, 1) {
+ return false
+ }
+
+ // The set of characters that may appear in URI is as follows:
+ //
+ // '0'-'9', 'A'-'Z', 'a'-'z', '_', '-', ';', '/', '?', ':', '@', '&',
+ // '=', '+', '$', ',', '.', '!', '~', '*', '\'', '(', ')', '[', ']',
+ // '%'.
+ // [Go] Convert this into more reasonable logic.
+ for is_alpha(parser.buffer, parser.buffer_pos) || parser.buffer[parser.buffer_pos] == ';' ||
+ parser.buffer[parser.buffer_pos] == '/' || parser.buffer[parser.buffer_pos] == '?' ||
+ parser.buffer[parser.buffer_pos] == ':' || parser.buffer[parser.buffer_pos] == '@' ||
+ parser.buffer[parser.buffer_pos] == '&' || parser.buffer[parser.buffer_pos] == '=' ||
+ parser.buffer[parser.buffer_pos] == '+' || parser.buffer[parser.buffer_pos] == '$' ||
+ parser.buffer[parser.buffer_pos] == ',' || parser.buffer[parser.buffer_pos] == '.' ||
+ parser.buffer[parser.buffer_pos] == '!' || parser.buffer[parser.buffer_pos] == '~' ||
+ parser.buffer[parser.buffer_pos] == '*' || parser.buffer[parser.buffer_pos] == '\'' ||
+ parser.buffer[parser.buffer_pos] == '(' || parser.buffer[parser.buffer_pos] == ')' ||
+ parser.buffer[parser.buffer_pos] == '[' || parser.buffer[parser.buffer_pos] == ']' ||
+ parser.buffer[parser.buffer_pos] == '%' {
+ // Check if it is a URI-escape sequence.
+ if parser.buffer[parser.buffer_pos] == '%' {
+ if !yaml_parser_scan_uri_escapes(parser, directive, start_mark, &s) {
+ return false
+ }
+ } else {
+ if !read(parser, &s) {
+ return false
+ }
+ }
+ if !cache(parser, 1) {
+ return false
+ }
+ }
+
+ // Check if the tag is non-empty.
+ if len(s) == 0 {
+ yaml_parser_set_scanner_tag_error(parser, directive,
+ start_mark, "did not find expected tag URI")
+ return false
+ }
+ *uri = s
+ return true
+}
+
+// Decode an URI-escape sequence corresponding to a single UTF-8 character.
+func yaml_parser_scan_uri_escapes(parser *yaml_parser_t, directive bool, start_mark yaml_mark_t, s *[]byte) bool {
+
+ // Decode the required number of characters.
+ w := 1024
+ for w > 0 {
+ // Check for a URI-escaped octet.
+ if !cache(parser, 3) {
+ return false
+ }
+
+ if !(parser.buffer[parser.buffer_pos] == '%' &&
+ is_hex(parser.buffer, parser.buffer_pos+1) &&
+ is_hex(parser.buffer, parser.buffer_pos+2)) {
+ return yaml_parser_set_scanner_tag_error(parser, directive,
+ start_mark, "did not find URI escaped octet")
+ }
+
+ // Get the octet.
+ octet := byte((as_hex(parser.buffer, parser.buffer_pos+1) << 4) + as_hex(parser.buffer, parser.buffer_pos+2))
+
+ // If it is the leading octet, determine the length of the UTF-8 sequence.
+ if w == 1024 {
+ w = width(octet)
+ if w == 0 {
+ return yaml_parser_set_scanner_tag_error(parser, directive,
+ start_mark, "found an incorrect leading UTF-8 octet")
+ }
+ } else {
+ // Check if the trailing octet is correct.
+ if octet&0xC0 != 0x80 {
+ return yaml_parser_set_scanner_tag_error(parser, directive,
+ start_mark, "found an incorrect trailing UTF-8 octet")
+ }
+ }
+
+ // Copy the octet and move the pointers.
+ *s = append(*s, octet)
+ skip(parser)
+ skip(parser)
+ skip(parser)
+ w--
+ }
+ return true
+}
+
+// Scan a block scalar.
+func yaml_parser_scan_block_scalar(parser *yaml_parser_t, token *yaml_token_t, literal bool) bool {
+ // Eat the indicator '|' or '>'.
+ start_mark := parser.mark
+ skip(parser)
+
+ // Scan the additional block scalar indicators.
+ if !cache(parser, 1) {
+ return false
+ }
+
+ // Check for a chomping indicator.
+ var chomping, increment int
+ if parser.buffer[parser.buffer_pos] == '+' || parser.buffer[parser.buffer_pos] == '-' {
+ // Set the chomping method and eat the indicator.
+ if parser.buffer[parser.buffer_pos] == '+' {
+ chomping = +1
+ } else {
+ chomping = -1
+ }
+ skip(parser)
+
+ // Check for an indentation indicator.
+ if !cache(parser, 1) {
+ return false
+ }
+ if is_digit(parser.buffer, parser.buffer_pos) {
+ // Check that the intendation is greater than 0.
+ if parser.buffer[parser.buffer_pos] == '0' {
+ yaml_parser_set_scanner_error(parser, "while scanning a block scalar",
+ start_mark, "found an intendation indicator equal to 0")
+ return false
+ }
+
+ // Get the intendation level and eat the indicator.
+ increment = as_digit(parser.buffer, parser.buffer_pos)
+ skip(parser)
+ }
+
+ } else if is_digit(parser.buffer, parser.buffer_pos) {
+ // Do the same as above, but in the opposite order.
+
+ if parser.buffer[parser.buffer_pos] == '0' {
+ yaml_parser_set_scanner_error(parser, "while scanning a block scalar",
+ start_mark, "found an intendation indicator equal to 0")
+ return false
+ }
+ increment = as_digit(parser.buffer, parser.buffer_pos)
+ skip(parser)
+
+ if !cache(parser, 1) {
+ return false
+ }
+ if parser.buffer[parser.buffer_pos] == '+' || parser.buffer[parser.buffer_pos] == '-' {
+ if parser.buffer[parser.buffer_pos] == '+' {
+ chomping = +1
+ } else {
+ chomping = -1
+ }
+ skip(parser)
+ }
+ }
+
+ // Eat whitespaces and comments to the end of the line.
+ if !cache(parser, 1) {
+ return false
+ }
+ for is_blank(parser.buffer, parser.buffer_pos) {
+ skip(parser)
+ if !cache(parser, 1) {
+ return false
+ }
+ }
+ if parser.buffer[parser.buffer_pos] == '#' {
+ for !is_breakz(parser.buffer, parser.buffer_pos) {
+ skip(parser)
+ if !cache(parser, 1) {
+ return false
+ }
+ }
+ }
+
+ // Check if we are at the end of the line.
+ if !is_breakz(parser.buffer, parser.buffer_pos) {
+ yaml_parser_set_scanner_error(parser, "while scanning a block scalar",
+ start_mark, "did not find expected comment or line break")
+ return false
+ }
+
+ // Eat a line break.
+ if is_break(parser.buffer, parser.buffer_pos) {
+ if !cache(parser, 2) {
+ return false
+ }
+ skip_line(parser)
+ }
+
+ end_mark := parser.mark
+
+ // Set the intendation level if it was specified.
+ var indent int
+ if increment > 0 {
+ if parser.indent >= 0 {
+ indent = parser.indent + increment
+ } else {
+ indent = increment
+ }
+ }
+
+ // Scan the leading line breaks and determine the indentation level if needed.
+ var s, leading_break, trailing_breaks []byte
+ if !yaml_parser_scan_block_scalar_breaks(parser, &indent, &trailing_breaks, start_mark, &end_mark) {
+ return false
+ }
+
+ // Scan the block scalar content.
+ if !cache(parser, 1) {
+ return false
+ }
+ var leading_blank, trailing_blank bool
+ for parser.mark.column == indent && !is_z(parser.buffer, parser.buffer_pos) {
+ // We are at the beginning of a non-empty line.
+
+ // Is it a trailing whitespace?
+ trailing_blank = is_blank(parser.buffer, parser.buffer_pos)
+
+ // Check if we need to fold the leading line break.
+ if !literal && !leading_blank && !trailing_blank && leading_break[0] == '\n' {
+ // Do we need to join the lines by space?
+ if len(trailing_breaks) == 0 {
+ s = append(s, ' ')
+ }
+ } else {
+ s = append(s, leading_break...)
+ }
+ leading_break = leading_break[:0]
+
+ // Append the remaining line breaks.
+ s = append(s, trailing_breaks...)
+ trailing_breaks = trailing_breaks[:0]
+
+ // Is it a leading whitespace?
+ leading_blank = is_blank(parser.buffer, parser.buffer_pos)
+
+ // Consume the current line.
+ for !is_breakz(parser.buffer, parser.buffer_pos) {
+ if !read(parser, &s) {
+ return false
+ }
+ if !cache(parser, 1) {
+ return false
+ }
+ }
+
+ // Consume the line break.
+ if !cache(parser, 2) {
+ return false
+ }
+
+ if !read_line(parser, &leading_break) {
+ return false
+ }
+
+ // Eat the following intendation spaces and line breaks.
+ if !yaml_parser_scan_block_scalar_breaks(parser, &indent, &trailing_breaks, start_mark, &end_mark) {
+ return false
+ }
+ }
+
+ // Chomp the tail.
+ if chomping != -1 {
+ s = append(s, leading_break...)
+ }
+ if chomping == 1 {
+ s = append(s, trailing_breaks...)
+ }
+
+ // Create a token.
+ *token = yaml_token_t{
+ typ: yaml_SCALAR_TOKEN,
+ start_mark: start_mark,
+ end_mark: end_mark,
+ }
+ token.scalar.value = s
+ if literal {
+ token.scalar.style = yaml_LITERAL_SCALAR_STYLE
+ } else {
+ token.scalar.style = yaml_FOLDED_SCALAR_STYLE
+ }
+
+ return true
+}
+
+// Scan intendation spaces and line breaks for a block scalar. Determine the
+// intendation level if needed.
+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 {
+ *end_mark = parser.mark
+
+ // Eat the intendation spaces and line breaks.
+ max_indent := 0
+ for {
+ // Eat the intendation spaces.
+ if !cache(parser, 1) {
+ return false
+ }
+ for *indent == 0 || parser.mark.column < *indent && is_space(parser.buffer, parser.buffer_pos) {
+ skip(parser)
+ if !cache(parser, 1) {
+ return false
+ }
+ }
+ if parser.mark.column > max_indent {
+ max_indent = parser.mark.column
+ }
+
+ // Check for a tab character messing the intendation.
+ if (*indent == 0 || parser.mark.column < *indent) && is_tab(parser.buffer, parser.buffer_pos) {
+ return yaml_parser_set_scanner_error(parser, "while scanning a block scalar",
+ start_mark, "found a tab character where an intendation space is expected")
+ }
+
+ // Have we found a non-empty line?
+ if !is_break(parser.buffer, parser.buffer_pos) {
+ break
+ }
+
+ // Consume the line break.
+ if !cache(parser, 2) {
+ return false
+ }
+ if !read_line(parser, breaks) {
+ return false
+ }
+ *end_mark = parser.mark
+ }
+
+ // Determine the indentation level if needed.
+ if *indent == 0 {
+ *indent = max_indent
+ if *indent < parser.indent+1 {
+ *indent = parser.indent + 1
+ }
+ if *indent < 1 {
+ *indent = 1
+ }
+ }
+ return true
+}
+
+// Scan a quoted scalar.
+func yaml_parser_scan_flow_scalar(parser *yaml_parser_t, token *yaml_token_t, single bool) bool {
+ // Eat the left quote.
+ start_mark := parser.mark
+ skip(parser)
+
+ // Consume the content of the quoted scalar.
+ var s, leading_break, trailing_breaks, whitespaces []byte
+ for {
+ // Check that there are no document indicators at the beginning of the line.
+ if !cache(parser, 4) {
+ return false
+ }
+
+ if parser.mark.column == 0 &&
+ ((parser.buffer[parser.buffer_pos+0] == '-' &&
+ parser.buffer[parser.buffer_pos+1] == '-' &&
+ parser.buffer[parser.buffer_pos+2] == '-') ||
+ (parser.buffer[parser.buffer_pos+0] == '.' &&
+ parser.buffer[parser.buffer_pos+1] == '.' &&
+ parser.buffer[parser.buffer_pos+2] == '.')) &&
+ is_blankz(parser.buffer, parser.buffer_pos+3) {
+ yaml_parser_set_scanner_error(parser, "while scanning a quoted scalar",
+ start_mark, "found unexpected document indicator")
+ return false
+ }
+
+ // Check for EOF.
+ if is_z(parser.buffer, parser.buffer_pos) {
+ yaml_parser_set_scanner_error(parser, "while scanning a quoted scalar",
+ start_mark, "found unexpected end of stream")
+ return false
+ }
+
+ // Consume non-blank characters.
+ if !cache(parser, 2) {
+ return false
+ }
+ leading_blanks := false
+ for !is_blankz(parser.buffer, parser.buffer_pos) {
+ if single && parser.buffer[parser.buffer_pos] == '\'' && parser.buffer[parser.buffer_pos+1] == '\'' {
+ // Is is an escaped single quote.
+ s = append(s, '\'')
+ skip(parser)
+ skip(parser)
+
+ } else if single && parser.buffer[parser.buffer_pos] == '\'' {
+ // It is a right single quote.
+ break
+ } else if !single && parser.buffer[parser.buffer_pos] == '"' {
+ // It is a right double quote.
+ break
+
+ } else if !single && parser.buffer[parser.buffer_pos] == '\\' && is_break(parser.buffer, parser.buffer_pos+1) {
+ // It is an escaped line break.
+ if !cache(parser, 3) {
+ return false
+ }
+ skip(parser)
+ skip_line(parser)
+ leading_blanks = true
+ break
+
+ } else if !single && parser.buffer[parser.buffer_pos] == '\\' {
+ // It is an escape sequence.
+ code_length := 0
+
+ // Check the escape character.
+ switch parser.buffer[parser.buffer_pos+1] {
+ case '0':
+ s = append(s, 0)
+ case 'a':
+ s = append(s, '\x07')
+ case 'b':
+ s = append(s, '\x08')
+ case 't', '\t':
+ s = append(s, '\x09')
+ case 'n':
+ s = append(s, '\x0A')
+ case 'v':
+ s = append(s, '\x0B')
+ case 'f':
+ s = append(s, '\x0C')
+ case 'r':
+ s = append(s, '\x0D')
+ case 'e':
+ s = append(s, '\x1B')
+ case ' ':
+ s = append(s, '\x20')
+ case '"':
+ s = append(s, '"')
+ case '\'':
+ s = append(s, '\'')
+ case '\\':
+ s = append(s, '\\')
+ case 'N': // NEL (#x85)
+ s = append(s, '\xC2')
+ s = append(s, '\x85')
+ case '_': // #xA0
+ s = append(s, '\xC2')
+ s = append(s, '\xA0')
+ case 'L': // LS (#x2028)
+ s = append(s, '\xE2')
+ s = append(s, '\x80')
+ s = append(s, '\xA8')
+ case 'P': // PS (#x2029)
+ s = append(s, '\xE2')
+ s = append(s, '\x80')
+ s = append(s, '\xA9')
+ case 'x':
+ code_length = 2
+ case 'u':
+ code_length = 4
+ case 'U':
+ code_length = 8
+ default:
+ yaml_parser_set_scanner_error(parser, "while parsing a quoted scalar",
+ start_mark, "found unknown escape character")
+ return false
+ }
+
+ skip(parser)
+ skip(parser)
+
+ // Consume an arbitrary escape code.
+ if code_length > 0 {
+ var value int
+
+ // Scan the character value.
+ if !cache(parser, code_length) {
+ return false
+ }
+ for k := 0; k < code_length; k++ {
+ if !is_hex(parser.buffer, parser.buffer_pos+k) {
+ yaml_parser_set_scanner_error(parser, "while parsing a quoted scalar",
+ start_mark, "did not find expected hexdecimal number")
+ return false
+ }
+ value = (value << 4) + as_hex(parser.buffer, parser.buffer_pos+k)
+ }
+
+ // Check the value and write the character.
+ if (value >= 0xD800 && value <= 0xDFFF) || value > 0x10FFFF {
+ yaml_parser_set_scanner_error(parser, "while parsing a quoted scalar",
+ start_mark, "found invalid Unicode character escape code")
+ return false
+ }
+ if value <= 0x7F {
+ s = append(s, byte(value))
+ } else if value <= 0x7FF {
+ s = append(s, byte(0xC0+(value>>6)))
+ s = append(s, byte(0x80+(value&0x3F)))
+ } else if value <= 0xFFFF {
+ s = append(s, byte(0xE0+(value>>12)))
+ s = append(s, byte(0x80+((value>>6)&0x3F)))
+ s = append(s, byte(0x80+(value&0x3F)))
+ } else {
+ s = append(s, byte(0xF0+(value>>18)))
+ s = append(s, byte(0x80+((value>>12)&0x3F)))
+ s = append(s, byte(0x80+((value>>6)&0x3F)))
+ s = append(s, byte(0x80+(value&0x3F)))
+ }
+
+ // Advance the pointer.
+ for k := 0; k < code_length; k++ {
+ skip(parser)
+ }
+ }
+ } else {
+ // It is a non-escaped non-blank character.
+ if !read(parser, &s) {
+ return false
+ }
+ }
+ if !cache(parser, 2) {
+ return false
+ }
+ }
+
+ // Check if we are at the end of the scalar.
+ if single {
+ if parser.buffer[parser.buffer_pos] == '\'' {
+ break
+ }
+ } else {
+ if parser.buffer[parser.buffer_pos] == '"' {
+ break
+ }
+ }
+
+ // Consume blank characters.
+ if !cache(parser, 1) {
+ return false
+ }
+
+ for is_blank(parser.buffer, parser.buffer_pos) || is_break(parser.buffer, parser.buffer_pos) {
+ if is_blank(parser.buffer, parser.buffer_pos) {
+ // Consume a space or a tab character.
+ if !leading_blanks {
+ if !read(parser, &whitespaces) {
+ return false
+ }
+ } else {
+ skip(parser)
+ }
+ } else {
+ if !cache(parser, 2) {
+ return false
+ }
+
+ // Check if it is a first line break.
+ if !leading_blanks {
+ whitespaces = whitespaces[:0]
+ if !read_line(parser, &leading_break) {
+ return false
+ }
+ leading_blanks = true
+ } else {
+ if !read_line(parser, &trailing_breaks) {
+ return false
+ }
+ }
+ }
+ if !cache(parser, 1) {
+ return false
+ }
+ }
+
+ // Join the whitespaces or fold line breaks.
+ if leading_blanks {
+ // Do we need to fold line breaks?
+ if leading_break[0] == '\n' {
+ if len(trailing_breaks) == 0 {
+ s = append(s, ' ')
+ } else {
+ s = append(s, trailing_breaks...)
+ }
+ } else {
+ s = append(s, leading_break...)
+ s = append(s, trailing_breaks...)
+ }
+ trailing_breaks = trailing_breaks[:0]
+ leading_break = leading_break[:0]
+ } else {
+ s = append(s, whitespaces...)
+ whitespaces = whitespaces[:0]
+ }
+ }
+
+ // Eat the right quote.
+ skip(parser)
+ end_mark := parser.mark
+
+ // Create a token.
+ *token = yaml_token_t{
+ typ: yaml_SCALAR_TOKEN,
+ start_mark: start_mark,
+ end_mark: end_mark,
+ }
+ token.scalar.value = s
+ if single {
+ token.scalar.style = yaml_SINGLE_QUOTED_SCALAR_STYLE
+ } else {
+ token.scalar.style = yaml_DOUBLE_QUOTED_SCALAR_STYLE
+ }
+ return true
+}
+
+// Scan a plain scalar.
+func yaml_parser_scan_plain_scalar(parser *yaml_parser_t, token *yaml_token_t) bool {
+ var s, leading_break, trailing_breaks, whitespaces []byte
+ var leading_blanks bool
+ var indent = parser.indent + 1
+
+ start_mark := parser.mark
+ end_mark := parser.mark
+
+ // Consume the content of the plain scalar.
+ for {
+ // Check for a document indicator.
+ if !cache(parser, 4) {
+ return false
+ }
+ if parser.mark.column == 0 &&
+ ((parser.buffer[parser.buffer_pos+0] == '-' &&
+ parser.buffer[parser.buffer_pos+1] == '-' &&
+ parser.buffer[parser.buffer_pos+2] == '-') ||
+ (parser.buffer[parser.buffer_pos+0] == '.' &&
+ parser.buffer[parser.buffer_pos+1] == '.' &&
+ parser.buffer[parser.buffer_pos+2] == '.')) &&
+ is_blankz(parser.buffer, parser.buffer_pos+3) {
+ break
+ }
+
+ // Check for a comment.
+ if parser.buffer[parser.buffer_pos] == '#' {
+ break
+ }
+
+ // Consume non-blank characters.
+ for !is_blankz(parser.buffer, parser.buffer_pos) {
+
+ // Check for 'x:x' in the flow context. TODO: Fix the test "spec-08-13".
+ if parser.flow_level > 0 &&
+ parser.buffer[parser.buffer_pos] == ':' &&
+ !is_blankz(parser.buffer, parser.buffer_pos+1) {
+ yaml_parser_set_scanner_error(parser, "while scanning a plain scalar",
+ start_mark, "found unexpected ':'")
+ return false
+ }
+
+ // Check for indicators that may end a plain scalar.
+ if (parser.buffer[parser.buffer_pos] == ':' && is_blankz(parser.buffer, parser.buffer_pos+1)) ||
+ (parser.flow_level > 0 &&
+ (parser.buffer[parser.buffer_pos] == ',' || parser.buffer[parser.buffer_pos] == ':' ||
+ parser.buffer[parser.buffer_pos] == '?' || parser.buffer[parser.buffer_pos] == '[' ||
+ parser.buffer[parser.buffer_pos] == ']' || parser.buffer[parser.buffer_pos] == '{' ||
+ parser.buffer[parser.buffer_pos] == '}')) {
+ break
+ }
+
+ // Check if we need to join whitespaces and breaks.
+ if leading_blanks || len(whitespaces) > 0 {
+ if leading_blanks {
+ // Do we need to fold line breaks?
+ if leading_break[0] == '\n' {
+ if len(trailing_breaks) == 0 {
+ s = append(s, ' ')
+ } else {
+ s = append(s, trailing_breaks...)
+ }
+ } else {
+ s = append(s, leading_break...)
+ s = append(s, trailing_breaks...)
+ }
+ trailing_breaks = trailing_breaks[:0]
+ leading_break = leading_break[:0]
+ leading_blanks = false
+ } else {
+ s = append(s, whitespaces...)
+ whitespaces = whitespaces[:0]
+ }
+ }
+
+ // Copy the character.
+ if !read(parser, &s) {
+ return false
+ }
+
+ end_mark = parser.mark
+ if !cache(parser, 2) {
+ return false
+ }
+ }
+
+ // Is it the end?
+ if !(is_blank(parser.buffer, parser.buffer_pos) || is_break(parser.buffer, parser.buffer_pos)) {
+ break
+ }
+
+ // Consume blank characters.
+ if !cache(parser, 1) {
+ return false
+ }
+
+ for is_blank(parser.buffer, parser.buffer_pos) || is_break(parser.buffer, parser.buffer_pos) {
+ if is_blank(parser.buffer, parser.buffer_pos) {
+
+ // Check for tab character that abuse intendation.
+ if leading_blanks && parser.mark.column < indent && is_tab(parser.buffer, parser.buffer_pos) {
+ yaml_parser_set_scanner_error(parser, "while scanning a plain scalar",
+ start_mark, "found a tab character that violate intendation")
+ return false
+ }
+
+ // Consume a space or a tab character.
+ if !leading_blanks {
+ if !read(parser, &whitespaces) {
+ return false
+ }
+ } else {
+ skip(parser)
+ }
+ } else {
+ if !cache(parser, 2) {
+ return false
+ }
+
+ // Check if it is a first line break.
+ if !leading_blanks {
+ whitespaces = whitespaces[:0]
+ if !read_line(parser, &leading_break) {
+ return false
+ }
+ leading_blanks = true
+ } else {
+ if !read_line(parser, &trailing_breaks) {
+ return false
+ }
+ }
+ }
+ if !cache(parser, 1) {
+ return false
+ }
+ }
+
+ // Check intendation level.
+ if parser.flow_level == 0 && parser.mark.column < indent {
+ break
+ }
+ }
+
+ // Create a token.
+ *token = yaml_token_t{
+ typ: yaml_SCALAR_TOKEN,
+ start_mark: start_mark,
+ end_mark: end_mark,
+ }
+ token.scalar.value = s
+ token.scalar.style = yaml_PLAIN_SCALAR_STYLE
+
+ // Note that we change the 'simple_key_allowed' flag.
+ if leading_blanks {
+ parser.simple_key_allowed = true
+ }
+ return true
+}
diff --git a/yaml_h.go b/yaml_h.go
new file mode 100644
index 0000000..ad23067
--- /dev/null
+++ b/yaml_h.go
@@ -0,0 +1,1513 @@
+package goyaml
+
+import (
+ "io"
+)
+
+// The version directive data.
+type yaml_version_directive_t struct {
+ major int // The major version number.
+ minor int // The minor version number.
+}
+
+// The tag directive data.
+type yaml_tag_directive_t struct {
+ handle []byte // The tag handle.
+ prefix []byte // The tag prefix.
+}
+
+type yaml_encoding_t int
+
+// The stream encoding.
+const (
+ // Let the parser choose the encoding.
+ yaml_ANY_ENCODING yaml_encoding_t = iota
+
+ yaml_UTF8_ENCODING // The default UTF-8 encoding.
+ yaml_UTF16LE_ENCODING // The UTF-16-LE encoding with BOM.
+ yaml_UTF16BE_ENCODING // The UTF-16-BE encoding with BOM.
+)
+
+type yaml_break_t int
+
+// Line break types.
+const (
+ // Let the parser choose the break type.
+ yaml_ANY_BREAK yaml_break_t = iota
+
+ yaml_CR_BREAK // Use CR for line breaks (Mac style).
+ yaml_LN_BREAK // Use LN for line breaks (Unix style).
+ yaml_CRLN_BREAK // Use CR LN for line breaks (DOS style).
+)
+
+type yaml_error_type_t int
+
+// Many bad things could happen with the parser and emitter.
+const (
+ // No error is produced.
+ yaml_NO_ERROR yaml_error_type_t = iota
+
+ yaml_MEMORY_ERROR // Cannot allocate or reallocate a block of memory.
+ yaml_READER_ERROR // Cannot read or decode the input stream.
+ yaml_SCANNER_ERROR // Cannot scan the input stream.
+ yaml_PARSER_ERROR // Cannot parse the input stream.
+ yaml_COMPOSER_ERROR // Cannot compose a YAML document.
+ yaml_WRITER_ERROR // Cannot write to the output stream.
+ yaml_EMITTER_ERROR // Cannot emit a YAML stream.
+)
+
+// The pointer position.
+type yaml_mark_t struct {
+ index int // The position index.
+ line int // The position line.
+ column int // The position column.
+}
+
+// Node Styles
+
+type yaml_scalar_style_t int
+
+// Scalar styles.
+const (
+ // Let the emitter choose the style.
+ yaml_ANY_SCALAR_STYLE yaml_scalar_style_t = iota
+
+ yaml_PLAIN_SCALAR_STYLE // The plain scalar style.
+ yaml_SINGLE_QUOTED_SCALAR_STYLE // The single-quoted scalar style.
+ yaml_DOUBLE_QUOTED_SCALAR_STYLE // The double-quoted scalar style.
+ yaml_LITERAL_SCALAR_STYLE // The literal scalar style.
+ yaml_FOLDED_SCALAR_STYLE // The folded scalar style.
+)
+
+type yaml_sequence_style_t int
+
+// Sequence styles.
+const (
+ // Let the emitter choose the style.
+ yaml_ANY_SEQUENCE_STYLE yaml_sequence_style_t = iota
+
+ yaml_BLOCK_SEQUENCE_STYLE // The block sequence style.
+ yaml_FLOW_SEQUENCE_STYLE // The flow sequence style.
+)
+
+type yaml_mapping_style_t int
+
+// Mapping styles.
+const (
+ // Let the emitter choose the style.
+ YAML_ANY_MAPPING_STYLE yaml_mapping_style_t = iota
+
+ yaml_BLOCK_MAPPING_STYLE // The block mapping style.
+ yaml_FLOW_MAPPING_STYLE // The flow mapping style.
+)
+
+// Tokens
+
+type yaml_token_type_t int
+
+// Token types.
+const (
+ // An empty token.
+ yaml_NO_TOKEN yaml_token_type_t = iota
+
+ yaml_STREAM_START_TOKEN // A STREAM-START token.
+ yaml_STREAM_END_TOKEN // A STREAM-END token.
+
+ yaml_VERSION_DIRECTIVE_TOKEN // A VERSION-DIRECTIVE token.
+ yaml_TAG_DIRECTIVE_TOKEN // A TAG-DIRECTIVE token.
+ yaml_DOCUMENT_START_TOKEN // A DOCUMENT-START token.
+ yaml_DOCUMENT_END_TOKEN // A DOCUMENT-END token.
+
+ yaml_BLOCK_SEQUENCE_START_TOKEN // A BLOCK-SEQUENCE-START token.
+ yaml_BLOCK_MAPPING_START_TOKEN // A BLOCK-SEQUENCE-END token.
+ yaml_BLOCK_END_TOKEN // A BLOCK-END token.
+
+ yaml_FLOW_SEQUENCE_START_TOKEN // A FLOW-SEQUENCE-START token.
+ yaml_FLOW_SEQUENCE_END_TOKEN // A FLOW-SEQUENCE-END token.
+ yaml_FLOW_MAPPING_START_TOKEN // A FLOW-MAPPING-START token.
+ yaml_FLOW_MAPPING_END_TOKEN // A FLOW-MAPPING-END token.
+
+ yaml_BLOCK_ENTRY_TOKEN // A BLOCK-ENTRY token.
+ yaml_FLOW_ENTRY_TOKEN // A FLOW-ENTRY token.
+ yaml_KEY_TOKEN // A KEY token.
+ yaml_VALUE_TOKEN // A VALUE token.
+
+ yaml_ALIAS_TOKEN // An ALIAS token.
+ yaml_ANCHOR_TOKEN // An ANCHOR token.
+ yaml_TAG_TOKEN // A TAG token.
+ yaml_SCALAR_TOKEN // A SCALAR token.
+)
+
+// The token structure.
+type yaml_token_t struct {
+
+ // The token type.
+ typ yaml_token_type_t
+
+ // The token data.
+
+ // The stream start (for yaml_STREAM_START_TOKEN).
+ stream_start struct {
+ encoding yaml_encoding_t // The stream encoding.
+ }
+
+ // The alias (for yaml_ALIAS_TOKEN).
+ alias struct {
+ value []byte // The alias value.
+ }
+
+ // The anchor (for yaml_ANCHOR_TOKEN).
+ anchor struct {
+ value []byte // The anchor value.
+ }
+
+ // The tag (for yaml_TAG_TOKEN).
+ tag struct {
+ handle []byte // The tag handle.
+ suffix []byte // The tag suffix.
+ }
+
+ // The scalar value (for yaml_SCALAR_TOKEN).
+ scalar struct {
+ value []byte // The scalar value.
+ style yaml_scalar_style_t // The scalar style.
+ }
+
+ // The version directive (for yaml_VERSION_DIRECTIVE_TOKEN).
+ version_directive struct {
+ major int // The major version number.
+ minor int // The minor version number.
+ }
+
+ // The tag directive (for yaml_TAG_DIRECTIVE_TOKEN).
+ tag_directive struct {
+ handle []byte // The tag handle.
+ prefix []byte // The tag prefix.
+ }
+
+ // The beginning of the token.
+ start_mark yaml_mark_t
+ // The end of the token.
+ end_mark yaml_mark_t
+}
+
+// Events
+
+type yaml_event_type_t int
+
+// Event types.
+const (
+ // An empty event.
+ yaml_NO_EVENT yaml_event_type_t = iota
+
+ yaml_STREAM_START_EVENT // A STREAM-START event.
+ yaml_STREAM_END_EVENT // A STREAM-END event.
+ yaml_DOCUMENT_START_EVENT // A DOCUMENT-START event.
+ yaml_DOCUMENT_END_EVENT // A DOCUMENT-END event.
+ yaml_ALIAS_EVENT // An ALIAS event.
+ yaml_SCALAR_EVENT // A SCALAR event.
+ yaml_SEQUENCE_START_EVENT // A SEQUENCE-START event.
+ yaml_SEQUENCE_END_EVENT // A SEQUENCE-END event.
+ yaml_MAPPING_START_EVENT // A MAPPING-START event.
+ yaml_MAPPING_END_EVENT // A MAPPING-END event.
+)
+
+// The event structure.
+type yaml_event_t struct {
+
+ // The event type.
+ typ yaml_event_type_t
+
+ // The event data.
+
+ // The stream parameters (for yaml_STREAM_START_EVENT).
+ stream_start struct {
+ encoding yaml_encoding_t // The document encoding.
+ }
+
+ // The document parameters (for yaml_DOCUMENT_START_EVENT).
+ document_start struct {
+ version_directive *yaml_version_directive_t // The version directive.
+
+ // The list of tag directives.
+ tag_directives []yaml_tag_directive_t
+ implicit bool // Is the document indicator implicit?
+ }
+
+ // The document end parameters (for yaml_DOCUMENT_END_EVENT).
+ document_end struct {
+ implicit bool // Is the document end indicator implicit?
+ }
+
+ // The alias parameters (for yaml_ALIAS_EVENT).
+ alias struct {
+ anchor []byte // The anchor.
+ }
+
+ // The scalar parameters (for yaml_SCALAR_EVENT).
+ scalar struct {
+ anchor []byte // The anchor.
+ tag []byte // The tag.
+ value []byte // The scalar value.
+ length int // The length of the scalar value.
+ plain_implicit bool // Is the tag optional for the plain style?
+ quoted_implicit bool // Is the tag optional for any non-plain style?
+ style yaml_scalar_style_t // The scalar style.
+ }
+
+ // The sequence parameters (for yaml_SEQUENCE_START_EVENT).
+ sequence_start struct {
+ anchor []byte // The anchor.
+ tag []byte // The tag.
+ implicit bool // Is the tag optional?
+ style yaml_sequence_style_t // The sequence style.
+ }
+
+ // The mapping parameters (for yaml_MAPPING_START_EVENT).
+ mapping_start struct {
+ anchor []byte // The anchor.
+ tag []byte // The tag.
+ implicit bool // Is the tag optional?
+ style yaml_mapping_style_t // The mapping style.
+ }
+
+ start_mark yaml_mark_t // The beginning of the event.
+ end_mark yaml_mark_t // The end of the event.
+
+}
+
+///**
+// * Create the STREAM-START event.
+// *
+// * @param[out] event An empty event object.
+// * @param[in] encoding The stream encoding.
+// *
+// * @returns @c 1 if the function succeeded, @c 0 on error.
+// */
+//
+//YAML_DECLARE(int)
+//yaml_stream_start_event_initialize(yaml_event_t *event,
+// yaml_encoding_t encoding);
+//
+///**
+// * Create the STREAM-END event.
+// *
+// * @param[out] event An empty event object.
+// *
+// * @returns @c 1 if the function succeeded, @c 0 on error.
+// */
+//
+//YAML_DECLARE(int)
+//yaml_stream_end_event_initialize(yaml_event_t *event);
+//
+///**
+// * Create the DOCUMENT-START event.
+// *
+// * The @a implicit argument is considered as a stylistic parameter and may be
+// * ignored by the emitter.
+// *
+// * @param[out] event An empty event object.
+// * @param[in] version_directive The %YAML directive value or
+// * @c NULL.
+// * @param[in] tag_directives_start The beginning of the %TAG
+// * directives list.
+// * @param[in] tag_directives_end The end of the %TAG directives
+// * list.
+// * @param[in] implicit If the document start indicator is
+// * implicit.
+// *
+// * @returns @c 1 if the function succeeded, @c 0 on error.
+// */
+//
+//YAML_DECLARE(int)
+//yaml_document_start_event_initialize(yaml_event_t *event,
+// yaml_version_directive_t *version_directive,
+// yaml_tag_directive_t *tag_directives_start,
+// yaml_tag_directive_t *tag_directives_end,
+// int implicit);
+//
+///**
+// * Create the DOCUMENT-END event.
+// *
+// * The @a implicit argument is considered as a stylistic parameter and may be
+// * ignored by the emitter.
+// *
+// * @param[out] event An empty event object.
+// * @param[in] implicit If the document end indicator is implicit.
+// *
+// * @returns @c 1 if the function succeeded, @c 0 on error.
+// */
+//
+//YAML_DECLARE(int)
+//yaml_document_end_event_initialize(yaml_event_t *event, int implicit);
+//
+///**
+// * Create an ALIAS event.
+// *
+// * @param[out] event An empty event object.
+// * @param[in] anchor The anchor value.
+// *
+// * @returns @c 1 if the function succeeded, @c 0 on error.
+// */
+//
+//YAML_DECLARE(int)
+//yaml_alias_event_initialize(yaml_event_t *event, yaml_char_t *anchor);
+//
+///**
+// * Create a SCALAR event.
+// *
+// * The @a style argument may be ignored by the emitter.
+// *
+// * Either the @a tag attribute or one of the @a plain_implicit and
+// * @a quoted_implicit flags must be set.
+// *
+// * @param[out] event An empty event object.
+// * @param[in] anchor The scalar anchor or @c NULL.
+// * @param[in] tag The scalar tag or @c NULL.
+// * @param[in] value The scalar value.
+// * @param[in] length The length of the scalar value.
+// * @param[in] plain_implicit If the tag may be omitted for the plain
+// * style.
+// * @param[in] quoted_implicit If the tag may be omitted for any
+// * non-plain style.
+// * @param[in] style The scalar style.
+// *
+// * @returns @c 1 if the function succeeded, @c 0 on error.
+// */
+//
+//YAML_DECLARE(int)
+//yaml_scalar_event_initialize(yaml_event_t *event,
+// yaml_char_t *anchor, yaml_char_t *tag,
+// yaml_char_t *value, int length,
+// int plain_implicit, int quoted_implicit,
+// yaml_scalar_style_t style);
+//
+///**
+// * Create a SEQUENCE-START event.
+// *
+// * The @a style argument may be ignored by the emitter.
+// *
+// * Either the @a tag attribute or the @a implicit flag must be set.
+// *
+// * @param[out] event An empty event object.
+// * @param[in] anchor The sequence anchor or @c NULL.
+// * @param[in] tag The sequence tag or @c NULL.
+// * @param[in] implicit If the tag may be omitted.
+// * @param[in] style The sequence style.
+// *
+// * @returns @c 1 if the function succeeded, @c 0 on error.
+// */
+//
+//YAML_DECLARE(int)
+//yaml_sequence_start_event_initialize(yaml_event_t *event,
+// yaml_char_t *anchor, yaml_char_t *tag, int implicit,
+// yaml_sequence_style_t style);
+//
+///**
+// * Create a SEQUENCE-END event.
+// *
+// * @param[out] event An empty event object.
+// *
+// * @returns @c 1 if the function succeeded, @c 0 on error.
+// */
+//
+//YAML_DECLARE(int)
+//yaml_sequence_end_event_initialize(yaml_event_t *event);
+//
+///**
+// * Create a MAPPING-START event.
+// *
+// * The @a style argument may be ignored by the emitter.
+// *
+// * Either the @a tag attribute or the @a implicit flag must be set.
+// *
+// * @param[out] event An empty event object.
+// * @param[in] anchor The mapping anchor or @c NULL.
+// * @param[in] tag The mapping tag or @c NULL.
+// * @param[in] implicit If the tag may be omitted.
+// * @param[in] style The mapping style.
+// *
+// * @returns @c 1 if the function succeeded, @c 0 on error.
+// */
+//
+//YAML_DECLARE(int)
+//yaml_mapping_start_event_initialize(yaml_event_t *event,
+// yaml_char_t *anchor, yaml_char_t *tag, int implicit,
+// yaml_mapping_style_t style);
+//
+///**
+// * Create a MAPPING-END event.
+// *
+// * @param[out] event An empty event object.
+// *
+// * @returns @c 1 if the function succeeded, @c 0 on error.
+// */
+//
+//YAML_DECLARE(int)
+//yaml_mapping_end_event_initialize(yaml_event_t *event);
+//
+///**
+// * Free any memory allocated for an event object.
+// *
+// * @param[in,out] event An event object.
+// */
+//
+//YAML_DECLARE(void)
+//yaml_event_delete(yaml_event_t *event);
+//
+//// @}
+//
+
+// Nodes
+
+const (
+ yaml_NULL_TAG = "tag:yaml.org,2002:null" // The tag !!null with the only possible value: null.
+ yaml_BOOL_TAG = "tag:yaml.org,2002:bool" // The tag !!bool with the values: true and false.
+ yaml_STR_TAG = "tag:yaml.org,2002:str" // The tag !!str for string values.
+ yaml_INT_TAG = "tag:yaml.org,2002:int" // The tag !!int for integer values.
+ yaml_FLOAT_TAG = "tag:yaml.org,2002:float" // The tag !!float for float values.
+ yaml_TIMESTAMP_TAG = "tag:yaml.org,2002:timestamp" // The tag !!timestamp for date and time values.
+
+ yaml_SEQ_TAG = "tag:yaml.org,2002:seq" // The tag !!seq is used to denote sequences.
+ yaml_MAP_TAG = "tag:yaml.org,2002:map" // The tag !!map is used to denote mapping.
+
+ yaml_DEFAULT_SCALAR_TAG = yaml_STR_TAG // The default scalar tag is !!str.
+ yaml_DEFAULT_SEQUENCE_TAG = yaml_SEQ_TAG // The default sequence tag is !!seq.
+ yaml_DEFAULT_MAPPING_TAG = yaml_MAP_TAG // The default mapping tag is !!map.
+)
+
+type yaml_node_type_t int
+
+// Node types.
+const (
+ // An empty node.
+ yaml_NO_NODE yaml_node_type_t = iota
+
+ yaml_SCALAR_NODE // A scalar node.
+ yaml_SEQUENCE_NODE // A sequence node.
+ yaml_MAPPING_NODE // A mapping node.
+)
+
+// An element of a sequence node.
+type yaml_node_item_t int
+
+// An element of a mapping node.
+type yaml_node_pair_t struct {
+ key int // The key of the element.
+ value int // The value of the element.
+}
+
+// The node structure.
+type yaml_node_t struct {
+ typ yaml_node_type_t // The node type.
+ tag []byte // The node tag.
+
+ // The node data.
+
+ // The scalar parameters (for yaml_SCALAR_NODE).
+ scalar struct {
+ value []byte // The scalar value.
+ length int // The length of the scalar value.
+ style yaml_scalar_style_t // The scalar style.
+ }
+
+ // The sequence parameters (for YAML_SEQUENCE_NODE).
+ sequence struct {
+ items_data []yaml_node_item_t // The stack of sequence items.
+ style yaml_sequence_style_t // The sequence style.
+ }
+
+ // The mapping parameters (for yaml_MAPPING_NODE).
+ mapping struct {
+ pairs_data []yaml_node_pair_t // The stack of mapping pairs (key, value).
+ pairs_start *yaml_node_pair_t // The beginning of the stack.
+ pairs_end *yaml_node_pair_t // The end of the stack.
+ pairs_top *yaml_node_pair_t // The top of the stack.
+ style yaml_mapping_style_t // The mapping style.
+ }
+
+ start_mark yaml_mark_t // The beginning of the node.
+ end_mark yaml_mark_t // The end of the node.
+
+}
+
+// The document structure.
+type yaml_document_t struct {
+
+ // The document nodes.
+ nodes []yaml_node_t
+
+ // The version directive.
+ version_directive *yaml_version_directive_t
+
+ // The list of tag directives.
+ tag_directives_data []yaml_tag_directive_t
+ tag_directives_start int // The beginning of the tag directives list.
+ tag_directives_end int // The end of the tag directives list.
+
+ start_implicit int // Is the document start indicator implicit?
+ end_implicit int // Is the document end indicator implicit?
+
+ start_mark yaml_mark_t // The beginning of the document.
+ end_mark yaml_mark_t // The end of the document.
+
+}
+
+///**
+// * Create a YAML document.
+// *
+// * @param[out] document An empty document object.
+// * @param[in] version_directive The %YAML directive value or
+// * @c NULL.
+// * @param[in] tag_directives_start The beginning of the %TAG
+// * directives list.
+// * @param[in] tag_directives_end The end of the %TAG directives
+// * list.
+// * @param[in] start_implicit If the document start indicator is
+// * implicit.
+// * @param[in] end_implicit If the document end indicator is
+// * implicit.
+// *
+// * @returns @c 1 if the function succeeded, @c 0 on error.
+// */
+//
+//YAML_DECLARE(int)
+//yaml_document_initialize(yaml_document_t *document,
+// yaml_version_directive_t *version_directive,
+// yaml_tag_directive_t *tag_directives_start,
+// yaml_tag_directive_t *tag_directives_end,
+// int start_implicit, int end_implicit);
+//
+///**
+// * Delete a YAML document and all its nodes.
+// *
+// * @param[in,out] document A document object.
+// */
+//
+//YAML_DECLARE(void)
+//yaml_document_delete(yaml_document_t *document);
+//
+///**
+// * Get a node of a YAML document.
+// *
+// * The pointer returned by this function is valid until any of the functions
+// * modifying the documents are called.
+// *
+// * @param[in] document A document object.
+// * @param[in] index The node id.
+// *
+// * @returns the node objct or @c NULL if @c node_id is out of range.
+// */
+//
+//YAML_DECLARE(yaml_node_t *)
+//yaml_document_get_node(yaml_document_t *document, int index);
+//
+///**
+// * Get the root of a YAML document node.
+// *
+// * The root object is the first object added to the document.
+// *
+// * The pointer returned by this function is valid until any of the functions
+// * modifying the documents are called.
+// *
+// * An empty document produced by the parser signifies the end of a YAML
+// * stream.
+// *
+// * @param[in] document A document object.
+// *
+// * @returns the node object or @c NULL if the document is empty.
+// */
+//
+//YAML_DECLARE(yaml_node_t *)
+//yaml_document_get_root_node(yaml_document_t *document);
+//
+///**
+// * Create a SCALAR node and attach it to the document.
+// *
+// * The @a style argument may be ignored by the emitter.
+// *
+// * @param[in,out] document A document object.
+// * @param[in] tag The scalar tag.
+// * @param[in] value The scalar value.
+// * @param[in] length The length of the scalar value.
+// * @param[in] style The scalar style.
+// *
+// * @returns the node id or @c 0 on error.
+// */
+//
+//YAML_DECLARE(int)
+//yaml_document_add_scalar(yaml_document_t *document,
+// yaml_char_t *tag, yaml_char_t *value, int length,
+// yaml_scalar_style_t style);
+//
+///**
+// * Create a SEQUENCE node and attach it to the document.
+// *
+// * The @a style argument may be ignored by the emitter.
+// *
+// * @param[in,out] document A document object.
+// * @param[in] tag The sequence tag.
+// * @param[in] style The sequence style.
+// *
+// * @returns the node id or @c 0 on error.
+// */
+//
+//YAML_DECLARE(int)
+//yaml_document_add_sequence(yaml_document_t *document,
+// yaml_char_t *tag, yaml_sequence_style_t style);
+//
+///**
+// * Create a MAPPING node and attach it to the document.
+// *
+// * The @a style argument may be ignored by the emitter.
+// *
+// * @param[in,out] document A document object.
+// * @param[in] tag The sequence tag.
+// * @param[in] style The sequence style.
+// *
+// * @returns the node id or @c 0 on error.
+// */
+//
+//YAML_DECLARE(int)
+//yaml_document_add_mapping(yaml_document_t *document,
+// yaml_char_t *tag, yaml_mapping_style_t style);
+//
+///**
+// * Add an item to a SEQUENCE node.
+// *
+// * @param[in,out] document A document object.
+// * @param[in] sequence The sequence node id.
+// * @param[in] item The item node id.
+//*
+// * @returns @c 1 if the function succeeded, @c 0 on error.
+// */
+//
+//YAML_DECLARE(int)
+//yaml_document_append_sequence_item(yaml_document_t *document,
+// int sequence, int item);
+//
+///**
+// * Add a pair of a key and a value to a MAPPING node.
+// *
+// * @param[in,out] document A document object.
+// * @param[in] mapping The mapping node id.
+// * @param[in] key The key node id.
+// * @param[in] value The value node id.
+//*
+// * @returns @c 1 if the function succeeded, @c 0 on error.
+// */
+//
+//YAML_DECLARE(int)
+//yaml_document_append_mapping_pair(yaml_document_t *document,
+// int mapping, int key, int value);
+//
+
+// Parser Definitions
+
+// The prototype of a read handler.
+//
+// The read handler is called when the parser needs to read more bytes from the
+// source. The handler should write not more than size bytes to the buffer.
+// The number of written bytes should be set to the size_read variable.
+//
+// [in,out] data A pointer to an application data specified by
+// yaml_parser_set_input().
+// [out] buffer The buffer to write the data from the source.
+// [in] size The size of the buffer.
+// [out] size_read The actual number of bytes read from the source.
+//
+// On success, the handler should return 1. If the handler failed,
+// the returned value should be 0. On EOF, the handler should set the
+// size_read to 0 and return 1.
+type yaml_read_handler_t func(parser *yaml_parser_t, buffer []byte) (n int, err error)
+
+// This structure holds information about a potential simple key.
+type yaml_simple_key_t struct {
+ possible bool // Is a simple key possible?
+ required bool // Is a simple key required?
+ token_number int // The number of the token.
+ mark yaml_mark_t // The position mark.
+}
+
+// The states of the parser.
+type yaml_parser_state_t int
+
+const (
+ yaml_PARSE_STREAM_START_STATE yaml_parser_state_t = iota
+
+ yaml_PARSE_IMPLICIT_DOCUMENT_START_STATE // Expect the beginning of an implicit document.
+ yaml_PARSE_DOCUMENT_START_STATE // Expect DOCUMENT-START.
+ yaml_PARSE_DOCUMENT_CONTENT_STATE // Expect the content of a document.
+ yaml_PARSE_DOCUMENT_END_STATE // Expect DOCUMENT-END.
+ yaml_PARSE_BLOCK_NODE_STATE // Expect a block node.
+ yaml_PARSE_BLOCK_NODE_OR_INDENTLESS_SEQUENCE_STATE // Expect a block node or indentless sequence.
+ yaml_PARSE_FLOW_NODE_STATE // Expect a flow node.
+ yaml_PARSE_BLOCK_SEQUENCE_FIRST_ENTRY_STATE // Expect the first entry of a block sequence.
+ yaml_PARSE_BLOCK_SEQUENCE_ENTRY_STATE // Expect an entry of a block sequence.
+ yaml_PARSE_INDENTLESS_SEQUENCE_ENTRY_STATE // Expect an entry of an indentless sequence.
+ yaml_PARSE_BLOCK_MAPPING_FIRST_KEY_STATE // Expect the first key of a block mapping.
+ yaml_PARSE_BLOCK_MAPPING_KEY_STATE // Expect a block mapping key.
+ yaml_PARSE_BLOCK_MAPPING_VALUE_STATE // Expect a block mapping value.
+ yaml_PARSE_FLOW_SEQUENCE_FIRST_ENTRY_STATE // Expect the first entry of a flow sequence.
+ yaml_PARSE_FLOW_SEQUENCE_ENTRY_STATE // Expect an entry of a flow sequence.
+ yaml_PARSE_FLOW_SEQUENCE_ENTRY_MAPPING_KEY_STATE // Expect a key of an ordered mapping.
+ yaml_PARSE_FLOW_SEQUENCE_ENTRY_MAPPING_VALUE_STATE // Expect a value of an ordered mapping.
+ yaml_PARSE_FLOW_SEQUENCE_ENTRY_MAPPING_END_STATE // Expect the and of an ordered mapping entry.
+ yaml_PARSE_FLOW_MAPPING_FIRST_KEY_STATE // Expect the first key of a flow mapping.
+ yaml_PARSE_FLOW_MAPPING_KEY_STATE // Expect a key of a flow mapping.
+ yaml_PARSE_FLOW_MAPPING_VALUE_STATE // Expect a value of a flow mapping.
+ yaml_PARSE_FLOW_MAPPING_EMPTY_VALUE_STATE // Expect an empty value of a flow mapping.
+ yaml_PARSE_END_STATE // Expect nothing.
+)
+
+// This structure holds aliases data.
+type yaml_alias_data_t struct {
+ anchor []byte // The anchor.
+ index int // The node id.
+ mark yaml_mark_t // The anchor mark.
+}
+
+// The parser structure.
+//
+// All members are internal. Manage the structure using the
+// yaml_parser_ family of functions.
+type yaml_parser_t struct {
+
+ // Error handling
+
+ error yaml_error_type_t // Error type.
+
+ problem string // Error description.
+
+ // The byte about which the problem occured.
+ problem_offset int
+ problem_value int
+ problem_mark yaml_mark_t
+
+ // The error context.
+ context string
+ context_mark yaml_mark_t
+
+ // Reader stuff
+
+ read_handler yaml_read_handler_t // Read handler.
+
+ input_file io.Reader // File input data.
+ input []byte // String input data.
+ input_pos int
+
+ eof bool // EOF flag
+
+ buffer []byte // The working buffer.
+ buffer_pos int // The current position of the buffer.
+
+ unread int // The number of unread characters in the buffer.
+
+ raw_buffer []byte // The raw buffer.
+ raw_buffer_pos int // The current position of the buffer.
+
+ encoding yaml_encoding_t // The input encoding.
+
+ offset int // The offset of the current position (in bytes).
+ mark yaml_mark_t // The mark of the current position.
+
+ // Scanner stuff
+
+ stream_start_produced bool // Have we started to scan the input stream?
+ stream_end_produced bool // Have we reached the end of the input stream?
+
+ flow_level int // The number of unclosed '[' and '{' indicators.
+
+ tokens []yaml_token_t // The tokens queue.
+ tokens_head int // The head of the tokens queue.
+ tokens_parsed int // The number of tokens fetched from the queue.
+ token_available bool // Does the tokens queue contain a token ready for dequeueing.
+
+ indent int // The current indentation level.
+ indents []int // The indentation levels stack.
+
+ simple_key_allowed bool // May a simple key occur at the current position?
+ simple_keys []yaml_simple_key_t // The stack of simple keys.
+
+ // Parser stuff
+
+ state yaml_parser_state_t // The current parser state.
+ states []yaml_parser_state_t // The parser states stack.
+ marks []yaml_mark_t // The stack of marks.
+ tag_directives []yaml_tag_directive_t // The list of TAG directives.
+
+ // Dumper stuff
+
+ aliases []yaml_alias_data_t // The alias data.
+
+ document *yaml_document_t // The currently parsed document.
+}
+
+//
+///**
+// * Initialize a parser.
+// *
+// * This function creates a new parser object. An application is responsible
+// * for destroying the object using the yaml_parser_delete() function.
+// *
+// * @param[out] parser An empty parser object.
+// *
+// * @returns @c 1 if the function succeeded, @c 0 on error.
+// */
+//
+//YAML_DECLARE(int)
+//yaml_parser_initialize(yaml_parser_t *parser);
+//
+///**
+// * Destroy a parser.
+// *
+// * @param[in,out] parser A parser object.
+// */
+//
+//YAML_DECLARE(void)
+//yaml_parser_delete(yaml_parser_t *parser);
+//
+///**
+// * Set a string input.
+// *
+// * Note that the @a input pointer must be valid while the @a parser object
+// * exists. The application is responsible for destroing @a input after
+// * destroying the @a parser.
+// *
+// * @param[in,out] parser A parser object.
+// * @param[in] input A source data.
+// * @param[in] size The length of the source data in bytes.
+// */
+//
+//YAML_DECLARE(void)
+//yaml_parser_set_input_string(yaml_parser_t *parser,
+// unsigned char *input, int size);
+//
+///**
+// * Set a file input.
+// *
+// * @a file should be a file object open for reading. The application is
+// * responsible for closing the @a file.
+// *
+// * @param[in,out] parser A parser object.
+// * @param[in] file An open file.
+// */
+//
+//YAML_DECLARE(void)
+//yaml_parser_set_input_file(yaml_parser_t *parser, FILE *file);
+//
+///**
+// * Set a generic input handler.
+// *
+// * @param[in,out] parser A parser object.
+// * @param[in] handler A read handler.
+// * @param[in] data Any application data for passing to the read
+// * handler.
+// */
+//
+//YAML_DECLARE(void)
+//yaml_parser_set_input(yaml_parser_t *parser,
+// yaml_read_handler_t *handler, void *data);
+//
+///**
+// * Set the source encoding.
+// *
+// * @param[in,out] parser A parser object.
+// * @param[in] encoding The source encoding.
+// */
+//
+//YAML_DECLARE(void)
+//yaml_parser_set_encoding(yaml_parser_t *parser, yaml_encoding_t encoding);
+//
+///**
+// * Scan the input stream and produce the next token.
+// *
+// * Call the function subsequently to produce a sequence of tokens corresponding
+// * to the input stream. The initial token has the type
+// * yaml_STREAM_START_TOKEN while the ending token has the type
+// * yaml_STREAM_END_TOKEN.
+// *
+// * An application is responsible for freeing any buffers associated with the
+// * produced token object using the @c yaml_token_delete function.
+// *
+// * An application must not alternate the calls of yaml_parser_scan() with the
+// * calls of yaml_parser_parse() or yaml_parser_load(). Doing this will break
+// * the parser.
+// *
+// * @param[in,out] parser A parser object.
+// * @param[out] token An empty token object.
+// *
+// * @returns @c 1 if the function succeeded, @c 0 on error.
+// */
+//
+//YAML_DECLARE(int)
+//yaml_parser_scan(yaml_parser_t *parser, yaml_token_t *token);
+//
+///**
+// * Parse the input stream and produce the next parsing event.
+// *
+// * Call the function subsequently to produce a sequence of events corresponding
+// * to the input stream. The initial event has the type
+// * yaml_STREAM_START_EVENT while the ending event has the type
+// * yaml_STREAM_END_EVENT.
+// *
+// * An application is responsible for freeing any buffers associated with the
+// * produced event object using the yaml_event_delete() function.
+// *
+// * An application must not alternate the calls of yaml_parser_parse() with the
+// * calls of yaml_parser_scan() or yaml_parser_load(). Doing this will break the
+// * parser.
+// *
+// * @param[in,out] parser A parser object.
+// * @param[out] event An empty event object.
+// *
+// * @returns @c 1 if the function succeeded, @c 0 on error.
+// */
+//
+//YAML_DECLARE(int)
+//yaml_parser_parse(yaml_parser_t *parser, yaml_event_t *event);
+//
+///**
+// * Parse the input stream and produce the next YAML document.
+// *
+// * Call this function subsequently to produce a sequence of documents
+// * constituting the input stream.
+// *
+// * If the produced document has no root node, it means that the document
+// * end has been reached.
+// *
+// * An application is responsible for freeing any data associated with the
+// * produced document object using the yaml_document_delete() function.
+// *
+// * An application must not alternate the calls of yaml_parser_load() with the
+// * calls of yaml_parser_scan() or yaml_parser_parse(). Doing this will break
+// * the parser.
+// *
+// * @param[in,out] parser A parser object.
+// * @param[out] document An empty document object.
+// *
+// * @return @c 1 if the function succeeded, @c 0 on error.
+// */
+//
+//YAML_DECLARE(int)
+//yaml_parser_load(yaml_parser_t *parser, yaml_document_t *document);
+//
+//// @}
+//
+///**
+// * @defgroup emitter Emitter Definitions
+// * @{
+// */
+//
+///**
+// * The prototype of a write handler.
+// *
+// * The write handler is called when the emitter needs to flush the accumulated
+// * characters to the output. The handler should write @a size bytes of the
+// * @a buffer to the output.
+// *
+// * @param[in,out] data A pointer to an application data specified by
+// * yaml_emitter_set_output().
+// * @param[in] buffer The buffer with bytes to be written.
+// * @param[in] size The size of the buffer.
+// *
+// * @returns On success, the handler should return @c 1. If the handler failed,
+// * the returned value should be @c 0.
+// */
+//
+//typedef int yaml_write_handler_t(void *data, unsigned char *buffer, int size);
+//
+//// The emitter states.
+//typedef enum yaml_emitter_state_e {
+// // Expect STREAM-START.
+// YAML_EMIT_STREAM_START_STATE,
+// // Expect the first DOCUMENT-START or STREAM-END.
+// YAML_EMIT_FIRST_DOCUMENT_START_STATE,
+// // Expect DOCUMENT-START or STREAM-END.
+// YAML_EMIT_DOCUMENT_START_STATE,
+// // Expect the content of a document.
+// YAML_EMIT_DOCUMENT_CONTENT_STATE,
+// // Expect DOCUMENT-END.
+// YAML_EMIT_DOCUMENT_END_STATE,
+// // Expect the first item of a flow sequence.
+// YAML_EMIT_FLOW_SEQUENCE_FIRST_ITEM_STATE,
+// // Expect an item of a flow sequence.
+// YAML_EMIT_FLOW_SEQUENCE_ITEM_STATE,
+// // Expect the first key of a flow mapping.
+// YAML_EMIT_FLOW_MAPPING_FIRST_KEY_STATE,
+// // Expect a key of a flow mapping.
+// YAML_EMIT_FLOW_MAPPING_KEY_STATE,
+// // Expect a value for a simple key of a flow mapping.
+// YAML_EMIT_FLOW_MAPPING_SIMPLE_VALUE_STATE,
+// // Expect a value of a flow mapping.
+// YAML_EMIT_FLOW_MAPPING_VALUE_STATE,
+// // Expect the first item of a block sequence.
+// YAML_EMIT_BLOCK_SEQUENCE_FIRST_ITEM_STATE,
+// // Expect an item of a block sequence.
+// YAML_EMIT_BLOCK_SEQUENCE_ITEM_STATE,
+// // Expect the first key of a block mapping.
+// YAML_EMIT_BLOCK_MAPPING_FIRST_KEY_STATE,
+// // Expect the key of a block mapping.
+// YAML_EMIT_BLOCK_MAPPING_KEY_STATE,
+// // Expect a value for a simple key of a block mapping.
+// YAML_EMIT_BLOCK_MAPPING_SIMPLE_VALUE_STATE,
+// // Expect a value of a block mapping.
+// YAML_EMIT_BLOCK_MAPPING_VALUE_STATE,
+// // Expect nothing.
+// YAML_EMIT_END_STATE
+//} yaml_emitter_state_t;
+//
+///**
+// * The emitter structure.
+// *
+// * All members are internal. Manage the structure using the @c yaml_emitter_
+// * family of functions.
+// */
+//
+//typedef struct yaml_emitter_s {
+//
+// /**
+// * @name Error handling
+// * @{
+// */
+//
+// // Error type.
+// yaml_error_type_t error;
+// // Error description.
+// char *problem;
+//
+// /**
+// * @}
+// */
+//
+// /**
+// * @name Writer stuff
+// * @{
+// */
+//
+// // Write handler.
+// yaml_write_handler_t *write_handler;
+//
+// // A pointer for passing to the white handler.
+// void *write_handler_data;
+//
+// // Standard (string or file) output data.
+// union {
+// // String output data.
+// struct {
+// // The buffer pointer.
+// unsigned char *buffer;
+// // The buffer size.
+// int size;
+// // The number of written bytes.
+// int *size_written;
+// } string;
+//
+// // File output data.
+// FILE *file;
+// } output;
+//
+// // The working buffer.
+// struct {
+// // The beginning of the buffer.
+// yaml_char_t *start;
+// // The end of the buffer.
+// yaml_char_t *end;
+// // The current position of the buffer.
+// yaml_char_t *pointer;
+// // The last filled position of the buffer.
+// yaml_char_t *last;
+// } buffer;
+//
+// // The raw buffer.
+// struct {
+// // The beginning of the buffer.
+// unsigned char *start;
+// // The end of the buffer.
+// unsigned char *end;
+// // The current position of the buffer.
+// unsigned char *pointer;
+// // The last filled position of the buffer.
+// unsigned char *last;
+// } raw_buffer;
+//
+// // The stream encoding.
+// yaml_encoding_t encoding;
+//
+// /**
+// * @}
+// */
+//
+// /**
+// * @name Emitter stuff
+// * @{
+// */
+//
+// // If the output is in the canonical style?
+// int canonical;
+// // The number of indentation spaces.
+// int best_indent;
+// // The preferred width of the output lines.
+// int best_width;
+// // Allow unescaped non-ASCII characters?
+// int unicode;
+// // The preferred line break.
+// yaml_break_t line_break;
+//
+// // The stack of states.
+// struct {
+// // The beginning of the stack.
+// yaml_emitter_state_t *start;
+// // The end of the stack.
+// yaml_emitter_state_t *end;
+// // The top of the stack.
+// yaml_emitter_state_t *top;
+// } states;
+//
+// // The current emitter state.
+// yaml_emitter_state_t state;
+//
+// // The event queue.
+// struct {
+// // The beginning of the event queue.
+// yaml_event_t *start;
+// // The end of the event queue.
+// yaml_event_t *end;
+// // The head of the event queue.
+// yaml_event_t *head;
+// // The tail of the event queue.
+// yaml_event_t *tail;
+// } events;
+//
+// // The stack of indentation levels.
+// struct {
+// // The beginning of the stack.
+// int *start;
+// // The end of the stack.
+// int *end;
+// // The top of the stack.
+// int *top;
+// } indents;
+//
+// // The list of tag directives.
+// struct {
+// // The beginning of the list.
+// yaml_tag_directive_t *start;
+// // The end of the list.
+// yaml_tag_directive_t *end;
+// // The top of the list.
+// yaml_tag_directive_t *top;
+// } tag_directives;
+//
+// // The current indentation level.
+// int indent;
+//
+// // The current flow level.
+// int flow_level;
+//
+// // Is it the document root context?
+// int root_context;
+// // Is it a sequence context?
+// int sequence_context;
+// // Is it a mapping context?
+// int mapping_context;
+// // Is it a simple mapping key context?
+// int simple_key_context;
+//
+// // The current line.
+// int line;
+// // The current column.
+// int column;
+// // If the last character was a whitespace?
+// int whitespace;
+// // If the last character was an indentation character (' ', '-', '?', ':')?
+// int indention;
+// // If an explicit document end is required?
+// int open_ended;
+//
+// // Anchor analysis.
+// struct {
+// // The anchor value.
+// yaml_char_t *anchor;
+// // The anchor length.
+// int anchor_length;
+// // Is it an alias?
+// int alias;
+// } anchor_data;
+//
+// // Tag analysis.
+// struct {
+// // The tag handle.
+// yaml_char_t *handle;
+// // The tag handle length.
+// int handle_length;
+// // The tag suffix.
+// yaml_char_t *suffix;
+// // The tag suffix length.
+// int suffix_length;
+// } tag_data;
+//
+// // Scalar analysis.
+// struct {
+// // The scalar value.
+// yaml_char_t *value;
+// // The scalar length.
+// int length;
+// // Does the scalar contain line breaks?
+// int multiline;
+// // Can the scalar be expessed in the flow plain style?
+// int flow_plain_allowed;
+// // Can the scalar be expressed in the block plain style?
+// int block_plain_allowed;
+// // Can the scalar be expressed in the single quoted style?
+// int single_quoted_allowed;
+// // Can the scalar be expressed in the literal or folded styles?
+// int block_allowed;
+// // The output style.
+// yaml_scalar_style_t style;
+// } scalar_data;
+//
+// /**
+// * @}
+// */
+//
+// /**
+// * @name Dumper stuff
+// * @{
+// */
+//
+// // If the stream was already opened?
+// int opened;
+// // If the stream was already closed?
+// int closed;
+//
+// // The information associated with the document nodes.
+// struct {
+// // The number of references.
+// int references;
+// // The anchor id.
+// int anchor;
+// // If the node has been emitted?
+// int serialized;
+// } *anchors;
+//
+// // The last assigned anchor id.
+// int last_anchor_id;
+//
+// // The currently emitted document.
+// yaml_document_t *document;
+//
+// /**
+// * @}
+// */
+//
+//} yaml_emitter_t;
+//
+///**
+// * Initialize an emitter.
+// *
+// * This function creates a new emitter object. An application is responsible
+// * for destroying the object using the yaml_emitter_delete() function.
+// *
+// * @param[out] emitter An empty parser object.
+// *
+// * @returns @c 1 if the function succeeded, @c 0 on error.
+// */
+//
+//YAML_DECLARE(int)
+//yaml_emitter_initialize(yaml_emitter_t *emitter);
+//
+///**
+// * Destroy an emitter.
+// *
+// * @param[in,out] emitter An emitter object.
+// */
+//
+//YAML_DECLARE(void)
+//yaml_emitter_delete(yaml_emitter_t *emitter);
+//
+///**
+// * Set a string output.
+// *
+// * The emitter will write the output characters to the @a output buffer of the
+// * size @a size. The emitter will set @a size_written to the number of written
+// * bytes. If the buffer is smaller than required, the emitter produces the
+// * YAML_WRITE_ERROR error.
+// *
+// * @param[in,out] emitter An emitter object.
+// * @param[in] output An output buffer.
+// * @param[in] size The buffer size.
+// * @param[in] size_written The pointer to save the number of written
+// * bytes.
+// */
+//
+//YAML_DECLARE(void)
+//yaml_emitter_set_output_string(yaml_emitter_t *emitter,
+// unsigned char *output, int size, size_t *size_written);
+//
+///**
+// * Set a file output.
+// *
+// * @a file should be a file object open for writing. The application is
+// * responsible for closing the @a file.
+// *
+// * @param[in,out] emitter An emitter object.
+// * @param[in] file An open file.
+// */
+//
+//YAML_DECLARE(void)
+//yaml_emitter_set_output_file(yaml_emitter_t *emitter, FILE *file);
+//
+///**
+// * Set a generic output handler.
+// *
+// * @param[in,out] emitter An emitter object.
+// * @param[in] handler A write handler.
+// * @param[in] data Any application data for passing to the write
+// * handler.
+// */
+//
+//YAML_DECLARE(void)
+//yaml_emitter_set_output(yaml_emitter_t *emitter,
+// yaml_write_handler_t *handler, void *data);
+//
+///**
+// * Set the output encoding.
+// *
+// * @param[in,out] emitter An emitter object.
+// * @param[in] encoding The output encoding.
+// */
+//
+//YAML_DECLARE(void)
+//yaml_emitter_set_encoding(yaml_emitter_t *emitter, yaml_encoding_t encoding);
+//
+///**
+// * Set if the output should be in the "canonical" format as in the YAML
+// * specification.
+// *
+// * @param[in,out] emitter An emitter object.
+// * @param[in] canonical If the output is canonical.
+// */
+//
+//YAML_DECLARE(void)
+//yaml_emitter_set_canonical(yaml_emitter_t *emitter, int canonical);
+//
+///**
+// * Set the intendation increment.
+// *
+// * @param[in,out] emitter An emitter object.
+// * @param[in] indent The indentation increment (1 < . < 10).
+// */
+//
+//YAML_DECLARE(void)
+//yaml_emitter_set_indent(yaml_emitter_t *emitter, int indent);
+//
+///**
+// * Set the preferred line width. @c -1 means unlimited.
+// *
+// * @param[in,out] emitter An emitter object.
+// * @param[in] width The preferred line width.
+// */
+//
+//YAML_DECLARE(void)
+//yaml_emitter_set_width(yaml_emitter_t *emitter, int width);
+//
+///**
+// * Set if unescaped non-ASCII characters are allowed.
+// *
+// * @param[in,out] emitter An emitter object.
+// * @param[in] unicode If unescaped Unicode characters are allowed.
+// */
+//
+//YAML_DECLARE(void)
+//yaml_emitter_set_unicode(yaml_emitter_t *emitter, int unicode);
+//
+///**
+// * Set the preferred line break.
+// *
+// * @param[in,out] emitter An emitter object.
+// * @param[in] line_break The preferred line break.
+// */
+//
+//YAML_DECLARE(void)
+//yaml_emitter_set_break(yaml_emitter_t *emitter, yaml_break_t line_break);
+//
+///**
+// * Emit an event.
+// *
+// * The event object may be generated using the yaml_parser_parse() function.
+// * The emitter takes the responsibility for the event object and destroys its
+// * content after it is emitted. The event object is destroyed even if the
+// * function fails.
+// *
+// * @param[in,out] emitter An emitter object.
+// * @param[in,out] event An event object.
+// *
+// * @returns @c 1 if the function succeeded, @c 0 on error.
+// */
+//
+//YAML_DECLARE(int)
+//yaml_emitter_emit(yaml_emitter_t *emitter, yaml_event_t *event);
+//
+///**
+// * Start a YAML stream.
+// *
+// * This function should be used before yaml_emitter_dump() is called.
+// *
+// * @param[in,out] emitter An emitter object.
+// *
+// * @returns @c 1 if the function succeeded, @c 0 on error.
+// */
+//
+//YAML_DECLARE(int)
+//yaml_emitter_open(yaml_emitter_t *emitter);
+//
+///**
+// * Finish a YAML stream.
+// *
+// * This function should be used after yaml_emitter_dump() is called.
+// *
+// * @param[in,out] emitter An emitter object.
+// *
+// * @returns @c 1 if the function succeeded, @c 0 on error.
+// */
+//
+//YAML_DECLARE(int)
+//yaml_emitter_close(yaml_emitter_t *emitter);
+//
+///**
+// * Emit a YAML document.
+// *
+// * The documen object may be generated using the yaml_parser_load() function
+// * or the yaml_document_initialize() function. The emitter takes the
+// * responsibility for the document object and destoys its content after
+// * it is emitted. The document object is destroyedeven if the function fails.
+// *
+// * @param[in,out] emitter An emitter object.
+// * @param[in,out] document A document object.
+// *
+// * @returns @c 1 if the function succeeded, @c 0 on error.
+// */
+//
+//YAML_DECLARE(int)
+//yaml_emitter_dump(yaml_emitter_t *emitter, yaml_document_t *document);
+//
+///**
+// * Flush the accumulated characters to the output.
+// *
+// * @param[in,out] emitter An emitter object.
+// *
+// * @returns @c 1 if the function succeeded, @c 0 on error.
+// */
+//
+//YAML_DECLARE(int)
+//yaml_emitter_flush(yaml_emitter_t *emitter);
+//
+//// @}
+//
+//#ifdef __cplusplus
+//}
+//#endif
+//
+//#endif /* #ifndef YAML_H */
+//
diff --git a/yaml_private_h.go b/yaml_private_h.go
new file mode 100644
index 0000000..c01c7f3
--- /dev/null
+++ b/yaml_private_h.go
@@ -0,0 +1,249 @@
+package goyaml
+
+const (
+ // The size of the input raw buffer.
+ input_raw_buffer_size = 16384
+
+ // The size of the input buffer.
+ // It should be possible to decode the whole raw buffer.
+ input_buffer_size = input_raw_buffer_size * 3
+
+ // The size of the output buffer.
+ output_buffer_size = 16384
+
+ // The size of the output raw buffer.
+ // It should be possible to encode the whole output buffer.
+ output_raw_buffer_size = (output_buffer_size*2 + 2)
+
+ // The size of other stacks and queues.
+ initial_stack_size = 16
+ initial_queue_size = 16
+ initial_string_size = 16
+)
+
+// Check if the character at the specified position is an alphabetical
+// character, a digit, '_', or '-'.
+func is_alpha(b []byte, i int) bool {
+ return b[i] >= '0' && b[i] <= '9' || b[i] >= 'A' && b[i] <= 'Z' || b[i] >= 'a' && b[i] <= 'z' || b[i] == '_' || b[i] == '-'
+}
+
+// Check if the character at the specified position is a digit.
+func is_digit(b []byte, i int) bool {
+ return b[i] >= '0' && b[i] <= '9'
+}
+
+// Get the value of a digit.
+func as_digit(b []byte, i int) int {
+ return int(b[i]) - '0'
+}
+
+// Check if the character at the specified position is a hex-digit.
+func is_hex(b []byte, i int) bool {
+ return b[i] >= '0' && b[i] <= '9' || b[i] >= 'A' && b[i] <= 'F' || b[i] >= 'a' && b[i] <= 'f'
+}
+
+// Get the value of a hex-digit.
+func as_hex(b []byte, i int) int {
+ bi := b[i]
+ if bi >= 'A' && bi <= 'F' {
+ return int(bi) - 'A' + 10
+ }
+ if bi >= 'a' && bi <= 'f' {
+ return int(bi) - 'a' + 10
+ }
+ return int(bi) - '0'
+}
+
+// Check if the character is ASCII.
+func is_ascii(b []byte, i int) bool {
+ return b[i] <= 0x7F
+}
+
+// Check if the character at the start of the buffer can be printed unescaped.
+func is_printable(b []byte, i int) bool {
+ return ((b[i] == 0x0A) || // . == #x0A
+ (b[i] >= 0x20 && b[i] <= 0x7E) || // #x20 <= . <= #x7E
+ (b[i] == 0xC2 && b[i+1] >= 0xA0) || // #0xA0 <= . <= #xD7FF
+ (b[i] > 0xC2 && b[i] < 0xED) ||
+ (b[i] == 0xED && b[i+1] < 0xA0) ||
+ (b[i] == 0xEE) ||
+ (b[i] == 0xEF && // #xE000 <= . <= #xFFFD
+ !(b[i+1] == 0xBB && b[i+2] == 0xBF) && // && . != #xFEFF
+ !(b[i+1] == 0xBF && (b[i+2] == 0xBE || b[i+2] == 0xBF))))
+}
+
+// Check if the character at the specified position is NUL.
+func is_z(b []byte, i int) bool {
+ return b[i] == 0x00
+}
+
+// Check if the beginning of the buffer is a BOM.
+func is_bom(b []byte, i int) bool {
+ return b[0] == 0xEF && b[1] == 0xBB && b[2] == 0xBF
+}
+
+// Check if the character at the specified position is space.
+func is_space(b []byte, i int) bool {
+ return b[i] == ' '
+}
+
+// Check if the character at the specified position is tab.
+func is_tab(b []byte, i int) bool {
+ return b[i] == '\t'
+}
+
+// Check if the character at the specified position is blank (space or tab).
+func is_blank(b []byte, i int) bool {
+ return is_space(b, i) || is_tab(b, i)
+}
+
+// Check if the character at the specified position is a line break.
+func is_break(b []byte, i int) bool {
+ return (b[i] == '\r' || // CR (#xD)
+ b[i] == '\n' || // LF (#xA)
+ b[i] == 0xC2 && b[i+1] == 0x85 || // NEL (#x85)
+ b[i] == 0xE2 && b[i+1] == 0x80 && b[i+2] == 0xA8 || // LS (#x2028)
+ b[i] == 0xE2 && b[i+1] == 0x80 && b[i+2] == 0xA9) // PS (#x2029)
+}
+
+func is_crlf(b []byte, i int) bool {
+ return b[i] == '\r' && b[i+1] == '\n'
+}
+
+// Check if the character is a line break or NUL.
+func is_breakz(b []byte, i int) bool {
+ return is_break(b, i) || b[i] == 0x00
+}
+
+// Check if the character is a line break, space, or NUL.
+func is_spacez(b []byte, i int) bool {
+ return is_space(b, i) || is_breakz(b, i)
+}
+
+// Check if the character is a line break, space, tab, or NUL.
+func is_blankz(b []byte, i int) bool {
+ return is_blank(b, i) || is_breakz(b, i)
+}
+
+// Determine the width of the character.
+func width(b byte) int {
+ switch {
+ case b&0x80 == 0x00:
+ return 1
+ case b&0xE0 == 0xC0:
+ return 2
+ case b&0xF0 == 0xE0:
+ return 3
+ case b&0xF8 == 0xF0:
+ return 4
+ }
+ return 0
+}
+
+
+///*
+// * Event initializers.
+// */
+//
+//#define EVENT_INIT(event,event_type,event_start_mark,event_end_mark)
+// (memset(&(event), 0, sizeof(yaml_event_t)),
+// (event).type = (event_type),
+// (event).start_mark = (event_start_mark),
+// (event).end_mark = (event_end_mark))
+//
+
+//#define DOCUMENT_END_EVENT_INIT(event,event_implicit,start_mark,end_mark)
+// (EVENT_INIT((event),YAML_DOCUMENT_END_EVENT,(start_mark),(end_mark)),
+// (event).data.document_end.implicit = (event_implicit))
+//
+//#define ALIAS_EVENT_INIT(event,event_anchor,start_mark,end_mark)
+// (EVENT_INIT((event),YAML_ALIAS_EVENT,(start_mark),(end_mark)),
+// (event).data.alias.anchor = (event_anchor))
+//
+//#define SCALAR_EVENT_INIT(event,event_anchor,event_tag,event_value,event_length,
+// event_plain_implicit, event_quoted_implicit,event_style,start_mark,end_mark)
+// (EVENT_INIT((event),YAML_SCALAR_EVENT,(start_mark),(end_mark)),
+// (event).data.scalar.anchor = (event_anchor),
+// (event).data.scalar.tag = (event_tag),
+// (event).data.scalar.value = (event_value),
+// (event).data.scalar.length = (event_length),
+// (event).data.scalar.plain_implicit = (event_plain_implicit),
+// (event).data.scalar.quoted_implicit = (event_quoted_implicit),
+// (event).data.scalar.style = (event_style))
+//
+//#define SEQUENCE_START_EVENT_INIT(event,event_anchor,event_tag,
+// event_implicit,event_style,start_mark,end_mark)
+// (EVENT_INIT((event),YAML_SEQUENCE_START_EVENT,(start_mark),(end_mark)),
+// (event).data.sequence_start.anchor = (event_anchor),
+// (event).data.sequence_start.tag = (event_tag),
+// (event).data.sequence_start.implicit = (event_implicit),
+// (event).data.sequence_start.style = (event_style))
+//
+//#define SEQUENCE_END_EVENT_INIT(event,start_mark,end_mark)
+// (EVENT_INIT((event),YAML_SEQUENCE_END_EVENT,(start_mark),(end_mark)))
+//
+//#define MAPPING_START_EVENT_INIT(event,event_anchor,event_tag,
+// event_implicit,event_style,start_mark,end_mark)
+// (EVENT_INIT((event),YAML_MAPPING_START_EVENT,(start_mark),(end_mark)),
+// (event).data.mapping_start.anchor = (event_anchor),
+// (event).data.mapping_start.tag = (event_tag),
+// (event).data.mapping_start.implicit = (event_implicit),
+// (event).data.mapping_start.style = (event_style))
+//
+//#define MAPPING_END_EVENT_INIT(event,start_mark,end_mark)
+// (EVENT_INIT((event),YAML_MAPPING_END_EVENT,(start_mark),(end_mark)))
+//
+///*
+// * Document initializer.
+// */
+//
+//#define DOCUMENT_INIT(document,document_nodes_start,document_nodes_end,
+// document_version_directive,document_tag_directives_start,
+// document_tag_directives_end,document_start_implicit,
+// document_end_implicit,document_start_mark,document_end_mark)
+// (memset(&(document), 0, sizeof(yaml_document_t)),
+// (document).nodes.start = (document_nodes_start),
+// (document).nodes.end = (document_nodes_end),
+// (document).nodes.top = (document_nodes_start),
+// (document).version_directive = (document_version_directive),
+// (document).tag_directives.start = (document_tag_directives_start),
+// (document).tag_directives.end = (document_tag_directives_end),
+// (document).start_implicit = (document_start_implicit),
+// (document).end_implicit = (document_end_implicit),
+// (document).start_mark = (document_start_mark),
+// (document).end_mark = (document_end_mark))
+//
+///*
+// * Node initializers.
+// */
+//
+//#define NODE_INIT(node,node_type,node_tag,node_start_mark,node_end_mark)
+// (memset(&(node), 0, sizeof(yaml_node_t)),
+// (node).type = (node_type),
+// (node).tag = (node_tag),
+// (node).start_mark = (node_start_mark),
+// (node).end_mark = (node_end_mark))
+//
+//#define SCALAR_NODE_INIT(node,node_tag,node_value,node_length,
+// node_style,start_mark,end_mark)
+// (NODE_INIT((node),YAML_SCALAR_NODE,(node_tag),(start_mark),(end_mark)),
+// (node).data.scalar.value = (node_value),
+// (node).data.scalar.length = (node_length),
+// (node).data.scalar.style = (node_style))
+//
+//#define SEQUENCE_NODE_INIT(node,node_tag,node_items_start,node_items_end,
+// node_style,start_mark,end_mark)
+// (NODE_INIT((node),YAML_SEQUENCE_NODE,(node_tag),(start_mark),(end_mark)),
+// (node).data.sequence.items.start = (node_items_start),
+// (node).data.sequence.items.end = (node_items_end),
+// (node).data.sequence.items.top = (node_items_start),
+// (node).data.sequence.style = (node_style))
+//
+//#define MAPPING_NODE_INIT(node,node_tag,node_pairs_start,node_pairs_end,
+// node_style,start_mark,end_mark)
+// (NODE_INIT((node),YAML_MAPPING_NODE,(node_tag),(start_mark),(end_mark)),
+// (node).data.mapping.pairs.start = (node_pairs_start),
+// (node).data.mapping.pairs.end = (node_pairs_end),
+// (node).data.mapping.pairs.top = (node_pairs_start),
+// (node).data.mapping.style = (node_style))
+//