S-expression parsing library with typed codecs for OCaml
0
fork

Configure Feed

Select the types of activity you want to include in your feed.

OCaml 98.6%
Dune 0.4%
Other 0.9%
22 1 0

Clone this repository

https://tangled.org/gazagnaire.org/ocaml-sexpt https://tangled.org/did:plc:jhift2vwcxhou52p3sewcrpx/ocaml-sexpt
git@git.recoil.org:gazagnaire.org/ocaml-sexpt git@git.recoil.org:did:plc:jhift2vwcxhou52p3sewcrpx/ocaml-sexpt

For self-hosted knots, clone URLs may differ based on your setup.

Download tar.gz
README.md

sexpt#

Declarative S-expression codecs for OCaml.

Overview#

Sexpt provides a bidirectional codec system for S-expressions, inspired by Daniel Bünzli's Jsont library. Codecs are defined once and used for both encoding and decoding, eliminating the common source of bugs where serialisation and deserialisation logic diverge.

The library consists of two packages:

  • sexpt -- Core S-expression parsing and codec combinators
  • sexpt.codecs -- Domain-specific codecs (Dune configuration files, and more to come)

Installation#

opam install sexpt

Basic Usage#

Defining a Codec#

open Sexpt

type config = { host : string; port : int; debug : bool }

let config_codec =
  Record.(
    obj (fun host port debug -> { host; port; debug })
    |> mem "host" string ~enc:(fun c -> c.host)
    |> mem "port" int ~enc:(fun c -> c.port)
    |> mem "debug" bool ~enc:(fun c -> c.debug) ~dec_absent:false
    |> finish
  )

Decoding#

let config =
  decode_string_exn config_codec
    {|((host "localhost") (port 8080) (debug true))|}

Encoding#

let sexp = encode config_codec { host = "example.com"; port = 443; debug = false }
(* ((host "example.com") (port 443) (debug false)) *)

S-expression Format#

S-expressions are a minimal data format with two constructs: atoms and lists.

; Atoms
hello
"hello world"
123

; Lists
(a b c)
((x 1) (y 2))

; Records as association lists
((name "Alice")
 (age 30)
 (active true))

; Variants as tagged values
(Some 42)
None

Base Codecs#

Codec OCaml Type S-expression
string string foo, "hello"
int int 42, -17
float float 3.14, -0.5
bool bool true, false
unit unit ()

Combinators#

(* Optional values *)
let opt_int = option int

(* Lists *)
let int_list = list int

(* Pairs *)
let pair_codec = pair string int

Records#

type person = { name : string; age : int; email : string option }

let person_codec =
  Record.(
    obj (fun name age email -> { name; age; email })
    |> mem "name" string ~enc:(fun p -> p.name)
    |> mem "age" int ~enc:(fun p -> p.age)
    |> opt_mem "email" string ~enc:(fun p -> p.email)
    |> finish
  )

Variants#

type colour = Red | Green | Blue | Rgb of int * int * int

let colour_codec =
  Sexpt.Variant.variant [
    Sexpt.Variant.case0 "Red" Red (function Red -> true | _ -> false);
    Sexpt.Variant.case0 "Green" Green (function Green -> true | _ -> false);
    Sexpt.Variant.case0 "Blue" Blue (function Blue -> true | _ -> false);
    Sexpt.Variant.casev "Rgb" (Sexpt.triple Sexpt.int Sexpt.int Sexpt.int)
      (fun (r, g, b) -> Rgb (r, g, b))
      (function Rgb (r, g, b) -> Some (r, g, b) | _ -> None);
  ]

Dune File Support#

The sexpt.codecs package provides utilities for working with Dune configuration files programmatically.

open Sexpt_codecs.Dune

(* Parse a dune-project file *)
let proj = Dune_project.parse sexps
let name = proj.name        (* Some "my-project" *)
let version = proj.version  (* Some "1.0.0" *)

(* Build stanzas programmatically *)
let lib = library ~public_name:"my-lib" ~libraries:["fmt"; "logs"] "foo"

(* Variable expansion *)
let expanded = expand ~env:(function
  | "name" -> Some "Alice"
  | _ -> None
) (Sexp.parse_string_exn "(hello %{name})")
(* (hello Alice) *)

Limitations#

The library does not currently support:

  • Streaming parsing via bytesrw -- a future version could integrate with the bytesrw ecosystem for incremental parsing of large S-expressions
  • Preserving comments or formatting during round-trips
  • Custom atom quoting styles
  • Jsont -- JSON codecs for OCaml. Primary inspiration for the API design.
  • Sexplib -- Jane Street's S-expression library with PPX derivers.
  • Csexp -- Canonical S-expressions used by Dune's RPC protocol.

Licence#

ISC