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.
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
.
type ('a, 'b) fold = 'b t -> 'b -> 'a -> 'b
The type for folds on values of type 'a
.
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
.
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.
inline_ext_default f
is the inline extension defaulter of f
.
block_ext_default f
is the block extension defaulter of f
.
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