[ANN] OTOML 0.9.0 — a compliant and flexible TOML parsing, manipulation, and pretty-printing library

A new 0.9.3 relase is available. Still not 1.0.0 just in case. The change I’m most glad I managed to make is that the lexer is now re-entrant and doesn’t use any mutable state. Where can I apply for the “Designed for multicore OCaml” certification sticker? :wink:

Breaking change in the functor interface

I found an oversight that took a breaking change to fix. It didn’t break any package that was already in the OPAM repository, so I’m glad I noticed it before it caused anyone trouble.

My idea to make the functor take separate integer and float modules turned out to be misguided: it wouldn’t compose with Otoml.get_float ~strict:false and similar functions that apply type conversions.

Logically, Otoml.get_float ~strict:false (Otoml.integer 5) should produce Otoml.TomlFloat 5.0. However, it means that get_float needs to know how to convert integers to float. If integer and float types are in separate modules, that isn’t possible.

So I combined both integers and floats in a single TomlNumber. That way people who want to bring their own bignum libraries will have to write more code, but numbers will behave as they are expected to in a dynamically typed format.

module BigNumber = struct
  type int = Z.t
  type float = Decimal.t

  let int_of_string = Z.of_string
  let int_to_string = Z.to_string
  let int_of_boolean b = if b then Z.one else Z.zero
  let int_to_boolean n = (n <> Z.zero)

  (* Can't just reuse Decimal.to/of_string because their optional arguments
     would cause a signature mismatch. *)
  let float_of_string s = Decimal.of_string s

  (* Decimal.to_string uses "NaN" spelling
     while TOML requires all special float values to be lowercase. *)
  let float_to_string x = Decimal.to_string x |> String.lowercase_ascii
  let float_of_boolean b = if b then Decimal.one else Decimal.zero
  let float_to_boolean x = (x <> Decimal.zero)

  let float_of_int = Decimal.of_bigint
  let int_of_float = Decimal.to_bigint
end

module Otoml = Otoml.Base.Make (BigNumber) (Otoml.Base.StringDate)

The next release will likely be 1.0.0 for real.

2 Likes