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(** YAML tags for type information *)
7
8type t = {
9 handle : string; (** e.g., "!" or "!!" or "!foo!" *)
10 suffix : string; (** e.g., "str", "int", "custom/type" *)
11}
12
13let make ~handle ~suffix = { handle; suffix }
14
15let of_string s =
16 let len = String.length s in
17 match len with
18 | 0 -> None
19 | _ when s.[0] <> '!' -> None
20 | 1 -> Some { handle = "!"; suffix = "" }
21 | _ -> (
22 match s.[1] with
23 | '!' ->
24 (* !! handle *)
25 Some { handle = "!!"; suffix = String.sub s 2 (len - 2) }
26 | '<' ->
27 (* Verbatim tag !<...> *)
28 if len > 2 && s.[len - 1] = '>' then
29 Some { handle = "!"; suffix = String.sub s 2 (len - 3) }
30 else None
31 | _ ->
32 (* Primary handle or local tag *)
33 Some { handle = "!"; suffix = String.sub s 1 (len - 1) })
34
35let to_string t =
36 if t.handle = "!" && t.suffix = "" then "!" else t.handle ^ t.suffix
37
38let to_uri t =
39 match t.handle with
40 | "!!" -> "tag:yaml.org,2002:" ^ t.suffix
41 | "!" -> "!" ^ t.suffix
42 | h -> h ^ t.suffix
43
44let pp fmt t = Format.pp_print_string fmt (to_string t)
45let equal a b = String.equal a.handle b.handle && String.equal a.suffix b.suffix
46
47let compare a b =
48 let c = String.compare a.handle b.handle in
49 if c <> 0 then c else String.compare a.suffix b.suffix
50
51(** Standard tags *)
52
53let null = { handle = "!!"; suffix = "null" }
54let bool = { handle = "!!"; suffix = "bool" }
55let int = { handle = "!!"; suffix = "int" }
56let float = { handle = "!!"; suffix = "float" }
57let str = { handle = "!!"; suffix = "str" }
58let seq = { handle = "!!"; suffix = "seq" }
59let map = { handle = "!!"; suffix = "map" }
60let binary = { handle = "!!"; suffix = "binary" }
61let timestamp = { handle = "!!"; suffix = "timestamp" }
62
63(** Check if tag matches a standard type *)
64
65let is_null t = equal t null || (t.handle = "!" && t.suffix = "")
66let is_bool t = equal t bool
67let is_int t = equal t int
68let is_float t = equal t float
69let is_str t = equal t str
70let is_seq t = equal t seq
71let is_map t = equal t map