package ortac-wrapper
Wrapper plugin for Ortac
Install
Dune Dependency
Authors
Maintainers
Sources
0.7.0.tar.gz
md5=1429cb7ec517060772f97504d84ff789
sha512=498e1b40dd29f5feef3df5fa54f924c7b53f24726b1613a5d8dd7ef8ca16b8cf97a76b9fd2951f32143b59a67b8d80fe13b081890fca07787a5a5fda30102a97
doc/src/ortac-wrapper.plugin/generate.ml.html
Source file generate.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
module W = Ortac_core.Warnings open Ppxlib open Ortac_core.Builder open Ir module F = Failure module M = Map.Make (String) module Context = Ortac_core.Context let header = "(* This file is generated by ortac wrapper,\n\ \ edit the original interface file instead *)" let setup name loc register_name next = [%expr let [%p pvar register_name] = Ortac_runtime.Errors.create [%e elocation loc] [%e estring name] in [%e next]] let copies copies next = if copies = [] then next else let vars, exprs = List.split copies in let vars = List.map (fun v -> ppat_var (noloc v)) vars in [%expr let [%p ppat_tuple vars] = Ortac_runtime.copy [%e pexp_tuple exprs] in [%e next]] let term (t : Ir.term) next = match t.translation with Error _ -> next | Ok c -> pexp_sequence c next let terms terms next = List.fold_left (fun acc t -> term t acc) next terms let compute_check (c : Ir.check) next = match c.translations with | Error _ -> next | Ok ((x, e), _) -> pexp_let Nonrecursive [ value_binding ~pat:(pvar x) ~expr:e ] next let compute_checks checks next = List.fold_left (fun acc t -> compute_check t acc) next checks let check_positive (c : Ir.check) next = match c.translations with | Error _ -> next | Ok (_, p) -> pexp_sequence p next let checks ~register_name positive checks next = if positive then List.fold_left (fun acc t -> check_positive t acc) next checks else let all_checks = List.fold_left (fun acc c -> match c.translations with | Error _ -> acc | Ok ((x, _), _) -> eapply (evar "(&&)") [ acc; evar x ]) (ebool true) checks in [%expr if [%e all_checks] then [%e F.unexpected_checks ~register_name]; [%e next]] let invariants ~register_name pos instance (t : type_) next = List.fold_left (fun next (t : invariant) -> match t.translation with | Error _ -> next | Ok (name, _) -> pexp_sequence (eapply (evar name) [ register_name; evar pos; evar instance ]) next) next t.invariants let var_invariants ~register_name pos ignore_consumes (v : ocaml_var) next = if ignore_consumes && v.consumed then next else invariants ~register_name pos v.name v.type_ next let vars_invariants ~register_name pos ignore_consumes vl next = List.fold_left (fun acc t -> var_invariants ~register_name pos ignore_consumes t acc) next vl let group_xpost (v : Ir.value) = let register_name = evar v.register_name in let invariants = vars_invariants ~register_name "XPost" true v.arguments in let default_cases = [ case ~guard:None ~lhs:[%pat? (Stack_overflow | Out_of_memory) as e] ~rhs: [%expr [%e checks ~register_name true v.checks @@ invariants @@ F.report ~register_name]; raise e]; case ~guard:None ~lhs:[%pat? e] ~rhs: [%expr [%e F.unexpected_exn ~allowed_exn:[] ~exn:(evar "e") ~register_name]; [%e checks ~register_name true v.checks @@ invariants @@ F.report ~register_name]; raise e]; ] in let default_cases = let invalid_arg_case = case ~guard:None ~lhs:[%pat? Invalid_argument _ as e] ~rhs: [%expr [%e checks ~register_name false v.checks @@ invariants @@ F.report ~register_name]; raise e] in if v.checks = [] then default_cases else invalid_arg_case :: default_cases in let tbl = Hashtbl.create 0 in let rec aux keys = function | [] -> keys | { exn; args; translation = Ok translation } :: t -> Hashtbl.add tbl exn translation; aux (M.add exn args keys) t | _ :: t -> aux keys t in aux M.empty v.xpostconditions |> fun s -> M.fold (fun exn args acc -> let e = gen_symbol ~prefix:"__e_" () in let lhs = ppat_alias (ppat_construct (lident exn) (if args = 0 then None else Some ppat_any)) (noloc e) in let matches = Hashtbl.find_all tbl exn |> List.map (pexp_match (evar e)) |> esequence in let rhs = esequence [ matches; checks ~register_name true v.checks @@ invariants @@ F.report ~register_name; eapply (evar "raise") [ evar e ]; ] in case ~guard:None ~lhs ~rhs :: acc) s default_cases let args f = List.map (fun a -> (a.label, f a.name)) let rets (returns : ocaml_var list) = match returns with | [] -> (eunit, punit) | [ x ] -> (evar x.name, pvar x.name) | ret -> List.fold_right (fun (x : ocaml_var) (e, p) -> (evar x.name :: e, pvar x.name :: p)) ret ([], []) |> fun (e, p) -> (pexp_tuple e, ppat_tuple p) let projection (p : Ir.projection) = let register_name = evar p.register_name in let default_cases = [ case ~guard:None ~lhs:[%pat? (Stack_overflow | Out_of_memory) as e] ~rhs: [%expr [%e F.report ~register_name]; raise e]; case ~guard:None ~lhs:[%pat? e] ~rhs: [%expr [%e F.unexpected_exn ~allowed_exn:[] ~exn:(evar "e") ~register_name]; [%e F.report ~register_name]; raise e]; ] in let report = pexp_sequence (F.report ~register_name) in let eargs = args evar p.arguments in let pargs = args pvar p.arguments in let eret, pret = rets p.returns in let call = pexp_apply (evar p.ocaml_name) eargs in let try_call = pexp_try call default_cases in let body = setup p.name p.loc p.register_name @@ pexp_let Nonrecursive [ value_binding ~pat:pret ~expr:try_call ] @@ report @@ eret in [ [%stri let [%p pvar p.name] = [%e efun pargs body]] ] let value (v : Ir.value) = let register_name = evar v.register_name in let report = pexp_sequence (F.report ~register_name) in let eargs = args evar v.arguments in let pargs = args pvar v.arguments in let eret, pret = rets v.returns in let call = pexp_apply (evar v.name) eargs in let try_call = pexp_try call (group_xpost v) in let body = setup v.name v.loc v.register_name @@ copies v.copies @@ terms v.preconditions @@ vars_invariants ~register_name "Pre" false v.arguments @@ compute_checks v.checks @@ report @@ pexp_let Nonrecursive [ value_binding ~pat:pret ~expr:try_call ] @@ terms v.postconditions @@ checks ~register_name true v.checks @@ vars_invariants ~register_name "Post" true v.arguments @@ vars_invariants ~register_name "Post" false v.returns @@ report @@ eret in [ [%stri let [%p pvar v.name] = [%e efun pargs body]] ] let function_ (f : Ir.function_) = match f.definition with | Some { translation = Ok def; _ } -> let pat = pvar f.name in let pargs = args pvar f.arguments in let expr = efun pargs def in let rec_flag = if f.rec_ then Recursive else Nonrecursive in [ pstr_value rec_flag [ value_binding ~pat ~expr ] ] | _ -> [] let constant (c : Ir.constant) = let register_name = evar c.register_name in let report = pexp_sequence (F.report ~register_name) in let body = setup c.name c.loc c.register_name @@ terms c.checks @@ invariants ~register_name "Pre" c.name c.type_ @@ report @@ evar c.name in [ [%stri let [%p pvar c.name] = [%e body]] ] let type_ (t : Ir.type_) = List.filter_map (fun (i : invariant) -> Result.to_option i.translation |> Option.map snd) t.invariants let axiom (a : Ir.axiom) = let register_name = evar a.register_name in let report = pexp_sequence (F.report ~register_name) in let body = setup a.name a.loc a.register_name @@ term a.definition @@ report @@ eunit in [ [%stri let () = [%e body]] ] let reorder_structure_items items = let is_projection = function Projection _ -> true | _ -> false in let non_projections, projections = List.partition (fun item -> not (is_projection item)) items in non_projections @ projections let structure runtime module_name ir : Ppxlib.structure = let ir = { ir with structure = reorder_structure_items ir.structure } in (pmod_ident (lident module_name) |> include_infos |> pstr_include) :: pstr_module (module_binding ~name:{ txt = Some "Ortac_runtime"; loc } ~expr:(pmod_ident (lident runtime))) :: (Ir.map_translation ir ~f:(function | Ir.Value v -> value v | Ir.Projection p -> projection p | Ir.Function f -> function_ f | Ir.Predicate f -> function_ f | Ir.Constant c -> constant c | Ir.Type t -> type_ t | Ir.Axiom a -> axiom a) |> List.flatten) let signature ~runtime ~module_name namespace s = let open Ortac_core in let context = Context.init module_name namespace in let ir = Ir_of_gospel.signature ~context s in Report.emit_warnings Fmt.stderr ir; structure runtime (Context.module_name context) ir let generate path fmt = let module_name = Ortac_core.Utils.module_name_of_path path in Gospel.Parser_frontend.parse_ocaml_gospel path |> Ortac_core.Utils.type_check [] path |> fun (env, sigs) -> assert (List.length env = 1); signature ~runtime:"Ortac_runtime" ~module_name (List.hd env) sigs |> Fmt.pf fmt "%s%a@." header Ppxlib_ast.Pprintast.structure
sectionYPositions = computeSectionYPositions($el), 10)"
x-init="setTimeout(() => sectionYPositions = computeSectionYPositions($el), 10)"
>