package ppx_deriving_jsoo
Ppx deriver for Js_of_ocaml
Install
Dune Dependency
Authors
Maintainers
Sources
ppx_deriving_jsoo-0.3.tar.gz
md5=fe7cc6e9871ec6eb9f4db51360f0b5b0
sha512=f7bd3b4839a383959c2cb96632cc5fb9e60b7c2655aea34d535fe2b5c1af290125c895541a063f75cad0acad7d808a61535c7a5e974a4c4fb05526979f886a20
doc/src/ppx_deriving_jsoo.lib/ppx_deriving_jsoo_lib.ml.html
Source file ppx_deriving_jsoo_lib.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 259 260 261 262 263 264 265 266 267 268 269 270 271 272 273 274 275 276 277 278 279 280 281 282 283 284 285 286 287 288 289 290 291 292 293 294 295 296 297 298 299 300 301 302 303 304 305 306 307 308 309 310 311 312 313 314 315 316 317 318 319 320 321 322 323 324 325 326 327 328 329 330 331 332 333 334 335 336 337 338 339 340 341 342 343 344 345 346 347 348 349 350 351 352 353 354 355 356 357 358 359 360 361 362 363 364 365 366 367 368 369 370 371 372 373 374 375 376 377 378 379 380 381 382 383 384 385 386 387 388 389 390
open Ppxlib open Ast_builder.Default module Common = Common module Jsoo_type = Jsoo_type module Jsoo_conv = Jsoo_conv module Ppx_js = Ppx_js open Common module Base = struct let jsoo_types ?modules ?enum ?camel ?snake ~case ~rm_prefix ~mut l = let l = List.map (fun t -> let loc = t.ptype_loc in let name = t.ptype_name.txt in let name_js = mkl ~loc @@ jsoo_name ?modules name in let params = t.ptype_params in let ct_or_t, ct_ext = Jsoo_type.declaration_of_type_kind ?rm_prefix ?modules ?enum ?camel ?snake ~case ~mut t in match ct_or_t with | CT expr -> ct_ext @ [class_infos ~loc ~virt:Concrete ~params ~name:name_js ~expr], None, true | TT c -> ct_ext, Some ( type_declaration ~loc ~name:name_js ~params ~cstrs:[] ~kind:Ptype_abstract ~manifest:(Some c) ~private_:Public), false ) l in List.flatten @@ List.map (fun (x, _, _) -> x) l, List.filter_map (fun (_, x, _) -> x) l, List.map (fun (_, _, x) -> x) l let jsoo_convs ?modules ?enum ~case ~rm_prefix ~mut ?camel ?snake ?remove_undefined l = List.map (fun t -> let cv = Jsoo_conv.conv_expressions ?rm_prefix ?modules ?enum ?camel ?snake ?remove_undefined ~case ~mut t in t, cv) l let jsoo_str ~loc ~rec_flag ~case ~rm_prefix ~recursive ~mut ?modules ?enum ?camel ?snake ?remove_undefined l = let cts, ts, are_class_type = jsoo_types ~case ~rm_prefix ~mut ?modules ?enum ?camel ?snake l in let convs = jsoo_convs ~case ~rm_prefix ~mut ?modules ?enum ?camel ?snake ?remove_undefined l in let vals, conv = List.split @@ List.map2 (fun (t, cv) is_class_type -> let loc = t.ptype_loc in let name = t.ptype_name.txt in let _name_js, name_to, name_of, name_conv = jsoo_name ?modules name, jsoo_name_to ?modules name, jsoo_name_of ?modules name, jsoo_name_conv ?modules name in let to_sig, of_sig, conv_sig = Jsoo_conv.conv_signatures ~is_class_type t in let acc = List.flatten @@ List.map (fun ({e_to; e_of; _}, (name_to, name_of)) -> [ value_binding ~loc ~pat:(pvar ~loc name_to) ~expr:e_to; value_binding ~loc ~pat:(pvar ~loc name_of) ~expr:e_of ]) cv.e_acc in acc @ [ value_binding ~loc ~pat:(ppat_constraint ~loc (pvar ~loc name_to) to_sig) ~expr:cv.e_to; value_binding ~loc ~pat:(ppat_constraint ~loc (pvar ~loc name_of) of_sig) ~expr:cv.e_of ], value_binding ~loc ~pat:(ppat_constraint ~loc (pvar ~loc name_conv) conv_sig) ~expr:(pexp_tuple ~loc [evar ~loc name_to; evar ~loc name_of]) ) convs are_class_type in let rec_flag_type = match recursive with | None -> rec_flag | Some true -> Recursive | Some false -> Nonrecursive in let vals = List.flatten vals in let rec_flag_conv = match recursive, List.length vals with | Some true, _ -> Recursive | Some false, _ -> Nonrecursive | None, i when i <= 2 -> Nonrecursive | _ -> Recursive in pstr_class_type ~loc cts :: (match ts with [] -> [] | _ -> [ pstr_type ~loc rec_flag_type ts ]) @ [ pstr_value ~loc rec_flag_conv vals; pstr_value ~loc Nonrecursive conv ] let jsoo_sig ~loc ~rec_flag ~case ~rm_prefix ~mut ?modules ?enum ?camel ?snake l = let cts, ts, are_class_type = jsoo_types ~case ~rm_prefix ~mut ?modules ?enum ?camel ?snake l in let sigs = List.flatten @@ List.map2 (fun t is_class_type -> let loc = t.ptype_loc in let name = t.ptype_name.txt in let _name_js, name_to, name_of, name_conv = jsoo_name ?modules name, jsoo_name_to ?modules name, jsoo_name_of ?modules name, jsoo_name_conv ?modules name in let to_sig, of_sig, conv_sig = Jsoo_conv.conv_signatures ~is_class_type t in [ value_description ~loc ~name:{txt=name_to; loc} ~type_:to_sig ~prim:[]; value_description ~loc ~name:{txt=name_of; loc} ~type_:of_sig ~prim:[]; value_description ~loc ~name:{txt=name_conv; loc} ~type_:conv_sig ~prim:[]; ]) l are_class_type in let s = psig_class_type ~loc cts :: ( match ts with [] -> [] | _ -> [ psig_type ~loc rec_flag ts ]) in s @ List.map (psig_value ~loc) sigs let jsoo_types_str ~loc ~rec_flag ~case ~rm_prefix ~recursive ~mut ?modules ?enum ?camel ?snake l = let rec_flag = match recursive with | None -> rec_flag | Some true -> Recursive | Some false -> Nonrecursive in let cts, ts, _ = jsoo_types ~case ~rm_prefix ~mut ?modules ?enum ?camel ?snake l in pstr_class_type ~loc cts :: ( match ts with [] -> [] | _ -> [ pstr_type ~loc rec_flag ts ]) let jsoo_convs_str ~loc ~case ~rm_prefix ~recursive ~mut ?modules ?enum ?camel ?snake ?remove_undefined l = let l = jsoo_convs ~case ~rm_prefix ~mut ?modules ?enum ?camel ?snake ?remove_undefined l in let vals, conv = List.split @@ List.map (fun (t, cv) -> let loc = t.ptype_loc in let name = t.ptype_name.txt in let name_to, name_of, name_conv = jsoo_name_to ?modules name, jsoo_name_of ?modules name, jsoo_name_conv ?modules name in let acc = List.flatten @@ List.map (fun ({e_to; e_of; _}, (name_to, name_of)) -> [ value_binding ~loc ~pat:(pvar ~loc name_to) ~expr:e_to; value_binding ~loc ~pat:(pvar ~loc name_of) ~expr:e_of ]) cv.e_acc in acc @ [ value_binding ~loc ~pat:(pvar ~loc name_to) ~expr:cv.e_to; value_binding ~loc ~pat:(pvar ~loc name_of) ~expr:cv.e_of ], value_binding ~loc ~pat:(pvar ~loc name_conv) ~expr:(pexp_tuple ~loc [evar ~loc name_to; evar ~loc name_of])) l in let vals = List.flatten vals in let rec_flag = match recursive, List.length vals with | Some true, _ -> Recursive | Some false, _ -> Nonrecursive | None, i when i <= 2 -> Nonrecursive | _ -> Recursive in [ pstr_value ~loc rec_flag vals; pstr_value ~loc Nonrecursive conv ] end module Ppx_deriver = struct open Base let str_jsoo_types ~loc ~path:_ (rec_flag, types) case force_debug rm_prefix recursive mut modules enum camel snake _remove_undefined = if fake then [] else let str = jsoo_types_str ~loc ~rec_flag ~case ~rm_prefix ~recursive ~mut ?modules ?enum ~camel ~snake types in debug ~force:force_debug "%s" (str_of_structure str); str let sig_jsoo_types ~loc ~path:_ (rec_flag, l) case rm_prefix recursive mut modules enum camel snake = if fake then [] else let rec_flag = match recursive with | None -> rec_flag | Some true -> Recursive | Some false -> Nonrecursive in let cts, ts, _ = jsoo_types ~case ~rm_prefix ~mut ?modules ?enum ~camel ~snake l in let s = psig_class_type ~loc cts :: ( match ts with [] -> [] | _ -> [ psig_type ~loc rec_flag ts ]) in s let str_jsoo_convs ~loc ~path:_ (_rec_flag, l) case force_debug rm_prefix recursive mut modules enum camel snake remove_undefined = if fake then [] else let str = jsoo_convs_str ~loc ~case ~rm_prefix ~recursive ~mut ?modules ?enum ~camel ~snake ~remove_undefined l in debug ~force:force_debug "%s" (str_of_structure str); Ppx_js.transform#structure str let str_gen ~loc ~path:_ (rec_flag, l) case force_debug rm_prefix recursive mut modules enum camel snake remove_undefined = if fake then [] else let str = jsoo_str ~loc ~rec_flag ~case ~rm_prefix ~recursive ~mut ?modules ?enum ~camel ~snake ~remove_undefined l in debug ~force:force_debug "%s" (str_of_structure str); Ppx_js.transform#structure str let sig_gen ~loc ~path:_ (rec_flag, l) case rm_prefix _recursive mut modules enum camel snake = if fake then [] else let s = jsoo_sig ~loc ~rec_flag ~case ~rm_prefix ~mut ?modules ?enum ~camel ~snake l in Pprintast.signature Format.err_formatter s; Ppx_js.transform#signature s let ebool t = let f = Deriving.Args.to_func t in Deriving.Args.of_func (fun ctx loc x k -> match x.pexp_desc with | Pexp_construct ({txt=Lident "true"; _}, _) -> f ctx loc true k | Pexp_construct ({txt=Lident "false"; _}, _) -> f ctx loc false k | _ -> Location.raise_errorf ~loc "wrong boolean argument") let construct_pair t = let f = Deriving.Args.to_func t in Deriving.Args.of_func (fun ctx loc x k -> match x.pexp_desc with | Pexp_tuple [ {pexp_desc=Pexp_construct ({txt=id1; _}, None); _}; {pexp_desc=Pexp_construct ({txt=id2; _}, None); _} ] -> f ctx loc (Longident.name id1, Longident.name id2) k | _ -> Location.raise_errorf ~loc "wrong ident pair argument") let enum t = let f = Deriving.Args.to_func t in Deriving.Args.of_func (fun ctx loc x k -> match x.pexp_desc with | Pexp_construct ({txt=Lident "String"; _}, _) -> f ctx loc `string k | Pexp_construct ({txt=Lident "Int"; _}, _) -> f ctx loc `int k | _ -> f ctx loc `string k) let args_str = Deriving.Args.( empty +> flag "case" +> flag "debug" +> arg "remove_prefix" (ebool __) +> arg "recursive" (ebool __) +> flag "mut" +> arg "modules" (elist (construct_pair __)) +> arg "enum" (enum __) +> flag "camel" +> flag "snake" +> flag "remove_undefined" ) let args_sig = Deriving.Args.( empty +> flag "case" +> arg "remove_prefix" (ebool __) +> arg "recursive" (ebool __) +> flag "mut" +> arg "modules" (elist (construct_pair __)) +> arg "enum" (enum __) +> flag "camel" +> flag "snake" ) let main () = let str_type_decl = Deriving.Generator.make args_str str_gen in let sig_type_decl = Deriving.Generator.make args_sig sig_gen in Deriving.ignore @@ Deriving.add jsoo ~str_type_decl ~sig_type_decl; let str_type_decl = Deriving.Generator.make args_str str_jsoo_types in let sig_type_decl = Deriving.Generator.make args_sig sig_jsoo_types in Deriving.ignore @@ Deriving.add "jsoo_type" ~str_type_decl ~sig_type_decl; let str_type_decl = Deriving.Generator.make args_str str_jsoo_convs in Deriving.ignore @@ Deriving.add "jsoo_conv" ~str_type_decl end module Deriver_exe = struct open Base type options = { case : bool; remove_prefix : bool option; recursive : bool option; mut : bool; debug : bool; modules : (string * string) list option; enum : [ `string | `int ] option; remove_undefined : bool; } let options = { case=false; remove_prefix=None; recursive=None; mut=false; debug=false; modules=None; enum=None; remove_undefined=false} let get_bool s e = match e.pexp_desc with | Pexp_construct ({txt=Lident "true"; _}, _) -> true | Pexp_construct ({txt=Lident "false"; _}, _) -> false | _ -> Location.raise_errorf ~loc:e.pexp_loc "wrong boolean argument for %S" s let rec get_list acc e = match e.pexp_desc with | Pexp_construct ({ txt = Lident "[]"; _ }, None) -> List.rev acc | Pexp_construct ({ txt = Lident "::"; _ }, Some arg) -> begin match arg.pexp_desc with | Pexp_tuple [hd; tl] -> get_list (hd :: acc) tl | _ -> Location.raise_errorf ~loc:arg.pexp_loc "wrong list argument" end | _ -> Location.raise_errorf ~loc:e.pexp_loc "wrong list argument" let get_construct_pair s e = match e.pexp_desc with | Pexp_tuple [ {pexp_desc=Pexp_construct ({txt=id1; _}, None); _}; {pexp_desc=Pexp_construct ({txt=id2; _}, None); _} ] -> (Longident.name id1, Longident.name id2) | _ -> Location.raise_errorf ~loc:e.pexp_loc "wrong ident pair for %S" s let get_enum e = match e.pexp_desc with | Pexp_construct ({txt=Lident "String"; _}, _) -> Some `string | Pexp_construct ({txt=Lident "Int"; _}, _) -> Some `int | _ -> Some `string let get_options = function | {pexp_desc=Pexp_record (l, _); _} -> let l = List.filter_map (function ({txt=Lident s; _}, e) -> Some (s, e) | _ -> None) l in let opt = List.fold_left (fun acc (s, e) -> match s with | "case" -> {acc with case = true} | "remove_prefix" -> {acc with remove_prefix = Some (get_bool s e)} | "recursive" -> {acc with recursive = Some (get_bool s e)} | "mut" -> {acc with mut = true} | "debug" -> {acc with debug = true} | "modules" -> {acc with modules = Some (List.map (get_construct_pair s) (get_list [] e))} | "enum" -> {acc with enum = get_enum e} | "remove_undefined" -> {acc with remove_undefined = true} | _ -> Location.raise_errorf ~loc:e.pexp_loc "argument %S not handled" s ) options l in Some opt | _ -> Some options let filter l = let t = List.hd @@ List.rev l in let rec iter = function | [] -> None | a :: tl -> if a.attr_name.txt <> "deriving" then iter tl else match a.attr_payload with | PStr str -> let rec aux = function | [] -> iter tl | it :: str -> match it.pstr_desc with | Pstr_eval ({pexp_desc=Pexp_ident {txt=Lident "jsoo"; _}; _}, _) -> Some options | Pstr_eval ({pexp_desc=Pexp_apply ({pexp_desc=Pexp_ident {txt=Lident "jsoo"; _}; _}, [Nolabel, e]); _}, _) -> get_options e | Pstr_eval ({pexp_desc=Pexp_tuple l; _}, _) -> let rec aux2 = function | [] -> aux str | h :: etl -> match h with | {pexp_desc=Pexp_ident {txt=Lident "jsoo"; _}; _} -> Some options | {pexp_desc=Pexp_apply ({pexp_desc=Pexp_ident {txt=Lident "jsoo"; _}; _}, [Nolabel, e]); _} -> get_options e | _ -> aux2 etl in aux2 l | _ -> aux str in aux str | _ -> iter tl in iter t.ptype_attributes let process ~loc ?(kind=`all) ~rec_flag ~case ~rm_prefix ~recursive ~mut ?modules ?enum ?remove_undefined l = match kind with | `all -> jsoo_str ~loc ~rec_flag ~case ~rm_prefix ~recursive ~mut ?modules ?enum ?remove_undefined l | `typ -> jsoo_types_str ~loc ~rec_flag ~case ~rm_prefix ~recursive ~mut ?modules ?enum l | `conv -> jsoo_convs_str ~loc ~case ~rm_prefix ~recursive ~mut ?modules ?enum ?remove_undefined l let rec derive_str ?(loc=Location.none) ?kind name str = let str = List.fold_left (fun acc it -> match it.pstr_desc with | Pstr_type (rec_flag, l) -> begin match filter l with | None -> acc | Some o -> let str = process ~loc:it.pstr_loc ?kind ~rec_flag ~case:o.case ~rm_prefix:o.remove_prefix ~recursive:o.recursive ~mut:o.mut ?modules:o.modules ?enum:o.enum ~remove_undefined:o.remove_undefined l in Common.debug ~force:o.debug "%s" (Common.str_of_structure str); acc @ (Ppx_js.transform#structure str) end | Pstr_module p -> begin match p.pmb_name.txt with | None -> acc | Some name -> begin match p.pmb_expr.pmod_desc with | Pmod_structure str -> let str = derive_str ?kind name str in if List.length str <= 1 then acc else let loc = p.pmb_expr.pmod_loc in acc @ [ pstr_module ~loc @@ module_binding ~loc ~name:{txt=Some name; loc} ~expr:(pmod_structure ~loc str) ] | _ -> acc end end | Pstr_attribute a -> if a.attr_name.txt <> "jsoo" then acc else begin match a.attr_payload with | PStr str -> acc @ Ppx_js.transform#structure str | _ -> acc end | _ -> acc) [] str in pstr_open ~loc (open_infos ~loc ~override:Fresh ~expr:(pmod_ident ~loc (Common.llid ~loc name))) :: str let main () = let filename = ref None in let outfile = ref None in let kind = ref `all in let specs = [ "--output", Arg.String (fun s -> outfile := Some s), "output file"; "-o", Arg.String (fun s -> outfile := Some s), "alias of --output"; "--type-only", Arg.Unit (fun () -> kind := `typ), "only output type/class type"; "--conv-only", Arg.Unit (fun () -> kind := `conv), "only output conversion function"; ] in let usage = "derive_jsoo <options> <filename>" in Arg.parse specs (fun f -> filename := Some f) usage; match !filename with | None -> Arg.usage specs usage | Some f -> let name = String.capitalize_ascii @@ Filename.(remove_extension @@ basename f) in let ic = open_in f in let s = really_input_string ic (in_channel_length ic) in let lexbuf = Lexing.from_string s in let str = Parse.implementation lexbuf in let str = derive_str ~kind:!kind name str in match !outfile with | None -> Pprintast.structure Format.std_formatter str | Some f -> let oc = open_out f in Pprintast.structure (Format.formatter_of_out_channel oc) str end
sectionYPositions = computeSectionYPositions($el), 10)"
x-init="setTimeout(() => sectionYPositions = computeSectionYPositions($el), 10)"
>