Module Cmarkit.Folder

Abstract syntax tree folders.

Folders help with pushing abstract syntax tree folds in every node with a minimal amount of code by defaulting the cases you don't handle. The default fold returns the accumulator unchanged on leaves and otherwise propagates the fold to all children.

See an example.

Fold results

type 'a result = [
  1. | `Default
    (*

    Do the default fold

    *)
  2. | `Fold of 'a
]

The type for folder results. The `Default case indicates the folder to perform the default fold.

val default : 'a result

default is `Default.

val ret : 'a -> 'a result

ret v is `Fold v.

Folders

type 'a t

The type for abstract syntax tree folders with result values of type 'a.

type ('a, 'b) fold = 'b t -> 'b -> 'a -> 'b

The type for folds on values of type 'a.

type ('a, 'b) folder = 'b t -> 'b -> 'a -> 'b result

The type for folders on value of type 'a.

This is what you specify. Return `Default if you are not interested in handling the given case. Use fold_inline or fold_block with the given folder if you need to call the folder recursively.

val make : ?inline_ext_default:(Inline.t, 'a) fold -> ?block_ext_default:(Block.t, 'a) fold -> ?inline:(Inline.t, 'a) folder -> ?block:(Block.t, 'a) folder -> unit -> 'a t

make ?inline ?block () is a folder using inline and block to fold the abstract syntax tree. Both default to fun _ _ _ -> `Default.

The folder knows how to default the built-in abstract syntax tree and the built-in extensions. It folds them in document and depth-first order.

If you extend the abstract syntax tree you need to indicate how to default these new cases by providing inline_ext_default or block_ext_default functions. By default these functions raise Invalid_argument.

Folding

val fold_inline : 'a t -> 'a -> Inline.t -> 'a

fold_inline f acc i folds i with f starting with acc.

val fold_block : 'a t -> 'a -> Block.t -> 'a

fold_block f acc b folds b with f starting with acc.

val fold_doc : 'a t -> 'a -> Doc.t -> 'a

fold_doc f acc d folds Doc.block d with f starting with acc.

Warning. Blocks present in d's Doc.defs is not folded over. Note however that if these definitions were defined by d's abstract syntax tree, they will already have been folded over on Block.Link_reference_definition and Block.Ext_footnote_definition cases.

Accessors

val inline_folder : 'a t -> (Inline.t, 'a) folder

inline_folder f is the inline folder of f.

val block_folder : 'a t -> (Block.t, 'a) folder

block_folder f is the block folder of f.

val inline_ext_default : 'a t -> (Inline.t, 'a) fold

inline_ext_default f is the inline extension defaulter of f.

val block_ext_default : 'a t -> (Block.t, 'a) fold

block_ext_default f is the block extension defaulter of f.

Example

This example collects the languages present in the code blocks of a document.

let code_block_langs doc =
  let open Cmarkit in
  let module String_set = Set.Make (String) in
  let block m acc = function
  | Block.Code_block (cb, _) ->
      let acc = match Block.Code_block.info_string cb with
      | None -> acc
      | Some (info, _) ->
          match Block.Code_block.language_of_info_string info with
          | None -> acc
          | Some (lang, _) -> String_set.add lang acc
      in
      Folder.ret acc
  | _ ->
      Folder.default (* let the folder thread the fold *)
  in
  let folder = Folder.make ~block () in
  let langs = Folder.fold_doc folder String_set.empty doc in
  String_set.elements langs