I have the following attribute attached to nodes [@profiling.mark [ "label1"; "label2"; "label3" ]]
which gives me this AST:
[{attr_name = {txt = "profiling.mark"};
attr_payload =
PStr
[{pstr_desc =
Pstr_eval
({pexp_desc =
Pexp_construct ({txt = Lident "::"},
Some
{pexp_desc =
Pexp_tuple
[{pexp_desc =
Pexp_constant
(Pconst_string ("label1", ...));
pexp_loc_stack = []};
{pexp_desc =
Pexp_construct ({txt = Lident "::"},
Some
{pexp_desc =
Pexp_tuple
[{pexp_desc =
Pexp_constant
(Pconst_string ("label2", ...));
pexp_loc_stack = []};
{pexp_desc =
Pexp_construct
({txt = Lident "::"},
Some
{pexp_desc =
Pexp_tuple
[{pexp_desc =
Pexp_constant
(Pconst_string ("label3",
...));
pexp_loc_stack = []};
{pexp_desc =
Pexp_construct
({txt = Lident "[]"},
None);
pexp_loc_stack = []}];
pexp_loc_stack = []});
pexp_loc_stack = []}];
pexp_loc_stack = []});
pexp_loc_stack = []}];
pexp_loc_stack = []});
pexp_loc_stack = []},
...)}]}]
If I want to extract the labels, I need to destruct a Pstr_construct
so I did this:
Ppxlib.PStr
[
[%stri
[%e?
{
pexp_desc =
Pexp_construct
( { txt = Lident "::"; _ },
Some { pexp_desc = Pexp_tuple labels; _ } );
_;
}]];
] ->
{ metadata = labels }
First of all, I tried to use metaquot to destroy the list but couldn't find the way to do it. But the most important is that labels
is an expression list
and not an expression
so I can't reconstruct it with [%e labels]
.
I then came up with a different approach:
Ppxlib.PStr
[
[%stri
[%e?
{
pexp_desc =
Pexp_construct ({ txt = Lident "::"; _ }, Some labels);
_;
}]];
] ->
{ metadata = Some labels }
But when I read the preprocessed file I see this: ("label1", ["label2"; "label3"])
. I don't have a list but a tuple with an element and a list. In my case, I need ["label1"; "label2"; "label3"]
.
Am I doing something wrong or missing something somewhere?
Extracting a list can be done with
let rec extract_list =function
| [%expr [%e? h] :: [%e? r] ] -> Option.map (List.cons h) (extract_list r)
| [%expr [] ] -> Some []
| _ -> None
Reconstructing the list is similar:
let rec embed_list loc = function
| [] -> [%expr []]
| [e] -> [%expr [[%e e]] ]
| a::q -> [%expr [%e a]::[%e embed_list loc q] ]