Pure OCaml Yaml 1.2 reader and writer using Bytesrw
1(*---------------------------------------------------------------------------
2 Copyright (c) 2025 Anil Madhavapeddy <anil@recoil.org>. All rights reserved.
3 SPDX-License-Identifier: ISC
4 ---------------------------------------------------------------------------*)
5
6(* Format parser events as tree notation compatible with yaml-test-suite *)
7
8open Yamlrw
9
10let escape_string s =
11 let buf = Buffer.create (String.length s * 2) in
12 String.iter (fun c ->
13 match c with
14 | '\n' -> Buffer.add_string buf "\\n"
15 | '\t' -> Buffer.add_string buf "\\t"
16 | '\r' -> Buffer.add_string buf "\\r"
17 | '\\' -> Buffer.add_string buf "\\\\"
18 | '\x00' -> Buffer.add_string buf "\\0"
19 | '\x07' -> Buffer.add_string buf "\\a"
20 | '\x08' -> Buffer.add_string buf "\\b"
21 | '\x0b' -> Buffer.add_string buf "\\v"
22 | '\x0c' -> Buffer.add_string buf "\\f"
23 | '\x1b' -> Buffer.add_string buf "\\e"
24 | '\xa0' -> Buffer.add_string buf "\\_"
25 | c -> Buffer.add_char buf c
26 ) s;
27 Buffer.contents buf
28
29let style_char = function
30 | `Plain -> ':'
31 | `Single_quoted -> '\''
32 | `Double_quoted -> '"'
33 | `Literal -> '|'
34 | `Folded -> '>'
35 | `Any -> ':'
36
37let format_event { Event.event; span = _span } =
38 match event with
39 | Event.Stream_start _ -> "+STR"
40 | Event.Stream_end -> "-STR"
41 | Event.Document_start { implicit; _ } ->
42 if implicit then "+DOC"
43 else "+DOC ---"
44 | Event.Document_end { implicit } ->
45 if implicit then "-DOC"
46 else "-DOC ..."
47 | Event.Mapping_start { anchor; tag; style; _ } ->
48 let anchor_str = match anchor with Some a -> " &" ^ a | None -> "" in
49 let tag_str = match tag with Some t -> " <" ^ t ^ ">" | None -> "" in
50 let flow_str = match style with `Flow -> " {}" | _ -> "" in
51 Printf.sprintf "+MAP%s%s%s" flow_str anchor_str tag_str
52 | Event.Mapping_end -> "-MAP"
53 | Event.Sequence_start { anchor; tag; style; _ } ->
54 let anchor_str = match anchor with Some a -> " &" ^ a | None -> "" in
55 let tag_str = match tag with Some t -> " <" ^ t ^ ">" | None -> "" in
56 let flow_str = match style with `Flow -> " []" | _ -> "" in
57 Printf.sprintf "+SEQ%s%s%s" flow_str anchor_str tag_str
58 | Event.Sequence_end -> "-SEQ"
59 | Event.Scalar { anchor; tag; value; style; _ } ->
60 let anchor_str = match anchor with Some a -> " &" ^ a | None -> "" in
61 let tag_str = match tag with Some t -> " <" ^ t ^ ">" | None -> "" in
62 let style_c = style_char style in
63 Printf.sprintf "=VAL%s%s %c%s" anchor_str tag_str style_c (escape_string value)
64 | Event.Alias { anchor } ->
65 Printf.sprintf "=ALI *%s" anchor
66
67let of_spanned_events events =
68 let buf = Buffer.create 256 in
69 List.iter (fun (e : Event.spanned) ->
70 let line = format_event e in
71 Buffer.add_string buf line;
72 Buffer.add_char buf '\n'
73 ) events;
74 Buffer.contents buf