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(* Compilation of pattern matching *)
17
18open Misc
19open Asttypes
20open Types
21open Typedtree
22open Lambda
23open Parmatch
24open Printf
25
26
27let dbg = false
28
29(*  See Peyton-Jones, ``The Implementation of functional programming
30    languages'', chapter 5. *)
31(*
32  Well, it was true at the beginning of the world.
33  Now, see Lefessant-Maranget ``Optimizing Pattern-Matching'' ICFP'2001
34*)
35
36
37(*
38   Many functions on the various data structures of the algorithm :
39     - Pattern matrices.
40     - Default environments: mapping from matrices to exit numbers.
41     - Contexts:  matrices whose column are partitioned into
42       left and right.
43     - Jump summaries: mapping from exit numbers to contexts
44*)
45
46let string_of_lam lam =
47  Printlambda.lambda Format.str_formatter lam ;
48  Format.flush_str_formatter ()
49
50type matrix = pattern list list
51
52let add_omega_column pss = List.map (fun ps -> omega::ps) pss
53
54type ctx = {left:pattern list ; right:pattern list}
55
56let pretty_ctx ctx =
57  List.iter
58    (fun {left=left ; right=right} ->
59      prerr_string "LEFT:" ;
60      pretty_line left ;
61      prerr_string " RIGHT:" ;
62      pretty_line right ;
63      prerr_endline "")
64    ctx
65
66let le_ctx c1 c2 =
67  le_pats c1.left c2.left &&
68  le_pats c1.right c2.right
69
70let lshift {left=left ; right=right} = match right with
71| x::xs -> {left=x::left ; right=xs}
72| _ ->  assert false
73
74let lforget {left=left ; right=right} = match right with
75| _::xs -> {left=omega::left ; right=xs}
76|  _ -> assert false
77
78let rec small_enough n = function
79  | [] -> true
80  | _::rem ->
81      if n <= 0 then false
82      else small_enough (n-1) rem
83
84let ctx_lshift ctx =
85  if small_enough 31 ctx then
86    List.map lshift ctx
87  else (* Context pruning *) begin
88    get_mins le_ctx (List.map lforget ctx)
89  end
90
91let  rshift {left=left ; right=right} = match left with
92| p::ps -> {left=ps ; right=p::right}
93| _ -> assert false
94
95let ctx_rshift ctx = List.map rshift ctx
96
97let rec nchars n ps =
98  if n <= 0 then [],ps
99  else match ps with
100  | p::rem ->
101    let chars, cdrs = nchars (n-1) rem in
102    p::chars,cdrs
103  | _ -> assert false
104
105let  rshift_num n {left=left ; right=right} =
106  let shifted,left = nchars n left in
107  {left=left ; right = shifted@right}
108
109let ctx_rshift_num n ctx = List.map (rshift_num n) ctx
110
111(* Recombination of contexts (eg: (_,_)::p1::p2::rem ->  (p1,p2)::rem)
112  All mutable fields are replaced by '_', since side-effects in
113  guards can alter these fields *)
114
115let combine {left=left ; right=right} = match left with
116| p::ps -> {left=ps ; right=set_args_erase_mutable p right}
117| _ -> assert false
118
119let ctx_combine ctx = List.map combine ctx
120
121let ncols = function
122  | [] -> 0
123  | ps::_ -> List.length ps
124
125
126exception NoMatch
127exception OrPat
128
129let filter_matrix matcher pss =
130
131  let rec filter_rec = function
132    | (p::ps)::rem ->
133        begin match p.pat_desc with
134        | Tpat_alias (p,_,_) ->
135            filter_rec ((p::ps)::rem)
136        | Tpat_var _ ->
137            filter_rec ((omega::ps)::rem)
138        | _ ->
139            begin
140              let rem = filter_rec rem in
141              try
142                matcher p ps::rem
143              with
144              | NoMatch -> rem
145              | OrPat   ->
146                match p.pat_desc with
147                | Tpat_or (p1,p2,_) -> filter_rec [(p1::ps) ;(p2::ps)]@rem
148                | _ -> assert false
149            end
150        end
151    | [] -> []
152    | _ ->
153        pretty_matrix pss ;
154        fatal_error "Matching.filter_matrix" in
155  filter_rec pss
156
157let make_default matcher env =
158  let rec make_rec = function
159    | [] -> []
160    | ([[]],i)::_ -> [[[]],i]
161    | (pss,i)::rem ->
162        let rem = make_rec rem in
163        match filter_matrix matcher pss with
164        | [] -> rem
165        | ([]::_) -> ([[]],i)::rem
166        | pss -> (pss,i)::rem in
167  make_rec env
168
169let ctx_matcher p =
170  let p = normalize_pat p in
171  match p.pat_desc with
172  | Tpat_construct (_, cstr,omegas) ->
173      begin match cstr.cstr_tag with
174      | Cstr_extension _ ->
175          let nargs = List.length omegas in
176          (fun q rem -> match q.pat_desc with
177          | Tpat_construct (_, _cstr',args)
178            when List.length args = nargs ->
179                p,args @ rem
180          | Tpat_any -> p,omegas @ rem
181          | _ -> raise NoMatch)
182      | _ ->
183          (fun q rem -> match q.pat_desc with
184          | Tpat_construct (_, cstr',args)
185            when cstr.cstr_tag=cstr'.cstr_tag ->
186              p,args @ rem
187          | Tpat_any -> p,omegas @ rem
188          | _ -> raise NoMatch)
189      end
190  | Tpat_constant cst ->
191      (fun q rem -> match q.pat_desc with
192      | Tpat_constant cst' when const_compare cst cst' = 0 ->
193          p,rem
194      | Tpat_any -> p,rem
195      | _ -> raise NoMatch)
196  | Tpat_variant (lab,Some omega,_) ->
197      (fun q rem -> match q.pat_desc with
198      | Tpat_variant (lab',Some arg,_) when lab=lab' ->
199          p,arg::rem
200      | Tpat_any -> p,omega::rem
201      | _ -> raise NoMatch)
202  | Tpat_variant (lab,None,_) ->
203      (fun q rem -> match q.pat_desc with
204      | Tpat_variant (lab',None,_) when lab=lab' ->
205          p,rem
206      | Tpat_any -> p,rem
207      | _ -> raise NoMatch)
208  | Tpat_array omegas ->
209      let len = List.length omegas in
210      (fun q rem -> match q.pat_desc with
211      | Tpat_array args when List.length args=len ->
212          p,args @ rem
213      | Tpat_any -> p, omegas @ rem
214      | _ -> raise NoMatch)
215  | Tpat_tuple omegas ->
216      (fun q rem -> match q.pat_desc with
217      | Tpat_tuple args -> p,args @ rem
218      | _          -> p, omegas @ rem)
219  | Tpat_record (l,_) -> (* Records are normalized *)
220      (fun q rem -> match q.pat_desc with
221      | Tpat_record (l',_) ->
222          let l' = all_record_args l' in
223          p, List.fold_right (fun (_, _,p) r -> p::r) l' rem
224      | _ -> p,List.fold_right (fun (_, _,p) r -> p::r) l rem)
225  | Tpat_lazy omega ->
226      (fun q rem -> match q.pat_desc with
227      | Tpat_lazy arg -> p, (arg::rem)
228      | _          -> p, (omega::rem))
229 | _ -> fatal_error "Matching.ctx_matcher"
230
231
232
233
234let filter_ctx q ctx =
235
236  let matcher = ctx_matcher q in
237
238  let rec filter_rec = function
239    | ({right=p::ps} as l)::rem ->
240        begin match p.pat_desc with
241        | Tpat_or (p1,p2,_) ->
242            filter_rec ({l with right=p1::ps}::{l with right=p2::ps}::rem)
243        | Tpat_alias (p,_,_) ->
244            filter_rec ({l with right=p::ps}::rem)
245        | Tpat_var _ ->
246            filter_rec ({l with right=omega::ps}::rem)
247        | _ ->
248            begin let rem = filter_rec rem in
249            try
250              let to_left, right = matcher p ps in
251              {left=to_left::l.left ; right=right}::rem
252            with
253            | NoMatch -> rem
254            end
255        end
256    | [] -> []
257    | _ ->  fatal_error "Matching.filter_ctx" in
258
259  filter_rec ctx
260
261let select_columns pss ctx =
262  let n = ncols pss in
263  List.fold_right
264    (fun ps r ->
265      List.fold_right
266        (fun {left=left ; right=right} r ->
267          let transfert, right = nchars n right in
268          try
269            {left = lubs transfert ps @ left ; right=right}::r
270          with
271          | Empty -> r)
272        ctx r)
273    pss []
274
275let ctx_lub p ctx =
276  List.fold_right
277    (fun {left=left ; right=right} r ->
278      match right with
279      | q::rem ->
280          begin try
281            {left=left ; right = lub p q::rem}::r
282          with
283          | Empty -> r
284          end
285      | _ -> fatal_error "Matching.ctx_lub")
286    ctx []
287
288let ctx_match ctx pss =
289  List.exists
290    (fun {right=qs} ->
291      List.exists
292        (fun ps -> compats qs ps)
293        pss)
294    ctx
295
296type jumps = (int * ctx list) list
297
298let pretty_jumps (env : jumps) = match env with
299| [] -> ()
300| _ ->
301    List.iter
302      (fun (i,ctx) ->
303        Printf.fprintf stderr "jump for %d\n" i ;
304        pretty_ctx ctx)
305      env
306
307
308let rec jumps_extract i = function
309  | [] -> [],[]
310  | (j,pss) as x::rem as all ->
311      if i=j then pss,rem
312      else if j < i then [],all
313      else
314        let r,rem = jumps_extract i rem in
315        r,(x::rem)
316
317let rec jumps_remove i = function
318  | [] -> []
319  | (j,_)::rem when i=j -> rem
320  | x::rem -> x::jumps_remove i rem
321
322let jumps_empty = []
323and jumps_is_empty = function
324  |  [] -> true
325  |  _ -> false
326
327let jumps_singleton i = function
328  | []  -> []
329  | ctx ->  [i,ctx]
330
331let jumps_add i pss jumps = match pss with
332| [] -> jumps
333| _  ->
334    let rec add = function
335      | [] -> [i,pss]
336      | (j,qss) as x::rem as all ->
337          if j > i then x::add rem
338      else if j < i then (i,pss)::all
339      else (i,(get_mins le_ctx (pss@qss)))::rem in
340    add jumps
341
342
343let rec jumps_union (env1:(int*ctx list)list) env2 = match env1,env2 with
344| [],_ -> env2
345| _,[] -> env1
346| ((i1,pss1) as x1::rem1), ((i2,pss2) as x2::rem2) ->
347    if i1=i2 then
348      (i1,get_mins le_ctx (pss1@pss2))::jumps_union rem1 rem2
349    else if i1 > i2 then
350      x1::jumps_union rem1 env2
351    else
352      x2::jumps_union env1 rem2
353
354
355let rec merge = function
356  | env1::env2::rem ->  jumps_union env1 env2::merge rem
357  | envs -> envs
358
359let rec jumps_unions envs = match envs with
360  | [] -> []
361  | [env] -> env
362  | _ -> jumps_unions (merge envs)
363
364let jumps_map f env =
365  List.map
366    (fun (i,pss) -> i,f pss)
367    env
368
369(* Pattern matching before any compilation *)
370
371type pattern_matching =
372  { mutable cases : (pattern list * lambda) list;
373    args : (lambda * let_kind) list ;
374    default : (matrix * int) list}
375
376(* Pattern matching after application of both the or-pat rule and the
377   mixture rule *)
378
379type pm_or_compiled =
380  {body : pattern_matching ;
381   handlers : (matrix * int * Ident.t list * pattern_matching) list ;
382   or_matrix : matrix ; }
383
384type pm_half_compiled =
385  | PmOr of pm_or_compiled
386  | PmVar of pm_var_compiled
387  | Pm of pattern_matching
388
389and pm_var_compiled =
390    {inside : pm_half_compiled ; var_arg : lambda ; }
391
392type pm_half_compiled_info =
393    {me : pm_half_compiled ;
394     matrix : matrix ;
395     top_default : (matrix * int) list ; }
396
397let pretty_cases cases =
398  List.iter
399    (fun (ps,_l) ->
400      List.iter
401        (fun p ->
402          Parmatch.top_pretty Format.str_formatter p ;
403          prerr_string " " ;
404          prerr_string (Format.flush_str_formatter ()))
405        ps ;
406(*
407      prerr_string " -> " ;
408      Printlambda.lambda Format.str_formatter l ;
409      prerr_string (Format.flush_str_formatter ()) ;
410*)
411      prerr_endline "")
412    cases
413
414let pretty_def def =
415  prerr_endline "+++++ Defaults +++++" ;
416  List.iter
417    (fun (pss,i) ->
418      Printf.fprintf stderr "Matrix for %d\n"  i ;
419      pretty_matrix pss)
420    def ;
421  prerr_endline "+++++++++++++++++++++"
422
423let pretty_pm pm = pretty_cases pm.cases
424
425
426let rec pretty_precompiled = function
427  | Pm pm ->
428      prerr_endline "++++ PM ++++" ;
429      pretty_pm pm
430  | PmVar x ->
431      prerr_endline "++++ VAR ++++" ;
432      pretty_precompiled x.inside
433  | PmOr x ->
434      prerr_endline "++++ OR ++++" ;
435      pretty_pm x.body ;
436      pretty_matrix x.or_matrix ;
437      List.iter
438        (fun (_,i,_,pm) ->
439          eprintf "++ Handler %d ++\n" i ;
440          pretty_pm pm)
441        x.handlers
442
443let pretty_precompiled_res first nexts =
444  pretty_precompiled first ;
445  List.iter
446    (fun (e, pmh) ->
447      eprintf "** DEFAULT %d **\n" e ;
448      pretty_precompiled pmh)
449    nexts
450
451
452
453(* Identifing some semantically equivalent lambda-expressions,
454   Our goal here is also to
455   find alpha-equivalent (simple) terms *)
456
457(* However, as shown by PR#6359 such sharing may hinders the
458   lambda-code invariant that all bound idents are unique,
459   when switches are compiled to test sequences.
460   The definitive fix is the systematic introduction of exit/catch
461   in case action sharing is present.
462*)
463
464
465module StoreExp =
466  Switch.Store
467    (struct
468      type t = lambda
469      type key = lambda
470      let make_key = Lambda.make_key
471    end)
472
473
474let make_exit i = Lstaticraise (i,[])
475
476(* Introduce a catch, if worth it *)
477let make_catch d k = match d with
478| Lstaticraise (_,[]) -> k d
479| _ ->
480    let e = next_raise_count () in
481    Lstaticcatch (k (make_exit e),(e,[]),d)
482
483(* Introduce a catch, if worth it, delayed version *)
484let rec as_simple_exit = function
485  | Lstaticraise (i,[]) -> Some i
486  | Llet (Alias,_k,_,_,e) -> as_simple_exit e
487  | _ -> None
488
489
490let make_catch_delayed handler = match as_simple_exit handler with
491| Some i -> i,(fun act -> act)
492| None ->
493    let i = next_raise_count () in
494(*
495    Printf.eprintf "SHARE LAMBDA: %i\n%s\n" i (string_of_lam handler);
496*)
497    i,
498    (fun body -> match body with
499    | Lstaticraise (j,_) ->
500        if i=j then handler else body
501    | _ -> Lstaticcatch (body,(i,[]),handler))
502
503
504let raw_action l =
505  match make_key l with | Some l -> l | None -> l
506
507
508let tr_raw act = match make_key act with
509| Some act -> act
510| None -> raise Exit
511
512let same_actions = function
513  | [] -> None
514  | [_,act] -> Some act
515  | (_,act0) :: rem ->
516      try
517        let raw_act0 = tr_raw act0 in
518        let rec s_rec = function
519          | [] -> Some act0
520          | (_,act)::rem ->
521              if raw_act0 = tr_raw act then
522                s_rec rem
523              else
524                None in
525        s_rec rem
526      with
527      | Exit -> None
528
529
530(* Test for swapping two clauses *)
531
532let up_ok_action act1 act2 =
533  try
534    let raw1 = tr_raw act1
535    and raw2 = tr_raw act2 in
536    raw1 = raw2
537  with
538  | Exit -> false
539
540(* Nothing is known about exception/extension patterns,
541   because of potential rebind *)
542let rec exc_inside p = match p.pat_desc with
543  | Tpat_construct (_,{cstr_tag=Cstr_extension _},_) -> true
544  | Tpat_any|Tpat_constant _|Tpat_var _
545  | Tpat_construct (_,_,[])
546  | Tpat_variant (_,None,_)
547    -> false
548  | Tpat_construct (_,_,ps)
549  | Tpat_tuple ps
550  | Tpat_array ps
551      -> exc_insides ps
552  | Tpat_variant (_, Some q,_)
553  | Tpat_alias (q,_,_)
554  | Tpat_lazy q
555    -> exc_inside q
556  | Tpat_record (lps,_) ->
557      List.exists (fun (_,_,p) -> exc_inside p) lps
558  | Tpat_or (p1,p2,_) -> exc_inside p1 || exc_inside p2
559
560and exc_insides ps = List.exists exc_inside ps
561
562let up_ok (ps,act_p) l =
563  if exc_insides ps then match l with [] -> true | _::_ -> false
564  else
565    List.for_all
566      (fun (qs,act_q) ->
567        up_ok_action act_p act_q ||
568        not (Parmatch.compats ps qs))
569      l
570
571
572(*
573   Simplify fonction normalize the first column of the match
574     - records are expanded so that they possess all fields
575     - aliases are removed and replaced by bindings in actions.
576   However or-patterns are simplified differently,
577     - aliases are not removed
578     - or-patterns (_|p) are changed into _
579*)
580
581exception Var of pattern
582
583let simplify_or p =
584  let rec simpl_rec p = match p with
585    | {pat_desc = Tpat_any|Tpat_var _} -> raise (Var p)
586    | {pat_desc = Tpat_alias (q,id,s)} ->
587        begin try
588          {p with pat_desc = Tpat_alias (simpl_rec q,id,s)}
589        with
590        | Var q -> raise (Var {p with pat_desc = Tpat_alias (q,id,s)})
591        end
592    | {pat_desc = Tpat_or (p1,p2,o)} ->
593        let q1 = simpl_rec p1 in
594        begin try
595          let q2 = simpl_rec p2 in
596          {p with pat_desc = Tpat_or (q1, q2, o)}
597        with
598        | Var q2 -> raise (Var {p with pat_desc = Tpat_or (q1, q2, o)})
599        end
600    | {pat_desc = Tpat_record (lbls,closed)} ->
601        let all_lbls = all_record_args lbls in
602        {p with pat_desc=Tpat_record (all_lbls, closed)}
603    | _ -> p in
604  try
605    simpl_rec p
606  with
607  | Var p -> p
608
609let simplify_cases args cls = match args with
610| [] -> assert false
611| (arg,_)::_ ->
612    let rec simplify = function
613      | [] -> []
614      | ((pat :: patl, action) as cl) :: rem ->
615          begin match pat.pat_desc with
616          | Tpat_var (id, _) ->
617              (omega :: patl, bind Alias id arg action) ::
618              simplify rem
619          | Tpat_any ->
620              cl :: simplify rem
621          | Tpat_alias(p, id,_) ->
622              simplify ((p :: patl, bind Alias id arg action) :: rem)
623          | Tpat_record ([],_) ->
624              (omega :: patl, action)::
625              simplify rem
626          | Tpat_record (lbls, closed) ->
627              let all_lbls = all_record_args lbls in
628              let full_pat =
629                {pat with pat_desc=Tpat_record (all_lbls, closed)} in
630              (full_pat::patl,action)::
631              simplify rem
632          | Tpat_or _ ->
633              let pat_simple  = simplify_or pat in
634              begin match pat_simple.pat_desc with
635              | Tpat_or _ ->
636                  (pat_simple :: patl, action) ::
637                  simplify rem
638              | _ ->
639                  simplify ((pat_simple::patl,action) :: rem)
640              end
641          | _ -> cl :: simplify rem
642          end
643      | _ -> assert false in
644
645    simplify cls
646
647
648
649(* Once matchings are simplified one can easily find
650   their nature *)
651
652let rec what_is_cases cases = match cases with
653| ({pat_desc=Tpat_any} :: _, _) :: rem -> what_is_cases rem
654| (({pat_desc=(Tpat_var _|Tpat_or (_,_,_)|Tpat_alias (_,_,_))}::_),_)::_
655  -> assert false (* applies to simplified matchings only *)
656| (p::_,_)::_ -> p
657| [] -> omega
658| _ -> assert false
659
660
661
662(* A few operations on default environments *)
663let as_matrix cases = get_mins le_pats (List.map (fun (ps,_) -> ps) cases)
664
665(* For extension matching, record no information in matrix *)
666let as_matrix_omega cases =
667  get_mins le_pats
668    (List.map
669       (fun (ps,_) ->
670         match ps with
671         | [] -> assert false
672         | _::ps -> omega::ps)
673       cases)
674
675let cons_default matrix raise_num default =
676  match matrix with
677  | [] -> default
678  | _ -> (matrix,raise_num)::default
679
680let default_compat p def =
681  List.fold_right
682    (fun (pss,i) r ->
683      let qss =
684        List.fold_right
685          (fun qs r -> match qs with
686            | q::rem when Parmatch.compat p q -> rem::r
687            | _ -> r)
688          pss [] in
689      match qss with
690      | [] -> r
691      | _  -> (qss,i)::r)
692    def []
693
694(* Or-pattern expansion, variables are a complication w.r.t. the article *)
695let rec extract_vars r p = match p.pat_desc with
696| Tpat_var (id, _) -> IdentSet.add id r
697| Tpat_alias (p, id,_ ) ->
698    extract_vars (IdentSet.add id r) p
699| Tpat_tuple pats ->
700    List.fold_left extract_vars r pats
701| Tpat_record (lpats,_) ->
702    List.fold_left
703      (fun r (_, _, p) -> extract_vars r p)
704      r lpats
705| Tpat_construct (_, _, pats) ->
706    List.fold_left extract_vars r pats
707| Tpat_array pats ->
708    List.fold_left extract_vars r pats
709| Tpat_variant (_,Some p, _) -> extract_vars r p
710| Tpat_lazy p -> extract_vars r p
711| Tpat_or (p,_,_) -> extract_vars r p
712| Tpat_constant _|Tpat_any|Tpat_variant (_,None,_) -> r
713
714exception Cannot_flatten
715
716let mk_alpha_env arg aliases ids =
717  List.map
718    (fun id -> id,
719      if List.mem id aliases then
720        match arg with
721        | Some v -> v
722        | _      -> raise Cannot_flatten
723      else
724        Ident.create (Ident.name id))
725    ids
726
727let rec explode_or_pat arg patl mk_action rem vars aliases = function
728  | {pat_desc = Tpat_or (p1,p2,_)} ->
729      explode_or_pat
730        arg patl mk_action
731        (explode_or_pat arg patl mk_action rem vars aliases p2)
732        vars aliases p1
733  | {pat_desc = Tpat_alias (p,id, _)} ->
734      explode_or_pat arg patl mk_action rem vars (id::aliases) p
735  | {pat_desc = Tpat_var (x, _)} ->
736      let env = mk_alpha_env arg (x::aliases) vars in
737      (omega::patl,mk_action (List.map snd env))::rem
738  | p ->
739      let env = mk_alpha_env arg aliases vars in
740      (alpha_pat env p::patl,mk_action (List.map snd env))::rem
741
742let pm_free_variables {cases=cases} =
743  List.fold_right
744    (fun (_,act) r -> IdentSet.union (free_variables act) r)
745    cases IdentSet.empty
746
747
748(* Basic grouping predicates *)
749let pat_as_constr = function
750  | {pat_desc=Tpat_construct (_, cstr,_)} -> cstr
751  | _ -> fatal_error "Matching.pat_as_constr"
752
753let group_constant = function
754  | {pat_desc= Tpat_constant _} -> true
755  | _                           -> false
756
757and group_constructor = function
758  | {pat_desc = Tpat_construct (_,_,_)} -> true
759  | _ -> false
760
761and group_variant = function
762  | {pat_desc = Tpat_variant (_, _, _)} -> true
763  | _ -> false
764
765and group_var = function
766  | {pat_desc=Tpat_any} -> true
767  | _ -> false
768
769and group_tuple = function
770  | {pat_desc = (Tpat_tuple _|Tpat_any)} -> true
771  | _ -> false
772
773and group_record = function
774  | {pat_desc = (Tpat_record _|Tpat_any)} -> true
775  | _ -> false
776
777and group_array = function
778  | {pat_desc=Tpat_array _} -> true
779  | _ -> false
780
781and group_lazy = function
782  | {pat_desc = Tpat_lazy _} -> true
783  | _ -> false
784
785let get_group p = match p.pat_desc with
786| Tpat_any -> group_var
787| Tpat_constant _ -> group_constant
788| Tpat_construct _ -> group_constructor
789| Tpat_tuple _ -> group_tuple
790| Tpat_record _ -> group_record
791| Tpat_array _ -> group_array
792| Tpat_variant (_,_,_) -> group_variant
793| Tpat_lazy _ -> group_lazy
794|  _ -> fatal_error "Matching.get_group"
795
796
797
798let is_or p = match p.pat_desc with
799| Tpat_or _ -> true
800| _ -> false
801
802(* Conditions for appending to the Or matrix *)
803let conda p q = not (compat p q)
804and condb act ps qs =  not (is_guarded act) && Parmatch.le_pats qs ps
805
806let or_ok p ps l =
807  List.for_all
808    (function
809      | ({pat_desc=Tpat_or _} as q::qs,act) ->
810          conda p q || condb act ps qs
811      | _ -> true)
812    l
813
814(* Insert or append a pattern in the Or matrix *)
815
816let equiv_pat p q = le_pat p q && le_pat q p
817
818let rec get_equiv p l = match l with
819  | (q::_,_) as cl::rem ->
820      if equiv_pat p q then
821        let others,rem = get_equiv p rem in
822        cl::others,rem
823      else
824        [],l
825  | _ -> [],l
826
827
828let insert_or_append p ps act ors no =
829  let rec attempt seen = function
830    | (q::qs,act_q) as cl::rem ->
831        if is_or q then begin
832          if compat p q then
833            if
834              IdentSet.is_empty (extract_vars IdentSet.empty p) &&
835              IdentSet.is_empty (extract_vars IdentSet.empty q) &&
836              equiv_pat p q
837            then (* attempt insert, for equivalent orpats with no variables *)
838              let _, not_e = get_equiv q rem in
839              if
840                or_ok p ps not_e && (* check append condition for head of O *)
841                List.for_all        (* check insert condition for tail of O *)
842                  (fun cl -> match cl with
843                  | (q::_,_) -> not (compat p q)
844                  | _        -> assert false)
845                  seen
846              then (* insert *)
847                List.rev_append seen ((p::ps,act)::cl::rem), no
848              else (* fail to insert or append *)
849                ors,(p::ps,act)::no
850            else if condb act_q ps qs then (* check condition (b) for append *)
851              attempt (cl::seen) rem
852            else
853              ors,(p::ps,act)::no
854          else (* p # q, go on with append/insert *)
855            attempt (cl::seen) rem
856        end else (* q is not an or-pat, go on with append/insert *)
857          attempt (cl::seen) rem
858    | _  -> (* [] in fact *)
859        (p::ps,act)::ors,no in (* success in appending *)
860  attempt [] ors
861
862(* Reconstruct default information from half_compiled  pm list *)
863
864let rec rebuild_matrix pmh = match pmh with
865  | Pm pm -> as_matrix pm.cases
866  | PmOr {or_matrix=m} -> m
867  | PmVar x -> add_omega_column  (rebuild_matrix x.inside)
868
869let rec rebuild_default nexts def = match nexts with
870| [] -> def
871| (e, pmh)::rem ->
872    (add_omega_column (rebuild_matrix pmh), e)::
873    rebuild_default rem def
874
875let rebuild_nexts arg nexts k =
876  List.fold_right
877    (fun (e, pm) k -> (e, PmVar {inside=pm ; var_arg=arg})::k)
878    nexts k
879
880
881(*
882  Split a matching.
883    Splitting is first directed by or-patterns, then by
884    tests (e.g. constructors)/variable transitions.
885
886    The approach is greedy, every split function attempts to
887    raise rows as much as possible in the top matrix,
888    then splitting applies again to the remaining rows.
889
890    Some precompilation of or-patterns and
891    variable pattern occurs. Mostly this means that bindings
892    are performed now,  being replaced by let-bindings
893    in actions (cf. simplify_cases).
894
895    Additionally, if the match argument is a variable, matchings whose
896    first column is made of variables only are splitted further
897    (cf. precompile_var).
898
899*)
900
901
902let rec split_or argo cls args def =
903
904  let cls = simplify_cases args cls in
905
906  let rec do_split before ors no = function
907    | [] ->
908        cons_next
909          (List.rev before) (List.rev ors) (List.rev no)
910    | ((p::ps,act) as cl)::rem ->
911        if up_ok cl no then
912          if is_or p then
913            let ors, no = insert_or_append p ps act ors no in
914            do_split before ors no rem
915          else begin
916            if up_ok cl ors then
917              do_split (cl::before) ors no rem
918            else if or_ok p ps ors then
919              do_split before (cl::ors) no rem
920            else
921              do_split before ors (cl::no) rem
922          end
923        else
924          do_split before ors (cl::no) rem
925    | _ -> assert false
926
927  and cons_next yes yesor = function
928    | [] ->
929        precompile_or argo yes yesor args def []
930    | rem ->
931        let {me=next ; matrix=matrix ; top_default=def},nexts =
932          do_split [] [] [] rem in
933        let idef = next_raise_count () in
934        precompile_or
935          argo yes yesor args
936          (cons_default matrix idef def)
937          ((idef,next)::nexts) in
938
939  do_split [] [] [] cls
940
941(* Ultra-naive splitting, close to semantics, used for extension,
942   as potential rebind prevents any kind of optimisation *)
943
944and split_naive cls args def k =
945
946  let rec split_exc cstr0 yes = function
947    | [] ->
948        let yes = List.rev yes in
949        { me = Pm {cases=yes; args=args; default=def;} ;
950          matrix = as_matrix_omega yes ;
951          top_default=def},
952        k
953    | (p::_,_ as cl)::rem ->
954        if group_constructor p then
955          let cstr = pat_as_constr p in
956          if cstr = cstr0 then split_exc cstr0 (cl::yes) rem
957          else
958            let yes = List.rev yes in
959            let {me=next ; matrix=matrix ; top_default=def}, nexts =
960              split_exc cstr [cl] rem in
961            let idef = next_raise_count () in
962            let def = cons_default matrix idef def in
963            { me = Pm {cases=yes; args=args; default=def} ;
964              matrix = as_matrix_omega yes ;
965              top_default = def; },
966            (idef,next)::nexts
967        else
968          let yes = List.rev yes in
969          let {me=next ; matrix=matrix ; top_default=def}, nexts =
970              split_noexc [cl] rem in
971            let idef = next_raise_count () in
972            let def = cons_default matrix idef def in
973            { me = Pm {cases=yes; args=args; default=def} ;
974              matrix = as_matrix_omega yes ;
975              top_default = def; },
976            (idef,next)::nexts
977    | _ -> assert false
978
979  and split_noexc yes = function
980    | [] -> precompile_var args (List.rev yes) def k
981    | (p::_,_ as cl)::rem ->
982        if group_constructor p then
983          let yes= List.rev yes in
984          let {me=next; matrix=matrix; top_default=def;},nexts =
985            split_exc (pat_as_constr p) [cl] rem in
986          let idef = next_raise_count () in
987          precompile_var
988            args yes
989            (cons_default matrix idef def)
990            ((idef,next)::nexts)
991        else split_noexc (cl::yes) rem
992    | _ -> assert false in
993
994  match cls with
995  | [] -> assert false
996  | (p::_,_ as cl)::rem ->
997      if group_constructor p then
998        split_exc (pat_as_constr p) [cl] rem
999      else
1000        split_noexc [cl] rem
1001  | _ -> assert false
1002
1003and split_constr cls args def k =
1004  let ex_pat = what_is_cases cls in
1005  match ex_pat.pat_desc with
1006  | Tpat_any -> precompile_var args cls def k
1007  | Tpat_construct (_,{cstr_tag=Cstr_extension _},_) ->
1008      split_naive cls args def k
1009  | _ ->
1010
1011      let group = get_group ex_pat in
1012
1013      let rec split_ex yes no = function
1014        | [] ->
1015            let yes = List.rev yes and no = List.rev no in
1016            begin match no with
1017            | [] ->
1018                {me = Pm {cases=yes ; args=args ; default=def} ;
1019                  matrix = as_matrix yes ;
1020                  top_default = def},
1021                k
1022            | cl::rem ->
1023                begin match yes with
1024                | [] ->
1025                    (* Could not success in raising up a constr matching up *)
1026                    split_noex [cl] [] rem
1027                | _ ->
1028                    let {me=next ; matrix=matrix ; top_default=def}, nexts =
1029                      split_noex [cl] [] rem in
1030                    let idef = next_raise_count () in
1031                    let def = cons_default matrix idef def in
1032                    {me = Pm {cases=yes ; args=args ; default=def} ;
1033                      matrix = as_matrix yes ;
1034                      top_default = def },
1035                    (idef, next)::nexts
1036                end
1037            end
1038        | (p::_,_) as cl::rem ->
1039            if group p && up_ok cl no then
1040              split_ex (cl::yes) no rem
1041            else
1042              split_ex yes (cl::no) rem
1043        | _ -> assert false
1044
1045      and split_noex yes no = function
1046        | [] ->
1047            let yes = List.rev yes and no = List.rev no in
1048            begin match no with
1049            | [] -> precompile_var args yes def k
1050            | cl::rem ->
1051                let {me=next ; matrix=matrix ; top_default=def}, nexts =
1052                  split_ex [cl] [] rem in
1053                let idef = next_raise_count () in
1054                precompile_var
1055                  args yes
1056                  (cons_default matrix idef def)
1057                  ((idef,next)::nexts)
1058            end
1059        | [ps,_ as cl]
1060            when List.for_all group_var ps && yes <> [] ->
1061       (* This enables an extra division in some frequent cases :
1062          last row is made of variables only *)
1063              split_noex yes (cl::no) []
1064        | (p::_,_) as cl::rem ->
1065            if not (group p) && up_ok cl no then
1066              split_noex (cl::yes) no rem
1067            else
1068              split_noex yes (cl::no) rem
1069        | _ -> assert false in
1070
1071      match cls with
1072      | ((p::_,_) as cl)::rem ->
1073          if group p then split_ex [cl] [] rem
1074          else split_noex [cl] [] rem
1075      | _ ->  assert false
1076
1077and precompile_var  args cls def k = match args with
1078| []  -> assert false
1079| _::((Lvar v as av,_) as arg)::rargs ->
1080    begin match cls with
1081    | [_] -> (* as splitted as it can *)
1082        dont_precompile_var args cls def k
1083    | _ ->
1084(* Precompile *)
1085        let var_cls =
1086          List.map
1087            (fun (ps,act) -> match ps with
1088            | _::ps -> ps,act | _     -> assert false)
1089            cls
1090        and var_def = make_default (fun _ rem -> rem) def in
1091        let {me=first ; matrix=matrix}, nexts =
1092          split_or (Some v) var_cls (arg::rargs) var_def in
1093
1094(* Compute top information *)
1095        match nexts with
1096        | [] -> (* If you need *)
1097            dont_precompile_var args cls def k
1098        | _  ->
1099            let rfirst =
1100              {me = PmVar {inside=first ; var_arg = av} ;
1101                matrix = add_omega_column matrix ;
1102                top_default = rebuild_default nexts def ; }
1103            and rnexts = rebuild_nexts av nexts k in
1104            rfirst, rnexts
1105    end
1106|  _ ->
1107    dont_precompile_var args cls def k
1108
1109and dont_precompile_var args cls def k =
1110  {me =  Pm {cases = cls ; args = args ; default = def } ;
1111    matrix=as_matrix cls ;
1112    top_default=def},k
1113
1114and is_exc p = match p.pat_desc with
1115| Tpat_or (p1,p2,_) -> is_exc p1 || is_exc p2
1116| Tpat_alias (p,_,_) -> is_exc p
1117| Tpat_construct (_,{cstr_tag=Cstr_extension _},_) -> true
1118| _ -> false
1119
1120and precompile_or argo cls ors args def k = match ors with
1121| [] -> split_constr cls args def k
1122| _  ->
1123    let rec do_cases = function
1124      | ({pat_desc=Tpat_or _} as orp::patl, action)::rem ->
1125          let do_opt = not (is_exc orp) in
1126          let others,rem =
1127            if do_opt then get_equiv orp rem
1128            else [],rem in
1129          let orpm =
1130            {cases =
1131              (patl, action)::
1132              List.map
1133                (function
1134                  | (_::ps,action) -> ps,action
1135                  | _ -> assert false)
1136                others ;
1137              args = (match args with _::r -> r | _ -> assert false) ;
1138              default = default_compat (if do_opt then orp else omega) def} in
1139          let vars =
1140            IdentSet.elements
1141              (IdentSet.inter
1142                 (extract_vars IdentSet.empty orp)
1143                 (pm_free_variables orpm)) in
1144          let or_num = next_raise_count () in
1145          let new_patl = Parmatch.omega_list patl in
1146
1147          let mk_new_action vs =
1148            Lstaticraise
1149              (or_num, List.map (fun v -> Lvar v) vs) in
1150
1151          let do_optrec,body,handlers = do_cases rem in
1152          do_opt && do_optrec,
1153          explode_or_pat
1154            argo new_patl mk_new_action body vars [] orp,
1155          let mat = if do_opt then [[orp]] else [[omega]] in
1156          ((mat, or_num, vars , orpm):: handlers)
1157      | cl::rem ->
1158          let b,new_ord,new_to_catch = do_cases rem in
1159          b,cl::new_ord,new_to_catch
1160      | [] -> true,[],[] in
1161
1162    let do_opt,end_body, handlers = do_cases ors in
1163    let matrix = (if do_opt then as_matrix else as_matrix_omega) (cls@ors)
1164    and body = {cases=cls@end_body ; args=args ; default=def} in
1165    {me = PmOr {body=body ; handlers=handlers ; or_matrix=matrix} ;
1166      matrix=matrix ;
1167      top_default=def},
1168    k
1169
1170let split_precompile argo pm =
1171  let {me=next}, nexts = split_or argo pm.cases pm.args pm.default  in
1172  if dbg && (nexts <> [] || (match next with PmOr _ -> true | _ -> false))
1173  then begin
1174    prerr_endline "** SPLIT **" ;
1175    pretty_pm pm ;
1176    pretty_precompiled_res  next nexts
1177  end ;
1178  next, nexts
1179
1180
1181(* General divide functions *)
1182
1183let add_line patl_action pm = pm.cases <- patl_action :: pm.cases; pm
1184
1185type cell =
1186  {pm : pattern_matching ;
1187  ctx : ctx list ;
1188  pat : pattern}
1189
1190let add make_matching_fun division eq_key key patl_action args =
1191  try
1192    let (_,cell) = List.find (fun (k,_) -> eq_key key k) division in
1193    cell.pm.cases <- patl_action :: cell.pm.cases;
1194    division
1195  with Not_found ->
1196    let cell = make_matching_fun args in
1197    cell.pm.cases <- [patl_action] ;
1198    (key, cell) :: division
1199
1200
1201let divide make eq_key get_key get_args ctx pm =
1202
1203  let rec divide_rec = function
1204    | (p::patl,action) :: rem ->
1205        let this_match = divide_rec rem in
1206        add
1207          (make p pm.default ctx)
1208          this_match eq_key (get_key p) (get_args p patl,action) pm.args
1209    | _ -> [] in
1210
1211  divide_rec pm.cases
1212
1213
1214let divide_line make_ctx make get_args pat ctx pm =
1215  let rec divide_rec = function
1216    | (p::patl,action) :: rem ->
1217        let this_match = divide_rec rem in
1218        add_line (get_args p patl, action) this_match
1219    | _ -> make pm.default pm.args in
1220
1221  {pm = divide_rec pm.cases ;
1222  ctx=make_ctx ctx ;
1223  pat=pat}
1224
1225
1226
1227(* Then come various functions,
1228   There is one set of functions per matching style
1229   (constants, constructors etc.)
1230
1231   - matcher functions are arguments to make_default (for default handlers)
1232   They may raise NoMatch or OrPat and perform the full
1233   matching (selection + arguments).
1234
1235
1236   - get_args and get_key are for the compiled matrices, note that
1237   selection and getting arguments are separated.
1238
1239   - make_ _matching combines the previous functions for producing
1240   new  ``pattern_matching'' records.
1241*)
1242
1243
1244
1245let rec matcher_const cst p rem = match p.pat_desc with
1246| Tpat_or (p1,p2,_) ->
1247    begin try
1248      matcher_const cst p1 rem with
1249    | NoMatch -> matcher_const cst p2 rem
1250    end
1251| Tpat_constant c1 when const_compare c1 cst = 0 -> rem
1252| Tpat_any    -> rem
1253| _ -> raise NoMatch
1254
1255let get_key_constant caller = function
1256  | {pat_desc= Tpat_constant cst} -> cst
1257  | p ->
1258      prerr_endline ("BAD: "^caller) ;
1259      pretty_pat p ;
1260      assert false
1261
1262let get_args_constant _ rem = rem
1263
1264let make_constant_matching p def ctx = function
1265    [] -> fatal_error "Matching.make_constant_matching"
1266  | (_ :: argl) ->
1267      let def =
1268        make_default
1269          (matcher_const (get_key_constant "make" p)) def
1270      and ctx =
1271        filter_ctx p  ctx in
1272      {pm = {cases = []; args = argl ; default = def} ;
1273        ctx = ctx ;
1274        pat = normalize_pat p}
1275
1276
1277
1278
1279let divide_constant ctx m =
1280  divide
1281    make_constant_matching
1282    (fun c d -> const_compare c d = 0) (get_key_constant "divide")
1283    get_args_constant
1284    ctx m
1285
1286(* Matching against a constructor *)
1287
1288
1289let make_field_args loc binding_kind arg first_pos last_pos argl =
1290  let rec make_args pos =
1291    if pos > last_pos
1292    then argl
1293    else (Lprim(Pfield pos, [arg], loc), binding_kind) :: make_args (pos + 1)
1294  in make_args first_pos
1295
1296let get_key_constr = function
1297  | {pat_desc=Tpat_construct (_, cstr,_)} -> cstr.cstr_tag
1298  | _ -> assert false
1299
1300let get_args_constr p rem = match p with
1301| {pat_desc=Tpat_construct (_, _, args)} -> args @ rem
1302| _ -> assert false
1303
1304let matcher_constr cstr = match cstr.cstr_arity with
1305| 0 ->
1306    let rec matcher_rec q rem = match q.pat_desc with
1307    | Tpat_or (p1,p2,_) ->
1308        begin
1309          try
1310            matcher_rec p1 rem
1311          with
1312          | NoMatch -> matcher_rec p2 rem
1313        end
1314    | Tpat_construct (_, cstr1, []) when cstr.cstr_tag = cstr1.cstr_tag ->
1315        rem
1316    | Tpat_any -> rem
1317    | _ -> raise NoMatch in
1318    matcher_rec
1319| 1 ->
1320    let rec matcher_rec q rem = match q.pat_desc with
1321    | Tpat_or (p1,p2,_) ->
1322        let r1 = try Some (matcher_rec p1 rem) with NoMatch -> None
1323        and r2 = try Some (matcher_rec p2 rem) with NoMatch -> None in
1324        begin match r1,r2 with
1325        | None, None -> raise NoMatch
1326        | Some r1, None -> r1
1327        | None, Some r2 -> r2
1328        | Some (a1::_), Some (a2::_) ->
1329            {a1 with
1330             pat_loc = Location.none ;
1331             pat_desc = Tpat_or (a1, a2, None)}::
1332            rem
1333        | _, _ -> assert false
1334        end
1335    | Tpat_construct (_, cstr1, [arg])
1336      when cstr.cstr_tag = cstr1.cstr_tag -> arg::rem
1337    | Tpat_any -> omega::rem
1338    | _ -> raise NoMatch in
1339    matcher_rec
1340| _ ->
1341    fun q rem -> match q.pat_desc with
1342    | Tpat_or (_,_,_) -> raise OrPat
1343    | Tpat_construct (_, cstr1, args)
1344      when cstr.cstr_tag = cstr1.cstr_tag -> args @ rem
1345    | Tpat_any -> Parmatch.omegas cstr.cstr_arity @ rem
1346    | _        -> raise NoMatch
1347
1348let make_constr_matching p def ctx = function
1349    [] -> fatal_error "Matching.make_constr_matching"
1350  | ((arg, _mut) :: argl) ->
1351      let cstr = pat_as_constr p in
1352      let newargs =
1353        if cstr.cstr_inlined <> None then
1354          (arg, Alias) :: argl
1355        else match cstr.cstr_tag with
1356          Cstr_constant _ | Cstr_block _ ->
1357            make_field_args p.pat_loc Alias arg 0 (cstr.cstr_arity - 1) argl
1358        | Cstr_unboxed -> (arg, Alias) :: argl
1359        | Cstr_extension _ ->
1360            make_field_args p.pat_loc Alias arg 1 cstr.cstr_arity argl in
1361      {pm=
1362        {cases = []; args = newargs;
1363          default = make_default (matcher_constr cstr) def} ;
1364        ctx =  filter_ctx p ctx ;
1365        pat=normalize_pat p}
1366
1367
1368let divide_constructor ctx pm =
1369  divide
1370    make_constr_matching
1371    (=) get_key_constr get_args_constr
1372    ctx pm
1373
1374(* Matching against a variant *)
1375
1376let rec matcher_variant_const lab p rem = match p.pat_desc with
1377| Tpat_or (p1, p2, _) ->
1378    begin
1379      try
1380        matcher_variant_const lab p1 rem
1381      with
1382      | NoMatch -> matcher_variant_const lab p2 rem
1383    end
1384| Tpat_variant (lab1,_,_) when lab1=lab -> rem
1385| Tpat_any -> rem
1386| _   -> raise NoMatch
1387
1388
1389let make_variant_matching_constant p lab def ctx = function
1390    [] -> fatal_error "Matching.make_variant_matching_constant"
1391  | (_ :: argl) ->
1392      let def = make_default (matcher_variant_const lab) def
1393      and ctx = filter_ctx p ctx in
1394      {pm={ cases = []; args = argl ; default=def} ;
1395        ctx=ctx ;
1396        pat = normalize_pat p}
1397
1398let matcher_variant_nonconst lab p rem = match p.pat_desc with
1399| Tpat_or (_,_,_) -> raise OrPat
1400| Tpat_variant (lab1,Some arg,_) when lab1=lab -> arg::rem
1401| Tpat_any -> omega::rem
1402| _   -> raise NoMatch
1403
1404
1405let make_variant_matching_nonconst p lab def ctx = function
1406    [] -> fatal_error "Matching.make_variant_matching_nonconst"
1407  | ((arg, _mut) :: argl) ->
1408      let def = make_default (matcher_variant_nonconst lab) def
1409      and ctx = filter_ctx p ctx in
1410      {pm=
1411        {cases = []; args = (Lprim(Pfield 1, [arg], p.pat_loc), Alias) :: argl;
1412          default=def} ;
1413        ctx=ctx ;
1414        pat = normalize_pat p}
1415
1416let divide_variant row ctx {cases = cl; args = al; default=def} =
1417  let row = Btype.row_repr row in
1418  let rec divide = function
1419      ({pat_desc = Tpat_variant(lab, pato, _)} as p:: patl, action) :: rem ->
1420        let variants = divide rem in
1421        if try Btype.row_field_repr (List.assoc lab row.row_fields) = Rabsent
1422        with Not_found -> true
1423        then
1424          variants
1425        else begin
1426          let tag = Btype.hash_variant lab in
1427          match pato with
1428            None ->
1429              add (make_variant_matching_constant p lab def ctx) variants
1430                (=) (Cstr_constant tag) (patl, action) al
1431          | Some pat ->
1432              add (make_variant_matching_nonconst p lab def ctx) variants
1433                (=) (Cstr_block tag) (pat :: patl, action) al
1434        end
1435    | _ -> []
1436  in
1437  divide cl
1438
1439(*
1440  Three ``no-test'' cases
1441  *)
1442
1443(* Matching against a variable *)
1444
1445let get_args_var _ rem = rem
1446
1447
1448let make_var_matching def = function
1449  | [] ->  fatal_error "Matching.make_var_matching"
1450  | _::argl ->
1451      {cases=[] ;
1452        args = argl ;
1453        default= make_default get_args_var def}
1454
1455let divide_var ctx pm =
1456  divide_line ctx_lshift make_var_matching get_args_var omega ctx pm
1457
1458(* Matching and forcing a lazy value *)
1459
1460let get_arg_lazy p rem = match p with
1461| {pat_desc = Tpat_any} -> omega :: rem
1462| {pat_desc = Tpat_lazy arg} -> arg :: rem
1463| _ ->  assert false
1464
1465let matcher_lazy p rem = match p.pat_desc with
1466| Tpat_or (_,_,_)     -> raise OrPat
1467| Tpat_var _          -> get_arg_lazy omega rem
1468| _                   -> get_arg_lazy p rem
1469
1470(* Inlining the tag tests before calling the primitive that works on
1471   lazy blocks. This is also used in translcore.ml.
1472   No other call than Obj.tag when the value has been forced before.
1473*)
1474
1475let prim_obj_tag =
1476  Primitive.simple ~name:"caml_obj_tag" ~arity:1 ~alloc:false
1477
1478let get_mod_field modname field =
1479  lazy (
1480    try
1481      let mod_ident = Ident.create_persistent modname in
1482      let env = Env.open_pers_signature modname Env.initial_safe_string in
1483      let p = try
1484        match Env.lookup_value (Longident.Lident field) env with
1485        | (Path.Pdot(_,_,i), _) -> i
1486        | _ -> fatal_error ("Primitive "^modname^"."^field^" not found.")
1487      with Not_found ->
1488        fatal_error ("Primitive "^modname^"."^field^" not found.")
1489      in
1490      Lprim(Pfield p,
1491            [Lprim(Pgetglobal mod_ident, [], Location.none)],
1492            Location.none)
1493    with Not_found -> fatal_error ("Module "^modname^" unavailable.")
1494  )
1495
1496let code_force_lazy_block =
1497  get_mod_field "CamlinternalLazy" "force_lazy_block"
1498;;
1499
1500(* inline_lazy_force inlines the beginning of the code of Lazy.force. When
1501   the value argument is tagged as:
1502   - forward, take field 0
1503   - lazy, call the primitive that forces (without testing again the tag)
1504   - anything else, return it
1505
1506   Using Lswitch below relies on the fact that the GC does not shortcut
1507   Forward(val_out_of_heap).
1508*)
1509
1510let inline_lazy_force_cond arg loc =
1511  let idarg = Ident.create "lzarg" in
1512  let varg = Lvar idarg in
1513  let tag = Ident.create "tag" in
1514  let force_fun = Lazy.force code_force_lazy_block in
1515  Llet(Strict, Pgenval, idarg, arg,
1516       Llet(Alias, Pgenval, tag, Lprim(Pccall prim_obj_tag, [varg], loc),
1517            Lifthenelse(
1518              (* if (tag == Obj.forward_tag) then varg.(0) else ... *)
1519              Lprim(Pintcomp Ceq,
1520                    [Lvar tag; Lconst(Const_base(Const_int Obj.forward_tag))],
1521                    loc),
1522              Lprim(Pfield 0, [varg], loc),
1523              Lifthenelse(
1524                (* ... if (tag == Obj.lazy_tag) then Lazy.force varg else ... *)
1525                Lprim(Pintcomp Ceq,
1526                      [Lvar tag; Lconst(Const_base(Const_int Obj.lazy_tag))],
1527                      loc),
1528                Lapply{ap_should_be_tailcall=false;
1529                       ap_loc=loc;
1530                       ap_func=force_fun;
1531                       ap_args=[varg];
1532                       ap_inlined=Default_inline;
1533                       ap_specialised=Default_specialise},
1534                (* ... arg *)
1535                  varg))))
1536
1537let inline_lazy_force_switch arg loc =
1538  let idarg = Ident.create "lzarg" in
1539  let varg = Lvar idarg in
1540  let force_fun = Lazy.force code_force_lazy_block in
1541  Llet(Strict, Pgenval, idarg, arg,
1542       Lifthenelse(
1543         Lprim(Pisint, [varg], loc), varg,
1544         (Lswitch
1545            (varg,
1546             { sw_numconsts = 0; sw_consts = [];
1547               sw_numblocks = 256;  (* PR#6033 - tag ranges from 0 to 255 *)
1548               sw_blocks =
1549                 [ (Obj.forward_tag, Lprim(Pfield 0, [varg], loc));
1550                   (Obj.lazy_tag,
1551                    Lapply{ap_should_be_tailcall=false;
1552                           ap_loc=loc;
1553                           ap_func=force_fun;
1554                           ap_args=[varg];
1555                           ap_inlined=Default_inline;
1556                           ap_specialised=Default_specialise}) ];
1557               sw_failaction = Some varg } ))))
1558
1559let inline_lazy_force arg loc =
1560  if !Clflags.native_code then
1561    (* Lswitch generates compact and efficient native code *)
1562    inline_lazy_force_switch arg loc
1563  else
1564    (* generating bytecode: Lswitch would generate too many rather big
1565       tables (~ 250 elts); conditionals are better *)
1566    inline_lazy_force_cond arg loc
1567
1568let make_lazy_matching def = function
1569    [] -> fatal_error "Matching.make_lazy_matching"
1570  | (arg,_mut) :: argl ->
1571      { cases = [];
1572        args =
1573          (inline_lazy_force arg Location.none, Strict) :: argl;
1574        default = make_default matcher_lazy def }
1575
1576let divide_lazy p ctx pm =
1577  divide_line
1578    (filter_ctx p)
1579    make_lazy_matching
1580    get_arg_lazy
1581    p ctx pm
1582
1583(* Matching against a tuple pattern *)
1584
1585
1586let get_args_tuple arity p rem = match p with
1587| {pat_desc = Tpat_any} -> omegas arity @ rem
1588| {pat_desc = Tpat_tuple args} ->
1589    args @ rem
1590| _ ->  assert false
1591
1592let matcher_tuple arity p rem = match p.pat_desc with
1593| Tpat_or (_,_,_)     -> raise OrPat
1594| Tpat_var _          -> get_args_tuple arity omega rem
1595| _                   ->  get_args_tuple arity p rem
1596
1597let make_tuple_matching loc arity def = function
1598    [] -> fatal_error "Matching.make_tuple_matching"
1599  | (arg, _mut) :: argl ->
1600      let rec make_args pos =
1601        if pos >= arity
1602        then argl
1603        else (Lprim(Pfield pos, [arg], loc), Alias) :: make_args (pos + 1) in
1604      {cases = []; args = make_args 0 ;
1605        default=make_default (matcher_tuple arity) def}
1606
1607
1608let divide_tuple arity p ctx pm =
1609  divide_line
1610    (filter_ctx p)
1611    (make_tuple_matching p.pat_loc arity)
1612    (get_args_tuple  arity) p ctx pm
1613
1614(* Matching against a record pattern *)
1615
1616
1617let record_matching_line num_fields lbl_pat_list =
1618  let patv = Array.make num_fields omega in
1619  List.iter (fun (_, lbl, pat) -> patv.(lbl.lbl_pos) <- pat) lbl_pat_list;
1620  Array.to_list patv
1621
1622let get_args_record num_fields p rem = match p with
1623| {pat_desc=Tpat_any} ->
1624    record_matching_line num_fields [] @ rem
1625| {pat_desc=Tpat_record (lbl_pat_list,_)} ->
1626    record_matching_line num_fields lbl_pat_list @ rem
1627| _ -> assert false
1628
1629let matcher_record num_fields p rem = match p.pat_desc with
1630| Tpat_or (_,_,_) -> raise OrPat
1631| Tpat_var _      -> get_args_record num_fields omega rem
1632| _               -> get_args_record num_fields p rem
1633
1634let make_record_matching loc all_labels def = function
1635    [] -> fatal_error "Matching.make_record_matching"
1636  | ((arg, _mut) :: argl) ->
1637      let rec make_args pos =
1638        if pos >= Array.length all_labels then argl else begin
1639          let lbl = all_labels.(pos) in
1640          let access =
1641            match lbl.lbl_repres with
1642            | Record_regular | Record_inlined _ ->
1643              Lprim (Pfield lbl.lbl_pos, [arg], loc)
1644            | Record_unboxed _ -> arg
1645            | Record_float -> Lprim (Pfloatfield lbl.lbl_pos, [arg], loc)
1646            | Record_extension -> Lprim (Pfield (lbl.lbl_pos + 1), [arg], loc)
1647          in
1648          let str =
1649            match lbl.lbl_mut with
1650              Immutable -> Alias
1651            | Mutable -> StrictOpt in
1652          (access, str) :: make_args(pos + 1)
1653        end in
1654      let nfields = Array.length all_labels in
1655      let def= make_default (matcher_record nfields) def in
1656      {cases = []; args = make_args 0 ; default = def}
1657
1658
1659let divide_record all_labels p ctx pm =
1660  let get_args = get_args_record (Array.length all_labels) in
1661  divide_line
1662    (filter_ctx p)
1663    (make_record_matching p.pat_loc all_labels)
1664    get_args
1665    p ctx pm
1666
1667(* Matching against an array pattern *)
1668
1669let get_key_array = function
1670  | {pat_desc=Tpat_array patl} -> List.length patl
1671  | _ -> assert false
1672
1673let get_args_array p rem = match p with
1674| {pat_desc=Tpat_array patl} -> patl@rem
1675| _ -> assert false
1676
1677let matcher_array len p rem = match p.pat_desc with
1678| Tpat_or (_,_,_) -> raise OrPat
1679| Tpat_array args when List.length args=len -> args @ rem
1680| Tpat_any -> Parmatch.omegas len @ rem
1681| _ -> raise NoMatch
1682
1683let make_array_matching kind p def ctx = function
1684  | [] -> fatal_error "Matching.make_array_matching"
1685  | ((arg, _mut) :: argl) ->
1686      let len = get_key_array p in
1687      let rec make_args pos =
1688        if pos >= len
1689        then argl
1690        else (Lprim(Parrayrefu kind,
1691                    [arg; Lconst(Const_base(Const_int pos))],
1692                    p.pat_loc),
1693              StrictOpt) :: make_args (pos + 1) in
1694      let def = make_default (matcher_array len) def
1695      and ctx = filter_ctx p ctx in
1696      {pm={cases = []; args = make_args 0 ; default = def} ;
1697        ctx=ctx ;
1698        pat = normalize_pat p}
1699
1700let divide_array kind ctx pm =
1701  divide
1702    (make_array_matching kind)
1703    (=) get_key_array get_args_array ctx pm
1704
1705
1706(*
1707   Specific string test sequence
1708   Will be called by the bytecode compiler, from bytegen.ml.
1709   The strategy is first dichotomic search (we perform 3-way tests
1710   with compare_string), then sequence of equality tests
1711   when there are less then T=strings_test_threshold static strings to match.
1712
1713  Increasing T entails (slightly) less code, decreasing T
1714  (slightly) favors runtime speed.
1715  T=8 looks a decent tradeoff.
1716*)
1717
1718(* Utilities *)
1719
1720let strings_test_threshold = 8
1721
1722let prim_string_notequal =
1723  Pccall(Primitive.simple
1724           ~name:"caml_string_notequal"
1725           ~arity:2
1726           ~alloc:false)
1727
1728let prim_string_compare =
1729  Pccall(Primitive.simple
1730           ~name:"caml_string_compare"
1731           ~arity:2
1732           ~alloc:false)
1733
1734let bind_sw arg k = match arg with
1735| Lvar _ -> k arg
1736| _ ->
1737    let id = Ident.create "switch" in
1738    Llet (Strict,Pgenval,id,arg,k (Lvar id))
1739
1740
1741(* Sequential equality tests *)
1742
1743let make_string_test_sequence loc arg sw d =
1744  let d,sw = match d with
1745  | None ->
1746      begin match sw with
1747      | (_,d)::sw -> d,sw
1748      | [] -> assert false
1749      end
1750  | Some d -> d,sw in
1751  bind_sw arg
1752    (fun arg ->
1753      List.fold_right
1754        (fun (s,lam) k ->
1755          Lifthenelse
1756            (Lprim
1757               (prim_string_notequal,
1758                [arg; Lconst (Const_immstring s)], loc),
1759             k,lam))
1760        sw d)
1761
1762let rec split k xs = match xs with
1763| [] -> assert false
1764| x0::xs ->
1765    if k <= 1 then [],x0,xs
1766    else
1767      let xs,y0,ys = split (k-2) xs in
1768      x0::xs,y0,ys
1769
1770let zero_lam  = Lconst (Const_base (Const_int 0))
1771
1772let tree_way_test loc arg lt eq gt =
1773  Lifthenelse
1774    (Lprim (Pintcomp Clt,[arg;zero_lam], loc),lt,
1775     Lifthenelse(Lprim (Pintcomp Clt,[zero_lam;arg], loc),gt,eq))
1776
1777(* Dichotomic tree *)
1778
1779
1780let rec do_make_string_test_tree loc arg sw delta d =
1781  let len = List.length sw in
1782  if len <= strings_test_threshold+delta then
1783    make_string_test_sequence loc arg sw d
1784  else
1785    let lt,(s,act),gt = split len sw in
1786    bind_sw
1787      (Lprim
1788         (prim_string_compare,
1789          [arg; Lconst (Const_immstring s)], loc;))
1790      (fun r ->
1791        tree_way_test loc r
1792          (do_make_string_test_tree loc arg lt delta d)
1793          act
1794          (do_make_string_test_tree loc arg gt delta d))
1795
1796(* Entry point *)
1797let expand_stringswitch loc arg sw d = match d with
1798| None ->
1799    bind_sw arg
1800      (fun arg -> do_make_string_test_tree loc arg sw 0 None)
1801| Some e ->
1802    bind_sw arg
1803      (fun arg ->
1804        make_catch e
1805          (fun d -> do_make_string_test_tree loc arg sw 1 (Some d)))
1806
1807(**********************)
1808(* Generic test trees *)
1809(**********************)
1810
1811(* Sharing *)
1812
1813(* Add handler, if shared *)
1814let handle_shared () =
1815  let hs = ref (fun x -> x) in
1816  let handle_shared act = match act with
1817  | Switch.Single act -> act
1818  | Switch.Shared act ->
1819      let i,h = make_catch_delayed act in
1820      let ohs = !hs in
1821      hs := (fun act -> h (ohs act)) ;
1822      make_exit i in
1823  hs,handle_shared
1824
1825
1826let share_actions_tree sw d =
1827  let store = StoreExp.mk_store () in
1828(* Default action is always shared *)
1829  let d =
1830    match d with
1831    | None -> None
1832    | Some d -> Some (store.Switch.act_store_shared d) in
1833(* Store all other actions *)
1834  let sw =
1835    List.map  (fun (cst,act) -> cst,store.Switch.act_store act) sw in
1836
1837(* Retrieve all actions, including potentiel default *)
1838  let acts = store.Switch.act_get_shared () in
1839
1840(* Array of actual actions *)
1841  let hs,handle_shared = handle_shared () in
1842  let acts = Array.map handle_shared acts in
1843
1844(* Reconstruct default and switch list *)
1845  let d = match d with
1846  | None -> None
1847  | Some d -> Some (acts.(d)) in
1848  let sw = List.map (fun (cst,j) -> cst,acts.(j)) sw in
1849  !hs,sw,d
1850
1851(* Note: dichotomic search requires sorted input with no duplicates *)
1852let rec uniq_lambda_list sw = match sw with
1853  | []|[_] -> sw
1854  | (c1,_ as p1)::((c2,_)::sw2 as sw1) ->
1855      if const_compare c1 c2 = 0 then uniq_lambda_list (p1::sw2)
1856      else p1::uniq_lambda_list sw1
1857
1858let sort_lambda_list l =
1859  let l =
1860    List.stable_sort (fun (x,_) (y,_) -> const_compare x y) l in
1861  uniq_lambda_list l
1862
1863let rec cut n l =
1864  if n = 0 then [],l
1865  else match l with
1866    [] -> raise (Invalid_argument "cut")
1867  | a::l -> let l1,l2 = cut (n-1) l in a::l1, l2
1868
1869let rec do_tests_fail loc fail tst arg = function
1870  | [] -> fail
1871  | (c, act)::rem ->
1872      Lifthenelse
1873        (Lprim (tst, [arg ; Lconst (Const_base c)], loc),
1874         do_tests_fail loc fail tst arg rem,
1875         act)
1876
1877let rec do_tests_nofail loc tst arg = function
1878  | [] -> fatal_error "Matching.do_tests_nofail"
1879  | [_,act] -> act
1880  | (c,act)::rem ->
1881      Lifthenelse
1882        (Lprim (tst, [arg ; Lconst (Const_base c)], loc),
1883         do_tests_nofail loc tst arg rem,
1884         act)
1885
1886let make_test_sequence loc fail tst lt_tst arg const_lambda_list =
1887  let const_lambda_list = sort_lambda_list const_lambda_list in
1888  let hs,const_lambda_list,fail =
1889    share_actions_tree const_lambda_list fail in
1890
1891  let rec make_test_sequence const_lambda_list =
1892    if List.length const_lambda_list >= 4 && lt_tst <> Pignore then
1893      split_sequence const_lambda_list
1894    else match fail with
1895    | None -> do_tests_nofail loc tst arg const_lambda_list
1896    | Some fail -> do_tests_fail loc fail tst arg const_lambda_list
1897
1898  and split_sequence const_lambda_list =
1899    let list1, list2 =
1900      cut (List.length const_lambda_list / 2) const_lambda_list in
1901    Lifthenelse(Lprim(lt_tst,
1902                      [arg; Lconst(Const_base (fst(List.hd list2)))],
1903                      loc),
1904                make_test_sequence list1, make_test_sequence list2)
1905  in
1906  hs (make_test_sequence const_lambda_list)
1907
1908
1909module SArg = struct
1910  type primitive = Lambda.primitive
1911
1912  let eqint = Pintcomp Ceq
1913  let neint = Pintcomp Cneq
1914  let leint = Pintcomp Cle
1915  let ltint = Pintcomp Clt
1916  let geint = Pintcomp Cge
1917  let gtint = Pintcomp Cgt
1918
1919  type act = Lambda.lambda
1920
1921  let make_prim p args = Lprim (p,args,Location.none)
1922  let make_offset arg n = match n with
1923  | 0 -> arg
1924  | _ -> Lprim (Poffsetint n,[arg],Location.none)
1925
1926  let bind arg body =
1927    let newvar,newarg = match arg with
1928    | Lvar v -> v,arg
1929    | _      ->
1930        let newvar = Ident.create "switcher" in
1931        newvar,Lvar newvar in
1932    bind Alias newvar arg (body newarg)
1933  let make_const i = Lconst (Const_base (Const_int i))
1934  let make_isout h arg = Lprim (Pisout, [h ; arg],Location.none)
1935  let make_isin h arg = Lprim (Pnot,[make_isout h arg],Location.none)
1936  let make_if cond ifso ifnot = Lifthenelse (cond, ifso, ifnot)
1937  let make_switch arg cases acts =
1938    let l = ref [] in
1939    for i = Array.length cases-1 downto 0 do
1940      l := (i,acts.(cases.(i))) ::  !l
1941    done ;
1942    Lswitch(arg,
1943            {sw_numconsts = Array.length cases ; sw_consts = !l ;
1944             sw_numblocks = 0 ; sw_blocks =  []  ;
1945             sw_failaction = None})
1946  let make_catch  = make_catch_delayed
1947  let make_exit = make_exit
1948
1949end
1950
1951(* Action sharing for Lswitch argument *)
1952let share_actions_sw sw =
1953(* Attempt sharing on all actions *)
1954  let store = StoreExp.mk_store () in
1955  let fail = match sw.sw_failaction with
1956  | None -> None
1957  | Some fail ->
1958      (* Fail is translated to exit, whatever happens *)
1959      Some (store.Switch.act_store_shared fail) in
1960  let consts =
1961    List.map
1962      (fun (i,e) -> i,store.Switch.act_store e)
1963      sw.sw_consts
1964  and blocks =
1965    List.map
1966      (fun (i,e) -> i,store.Switch.act_store e)
1967      sw.sw_blocks in
1968  let acts = store.Switch.act_get_shared () in
1969  let hs,handle_shared = handle_shared () in
1970  let acts = Array.map handle_shared acts in
1971  let fail = match fail with
1972  | None -> None
1973  | Some fail -> Some (acts.(fail)) in
1974  !hs,
1975  { sw with
1976    sw_consts = List.map (fun (i,j) -> i,acts.(j)) consts ;
1977    sw_blocks = List.map (fun (i,j) -> i,acts.(j)) blocks ;
1978    sw_failaction = fail; }
1979
1980(* Reintroduce fail action in switch argument,
1981   for the sake of avoiding carrying over huge switches *)
1982
1983let reintroduce_fail sw = match sw.sw_failaction with
1984| None ->
1985    let t = Hashtbl.create 17 in
1986    let seen (_,l) = match as_simple_exit l with
1987    | Some i ->
1988        let old = try Hashtbl.find t i with Not_found -> 0 in
1989        Hashtbl.replace t i (old+1)
1990    | None -> () in
1991    List.iter seen sw.sw_consts ;
1992    List.iter seen sw.sw_blocks ;
1993    let i_max = ref (-1)
1994    and max = ref (-1) in
1995    Hashtbl.iter
1996      (fun i c ->
1997        if c > !max then begin
1998          i_max := i ;
1999          max := c
2000        end) t ;
2001    if !max >= 3 then
2002      let default = !i_max in
2003      let remove =
2004        List.filter
2005          (fun (_,lam) -> match as_simple_exit lam with
2006          | Some j -> j <> default
2007          | None -> true) in
2008      {sw with
2009       sw_consts = remove sw.sw_consts ;
2010       sw_blocks = remove sw.sw_blocks ;
2011       sw_failaction = Some (make_exit default)}
2012    else sw
2013| Some _ -> sw
2014
2015
2016module Switcher = Switch.Make(SArg)
2017open Switch
2018
2019let rec last def = function
2020  | [] -> def
2021  | [x,_] -> x
2022  | _::rem -> last def rem
2023
2024let get_edges low high l = match l with
2025| [] -> low, high
2026| (x,_)::_ -> x, last high l
2027
2028
2029let as_interval_canfail fail low high l =
2030  let store = StoreExp.mk_store () in
2031
2032  let do_store _tag act =
2033
2034    let i =  store.act_store act in
2035(*
2036    eprintf "STORE [%s] %i %s\n" tag i (string_of_lam act) ;
2037*)
2038    i in
2039
2040  let rec nofail_rec cur_low cur_high cur_act = function
2041    | [] ->
2042        if cur_high = high then
2043          [cur_low,cur_high,cur_act]
2044        else
2045          [(cur_low,cur_high,cur_act) ; (cur_high+1,high, 0)]
2046    | ((i,act_i)::rem) as all ->
2047        let act_index = do_store "NO" act_i in
2048        if cur_high+1= i then
2049          if act_index=cur_act then
2050            nofail_rec cur_low i cur_act rem
2051          else if act_index=0 then
2052            (cur_low,i-1, cur_act)::fail_rec i i rem
2053          else
2054            (cur_low, i-1, cur_act)::nofail_rec i i act_index rem
2055        else if act_index = 0 then
2056          (cur_low, cur_high, cur_act)::
2057          fail_rec (cur_high+1) (cur_high+1) all
2058        else
2059          (cur_low, cur_high, cur_act)::
2060          (cur_high+1,i-1,0)::
2061          nofail_rec i i act_index rem
2062
2063  and fail_rec cur_low cur_high = function
2064    | [] -> [(cur_low, cur_high, 0)]
2065    | (i,act_i)::rem ->
2066        let index = do_store "YES" act_i in
2067        if index=0 then fail_rec cur_low i rem
2068        else
2069          (cur_low,i-1,0)::
2070          nofail_rec i i index rem in
2071
2072  let init_rec = function
2073    | [] -> [low,high,0]
2074    | (i,act_i)::rem ->
2075        let index = do_store "INIT" act_i in
2076        if index=0 then
2077          fail_rec low i rem
2078        else
2079          if low < i then
2080            (low,i-1,0)::nofail_rec i i index rem
2081          else
2082            nofail_rec i i index rem in
2083
2084  assert (do_store "FAIL" fail = 0) ; (* fail has action index 0 *)
2085  let r = init_rec l in
2086  Array.of_list r,  store
2087
2088let as_interval_nofail l =
2089  let store = StoreExp.mk_store () in
2090  let rec some_hole = function
2091    | []|[_] -> false
2092    | (i,_)::((j,_)::_ as rem) ->
2093        j > i+1 || some_hole rem in
2094  let rec i_rec cur_low cur_high cur_act = function
2095    | [] ->
2096        [cur_low, cur_high, cur_act]
2097    | (i,act)::rem ->
2098        let act_index = store.act_store act in
2099        if act_index = cur_act then
2100          i_rec cur_low i cur_act rem
2101        else
2102          (cur_low, cur_high, cur_act)::
2103          i_rec i i act_index rem in
2104  let inters = match l with
2105  | (i,act)::rem ->
2106      let act_index =
2107        (* In case there is some hole and that a switch is emitted,
2108           action 0 will be used as the action of unreacheable
2109           cases (cf. switch.ml, make_switch).
2110           Hence, this action will be shared *)
2111        if some_hole rem then
2112          store.act_store_shared act
2113        else
2114          store.act_store act in
2115      assert (act_index = 0) ;
2116      i_rec i i act_index rem
2117  | _ -> assert false in
2118
2119  Array.of_list inters, store
2120
2121
2122let sort_int_lambda_list l =
2123  List.sort
2124    (fun (i1,_) (i2,_) ->
2125      if i1 < i2 then -1
2126      else if i2 < i1 then 1
2127      else 0)
2128    l
2129
2130let as_interval fail low high l =
2131  let l = sort_int_lambda_list l in
2132  get_edges low high l,
2133  (match fail with
2134  | None -> as_interval_nofail l
2135  | Some act -> as_interval_canfail act low high l)
2136
2137let call_switcher fail arg low high int_lambda_list =
2138  let edges, (cases, actions) =
2139    as_interval fail low high int_lambda_list in
2140  Switcher.zyva edges arg cases actions
2141
2142
2143let rec list_as_pat = function
2144  | [] -> fatal_error "Matching.list_as_pat"
2145  | [pat] -> pat
2146  | pat::rem ->
2147      {pat with pat_desc = Tpat_or (pat,list_as_pat rem,None)}
2148
2149
2150let complete_pats_constrs = function
2151  | p::_ as pats ->
2152      List.map
2153        (pat_of_constr p)
2154        (complete_constrs p (List.map get_key_constr pats))
2155  | _ -> assert false
2156
2157
2158(*
2159     Following two ``failaction'' function compute n, the trap handler
2160    to jump to in case of failure of elementary tests
2161*)
2162
2163let mk_failaction_neg partial ctx def = match partial with
2164| Partial ->
2165    begin match def with
2166    | (_,idef)::_ ->
2167        Some (Lstaticraise (idef,[])),jumps_singleton idef ctx
2168    | [] ->
2169       (* Act as Total, this means
2170          If no appropriate default matrix exists,
2171          then this switch cannot fail *)
2172        None, jumps_empty
2173    end
2174| Total ->
2175    None, jumps_empty
2176
2177
2178
2179(* In line with the article and simpler than before *)
2180let mk_failaction_pos partial seen ctx defs  =
2181  if dbg then begin
2182    prerr_endline "**POS**" ;
2183    pretty_def defs ;
2184    ()
2185  end ;
2186  let rec scan_def env to_test defs = match to_test,defs with
2187  | ([],_)|(_,[]) ->
2188      List.fold_left
2189        (fun  (klist,jumps) (pats,i)->
2190          let action = Lstaticraise (i,[]) in
2191          let klist =
2192            List.fold_right
2193              (fun pat r -> (get_key_constr pat,action)::r)
2194              pats klist
2195          and jumps =
2196            jumps_add i (ctx_lub (list_as_pat pats) ctx) jumps in
2197          klist,jumps)
2198        ([],jumps_empty) env
2199  | _,(pss,idef)::rem ->
2200      let now, later =
2201        List.partition
2202          (fun (_p,p_ctx) -> ctx_match p_ctx pss) to_test in
2203      match now with
2204      | [] -> scan_def env to_test rem
2205      | _  -> scan_def ((List.map fst now,idef)::env) later rem in
2206
2207  let fail_pats = complete_pats_constrs seen in
2208  if List.length fail_pats < 32 then begin
2209    let fail,jmps =
2210      scan_def
2211        []
2212        (List.map
2213           (fun pat -> pat, ctx_lub pat ctx)
2214           fail_pats)
2215        defs in
2216    if dbg then begin
2217      eprintf "POSITIVE JUMPS [%i]:\n" (List.length fail_pats);
2218      pretty_jumps jmps
2219    end ;
2220    None,fail,jmps
2221  end else begin (* Too many non-matched constructors -> reduced information *)
2222    if dbg then eprintf "POS->NEG!!!\n%!" ;
2223    let fail,jumps =  mk_failaction_neg partial ctx defs in
2224    if dbg then
2225      eprintf "FAIL: %s\n"
2226        (match fail with
2227        | None -> "<none>"
2228        | Some lam -> string_of_lam lam) ;
2229    fail,[],jumps
2230  end
2231
2232let combine_constant loc arg cst partial ctx def
2233    (const_lambda_list, total, _pats) =
2234  let fail, local_jumps =
2235    mk_failaction_neg partial ctx def in
2236  let lambda1 =
2237    match cst with
2238    | Const_int _ ->
2239        let int_lambda_list =
2240          List.map (function Const_int n, l -> n,l | _ -> assert false)
2241            const_lambda_list in
2242        call_switcher fail arg min_int max_int int_lambda_list
2243    | Const_char _ ->
2244        let int_lambda_list =
2245          List.map (function Const_char c, l -> (Char.code c, l)
2246            | _ -> assert false)
2247            const_lambda_list in
2248        call_switcher fail arg 0 255 int_lambda_list
2249    | Const_string _ ->
2250(* Note as the bytecode compiler may resort to dichotomic search,
2251   the clauses of stringswitch  are sorted with duplicates removed.
2252   This partly applies to the native code compiler, which requires
2253   no duplicates *)
2254        let const_lambda_list = sort_lambda_list const_lambda_list in
2255        let sw =
2256          List.map
2257            (fun (c,act) -> match c with
2258            | Const_string (s,_) -> s,act
2259            | _ -> assert false)
2260            const_lambda_list in
2261        let hs,sw,fail = share_actions_tree sw fail in
2262        hs (Lstringswitch (arg,sw,fail,loc))
2263    | Const_float _ ->
2264        make_test_sequence loc
2265          fail
2266          (Pfloatcomp Cneq) (Pfloatcomp Clt)
2267          arg const_lambda_list
2268    | Const_int32 _ ->
2269        make_test_sequence loc
2270          fail
2271          (Pbintcomp(Pint32, Cneq)) (Pbintcomp(Pint32, Clt))
2272          arg const_lambda_list
2273    | Const_int64 _ ->
2274        make_test_sequence loc
2275          fail
2276          (Pbintcomp(Pint64, Cneq)) (Pbintcomp(Pint64, Clt))
2277          arg const_lambda_list
2278    | Const_nativeint _ ->
2279        make_test_sequence loc
2280          fail
2281          (Pbintcomp(Pnativeint, Cneq)) (Pbintcomp(Pnativeint, Clt))
2282          arg const_lambda_list
2283  in lambda1,jumps_union local_jumps total
2284
2285
2286
2287let split_cases tag_lambda_list =
2288  let rec split_rec = function
2289      [] -> ([], [])
2290    | (cstr, act) :: rem ->
2291        let (consts, nonconsts) = split_rec rem in
2292        match cstr with
2293          Cstr_constant n -> ((n, act) :: consts, nonconsts)
2294        | Cstr_block n    -> (consts, (n, act) :: nonconsts)
2295        | Cstr_unboxed    -> (consts, (0, act) :: nonconsts)
2296        | Cstr_extension _ -> assert false in
2297  let const, nonconst = split_rec tag_lambda_list in
2298  sort_int_lambda_list const,
2299  sort_int_lambda_list nonconst
2300
2301let split_extension_cases tag_lambda_list =
2302  let rec split_rec = function
2303      [] -> ([], [])
2304    | (cstr, act) :: rem ->
2305        let (consts, nonconsts) = split_rec rem in
2306        match cstr with
2307          Cstr_extension(path, true) -> ((path, act) :: consts, nonconsts)
2308        | Cstr_extension(path, false) -> (consts, (path, act) :: nonconsts)
2309        | _ -> assert false in
2310  split_rec tag_lambda_list
2311
2312
2313let combine_constructor loc arg ex_pat cstr partial ctx def
2314    (tag_lambda_list, total1, pats) =
2315  if cstr.cstr_consts < 0 then begin
2316    (* Special cases for extensions *)
2317    let fail, local_jumps =
2318      mk_failaction_neg partial ctx def in
2319    let lambda1 =
2320      let consts, nonconsts = split_extension_cases tag_lambda_list in
2321      let default, consts, nonconsts =
2322        match fail with
2323        | None ->
2324            begin match consts, nonconsts with
2325            | _, (_, act)::rem -> act, consts, rem
2326            | (_, act)::rem, _ -> act, rem, nonconsts
2327            | _ -> assert false
2328            end
2329        | Some fail -> fail, consts, nonconsts in
2330      let nonconst_lambda =
2331        match nonconsts with
2332          [] -> default
2333        | _ ->
2334            let tag = Ident.create "tag" in
2335            let tests =
2336              List.fold_right
2337                (fun (path, act) rem ->
2338                   Lifthenelse(Lprim(Pintcomp Ceq,
2339                                     [Lvar tag;
2340                                      transl_path ex_pat.pat_env path], loc),
2341                               act, rem))
2342                nonconsts
2343                default
2344            in
2345              Llet(Alias, Pgenval,tag, Lprim(Pfield 0, [arg], loc), tests)
2346      in
2347        List.fold_right
2348          (fun (path, act) rem ->
2349             Lifthenelse(Lprim(Pintcomp Ceq,
2350                               [arg; transl_path ex_pat.pat_env path], loc),
2351                         act, rem))
2352          consts
2353          nonconst_lambda
2354    in
2355    lambda1, jumps_union local_jumps total1
2356  end else begin
2357    (* Regular concrete type *)
2358    let ncases = List.length tag_lambda_list
2359    and nconstrs =  cstr.cstr_consts + cstr.cstr_nonconsts in
2360    let sig_complete = ncases = nconstrs in
2361    let fail_opt,fails,local_jumps =
2362      if sig_complete then None,[],jumps_empty
2363      else
2364        mk_failaction_pos partial pats ctx def in
2365
2366    let tag_lambda_list = fails @ tag_lambda_list in
2367    let (consts, nonconsts) = split_cases tag_lambda_list in
2368    let lambda1 =
2369      match fail_opt,same_actions tag_lambda_list with
2370      | None,Some act -> act (* Identical actions, no failure *)
2371      | _ ->
2372          match
2373            (cstr.cstr_consts, cstr.cstr_nonconsts, consts, nonconsts)
2374          with
2375          | (1, 1, [0, act1], [0, act2]) ->
2376           (* Typically, match on lists, will avoid isint primitive in that
2377              case *)
2378              Lifthenelse(arg, act2, act1)
2379          | (n,0,_,[])  -> (* The type defines constant constructors only *)
2380              call_switcher fail_opt arg 0 (n-1) consts
2381          | (n, _, _, _) ->
2382              let act0  =
2383                (* = Some act when all non-const constructors match to act *)
2384                match fail_opt,nonconsts with
2385                | Some a,[] -> Some a
2386                | Some _,_ ->
2387                    if List.length nonconsts = cstr.cstr_nonconsts then
2388                      same_actions nonconsts
2389                    else None
2390                | None,_ -> same_actions nonconsts in
2391              match act0 with
2392              | Some act ->
2393                  Lifthenelse
2394                    (Lprim (Pisint, [arg], loc),
2395                     call_switcher
2396                       fail_opt arg
2397                       0 (n-1) consts,
2398                     act)
2399(* Emit a switch, as bytecode implements this sophisticated instruction *)
2400              | None ->
2401                  let sw =
2402                    {sw_numconsts = cstr.cstr_consts; sw_consts = consts;
2403                     sw_numblocks = cstr.cstr_nonconsts; sw_blocks = nonconsts;
2404                     sw_failaction = fail_opt} in
2405                  let hs,sw = share_actions_sw sw in
2406                  let sw = reintroduce_fail sw in
2407                  hs (Lswitch (arg,sw)) in
2408    lambda1, jumps_union local_jumps total1
2409  end
2410
2411let make_test_sequence_variant_constant fail arg int_lambda_list =
2412  let _, (cases, actions) =
2413    as_interval fail min_int max_int int_lambda_list in
2414  Switcher.test_sequence arg cases actions
2415
2416let call_switcher_variant_constant fail arg int_lambda_list =
2417  call_switcher fail arg min_int max_int int_lambda_list
2418
2419
2420let call_switcher_variant_constr loc fail arg int_lambda_list =
2421  let v = Ident.create "variant" in
2422  Llet(Alias, Pgenval, v, Lprim(Pfield 0, [arg], loc),
2423       call_switcher
2424         fail (Lvar v) min_int max_int int_lambda_list)
2425
2426let combine_variant loc row arg partial ctx def
2427                    (tag_lambda_list, total1, _pats) =
2428  let row = Btype.row_repr row in
2429  let num_constr = ref 0 in
2430  if row.row_closed then
2431    List.iter
2432      (fun (_, f) ->
2433        match Btype.row_field_repr f with
2434          Rabsent | Reither(true, _::_, _, _) -> ()
2435        | _ -> incr num_constr)
2436      row.row_fields
2437  else
2438    num_constr := max_int;
2439  let test_int_or_block arg if_int if_block =
2440    Lifthenelse(Lprim (Pisint, [arg], loc), if_int, if_block) in
2441  let sig_complete =  List.length tag_lambda_list = !num_constr
2442  and one_action = same_actions tag_lambda_list in
2443  let fail, local_jumps =
2444    if
2445      sig_complete  || (match partial with Total -> true | _ -> false)
2446    then
2447      None, jumps_empty
2448    else
2449      mk_failaction_neg partial ctx def in
2450  let (consts, nonconsts) = split_cases tag_lambda_list in
2451  let lambda1 = match fail, one_action with
2452  | None, Some act -> act
2453  | _,_ ->
2454      match (consts, nonconsts) with
2455      | ([_, act1], [_, act2]) when fail=None ->
2456          test_int_or_block arg act1 act2
2457      | (_, []) -> (* One can compare integers and pointers *)
2458          make_test_sequence_variant_constant fail arg consts
2459      | ([], _) ->
2460          let lam = call_switcher_variant_constr loc
2461              fail arg nonconsts in
2462          (* One must not dereference integers *)
2463          begin match fail with
2464          | None -> lam
2465          | Some fail -> test_int_or_block arg fail lam
2466          end
2467      | (_, _) ->
2468          let lam_const =
2469            call_switcher_variant_constant
2470              fail arg consts
2471          and lam_nonconst =
2472            call_switcher_variant_constr loc
2473              fail arg nonconsts in
2474          test_int_or_block arg lam_const lam_nonconst
2475  in
2476  lambda1, jumps_union local_jumps total1
2477
2478
2479let combine_array loc arg kind partial ctx def
2480    (len_lambda_list, total1, _pats)  =
2481  let fail, local_jumps = mk_failaction_neg partial  ctx def in
2482  let lambda1 =
2483    let newvar = Ident.create "len" in
2484    let switch =
2485      call_switcher
2486        fail (Lvar newvar)
2487        0 max_int len_lambda_list in
2488    bind
2489      Alias newvar (Lprim(Parraylength kind, [arg], loc)) switch in
2490  lambda1, jumps_union local_jumps total1
2491
2492(* Insertion of debugging events *)
2493
2494let rec event_branch repr lam =
2495  begin match lam, repr with
2496    (_, None) ->
2497      lam
2498  | (Levent(lam', ev), Some r) ->
2499      incr r;
2500      Levent(lam', {lev_loc = ev.lev_loc;
2501                    lev_kind = ev.lev_kind;
2502                    lev_repr = repr;
2503                    lev_env = ev.lev_env})
2504  | (Llet(str, k, id, lam, body), _) ->
2505      Llet(str, k, id, lam, event_branch repr body)
2506  | Lstaticraise _,_ -> lam
2507  | (_, Some _) ->
2508      Printlambda.lambda Format.str_formatter lam ;
2509      fatal_error
2510        ("Matching.event_branch: "^Format.flush_str_formatter ())
2511  end
2512
2513
2514(*
2515   This exception is raised when the compiler cannot produce code
2516   because control cannot reach the compiled clause,
2517
2518   Unused is raised initially in compile_test.
2519
2520   compile_list (for compiling switch results) catch Unused
2521
2522   comp_match_handlers (for compiling splitted matches)
2523   may reraise Unused
2524
2525
2526*)
2527
2528exception Unused
2529
2530let compile_list compile_fun division =
2531
2532  let rec c_rec totals = function
2533  | [] -> [], jumps_unions totals, []
2534  | (key, cell) :: rem ->
2535      begin match cell.ctx with
2536      | [] -> c_rec totals rem
2537      | _  ->
2538          try
2539            let (lambda1, total1) = compile_fun cell.ctx cell.pm in
2540            let c_rem, total, new_pats =
2541              c_rec
2542                (jumps_map ctx_combine total1::totals) rem in
2543            ((key,lambda1)::c_rem), total, (cell.pat::new_pats)
2544          with
2545          | Unused -> c_rec totals rem
2546      end in
2547  c_rec [] division
2548
2549
2550let compile_orhandlers compile_fun lambda1 total1 ctx to_catch =
2551  let rec do_rec r total_r = function
2552    | [] -> r,total_r
2553    | (mat,i,vars,pm)::rem ->
2554        begin try
2555          let ctx = select_columns mat ctx in
2556          let handler_i, total_i = compile_fun ctx pm in
2557          match raw_action r with
2558          | Lstaticraise (j,args) ->
2559              if i=j then
2560                List.fold_right2 (bind Alias) vars args handler_i,
2561                jumps_map (ctx_rshift_num (ncols mat)) total_i
2562              else
2563                do_rec r total_r rem
2564          | _ ->
2565              do_rec
2566                (Lstaticcatch (r,(i,vars), handler_i))
2567                (jumps_union
2568                   (jumps_remove i total_r)
2569                   (jumps_map (ctx_rshift_num (ncols mat)) total_i))
2570              rem
2571        with
2572        | Unused ->
2573            do_rec (Lstaticcatch (r, (i,vars), lambda_unit)) total_r rem
2574        end in
2575  do_rec lambda1 total1 to_catch
2576
2577
2578let compile_test compile_fun partial divide combine ctx to_match =
2579  let division = divide ctx to_match in
2580  let c_div = compile_list compile_fun division in
2581  match c_div with
2582  | [],_,_ ->
2583     begin match mk_failaction_neg partial ctx to_match.default with
2584     | None,_ -> raise Unused
2585     | Some l,total -> l,total
2586     end
2587  | _ ->
2588      combine ctx to_match.default c_div
2589
2590(* Attempt to avoid some useless bindings by lowering them *)
2591
2592(* Approximation of v present in lam *)
2593let rec approx_present v = function
2594  | Lconst _ -> false
2595  | Lstaticraise (_,args) ->
2596      List.exists (fun lam -> approx_present v lam) args
2597  | Lprim (_,args,_) ->
2598      List.exists (fun lam -> approx_present v lam) args
2599  | Llet (Alias, _k, _, l1, l2) ->
2600      approx_present v l1 || approx_present v l2
2601  | Lvar vv -> Ident.same v vv
2602  | _ -> true
2603
2604let rec lower_bind v arg lam = match lam with
2605| Lifthenelse (cond, ifso, ifnot) ->
2606    let pcond = approx_present v cond
2607    and pso = approx_present v ifso
2608    and pnot = approx_present v ifnot in
2609    begin match pcond, pso, pnot with
2610    | false, false, false -> lam
2611    | false, true, false ->
2612        Lifthenelse (cond, lower_bind v arg ifso, ifnot)
2613    | false, false, true ->
2614        Lifthenelse (cond, ifso, lower_bind v arg ifnot)
2615    | _,_,_ -> bind Alias v arg lam
2616    end
2617| Lswitch (ls,({sw_consts=[i,act] ; sw_blocks = []} as sw))
2618    when not (approx_present v ls) ->
2619      Lswitch (ls, {sw with sw_consts = [i,lower_bind v arg act]})
2620| Lswitch (ls,({sw_consts=[] ; sw_blocks = [i,act]} as sw))
2621    when not (approx_present v ls) ->
2622      Lswitch (ls, {sw with sw_blocks = [i,lower_bind v arg act]})
2623| Llet (Alias, k, vv, lv, l) ->
2624    if approx_present v lv then
2625      bind Alias v arg lam
2626    else
2627      Llet (Alias, k, vv, lv, lower_bind v arg l)
2628| _ ->
2629    bind Alias v arg lam
2630
2631let bind_check str v arg lam = match str,arg with
2632| _, Lvar _ ->bind str v arg lam
2633| Alias,_ -> lower_bind v arg lam
2634| _,_     -> bind str v arg lam
2635
2636let comp_exit ctx m = match m.default with
2637| (_,i)::_ -> Lstaticraise (i,[]), jumps_singleton i ctx
2638| _        -> fatal_error "Matching.comp_exit"
2639
2640
2641
2642let rec comp_match_handlers comp_fun partial ctx arg first_match next_matchs =
2643  match next_matchs with
2644  | [] -> comp_fun partial ctx arg first_match
2645  | rem ->
2646      let rec c_rec body total_body = function
2647        | [] -> body, total_body
2648        (* Hum, -1 means never taken
2649        | (-1,pm)::rem -> c_rec body total_body rem *)
2650        | (i,pm)::rem ->
2651            let ctx_i,total_rem = jumps_extract i total_body in
2652            begin match ctx_i with
2653            | [] -> c_rec body total_body rem
2654            | _ ->
2655                try
2656                  let li,total_i =
2657                    comp_fun
2658                      (match rem with [] -> partial | _ -> Partial)
2659                      ctx_i arg pm in
2660                  c_rec
2661                    (Lstaticcatch (body,(i,[]),li))
2662                    (jumps_union total_i total_rem)
2663                    rem
2664                with
2665                | Unused ->
2666                    c_rec (Lstaticcatch (body,(i,[]),lambda_unit))
2667                      total_rem  rem
2668            end in
2669   try
2670      let first_lam,total = comp_fun Partial ctx arg first_match in
2671      c_rec first_lam total rem
2672   with Unused -> match next_matchs with
2673   | [] -> raise Unused
2674   | (_,x)::xs ->  comp_match_handlers comp_fun partial ctx arg x xs
2675
2676(* To find reasonable names for variables *)
2677
2678let rec name_pattern default = function
2679    (pat :: _, _) :: rem ->
2680      begin match pat.pat_desc with
2681        Tpat_var (id, _) -> id
2682      | Tpat_alias(_, id, _) -> id
2683      | _ -> name_pattern default rem
2684      end
2685  | _ -> Ident.create default
2686
2687let arg_to_var arg cls = match arg with
2688| Lvar v -> v,arg
2689| _ ->
2690    let v = name_pattern "match" cls in
2691    v,Lvar v
2692
2693
2694(*
2695  The main compilation function.
2696   Input:
2697      repr=used for inserting debug events
2698      partial=exhaustiveness information from Parmatch
2699      ctx=a context
2700      m=a pattern matching
2701
2702   Output: a lambda term, a jump summary {..., exit number -> context, .. }
2703*)
2704
2705let rec compile_match repr partial ctx m = match m with
2706| { cases = []; args = [] } -> comp_exit ctx m
2707| { cases = ([], action) :: rem } ->
2708    if is_guarded action then begin
2709      let (lambda, total) =
2710        compile_match None partial ctx { m with cases = rem } in
2711      event_branch repr (patch_guarded lambda action), total
2712    end else
2713      (event_branch repr action, jumps_empty)
2714| { args = (arg, str)::argl } ->
2715    let v,newarg = arg_to_var arg m.cases in
2716    let first_match,rem =
2717      split_precompile (Some v)
2718        { m with args = (newarg, Alias) :: argl } in
2719    let (lam, total) =
2720      comp_match_handlers
2721        ((if dbg then do_compile_matching_pr else do_compile_matching) repr)
2722        partial ctx newarg first_match rem in
2723    bind_check str v arg lam, total
2724| _ -> assert false
2725
2726
2727(* verbose version of do_compile_matching, for debug *)
2728
2729and do_compile_matching_pr repr partial ctx arg x =
2730  prerr_string "COMPILE: " ;
2731  prerr_endline (match partial with Partial -> "Partial" | Total -> "Total") ;
2732  prerr_endline "MATCH" ;
2733  pretty_precompiled x ;
2734  prerr_endline "CTX" ;
2735  pretty_ctx ctx ;
2736  let (_, jumps) as r =  do_compile_matching repr partial ctx arg x in
2737  prerr_endline "JUMPS" ;
2738  pretty_jumps jumps ;
2739  r
2740
2741and do_compile_matching repr partial ctx arg pmh = match pmh with
2742| Pm pm ->
2743  let pat = what_is_cases pm.cases in
2744  begin match pat.pat_desc with
2745  | Tpat_any ->
2746      compile_no_test
2747        divide_var ctx_rshift repr partial ctx pm
2748  | Tpat_tuple patl ->
2749      compile_no_test
2750        (divide_tuple (List.length patl) (normalize_pat pat)) ctx_combine
2751        repr partial ctx pm
2752  | Tpat_record ((_, lbl,_)::_,_) ->
2753      compile_no_test
2754        (divide_record lbl.lbl_all (normalize_pat pat))
2755        ctx_combine repr partial ctx pm
2756  | Tpat_constant cst ->
2757      compile_test
2758        (compile_match repr partial) partial
2759        divide_constant
2760        (combine_constant pat.pat_loc arg cst partial)
2761        ctx pm
2762  | Tpat_construct (_, cstr, _) ->
2763      compile_test
2764        (compile_match repr partial) partial
2765        divide_constructor
2766        (combine_constructor pat.pat_loc arg pat cstr partial)
2767        ctx pm
2768  | Tpat_array _ ->
2769      let kind = Typeopt.array_pattern_kind pat in
2770      compile_test (compile_match repr partial) partial
2771        (divide_array kind) (combine_array pat.pat_loc arg kind partial)
2772        ctx pm
2773  | Tpat_lazy _ ->
2774      compile_no_test
2775        (divide_lazy (normalize_pat pat))
2776        ctx_combine repr partial ctx pm
2777  | Tpat_variant(_, _, row) ->
2778      compile_test (compile_match repr partial) partial
2779        (divide_variant !row)
2780        (combine_variant pat.pat_loc !row arg partial)
2781        ctx pm
2782  | _ -> assert false
2783  end
2784| PmVar {inside=pmh ; var_arg=arg} ->
2785    let lam, total =
2786      do_compile_matching repr partial (ctx_lshift ctx) arg pmh in
2787    lam, jumps_map ctx_rshift total
2788| PmOr {body=body ; handlers=handlers} ->
2789    let lam, total = compile_match repr partial ctx body in
2790    compile_orhandlers (compile_match repr partial) lam total ctx handlers
2791
2792and compile_no_test divide up_ctx repr partial ctx to_match =
2793  let {pm=this_match ; ctx=this_ctx } = divide ctx to_match in
2794  let lambda,total = compile_match repr partial this_ctx this_match in
2795  lambda, jumps_map up_ctx total
2796
2797
2798
2799
2800(* The entry points *)
2801
2802(*
2803   If there is a guard in a matching or a lazy pattern,
2804   then set exhaustiveness info to Partial.
2805   (because of side effects, assume the worst).
2806
2807   Notice that exhaustiveness information is trusted by the compiler,
2808   that is, a match flagged as Total should not fail at runtime.
2809   More specifically, for instance if match y with x::_ -> x is flagged
2810   total (as it happens during JoCaml compilation) then y cannot be []
2811   at runtime. As a consequence, the static Total exhaustiveness information
2812   have to be downgraded to Partial, in the dubious cases where guards
2813   or lazy pattern execute arbitrary code that may perform side effects
2814   and change the subject values.
2815LM:
2816   Lazy pattern was PR #5992, initial patch by lwp25.
2817   I have  generalized the patch, so as to also find mutable fields.
2818*)
2819
2820let find_in_pat pred =
2821  let rec find_rec p =
2822    pred p.pat_desc ||
2823    begin match p.pat_desc with
2824    | Tpat_alias (p,_,_) | Tpat_variant (_,Some p,_) | Tpat_lazy p ->
2825        find_rec p
2826    | Tpat_tuple ps|Tpat_construct (_,_,ps) | Tpat_array ps ->
2827        List.exists find_rec ps
2828    | Tpat_record (lpats,_) ->
2829        List.exists
2830          (fun (_, _, p) -> find_rec p)
2831          lpats
2832    | Tpat_or (p,q,_) ->
2833        find_rec p || find_rec q
2834    | Tpat_constant _ | Tpat_var _
2835    | Tpat_any | Tpat_variant (_,None,_) -> false
2836  end in
2837  find_rec
2838
2839let is_lazy_pat = function
2840  | Tpat_lazy _ -> true
2841  | Tpat_alias _ | Tpat_variant _ | Tpat_record _
2842  | Tpat_tuple _|Tpat_construct _ | Tpat_array _
2843  | Tpat_or _ | Tpat_constant _ | Tpat_var _ | Tpat_any
2844      -> false
2845
2846let is_lazy p = find_in_pat is_lazy_pat p
2847
2848let have_mutable_field p = match p with
2849| Tpat_record (lps,_) ->
2850    List.exists
2851      (fun (_,lbl,_) ->
2852        match lbl.Types.lbl_mut with
2853        | Mutable -> true
2854        | Immutable -> false)
2855      lps
2856| Tpat_alias _ | Tpat_variant _ | Tpat_lazy _
2857| Tpat_tuple _|Tpat_construct _ | Tpat_array _
2858| Tpat_or _
2859| Tpat_constant _ | Tpat_var _ | Tpat_any
2860  -> false
2861
2862let is_mutable p = find_in_pat have_mutable_field p
2863
2864(* Downgrade Total when
2865   1. Matching accesses some mutable fields;
2866   2. And there are  guards or lazy patterns.
2867*)
2868
2869let check_partial is_mutable is_lazy pat_act_list = function
2870  | Partial -> Partial
2871  | Total ->
2872      if
2873        pat_act_list = [] ||  (* allow empty case list *)
2874        List.exists
2875          (fun (pats, lam) ->
2876            is_mutable pats && (is_guarded lam || is_lazy pats))
2877          pat_act_list
2878      then Partial
2879      else Total
2880
2881let check_partial_list =
2882  check_partial (List.exists is_mutable) (List.exists is_lazy)
2883let check_partial = check_partial is_mutable is_lazy
2884
2885(* have toplevel handler when appropriate *)
2886
2887let start_ctx n = [{left=[] ; right = omegas n}]
2888
2889let check_total total lambda i handler_fun =
2890  if jumps_is_empty total then
2891    lambda
2892  else begin
2893    Lstaticcatch(lambda, (i,[]), handler_fun())
2894  end
2895
2896let compile_matching repr handler_fun arg pat_act_list partial =
2897  let partial = check_partial pat_act_list partial in
2898  match partial with
2899  | Partial ->
2900      let raise_num = next_raise_count () in
2901      let pm =
2902        { cases = List.map (fun (pat, act) -> ([pat], act)) pat_act_list;
2903          args = [arg, Strict] ;
2904          default = [[[omega]],raise_num]} in
2905      begin try
2906        let (lambda, total) = compile_match repr partial (start_ctx 1) pm in
2907        check_total total lambda raise_num handler_fun
2908      with
2909      | Unused -> assert false (* ; handler_fun() *)
2910      end
2911  | Total ->
2912      let pm =
2913        { cases = List.map (fun (pat, act) -> ([pat], act)) pat_act_list;
2914          args = [arg, Strict] ;
2915          default = []} in
2916      let (lambda, total) = compile_match repr partial (start_ctx 1) pm in
2917      assert (jumps_is_empty total) ;
2918      lambda
2919
2920
2921let partial_function loc () =
2922  (* [Location.get_pos_info] is too expensive *)
2923  let (fname, line, char) = Location.get_pos_info loc.Location.loc_start in
2924  Lprim(Praise Raise_regular, [Lprim(Pmakeblock(0, Immutable, None),
2925          [transl_normal_path Predef.path_match_failure;
2926           Lconst(Const_block(0,
2927              [Const_base(Const_string (fname, None));
2928               Const_base(Const_int line);
2929               Const_base(Const_int char)]))], loc)], loc)
2930
2931let for_function loc repr param pat_act_list partial =
2932  compile_matching repr (partial_function loc) param pat_act_list partial
2933
2934(* In the following two cases, exhaustiveness info is not available! *)
2935let for_trywith param pat_act_list =
2936  compile_matching None
2937    (fun () -> Lprim(Praise Raise_reraise, [param], Location.none))
2938    param pat_act_list Partial
2939
2940let simple_for_let loc param pat body =
2941  compile_matching None (partial_function loc) param [pat, body] Partial
2942
2943
2944(* Optimize binding of immediate tuples
2945
2946   The goal of the implementation of 'for_let' below, which replaces
2947   'simple_for_let', is to avoid tuple allocation in cases such as
2948   this one:
2949
2950     let (x,y) =
2951        let foo = ... in
2952        if foo then (1, 2) else (3,4)
2953     in bar
2954
2955   The compiler easily optimizes the simple `let (x,y) = (1,2) in ...`
2956   case (call to Matching.for_multiple_match from Translcore), but
2957   didn't optimize situations where the rhs tuples are hidden under
2958   a more complex context.
2959
2960   The idea comes from Alain Frisch who suggested and implemented
2961   the following compilation method, based on Lassign:
2962
2963     let x = dummy in let y = dummy in
2964     begin
2965      let foo = ... in
2966      if foo then
2967        (let x1 = 1 in let y1 = 2 in x <- x1; y <- y1)
2968      else
2969        (let x2 = 3 in let y2 = 4 in x <- x2; y <- y2)
2970     end;
2971     bar
2972
2973   The current implementation from Gabriel Scherer uses Lstaticcatch /
2974   Lstaticraise instead:
2975
2976     catch
2977       let foo = ... in
2978       if foo then
2979         (let x1 = 1 in let y1 = 2 in exit x1 y1)
2980       else
2981        (let x2 = 3 in let y2 = 4 in exit x2 y2)
2982     with x y ->
2983       bar
2984
2985   The catch/exit is used to avoid duplication of the let body ('bar'
2986   in the example), on 'if' branches for example; it is useless for
2987   linear contexts such as 'let', but we don't need to be careful to
2988   generate nice code because Simplif will remove such useless
2989   catch/exit.
2990*)
2991
2992let rec map_return f = function
2993  | Llet (str, k, id, l1, l2) -> Llet (str, k, id, l1, map_return f l2)
2994  | Lletrec (l1, l2) -> Lletrec (l1, map_return f l2)
2995  | Lifthenelse (lcond, lthen, lelse) ->
2996      Lifthenelse (lcond, map_return f lthen, map_return f lelse)
2997  | Lsequence (l1, l2) -> Lsequence (l1, map_return f l2)
2998  | Levent (l, ev) -> Levent (map_return f l, ev)
2999  | Ltrywith (l1, id, l2) -> Ltrywith (map_return f l1, id, map_return f l2)
3000  | Lstaticcatch (l1, b, l2) ->
3001      Lstaticcatch (map_return f l1, b, map_return f l2)
3002  | Lstaticraise _ | Lprim(Praise _, _, _) as l -> l
3003  | l -> f l
3004
3005(* The 'opt' reference indicates if the optimization is worthy.
3006
3007   It is shared by the different calls to 'assign_pat' performed from
3008   'map_return'. For example with the code
3009     let (x, y) = if foo then z else (1,2)
3010   the else-branch will activate the optimization for both branches.
3011
3012   That means that the optimization is activated if *there exists* an
3013   interesting tuple in one hole of the let-rhs context. We could
3014   choose to activate it only if *all* holes are interesting. We made
3015   that choice because being optimistic is extremely cheap (one static
3016   exit/catch overhead in the "wrong cases"), while being pessimistic
3017   can be costly (one unnecessary tuple allocation).
3018*)
3019
3020let assign_pat opt nraise catch_ids loc pat lam =
3021  let rec collect acc pat lam = match pat.pat_desc, lam with
3022  | Tpat_tuple patl, Lprim(Pmakeblock _, lams, _) ->
3023      opt := true;
3024      List.fold_left2 collect acc patl lams
3025  | Tpat_tuple patl, Lconst(Const_block(_, scl)) ->
3026      opt := true;
3027      let collect_const acc pat sc = collect acc pat (Lconst sc) in
3028      List.fold_left2 collect_const acc patl scl
3029  | _ ->
3030    (* pattern idents will be bound in staticcatch (let body), so we
3031       refresh them here to guarantee binders  uniqueness *)
3032    let pat_ids = pat_bound_idents pat in
3033    let fresh_ids = List.map (fun id -> id, Ident.rename id) pat_ids in
3034    (fresh_ids, alpha_pat fresh_ids pat, lam) :: acc
3035  in
3036
3037  (* sublets were accumulated by 'collect' with the leftmost tuple
3038     pattern at the bottom of the list; to respect right-to-left
3039     evaluation order for tuples, we must evaluate sublets
3040     top-to-bottom. To preserve tail-rec, we will fold_left the
3041     reversed list. *)
3042  let rev_sublets = List.rev (collect [] pat lam) in
3043  let exit =
3044    (* build an Ident.tbl to avoid quadratic refreshing costs *)
3045    let add t (id, fresh_id) = Ident.add id fresh_id t in
3046    let add_ids acc (ids, _pat, _lam) = List.fold_left add acc ids in
3047    let tbl = List.fold_left add_ids Ident.empty rev_sublets in
3048    let fresh_var id = Lvar (Ident.find_same id tbl) in
3049    Lstaticraise(nraise, List.map fresh_var catch_ids)
3050  in
3051  let push_sublet code (_ids, pat, lam) = simple_for_let loc lam pat code in
3052  List.fold_left push_sublet exit rev_sublets
3053
3054let for_let loc param pat body =
3055  match pat.pat_desc with
3056  | Tpat_any ->
3057      (* This eliminates a useless variable (and stack slot in bytecode)
3058         for "let _ = ...". See #6865. *)
3059      Lsequence(param, body)
3060  | Tpat_var (id, _) ->
3061      (* fast path, and keep track of simple bindings to unboxable numbers *)
3062      let k = Typeopt.value_kind pat.pat_env pat.pat_type in
3063      Llet(Strict, k, id, param, body)
3064  | _ ->
3065      let opt = ref false in
3066      let nraise = next_raise_count () in
3067      let catch_ids = pat_bound_idents pat in
3068      let bind = map_return (assign_pat opt nraise catch_ids loc pat) param in
3069      if !opt then Lstaticcatch(bind, (nraise, catch_ids), body)
3070      else simple_for_let loc param pat body
3071
3072(* Handling of tupled functions and matchings *)
3073
3074(* Easy case since variables are available *)
3075let for_tupled_function loc paraml pats_act_list partial =
3076  let partial = check_partial_list pats_act_list partial in
3077  let raise_num = next_raise_count () in
3078  let omegas = [List.map (fun _ -> omega) paraml] in
3079  let pm =
3080    { cases = pats_act_list;
3081      args = List.map (fun id -> (Lvar id, Strict)) paraml ;
3082      default = [omegas,raise_num]
3083    } in
3084  try
3085    let (lambda, total) = compile_match None partial
3086        (start_ctx (List.length paraml)) pm in
3087    check_total total lambda raise_num (partial_function loc)
3088  with
3089  | Unused -> partial_function loc ()
3090
3091
3092
3093let flatten_pattern size p = match p.pat_desc with
3094| Tpat_tuple args -> args
3095| Tpat_any -> omegas size
3096| _ -> raise Cannot_flatten
3097
3098let rec flatten_pat_line size p k = match p.pat_desc with
3099| Tpat_any ->  omegas size::k
3100| Tpat_tuple args -> args::k
3101| Tpat_or (p1,p2,_) ->  flatten_pat_line size p1 (flatten_pat_line size p2 k)
3102| Tpat_alias (p,_,_) -> (* Note: if this 'as' pat is here, then this is a
3103                           useless binding, solves PR #3780 *)
3104    flatten_pat_line size p k
3105| _ -> fatal_error "Matching.flatten_pat_line"
3106
3107let flatten_cases size cases =
3108  List.map
3109    (fun (ps,action) -> match ps with
3110    | [p] -> flatten_pattern size p,action
3111    | _ -> fatal_error "Matching.flatten_case")
3112    cases
3113
3114let flatten_matrix size pss =
3115  List.fold_right
3116    (fun ps r -> match ps with
3117    | [p] -> flatten_pat_line size p r
3118    | _   -> fatal_error "Matching.flatten_matrix")
3119    pss []
3120
3121let flatten_def size def =
3122  List.map
3123    (fun (pss,i) -> flatten_matrix size pss,i)
3124    def
3125
3126let flatten_pm size args pm =
3127    {args = args ; cases = flatten_cases size pm.cases ;
3128     default = flatten_def size pm.default}
3129
3130
3131let flatten_precompiled size args  pmh = match pmh with
3132| Pm pm -> Pm (flatten_pm size args pm)
3133| PmOr {body=b ; handlers=hs ; or_matrix=m} ->
3134    PmOr
3135      {body=flatten_pm size args b ;
3136       handlers=
3137         List.map
3138          (fun (mat,i,vars,pm) -> flatten_matrix size mat,i,vars,pm)
3139          hs ;
3140       or_matrix=flatten_matrix size m ;}
3141| PmVar _ -> assert false
3142
3143(*
3144   compiled_flattened is a ``comp_fun'' argument to comp_match_handlers.
3145   Hence it needs a fourth argument, which it ignores
3146*)
3147
3148let compile_flattened repr partial ctx _ pmh = match pmh with
3149| Pm pm -> compile_match repr partial ctx pm
3150| PmOr {body=b ; handlers=hs} ->
3151    let lam, total = compile_match repr partial ctx b in
3152    compile_orhandlers (compile_match repr partial) lam total ctx hs
3153| PmVar _ -> assert false
3154
3155let do_for_multiple_match loc paraml pat_act_list partial =
3156  let repr = None in
3157  let partial = check_partial pat_act_list partial in
3158  let raise_num,pm1 =
3159    match partial with
3160    | Partial ->
3161        let raise_num = next_raise_count () in
3162        raise_num,
3163        { cases = List.map (fun (pat, act) -> ([pat], act)) pat_act_list;
3164          args = [Lprim(Pmakeblock(0, Immutable, None), paraml, loc), Strict];
3165          default = [[[omega]],raise_num] }
3166    | _ ->
3167        -1,
3168        { cases = List.map (fun (pat, act) -> ([pat], act)) pat_act_list;
3169          args = [Lprim(Pmakeblock(0, Immutable, None), paraml, loc), Strict];
3170          default = [] } in
3171
3172  try
3173    try
3174(* Once for checking that compilation is possible *)
3175      let next, nexts = split_precompile None pm1 in
3176
3177      let size = List.length paraml
3178      and idl = List.map (fun _ -> Ident.create "match") paraml in
3179      let args =  List.map (fun id -> Lvar id, Alias) idl in
3180
3181      let flat_next = flatten_precompiled size args next
3182      and flat_nexts =
3183        List.map
3184          (fun (e,pm) ->  e,flatten_precompiled size args pm)
3185          nexts in
3186
3187      let lam, total =
3188        comp_match_handlers
3189          (compile_flattened repr)
3190          partial (start_ctx size) () flat_next flat_nexts in
3191      List.fold_right2 (bind Strict) idl paraml
3192        (match partial with
3193        | Partial ->
3194            check_total total lam raise_num (partial_function loc)
3195        | Total ->
3196            assert (jumps_is_empty total) ;
3197            lam)
3198    with Cannot_flatten ->
3199      let (lambda, total) = compile_match None partial (start_ctx 1) pm1 in
3200      begin match partial with
3201      | Partial ->
3202          check_total total lambda raise_num (partial_function loc)
3203      | Total ->
3204          assert (jumps_is_empty total) ;
3205          lambda
3206      end
3207  with Unused ->
3208    assert false (* ; partial_function loc () *)
3209
3210(* #PR4828: Believe it or not, the 'paraml' argument below
3211   may not be side effect free. *)
3212
3213let param_to_var param = match param with
3214| Lvar v -> v,None
3215| _ -> Ident.create "match",Some param
3216
3217let bind_opt (v,eo) k = match eo with
3218| None -> k
3219| Some e ->  Lambda.bind Strict v e k
3220
3221let for_multiple_match loc paraml pat_act_list partial =
3222  let v_paraml = List.map param_to_var paraml in
3223  let paraml = List.map (fun (v,_) -> Lvar v) v_paraml in
3224  List.fold_right bind_opt v_paraml
3225    (do_for_multiple_match loc paraml pat_act_list partial)
3226