package ppx_sexp_message
A ppx rewriter for easy construction of s-expressions
Install
Dune Dependency
Authors
Maintainers
Sources
ppx_sexp_message-v0.15.0.tar.gz
sha256=0d94785f80e45b97269e2e34b762a0909eba6a46e55c383cf8c1bdb8ffffdaba
doc/src/ppx_sexp_message.expander/ppx_sexp_message_expander.ml.html
Source file ppx_sexp_message_expander.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
open Base open Ppxlib open Ast_builder.Default let omit_nil_attr = Attribute.declare "sexp_message.sexp.omit_nil" Attribute.Context.core_type Ast_pattern.(pstr nil) () ;; let option_attr = Attribute.declare "sexp_message.sexp.option" Attribute.Context.core_type Ast_pattern.(pstr nil) () ;; let sexp_atom ~loc x = [%expr Ppx_sexp_conv_lib.Sexp.Atom [%e x]] let sexp_list ~loc x = [%expr Ppx_sexp_conv_lib.Sexp.List [%e x]] let sexp_inline ~loc l = match l with | [ x ] -> x | _ -> sexp_list ~loc (elist ~loc l) ;; (* Same as Ppx_sexp_value.omittable_sexp *) type omittable_sexp = | Present of expression | Optional of Location.t * expression * (expression -> expression) | Omit_nil of Location.t * expression * (expression -> expression) | Absent let present_or_omit_nil ~loc ~omit_nil expr = if omit_nil then Omit_nil (loc, expr, Fn.id) else Present expr ;; let wrap_sexp_if_present omittable_sexp ~f = match omittable_sexp with | Present e -> Present (f e) | Optional (loc, e, k) -> Optional (loc, e, fun e -> f (k e)) | Omit_nil (loc, e, k) -> Omit_nil (loc, e, fun e -> f (k e)) | Absent -> Absent ;; let sexp_of_constraint ~omit_nil ~loc expr ctyp = let optional ty = let sexp_of = Ppx_sexp_conv_expander.Sexp_of.core_type ty in Optional (loc, expr, fun expr -> eapply ~loc sexp_of [ expr ]) in match ctyp with | [%type: [%t? ty] option] when Option.is_some (Attribute.get option_attr ctyp) -> optional ty | [%type: [%t? ty] option] when omit_nil -> optional ty | _ -> let expr = let sexp_of = Ppx_sexp_conv_expander.Sexp_of.core_type ctyp in eapply ~loc sexp_of [ expr ] in let omit_nil_attr = lazy (* this is lazy so using [@omit_nil] inside [%message.omit_nil] is an error (unused attribute) *) (match Attribute.get omit_nil_attr ctyp with | Some () -> true | None -> false) in present_or_omit_nil ~loc expr ~omit_nil:(omit_nil || Lazy.force omit_nil_attr) ;; let sexp_of_constant ~loc const = let f typ = eapply ~loc (evar ~loc ("Ppx_sexp_conv_lib.Conv.sexp_of_" ^ typ)) [ pexp_constant ~loc const ] in match const with | Pconst_integer _ -> f "int" | Pconst_char _ -> f "char" | Pconst_string _ -> f "string" | Pconst_float _ -> f "float" ;; let rewrite_here e = match e.pexp_desc with | Pexp_extension ({ txt = "here"; _ }, PStr []) -> Ppx_here_expander.lift_position_as_string ~loc:e.pexp_loc | _ -> e ;; let sexp_of_expr ~omit_nil e = let e = rewrite_here e in let loc = { e.pexp_loc with loc_ghost = true } in match e.pexp_desc with | Pexp_constant (Pconst_string ("", _, _)) -> Absent | Pexp_constant const -> present_or_omit_nil ~loc ~omit_nil:false (sexp_of_constant ~loc const) | Pexp_constraint (expr, ctyp) -> sexp_of_constraint ~omit_nil ~loc expr ctyp | _ -> present_or_omit_nil ~loc ~omit_nil:false [%expr Ppx_sexp_conv_lib.Conv.sexp_of_string [%e e]] ;; let sexp_of_labelled_expr ~omit_nil (label, e) = let loc = { e.pexp_loc with loc_ghost = true } in match label, e.pexp_desc with | Nolabel, Pexp_constraint (expr, _) -> let expr_str = Pprintast.string_of_expression expr in let k e = sexp_inline ~loc [ sexp_atom ~loc (estring ~loc expr_str); e ] in wrap_sexp_if_present (sexp_of_expr ~omit_nil e) ~f:k | Nolabel, _ -> sexp_of_expr ~omit_nil e | Labelled "_", _ -> sexp_of_expr ~omit_nil e | Labelled label, _ -> let k e = sexp_inline ~loc [ sexp_atom ~loc (estring ~loc label); e ] in wrap_sexp_if_present (sexp_of_expr ~omit_nil e) ~f:k | Optional _, _ -> (* Could be used to encode sexp_option if that's ever needed. *) Location.raise_errorf ~loc "ppx_sexp_value: optional argument not allowed here" ;; let sexp_of_labelled_exprs ~omit_nil ~loc labels_and_exprs = let loc = { loc with loc_ghost = true } in let l = List.map labels_and_exprs ~f:(sexp_of_labelled_expr ~omit_nil) in let res = List.fold_left (List.rev l) ~init:(elist ~loc []) ~f:(fun acc e -> match e with | Absent -> acc | Present e -> [%expr [%e e] :: [%e acc]] | Optional (_, v_opt, k) -> (* We match simultaneously on the head and tail in the generated code to avoid changing their respective typing environments. *) [%expr match [%e v_opt], [%e acc] with | None, tl -> tl | Some v, tl -> [%e k [%expr v]] :: tl] | Omit_nil (_, e, k) -> [%expr match [%e e], [%e acc] with | Ppx_sexp_conv_lib.Sexp.List [], tl -> tl | v, tl -> [%e k [%expr v]] :: tl]) in let has_optional_values = List.exists l ~f:(function | (Optional _ | Omit_nil _ : omittable_sexp) -> true | Present _ | Absent -> false) in (* The two branches do the same thing, but when there are no optional values, we can do it at compile-time, which avoids making the generated code ugly. *) if has_optional_values then [%expr match [%e res] with | [ h ] -> h | ([] | _ :: _ :: _) as res -> [%e sexp_list ~loc [%expr res]]] else ( match res with | [%expr [ [%e? h] ]] -> h | _ -> sexp_list ~loc res) ;; let expand ~omit_nil ~path:_ e = let loc = e.pexp_loc in let labelled_exprs = match e.pexp_desc with | Pexp_apply (f, args) -> (Nolabel, f) :: args | _ -> [ Nolabel, e ] in sexp_of_labelled_exprs ~omit_nil ~loc labelled_exprs ;; let expand_opt ~omit_nil ~loc ~path = function | None -> let loc = { loc with loc_ghost = true } in sexp_list ~loc (elist ~loc []) | Some e -> expand ~omit_nil ~path e ;;
sectionYPositions = computeSectionYPositions($el), 10)"
x-init="setTimeout(() => sectionYPositions = computeSectionYPositions($el), 10)"
>