Legend:
Page
Library
Module
Module type
Parameter
Class
Class type
Source
Page
Library
Module
Module type
Parameter
Class
Class type
Source
lambda_normalization.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
(* This file is part of asak. * * Copyright (C) 2019 IRIF / OCaml Software Foundation. * * asak is distributed under the terms of the MIT license. See the * included LICENSE file for details. *) open Lambda let map_snd aux = List.map (fun (e,x) -> e, aux x) let map_opt aux = function | None -> None | Some x -> Some (aux x) let fold_lambda lvar llet = let rec aux expr = match expr with | Lvar x -> lvar x | Lconst _ -> expr | Llet (k,e,ident,l,r) -> llet aux k e ident l r | Lapply x -> let ap_func = aux x.ap_func in let ap_args = List.map aux x.ap_args in Lapply { x with ap_func; ap_args } | Lfunction { kind; params; return; body; attr; loc } -> let body = aux body in #if OCAML_VERSION >= (4, 14, 0) lfunction ~kind ~params ~return ~body ~attr ~loc #else Lfunction { kind; params; return; body; attr; loc } #endif | Lletrec (lst,l) -> Lletrec (map_snd aux lst, aux l) | Lprim (a,lst,b) -> Lprim (a,List.map aux lst, b) | Lstaticraise (a,lst) -> Lstaticraise (a,List.map aux lst) | Lifthenelse (i,f,e) -> Lifthenelse (aux i, aux f, aux e) | Lsequence (l,r) -> Lsequence (aux l, aux r) | Lwhile (l,r) -> Lwhile (aux l, aux r) | Lifused (i,l) -> Lifused (i, aux l) #if OCAML_VERSION >= (4, 06, 0) | Lswitch (l,s,i) -> let sw_consts = map_snd aux s.sw_consts in let sw_blocks = map_snd aux s.sw_blocks in Lswitch (aux l, {s with sw_consts; sw_blocks}, i) #else | Lswitch (l,s) -> let sw_consts = map_snd aux s.sw_consts in let sw_blocks = map_snd aux s.sw_blocks in Lswitch (aux l, {s with sw_consts; sw_blocks}) #endif | Lstringswitch (l,lst,opt,e) -> Lstringswitch (aux l, map_snd aux lst, map_opt aux opt, e) | Lassign (i,l) -> Lassign (i, aux l) | Levent (l,e) -> Levent (aux l, e) | Lstaticcatch (l,lst,r) -> Lstaticcatch (aux l, lst, aux r) | Ltrywith (l,i,r) -> Ltrywith (aux l, i, aux r) | Lfor (e,a,b,d,c) -> Lfor (e, aux a, aux b, d, aux c) | Lsend (a,b,c,d,e) -> Lsend (a, aux b, aux c, List.map aux d, e) #if OCAML_VERSION >= (4, 13, 0) | Lmutvar x -> lvar x | Lmutlet (e,ident,l,r) -> llet aux Strict e ident l r #endif in aux (* Replace every occurence of ident by its body *) let replace ident body = let lvar x = if x = ident then body else Lvar x in let llet aux a b c d e = Llet (a,b,c,aux d,aux e) in fold_lambda lvar llet (* Is the definition inlineable ? *) let inlineable x f = match x with | Alias -> true | Strict -> begin match f with | Lvar _ | Lconst _ -> true | _ -> false end | _ -> false (* Inline all possible "let definitions" (that is, all "let definitions" without a side effet) *) let inline_all = let lvar x = Lvar x in let llet aux k e ident l r = if inlineable k l then aux (replace ident l r) else Llet (k, e, ident, aux l, aux r) in fold_lambda lvar llet let extract_params_name xs = #if OCAML_VERSION >= (4, 08, 0) List.map fst xs #else xs #endif let create_ident x = #if OCAML_VERSION >= (4, 08, 0) Ident.create_local x #else Ident.create x #endif let normalize_local_variables ?name x = (* i for nonrec (from 1 to infinity), j for rec (from -1 to -infinity)*) let rec aux i j letbinds x = let aux' = aux i j letbinds in let lvar var = match List.assoc_opt var letbinds with | None -> x | Some x -> Lvar (create_ident (string_of_int x)) in match x with | Lvar var -> lvar var | Lconst _ -> x | Lapply x -> Lapply {x with ap_func=aux' x.ap_func; ap_args=List.map aux' x.ap_args} | Lfunction { kind; params; return; body; attr; loc } -> let params' = extract_params_name params in let (i,letbinds) = List.fold_right (fun id (i,acc) -> (i+1, (id,i)::acc)) params' (i,letbinds) in let body = aux i j letbinds body in #if OCAML_VERSION >= (4, 14, 0) lfunction ~kind ~params ~return ~body ~attr ~loc #else Lfunction { kind; params; return; body; attr; loc } #endif | Llet (a,b,id,l,r) -> Llet (a,b,id,aux' l, aux (i+1) j ((id,i)::letbinds) r) | Lletrec (lst,l) -> let (j,letbinds) = List.fold_right (fun (id,_) (j,acc) -> (j-1),(id,j)::acc) lst (j,letbinds) in Lletrec (List.map (fun (t,x) -> t,aux i j letbinds x) lst, aux i j letbinds l) | Lprim (a,b,c) -> Lprim (a, List.map aux' b,c) | Lstaticraise (a,b) -> Lstaticraise (a,List.map aux' b) | Lifthenelse (i,f,e) -> Lifthenelse (aux' i, aux' f, aux' e) | Lsequence (l,r) -> Lsequence (aux' l, aux' r) | Lwhile (l,r) -> Lwhile (aux' l, aux' r) | Lifused (a,b) -> Lifused (a, aux' b) #if OCAML_VERSION >= (4, 06, 0) | Lswitch (l,s,u) -> let s = {s with sw_consts = map_snd aux' s.sw_consts; sw_blocks = map_snd aux' s.sw_blocks} in Lswitch (aux' l, s, u) #else | Lswitch (l,s) -> let s = {s with sw_consts = map_snd aux' s.sw_consts; sw_blocks = map_snd aux' s.sw_blocks} in Lswitch (aux' l, s) #endif | Lstringswitch (l,lst,opt,loc) -> Lstringswitch (aux' l, map_snd aux' lst, map_opt aux' opt, loc) | Lassign (a,b) -> Lassign (a, aux' b) | Levent (a,b) -> Levent (aux' a, b) | Lstaticcatch (a,b,c) -> Lstaticcatch (aux' a, b, aux' c) | Ltrywith (l,id,r) -> Ltrywith (aux' l, id, aux (i+1) j ((id,i)::letbinds) r) | Lfor (id,a,b,d,c) -> Lfor (id,aux' a, aux' b, d, aux (i+1) j ((id,i)::letbinds) c) | Lsend (a,b,c,d,e) -> Lsend (a, aux' b, aux' c, List.map aux' d, e) #if OCAML_VERSION >= (4, 13, 0) | Lmutvar var -> lvar var | Lmutlet (b,id,l,r) -> Lmutlet (b,id,aux' l, aux (i+1) j ((id,i)::letbinds) r) #endif in let start = match name with | None -> [] | Some name -> [name,0] in aux 1 (-1) start x