My working unpac repository
at opam/upstream/seq 1342 lines 53 kB view raw
1(**************************************************************************) 2(* *) 3(* OCaml *) 4(* *) 5(* Xavier Leroy, projet Cristal, INRIA Rocquencourt *) 6(* *) 7(* Copyright 1996 Institut National de Recherche en Informatique et *) 8(* en Automatique. *) 9(* *) 10(* All rights reserved. This file is distributed under the terms of *) 11(* the GNU Lesser General Public License version 2.1, with the *) 12(* special exception on linking described in the file LICENSE. *) 13(* *) 14(**************************************************************************) 15 16(* Translation from typed abstract syntax to lambda terms, 17 for the core language *) 18 19open Misc 20open Asttypes 21open Primitive 22open Types 23open Data_types 24open Typedtree 25open Typeopt 26open Lambda 27open Debuginfo.Scoped_location 28 29type error = 30 Free_super_var 31 | Unreachable_reached 32 33exception Error of Location.t * error 34 35let use_dup_for_constant_mutable_arrays_bigger_than = 4 36 37(* Forward declaration -- to be filled in by Translmod.transl_module *) 38let transl_module = 39 ref((fun ~scopes:_ _cc _rootpath _modl -> assert false) : 40 scopes:scopes -> module_coercion -> Path.t option -> 41 module_expr -> lambda) 42 43let transl_struct_item = 44 ref ((fun ~scopes:_ _fields _rootpath _stri _next -> assert false) : 45 scopes:scopes -> Ident.t list -> Path.t option -> 46 structure_item -> (Ident.t list -> lambda) -> lambda) 47 48let transl_object = 49 ref (fun ~scopes:_ _id _s _cl -> assert false : 50 scopes:scopes -> Ident.t -> string list -> class_expr -> lambda) 51 52(* Compile an exception/extension definition *) 53 54let prim_fresh_oo_id = 55 Pccall (Primitive.simple ~name:"caml_fresh_oo_id" ~arity:1 ~alloc:false) 56 57let transl_extension_constructor ~scopes env path ext = 58 let path = 59 Printtyp.wrap_printing_env env ~error:true (fun () -> 60 Option.map (Out_type.rewrite_double_underscore_paths env) path) 61 in 62 let name = 63 match path, !Clflags.for_package with 64 None, _ -> Ident.name ext.ext_id 65 | Some p, None -> Path.name p 66 | Some p, Some pack -> Printf.sprintf "%s.%s" pack (Path.name p) 67 in 68 let loc = of_location ~scopes ext.ext_loc in 69 match ext.ext_kind with 70 Text_decl _ -> 71 Lprim (Pmakeblock (Obj.object_tag, Immutable, None), 72 [Lconst (Const_immstring name); 73 Lprim (prim_fresh_oo_id, [Lconst (const_int 0)], loc)], 74 loc) 75 | Text_rebind(path, _lid) -> 76 transl_extension_path loc env path 77 78(* To propagate structured constants *) 79 80exception Not_constant 81 82let extract_constant = function 83 Lconst sc -> sc 84 | _ -> raise Not_constant 85 86let extract_float = function 87 Const_float f -> f 88 | _ -> fatal_error "Translcore.extract_float" 89 90(* Insertion of debugging events *) 91 92let event_before ~scopes exp lam = 93 Translprim.event_before (of_location ~scopes exp.exp_loc) exp lam 94 95let event_after ~scopes exp lam = 96 Translprim.event_after (of_location ~scopes exp.exp_loc) exp lam 97 98let event_function ~scopes exp lam = 99 if !Clflags.debug && not !Clflags.native_code then 100 let repr = Some (ref 0) in 101 let (info, body) = lam repr in 102 (info, 103 Levent(body, {lev_loc = of_location ~scopes exp.exp_loc; 104 lev_kind = Lev_function; 105 lev_repr = repr; 106 lev_env = exp.exp_env})) 107 else 108 lam None 109 110(* Assertions *) 111 112let assert_failed loc ~scopes exp = 113 let slot = 114 transl_extension_path Loc_unknown 115 Env.initial Predef.path_assert_failure 116 in 117 let (fname, line, char) = 118 Location.get_pos_info loc.Location.loc_start 119 in 120 let loc = of_location ~scopes exp.exp_loc in 121 Lprim(Praise Raise_regular, [event_after ~scopes exp 122 (Lprim(Pmakeblock(0, Immutable, None), 123 [slot; 124 Lconst(Const_block(0, 125 [Const_immstring fname; 126 Const_int line; 127 Const_int char]))], loc))], loc) 128 129(* In cases where we're careful to preserve syntactic arity, we disable 130 the arity fusion attempted by simplif.ml *) 131let function_attribute_disallowing_arity_fusion = 132 { default_function_attribute with may_fuse_arity = false } 133 134let rec cut n l = 135 if n = 0 then ([],l) else 136 match l with [] -> failwith "Translcore.cut" 137 | a::l -> let (l1,l2) = cut (n-1) l in (a::l1,l2) 138 139(* [fuse_method_arity] is what ensures that a n-ary method is compiled as a 140 (n+1)-ary function, where the first parameter is self. It fuses together the 141 self and method parameters. 142 143 Input: fun self -> fun method_param_1 ... method_param_n -> body 144 Output: fun self method_param_1 ... method_param_n -> body 145 146 It detects whether the AST is a method by the presence of [Texp_poly] on the 147 inner function. This is only ever added to methods. 148*) 149let fuse_method_arity parent_params parent_body = 150 match parent_body with 151 | Tfunction_body 152 { exp_desc = Texp_function (method_params, method_body); 153 exp_extra; 154 } 155 when 156 List.exists 157 (function (Texp_poly _, _, _) -> true | _ -> false) 158 exp_extra 159 -> parent_params @ method_params, method_body 160 | _ -> parent_params, parent_body 161 162(* Translation of expressions *) 163 164let rec iter_exn_names f pat = 165 match pat.pat_desc with 166 | Tpat_var (id, _, _) -> f id 167 | Tpat_alias (p, id, _, _, _) -> 168 f id; 169 iter_exn_names f p 170 | _ -> () 171 172let transl_ident loc env ty path desc = 173 match desc.val_kind with 174 | Val_prim p -> 175 Translprim.transl_primitive loc p env ty (Some path) 176 | Val_anc _ -> 177 raise(Error(to_location loc, Free_super_var)) 178 | Val_reg | Val_self _ -> 179 transl_value_path loc env path 180 | _ -> fatal_error "Translcore.transl_exp: bad Texp_ident" 181 182let is_omitted = function 183 | Arg _ -> false 184 | Omitted () -> true 185 186let rec transl_exp ~scopes e = 187 transl_exp1 ~scopes ~in_new_scope:false e 188 189(* ~in_new_scope tracks whether we just opened a new scope. 190 191 When we just opened a new scope, we avoid introducing an extraneous anonymous 192 function scope and instead inherit the new scope. E.g., [let f x = ...] is 193 parsed as a let-bound Pexp_function node [let f = fun x -> ...]. 194 We give it f's scope. 195*) 196and transl_exp1 ~scopes ~in_new_scope e = 197 let eval_once = 198 (* Whether classes for immediate objects must be cached *) 199 match e.exp_desc with 200 Texp_function _ | Texp_for _ | Texp_while _ -> false 201 | _ -> true 202 in 203 if eval_once then transl_exp0 ~scopes ~in_new_scope e else 204 Translobj.oo_wrap e.exp_env true (transl_exp0 ~scopes ~in_new_scope) e 205 206and transl_exp0 ~in_new_scope ~scopes e = 207 match e.exp_desc with 208 | Texp_ident(path, _, desc) -> 209 transl_ident (of_location ~scopes e.exp_loc) 210 e.exp_env e.exp_type path desc 211 | Texp_constant cst -> 212 Lambda.lambda_of_const cst 213 | Texp_let(rec_flag, pat_expr_list, body) -> 214 transl_let ~scopes rec_flag pat_expr_list 215 (event_before ~scopes body (transl_exp ~scopes body)) 216 | Texp_function (params, body) -> 217 let scopes = 218 if in_new_scope then scopes 219 else enter_anonymous_function ~scopes 220 in 221 transl_function ~scopes e params body 222 | Texp_apply({ exp_desc = Texp_ident(path, _, {val_kind = Val_prim p}); 223 exp_type = prim_type } as funct, oargs) 224 when List.length oargs >= p.prim_arity 225 && List.for_all (fun (_, arg) -> not (is_omitted arg)) oargs -> 226 let argl, extra_args = cut p.prim_arity oargs in 227 let arg_exps = 228 List.map (function _, Arg x -> x | _, Omitted () -> assert false) argl 229 in 230 let args = transl_list ~scopes arg_exps in 231 let prim_exp = if extra_args = [] then Some e else None in 232 let lam = 233 Translprim.transl_primitive_application 234 (of_location ~scopes e.exp_loc) p e.exp_env prim_type path 235 prim_exp args arg_exps 236 in 237 if extra_args = [] then lam 238 else begin 239 let tailcall = Translattribute.get_tailcall_attribute funct in 240 let inlined = Translattribute.get_inlined_attribute funct in 241 let specialised = Translattribute.get_specialised_attribute funct in 242 let e = { e with exp_desc = Texp_apply(funct, oargs) } in 243 event_after ~scopes e 244 (transl_apply ~scopes ~tailcall ~inlined ~specialised 245 lam extra_args (of_location ~scopes e.exp_loc)) 246 end 247 | Texp_apply(funct, oargs) -> 248 let tailcall = Translattribute.get_tailcall_attribute funct in 249 let inlined = Translattribute.get_inlined_attribute funct in 250 let specialised = Translattribute.get_specialised_attribute funct in 251 let e = { e with exp_desc = Texp_apply(funct, oargs) } in 252 event_after ~scopes e 253 (transl_apply ~scopes ~tailcall ~inlined ~specialised 254 (transl_exp ~scopes funct) oargs (of_location ~scopes e.exp_loc)) 255 | Texp_match(arg, pat_expr_list, [], partial) -> 256 transl_match ~scopes e arg pat_expr_list partial 257 | Texp_match(arg, pat_expr_list, eff_pat_expr_list, partial) -> 258 (* need to separate the values from exceptions for transl_handler *) 259 let split_case (val_cases, exn_cases as acc) 260 ({ c_lhs; c_rhs } as case) = 261 if c_rhs.exp_desc = Texp_unreachable then acc else 262 let val_pat, exn_pat = split_pattern c_lhs in 263 match val_pat, exn_pat with 264 | None, None -> assert false 265 | Some pv, None -> 266 { case with c_lhs = pv } :: val_cases, exn_cases 267 | None, Some pe -> 268 val_cases, { case with c_lhs = pe } :: exn_cases 269 | Some pv, Some pe -> 270 { case with c_lhs = pv } :: val_cases, 271 { case with c_lhs = pe } :: exn_cases 272 in 273 let pat_expr_list, exn_pat_expr_list = 274 let x, y = List.fold_left split_case ([], []) pat_expr_list in 275 List.rev x, List.rev y 276 in 277 transl_handler ~scopes e arg (Some (pat_expr_list, partial)) 278 exn_pat_expr_list eff_pat_expr_list 279 | Texp_try(body, pat_expr_list, []) -> 280 let id = Typecore.name_cases "exn" pat_expr_list in 281 Ltrywith(transl_exp ~scopes body, id, 282 Matching.for_trywith ~scopes e.exp_loc (Lvar id) 283 (transl_cases_try ~scopes pat_expr_list)) 284 | Texp_try(body, exn_pat_expr_list, eff_pat_expr_list) -> 285 transl_handler ~scopes e body None exn_pat_expr_list eff_pat_expr_list 286 | Texp_tuple el -> 287 let ll, shape = transl_list_with_shape ~scopes (List.map snd el) in 288 begin try 289 Lconst(Const_block(0, List.map extract_constant ll)) 290 with Not_constant -> 291 Lprim(Pmakeblock(0, Immutable, Some shape), ll, 292 (of_location ~scopes e.exp_loc)) 293 end 294 | Texp_construct(_, cstr, args) -> 295 let ll, shape = transl_list_with_shape ~scopes args in 296 if cstr.cstr_inlined <> None then begin match ll with 297 | [x] -> x 298 | _ -> assert false 299 end else begin match cstr.cstr_tag with 300 Cstr_constant n -> 301 Lconst(const_int n) 302 | Cstr_unboxed -> 303 (match ll with [v] -> v | _ -> assert false) 304 | Cstr_block n -> 305 begin try 306 Lconst(Const_block(n, List.map extract_constant ll)) 307 with Not_constant -> 308 Lprim(Pmakeblock(n, Immutable, Some shape), ll, 309 of_location ~scopes e.exp_loc) 310 end 311 | Cstr_extension(path, is_const) -> 312 let lam = transl_extension_path 313 (of_location ~scopes e.exp_loc) e.exp_env path in 314 if is_const then lam 315 else 316 Lprim(Pmakeblock(0, Immutable, Some (Pgenval :: shape)), 317 lam :: ll, of_location ~scopes e.exp_loc) 318 end 319 | Texp_extension_constructor (_, path) -> 320 transl_extension_path (of_location ~scopes e.exp_loc) e.exp_env path 321 | Texp_variant(l, arg) -> 322 let tag = Btype.hash_variant l in 323 begin match arg with 324 None -> Lconst(const_int tag) 325 | Some arg -> 326 let lam = transl_exp ~scopes arg in 327 try 328 Lconst(Const_block(0, [const_int tag; 329 extract_constant lam])) 330 with Not_constant -> 331 Lprim(Pmakeblock(0, Immutable, None), 332 [Lconst(const_int tag); lam], 333 of_location ~scopes e.exp_loc) 334 end 335 | Texp_record {fields; representation; extended_expression} -> 336 transl_record ~scopes e.exp_loc e.exp_env 337 fields representation extended_expression 338 | Texp_atomic_loc (arg, _, lbl) -> 339 let shape = Some [Typeopt.value_kind arg.exp_env arg.exp_type; Pintval] in 340 let (arg, lbl) = transl_atomic_loc ~scopes arg lbl in 341 let loc = of_location ~scopes e.exp_loc in 342 Lprim (Pmakeblock (0, Immutable, shape), [arg; lbl], loc) 343 | Texp_field (arg, _, ({ lbl_atomic = Atomic; _ } as lbl)) -> 344 let arg, lbl = transl_atomic_loc ~scopes arg lbl in 345 let loc = of_location ~scopes e.exp_loc in 346 Lprim (Patomic_load, [arg; lbl], loc) 347 | Texp_field (arg, _, lbl) -> 348 let targ = transl_exp ~scopes arg in 349 begin match lbl.lbl_repres with 350 Record_regular | Record_inlined _ -> 351 Lprim (Pfield (lbl.lbl_pos, maybe_pointer e, lbl.lbl_mut), [targ], 352 of_location ~scopes e.exp_loc) 353 | Record_unboxed _ -> targ 354 | Record_float -> 355 Lprim (Pfloatfield lbl.lbl_pos, [targ], 356 of_location ~scopes e.exp_loc) 357 | Record_extension _ -> 358 Lprim (Pfield (lbl.lbl_pos + 1, maybe_pointer e, lbl.lbl_mut), [targ], 359 of_location ~scopes e.exp_loc) 360 end 361 | Texp_setfield (arg, _, ({ lbl_atomic = Atomic; _ } as lbl), newval) -> 362 let prim = 363 Primitive.simple 364 ~name:"caml_atomic_exchange_field" ~arity:3 ~alloc:false 365 in 366 let arg, lbl = transl_atomic_loc ~scopes arg lbl in 367 let newval = transl_exp ~scopes newval in 368 let loc = of_location ~scopes e.exp_loc in 369 Lprim ( 370 Pignore, 371 [Lprim (Pccall prim, [arg; lbl; newval], loc)], 372 loc 373 ) 374 | Texp_setfield(arg, _, lbl, newval) -> 375 let access = 376 match lbl.lbl_repres with 377 Record_regular 378 | Record_inlined _ -> 379 Psetfield(lbl.lbl_pos, maybe_pointer newval, Assignment) 380 | Record_unboxed _ -> assert false 381 | Record_float -> Psetfloatfield (lbl.lbl_pos, Assignment) 382 | Record_extension _ -> 383 Psetfield (lbl.lbl_pos + 1, maybe_pointer newval, Assignment) 384 in 385 Lprim(access, [transl_exp ~scopes arg; transl_exp ~scopes newval], 386 of_location ~scopes e.exp_loc) 387 | Texp_array (amut, expr_list) -> 388 let kind = array_kind e in 389 let ll = transl_list ~scopes expr_list in 390 let loc = of_location ~scopes e.exp_loc in 391 let makearray mutability = 392 Lprim (Pmakearray (kind, mutability), ll, loc) 393 in 394 let duparray_to_mutable array = 395 Lprim (Pduparray (kind, Mutable), [array], loc) 396 in 397 let imm_array = makearray Immutable in 398 begin try 399 (* For native code the decision as to which compilation strategy to 400 use is made later. This enables the Flambda passes to lift certain 401 kinds of array definitions to symbols. *) 402 (* Deactivate constant optimization if array is small enough *) 403 if amut = Asttypes.Mutable && 404 List.length ll <= use_dup_for_constant_mutable_arrays_bigger_than 405 then begin 406 raise Not_constant 407 end; 408 begin match List.map extract_constant ll with 409 | exception Not_constant 410 when kind = Pfloatarray && amut = Asttypes.Mutable -> 411 (* We cannot currently lift mutable [Pintarray] arrays safely in 412 Flambda because [caml_modify] might be called upon them 413 (e.g. from code operating on polymorphic arrays, or functions 414 such as [caml_array_blit]. 415 To avoid having different Lambda code for bytecode/Closure 416 vs. Flambda, we always generate [Pduparray] for mutable arrays 417 here, and deal with it in [Bytegen] (or in the case of Closure, 418 in [Cmmgen], which already has to handle [Pduparray Pmakearray 419 Pfloatarray] in the case where the array turned out to be 420 inconstant). 421 When not [Pfloatarray], the exception propagates to the handler 422 below. *) 423 duparray_to_mutable imm_array 424 | cl -> 425 let const = 426 match kind with 427 | Paddrarray | Pintarray -> 428 Lconst(Const_block(0, cl)) 429 | Pfloatarray -> 430 Lconst(Const_float_array(List.map extract_float cl)) 431 | Pgenarray -> 432 raise Not_constant (* can this really happen? *) 433 in 434 match amut with 435 | Mutable -> duparray_to_mutable const 436 | Immutable -> const 437 end 438 with Not_constant -> 439 makearray amut 440 end 441 | Texp_ifthenelse(cond, ifso, Some ifnot) -> 442 Lifthenelse(transl_exp ~scopes cond, 443 event_before ~scopes ifso (transl_exp ~scopes ifso), 444 event_before ~scopes ifnot (transl_exp ~scopes ifnot)) 445 | Texp_ifthenelse(cond, ifso, None) -> 446 Lifthenelse(transl_exp ~scopes cond, 447 event_before ~scopes ifso (transl_exp ~scopes ifso), 448 lambda_unit) 449 | Texp_sequence(expr1, expr2) -> 450 Lsequence(transl_exp ~scopes expr1, 451 event_before ~scopes expr2 (transl_exp ~scopes expr2)) 452 | Texp_while(cond, body) -> 453 Lwhile(transl_exp ~scopes cond, 454 event_before ~scopes body (transl_exp ~scopes body)) 455 | Texp_for(param, _, low, high, dir, body) -> 456 Lfor(param, transl_exp ~scopes low, transl_exp ~scopes high, dir, 457 event_before ~scopes body (transl_exp ~scopes body)) 458 | Texp_send(expr, met) -> 459 let lam = 460 let loc = of_location ~scopes e.exp_loc in 461 match met with 462 | Tmeth_val id -> 463 let obj = transl_exp ~scopes expr in 464 Lsend (Self, Lvar id, obj, [], loc) 465 | Tmeth_name nm -> 466 let obj = transl_exp ~scopes expr in 467 let (tag, cache) = Translobj.meth obj nm in 468 let kind = if cache = [] then Public else Cached in 469 Lsend (kind, tag, obj, cache, loc) 470 | Tmeth_ancestor(meth, path_self) -> 471 let self = transl_value_path loc e.exp_env path_self in 472 Lapply {ap_loc = loc; 473 ap_func = Lvar meth; 474 ap_args = [self]; 475 ap_tailcall = Default_tailcall; 476 ap_inlined = Default_inline; 477 ap_specialised = Default_specialise} 478 in 479 event_after ~scopes e lam 480 | Texp_new (cl, {Location.loc=loc}, _) -> 481 let loc = of_location ~scopes loc in 482 Lapply{ 483 ap_loc=loc; 484 ap_func= 485 Lprim(Pfield (0, Pointer, Mutable), 486 [transl_class_path loc e.exp_env cl], loc); 487 ap_args=[lambda_unit]; 488 ap_tailcall=Default_tailcall; 489 ap_inlined=Default_inline; 490 ap_specialised=Default_specialise; 491 } 492 | Texp_instvar(path_self, path, _) -> 493 let loc = of_location ~scopes e.exp_loc in 494 let self = transl_value_path loc e.exp_env path_self in 495 let var = transl_value_path loc e.exp_env path in 496 Lprim(Pfield_computed, [self; var], loc) 497 | Texp_setinstvar(path_self, path, _, expr) -> 498 let loc = of_location ~scopes e.exp_loc in 499 let self = transl_value_path loc e.exp_env path_self in 500 let var = transl_value_path loc e.exp_env path in 501 transl_setinstvar ~scopes loc self var expr 502 | Texp_override(path_self, modifs) -> 503 let loc = of_location ~scopes e.exp_loc in 504 let self = transl_value_path loc e.exp_env path_self in 505 let cpy = Ident.create_local "copy" in 506 Llet(Strict, Pgenval, cpy, 507 Lapply{ 508 ap_loc=Loc_unknown; 509 ap_func=Translobj.oo_prim "copy"; 510 ap_args=[self]; 511 ap_tailcall=Default_tailcall; 512 ap_inlined=Default_inline; 513 ap_specialised=Default_specialise; 514 }, 515 List.fold_right 516 (fun (id, _, expr) rem -> 517 Lsequence(transl_setinstvar ~scopes Loc_unknown 518 (Lvar cpy) (Lvar id) expr, rem)) 519 modifs 520 (Lvar cpy)) 521 | Texp_pack modl -> 522 !transl_module ~scopes Tcoerce_none None modl 523 | Texp_assert ({exp_desc=Texp_construct(_, {cstr_name="false"}, _)}, loc) -> 524 assert_failed loc ~scopes e 525 | Texp_assert (cond, loc) -> 526 if !Clflags.noassert 527 then lambda_unit 528 else Lifthenelse (transl_exp ~scopes cond, lambda_unit, 529 assert_failed loc ~scopes e) 530 | Texp_lazy e -> 531 (* when e needs no computation (constants, identifiers, ...), we 532 optimize the translation just as Lazy.lazy_from_val would 533 do *) 534 begin match Typeopt.classify_lazy_argument e with 535 | `Constant_or_function -> 536 (* A constant expr (of type <> float if [Config.flat_float_array] is 537 true) gets compiled as itself. *) 538 transl_exp ~scopes e 539 | `Float_that_cannot_be_shortcut 540 | `Identifier `Forward_value -> 541 Lprim (Pmakelazyblock Forward_tag, 542 [transl_exp ~scopes e], 543 of_location ~scopes e.exp_loc) 544 | `Identifier `Other -> 545 transl_exp ~scopes e 546 | `Other -> 547 (* other cases compile to a lazy block holding a function *) 548 let fn = lfunction ~kind:Curried 549 ~params:[Ident.create_local "param", Pgenval] 550 ~return:Pgenval 551 (* The translation of [e] may be a function, in 552 which case disallowing arity fusion gives a very 553 small performance improvement. 554 *) 555 ~attr:function_attribute_disallowing_arity_fusion 556 ~loc:(of_location ~scopes e.exp_loc) 557 ~body:(transl_exp ~scopes e) in 558 Lprim(Pmakelazyblock Lazy_tag, [fn], 559 of_location ~scopes e.exp_loc) 560 end 561 | Texp_object (cs, meths) -> 562 let cty = cs.cstr_type in 563 let cl = Ident.create_local "object" in 564 !transl_object ~scopes cl meths 565 { cl_desc = Tcl_structure cs; 566 cl_loc = e.exp_loc; 567 cl_type = Cty_signature cty; 568 cl_env = e.exp_env; 569 cl_attributes = []; 570 } 571 | Texp_letop{let_; ands; param; body; partial} -> 572 event_after ~scopes e 573 (transl_letop ~scopes e.exp_loc e.exp_env let_ ands param body partial) 574 | Texp_unreachable -> 575 raise (Error (e.exp_loc, Unreachable_reached)) 576 | Texp_struct_item (si, e) -> 577 !transl_struct_item ~scopes [] None si (fun _ -> transl_exp ~scopes e) 578 579and pure_module m = 580 match m.mod_desc with 581 Tmod_ident _ -> Alias 582 | Tmod_constraint (m,_,_,_) -> pure_module m 583 | _ -> Strict 584 585and transl_list ~scopes expr_list = 586 List.map (transl_exp ~scopes) expr_list 587 588and transl_list_with_shape ~scopes expr_list = 589 let transl_with_shape e = 590 let shape = Typeopt.value_kind e.exp_env e.exp_type in 591 transl_exp ~scopes e, shape 592 in 593 List.split (List.map transl_with_shape expr_list) 594 595and transl_guard ~scopes guard rhs = 596 let expr = event_before ~scopes rhs (transl_exp ~scopes rhs) in 597 match guard with 598 | None -> expr 599 | Some cond -> 600 event_before ~scopes cond 601 (Lifthenelse(transl_exp ~scopes cond, expr, staticfail)) 602 603and transl_cont cont c_cont body = 604 match cont, c_cont with 605 | Some id1, Some id2 -> Llet(Alias, Pgenval, id2, Lvar id1, body) 606 | None, None 607 | Some _, None -> body 608 | None, Some _ -> assert false 609 610and transl_case ~scopes ?cont {c_lhs; c_cont; c_guard; c_rhs} = 611 (c_lhs, transl_cont cont c_cont (transl_guard ~scopes c_guard c_rhs)) 612 613and transl_cases ~scopes ?cont cases = 614 let cases = 615 List.filter (fun c -> c.c_rhs.exp_desc <> Texp_unreachable) cases in 616 List.map (transl_case ~scopes ?cont) cases 617 618and transl_case_try ~scopes {c_lhs; c_guard; c_rhs} = 619 iter_exn_names Translprim.add_exception_ident c_lhs; 620 Misc.try_finally 621 (fun () -> c_lhs, transl_guard ~scopes c_guard c_rhs) 622 ~always:(fun () -> 623 iter_exn_names Translprim.remove_exception_ident c_lhs) 624 625and transl_cases_try ~scopes cases = 626 let cases = 627 List.filter (fun c -> c.c_rhs.exp_desc <> Texp_unreachable) cases in 628 List.map (transl_case_try ~scopes) cases 629 630and transl_tupled_cases ~scopes patl_expr_list = 631 let patl_expr_list = 632 List.filter (fun (_,_,e) -> e.exp_desc <> Texp_unreachable) 633 patl_expr_list in 634 List.map (fun (patl, guard, expr) -> (patl, transl_guard ~scopes guard expr)) 635 patl_expr_list 636 637and transl_apply ~scopes 638 ?(tailcall=Default_tailcall) 639 ?(inlined = Default_inline) 640 ?(specialised = Default_specialise) 641 lam sargs loc 642 = 643 let lapply funct args = 644 match funct with 645 Lsend(k, lmet, lobj, largs, _) -> 646 Lsend(k, lmet, lobj, largs @ args, loc) 647 | Levent(Lsend(k, lmet, lobj, largs, _), _) -> 648 Lsend(k, lmet, lobj, largs @ args, loc) 649 | Lapply ap -> 650 Lapply {ap with ap_args = ap.ap_args @ args; ap_loc = loc} 651 | lexp -> 652 Lapply { 653 ap_loc=loc; 654 ap_func=lexp; 655 ap_args=args; 656 ap_tailcall=tailcall; 657 ap_inlined=inlined; 658 ap_specialised=specialised; 659 } 660 in 661 (* Build a function application. 662 Particular care is required for out-of-order partial applications. 663 The following code guarantees that: 664 * arguments are evaluated right-to-left according to their order in 665 the type of the function, before the function is called; 666 * side-effects occurring after receiving a non-optional parameter 667 will occur exactly when all the arguments up to this parameter 668 have been received; 669 * side-effects occurring after receiving an optional parameter 670 will occur at the latest when all the arguments up to the first 671 non-optional parameter that follows it have been received. 672 *) 673 let rec build_apply lam args = function 674 (Omitted (), optional) :: l -> 675 (* Out-of-order partial application; we will need to build a closure *) 676 let defs = ref [] in 677 let protect name lam = 678 match lam with 679 Lvar _ | Lconst _ -> lam 680 | _ -> 681 let id = Ident.create_local name in 682 defs := (id, lam) :: !defs; 683 Lvar id 684 in 685 (* If all arguments in [args] were optional, delay their application 686 until after this one is received *) 687 let args, args' = 688 if List.for_all (fun (_,opt) -> opt) args then [], args 689 else args, [] 690 in 691 let lam = 692 if args = [] then lam else lapply lam (List.rev_map fst args) 693 in 694 (* Evaluate the function, applied to the arguments in [args] *) 695 let handle = protect "func" lam in 696 (* Evaluate the arguments whose applications was delayed; 697 if we already passed here this is a no-op. *) 698 let args' = 699 List.map (fun (arg, opt) -> protect "arg" arg, opt) args' 700 in 701 (* Evaluate the remaining arguments; 702 if we already passed here this is a no-op. *) 703 let l = 704 List.map 705 (fun (arg, opt) -> Typedtree.map_apply_arg (protect "arg") arg, opt) 706 l 707 in 708 let id_arg = Ident.create_local "param" in 709 (* Process remaining arguments and build closure *) 710 let body = 711 match build_apply handle ((Lvar id_arg, optional)::args') l with 712 Lfunction{kind = Curried; params = ids; return; body; attr; loc} 713 when List.length ids < Lambda.max_arity () -> 714 lfunction ~kind:Curried ~params:((id_arg, Pgenval)::ids) 715 ~return ~body ~attr ~loc 716 | body -> 717 lfunction ~kind:Curried ~params:[id_arg, Pgenval] 718 ~return:Pgenval ~body 719 ~attr:default_stub_attribute ~loc 720 in 721 (* Wrap "protected" definitions, starting from the left, 722 so that evaluation is right-to-left. *) 723 List.fold_right 724 (fun (id, lam) body -> Llet(Strict, Pgenval, id, lam, body)) 725 !defs body 726 | (Arg arg, optional) :: l -> 727 build_apply lam ((arg, optional) :: args) l 728 | [] -> 729 lapply lam (List.rev_map fst args) 730 in 731 let transl_arg arg = Typedtree.map_apply_arg (transl_exp ~scopes) arg in 732 (build_apply lam [] (List.map (fun (l, arg) -> 733 transl_arg arg, 734 Btype.is_optional l) 735 sargs) 736 : Lambda.lambda) 737 738(* There are two cases in function translation: 739 - [Tupled]. It takes a tupled argument, and we can flatten it. 740 - [Curried]. It takes each argument individually. 741 742 We first try treating the function as taking a flattened tupled argument (in 743 [trans_tupled_function]) and, if that doesn't work, we fall back to treating 744 the function as taking each argument individually (in 745 [trans_curried_function]). 746*) 747and transl_function_without_attributes ~scopes loc repr params body = 748 let return = 749 match body with 750 | Tfunction_body body -> 751 value_kind body.exp_env body.exp_type 752 | Tfunction_cases { cases = { c_rhs } :: _ } -> 753 value_kind c_rhs.exp_env c_rhs.exp_type 754 | Tfunction_cases { cases = [] } -> 755 (* With Camlp4/ppx, a pattern matching might be empty *) 756 Pgenval 757 in 758 transl_tupled_function ~scopes loc return repr params body 759 760and transl_tupled_function ~scopes loc return repr params body = 761 (* Cases are eligible for flattening if they belong to the only param. *) 762 let eligible_cases = 763 match params, body with 764 | [], Tfunction_cases { cases; partial } -> 765 Some (cases, partial) 766 | [ { fp_kind = Tparam_pat pat; fp_partial } ], Tfunction_body body -> 767 let case = 768 { c_lhs = pat; c_cont = None; c_guard = None; c_rhs = body } 769 in 770 Some ([ case ], fp_partial) 771 | _ -> None 772 in 773 match eligible_cases with 774 | Some (({ c_lhs = { pat_desc = Tpat_tuple pl } } :: _) as cases, partial) 775 when !Clflags.native_code 776 && List.length pl <= (Lambda.max_arity ()) -> 777 begin try 778 let size = List.length pl in 779 let pats_expr_list = 780 List.map 781 (fun {c_lhs; c_guard; c_rhs} -> 782 (Matching.flatten_pattern size c_lhs, c_guard, c_rhs)) 783 cases in 784 let kinds = 785 (* All the patterns might not share the same types. We must take the 786 union of the patterns types *) 787 match pats_expr_list with 788 | [] -> assert false 789 | (pats, _, _) :: cases -> 790 let first_case_kinds = 791 List.map (fun pat -> value_kind pat.pat_env pat.pat_type) pats 792 in 793 List.fold_left 794 (fun kinds (pats, _, _) -> 795 List.map2 (fun kind pat -> 796 value_kind_union kind 797 (value_kind pat.pat_env pat.pat_type)) 798 kinds pats) 799 first_case_kinds cases 800 in 801 let tparams = 802 List.map (fun kind -> Ident.create_local "param", kind) kinds 803 in 804 let params = List.map fst tparams in 805 ((Tupled, tparams, return), 806 Matching.for_tupled_function ~scopes loc params 807 (transl_tupled_cases ~scopes pats_expr_list) partial) 808 with Matching.Cannot_flatten -> 809 transl_curried_function ~scopes loc return repr params body 810 end 811 | _ -> transl_curried_function ~scopes loc return repr params body 812 813and transl_curried_function ~scopes loc return repr params body = 814 let cases_param, body = 815 match body with 816 | Tfunction_body body -> 817 None, event_before ~scopes body (transl_exp ~scopes body) 818 | Tfunction_cases { cases; partial; param; loc = cases_loc } -> 819 let kind = 820 match cases with 821 | [] -> 822 (* With Camlp4/ppx, a pattern matching might be empty *) 823 Pgenval 824 | {c_lhs=pat} :: other_cases -> 825 (* All the patterns might not share the same types. We must take the 826 union of the patterns types *) 827 List.fold_left (fun k {c_lhs=pat} -> 828 Typeopt.value_kind_union k 829 (value_kind pat.pat_env pat.pat_type)) 830 (value_kind pat.pat_env pat.pat_type) other_cases 831 in 832 let body = 833 Matching.for_function ~scopes cases_loc repr (Lvar param) 834 (transl_cases ~scopes cases) partial 835 in 836 Some (param, kind), body 837 in 838 let body, params = 839 List.fold_right (fun fp (body, params) -> 840 let param = fp.fp_param in 841 let param_loc = fp.fp_loc in 842 match fp.fp_kind with 843 | Tparam_pat pat -> 844 let kind = value_kind pat.pat_env pat.pat_type in 845 let body = 846 Matching.for_function ~scopes param_loc None (Lvar param) 847 [ pat, body ] 848 fp.fp_partial 849 in 850 body, (param, kind) :: params 851 | Tparam_optional_default (pat, default_arg) -> 852 let default_arg = 853 event_before ~scopes default_arg (transl_exp ~scopes default_arg) 854 in 855 let body = 856 Matching.for_optional_arg_default 857 ~scopes param_loc pat body ~default_arg ~param 858 in 859 (* The optional param is Pgenval as it's an option. *) 860 body, (param, Pgenval) :: params) 861 params 862 (body, Option.to_list cases_param) 863 in 864 (* chunk params according to Lambda.max_arity. If Lambda.max_arity = n and 865 N>n, then the translation of an N-ary typedtree function is an n-ary lambda 866 function returning the translation of an (N-n)-ary typedtree function. 867 *) 868 let params, return, body = 869 match Misc.Stdlib.List.chunks_of (Lambda.max_arity ()) params with 870 | [] -> 871 Misc.fatal_error "attempted to translate a function with zero arguments" 872 | first_chunk :: rest_of_chunks -> 873 let body, return = 874 List.fold_right 875 (fun chunk (body, return) -> 876 let attr = function_attribute_disallowing_arity_fusion in 877 let loc = of_location ~scopes loc in 878 let body = 879 lfunction ~kind:Curried ~params:chunk ~return ~body ~attr ~loc 880 in 881 (* we return Pgenval (for a function) after the rightmost chunk. *) 882 body, Pgenval) 883 rest_of_chunks 884 (body, return) 885 in 886 first_chunk, return, body 887 in 888 ((Curried, params, return), body) 889 890and transl_function ~scopes e params body = 891 let ((kind, params, return), body) = 892 event_function ~scopes e 893 (function repr -> 894 let params, body = fuse_method_arity params body in 895 transl_function_without_attributes ~scopes e.exp_loc repr params body) 896 in 897 let attr = function_attribute_disallowing_arity_fusion in 898 let loc = of_location ~scopes e.exp_loc in 899 let lam = lfunction ~kind ~params ~return ~body ~attr ~loc in 900 let attrs = 901 (* Collect attributes from the Pexp_newtype node for locally abstract types. 902 Otherwise we'd ignore the attribute in, e.g.: 903 fun [@inline] (type a) x -> ... 904 *) 905 List.fold_left 906 (fun attrs (extra_exp, _, extra_attrs) -> 907 match extra_exp with 908 | Texp_newtype _ -> extra_attrs @ attrs 909 | (Texp_constraint _ | Texp_coerce _ | Texp_poly _) -> attrs) 910 e.exp_attributes e.exp_extra 911 in 912 Translattribute.add_function_attributes lam e.exp_loc attrs 913 914(* Like transl_exp, but used when a new scope was just introduced. *) 915and transl_scoped_exp ~scopes expr = 916 transl_exp1 ~scopes ~in_new_scope:true expr 917 918(* Decides whether a pattern binding should introduce a new scope. *) 919and transl_bound_exp ~scopes ~in_structure pat expr = 920 let should_introduce_scope = 921 match expr.exp_desc with 922 | Texp_function _ -> true 923 | _ when in_structure -> true 924 | _ -> false in 925 match pat_bound_idents pat with 926 | (id :: _) when should_introduce_scope -> 927 transl_scoped_exp ~scopes:(enter_value_definition ~scopes id) expr 928 | _ -> transl_exp ~scopes expr 929 930(* 931 Notice: transl_let consumes (ie compiles) its pat_expr_list argument, 932 and returns a function that will take the body of the lambda-let construct. 933 This complication allows choosing any compilation order for the 934 bindings and body of let constructs. 935*) 936and transl_let ~scopes ?(in_structure=false) rec_flag pat_expr_list = 937 match rec_flag with 938 Nonrecursive -> 939 let rec transl = function 940 [] -> 941 fun body -> body 942 | {vb_pat=pat; vb_expr=expr; vb_rec_kind=_; vb_attributes=attr; vb_loc} 943 :: rem -> 944 let lam = transl_bound_exp ~scopes ~in_structure pat expr in 945 let lam = Translattribute.add_function_attributes lam vb_loc attr in 946 let mk_body = transl rem in 947 fun body -> 948 Matching.for_let ~scopes pat.pat_loc lam pat (mk_body body) 949 in transl pat_expr_list 950 | Recursive -> 951 let idlist = 952 List.map 953 (fun {vb_pat=pat} -> match pat.pat_desc with 954 Tpat_var (id,_,_) -> id 955 | _ -> assert false) 956 pat_expr_list in 957 let transl_case {vb_expr=expr; vb_attributes; vb_rec_kind = rkind; 958 vb_loc; vb_pat} id = 959 let def = transl_bound_exp ~scopes ~in_structure vb_pat expr in 960 let def = 961 Translattribute.add_function_attributes def vb_loc vb_attributes 962 in 963 ( id, rkind, def ) in 964 let lam_bds = List.map2 transl_case pat_expr_list idlist in 965 fun body -> Value_rec_compiler.compile_letrec lam_bds body 966 967and transl_setinstvar ~scopes loc self var expr = 968 Lprim(Psetfield_computed (maybe_pointer expr, Assignment), 969 [self; var; transl_exp ~scopes expr], loc) 970 971and transl_record ~scopes loc env fields repres opt_init_expr = 972 let size = Array.length fields in 973 (* Determine if there are "enough" fields (only relevant if this is a 974 functional-style record update *) 975 let no_init = match opt_init_expr with None -> true | _ -> false in 976 if no_init || size < Config.max_young_wosize 977 then begin 978 (* Allocate new record with given fields (and remaining fields 979 taken from init_expr if any *) 980 let init_id = Ident.create_local "init" in 981 let lv = 982 Array.mapi 983 (fun i (_, definition) -> 984 match definition with 985 | Kept (typ, mut) -> 986 let field_kind = value_kind env typ in 987 let access = 988 match repres with 989 Record_regular | Record_inlined _ -> 990 Pfield (i, maybe_pointer_type env typ, mut) 991 | Record_unboxed _ -> assert false 992 | Record_extension _ -> 993 Pfield (i + 1, maybe_pointer_type env typ, mut) 994 | Record_float -> Pfloatfield i in 995 Lprim(access, [Lvar init_id], 996 of_location ~scopes loc), 997 field_kind 998 | Overridden (_lid, expr) -> 999 let field_kind = value_kind expr.exp_env expr.exp_type in 1000 transl_exp ~scopes expr, field_kind) 1001 fields 1002 in 1003 let ll, shape = List.split (Array.to_list lv) in 1004 let mut = 1005 if Array.exists (fun (lbl, _) -> lbl.lbl_mut = Mutable) fields 1006 then Mutable 1007 else Immutable in 1008 let lam = 1009 try 1010 if mut = Mutable then raise Not_constant; 1011 let cl = List.map extract_constant ll in 1012 match repres with 1013 | Record_regular -> Lconst(Const_block(0, cl)) 1014 | Record_inlined tag -> Lconst(Const_block(tag, cl)) 1015 | Record_unboxed _ -> Lconst(match cl with [v] -> v | _ -> assert false) 1016 | Record_float -> 1017 Lconst(Const_float_array(List.map extract_float cl)) 1018 | Record_extension _ -> 1019 raise Not_constant 1020 with Not_constant -> 1021 let loc = of_location ~scopes loc in 1022 match repres with 1023 Record_regular -> 1024 Lprim(Pmakeblock(0, mut, Some shape), ll, loc) 1025 | Record_inlined tag -> 1026 Lprim(Pmakeblock(tag, mut, Some shape), ll, loc) 1027 | Record_unboxed _ -> (match ll with [v] -> v | _ -> assert false) 1028 | Record_float -> 1029 Lprim(Pmakearray (Pfloatarray, mut), ll, loc) 1030 | Record_extension path -> 1031 let slot = transl_extension_path loc env path in 1032 Lprim(Pmakeblock(0, mut, Some (Pgenval :: shape)), slot :: ll, loc) 1033 in 1034 begin match opt_init_expr with 1035 None -> lam 1036 | Some init_expr -> Llet(Strict, Pgenval, init_id, 1037 transl_exp ~scopes init_expr, lam) 1038 end 1039 end else begin 1040 (* Take a shallow copy of the init record, then mutate the fields 1041 of the copy *) 1042 let copy_id = Ident.create_local "newrecord" in 1043 let update_field cont (lbl, definition) = 1044 match definition with 1045 | Kept _ -> cont 1046 | Overridden (_lid, expr) -> 1047 let upd = 1048 match repres with 1049 Record_regular 1050 | Record_inlined _ -> 1051 Psetfield(lbl.lbl_pos, maybe_pointer expr, Assignment) 1052 | Record_unboxed _ -> assert false 1053 | Record_float -> Psetfloatfield (lbl.lbl_pos, Assignment) 1054 | Record_extension _ -> 1055 Psetfield(lbl.lbl_pos + 1, maybe_pointer expr, Assignment) 1056 in 1057 Lsequence(Lprim(upd, [Lvar copy_id; transl_exp ~scopes expr], 1058 of_location ~scopes loc), 1059 cont) 1060 in 1061 begin match opt_init_expr with 1062 None -> assert false 1063 | Some init_expr -> 1064 Llet(Strict, Pgenval, copy_id, 1065 Lprim(Pduprecord (repres, size), [transl_exp ~scopes init_expr], 1066 of_location ~scopes loc), 1067 Array.fold_left update_field (Lvar copy_id) fields) 1068 end 1069 end 1070 1071and transl_atomic_loc ~scopes arg lbl = 1072 let arg = transl_exp ~scopes arg in 1073 let offset = 1074 match lbl.lbl_repres with 1075 | Record_regular 1076 | Record_inlined _ -> 0 1077 | Record_float -> 1078 fatal_error 1079 "Translcore.transl_atomic_loc: atomic field in float record" 1080 | Record_unboxed _ -> 1081 fatal_error 1082 "Translcore.transl_atomic_loc: atomic field in unboxed record" 1083 | Record_extension _ -> 1 1084 in 1085 let lbl = Lconst (Const_int (lbl.lbl_pos + offset)) in 1086 (arg, lbl) 1087 1088and transl_match ~scopes e arg pat_expr_list partial = 1089 let rewrite_case (val_cases, exn_cases, static_handlers as acc) 1090 ({ c_lhs; c_guard; c_rhs } as case) = 1091 if c_rhs.exp_desc = Texp_unreachable then acc else 1092 let val_pat, exn_pat = split_pattern c_lhs in 1093 match val_pat, exn_pat with 1094 | None, None -> assert false 1095 | Some pv, None -> 1096 let val_case = 1097 transl_case ~scopes { case with c_lhs = pv } 1098 in 1099 val_case :: val_cases, exn_cases, static_handlers 1100 | None, Some pe -> 1101 let exn_case = transl_case_try ~scopes { case with c_lhs = pe } in 1102 val_cases, exn_case :: exn_cases, static_handlers 1103 | Some pv, Some pe -> 1104 assert (c_guard = None); 1105 let lbl = next_raise_count () in 1106 let static_raise ids = 1107 Lstaticraise (lbl, List.map (fun id -> Lvar id) ids) 1108 in 1109 (* Simplif doesn't like it if binders are not uniq, so we make sure to 1110 use different names in the value and the exception branches. *) 1111 let ids_full = Typedtree.pat_bound_idents_full pv in 1112 let ids = List.map (fun (id, _, _, _) -> id) ids_full in 1113 let ids_kinds = 1114 List.map (fun (id, _, ty, _) -> id, Typeopt.value_kind pv.pat_env ty) 1115 ids_full 1116 in 1117 let vids = List.map Ident.rename ids in 1118 let pv = alpha_pat (List.combine ids vids) pv in 1119 (* Also register the names of the exception so Re-raise happens. *) 1120 iter_exn_names Translprim.add_exception_ident pe; 1121 let rhs = 1122 Misc.try_finally 1123 (fun () -> event_before ~scopes c_rhs 1124 (transl_exp ~scopes c_rhs)) 1125 ~always:(fun () -> 1126 iter_exn_names Translprim.remove_exception_ident pe) 1127 in 1128 (pv, static_raise vids) :: val_cases, 1129 (pe, static_raise ids) :: exn_cases, 1130 (lbl, ids_kinds, rhs) :: static_handlers 1131 in 1132 let val_cases, exn_cases, static_handlers = 1133 let x, y, z = List.fold_left rewrite_case ([], [], []) pat_expr_list in 1134 List.rev x, List.rev y, List.rev z 1135 in 1136 (* In presence of exception patterns, the code we generate for 1137 1138 match <scrutinees> with 1139 | <val-patterns> -> <val-actions> 1140 | <exn-patterns> -> <exn-actions> 1141 1142 looks like 1143 1144 staticcatch 1145 (try (exit <val-exit> <scrutinees>) 1146 with <exn-patterns> -> <exn-actions>) 1147 with <val-exit> <val-ids> -> 1148 match <val-ids> with <val-patterns> -> <val-actions> 1149 1150 In particular, the 'exit' in the value case ensures that the 1151 value actions run outside the try..with exception handler. 1152 *) 1153 let static_catch scrutinees val_ids handler = 1154 let id = Typecore.name_pattern "exn" (List.map fst exn_cases) in 1155 let static_exception_id = next_raise_count () in 1156 Lstaticcatch 1157 (Ltrywith (Lstaticraise (static_exception_id, scrutinees), id, 1158 Matching.for_trywith ~scopes e.exp_loc (Lvar id) exn_cases), 1159 (static_exception_id, val_ids), 1160 handler) 1161 in 1162 let classic = 1163 match arg, exn_cases with 1164 | {exp_desc = Texp_tuple argl}, [] -> 1165 assert (static_handlers = []); 1166 Matching.for_multiple_match ~scopes e.exp_loc 1167 (transl_list ~scopes (List.map snd argl)) val_cases partial 1168 | {exp_desc = Texp_tuple argl}, _ :: _ -> 1169 let argl = List.map snd argl in 1170 let val_ids = 1171 List.map 1172 (fun arg -> 1173 Typecore.name_pattern "val" [], 1174 Typeopt.value_kind arg.exp_env arg.exp_type 1175 ) 1176 argl 1177 in 1178 let lvars = List.map (fun (id, _) -> Lvar id) val_ids in 1179 static_catch (transl_list ~scopes argl) val_ids 1180 (Matching.for_multiple_match ~scopes e.exp_loc 1181 lvars val_cases partial) 1182 | arg, [] -> 1183 assert (static_handlers = []); 1184 Matching.for_function ~scopes e.exp_loc 1185 None (transl_exp ~scopes arg) val_cases partial 1186 | arg, _ :: _ -> 1187 let val_id = Typecore.name_pattern "val" (List.map fst val_cases) in 1188 let k = Typeopt.value_kind arg.exp_env arg.exp_type in 1189 static_catch [transl_exp ~scopes arg] [val_id, k] 1190 (Matching.for_function ~scopes e.exp_loc 1191 None (Lvar val_id) val_cases partial) 1192 in 1193 List.fold_left (fun body (static_exception_id, val_ids, handler) -> 1194 Lstaticcatch (body, (static_exception_id, val_ids), handler) 1195 ) classic static_handlers 1196 1197and prim_alloc_stack = 1198 Pccall (Primitive.simple ~name:"caml_alloc_stack" ~arity:3 ~alloc:true) 1199 1200and transl_handler ~scopes e body val_caselist exn_caselist eff_caselist = 1201 let val_fun = 1202 match val_caselist with 1203 | None -> 1204 let param = Ident.create_local "param" in 1205 lfunction ~kind:Curried ~params:[param, Pgenval] 1206 ~return:Pgenval ~body:(Lvar param) 1207 ~attr:default_function_attribute ~loc:Loc_unknown 1208 | Some (val_caselist, partial) -> 1209 let val_cases = transl_cases ~scopes val_caselist in 1210 let param = Typecore.name_cases "param" val_caselist in 1211 let body = 1212 Matching.for_function ~scopes e.exp_loc None (Lvar param) val_cases 1213 partial 1214 in 1215 lfunction ~kind:Curried ~params:[param, Pgenval] 1216 ~return:Pgenval ~attr:default_function_attribute 1217 ~loc:Loc_unknown ~body 1218 in 1219 let exn_fun = 1220 let exn_cases = transl_cases ~scopes exn_caselist in 1221 let param = Typecore.name_cases "exn" exn_caselist in 1222 let body = Matching.for_trywith ~scopes e.exp_loc (Lvar param) exn_cases in 1223 lfunction ~kind:Curried ~params:[param, Pgenval] ~return:Pgenval 1224 ~attr:default_function_attribute ~loc:Loc_unknown ~body 1225 in 1226 let eff_fun = 1227 let param = Typecore.name_cases "eff" eff_caselist in 1228 let cont = Ident.create_local "k" in 1229 let cont_tail = Ident.create_local "ktail" in 1230 let eff_cases = transl_cases ~scopes ~cont eff_caselist in 1231 let body = 1232 Matching.for_handler ~scopes e.exp_loc (Lvar param) (Lvar cont) 1233 (Lvar cont_tail) eff_cases 1234 in 1235 lfunction ~kind:Curried 1236 ~params:[(param, Pgenval); (cont, Pgenval); (cont_tail, Pgenval)] 1237 ~return:Pgenval ~attr:default_function_attribute ~loc:Loc_unknown ~body 1238 in 1239 let (body_fun, arg) = 1240 match transl_exp ~scopes body with 1241 | Lapply { ap_func = fn; ap_args = [arg]; _ } 1242 when is_evaluated fn && is_evaluated arg -> (fn, arg) 1243 | body -> 1244 let param = Ident.create_local "param" in 1245 (lfunction ~kind:Curried ~params:[param, Pgenval] ~return:Pgenval 1246 ~attr:default_function_attribute ~loc:Loc_unknown 1247 ~body, 1248 Lconst(Const_int 0)) 1249 in 1250 let alloc_stack = 1251 Lprim(prim_alloc_stack, [val_fun; exn_fun; eff_fun], Loc_unknown) 1252 in 1253 Lprim(Prunstack, [alloc_stack; body_fun; arg], 1254 of_location ~scopes e.exp_loc) 1255 1256and transl_letop ~scopes loc env let_ ands param case partial = 1257 let rec loop prev_lam = function 1258 | [] -> prev_lam 1259 | and_ :: rest -> 1260 let left_id = Ident.create_local "left" in 1261 let right_id = Ident.create_local "right" in 1262 let op = 1263 transl_ident (of_location ~scopes and_.bop_op_name.loc) env 1264 and_.bop_op_type and_.bop_op_path and_.bop_op_val 1265 in 1266 let exp = transl_exp ~scopes and_.bop_exp in 1267 let lam = 1268 bind Strict right_id exp 1269 (Lapply{ 1270 ap_loc = of_location ~scopes and_.bop_loc; 1271 ap_func = op; 1272 ap_args=[Lvar left_id; Lvar right_id]; 1273 ap_tailcall = Default_tailcall; 1274 ap_inlined = Default_inline; 1275 ap_specialised = Default_specialise; 1276 }) 1277 in 1278 bind Strict left_id prev_lam (loop lam rest) 1279 in 1280 let op = 1281 transl_ident (of_location ~scopes let_.bop_op_name.loc) env 1282 let_.bop_op_type let_.bop_op_path let_.bop_op_val 1283 in 1284 let exp = loop (transl_exp ~scopes let_.bop_exp) ands in 1285 let func = 1286 let (kind, params, return), body = 1287 event_function ~scopes case.c_rhs 1288 (function repr -> 1289 let loc = case.c_rhs.exp_loc in 1290 let ghost_loc = { loc with loc_ghost = true } in 1291 transl_function_without_attributes ~scopes loc repr [] 1292 (Tfunction_cases 1293 { cases = [case]; param; partial; loc = ghost_loc; 1294 exp_extra = None; attributes = []; })) 1295 in 1296 let attr = function_attribute_disallowing_arity_fusion in 1297 let loc = of_location ~scopes case.c_rhs.exp_loc in 1298 lfunction ~kind ~params ~return ~body ~attr ~loc 1299 in 1300 Lapply{ 1301 ap_loc = of_location ~scopes loc; 1302 ap_func = op; 1303 ap_args=[exp; func]; 1304 ap_tailcall = Default_tailcall; 1305 ap_inlined = Default_inline; 1306 ap_specialised = Default_specialise; 1307 } 1308 1309(* Wrapper for class compilation *) 1310 1311(* 1312let transl_exp = transl_exp_wrap 1313 1314let transl_let rec_flag pat_expr_list body = 1315 match pat_expr_list with 1316 [] -> body 1317 | (_, expr) :: _ -> 1318 Translobj.oo_wrap expr.exp_env false 1319 (transl_let rec_flag pat_expr_list) body 1320*) 1321 1322(* Error report *) 1323 1324open Format_doc 1325 1326let report_error_doc ppf = function 1327 | Free_super_var -> 1328 fprintf ppf 1329 "Ancestor names can only be used to select inherited methods" 1330 | Unreachable_reached -> 1331 fprintf ppf "Unreachable expression was reached" 1332 1333let () = 1334 Location.register_error_of_exn 1335 (function 1336 | Error (loc, err) -> 1337 Some (Location.error_of_printer ~loc report_error_doc err) 1338 | _ -> 1339 None 1340 ) 1341 1342let report_error = Format_doc.compat report_error_doc