Repository: avsm/ocaml-yaml
Pull request #37 (2020-06-21 11:51:33)

Support YAML 1.2
It seems we can support YAML 1.2 effortlessly. This PR does the following three things:

1. Update upstream code.
2. Add an optional argument to `document_start` so that `version` can be passed to the C library.
3. Remove the support of YAML 1.0 because the C library does not seem to support YAML 1.0.


Patch:
diff --git a/README.md b/README.md
index 63e36f0..ccd068f 100644
--- a/README.md
+++ b/README.md
@@ -1,4 +1,4 @@
-## ocaml-yaml -- parse and generate YAML 1.1 files
+## ocaml-yaml -- parse and generate YAML 1.1/1.2 files
 
 This is an OCaml library to parse and generate the YAML file
 format.  It is intended to interoperable with the [Ezjsonm](https://github.com/mirage/ezjsonm)
diff --git a/lib/stream.ml b/lib/stream.ml
index d7e89a3..34c16b8 100644
--- a/lib/stream.ml
+++ b/lib/stream.ml
@@ -83,10 +83,15 @@ let list_of_tag_directives tds =
 
 let version_of_directive ~major ~minor =
   match major, minor with
-  | 1,0 -> `V1_0
   | 1,1 -> `V1_1
+  | 1,2 -> `V1_2
   | _ -> raise (Invalid_argument (Printf.sprintf "Unsupported Yaml version %d.%d" major minor))
 
+let directive_of_version =
+  function
+  | `V1_1 -> 1,1
+  | `V1_2 -> 1,2
+
 module Mark = struct
   type t = {
     index: int;
@@ -277,9 +282,18 @@ let stream_start t encoding =
 let stream_end t =
   check_emit "stream_end" t @@ B.stream_end_event_init t.event
 
-let document_start ?(implicit=true) t  =
+let document_start ?version ?(implicit=true) t  =
   let open Ctypes in
-  let ver = from_voidp T.Version_directive.t null in
+  let ver =
+    match version with
+    | None -> from_voidp T.Version_directive.t null
+    | Some v ->
+      let major, minor = directive_of_version v in
+      let v = make T.Version_directive.t in
+      setf v T.Version_directive.major major;
+      setf v T.Version_directive.minor minor;
+      allocate T.Version_directive.t @@ v
+  in
   let tag = from_voidp T.Tag_directive.t null in
   check_emit "doc_start" t @@ B.document_start_event_init t.event ver tag tag implicit
 
@@ -308,7 +322,7 @@ let emit t =
   let open Event in
   function
   | Stream_start { encoding } -> stream_start t encoding
-  | Document_start { version; implicit } -> document_start ~implicit t
+  | Document_start { version; implicit } -> document_start ?version ~implicit t
   | Document_end { implicit } -> document_end ~implicit t
   | Mapping_start { anchor; tag; implicit; style } -> mapping_start ?anchor ?tag ~implicit ~style t
   | Mapping_end -> mapping_end t
diff --git a/lib/types.ml b/lib/types.ml
index 3884a9f..b0cf359 100644
--- a/lib/types.ml
+++ b/lib/types.ml
@@ -15,8 +15,8 @@
 open Sexplib.Conv
 
 type version = [
- | `V1_0
  | `V1_1
+ | `V1_2
 ] [@@deriving sexp]
 
 type encoding = [
diff --git a/lib/yaml.mli b/lib/yaml.mli
index 93ea9b6..85b8804 100644
--- a/lib/yaml.mli
+++ b/lib/yaml.mli
@@ -85,7 +85,7 @@ and scalar_style = [
   The {{:http://www.yaml.org/spec/1.2/spec.html#id2786942:}Yaml spec section 7.3}
   has more details. *)
 
-type version = [ `V1_0 | `V1_1 ] [@@deriving sexp]
+type version = [ `V1_1 | `V1_2 ] [@@deriving sexp]
 (** Version of the YAML spec of a document.
   Refer to the {{:http://www.yaml.org/spec/1.2/spec.html}Yaml specification}
   for details of the differences between versions. *)
@@ -255,7 +255,7 @@ module Stream : sig
 
   val emit : emitter -> Event.t -> unit res
 
-  val document_start : ?implicit:bool -> emitter -> unit res
+  val document_start : ?version:version -> ?implicit:bool -> emitter -> unit res
 
   val document_end : ?implicit:bool -> emitter -> unit res
 
diff --git a/vendor/LICENSE b/vendor/License
similarity index 96%
rename from vendor/LICENSE
rename to vendor/License
index e7b6102..3d82c28 100644
--- a/vendor/LICENSE
+++ b/vendor/License
@@ -1,3 +1,4 @@
+Copyright (c) 2017-2020 Ingy döt Net
 Copyright (c) 2006-2016 Kirill Simonov
 
 Permission is hereby granted, free of charge, to any person obtaining a copy of
diff --git a/vendor/README.md b/vendor/README.md
index b41249d..13612c9 100644
--- a/vendor/README.md
+++ b/vendor/README.md
@@ -1,5 +1,5 @@
 This is a copy of https://github.com/yaml/libyaml.git
-revision 660242d6a418f0348c61057ed3052450527b3abf.
+revision 2c891fc7a770e8ba2fec34fc6b545c672beb37e6 (tag v0.2.5).
 
-yaml.h has been modified to remove anonymous structs, since ocaml-ctypes stub
+yaml.h has been modified to remove anonymous structs and unions, since ocaml-ctypes stub
 generation needs to probe their sizes at compile-time.
diff --git a/vendor/api.c b/vendor/api.c
index e793b08..16f88bd 100644
--- a/vendor/api.c
+++ b/vendor/api.c
@@ -623,10 +623,10 @@ yaml_token_delete(yaml_token_t *token)
  */
 
 static int
-yaml_check_utf8(yaml_char_t *start, size_t length)
+yaml_check_utf8(const yaml_char_t *start, size_t length)
 {
-    yaml_char_t *end = start+length;
-    yaml_char_t *pointer = start;
+    const yaml_char_t *end = start+length;
+    const yaml_char_t *pointer = start;
 
     while (pointer < end) {
         unsigned char octet;
@@ -794,7 +794,7 @@ yaml_document_end_event_initialize(yaml_event_t *event, int implicit)
  */
 
 YAML_DECLARE(int)
-yaml_alias_event_initialize(yaml_event_t *event, yaml_char_t *anchor)
+yaml_alias_event_initialize(yaml_event_t *event, const yaml_char_t *anchor)
 {
     yaml_mark_t mark = { 0, 0, 0 };
     yaml_char_t *anchor_copy = NULL;
@@ -819,8 +819,8 @@ yaml_alias_event_initialize(yaml_event_t *event, yaml_char_t *anchor)
 
 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,
+        const yaml_char_t *anchor, const yaml_char_t *tag,
+        const yaml_char_t *value, int length,
         int plain_implicit, int quoted_implicit,
         yaml_scalar_style_t style)
 {
@@ -873,7 +873,7 @@ error:
 
 YAML_DECLARE(int)
 yaml_sequence_start_event_initialize(yaml_event_t *event,
-        yaml_char_t *anchor, yaml_char_t *tag, int implicit,
+        const yaml_char_t *anchor, const yaml_char_t *tag, int implicit,
         yaml_sequence_style_t style)
 {
     yaml_mark_t mark = { 0, 0, 0 };
@@ -928,7 +928,7 @@ yaml_sequence_end_event_initialize(yaml_event_t *event)
 
 YAML_DECLARE(int)
 yaml_mapping_start_event_initialize(yaml_event_t *event,
-        yaml_char_t *anchor, yaml_char_t *tag, int implicit,
+        const yaml_char_t *anchor, const yaml_char_t *tag, int implicit,
         yaml_mapping_style_t style)
 {
     yaml_mark_t mark = { 0, 0, 0 };
@@ -1193,7 +1193,7 @@ yaml_document_get_root_node(yaml_document_t *document)
 
 YAML_DECLARE(int)
 yaml_document_add_scalar(yaml_document_t *document,
-        yaml_char_t *tag, yaml_char_t *value, int length,
+        const yaml_char_t *tag, const yaml_char_t *value, int length,
         yaml_scalar_style_t style)
 {
     struct {
@@ -1243,7 +1243,7 @@ error:
 
 YAML_DECLARE(int)
 yaml_document_add_sequence(yaml_document_t *document,
-        yaml_char_t *tag, yaml_sequence_style_t style)
+        const yaml_char_t *tag, yaml_sequence_style_t style)
 {
     struct {
         yaml_error_type_t error;
@@ -1288,7 +1288,7 @@ error:
 
 YAML_DECLARE(int)
 yaml_document_add_mapping(yaml_document_t *document,
-        yaml_char_t *tag, yaml_mapping_style_t style)
+        const yaml_char_t *tag, yaml_mapping_style_t style)
 {
     struct {
         yaml_error_type_t error;
diff --git a/vendor/emitter.c b/vendor/emitter.c
index b9392e4..609b28a 100644
--- a/vendor/emitter.c
+++ b/vendor/emitter.c
@@ -495,6 +495,7 @@ static int
 yaml_emitter_emit_stream_start(yaml_emitter_t *emitter,
         yaml_event_t *event)
 {
+    emitter->open_ended = 0;
     if (event->type == YAML_STREAM_START_EVENT)
     {
         if (!emitter->encoding) {
@@ -597,13 +598,20 @@ yaml_emitter_emit_document_start(yaml_emitter_t *emitter,
             if (!yaml_emitter_write_indent(emitter))
                 return 0;
         }
+        emitter->open_ended = 0;
 
         if (event->data.document_start.version_directive) {
             implicit = 0;
             if (!yaml_emitter_write_indicator(emitter, "%YAML", 1, 0, 0))
                 return 0;
-            if (!yaml_emitter_write_indicator(emitter, "1.1", 1, 0, 0))
-                return 0;
+            if (event->data.document_start.version_directive->minor == 1) {
+                if (!yaml_emitter_write_indicator(emitter, "1.1", 1, 0, 0))
+                    return 0;
+            }
+            else {
+                if (!yaml_emitter_write_indicator(emitter, "1.2", 1, 0, 0))
+                    return 0;
+            }
             if (!yaml_emitter_write_indent(emitter))
                 return 0;
         }
@@ -644,12 +652,25 @@ yaml_emitter_emit_document_start(yaml_emitter_t *emitter,
 
         emitter->state = YAML_EMIT_DOCUMENT_CONTENT_STATE;
 
+        emitter->open_ended = 0;
         return 1;
     }
 
     else if (event->type == YAML_STREAM_END_EVENT)
     {
 
+        /**
+         * This can happen if a block scalar with trailing empty lines
+         * is at the end of the stream
+         */
+        if (emitter->open_ended == 2)
+        {
+            if (!yaml_emitter_write_indicator(emitter, "...", 1, 0, 0))
+                return 0;
+            emitter->open_ended = 0;
+            if (!yaml_emitter_write_indent(emitter))
+                return 0;
+        }
         if (!yaml_emitter_flush(emitter))
             return 0;
 
@@ -691,9 +712,12 @@ yaml_emitter_emit_document_end(yaml_emitter_t *emitter,
         if (!event->data.document_end.implicit) {
             if (!yaml_emitter_write_indicator(emitter, "...", 1, 0, 0))
                 return 0;
+            emitter->open_ended = 0;
             if (!yaml_emitter_write_indent(emitter))
                 return 0;
         }
+        else if (!emitter->open_ended)
+            emitter->open_ended = 1;
         if (!yaml_emitter_flush(emitter))
             return 0;
 
@@ -999,6 +1023,8 @@ yaml_emitter_emit_alias(yaml_emitter_t *emitter, SHIM(yaml_event_t *event))
 {
     if (!yaml_emitter_process_anchor(emitter))
         return 0;
+    if (emitter->simple_key_context)
+        if (!PUT(emitter, ' ')) return 0;
     emitter->state = POP(emitter, emitter->states);
 
     return 1;
@@ -1227,7 +1253,7 @@ yaml_emitter_select_scalar_style(yaml_emitter_t *emitter, yaml_event_t *event)
 }
 
 /*
- * Write an achor.
+ * Write an anchor.
  */
 
 static int
@@ -1326,7 +1352,10 @@ static int
 yaml_emitter_analyze_version_directive(yaml_emitter_t *emitter,
         yaml_version_directive_t version_directive)
 {
-    if (version_directive.major != 1 || version_directive.minor != 1) {
+    if (version_directive.major != 1 || (
+        version_directive.minor != 1
+        && version_directive.minor != 2
+        )) {
         return yaml_emitter_set_emitter_error(emitter,
                 "incompatible %YAML directive");
     }
@@ -1796,7 +1825,6 @@ yaml_emitter_write_indicator(yaml_emitter_t *emitter,
 
     emitter->whitespace = is_whitespace;
     emitter->indention = (emitter->indention && is_indention);
-    emitter->open_ended = 0;
 
     return 1;
 }
@@ -1897,7 +1925,17 @@ yaml_emitter_write_plain_scalar(yaml_emitter_t *emitter,
 
     STRING_ASSIGN(string, value, length);
 
-    if (!emitter->whitespace) {
+    /**
+     * Avoid trailing spaces for empty values in block mode.
+     * In flow mode, we still want the space to prevent ambiguous things
+     * like {a:}.
+     * Currently, the emitter forbids any plain empty scalar in flow mode
+     * (e.g. it outputs {a: ''} instead), so emitter->flow_level will
+     * never be true here.
+     * But if the emitter is ever changed to allow emitting empty values,
+     * the check for flow_level is already here.
+     */
+    if (!emitter->whitespace && (length || emitter->flow_level)) {
         if (!PUT(emitter, ' ')) return 0;
     }
 
@@ -1939,10 +1977,6 @@ yaml_emitter_write_plain_scalar(yaml_emitter_t *emitter,
 
     emitter->whitespace = 0;
     emitter->indention = 0;
-    if (emitter->root_context)
-    {
-        emitter->open_ended = 1;
-    }
 
     return 1;
 }
@@ -2203,7 +2237,7 @@ yaml_emitter_write_block_scalar_hints(yaml_emitter_t *emitter,
         else if (string.start == string.pointer)
         {
             chomp_hint = "+";
-            emitter->open_ended = 1;
+            emitter->open_ended = 2;
         }
         else
         {
@@ -2213,7 +2247,7 @@ yaml_emitter_write_block_scalar_hints(yaml_emitter_t *emitter,
             if (IS_BREAK(string))
             {
                 chomp_hint = "+";
-                emitter->open_ended = 1;
+                emitter->open_ended = 2;
             }
         }
     }
diff --git a/vendor/loader.c b/vendor/loader.c
index db8501a..dea8ac4 100644
--- a/vendor/loader.c
+++ b/vendor/loader.c
@@ -37,27 +37,47 @@ yaml_parser_register_anchor(yaml_parser_t *parser,
 static void
 yaml_parser_delete_aliases(yaml_parser_t *parser);
 
+/*
+ * Document loading context.
+ */
+struct loader_ctx {
+    int *start;
+    int *end;
+    int *top;
+};
+
 /*
  * Composer functions.
  */
+static int
+yaml_parser_load_nodes(yaml_parser_t *parser, struct loader_ctx *ctx);
+
+static int
+yaml_parser_load_document(yaml_parser_t *parser, yaml_event_t *event);
 
 static int
-yaml_parser_load_document(yaml_parser_t *parser, yaml_event_t *first_event);
+yaml_parser_load_alias(yaml_parser_t *parser, yaml_event_t *event,
+        struct loader_ctx *ctx);
 
 static int
-yaml_parser_load_node(yaml_parser_t *parser, yaml_event_t *first_event);
+yaml_parser_load_scalar(yaml_parser_t *parser, yaml_event_t *event,
+        struct loader_ctx *ctx);
 
 static int
-yaml_parser_load_alias(yaml_parser_t *parser, yaml_event_t *first_event);
+yaml_parser_load_sequence(yaml_parser_t *parser, yaml_event_t *event,
+        struct loader_ctx *ctx);
 
 static int
-yaml_parser_load_scalar(yaml_parser_t *parser, yaml_event_t *first_event);
+yaml_parser_load_mapping(yaml_parser_t *parser, yaml_event_t *event,
+        struct loader_ctx *ctx);
 
 static int
-yaml_parser_load_sequence(yaml_parser_t *parser, yaml_event_t *first_event);
+yaml_parser_load_sequence_end(yaml_parser_t *parser, yaml_event_t *event,
+        struct loader_ctx *ctx);
 
 static int
-yaml_parser_load_mapping(yaml_parser_t *parser, yaml_event_t *first_event);
+yaml_parser_load_mapping_end(yaml_parser_t *parser, yaml_event_t *event,
+        struct loader_ctx *ctx);
 
 /*
  * Load the next document of the stream.
@@ -162,59 +182,78 @@ yaml_parser_delete_aliases(yaml_parser_t *parser)
  */
 
 static int
-yaml_parser_load_document(yaml_parser_t *parser, yaml_event_t *first_event)
+yaml_parser_load_document(yaml_parser_t *parser, yaml_event_t *event)
 {
-    yaml_event_t event;
+    struct loader_ctx ctx = { NULL, NULL, NULL };
 
-    assert(first_event->type == YAML_DOCUMENT_START_EVENT);
+    assert(event->type == YAML_DOCUMENT_START_EVENT);
                         /* DOCUMENT-START is expected. */
 
     parser->document->version_directive
-        = first_event->data.document_start.version_directive;
+        = event->data.document_start.version_directive;
     parser->document->tag_directives.start
-        = first_event->data.document_start.tag_directives.start;
+        = event->data.document_start.tag_directives.start;
     parser->document->tag_directives.end
-        = first_event->data.document_start.tag_directives.end;
+        = event->data.document_start.tag_directives.end;
     parser->document->start_implicit
-        = first_event->data.document_start.implicit;
-    parser->document->start_mark = first_event->start_mark;
-
-    if (!yaml_parser_parse(parser, &event)) return 0;
-
-    if (!yaml_parser_load_node(parser, &event)) return 0;
-
-    if (!yaml_parser_parse(parser, &event)) return 0;
-    assert(event.type == YAML_DOCUMENT_END_EVENT);
-                        /* DOCUMENT-END is expected. */
+        = event->data.document_start.implicit;
+    parser->document->start_mark = event->start_mark;
 
-    parser->document->end_implicit = event.data.document_end.implicit;
-    parser->document->end_mark = event.end_mark;
+    if (!STACK_INIT(parser, ctx, int*)) return 0;
+    if (!yaml_parser_load_nodes(parser, &ctx)) {
+        STACK_DEL(parser, ctx);
+        return 0;
+    }
+    STACK_DEL(parser, ctx);
 
     return 1;
 }
 
 /*
- * Compose a node.
+ * Compose a node tree.
  */
 
 static int
-yaml_parser_load_node(yaml_parser_t *parser, yaml_event_t *first_event)
+yaml_parser_load_nodes(yaml_parser_t *parser, struct loader_ctx *ctx)
 {
-    switch (first_event->type) {
-        case YAML_ALIAS_EVENT:
-            return yaml_parser_load_alias(parser, first_event);
-        case YAML_SCALAR_EVENT:
-            return yaml_parser_load_scalar(parser, first_event);
-        case YAML_SEQUENCE_START_EVENT:
-            return yaml_parser_load_sequence(parser, first_event);
-        case YAML_MAPPING_START_EVENT:
-            return yaml_parser_load_mapping(parser, first_event);
-        default:
-            assert(0);  /* Could not happen. */
-            return 0;
-    }
+    yaml_event_t event;
 
-    return 0;
+    do {
+        if (!yaml_parser_parse(parser, &event)) return 0;
+
+        switch (event.type) {
+            case YAML_ALIAS_EVENT:
+                if (!yaml_parser_load_alias(parser, &event, ctx)) return 0;
+                break;
+            case YAML_SCALAR_EVENT:
+                if (!yaml_parser_load_scalar(parser, &event, ctx)) return 0;
+                break;
+            case YAML_SEQUENCE_START_EVENT:
+                if (!yaml_parser_load_sequence(parser, &event, ctx)) return 0;
+                break;
+            case YAML_SEQUENCE_END_EVENT:
+                if (!yaml_parser_load_sequence_end(parser, &event, ctx))
+                    return 0;
+                break;
+            case YAML_MAPPING_START_EVENT:
+                if (!yaml_parser_load_mapping(parser, &event, ctx)) return 0;
+                break;
+            case YAML_MAPPING_END_EVENT:
+                if (!yaml_parser_load_mapping_end(parser, &event, ctx))
+                    return 0;
+                break;
+            default:
+                assert(0);  /* Could not happen. */
+                return 0;
+            case YAML_DOCUMENT_END_EVENT:
+                break;
+        }
+    } while (event.type != YAML_DOCUMENT_END_EVENT);
+
+    parser->document->end_implicit = event.data.document_end.implicit;
+    parser->document->end_mark = event.end_mark;
+
+    return 1;
 }
 
 /*
@@ -252,27 +291,80 @@ yaml_parser_register_anchor(yaml_parser_t *parser,
     return 1;
 }
 
+/*
+ * Compose node into its parent in the stree.
+ */
+
+static int
+yaml_parser_load_node_add(yaml_parser_t *parser, struct loader_ctx *ctx,
+        int index)
+{
+    struct yaml_node_s *parent;
+    int parent_index;
+
+    if (STACK_EMPTY(parser, *ctx)) {
+        /* This is the root node, there's no tree to add it to. */
+        return 1;
+    }
+
+    parent_index = *((*ctx).top - 1);
+    parent = &parser->document->nodes.start[parent_index-1];
+
+    switch (parent->type) {
+        case YAML_SEQUENCE_NODE:
+            if (!STACK_LIMIT(parser, parent->data.sequence.items, INT_MAX-1))
+                return 0;
+            if (!PUSH(parser, parent->data.sequence.items, index))
+                return 0;
+            break;
+        case YAML_MAPPING_NODE: {
+            yaml_node_pair_t pair;
+            if (!STACK_EMPTY(parser, parent->data.mapping.pairs)) {
+                yaml_node_pair_t *p = parent->data.mapping.pairs.top - 1;
+                if (p->key != 0 && p->value == 0) {
+                    p->value = index;
+                    break;
+                }
+            }
+
+            pair.key = index;
+            pair.value = 0;
+            if (!STACK_LIMIT(parser, parent->data.mapping.pairs, INT_MAX-1))
+                return 0;
+            if (!PUSH(parser, parent->data.mapping.pairs, pair))
+                return 0;
+
+            break;
+        }
+        default:
+            assert(0); /* Could not happen. */
+            return 0;
+    }
+    return 1;
+}
+
 /*
  * Compose a node corresponding to an alias.
  */
 
 static int
-yaml_parser_load_alias(yaml_parser_t *parser, yaml_event_t *first_event)
+yaml_parser_load_alias(yaml_parser_t *parser, yaml_event_t *event,
+        struct loader_ctx *ctx)
 {
-    yaml_char_t *anchor = first_event->data.alias.anchor;
+    yaml_char_t *anchor = event->data.alias.anchor;
     yaml_alias_data_t *alias_data;
 
     for (alias_data = parser->aliases.start;
             alias_data != parser->aliases.top; alias_data ++) {
         if (strcmp((char *)alias_data->anchor, (char *)anchor) == 0) {
             yaml_free(anchor);
-            return alias_data->index;
+            return yaml_parser_load_node_add(parser, ctx, alias_data->index);
         }
     }
 
     yaml_free(anchor);
     return yaml_parser_set_composer_error(parser, "found undefined alias",
-            first_event->start_mark);
+            event->start_mark);
 }
 
 /*
@@ -280,11 +372,12 @@ yaml_parser_load_alias(yaml_parser_t *parser, yaml_event_t *first_event)
  */
 
 static int
-yaml_parser_load_scalar(yaml_parser_t *parser, yaml_event_t *first_event)
+yaml_parser_load_scalar(yaml_parser_t *parser, yaml_event_t *event,
+        struct loader_ctx *ctx)
 {
     yaml_node_t node;
     int index;
-    yaml_char_t *tag = first_event->data.scalar.tag;
+    yaml_char_t *tag = event->data.scalar.tag;
 
     if (!STACK_LIMIT(parser, parser->document->nodes, INT_MAX-1)) goto error;
 
@@ -294,23 +387,23 @@ yaml_parser_load_scalar(yaml_parser_t *parser, yaml_event_t *first_event)
         if (!tag) goto error;
     }
 
-    SCALAR_NODE_INIT(node, tag, first_event->data.scalar.value,
-            first_event->data.scalar.length, first_event->data.scalar.style,
-            first_event->start_mark, first_event->end_mark);
+    SCALAR_NODE_INIT(node, tag, event->data.scalar.value,
+            event->data.scalar.length, event->data.scalar.style,
+            event->start_mark, event->end_mark);
 
     if (!PUSH(parser, parser->document->nodes, node)) goto error;
 
     index = parser->document->nodes.top - parser->document->nodes.start;
 
     if (!yaml_parser_register_anchor(parser, index,
-                first_event->data.scalar.anchor)) return 0;
+                event->data.scalar.anchor)) return 0;
 
-    return index;
+    return yaml_parser_load_node_add(parser, ctx, index);
 
 error:
     yaml_free(tag);
-    yaml_free(first_event->data.scalar.anchor);
-    yaml_free(first_event->data.scalar.value);
+    yaml_free(event->data.scalar.anchor);
+    yaml_free(event->data.scalar.value);
     return 0;
 }
 
@@ -319,17 +412,17 @@ error:
  */
 
 static int
-yaml_parser_load_sequence(yaml_parser_t *parser, yaml_event_t *first_event)
+yaml_parser_load_sequence(yaml_parser_t *parser, yaml_event_t *event,
+        struct loader_ctx *ctx)
 {
-    yaml_event_t event;
     yaml_node_t node;
     struct {
         yaml_node_item_t *start;
         yaml_node_item_t *end;
         yaml_node_item_t *top;
     } items = { NULL, NULL, NULL };
-    int index, item_index;
-    yaml_char_t *tag = first_event->data.sequence_start.tag;
+    int index;
+    yaml_char_t *tag = event->data.sequence_start.tag;
 
     if (!STACK_LIMIT(parser, parser->document->nodes, INT_MAX-1)) goto error;
 
@@ -342,48 +435,54 @@ yaml_parser_load_sequence(yaml_parser_t *parser, yaml_event_t *first_event)
     if (!STACK_INIT(parser, items, yaml_node_item_t*)) goto error;
 
     SEQUENCE_NODE_INIT(node, tag, items.start, items.end,
-            first_event->data.sequence_start.style,
-            first_event->start_mark, first_event->end_mark);
+            event->data.sequence_start.style,
+            event->start_mark, event->end_mark);
 
     if (!PUSH(parser, parser->document->nodes, node)) goto error;
 
     index = parser->document->nodes.top - parser->document->nodes.start;
 
     if (!yaml_parser_register_anchor(parser, index,
-                first_event->data.sequence_start.anchor)) return 0;
-
-    if (!yaml_parser_parse(parser, &event)) return 0;
-
-    while (event.type != YAML_SEQUENCE_END_EVENT) {
-        if (!STACK_LIMIT(parser,
-                    parser->document->nodes.start[index-1].data.sequence.items,
-                    INT_MAX-1)) return 0;
-        item_index = yaml_parser_load_node(parser, &event);
-        if (!item_index) return 0;
-        if (!PUSH(parser,
-                    parser->document->nodes.start[index-1].data.sequence.items,
-                    item_index)) return 0;
-        if (!yaml_parser_parse(parser, &event)) return 0;
-    }
+                event->data.sequence_start.anchor)) return 0;
+
+    if (!yaml_parser_load_node_add(parser, ctx, index)) return 0;
 
-    parser->document->nodes.start[index-1].end_mark = event.end_mark;
+    if (!STACK_LIMIT(parser, *ctx, INT_MAX-1)) return 0;
+    if (!PUSH(parser, *ctx, index)) return 0;
 
-    return index;
+    return 1;
 
 error:
     yaml_free(tag);
-    yaml_free(first_event->data.sequence_start.anchor);
+    yaml_free(event->data.sequence_start.anchor);
     return 0;
 }
 
+static int
+yaml_parser_load_sequence_end(yaml_parser_t *parser, yaml_event_t *event,
+        struct loader_ctx *ctx)
+{
+    int index;
+
+    assert(((*ctx).top - (*ctx).start) > 0);
+
+    index = *((*ctx).top - 1);
+    assert(parser->document->nodes.start[index-1].type == YAML_SEQUENCE_NODE);
+    parser->document->nodes.start[index-1].end_mark = event->end_mark;
+
+    (void)POP(parser, *ctx);
+
+    return 1;
+}
+
 /*
  * Compose a mapping node.
  */
 
 static int
-yaml_parser_load_mapping(yaml_parser_t *parser, yaml_event_t *first_event)
+yaml_parser_load_mapping(yaml_parser_t *parser, yaml_event_t *event,
+        struct loader_ctx *ctx)
 {
-    yaml_event_t event;
     yaml_node_t node;
     struct {
         yaml_node_pair_t *start;
@@ -391,8 +490,7 @@ yaml_parser_load_mapping(yaml_parser_t *parser, yaml_event_t *first_event)
         yaml_node_pair_t *top;
     } pairs = { NULL, NULL, NULL };
     int index;
-    yaml_node_pair_t pair;
-    yaml_char_t *tag = first_event->data.mapping_start.tag;
+    yaml_char_t *tag = event->data.mapping_start.tag;
 
     if (!STACK_LIMIT(parser, parser->document->nodes, INT_MAX-1)) goto error;
 
@@ -405,40 +503,42 @@ yaml_parser_load_mapping(yaml_parser_t *parser, yaml_event_t *first_event)
     if (!STACK_INIT(parser, pairs, yaml_node_pair_t*)) goto error;
 
     MAPPING_NODE_INIT(node, tag, pairs.start, pairs.end,
-            first_event->data.mapping_start.style,
-            first_event->start_mark, first_event->end_mark);
+            event->data.mapping_start.style,
+            event->start_mark, event->end_mark);
 
     if (!PUSH(parser, parser->document->nodes, node)) goto error;
 
     index = parser->document->nodes.top - parser->document->nodes.start;
 
     if (!yaml_parser_register_anchor(parser, index,
-                first_event->data.mapping_start.anchor)) return 0;
+                event->data.mapping_start.anchor)) return 0;
 
-    if (!yaml_parser_parse(parser, &event)) return 0;
-
-    while (event.type != YAML_MAPPING_END_EVENT) {
-        if (!STACK_LIMIT(parser,
-                    parser->document->nodes.start[index-1].data.mapping.pairs,
-                    INT_MAX-1)) return 0;
-        pair.key = yaml_parser_load_node(parser, &event);
-        if (!pair.key) return 0;
-        if (!yaml_parser_parse(parser, &event)) return 0;
-        pair.value = yaml_parser_load_node(parser, &event);
-        if (!pair.value) return 0;
-        if (!PUSH(parser,
-                    parser->document->nodes.start[index-1].data.mapping.pairs,
-                    pair)) return 0;
-        if (!yaml_parser_parse(parser, &event)) return 0;
-    }
+    if (!yaml_parser_load_node_add(parser, ctx, index)) return 0;
 
-    parser->document->nodes.start[index-1].end_mark = event.end_mark;
+    if (!STACK_LIMIT(parser, *ctx, INT_MAX-1)) return 0;
+    if (!PUSH(parser, *ctx, index)) return 0;
 
-    return index;
+    return 1;
 
 error:
     yaml_free(tag);
-    yaml_free(first_event->data.mapping_start.anchor);
+    yaml_free(event->data.mapping_start.anchor);
     return 0;
 }
 
+static int
+yaml_parser_load_mapping_end(yaml_parser_t *parser, yaml_event_t *event,
+        struct loader_ctx *ctx)
+{
+    int index;
+
+    assert(((*ctx).top - (*ctx).start) > 0);
+
+    index = *((*ctx).top - 1);
+    assert(parser->document->nodes.start[index-1].type == YAML_MAPPING_NODE);
+    parser->document->nodes.start[index-1].end_mark = event->end_mark;
+
+    (void)POP(parser, *ctx);
+
+    return 1;
+}
\ No newline at end of file
diff --git a/vendor/parser.c b/vendor/parser.c
index 1198c73..ec2f8d3 100644
--- a/vendor/parser.c
+++ b/vendor/parser.c
@@ -1261,7 +1261,10 @@ yaml_parser_process_directives(yaml_parser_t *parser,
                 goto error;
             }
             if (token->data.version_directive.major != 1
-                    || token->data.version_directive.minor != 1) {
+                    || (
+                        token->data.version_directive.minor != 1
+                        && token->data.version_directive.minor != 2
+                    )) {
                 yaml_parser_set_parser_error(parser,
                         "found incompatible YAML document", token->start_mark);
                 goto error;
diff --git a/vendor/scanner.c b/vendor/scanner.c
index ceee749..c6b4987 100644
--- a/vendor/scanner.c
+++ b/vendor/scanner.c
@@ -348,6 +348,7 @@
  *          SCALAR("another value",plain)
  *          KEY
  *          SCALAR("a mapping",plain)
+ *          VALUE
  *          BLOCK-MAPPING-START
  *          KEY
  *          SCALAR("key 1",plain)
@@ -711,7 +712,7 @@ yaml_parser_scan_tag_handle(yaml_parser_t *parser, int directive,
         yaml_mark_t start_mark, yaml_char_t **handle);
 
 static int
-yaml_parser_scan_tag_uri(yaml_parser_t *parser, int directive,
+yaml_parser_scan_tag_uri(yaml_parser_t *parser, int uri_char, int directive,
         yaml_char_t *head, yaml_mark_t start_mark, yaml_char_t **uri);
 
 static int
@@ -2292,7 +2293,7 @@ yaml_parser_scan_tag_directive_value(yaml_parser_t *parser,
 
     /* Scan a prefix. */
 
-    if (!yaml_parser_scan_tag_uri(parser, 1, NULL, start_mark, &prefix_value))
+    if (!yaml_parser_scan_tag_uri(parser, 1, 1, NULL, start_mark, &prefix_value))
         goto error;
 
     /* Expect a whitespace or line break. */
@@ -2410,7 +2411,7 @@ yaml_parser_scan_tag(yaml_parser_t *parser, yaml_token_t *token)
 
         /* Consume the tag value. */
 
-        if (!yaml_parser_scan_tag_uri(parser, 0, NULL, start_mark, &suffix))
+        if (!yaml_parser_scan_tag_uri(parser, 1, 0, NULL, start_mark, &suffix))
             goto error;
 
         /* Check for '>' and eat it. */
@@ -2438,14 +2439,14 @@ yaml_parser_scan_tag(yaml_parser_t *parser, yaml_token_t *token)
         {
             /* Scan the suffix now. */
 
-            if (!yaml_parser_scan_tag_uri(parser, 0, NULL, start_mark, &suffix))
+            if (!yaml_parser_scan_tag_uri(parser, 0, 0, NULL, start_mark, &suffix))
                 goto error;
         }
         else
         {
             /* It wasn't a handle after all.  Scan the rest of the tag. */
 
-            if (!yaml_parser_scan_tag_uri(parser, 0, handle, start_mark, &suffix))
+            if (!yaml_parser_scan_tag_uri(parser, 0, 0, handle, start_mark, &suffix))
                 goto error;
 
             /* Set the handle to '!'. */
@@ -2474,9 +2475,11 @@ yaml_parser_scan_tag(yaml_parser_t *parser, yaml_token_t *token)
     if (!CACHE(parser, 1)) goto error;
 
     if (!IS_BLANKZ(parser->buffer)) {
-        yaml_parser_set_scanner_error(parser, "while scanning a tag",
-                start_mark, "did not find expected whitespace or line break");
-        goto error;
+        if (!parser->flow_level || !CHECK(parser->buffer, ',') ) {
+            yaml_parser_set_scanner_error(parser, "while scanning a tag",
+                    start_mark, "did not find expected whitespace or line break");
+            goto error;
+        }
     }
 
     end_mark = parser->mark;
@@ -2565,7 +2568,7 @@ error:
  */
 
 static int
-yaml_parser_scan_tag_uri(yaml_parser_t *parser, int directive,
+yaml_parser_scan_tag_uri(yaml_parser_t *parser, int uri_char, int directive,
         yaml_char_t *head, yaml_mark_t start_mark, yaml_char_t **uri)
 {
     size_t length = head ? strlen((char *)head) : 0;
@@ -2601,8 +2604,11 @@ yaml_parser_scan_tag_uri(yaml_parser_t *parser, int directive,
      * The set of characters that may appear in URI is as follows:
      *
      *      '0'-'9', 'A'-'Z', 'a'-'z', '_', '-', ';', '/', '?', ':', '@', '&',
-     *      '=', '+', '$', ',', '.', '!', '~', '*', '\'', '(', ')', '[', ']',
-     *      '%'.
+     *      '=', '+', '$', '.', '!', '~', '*', '\'', '(', ')', '%'.
+     *
+     * If we are inside a verbatim tag <...> (parameter uri_char is true)
+     * then also the following flow indicators are allowed:
+     *      ',', '[', ']'
      */
 
     while (IS_ALPHA(parser->buffer) || CHECK(parser->buffer, ';')
@@ -2610,12 +2616,15 @@ yaml_parser_scan_tag_uri(yaml_parser_t *parser, int directive,
             || CHECK(parser->buffer, ':') || CHECK(parser->buffer, '@')
             || CHECK(parser->buffer, '&') || CHECK(parser->buffer, '=')
             || CHECK(parser->buffer, '+') || CHECK(parser->buffer, '$')
-            || CHECK(parser->buffer, ',') || CHECK(parser->buffer, '.')
+            || CHECK(parser->buffer, '.') || CHECK(parser->buffer, '%')
             || CHECK(parser->buffer, '!') || CHECK(parser->buffer, '~')
             || CHECK(parser->buffer, '*') || CHECK(parser->buffer, '\'')
             || CHECK(parser->buffer, '(') || CHECK(parser->buffer, ')')
-            || CHECK(parser->buffer, '[') || CHECK(parser->buffer, ']')
-            || CHECK(parser->buffer, '%'))
+            || (uri_char && (
+                CHECK(parser->buffer, ',')
+                || CHECK(parser->buffer, '[') || CHECK(parser->buffer, ']')
+                )
+            ))
     {
         /* Check if it is a URI-escape sequence. */
 
@@ -3456,7 +3465,7 @@ yaml_parser_scan_plain_scalar(yaml_parser_t *parser, yaml_token_t *token)
             if ((CHECK(parser->buffer, ':') && IS_BLANKZ_AT(parser->buffer, 1))
                     || (parser->flow_level &&
                         (CHECK(parser->buffer, ',')
-                         || CHECK(parser->buffer, '?') || CHECK(parser->buffer, '[')
+                         || CHECK(parser->buffer, '[')
                          || CHECK(parser->buffer, ']') || CHECK(parser->buffer, '{')
                          || CHECK(parser->buffer, '}'))))
                 break;
@@ -3518,12 +3527,12 @@ yaml_parser_scan_plain_scalar(yaml_parser_t *parser, yaml_token_t *token)
         {
             if (IS_BLANK(parser->buffer))
             {
-                /* Check for tab character that abuse indentation. */
+                /* Check for tab characters that abuse indentation. */
 
                 if (leading_blanks && (int)parser->mark.column < indent
                         && IS_TAB(parser->buffer)) {
                     yaml_parser_set_scanner_error(parser, "while scanning a plain scalar",
-                            start_mark, "found a tab character that violate indentation");
+                            start_mark, "found a tab character that violates indentation");
                     goto error;
                 }
 
diff --git a/vendor/yaml.h b/vendor/yaml.h
index df8e027..12b33a3 100644
--- a/vendor/yaml.h
+++ b/vendor/yaml.h
@@ -26,7 +26,9 @@ extern "C" {
 
 /** The public API declaration. */
 
-#ifdef _WIN32
+#if defined(__MINGW32__)
+#   define  YAML_DECLARE(type)  type
+#elif defined(_WIN32)
 #   if defined(YAML_DECLARE_STATIC)
 #       define  YAML_DECLARE(type)  type
 #   elif defined(YAML_DECLARE_EXPORT)
@@ -230,7 +232,7 @@ typedef enum yaml_token_type_e {
 
     /** A BLOCK-SEQUENCE-START token. */
     YAML_BLOCK_SEQUENCE_START_TOKEN,
-    /** A BLOCK-SEQUENCE-END token. */
+    /** A BLOCK-MAPPING-START token. */
     YAML_BLOCK_MAPPING_START_TOKEN,
     /** A BLOCK-END token. */
     YAML_BLOCK_END_TOKEN,
@@ -550,7 +552,7 @@ yaml_document_end_event_initialize(yaml_event_t *event, int implicit);
  */
 
 YAML_DECLARE(int)
-yaml_alias_event_initialize(yaml_event_t *event, yaml_char_t *anchor);
+yaml_alias_event_initialize(yaml_event_t *event, const yaml_char_t *anchor);
 
 /**
  * Create a SCALAR event.
@@ -576,8 +578,8 @@ yaml_alias_event_initialize(yaml_event_t *event, yaml_char_t *anchor);
 
 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,
+        const yaml_char_t *anchor, const yaml_char_t *tag,
+        const yaml_char_t *value, int length,
         int plain_implicit, int quoted_implicit,
         yaml_scalar_style_t style);
 
@@ -599,7 +601,7 @@ yaml_scalar_event_initialize(yaml_event_t *event,
 
 YAML_DECLARE(int)
 yaml_sequence_start_event_initialize(yaml_event_t *event,
-        yaml_char_t *anchor, yaml_char_t *tag, int implicit,
+        const yaml_char_t *anchor, const yaml_char_t *tag, int implicit,
         yaml_sequence_style_t style);
 
 /**
@@ -631,7 +633,7 @@ yaml_sequence_end_event_initialize(yaml_event_t *event);
 
 YAML_DECLARE(int)
 yaml_mapping_start_event_initialize(yaml_event_t *event,
-        yaml_char_t *anchor, yaml_char_t *tag, int implicit,
+        const yaml_char_t *anchor, const yaml_char_t *tag, int implicit,
         yaml_mapping_style_t style);
 
 /**
@@ -663,7 +665,7 @@ yaml_event_delete(yaml_event_t *event);
 
 /** The tag @c !!null with the only possible value: @c null. */
 #define YAML_NULL_TAG       "tag:yaml.org,2002:null"
-/** The tag @c !!bool with the values: @c true and @c falce. */
+/** The tag @c !!bool with the values: @c true and @c false. */
 #define YAML_BOOL_TAG       "tag:yaml.org,2002:bool"
 /** The tag @c !!str for string values. */
 #define YAML_STR_TAG        "tag:yaml.org,2002:str"
@@ -894,7 +896,7 @@ yaml_document_get_root_node(yaml_document_t *document);
 
 YAML_DECLARE(int)
 yaml_document_add_scalar(yaml_document_t *document,
-        yaml_char_t *tag, yaml_char_t *value, int length,
+        const yaml_char_t *tag, const yaml_char_t *value, int length,
         yaml_scalar_style_t style);
 
 /**
@@ -911,7 +913,7 @@ yaml_document_add_scalar(yaml_document_t *document,
 
 YAML_DECLARE(int)
 yaml_document_add_sequence(yaml_document_t *document,
-        yaml_char_t *tag, yaml_sequence_style_t style);
+        const yaml_char_t *tag, yaml_sequence_style_t style);
 
 /**
  * Create a MAPPING node and attach it to the document.
@@ -927,7 +929,7 @@ yaml_document_add_sequence(yaml_document_t *document,
 
 YAML_DECLARE(int)
 yaml_document_add_mapping(yaml_document_t *document,
-        yaml_char_t *tag, yaml_mapping_style_t style);
+        const yaml_char_t *tag, yaml_mapping_style_t style);
 
 /**
  * Add an item to a SEQUENCE node.
@@ -935,7 +937,7 @@ yaml_document_add_mapping(yaml_document_t *document,
  * @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.
  */
 
@@ -950,7 +952,7 @@ yaml_document_append_sequence_item(yaml_document_t *document,
  * @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.
  */
 
@@ -1018,6 +1020,7 @@ typedef enum yaml_parser_state_e {
     YAML_PARSE_DOCUMENT_CONTENT_STATE,
     /** Expect DOCUMENT-END. */
     YAML_PARSE_DOCUMENT_END_STATE,
+
     /** Expect a block node. */
     YAML_PARSE_BLOCK_NODE_STATE,
     /** Expect a block node or indentless sequence. */
@@ -1028,6 +1031,7 @@ typedef enum yaml_parser_state_e {
     YAML_PARSE_BLOCK_SEQUENCE_FIRST_ENTRY_STATE,
     /** Expect an entry of a block sequence. */
     YAML_PARSE_BLOCK_SEQUENCE_ENTRY_STATE,
+
     /** Expect an entry of an indentless sequence. */
     YAML_PARSE_INDENTLESS_SEQUENCE_ENTRY_STATE,
     /** Expect the first key of a block mapping. */
@@ -1038,6 +1042,7 @@ typedef enum yaml_parser_state_e {
     YAML_PARSE_BLOCK_MAPPING_VALUE_STATE,
     /** Expect the first entry of a flow sequence. */
     YAML_PARSE_FLOW_SEQUENCE_FIRST_ENTRY_STATE,
+
     /** Expect an entry of a flow sequence. */
     YAML_PARSE_FLOW_SEQUENCE_ENTRY_STATE,
     /** Expect a key of an ordered mapping. */
@@ -1049,6 +1054,7 @@ typedef enum yaml_parser_state_e {
     /** Expect the first key of a flow mapping. */
     YAML_PARSE_FLOW_MAPPING_FIRST_KEY_STATE,
     /** Expect a key of a flow mapping. */
+
     YAML_PARSE_FLOW_MAPPING_KEY_STATE,
     /** Expect a value of a flow mapping. */
     YAML_PARSE_FLOW_MAPPING_VALUE_STATE,
@@ -1203,7 +1209,7 @@ typedef struct yaml_parser_s {
     /** The number of tokens fetched from the queue. */
     size_t tokens_parsed;
 
-    /* Does the tokens queue contain a token ready for dequeueing. */
+    /** Does the tokens queue contain a token ready for dequeueing. */
     int token_available;
 
     /** The indentation levels stack. */
@@ -1444,7 +1450,7 @@ yaml_parser_parse(yaml_parser_t *parser, yaml_event_t *event);
  * @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.
+ * @returns @c 1 if the function succeeded, @c 0 on error.
  */
 
 YAML_DECLARE(int)
@@ -1487,6 +1493,7 @@ typedef enum yaml_emitter_state_e {
     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. */
@@ -1497,6 +1504,7 @@ typedef enum yaml_emitter_state_e {
     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. */
@@ -1507,6 +1515,7 @@ typedef enum yaml_emitter_state_e {
     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. */
@@ -1515,6 +1524,18 @@ typedef enum yaml_emitter_state_e {
     YAML_EMIT_END_STATE
 } yaml_emitter_state_t;
 
+
+/* This is needed for C++ */
+
+typedef struct yaml_anchors_s {
+    /** The number of references. */
+    int references;
+    /** The anchor id. */
+    int anchor;
+    /** If the node has been emitted? */
+    int serialized;
+} yaml_anchors_t;
+
 /**
  * The emitter structure.
  *
@@ -1546,7 +1567,7 @@ typedef struct yaml_emitter_s {
     /** Write handler. */
     yaml_write_handler_t *write_handler;
 
-    /** A pointer for passing to the white handler. */
+    /** A pointer for passing to the write handler. */
     void *write_handler_data;
 
     /** Standard (string or file) output data. */
@@ -1740,14 +1761,7 @@ typedef struct yaml_emitter_s {
     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;
+    yaml_anchors_t *anchors;
 
     /** The last assigned anchor id. */
     int last_anchor_id;
@@ -1851,7 +1865,7 @@ YAML_DECLARE(void)
 yaml_emitter_set_canonical(yaml_emitter_t *emitter, int canonical);
 
 /**
- * Set the intendation increment.
+ * Set the indentation increment.
  *
  * @param[in,out]   emitter     An emitter object.
  * @param[in]       indent      The indentation increment (1 < . < 10).
@@ -1938,8 +1952,8 @@ yaml_emitter_close(yaml_emitter_t *emitter);
  *
  * 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.
+ * responsibility for the document object and destroys its content after
+ * it is emitted. The document object is destroyed even if the function fails.
  *
  * @param[in,out]   emitter     An emitter object.
  * @param[in,out]   document    A document object.
diff --git a/yaml.opam b/yaml.opam
index b78704f..ff48459 100644
--- a/yaml.opam
+++ b/yaml.opam
@@ -28,7 +28,7 @@ build: [
   ["dune" "runtest" "-p" name "-j" jobs] {with-test}
 ]
 dev-repo: "git+https://github.com/avsm/ocaml-yaml.git"
-synopsis: "Parse and generate YAML 1.1 files"
+synopsis: "Parse and generate YAML 1.1/1.2 files"
 description: """
 This is an OCaml library to parse and generate the YAML file
 format.  It is intended to interoperable with the [Ezjsonm](https://github.com/mirage/ezjsonm)


Test patch:
diff --git a/tests/test.ml b/tests/test.ml
index 4e9eb7d..efb37d8 100644
--- a/tests/test.ml
+++ b/tests/test.ml
@@ -12,7 +12,7 @@
  * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
  * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. *)
 
-let files = [ "anchor.yml"; "cohttp.yml"; "linuxkit.yml"; "seq.yml"; "too_large.yml" ]
+let files = [ "anchor.yml"; "cohttp.yml"; "linuxkit.yml"; "seq.yml"; "too_large.yml"; "yaml-1.2.yml" ]
 let dir f = Fpath.(v "yaml" / f)
 
 let all_files = List.map dir ("bomb.yml"::files)
diff --git a/tests/yaml/yaml-1.2.yml b/tests/yaml/yaml-1.2.yml
new file mode 100644
index 0000000..d590de3
--- /dev/null
+++ b/tests/yaml/yaml-1.2.yml
@@ -0,0 +1,3 @@
+- {"when the key is quoted":"space after colon can be omitted."}
+- "quoted slashes \/ are allowed."
+- {?"a key can be looooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooger": "than 1024 when parsing is unambiguous before seeing the colon."}