package ppx_module
sectionYPositions = computeSectionYPositions($el), 10)"
x-init="setTimeout(() => sectionYPositions = computeSectionYPositions($el), 10)"
>
PPX-generated module instantiation graphs
Install
dune-project
Dependency
Authors
Maintainers
Sources
ppx_module-0.0.1.tbz
sha256=5cac9f2a43bf47bb6829ebbf31ba945117f95947c1334252052dac55fd29dc3e
sha512=73710780e913b33b07e835943de5669e43ccbdaa2de6ad869e64d5dcfb9264f8be37b8cd2ed2ce6311acce5a49484cc951cd652a8983ccf23a75e60c986fa03f
doc/src/ppx_module_ppx/ppx.ml.html
Source file ppx.ml
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 163 164 165 166 167 168 169 170 171 172 173 174 175 176 177 178 179 180 181 182 183 184 185 186 187 188 189 190 191 192 193 194 195 196 197 198 199 200 201 202 203 204 205 206 207 208 209 210 211 212 213 214 215 216 217 218 219 220 221 222 223 224 225 226 227 228 229 230 231 232 233 234 235 236 237 238 239 240 241 242 243 244 245 246 247 248 249 250 251 252 253 254 255 256 257 258 259open Ppxlib open Ast_builder.Default let attr_name = "ppx_module" let unknown_field_error ~loc field = Location.raise_errorf ~loc "unknown [@@ppx_module] field %S; supported fields are: name, cluster, \ parents" field type annotation = { name : string option; cluster : string option; parents : bool; } let expr_string = function | { pexp_desc = Pexp_constant (Pconst_string (s, _, _)); _ } -> Some s | _ -> None let expr_bool = function | { pexp_desc = Pexp_construct ({ txt = Lident "true"; _ }, None); _ } -> Some true | { pexp_desc = Pexp_construct ({ txt = Lident "false"; _ }, None); _ } -> Some false | _ -> None let parse_record_payload fields = let name = ref None in let cluster = ref None in let parents = ref true in let field_name { txt; loc } = match txt with | Lident field -> field | _ -> Location.raise_errorf ~loc "[@@ppx_module] fields must be unqualified" in let parse_string_field ~loc field expr = match expr_string expr with | Some value -> value | None -> Location.raise_errorf ~loc "[@@ppx_module] field %S must be a string literal" field in let parse_bool_field ~loc field expr = match expr_bool expr with | Some value -> value | None -> Location.raise_errorf ~loc "[@@ppx_module] field %S must be a boolean literal" field in let parse_field (({ loc; _ } as lid), expr) = match field_name lid with | "name" -> name := Some (parse_string_field ~loc "name" expr) | "cluster" -> cluster := Some (parse_string_field ~loc "cluster" expr) | "parents" -> parents := parse_bool_field ~loc "parents" expr | field -> unknown_field_error ~loc field in List.iter parse_field fields; { name = !name; cluster = !cluster; parents = !parents } let parse_annotation attr = match attr.attr_payload with | PStr [] -> { name = None; cluster = None; parents = true } | PStr [ { pstr_desc = Pstr_eval ({ pexp_desc = Pexp_record (fields, None); _ }, _); _; }; ] -> parse_record_payload fields | _ -> Location.raise_errorf ~loc:attr.attr_loc "[@@ppx_module] expects no payload or a record payload, e.g. \ [@@ppx_module] or [@@ppx_module { name = \"Memory.Domain\"; cluster = \ \"memory\" }]" let annotation mb = mb.pmb_attributes |> List.find_opt (fun a -> a.attr_name.txt = attr_name) |> Option.map parse_annotation let without_attr attrs = List.filter (fun a -> a.attr_name.txt <> attr_name) attrs let collect_functor_params expr = let rec go acc e = match e.pmod_desc with | Pmod_functor (Named ({ txt = Some n; _ }, _), body) -> go (acc @ [ n ]) body | Pmod_functor (Named ({ txt = None; _ }, _), body) -> go acc body | Pmod_functor (Unit, body) -> go acc body | Pmod_constraint (me, _) -> go acc me | _ -> acc in go [] expr type metadata = { loc : Location.t; source_file : string; source_line : int; source_item_name : string; name : string; cluster : string option; parents : bool; lexical_path : string list; context : string list; functor_params : string list; } let default_name source_file = source_file |> Filename.basename |> Filename.remove_extension |> String.capitalize_ascii let module_metadata ~(annotation : annotation) ~context ~lexical_stack item mb = let source_file = item.pstr_loc.loc_start.pos_fname in let loc = mb.pmb_loc in let source_item_name = Option.value ~default:"_" mb.pmb_name.txt in let name = Option.value ~default:(default_name source_file) annotation.name in { loc; source_file; source_line = loc.loc_start.pos_lnum; source_item_name; name; cluster = annotation.cluster; parents = annotation.parents; lexical_path = lexical_stack @ [ name ]; context; functor_params = collect_functor_params mb.pmb_expr; } let string_list_expr ~loc xs = xs |> List.map (estring ~loc) |> elist ~loc let option_string_expr ~loc = function | None -> [%expr None] | Some s -> [%expr Some [%e estring ~loc s]] let module_value_expr ~loc module_name value_name = pexp_ident ~loc { txt = Ldot (Lident module_name, value_name); loc } type dependency_kind = Parent_dependency | Context_dependency let dependency_kind_expr ~loc = function | Parent_dependency -> [%expr Ppx_module.Parent] | Context_dependency -> [%expr Ppx_module.Context] let dependency_expr ~loc kind param = let label = estring ~loc param in let kind = dependency_kind_expr ~loc kind in let node = module_value_expr ~loc param "ppx_module_node" in [%expr [%e label], [%e kind], [%e node]] let dependency_exprs ~loc ~parents ~context = List.map (dependency_expr ~loc Parent_dependency) parents @ List.map (dependency_expr ~loc Context_dependency) context |> elist ~loc let gen_bindings meta ~parent_params = let loc = meta.loc in let parents = dependency_exprs ~loc ~parents:parent_params ~context:meta.context in [ [%stri let ppx_module_name = lazy [%e estring ~loc meta.name]]; [%stri let ppx_module_node = Ppx_module.build_with_metadata ~source_file:[%e estring ~loc meta.source_file] ~source_line:[%e eint ~loc meta.source_line] ~source_item_name:[%e estring ~loc meta.source_item_name] ~cluster:[%e option_string_expr ~loc meta.cluster] ~lexical_path:[%e string_list_expr ~loc meta.lexical_path] ~functor_params:[%e string_list_expr ~loc meta.functor_params] ~name:ppx_module_name ~parents:[%e parents]]; ] let add_generated_bindings meta params_acc items = let parent_params = if meta.parents then params_acc else [] in items @ gen_bindings meta ~parent_params let inject_into_body meta expr = let rec go params_acc e = match e.pmod_desc with | Pmod_functor (Named (({ txt = Some n; _ } as nloc), mt), body) -> { e with pmod_desc = Pmod_functor (Named (nloc, mt), go (params_acc @ [ n ]) body); } | Pmod_functor (Named (({ txt = None; _ } as nloc), mt), body) -> { e with pmod_desc = Pmod_functor (Named (nloc, mt), go params_acc body); } | Pmod_functor (Unit, body) -> { e with pmod_desc = Pmod_functor (Unit, go params_acc body) } | Pmod_constraint (me, mt) -> { e with pmod_desc = Pmod_constraint (go params_acc me, mt) } | Pmod_structure items -> { e with pmod_desc = Pmod_structure (add_generated_bindings meta params_acc items); } | _ -> e in go [] expr let mapper = object (self) inherit Ast_traverse.map as super val mutable context_params : string list = [] val mutable lexical_stack : string list = [] method private map_nested_modules meta mb = let saved_context = context_params in let saved_lexical = lexical_stack in context_params <- saved_context @ meta.functor_params; lexical_stack <- meta.lexical_path; Fun.protect (fun () -> super#module_binding mb) ~finally:(fun () -> context_params <- saved_context; lexical_stack <- saved_lexical) method private rewrite_module_binding item mb = match annotation mb with | None -> super#module_binding mb | Some annotation -> let meta = module_metadata ~annotation ~context:context_params ~lexical_stack item mb in let mb = self#map_nested_modules meta mb in let pmb_expr = inject_into_body meta mb.pmb_expr in let pmb_attributes = without_attr mb.pmb_attributes in { mb with pmb_expr; pmb_attributes } method! structure_item item = match item.pstr_desc with | Pstr_module mb -> { item with pstr_desc = Pstr_module (self#rewrite_module_binding item mb); } | Pstr_recmodule mbs -> { item with pstr_desc = Pstr_recmodule (List.map (self#rewrite_module_binding item) mbs); } | _ -> super#structure_item item end let () = Driver.register_transformation "ppx_module" ~impl:mapper#structure
sectionYPositions = computeSectionYPositions($el), 10)"
x-init="setTimeout(() => sectionYPositions = computeSectionYPositions($el), 10)"
>