]> matita.cs.unibo.it Git - helm.git/commitdiff
Ooops, this completes the previous commit (ocaml extraction implementation).
authorClaudio Sacerdoti Coen <claudio.sacerdoticoen@unibo.it>
Sat, 2 Feb 2013 00:38:55 +0000 (00:38 +0000)
committerClaudio Sacerdoti Coen <claudio.sacerdoticoen@unibo.it>
Sat, 2 Feb 2013 00:38:55 +0000 (00:38 +0000)
18 files changed:
matita/components/ng_extraction/Makefile [new file with mode: 0644]
matita/components/ng_extraction/common.ml [new file with mode: 0644]
matita/components/ng_extraction/common.mli [new file with mode: 0644]
matita/components/ng_extraction/coq.ml [new file with mode: 0644]
matita/components/ng_extraction/coq.mli [new file with mode: 0644]
matita/components/ng_extraction/extraction.ml [new file with mode: 0644]
matita/components/ng_extraction/extraction.mli [new file with mode: 0644]
matita/components/ng_extraction/miniml.ml [new file with mode: 0644]
matita/components/ng_extraction/mlutil.ml [new file with mode: 0644]
matita/components/ng_extraction/mlutil.mli [new file with mode: 0644]
matita/components/ng_extraction/nCicExtraction.ml [new file with mode: 0644]
matita/components/ng_extraction/nCicExtraction.mli [new file with mode: 0644]
matita/components/ng_extraction/ocaml.ml [new file with mode: 0644]
matita/components/ng_extraction/ocaml.mli [new file with mode: 0644]
matita/components/ng_extraction/ocamlExtraction.ml [new file with mode: 0644]
matita/components/ng_extraction/ocamlExtraction.mli [new file with mode: 0644]
matita/components/ng_extraction/ocamlExtractionTable.ml [new file with mode: 0644]
matita/components/ng_extraction/ocamlExtractionTable.mli [new file with mode: 0644]

diff --git a/matita/components/ng_extraction/Makefile b/matita/components/ng_extraction/Makefile
new file mode 100644 (file)
index 0000000..8bbda65
--- /dev/null
@@ -0,0 +1,24 @@
+PACKAGE = ng_extraction
+PREDICATES =
+
+INTERFACE_FILES = \
+       nCicExtraction.mli \
+       coq.mli \
+       ocamlExtractionTable.mli  \
+       mlutil.mli \
+       common.mli \
+       extraction.mli \
+       ocaml.mli \
+       ocamlExtraction.mli
+#      extract_env.mli \
+
+IMPLEMENTATION_FILES = \
+   miniml.ml $(INTERFACE_FILES:%.mli=%.ml)
+EXTRA_OBJECTS_TO_INSTALL = 
+EXTRA_OBJECTS_TO_CLEAN =
+%.cmo: OCAMLOPTIONS += -w Ae
+%.cmi: OCAMLOPTIONS += -w Ae
+%.cmx: OCAMLOPTIONS += -w Ae
+
+include ../../Makefile.defs
+include ../Makefile.common
diff --git a/matita/components/ng_extraction/common.ml b/matita/components/ng_extraction/common.ml
new file mode 100644 (file)
index 0000000..57a27e9
--- /dev/null
@@ -0,0 +1,158 @@
+(************************************************************************)
+(*  v      *   The Coq Proof Assistant  /  The Coq Development Team     *)
+(* <O___,, *   INRIA - CNRS - LIX - LRI - PPS - Copyright 1999-2011     *)
+(*   \VV/  **************************************************************)
+(*    //   *      This file is distributed under the terms of the       *)
+(*         *       GNU Lesser General Public License Version 2.1        *)
+(************************************************************************)
+
+(*i $Id: common.ml 14641 2011-11-06 11:59:10Z herbelin $ i*)
+
+open Coq
+open OcamlExtractionTable
+open Miniml
+open Mlutil
+
+(*s Some pretty-print utility functions. *)
+
+let pp_par par st = if par then str "(" ++ st ++ str ")" else st
+
+let pp_apply st par args = match args with
+  | [] -> st
+  | _  -> hov 2 (pp_par par (st ++ spc () ++ prlist_with_sep spc identity args))
+
+let pr_binding = function
+  | [] -> mt ()
+  | l  -> str " " ++ prlist_with_sep (fun () -> str " ") pr_id l
+
+(** By default, in module Format, you can do horizontal placing of blocks
+    even if they include newlines, as long as the number of chars in the
+    blocks are less that a line length. To avoid this awkward situation,
+    we attach a big virtual size to [fnl] newlines. *)
+
+let fnl () = stras (1000000,"") ++ fnl ()
+
+let fnl2 () = fnl () ++ fnl ()
+
+let space_if = function true -> str " " | false -> mt ()
+
+let is_invalid_id s =
+ match s.[0] with 'a' .. 'z' | 'A' .. 'Z' -> false | _ -> true
+
+let rec lowercase_id id =
+ if id = "" then "x" else
+ if id.[0] = '_' then lowercase_id (String.sub id 1 (String.length id - 1)) else
+ if is_invalid_id id then lowercase_id ("x" ^ id) else
+ String.uncapitalize id
+
+let rec uppercase_id id =
+ if id = "" then "T" else
+ if id.[0] = '_' then uppercase_id (String.sub id 1 (String.length id - 1)) else
+ if is_invalid_id id then uppercase_id ("x" ^ id) else
+ String.capitalize id
+
+type kind = Term | Type | Cons
+
+let upperkind = function
+  | Type
+  | Term -> false
+  | Cons -> true
+
+let kindcase_id k id =
+  if upperkind k then uppercase_id id else lowercase_id id
+
+(*s de Bruijn environments for programs *)
+
+type env = identifier list * Idset.t
+
+(*s Generic renaming issues for local variable names. *)
+
+let rec rename_id id avoid =
+  if Idset.mem id avoid then rename_id (lift_subscript id) avoid else id
+
+let rec rename_vars avoid = function
+  | [] ->
+      [], avoid
+  | id :: idl when id == dummy_name ->
+      (* we don't rename dummy binders *)
+      let (idl', avoid') = rename_vars avoid idl in
+      (id :: idl', avoid')
+  | id :: idl ->
+      let (idl, avoid) = rename_vars avoid idl in
+      let id = rename_id (lowercase_id id) avoid in
+      (id :: idl, Idset.add id avoid)
+
+let rename_tvars avoid l =
+  let rec rename avoid = function
+    | [] -> [],avoid
+    | id :: idl ->
+       let id = rename_id (lowercase_id id) avoid in
+       let idl, avoid = rename (Idset.add id avoid) idl in
+       (id :: idl, avoid) in
+  fst (rename avoid l)
+
+let push_vars ids (db,avoid) =
+  let ids',avoid' = rename_vars avoid ids in
+  ids', (ids' @ db, avoid')
+
+let get_db_name n (db,_) =
+  let id = List.nth db (pred n) in
+  if id = dummy_name then "__" else id
+
+let empty_env status = [], get_global_ids status
+
+let fake_spec = NReference.Fix (0,-1,-1)
+
+let safe_name_of_reference status r =
+ match r with
+    NReference.Ref (uri, spec) when spec = fake_spec ->
+     (* The field of a record *)
+     NUri.name_of_uri uri
+  | _ -> NCicPp.r2s status true r
+
+let maybe_capitalize b n = if b then String.capitalize n else n
+
+let modname_of_filename status capitalize name =
+ try
+  let name = modname_of_filename status name in
+   status, maybe_capitalize capitalize name
+ with Not_found ->
+  let globs = Idset.elements (get_modnames status) in
+  let s = next_ident_away (String.uncapitalize name) globs in
+  let status = add_modname status s in
+  let status = add_modname_for_filename status name s in
+   status, maybe_capitalize capitalize s
+
+let ref_renaming status (k,r) =
+ let status,s =
+  let rec ref_renaming status (k,r) =
+   try status,name_of_reference status r
+   with Not_found ->
+   if is_projection status r then
+    (* The reference for the projection and the field of a record are different
+       and they would be assigned different names (name clash!). So we normalize
+       the projection reference into the field reference *)
+    let NReference.Ref (uri,_) = r in
+    let fieldref = NReference.reference_of_spec uri fake_spec in
+     ref_renaming status (k,fieldref)
+   else
+    let name = safe_name_of_reference status r in
+    let globs = Idset.elements (get_global_ids status) in
+    let s = next_ident_away (kindcase_id k name) globs in
+    let status = add_global_ids status s in
+    let status = add_name_for_reference status r s in
+     status,s
+  in
+   ref_renaming status (k,r)
+ in
+  let baseuri = Filename.dirname (NReference.string_of_reference r) in
+  if current_baseuri status = baseuri then
+   status,s
+  else
+   let modname = Filename.basename (Filename.dirname (NReference.string_of_reference r)) in
+   let status,modname = modname_of_filename status true modname in
+    status, modname ^ "." ^ s
+
+(* Main name printing function for a reference *)
+
+let pp_global status k r = ref_renaming status (k,r)
diff --git a/matita/components/ng_extraction/common.mli b/matita/components/ng_extraction/common.mli
new file mode 100644 (file)
index 0000000..4bde847
--- /dev/null
@@ -0,0 +1,44 @@
+(************************************************************************)
+(*  v      *   The Coq Proof Assistant  /  The Coq Development Team     *)
+(* <O___,, *   INRIA - CNRS - LIX - LRI - PPS - Copyright 1999-2011     *)
+(*   \VV/  **************************************************************)
+(*    //   *      This file is distributed under the terms of the       *)
+(*         *       GNU Lesser General Public License Version 2.1        *)
+(************************************************************************)
+
+(*i $Id: common.mli 14641 2011-11-06 11:59:10Z herbelin $ i*)
+
+open Coq
+open Miniml
+open Mlutil
+open OcamlExtractionTable
+
+(** By default, in module Format, you can do horizontal placing of blocks
+    even if they include newlines, as long as the number of chars in the
+    blocks are less that a line length. To avoid this awkward situation,
+    we attach a big virtual size to [fnl] newlines. *)
+
+val fnl : unit -> std_ppcmds
+val fnl2 : unit -> std_ppcmds
+val space_if : bool -> std_ppcmds
+
+val pp_par : bool -> std_ppcmds -> std_ppcmds
+val pp_apply : std_ppcmds -> bool -> std_ppcmds list -> std_ppcmds
+val pr_binding : identifier list -> std_ppcmds
+
+type env = identifier list * Idset.t
+val empty_env : #OcamlExtractionTable.status -> env
+
+val fake_spec: NReference.spec
+
+val rename_tvars: Idset.t -> identifier list -> identifier list
+val push_vars : identifier list -> env -> identifier list * env
+val get_db_name : int -> env -> identifier
+
+(* true = capitalize *)
+val modname_of_filename: #status as 'status-> bool -> string -> 'status * string
+
+type kind = Term | Type | Cons
+
+val pp_global :
+ #status as 'status -> kind -> NReference.reference -> 'status * string
diff --git a/matita/components/ng_extraction/coq.ml b/matita/components/ng_extraction/coq.ml
new file mode 100644 (file)
index 0000000..f68562c
--- /dev/null
@@ -0,0 +1,457 @@
+type identifier = string
+
+(* Util.ml *)
+
+let is_digit c = (c >= '0' && c <= '9')
+
+(* Nameops.ml *)
+
+let has_subscript id =
+  is_digit (id.[String.length id - 1])
+
+let code_of_0 = Char.code '0'
+let code_of_9 = Char.code '9'
+
+let cut_ident skip_quote s =
+  let slen = String.length s in
+  (* [n'] is the position of the first non nullary digit *)
+  let rec numpart n n' =
+    if n = 0 then
+      (* ident made of _ and digits only [and ' if skip_quote]: don't cut it *)
+      slen
+    else
+      let c = Char.code (String.get s (n-1)) in
+      if c = code_of_0 && n <> slen then
+        numpart (n-1) n'
+      else if code_of_0 <= c && c <= code_of_9 then
+        numpart (n-1) (n-1)
+      else if skip_quote & (c = Char.code '\'' || c = Char.code '_') then
+        numpart (n-1) (n-1)
+      else
+        n'
+  in
+  numpart slen slen
+
+let forget_subscript id =
+  let numstart = cut_ident false id in
+  let newid = String.make (numstart+1) '0' in
+  String.blit id 0 newid 0 numstart;
+  newid
+
+(* Namegen.ml *)
+
+let restart_subscript id =
+  if not (has_subscript id) then id else
+    (* Ce serait sans doute mieux avec quelque chose inspiré de
+     *** make_ident id (Some 0) *** mais ça brise la compatibilité... *)
+    forget_subscript id
+
+(* Rem: semantics is a bit different, if an ident starts with toto00 then
+  after successive renamings it comes to toto09, then it goes on with toto10 *)
+let lift_subscript id =
+  let len = String.length id in
+  let rec add carrypos =
+    let c = id.[carrypos] in
+    if is_digit c then
+      if c = '9' then begin
+        assert (carrypos>0);
+        add (carrypos-1)
+      end
+      else begin
+        let newid = String.copy id in
+        String.fill newid (carrypos+1) (len-1-carrypos) '0';
+        newid.[carrypos] <- Char.chr (Char.code c + 1);
+        newid
+      end
+    else begin
+      let newid = id^"0" in
+      if carrypos < len-1 then begin
+        String.fill newid (carrypos+1) (len-1-carrypos) '0';
+        newid.[carrypos+1] <- '1'
+      end;
+      newid
+    end
+  in add (len-1)
+
+let next_ident_away_from id bad =
+  let rec name_rec id = if bad id then name_rec (lift_subscript id) else id in
+  name_rec id
+
+let next_ident_away id avoid =
+  if List.mem id avoid then
+    next_ident_away_from (restart_subscript id) (fun id -> List.mem id avoid)
+  else id
+
+(* ----- *)
+
+type label
+type reference
+
+type env
+type constant_body
+type ('a,'b) prec_declaration
+
+type module_path
+type mod_bound_id
+
+module Intmap = Map.Make(struct type t = int let compare = compare end)
+
+module Intset = Set.Make(struct type t = int let compare = compare end)
+
+module Idset = Set.Make(struct type t = identifier let compare = compare end)
+
+module Uriset = Set.Make(struct type t = NUri.uri let compare = NUri.compare end)
+
+module Refmap = Map.Make(struct type t = NReference.reference let compare = NReference.compare end)
+
+module Stringmap = Map.Make(String)
+
+(* Pp_control.ml *)
+
+module Pp_control =
+ struct
+  let with_output_to _ = assert false
+  let get_margin _ = assert false
+ end
+
+(* Util.ml *)
+
+let list_map_i f =
+  let rec map_i_rec i = function
+    | [] -> []
+    | x::l -> let v = f i x in v :: map_i_rec (i+1) l
+  in
+  map_i_rec
+
+let list_map_i_status status f =
+  let rec map_i_rec status i = function
+    | [] -> status,[]
+    | x::l -> let status,v = f status i x in
+      let status,res = map_i_rec status (i+1) l in
+       status,v :: res
+  in
+  map_i_rec status
+
+let iterate f =
+  let rec iterate_f n x =
+    if n <= 0 then x else iterate_f (pred n) (f x)
+  in
+  iterate_f
+
+let rec list_skipn n l = match n,l with
+  | 0, _ -> l
+  | _, [] -> failwith "list_skipn"
+  | n, _::l -> list_skipn (pred n) l
+
+let list_split_at index l =
+  let rec aux i acc = function
+      tl when i = index -> (List.rev acc), tl
+    | hd :: tl -> aux (succ i) (hd :: acc) tl
+    | [] -> failwith "list_split_at: Invalid argument"
+  in aux 0 [] l
+
+let list_chop n l =
+  let rec chop_aux acc = function
+    | (0, l2) -> (List.rev acc, l2)
+    | (n, (h::t)) -> chop_aux (h::acc) (pred n, t)
+    | (_, []) -> failwith "list_chop"
+  in
+  chop_aux [] (n,l)
+
+let list_firstn n l =
+  let rec aux acc = function
+    | (0, _l) -> List.rev acc
+    | (n, (h::t)) -> aux (h::acc) (pred n, t)
+    | _ -> failwith "firstn"
+  in
+  aux [] (n,l)
+
+let list_fold_left_i f =
+  let rec it_list_f i a = function
+    | [] -> a
+    | b::l -> it_list_f (i+1) (f i a b) l
+  in
+  it_list_f
+
+let list_iter_i f l = list_fold_left_i (fun i _ x -> f i x) 0 () l
+
+let list_lastn n l =
+  let len = List.length l in
+  let rec aux m l =
+    if m = n then l else aux (m - 1) (List.tl l)
+  in
+  if len < n then failwith "lastn" else aux len l
+
+let array_map2 f v1 v2 =
+  if Array.length v1 <> Array.length v2 then invalid_arg "array_map2";
+  if Array.length v1 == 0 then
+    [| |]
+  else begin
+    let res = Array.create (Array.length v1) (f v1.(0) v2.(0)) in
+    for i = 1 to pred (Array.length v1) do
+      res.(i) <- f v1.(i) v2.(i)
+    done;
+    res
+  end
+
+let array_for_all f v =
+  let rec allrec = function
+    | -1 -> true
+    | n -> (f v.(n)) && (allrec (n-1))
+  in
+  allrec ((Array.length v)-1)
+
+let array_fold_right_i f v a =
+  let rec fold a n =
+    if n=0 then a
+    else
+      let k = n-1 in
+      fold (f k v.(k) a) k in
+  fold a (Array.length v)
+
+let identity x = x
+
+let interval n m =
+  let rec interval_n (l,m) =
+    if n > m then l else interval_n (m::l,pred m)
+  in
+  interval_n ([],m)
+
+let map_status status f l =
+ List.fold_right
+  (fun x (status,res)->let status,y = f status x in status,y::res) l (status,[])
+
+(* CSC: Inefficiently implemented *)
+let array_map_status status f l =
+ let status,res = map_status status f (Array.to_list l) in
+  status,Array.of_list res
+
+(* CSC: Inefficiently implemented *)
+let array_mapi_status status f l =
+ let status,res = list_map_i_status status f 0 (Array.to_list l) in
+  status,Array.of_list res
+
+(* Pp.ml4 *)
+
+type block_type =
+  | Pp_hbox of int
+  | Pp_vbox of int
+  | Pp_hvbox of int
+  | Pp_hovbox of int
+  | Pp_tbox
+
+type 'a ppcmd_token =
+  | Ppcmd_print of 'a
+  | Ppcmd_box of block_type * ('a ppcmd_token Stream.t)
+  | Ppcmd_print_break of int * int
+  | Ppcmd_set_tab
+  | Ppcmd_print_tbreak of int * int
+  | Ppcmd_white_space of int
+  | Ppcmd_force_newline
+  | Ppcmd_print_if_broken
+  | Ppcmd_open_box of block_type
+  | Ppcmd_close_box
+  | Ppcmd_close_tbox
+  | Ppcmd_comment of int
+
+type ppcmd = (int*string) ppcmd_token
+
+type std_ppcmds = ppcmd Stream.t
+
+type 'a ppdir_token =
+  | Ppdir_ppcmds of 'a ppcmd_token Stream.t
+  | Ppdir_print_newline
+  | Ppdir_print_flush
+
+let utf8_length s =
+  let len = String.length s
+  and cnt = ref 0
+  and nc = ref 0
+  and p = ref 0 in
+  while !p < len do
+    begin
+      match s.[!p] with
+      | '\000'..'\127' -> nc := 0 (* ascii char *)
+      | '\128'..'\191' -> nc := 0 (* cannot start with a continuation byte *)
+      | '\192'..'\223' -> nc := 1 (* expect 1 continuation byte *)
+      | '\224'..'\239' -> nc := 2 (* expect 2 continuation bytes *)
+      | '\240'..'\247' -> nc := 3 (* expect 3 continuation bytes *)
+      | '\248'..'\251' -> nc := 4 (* expect 4 continuation bytes *)
+      | '\252'..'\253' -> nc := 5 (* expect 5 continuation bytes *)
+      | '\254'..'\255' -> nc := 0 (* invalid byte *)
+    end ;
+    incr p ;
+    while !p < len && !nc > 0 do
+      match s.[!p] with
+      | '\128'..'\191' (* next continuation byte *) -> incr p ; decr nc
+      | _ (* not a continuation byte *) -> nc := 0
+    done ;
+    incr cnt
+  done ;
+  !cnt
+
+let (++) = Stream.iapp
+let str s = [< 'Ppcmd_print (utf8_length s,s) >]
+let spc () = [< 'Ppcmd_print_break (1,0) >]
+let mt () = [< >]
+let v n s = [< 'Ppcmd_box(Pp_vbox n,s) >]
+let hv n s = [< 'Ppcmd_box(Pp_hvbox n,s) >]
+let hov n s = [< 'Ppcmd_box(Pp_hovbox n,s) >]
+let int n = str (string_of_int n)
+let stras (i,s) = [< 'Ppcmd_print (i,s) >]
+let fnl () = [< 'Ppcmd_force_newline >]
+
+let com_eol = ref false
+
+let com_brk _ft = com_eol := false
+let com_if ft f =
+  if !com_eol then (com_eol := false; Format.pp_force_newline ft ())
+  else Lazy.force f
+
+let comments = ref []
+
+let rec split_com comacc acc pos = function
+    [] -> comments := List.rev acc; comacc
+  | ((b,e),c as com)::coms ->
+      (* Take all comments that terminates before pos, or begin exactly
+         at pos (used to print comments attached after an expression) *)
+      if e<=pos || pos=b then split_com (c::comacc) acc pos coms
+      else  split_com comacc (com::acc) pos coms
+
+let rec pr_com ft s =
+  let (s1,os) =
+    try
+      let n = String.index s '\n' in
+      String.sub s 0 n, Some (String.sub s (n+1) (String.length s - n - 1))
+    with Not_found -> s,None in
+  com_if ft (Lazy.lazy_from_val());
+(*  let s1 =
+    if String.length s1 <> 0 && s1.[0] = ' ' then
+      (Format.pp_print_space ft (); String.sub s1 1 (String.length s1 - 1))
+    else s1 in*)
+  Format.pp_print_as ft (utf8_length s1) s1;
+  match os with
+      Some s2 ->
+        if String.length s2 = 0 then (com_eol := true)
+        else
+          (Format.pp_force_newline ft (); pr_com ft s2)
+    | None -> ()
+
+let pp_dirs ft =
+  let pp_open_box = function
+    | Pp_hbox _n   -> Format.pp_open_hbox ft ()
+    | Pp_vbox n   -> Format.pp_open_vbox ft n
+    | Pp_hvbox n  -> Format.pp_open_hvbox ft n
+    | Pp_hovbox n -> Format.pp_open_hovbox ft n
+    | Pp_tbox     -> Format.pp_open_tbox ft ()
+  in
+  let rec pp_cmd = function
+    | Ppcmd_print(n,s)        ->
+        com_if ft (Lazy.lazy_from_val()); Format.pp_print_as ft n s
+    | Ppcmd_box(bty,ss)       -> (* Prevent evaluation of the stream! *)
+        com_if ft (Lazy.lazy_from_val());
+        pp_open_box bty ;
+        if not (Format.over_max_boxes ()) then Stream.iter pp_cmd ss;
+        Format.pp_close_box ft ()
+    | Ppcmd_open_box bty      -> com_if ft (Lazy.lazy_from_val()); pp_open_box bty
+    | Ppcmd_close_box         -> Format.pp_close_box ft ()
+    | Ppcmd_close_tbox        -> Format.pp_close_tbox ft ()
+    | Ppcmd_white_space n     ->
+        com_if ft (Lazy.lazy_from_fun (fun()->Format.pp_print_break ft n 0))
+    | Ppcmd_print_break(m,n)  ->
+        com_if ft (Lazy.lazy_from_fun(fun()->Format.pp_print_break ft m n))
+    | Ppcmd_set_tab           -> Format.pp_set_tab ft ()
+    | Ppcmd_print_tbreak(m,n) ->
+        com_if ft (Lazy.lazy_from_fun(fun()->Format.pp_print_tbreak ft m n))
+    | Ppcmd_force_newline     ->
+        com_brk ft; Format.pp_force_newline ft ()
+    | Ppcmd_print_if_broken   ->
+        com_if ft (Lazy.lazy_from_fun(fun()->Format.pp_print_if_newline ft ()))
+    | Ppcmd_comment i         ->
+        let coms = split_com [] [] i !comments in
+(*        Format.pp_open_hvbox ft 0;*)
+        List.iter (pr_com ft) coms(*;
+        Format.pp_close_box ft ()*)
+  in
+  let pp_dir = function
+    | Ppdir_ppcmds cmdstream -> Stream.iter pp_cmd cmdstream
+    | Ppdir_print_newline    ->
+        com_brk ft; Format.pp_print_newline ft ()
+    | Ppdir_print_flush      -> Format.pp_print_flush ft ()
+  in
+  fun dirstream ->
+    try
+      Stream.iter pp_dir dirstream; com_brk ft
+    with
+      | e -> Format.pp_print_flush ft () ; raise e
+
+let pp_with ft strm =
+  pp_dirs ft [< 'Ppdir_ppcmds strm >]
+
+(* Util.ml *)
+
+let rec prlist_with_sep sep elem l = match l with
+  | []   -> mt ()
+  | [h]  -> elem h
+  | h::t ->
+      let e = elem h and s = sep() and r = prlist_with_sep sep elem t in
+      e ++ s ++ r
+
+let rec prlist_with_sep_status status sep elem l = match l with
+  | []   -> status,mt ()
+  | [h]  -> elem status h
+  | h::t ->
+      let status,e = elem status h in
+      let s = sep() in
+      let status,r = prlist_with_sep_status status sep elem t in
+      status, e ++ s ++ r
+
+let rec prlist elem l = match l with
+  | []   -> mt ()
+  | h::t -> Stream.lapp (fun () -> elem h) (prlist elem t)
+
+let rec prlist_strict elem l = match l with
+  | []   -> mt ()
+  | h::t ->
+      let e = elem h in let r = prlist_strict elem t in e++r
+
+let prvecti_with_sep sep elem v =
+  let rec pr i =
+    if i = 0 then
+      elem 0 v.(0)
+    else
+      let r = pr (i-1) and s = sep () and e = elem i v.(i) in
+      r ++ s ++ e
+  in
+  let n = Array.length v in
+  if n = 0 then mt () else pr (n - 1)
+
+let prvecti_with_sep_status status sep elem v =
+  let rec pr status i =
+    if i = 0 then
+     elem status 0 v.(0)
+    else
+      let status,r = pr status (i-1) in
+      let s = sep () in
+      let status,e = elem status i v.(i) in
+      status, r ++ s ++ e
+  in
+  let n = Array.length v in
+  if n = 0 then status,mt () else pr status (n - 1)
+
+let prvecti elem v = prvecti_with_sep mt elem v
+
+let prvecti_status status elem v = prvecti_with_sep_status status mt elem v
+
+let prvect_with_sep sep elem v = prvecti_with_sep sep (fun _ -> elem) v
+
+let prvect_with_sep_status status sep elem v =
+ prvecti_with_sep_status status sep (fun status _ -> elem status) v
+
+let prvect elem v = prvect_with_sep mt elem v
+
+(* Nameops.ml *)
+
+let pr_id id = str id
+
+(* ---- *)
diff --git a/matita/components/ng_extraction/coq.mli b/matita/components/ng_extraction/coq.mli
new file mode 100644 (file)
index 0000000..98639e8
--- /dev/null
@@ -0,0 +1,83 @@
+type identifier = string
+
+val next_ident_away : identifier -> identifier list -> identifier
+
+val lift_subscript   : identifier -> identifier
+
+type label
+type reference
+
+type env
+type constant_body
+type ('a,'b) prec_declaration
+
+type module_path
+type mod_bound_id
+
+module Intmap : Map.S with type key = int
+
+module Intset : Set.S with type elt = int
+
+module Uriset : Set.S with type elt = NUri.uri
+
+module Idset : Set.S with type elt=identifier
+
+module Refmap : Map.S with type key = NReference.reference
+
+module Stringmap : Map.S with type key = string
+
+module Pp_control : sig
+ val with_output_to : out_channel -> Format.formatter
+ val get_margin: unit -> int option
+end
+
+val iterate : ('a -> 'a) -> int -> 'a -> 'a
+val list_skipn : int -> 'a list -> 'a list
+val list_split_at : int -> 'a list -> 'a list*'a list
+val list_chop : int -> 'a list -> 'a list * 'a list
+val list_firstn : int -> 'a list -> 'a list
+val list_iter_i :  (int -> 'a -> unit) -> 'a list -> unit
+val list_lastn : int -> 'a list -> 'a list
+val array_map2 : ('a -> 'b -> 'c) -> 'a array -> 'b array -> 'c array
+val array_for_all : ('a -> bool) -> 'a array -> bool
+val array_fold_right_i :
+  (int -> 'b -> 'a -> 'a) -> 'b array -> 'a -> 'a
+val identity : 'a -> 'a
+val interval : int -> int -> int list
+val map_status: 's -> ('s -> 'a -> 's * 'b) -> 'a list -> 's * 'b list
+val array_map_status: 's -> ('s -> 'a -> 's * 'b) -> 'a array -> 's * 'b array
+val array_mapi_status :
+ 's -> ('s -> int -> 'a -> 's * 'b) -> 'a array -> 's * 'b array
+
+type std_ppcmds
+val (++) : std_ppcmds -> std_ppcmds -> std_ppcmds
+val spc : unit -> std_ppcmds
+val str : string -> std_ppcmds
+val mt : unit -> std_ppcmds
+val v : int -> std_ppcmds -> std_ppcmds
+val hv : int -> std_ppcmds -> std_ppcmds
+val hov : int -> std_ppcmds -> std_ppcmds
+val int : int -> std_ppcmds
+val stras : int * string -> std_ppcmds
+val fnl : unit -> std_ppcmds
+val prlist_with_sep_status :
+ 'a -> (unit -> std_ppcmds) -> ('a -> 'b -> 'a * std_ppcmds) -> 'b list ->
+   'a * std_ppcmds
+val prlist_with_sep :
+   (unit -> std_ppcmds) -> ('b -> std_ppcmds) -> 'b list -> std_ppcmds
+val pr_id : identifier -> std_ppcmds
+val prlist : ('a -> std_ppcmds) -> 'a list -> std_ppcmds
+val prlist_strict :  ('a -> std_ppcmds) -> 'a list -> std_ppcmds
+val prvect_with_sep :
+   (unit -> std_ppcmds) -> ('a -> std_ppcmds) -> 'a array -> std_ppcmds
+val prvect_with_sep_status :
+ 's -> (unit -> std_ppcmds) -> ('s -> 'a -> 's * std_ppcmds) -> 'a array -> 's * std_ppcmds
+val prvect : ('a -> std_ppcmds) -> 'a array -> std_ppcmds
+val prvecti : (int -> 'a -> std_ppcmds) -> 'a array -> std_ppcmds
+val prvecti_status :
+ 's -> ('s -> int -> 'a -> 's * std_ppcmds) -> 'a array -> 's * std_ppcmds
+val list_map_i : (int -> 'a -> 'b) -> int -> 'a list -> 'b list
+val list_map_i_status :
+ 's -> ('s -> int -> 'a -> 's * 'b) -> int -> 'a list -> 's * 'b list
+
+val pp_with : Format.formatter -> std_ppcmds -> unit
diff --git a/matita/components/ng_extraction/extraction.ml b/matita/components/ng_extraction/extraction.ml
new file mode 100644 (file)
index 0000000..c186aef
--- /dev/null
@@ -0,0 +1,1318 @@
+(************************************************************************)
+(*  v      *   The Coq Proof Assistant  /  The Coq Development Team     *)
+(* <O___,, *   INRIA - CNRS - LIX - LRI - PPS - Copyright 1999-2011     *)
+(*   \VV/  **************************************************************)
+(*    //   *      This file is distributed under the terms of the       *)
+(*         *       GNU Lesser General Public License Version 2.1        *)
+(************************************************************************)
+
+(*i $Id: extraction.ml 14786 2011-12-10 12:55:19Z letouzey $ i*)
+
+open Coq
+open Miniml
+open OcamlExtractionTable
+open Mlutil
+open Common
+
+(* A set of all fixpoint functions currently being extracted *)
+(*CSC: very imperative, fix/check?*)
+let current_fixpoints = ref (None : NUri.uri option)
+
+let whd_betadeltaiota status context t =
+ NCicReduction.whd status ~subst:[] context t
+
+let whd_betaiotazeta status context t =
+ NCicReduction.whd status ~delta:max_int ~subst:[] context t
+
+let isRel = function NCic.Rel _ -> true | _ -> false
+
+let rec split_all_prods status ~subst context te =
+  match NCicReduction.whd status ~subst context te with
+   | NCic.Prod (name,so,ta) ->
+       split_all_prods status ~subst ((name,(NCic.Decl so))::context) ta
+   | _ -> context,te
+;;
+
+(* (nb_lam [na1:T1]...[nan:Tan]c) where c is not an abstraction
+ * gives n *)
+let nb_lam =
+  let rec nbrec n =
+   function
+    | NCic.Lambda (_,_,c) -> nbrec (n+1) c
+    | _ -> n
+  in
+  nbrec 0
+
+(* Given a positive integer n, transforms a lambda term [x1:T1]..[xn:Tn]T
+   into the pair ([(xn,Tn);...;(x1,T1)],T) *)
+let decompose_lam_n n =
+  if n < 0 then assert false else
+  let rec lamdec_rec l n c =
+    if n=0 then l,c
+    else match c with
+      | NCic.Lambda (x,t,c) -> lamdec_rec ((x,NCic.Decl t)::l) (n-1) c
+      | _ -> assert false
+  in
+  lamdec_rec [] n
+
+let decompose_lam =
+  let rec lamdec_rec l =
+   function
+    | NCic.Lambda (x,t,c) -> lamdec_rec ((x,t)::l) c
+    | c                -> l,c
+  in
+  lamdec_rec []
+
+let splay_prod_n status context n =
+  let rec decrec context m ln c = if m = 0 then (ln,c) else
+    match whd_betadeltaiota status context c with
+      | NCic.Prod (n,a,c0) ->
+          decrec ((n,NCic.Decl a)::context)
+            (m-1) ((n,NCic.Decl a)::ln) c0
+      | _                      -> invalid_arg "splay_prod_n"
+  in
+  decrec context n []
+
+let splay_prod status context =
+  let rec decrec context m c =
+    let t = whd_betadeltaiota status context c in
+    match t with
+      | NCic.Prod (n,a,c0) ->
+          decrec ((n,NCic.Decl a)::context) ((n,NCic.Decl a)::m) c0
+      | _ -> m,t
+  in
+  decrec context []
+
+let type_of status context t =
+ NCicTypeChecker.typeof status ~subst:[] ~metasenv:[] context t
+
+type sorts_family = InProp | InType
+
+let classify_sort =
+ function
+    NCic.Prop -> InProp
+  | NCic.Type u ->
+     match NCicEnvironment.family_of u with
+        `CProp -> InProp
+      | `Type -> InType
+
+let sort_of status context t =
+ match
+  NCicTypeChecker.typeof status ~subst:[] ~metasenv:[] context t
+ with
+    NCic.Sort s -> classify_sort s
+  | _ -> assert false
+
+(*S Generation of flags and signatures. *)
+
+(* The type [flag] gives us information about any Coq term:
+   \begin{itemize}
+   \item [TypeScheme] denotes a type scheme, that is
+     something that will become a type after enough applications.
+     More formally, a type scheme has type $(x_1:X_1)\ldots(x_n:X_n)s$ with
+     [s = Set], [Prop] or [Type]
+   \item [Default] denotes the other cases. It may be inexact after
+     instanciation. For example [(X:Type)X] is [Default] and may give [Set]
+     after instanciation, which is rather [TypeScheme]
+   \item [Logic] denotes a term of sort [Prop], or a type scheme on sort [Prop]
+   \item [Info] is the opposite. The same example [(X:Type)X] shows
+     that an [Info] term might in fact be [Logic] later on.
+   \end{itemize} *)
+
+type info = Logic | Info
+
+type scheme = TypeScheme | Default
+
+type flag = info * scheme
+
+(*s [flag_of_type] transforms a type [t] into a [flag].
+  Really important function. *)
+
+let rec flag_of_type status context t =
+  let t = whd_betadeltaiota status context t in
+  match t with
+    | NCic.Prod (x,t,c) -> flag_of_type status ((x,NCic.Decl t)::context) c
+    | NCic.Sort s ->
+       (match classify_sort s with
+           InProp -> (Logic,TypeScheme)
+         | InType -> (Info,TypeScheme))
+    | _ ->
+      if (sort_of status context t) = InProp then (Logic,Default)
+      else (Info,Default)
+
+(*s Two particular cases of [flag_of_type]. *)
+
+let is_default status context t=(flag_of_type status context t= (Info, Default))
+
+exception NotDefault of kill_reason
+
+let check_default status context t =
+  match flag_of_type status context t with
+    | _,TypeScheme -> raise (NotDefault Ktype)
+    | Logic,_ -> raise (NotDefault Kother)
+    | _ -> ()
+
+let is_info_scheme status context t =
+ (flag_of_type status context t = (Info, TypeScheme))
+
+(*s [type_sign] generates a signature aimed at treating a type application. *)
+
+let rec type_sign status context c =
+  match whd_betadeltaiota status context c with
+    | NCic.Prod (n,t,d) ->
+        (if is_info_scheme status context t then Keep else Kill Kother)
+        :: (type_sign status ((n,NCic.Decl t)::context) d)
+    | _ -> []
+
+let rec type_scheme_nb_args status context c =
+  match whd_betadeltaiota status context c with
+    | NCic.Prod (n,t,d) ->
+        let n = type_scheme_nb_args status ((n,NCic.Decl t)::context) d in
+        if is_info_scheme status context t then n+1 else n
+    | _ -> 0
+
+(*CSC: only useful for inline extraction
+let _ = register_type_scheme_nb_args type_scheme_nb_args
+*)
+
+(*s [type_sign_vl] does the same, plus a type var list. *)
+
+let rec type_sign_vl status context c =
+  match whd_betadeltaiota status context c with
+    | NCic.Prod (n,t,d) ->
+        let s,vl = type_sign_vl status ((n,NCic.Decl t)::context) d in
+        if not (is_info_scheme status context t) then Kill Kother::s, vl
+        else Keep::s, (next_ident_away (id_of_name n) vl) :: vl
+    | _ -> [],[]
+
+let rec nb_default_params status context c =
+  match whd_betadeltaiota status context c with
+    | NCic.Prod (n,t,d) ->
+        let n = nb_default_params status ((n,NCic.Decl t)::context) d in
+        if is_default status context t then n+1 else n
+    | _ -> 0
+
+(* Enriching a signature with implicit information *)
+
+let sign_with_implicits _r s =
+  let implicits = [](*CSC: implicits_of_global r*) in
+  let rec add_impl i = function
+    | [] -> []
+    | sign::s ->
+        let sign' =
+          if sign = Keep && List.mem i implicits then Kill Kother else sign
+        in sign' :: add_impl (succ i) s
+  in
+  add_impl 1 s
+
+(* Enriching a exception message *)
+
+let rec handle_exn _r _n _fn_name = function x -> x
+(*CSC: only for pretty printing
+  | MLexn s ->
+      (try Scanf.sscanf s "UNBOUND %d"
+         (fun i ->
+            assert ((0 < i) && (i <= n));
+            MLexn ("IMPLICIT "^ msg_non_implicit r (n+1-i) (fn_name i)))
+       with _ -> MLexn s)
+  | a -> ast_map (handle_exn r n fn_name) a*)
+
+(*S Management of type variable contexts. *)
+
+(* A De Bruijn variable context (db) is a context for translating Coq [Rel]
+   into ML type [Tvar]. *)
+
+(*s From a type signature toward a type variable context (db). *)
+
+let db_from_sign s =
+  let rec make i acc = function
+    | [] -> acc
+    | Keep :: l -> make (i+1) (i::acc) l
+    | Kill _ :: l -> make i (0::acc) l
+  in make 1 [] s
+
+(*s Create a type variable context from indications taken from
+  an inductive type (see just below). *)
+
+let rec db_from_ind dbmap i =
+  if i = 0 then []
+  else (try Intmap.find i dbmap with Not_found -> 0)::(db_from_ind dbmap (i-1))
+
+(*s [parse_ind_args] builds a map: [i->j] iff the i-th Coq argument
+  of a constructor corresponds to the j-th type var of the ML inductive. *)
+
+(* \begin{itemize}
+   \item [si] : signature of the inductive
+   \item [i] :  counter of Coq args for [(I args)]
+   \item [j] : counter of ML type vars
+   \item [relmax] : total args number of the constructor
+   \end{itemize} *)
+
+let parse_ind_args si args relmax =
+  let rec parse i j = function
+    | [] -> Intmap.empty
+    | Kill _ :: s -> parse (i+1) j s
+    | Keep :: s ->
+      (match args.(i-1) with
+         | NCic.Rel k -> Intmap.add (relmax+1-k) j (parse (i+1) (j+1) s)
+         | _ -> parse (i+1) (j+1) s)
+  in parse 1 1 si
+
+(*S Extraction of a type. *)
+
+(* [extract_type env db c args] is used to produce an ML type from the
+   coq term [(c args)], which is supposed to be a Coq type. *)
+
+(* [db] is a context for translating Coq [Rel] into ML type [Tvar]. *)
+
+(* [j] stands for the next ML type var. [j=0] means we do not
+   generate ML type var anymore (in subterms for example). *)
+
+
+let rec extract_type status context db j c args =
+  match whd_betaiotazeta status context c with
+    | NCic.Appl (d::args') ->
+        (* We just accumulate the arguments. *)
+        extract_type status context db j d (args' @ args)
+    | NCic.Lambda (_,_,d) ->
+        (match args with
+           | [] -> assert false (* otherwise the lambda would be reductible. *)
+           | a :: args -> extract_type status context db j (NCicSubstitution.subst status a d) args)
+    | NCic.Prod (n,t,d) ->
+        assert (args = []);
+        let context' = (n,NCic.Decl t)::context in
+        (match flag_of_type status context t with
+           | (Info, Default) ->
+               (* Standard case: two [extract_type] ... *)
+               let status,mld = extract_type status context' (0::db) j d [] in
+               let status,res = expand status mld in
+               (match res with
+                  | Tdummy d -> status,Tdummy d
+                  | _ ->
+                    let status,res=extract_type status context db 0 t []  in
+                     status,Tarr (res, mld))
+           | (Info, TypeScheme) when j > 0 ->
+               (* A new type var. *)
+               let status,mld=extract_type status context' (j::db) (j+1) d [] in
+               let status,res = expand status mld in
+               status,
+               (match res with
+                  | Tdummy d -> Tdummy d
+                  | _ -> Tarr (Tdummy Ktype, mld))
+           | _,lvl ->
+               let status,mld = extract_type status context' (0::db) j d [] in
+               let status,res = expand status mld in
+               status,
+               (match res with
+                  | Tdummy d -> Tdummy d
+                  | _ ->
+                      let reason = if lvl=TypeScheme then Ktype else Kother in
+                      Tarr (Tdummy reason, mld)))
+    | NCic.Sort _ -> status,Tdummy Ktype (* The two logical cases. *)
+    | _ when sort_of status context (NCicUntrusted.mk_appl c args) = InProp ->
+       status,Tdummy Kother
+    | NCic.Rel n ->
+        (match List.nth context (n-1) with
+           | (_,NCic.Def (t,_)) -> extract_type status context db j (NCicSubstitution.lift status n t) args
+           | _ ->
+               (* Asks [db] a translation for [n]. *)
+               if n > List.length db then status,Tunknown
+               else let n' = List.nth db (n-1) in
+               status,if n' = 0 then Tunknown else Tvar n')
+    | NCic.Const (NReference.Ref (uri,spec) as r) ->
+       (match spec with
+           NReference.Decl ->
+            let _,_,typ,_,_ = NCicEnvironment.get_checked_decl status r in
+            (match flag_of_type status [] typ with
+               | (Info, TypeScheme) ->
+                  extract_type_app status context db
+                   (r, type_sign status [] typ) args
+               | _ -> (* only other case here: Info, Default, i.e. not an ML type *)
+                   status,Tunknown (* Brutal approximation ... *))
+         | NReference.Def _ ->
+            let _,_,bo,typ,_,_ = NCicEnvironment.get_checked_def status r in
+            (match flag_of_type status [] typ with
+               | (Info, TypeScheme) ->
+                   let status,mlt =
+                    extract_type_app status context db
+                     (r, type_sign status [] typ) args in
+                   (*CSC: if is_custom r then mlt else*)
+                   let newc = NCicUntrusted.mk_appl bo args in
+                   let status,mlt' = extract_type status context db j newc [] in
+                   (* ML type abbreviations interact badly with Coq *)
+                   (* reduction, so [mlt] and [mlt'] might be different: *)
+                   (* The more precise is [mlt'], extracted after reduction *)
+                   (* The shortest is [mlt], which use abbreviations *)
+                   (* If possible, we take [mlt], otherwise [mlt']. *)
+                   let status,res1 = expand status mlt in
+                   let status,res2 = expand status mlt' in
+                   if res1=res2 then status,mlt else status,mlt'
+               | _ -> (* only other case here: Info, Default, i.e. not an ML type *)
+                      (* We try to reduce. *)
+                      let newc = NCicUntrusted.mk_appl bo args in
+                      extract_type status context db j newc [])
+         | NReference.Fix _ -> status,Tunknown
+         | NReference.Con _
+         | NReference.CoFix _ -> assert false
+         | NReference.Ind (_,i,_) ->
+            let status,ind = extract_ind status uri in
+            let s = ind.ind_packets.(i).ip_sign in
+             extract_type_app status context db (r,s) args)
+    | NCic.Match _ -> status,Tunknown
+    | _ -> assert false
+
+(*s Auxiliary function dealing with type application.
+  Precondition: [r] is a type scheme represented by the signature [s],
+  and is completely applied: [List.length args = List.length s]. *)
+
+and extract_type_app status context db (r,s) args =
+  let status,ml_args =
+    List.fold_right
+      (fun (b,c) (status,a) ->
+        if b=Keep then
+         let p =
+          List.length
+           (fst (splay_prod status context (type_of status context c))) in
+         let db = iterate (fun l -> 0 :: l) p db in
+         let status,res = extract_type_scheme status context db c p in
+          status,res::a
+        else status,a)
+      (List.combine s args) (status,[])
+  in status, Tglob (r,  ml_args)
+
+(*S Extraction of a type scheme. *)
+
+(* [extract_type_scheme env db c p] works on a Coq term [c] which is
+  an informative type scheme. It means that [c] is not a Coq type, but will
+  be when applied to sufficiently many arguments ([p] in fact).
+  This function decomposes p lambdas, with eta-expansion if needed. *)
+
+(* [db] is a context for translating Coq [Rel] into ML type [Tvar]. *)
+
+and extract_type_scheme status context db c p =
+  if p=0 then extract_type status context db 0 c []
+  else
+    let c = whd_betaiotazeta status context c in
+    match c with
+      | NCic.Lambda (n,t,d) ->
+          extract_type_scheme status((n,NCic.Decl t)::context) db d (p-1)
+      | _ ->
+          let rels=fst (splay_prod status context (type_of status context c)) in
+          let context = rels@context in
+          let eta_args = List.rev_map (fun x -> NCic.Rel x) (interval 1 p) in
+          extract_type status context db 0 (NCicSubstitution.lift status p c)
+           eta_args
+
+
+(*S Extraction of an inductive type. *)
+
+and extract_ind status uri =
+ try
+  status,lookup_ind status uri
+ with Not_found ->
+  let _,_,_,_,obj = NCicEnvironment.get_checked_obj status uri in
+  match obj with
+     NCic.Inductive (inductive,leftno,types,(_,ind_pragma)) ->
+      extract_ind0 status uri inductive ind_pragma leftno types
+   | _ -> assert false
+
+and extract_ind0 status uri inductive ind_pragma leftno types =
+    (* First, if this inductive is aliased via a Module, *)
+    (* we process the original inductive. *)
+    (* Everything concerning parameters. *)
+    (* We do that first, since they are common to all the [mib]. *)
+    let _,_,mipty0,_ = List.hd types in
+    let mipcontext,_=NCicReduction.split_prods status ~subst:[] [] ~-1 mipty0 in
+    let epar_rev,_= HExtlib.split_nth leftno (List.rev mipcontext) in
+    let epar = List.rev epar_rev in
+    (* First pass: we store inductive signatures together with *)
+    (* their type var list. *)
+    let packets =
+      Array.mapi
+        (fun tyno (_,name,arity,kl) ->
+           let _,sort=NCicReduction.split_prods status ~subst:[] [] ~-1 arity in
+           let sort=match sort with NCic.Sort sort -> sort | _ ->assert false in
+           let b = classify_sort sort <> InProp in
+           let s,v = if b then type_sign_vl status [] arity else [],[] in
+           let t = Array.make (List.length kl) [] in
+           let kl = Array.of_list kl in
+           let spec = NReference.Ind (inductive,tyno,leftno) in
+           let ref = NReference.reference_of_spec uri spec in
+           { ip_reference = ref;
+             ip_consreferences =
+              Array.mapi
+               (fun i _ ->
+                 NReference.reference_of_spec uri
+                  (NReference.Con (tyno,i+1,leftno))
+               ) kl;
+             ip_typename = name;
+             ip_consnames= Array.map (fun (_,name,_) -> name) kl;
+             ip_logical = (not b);
+             ip_sign = s;
+             ip_vars = v;
+             ip_types = t
+           })
+        (Array.of_list types)
+    in
+    let status = add_ind ~dummy:true status uri
+      {ind_kind = Standard;
+       ind_nparams = leftno;
+       ind_packets = packets
+      } in
+    (* Second pass: we extract constructors *)
+    let rec aux1 i status =
+     if i = List.length types then status
+     else begin
+      let p = packets.(i) in
+      let _,_,_,cl = List.nth types i in
+      if not p.ip_logical then
+        let ktypes = Array.of_list (List.map (fun (_,_,arity) -> arity) cl) in
+        let rec aux2 j status =
+         if j = Array.length ktypes then status
+         else begin
+          let tctx,t =
+           NCicReduction.split_prods status ~subst:[] [] leftno ktypes.(j) in
+          let prods,head = split_all_prods status ~subst:[] tctx t in
+          let nprods = List.length prods in
+          let args = match head with
+            | NCic.Appl (_f::args) -> Array.of_list args (* [f = Ind ip] *)
+            | _ -> [||]
+          in
+          let dbmap = parse_ind_args p.ip_sign args nprods in
+          let db = db_from_ind dbmap leftno in
+          let status,res = extract_type_cons status epar db dbmap t (leftno+1)in
+          p.ip_types.(j) <- res;
+          aux2 (j+1) status
+         end
+        in
+         let status = aux2 0 status in
+         aux1 (i+1) status
+      else begin
+       aux1 (i+1) status
+      end
+     end in
+    let status = aux1 0 status in
+    (* Third pass: we determine special cases. *)
+    let status,ind_info =
+     (*CSC: let ip = (kn, 0) in
+     let r = IndRef ip in
+     if is_custom r then raise_I status Standard;*)
+     if not inductive then status,Coinductive else
+     if List.length types <> 1 then status,Standard else
+     let p = packets.(0) in
+     if p.ip_logical then status,Standard else
+     if Array.length p.ip_types <> 1 then status,Standard else
+     let typ = p.ip_types.(0) in
+     let status,l =
+      List.fold_right
+       (fun x (status,res) ->
+         let status,y = expand status x in
+          status,y::res
+       ) typ (status,[]) in
+     let l = List.filter (fun t -> not (isDummy t)) l in
+     if List.length l = 1 && not (type_mem_kn uri (List.hd l))
+     then status,Singleton else
+     if l = [] then status,Standard else
+     (match ind_pragma with
+         `Regular -> status,Standard
+       | `Record fields ->
+           let baseuri = NUri.baseuri_of_uri uri in
+           let field_names = List.map (fun (n,_,_) -> n) fields in
+           assert (List.length field_names = List.length typ);
+           let rec select_fields status l typs = match l,typs with
+             | [],[] -> status,[]
+             | id::l, typ::typs ->
+                let status,res = expand status typ in
+                if isDummy res then
+                 select_fields status l typs
+                else
+                 (* Is it safe to use [id] for projections [foo.id] ? *)
+                 let status,res = type2signature status typ in
+                 let fielduri =
+                  NUri.uri_of_string (baseuri ^ "/" ^ id ^ ".con") in
+                 let fieldfakeref =
+                  NReference.reference_of_spec fielduri fake_spec in
+(*
+                 let ref =
+                  try
+                   let fieldspec =
+                    let (_,height,_,_,obj) =
+                     NCicEnvironment.get_checked_obj status fielduri
+                    in
+                     match obj with
+                        NCic.Fixpoint (_,fs,(_,_,`Projection)) ->
+                         let _,_,recparamno,_,_ = List.nth fs 0 in
+                         NReference.Fix (0,recparamno,height)
+                      | _ -> assert false
+                   in
+                    NReference.reference_of_spec fielduri fieldspec
+                  with NCicEnvironment.ObjectNotFound _ ->
+                    assert false
+                 in *)
+                 let status =
+                  if List.for_all ((=) Keep) res
+                  then
+                   let n = nb_default_params status [] mipty0 in
+                    guess_projection status fielduri n
+                  else status in
+                 let status,res = select_fields status l typs in
+                 status, fieldfakeref::res
+             | _ -> assert false
+           in
+           let status,field_glob = select_fields status field_names typ in
+           (* Is this record officially declared with its projections ? *)
+           (* If so, we use this information. *)
+           status, Record field_glob)
+    in
+    let i = {ind_kind = ind_info;
+             ind_nparams = leftno;
+             ind_packets = packets
+            } in
+    let status = add_ind status uri i in
+     status,i
+
+(*s [extract_type_cons] extracts the type of an inductive
+  constructor toward the corresponding list of ML types.
+
+   - [db] is a context for translating Coq [Rel] into ML type [Tvar]
+   - [dbmap] is a translation map (produced by a call to [parse_in_args])
+   - [i] is the rank of the current product (initially [params_nb+1])
+*)
+
+and extract_type_cons status context db dbmap c i =
+  match whd_betadeltaiota status context c with
+    | NCic.Prod (n,t,d) ->
+        let context' = (n,NCic.Decl t)::context in
+        let db' = (try Intmap.find i dbmap with Not_found -> 0) :: db in
+        let status,l = extract_type_cons status context' db' dbmap d (i+1) in
+        let status, res = extract_type status context db 0 t [] in
+        status, res::l
+    | _ -> status,[]
+
+(*s Recording the ML type abbreviation of a Coq type scheme constant. *)
+
+and mlt_env status r =
+ try
+  if false (*CSC:XXX not (visible_con kn)*) then raise Not_found;
+  match lookup_term status r with
+   | Dtype (_,_vl,mlt) -> Some (status,mlt)
+   | _ -> None
+ with Not_found ->
+  match r with
+     NReference.Ref (_,NReference.Def _) ->
+      let _,_,body,typ,_,_ = NCicEnvironment.get_checked_def status r in
+       (match flag_of_type status [] typ with
+          | Info,TypeScheme ->
+              let s,vl = type_sign_vl status [] typ in
+              let db = db_from_sign s in
+              let status,t =
+               extract_type_scheme status [] db body (List.length s) in
+              let status = add_term status r (Dtype (r, vl, t)) in
+               Some (status,t)
+          | _ -> None)
+   | NReference.Ref (_,NReference.Decl) -> None
+   | NReference.Ref (_,NReference.Fix _)
+   | NReference.Ref (_,NReference.CoFix _) -> assert false
+   | NReference.Ref (_,NReference.Ind _)
+   | NReference.Ref (_,NReference.Con _) -> None
+
+and expand status = type_expand status mlt_env
+and type2signature status = type_to_signature status mlt_env
+let type2sign status = type_to_sign status mlt_env
+let type_expunge status = type_expunge status mlt_env
+let type_expunge_from_sign status = type_expunge_from_sign status mlt_env
+
+(*s Extraction of the type of a constant. *)
+
+let type_of_constant status (NReference.Ref (uri,spec)) =
+ let (_,_,_,_,obj) = NCicEnvironment.get_checked_obj status uri in
+ match obj,spec with
+    NCic.Constant (_,_,_,typ,_),_ -> typ
+  | NCic.Fixpoint (_,fs,_), (NReference.Fix (n,_,_) | NReference.CoFix n) ->
+     let _,_,_,typ,_ = List.nth fs n in
+      typ
+  | _ -> assert false
+
+let record_constant_type status r opt_typ =
+  try
+(*CSC:XXX to be implemented?    if not (visible_con kn) then raise Not_found;*)
+    status,lookup_type status r
+  with Not_found ->
+    let typ = match opt_typ with
+      | None -> type_of_constant status r
+      | Some typ -> typ in
+    let status,mlt = extract_type status [] [] 1 typ [] in
+    let schema = (type_maxvar mlt, mlt) in
+    let status = add_type status r schema in
+     status,schema
+
+(*S Extraction of a term. *)
+
+(* Precondition: [(c args)] is not a type scheme, and is informative. *)
+
+(* [mle] is a ML environment [Mlenv.t]. *)
+(* [mlt] is the ML type we want our extraction of [(c args)] to have. *)
+
+let rec extract_term status context mle mlt c args =
+  match c with
+      NCic.Appl [] -> assert false
+    | NCic.Appl (f::a) ->
+        extract_term status context mle mlt f (a@args)
+    | NCic.Lambda (n, t, d) ->
+        let id = n in
+        (match args with
+           | a :: l ->
+               (* We make as many [LetIn] as possible. *)
+                let d' = NCic.LetIn (id,t,a,NCic.Appl (d::(List.map (NCicSubstitution.lift status 1) l)))
+               in extract_term status context mle mlt d' []
+           | [] ->
+               let context' = (id, NCic.Decl t)::context in
+               let id, a =
+                 try check_default status context t; Id id, new_meta()
+                 with NotDefault d -> Dummy, Tdummy d
+               in
+               let b = new_meta () in
+               (* If [mlt] cannot be unified with an arrow type, then magic! *)
+               let magic = needs_magic (mlt, Tarr (a, b)) in
+               let status,d' =
+                extract_term status context' (Mlenv.push_type mle a) b d [] in
+               status,put_magic_if magic (MLlam (id, d')))
+    | NCic.LetIn (n, t1, c1, c2) ->
+        let id = n in
+        let context' = (id, NCic.Def (c1, t1))::context in
+        let args' = List.map (NCicSubstitution.lift status 1) args in
+        (try
+          check_default status context t1;
+          let a = new_meta () in
+          let status,c1' = extract_term status context mle a c1 [] in
+          (* The type of [c1'] is generalized and stored in [mle]. *)
+          let mle' =
+            if generalizable c1'
+            then Mlenv.push_gen mle a
+            else Mlenv.push_type mle a
+          in
+          let status,res = extract_term status context' mle' mlt c2 args' in
+          status,MLletin (Id id, c1', res)
+        with NotDefault d ->
+          let mle' = Mlenv.push_std_type mle (Tdummy d) in
+          let status,res = extract_term status context' mle' mlt c2 args' in
+          status,ast_pop res)
+    | NCic.Const ((NReference.Ref (uri,
+       ( NReference.Decl
+       | NReference.Def _
+       | NReference.Fix _
+       | NReference.CoFix _ ))) as ref) ->
+        extract_cst_app status context mle mlt uri ref args
+    | NCic.Const ((NReference.Ref (_,(NReference.Con _))) as ref) ->
+        extract_cons_app status context mle mlt ref args
+    | NCic.Rel n ->
+        (* As soon as the expected [mlt] for the head is known, *)
+        (* we unify it with an fresh copy of the stored type of [Rel n]. *)
+        let extract_rel status mlt =
+         status,put_magic (mlt, Mlenv.get mle n) (MLrel n)
+        in extract_app status context mle mlt extract_rel args
+    | NCic.Match (ref,_,c0,br) ->
+         extract_app status context mle mlt
+         (extract_case context mle (ref,c0,Array.of_list br)) args
+    | NCic.Const (NReference.Ref (_,NReference.Ind _))
+    | NCic.Prod _
+    | NCic.Sort _
+    | NCic.Implicit _
+    | NCic.Meta _ -> assert false
+
+(*s [extract_maybe_term] is [extract_term] for usual terms, else [MLdummy] *)
+
+and extract_maybe_term status context mle mlt c =
+  try check_default status context (type_of status context c);
+    extract_term status context mle mlt c []
+  with NotDefault d ->
+    status,put_magic (mlt, Tdummy d) MLdummy
+
+(*s Generic way to deal with an application. *)
+
+(* We first type all arguments starting with unknown meta types.
+   This gives us the expected type of the head. Then we use the
+   [mk_head] to produce the ML head from this type. *)
+
+and extract_app status context mle mlt mk_head args =
+  let metas = List.map new_meta args in
+  let type_head = type_recomp (metas, mlt) in
+  let status,mlargs =
+   List.fold_right2
+    (fun x y (status,res) ->
+      let status,z = extract_maybe_term status context mle x y in
+       status,z::res
+    ) metas args (status,[]) in
+  let status,res = mk_head status type_head in
+  status,mlapp res mlargs
+
+(*s Auxiliary function used to extract arguments of constant or constructor. *)
+
+and make_mlargs status context e s args typs =
+  let rec f status = function
+    | [], [], _ -> status,[]
+    | a::la, t::lt, [] ->
+       let status,res = extract_maybe_term status context e t a in
+       let status,res2 = f status (la,lt,[]) in
+       status, res :: res2
+    | a::la, t::lt, Keep::s ->
+       let status,res = extract_maybe_term status context e t a in
+       let status,res2 = f status (la,lt,s) in
+        status, res :: res2
+    | _::la, _::lt, _::s -> f status (la,lt,s)
+    | _ -> assert false
+  in f status (args,typs,s)
+
+(*s Extraction of a constant applied to arguments. *)
+
+and extract_cst_app status context mle mlt uri ref args =
+  (* First, the [ml_schema] of the constant, in expanded version. *)
+  let status,(nb,t) = record_constant_type status ref None in
+  let status,res = expand status t in
+  let schema = nb, res in
+  (* Can we instantiate types variables for this constant ? *)
+  (* In Ocaml, inside the definition of this constant, the answer is no. *)
+  let instantiated =
+    if
+     match !current_fixpoints with None -> false | Some uri' -> NUri.eq uri uri'
+    then var2var' (snd schema)
+    else instantiation schema
+  in
+  (* Then the expected type of this constant. *)
+  let a = new_meta () in
+  (* We compare stored and expected types in two steps. *)
+  (* First, can [kn] be applied to all args ? *)
+  let metas = List.map new_meta args in
+  let magic1 = needs_magic (type_recomp (metas, a), instantiated) in
+  (* Second, is the resulting type compatible with the expected type [mlt] ? *)
+  let magic2 = needs_magic (a, mlt) in
+  (* The internal head receives a magic if [magic1] *)
+  let head = put_magic_if magic1 (MLglob ref) in
+  (* Now, the extraction of the arguments. *)
+  let status,s_full = type2signature status (snd schema) in
+  let s_full = sign_with_implicits ref s_full in
+  let s = sign_no_final_keeps s_full in
+  let ls = List.length s in
+  let la = List.length args in
+  (* The ml arguments, already expunged from known logical ones *)
+  let status,mla = make_mlargs status context mle s args metas in
+  let mla =
+    if not magic1 then
+      try
+        let l,l' = list_chop (projection_arity status ref) mla in
+        if l' <> [] then (List.map (fun _ -> MLexn "Proj Args") l) @ l'
+        else mla
+      with _ -> mla
+    else mla
+  in
+  (* For strict languages, purely logical signatures with at least
+     one [Kill Kother] lead to a dummy lam. So a [MLdummy] is left
+     accordingly. *)
+  let optdummy = match sign_kind s_full with
+    | UnsafeLogicalSig -> [MLdummy]
+    | _ -> []
+  in
+  (* Different situations depending of the number of arguments: *)
+  if la >= ls
+  then
+    (* Enough args, cleanup already done in [mla], we only add the
+       additionnal dummy if needed. *)
+    status,put_magic_if (magic2 && not magic1) (mlapp head (optdummy @ mla))
+  else
+    (* Partially applied function with some logical arg missing.
+       We complete via eta and expunge logical args. *)
+    let ls' = ls-la in
+    let s' = list_skipn la s in
+    let mla = (List.map (ast_lift ls') mla) @ (eta_args_sign ls' s') in
+    let e = anonym_or_dummy_lams (mlapp head mla) s' in
+    status,put_magic_if magic2 (remove_n_lams (List.length optdummy) e)
+
+(*s Extraction of an inductive constructor applied to arguments. *)
+
+(* \begin{itemize}
+   \item In ML, contructor arguments are uncurryfied.
+   \item We managed to suppress logical parts inside inductive definitions,
+   but they must appears outside (for partial applications for instance)
+   \item We also suppressed all Coq parameters to the inductives, since
+   they are fixed, and thus are not used for the computation.
+   \end{itemize} *)
+
+and extract_cons_app status context mle mlt ref (*(((kn,i) as ip,j) as cp)*) args =
+  let uri,i,j =
+   match ref with
+      NReference.Ref (uri,NReference.Con(i,j,_)) -> uri,i,j
+    | _ -> assert false in
+  let b,_,_,_,_ = NCicEnvironment.get_checked_indtys status ref in
+  let tyref = NReference.mk_indty b ref in
+  (* First, we build the type of the constructor, stored in small pieces. *)
+  let status,mi = extract_ind status uri in
+  let params_nb = mi.ind_nparams in
+  let oi = mi.ind_packets.(i) in
+  let nb_tvars = List.length oi.ip_vars in
+  let status,types =
+   List.fold_right
+    (fun x (status,res) ->
+      let status,y = expand status x in
+       status,y::res
+    ) oi.ip_types.(j-1) (status,[]) in
+  let list_tvar = List.map (fun i -> Tvar i) (interval 1 nb_tvars) in
+  let type_cons = type_recomp (types, Tglob (tyref, list_tvar)) in
+  let type_cons = instantiation (nb_tvars, type_cons) in
+  (* Then, the usual variables [s], [ls], [la], ... *)
+  let status,s =
+   List.fold_right
+    (fun x (status,res) ->
+      let status,y = type2sign status x in
+       status,y::res)
+    types (status,[]) in
+  let s = sign_with_implicits ref s in
+  let ls = List.length s in
+  let la = List.length args in
+  assert (la <= ls + params_nb);
+  let la' = max 0 (la - params_nb) in
+  let args' = list_lastn la' args in
+  (* Now, we build the expected type of the constructor *)
+  let metas = List.map new_meta args' in
+  (* If stored and expected types differ, then magic! *)
+  let a = new_meta () in
+  let magic1 = needs_magic (type_cons, type_recomp (metas, a)) in
+  let magic2 = needs_magic (a, mlt) in
+  let head status mla =
+    if mi.ind_kind = Singleton then
+      status, put_magic_if magic1 (List.hd mla)
+    else
+      let status,typeargs = match snd (type_decomp type_cons) with
+        | Tglob (_,l) ->
+           List.fold_right
+            (fun x (status,res) ->
+              let status,y = type_simpl status x in
+               status,y::res)
+            l (status,[])
+        | _ -> assert false
+      in
+      let info = {c_kind = mi.ind_kind; c_typs = typeargs} in
+      status, put_magic_if magic1 (MLcons (info, ref, mla))
+  in
+  (* Different situations depending of the number of arguments: *)
+  if la < params_nb then
+    let status,head' = head status (eta_args_sign ls s) in
+    status,
+    put_magic_if magic2
+      (dummy_lams (anonym_or_dummy_lams head' s) (params_nb - la))
+  else
+    let status,mla = make_mlargs status context mle s args' metas in
+    if la = ls + params_nb
+    then
+     let status,res = head status mla in
+      status,put_magic_if (magic2 && not magic1) res
+    else (* [ params_nb <= la <= ls + params_nb ] *)
+      let ls' = params_nb + ls - la in
+      let s' = list_lastn ls' s in
+      let mla = (List.map (ast_lift ls') mla) @ (eta_args_sign ls' s') in
+      let status,res = head status mla in
+       status,put_magic_if magic2 (anonym_or_dummy_lams res s')
+
+(*S Extraction of a case. *)
+
+and extract_case context mle (ip,c,br) status mlt =
+  (* [br]: bodies of each branch (in functional form) *)
+  (* [ni]: number of arguments without parameters in each branch *)
+  let uri,i =
+   match ip with
+      NReference.Ref (uri,NReference.Ind (_,i,_)) -> uri,i
+    | _ -> assert false
+  in
+  let br_size = Array.length br in
+  if br_size = 0 then begin
+    (*CSC: to be implemented only if we allow inlining of recursors add_recursors env kn; (* May have passed unseen if logical ... *)*)
+    status,MLexn "absurd case"
+  end else
+    (* [c] has an inductive type, and is not a type scheme type. *)
+    let t = type_of status context c in
+    (* The only non-informative case: [c] is of sort [Prop] *)
+    if (sort_of status context t) = InProp then
+      begin
+        (*CSC: to be implemented only if we allow inlining of recursors add_recursors env kn; (* May have passed unseen if logical ... *)*)
+        (* Logical singleton case: *)
+        (* [match c with C i j k -> t] becomes [t'] *)
+        assert (br_size = 1);
+        let ni =
+         let _,leftno,tys,_,_ = NCicEnvironment.get_checked_indtys status ip in
+         let _,_,_,cl = List.hd tys in
+         let _,_,cty = List.hd cl in
+         let prods,_ = split_all_prods status ~subst:[] [] cty in
+         List.length prods - leftno
+        in
+        let s = iterate (fun l -> Kill Kother :: l) ni [] in
+        let mlt = iterate (fun t -> Tarr (Tdummy Kother, t)) ni mlt in
+        let status,e = extract_maybe_term status context mle mlt br.(0) in
+        status, snd (case_expunge s e)
+      end
+    else
+      let status,mi = extract_ind status uri in
+      let oi = mi.ind_packets.(i) in
+      let metas = Array.init (List.length oi.ip_vars) new_meta in
+      (* The extraction of the head. *)
+      let type_head = Tglob (ip, Array.to_list metas) in
+      let status,a = extract_term status context mle type_head c [] in
+      (* The extraction of each branch. *)
+      let extract_branch status i =
+        let r = NReference.mk_constructor (i+1) ip in
+        (* The types of the arguments of the corresponding constructor. *)
+        let f status t =
+         let status,res = expand status t in
+         status,type_subst_vect metas res in
+        let status,l =
+         List.fold_right
+          (fun x (status,res) ->
+            let status,y = f status x in
+             status,y::res)
+          oi.ip_types.(i) (status,[]) in
+        (* the corresponding signature *)
+        let status,s =
+         List.fold_right
+          (fun x (status,res) ->
+            let status,y = type2sign status x in
+             status,y::res)
+          oi.ip_types.(i) (status,[]) in
+        let s = sign_with_implicits r s in
+        (* Extraction of the branch (in functional form). *)
+        let status,e =
+         extract_maybe_term status context mle (type_recomp (l,mlt)) br.(i) in
+        (* We suppress dummy arguments according to signature. *)
+        let ids,e = case_expunge s e in
+        let e' = handle_exn r (List.length s) (fun _ -> "_") e in
+        status,(r, List.rev ids, e')
+      in
+      if mi.ind_kind = Singleton then
+        begin
+          (* Informative singleton case: *)
+          (* [match c with C i -> t] becomes [let i = c' in t'] *)
+          assert (br_size = 1);
+          let status,(_,ids,e') = extract_branch status 0 in
+          assert (List.length ids = 1);
+          status,MLletin (tmp_id (List.hd ids),a,e')
+        end
+      else
+        (* Standard case: we apply [extract_branch]. *)
+        let status,typs = List.fold_right
+         (fun x (status,res) ->
+           let status,y = type_simpl status x in
+            status,y::res)
+         (Array.to_list metas) (status,[]) in
+        let info={ m_kind = mi.ind_kind; m_typs = typs; m_same = BranchNone } in
+        let status,res =
+         array_fold_right_i
+          (fun i _ (status,res) ->
+            let status,y = extract_branch status i in
+             status,y::res) br (status,[])
+        in
+         status,MLcase (info, a, Array.of_list res)
+
+(*S ML declarations. *)
+
+(* [decomp_lams_eta env c t] finds the number [n] of products in the type [t],
+   and decompose the term [c] in [n] lambdas, with eta-expansion if needed. *)
+
+let rec decomp_lams_eta_n n m status context c t =
+  let rels = fst (splay_prod_n status context n t) in
+  let rels',c = decompose_lam c in
+  let d = n - m in
+  (* we'd better keep rels' as long as possible. *)
+  let rels=(list_firstn d rels)@(List.map (fun (n,t) -> n, NCic.Decl t) rels')in
+  let eta_args = List.rev_map (fun n -> NCic.Rel n) (interval 1 d) in
+  rels, NCic.Appl ((NCicSubstitution.lift status d c)::eta_args)
+
+(* Let's try to identify some situation where extracted code
+   will allow generalisation of type variables *)
+
+let rec gentypvar_ok c =
+ match c with
+  | NCic.Lambda _ -> true
+  | NCic.Const (NReference.Ref (_,
+     (NReference.Decl
+     |NReference.Def _
+     |NReference.Fix _
+     |NReference.CoFix _))) -> true
+  | NCic.Appl (c::v) ->
+      (* if all arguments are variables, these variables will
+         disappear after extraction (see [empty_s] below) *)
+      List.for_all isRel v && gentypvar_ok c
+  | _ -> false
+
+(*s From a constant to a ML declaration. *)
+
+let extract_std_constant status uri body typ =
+  reset_meta_count ();
+  (* The short type [t] (i.e. possibly with abbreviations). *)
+  let status,res = record_constant_type status uri (Some typ) in
+  let t = snd res in
+  (* The real type [t']: without head products, expanded, *)
+  (* and with [Tvar] translated to [Tvar'] (not instantiable). *)
+  let status,res = expand status (var2var' t) in
+  let l,t' = type_decomp res in
+  let status,s =
+   List.fold_right
+    (fun x (status,res) ->
+      let status,y = type2sign status x in
+       status,y::res)
+    l (status,[]) in
+  (* Check for user-declared implicit information *)
+  let s = sign_with_implicits uri(*CSC: (ConstRef uri)*) s in
+  (* Decomposing the top level lambdas of [body].
+     If there isn't enough, it's ok, as long as remaining args
+     aren't to be pruned (and initial lambdas aren't to be all
+     removed if the target language is strict). In other situations,
+     eta-expansions create artificially enough lams (but that may
+     break user's clever let-ins and partial applications). *)
+  let rels, c =
+    let n = List.length s
+    and m = nb_lam body in
+    if n <= m then decompose_lam_n n body
+    else
+      let s,s' = list_split_at m s in
+      if List.for_all ((=) Keep) s' && sign_kind s <> UnsafeLogicalSig
+      then decompose_lam_n m body
+      else decomp_lams_eta_n n m status [] body typ
+  in
+  (* Should we do one eta-expansion to avoid non-generalizable '_a ? *)
+  let rels, c =
+    let n = List.length rels in
+    let s,s' = list_split_at n s in
+    let k = sign_kind s in
+    let empty_s = (k = EmptySig || k = SafeLogicalSig) in
+    if empty_s && not (gentypvar_ok c) && s' <> [] && type_maxvar t <> 0
+    then decomp_lams_eta_n (n+1) n status [] body typ
+    else rels,c
+  in
+  let n = List.length rels in
+  let s = list_firstn n s in
+  let l,l' = list_split_at n l in
+  let t' = type_recomp (l',t') in
+  (* The initial ML environment. *)
+  let mle = List.fold_left Mlenv.push_std_type Mlenv.empty l in
+  (* The lambdas names. *)
+  let ids = List.map (fun (n,_) -> Id (id_of_name n)) rels in
+  (* The according Coq environment. *)
+  let context = rels in
+  (* The real extraction: *)
+  let status,e = extract_term status context mle t' c [] in
+  (* Expunging term and type from dummy lambdas. *)
+  let trm = term_expunge s (ids,e) in
+  let trm = handle_exn uri n (fun i -> fst (List.nth rels (i-1))) trm in
+  let status,res = type_expunge_from_sign status s t in
+  status,trm,res
+
+let extract_constant_spec status r bo typ =
+  match flag_of_type status [] typ with
+    | (Logic, TypeScheme) ->
+       status,Stype (r, [], Some (Tdummy Ktype))
+    | (Logic, Default) -> status,Sval (r, Tdummy Kother)
+    | (Info, TypeScheme) ->
+        let s,vl = type_sign_vl status [] typ in
+        (match bo with
+          | None -> status,Stype (r, vl, None)
+          | Some body ->
+              let db = db_from_sign s in
+              let status,t =
+               extract_type_scheme status [] db body (List.length s) in
+              status,Stype (r, vl, Some t))
+    | (Info, Default) ->
+        let status,(_,t) = record_constant_type status r (Some typ) in
+        let status,res = type_expunge status t in
+        status,Sval (r,res)
+
+
+let extract_fixpoint_common uri height fix_or_cofix ifl =
+  let recparamnoi,ti,ci =
+   List.fold_right
+    (fun (_,_,recparamno,ty,bo) (recparamnos,tys,bos) ->
+      recparamno::recparamnos,ty::tys,bo::bos) ifl ([],[],[]) in
+  let recparamnoi = Array.of_list recparamnoi in
+  let ti = Array.of_list ti in
+  let ci = Array.of_list ci in
+  let n = Array.length ti in
+  let vkn =
+   Array.init n
+    (fun i ->
+      if fix_or_cofix then
+       NReference.reference_of_spec uri
+        (NReference.Fix (i,recparamnoi.(i),height))
+      else
+       NReference.reference_of_spec uri (NReference.CoFix i)) in
+  ti,ci,n,vkn
+
+let extract_fixpoint status uri height fix_or_cofix is_projection ifl =
+  let status =
+   if is_projection then
+    let _,_,recparamno,_,_ = List.nth ifl 0 in
+    let fieldspec = NReference.Fix (0,recparamno,height) in
+    let ref = NReference.reference_of_spec uri fieldspec in
+     confirm_projection status ref
+   else
+    status in
+  let ti,ci,n,vkn= extract_fixpoint_common uri height fix_or_cofix ifl in
+  let types = Array.make n (Tdummy Kother)
+  and terms = Array.make n MLdummy in
+  current_fixpoints := Some uri;
+  let status = ref status in
+  for i = 0 to n-1 do
+    if sort_of !status [] ti.(i) <> InProp then begin
+      let status',e,t = extract_std_constant !status vkn.(i) ci.(i) ti.(i) in
+      status := status';
+      terms.(i) <- e;
+      types.(i) <- t;
+    end
+  done;
+  let status = !status in
+  current_fixpoints := None;
+  status,Dfix (vkn, terms, types)
+
+let extract_fixpoint_spec status uri height fix_or_cofix ifl =
+  let ti,_,_,vkn= extract_fixpoint_common uri height fix_or_cofix ifl in
+  let status,specs =
+   array_mapi_status status
+    (fun status i vkn ->
+      if sort_of status [] ti.(i) <> InProp then begin
+       let status,spec = extract_constant_spec status vkn None ti.(i) in
+       status, Some spec
+      end
+     else status,None
+    ) vkn in
+  status,HExtlib.filter_map (fun x -> x) (Array.to_list specs)
+
+let extract_constant status r bo typ =
+  match bo with
+    | None -> (* A logical axiom is risky, an informative one is fatal. *)
+        (match flag_of_type status [] typ with
+           | (Info,TypeScheme) ->
+               if true (*CSC: not (is_custom r)*) then () (*CSC: only for warnings add_info_axiom r*);
+               let n = type_scheme_nb_args status [] typ in
+               let ids = iterate (fun l -> anonymous_name::l) n [] in
+               status,Dtype (r, ids, Taxiom)
+           | (Info,Default) ->
+               if true (*CSC: not (is_custom r)*) then () (*CSC: only for warnings add_info_axiom r*);
+               let status,(_,t) = record_constant_type status r (Some typ) in
+               let status,res = type_expunge status t in
+               status, Dterm (r, MLaxiom, res)
+           | (Logic,TypeScheme) ->
+               (*CSC: only for warnings add_log_axiom r;*)
+               status,Dtype (r, [], Tdummy Ktype)
+           | (Logic,Default) ->
+               (*CSC: only for warnings add_log_axiom r;*)
+               status,Dterm (r, MLdummy, Tdummy Kother))
+    | Some body ->
+        (match flag_of_type status [] typ with
+           | (Logic, Default) ->
+              status,Dterm (r, MLdummy, Tdummy Kother)
+           | (Logic, TypeScheme) ->
+              status,Dtype (r, [], Tdummy Ktype)
+           | (Info, Default) ->
+               let status,e,t = extract_std_constant status r body typ in
+               status,Dterm (r,e,t)
+           | (Info, TypeScheme) ->
+               let s,vl = type_sign_vl status [] typ in
+               let db = db_from_sign s in
+               let status,t =
+                extract_type_scheme status [] db body (List.length s)
+               in status,Dtype (r, vl, t))
+
+let extract_inductive status uri inductive ind_pragma leftno types =
+  let status,ind = extract_ind0 status uri inductive ind_pragma leftno types in
+  (*CSC: add_recursors status kn;*)
+  let f status _i _j l =
+    let implicits = [] (*CSC:implicits_of_global (ConstructRef ((kn,i),j+1))*) in
+    let rec filter status i = function
+      | [] -> status,[]
+      | t::l ->
+          let status,l' = filter status (succ i) l in
+          let status,res = expand status t in
+          if isDummy res || List.mem i implicits then status,l'
+          else status,t::l'
+    in filter status 1 l
+  in
+  let status,packets =
+    array_fold_right_i
+     (fun i p (status,res) ->
+       let status,types = 
+        array_fold_right_i
+        (fun j x (status,res) ->
+          let status,y = f status i j x in
+           status,y::res
+        ) p.ip_types (status,[])
+       in
+        status, { p with ip_types = Array.of_list types }::res
+     ) ind.ind_packets (status,[])
+  in status,{ ind with ind_packets = Array.of_list packets }
+
+(*s Is a [ml_decl] logical ? *)
+
+let logical_decl = function
+  | Dterm (_,MLdummy,Tdummy _) -> true
+  | Dtype (_,[],Tdummy _) -> true
+  | Dfix (_,av,tv) ->
+      (array_for_all ((=) MLdummy) av) &&
+      (array_for_all isDummy tv)
+  | Dind i -> array_for_all (fun ip -> ip.ip_logical) i.ind_packets
+  | _ -> false
+
+(*s Is a [ml_spec] logical ? *)
+
+let logical_spec = function
+  | Stype (_, [], Some (Tdummy _)) -> true
+  | Sval (_,Tdummy _) -> true
+  | Sind i -> array_for_all (fun ip -> ip.ip_logical) i.ind_packets
+  | _ -> false
+
+let extract_impl status (uri,height,metasenv,subst,obj_kind) =
+ assert (metasenv=[]);
+ assert (subst=[]);
+ let status,decl =
+  match obj_kind with
+     NCic.Constant (_,_,bo,typ,_) ->
+      let r =
+       let spec =
+        match bo with
+           None -> NReference.Decl
+         | Some _ -> NReference.Def height
+       in NReference.reference_of_spec uri spec
+      in
+       extract_constant status r bo typ
+   | NCic.Inductive (inductive,leftno,types,(_,ind_pragma)) ->
+      let status,res =
+       extract_inductive status uri inductive ind_pragma leftno types
+      in
+       status,Dind res
+   | NCic.Fixpoint (fix_or_cofix,ifl,(_,_,def_pragma)) ->
+      extract_fixpoint status uri height fix_or_cofix
+       (def_pragma = `Projection) ifl
+ in
+  status, if logical_decl decl then None else Some decl
+;;
+
+let extract_spec status (uri,height,metasenv,subst,obj_kind) =
+ assert (metasenv=[]);
+ assert (subst=[]);
+ match obj_kind with
+    NCic.Constant (_,_,bo,typ,_) ->
+     let r =
+      let spec =
+       match bo with
+          None -> NReference.Decl
+        | Some _ -> NReference.Def height
+      in NReference.reference_of_spec uri spec
+     in
+     let status,spec = extract_constant_spec status r bo typ in
+     status,if logical_spec spec then [] else [spec]
+  | NCic.Inductive (inductive,leftno,types,(_,ind_pragma)) ->
+     let status,res =
+      extract_inductive status uri inductive ind_pragma leftno types in
+     let spec = Sind res in
+     status,if logical_spec spec then [] else [spec]
+  | NCic.Fixpoint (fix_or_cofix,ifl,_) ->
+     extract_fixpoint_spec status uri height fix_or_cofix ifl
+
+let extract status obj =
+ let status,res = extract_impl status obj in
+ let status,resl = extract_spec status obj in
+  status,res,resl
diff --git a/matita/components/ng_extraction/extraction.mli b/matita/components/ng_extraction/extraction.mli
new file mode 100644 (file)
index 0000000..efb2c63
--- /dev/null
@@ -0,0 +1,19 @@
+(************************************************************************)
+(*  v      *   The Coq Proof Assistant  /  The Coq Development Team     *)
+(* <O___,, *   INRIA - CNRS - LIX - LRI - PPS - Copyright 1999-2011     *)
+(*   \VV/  **************************************************************)
+(*    //   *      This file is distributed under the terms of the       *)
+(*         *       GNU Lesser General Public License Version 2.1        *)
+(************************************************************************)
+
+(*i $Id: extraction.mli 14641 2011-11-06 11:59:10Z herbelin $ i*)
+
+(*s Extraction from Coq terms to Miniml. *)
+
+open Coq
+open Miniml
+open OcamlExtractionTable
+
+val extract:
+ #OcamlExtractionTable.status as 'status -> NCic.obj ->
+  'status * ml_decl option * ml_spec list
diff --git a/matita/components/ng_extraction/miniml.ml b/matita/components/ng_extraction/miniml.ml
new file mode 100644 (file)
index 0000000..8fc7954
--- /dev/null
@@ -0,0 +1,181 @@
+(************************************************************************)
+(*  v      *   The Coq Proof Assistant  /  The Coq Development Team     *)
+(* <O___,, *   INRIA - CNRS - LIX - LRI - PPS - Copyright 1999-2011     *)
+(*   \VV/  **************************************************************)
+(*    //   *      This file is distributed under the terms of the       *)
+(*         *       GNU Lesser General Public License Version 2.1        *)
+(************************************************************************)
+
+(*i $Id: miniml.mli 14641 2011-11-06 11:59:10Z herbelin $ i*)
+
+(*s Target language for extraction: a core ML called MiniML. *)
+
+open Coq
+
+(* The [signature] type is used to know how many arguments a CIC
+   object expects, and what these arguments will become in the ML
+   object. *)
+
+(* We eliminate from terms:  1) types 2) logical parts.
+   [Kother] stands both for logical or other reasons
+   (for instance user-declared implicit arguments w.r.t. extraction). *)
+
+type kill_reason = Ktype | Kother
+
+type sign = Keep | Kill of kill_reason
+
+
+(* Convention: outmost lambda/product gives the head of the list. *)
+
+type signature = sign list
+
+(*s ML type expressions. *)
+
+type ml_type =
+  | Tarr    of ml_type * ml_type
+  | Tglob   of NReference.reference * ml_type list
+  | Tvar    of int
+  | Tvar'   of int (* same as Tvar, used to avoid clash *)
+  | Tmeta   of ml_meta (* used during ML type reconstruction *)
+  | Tdummy  of kill_reason
+  | Tunknown
+  | Taxiom
+
+and ml_meta = { id : int; mutable contents : ml_type option }
+
+(* ML type schema.
+   The integer is the number of variable in the schema. *)
+
+type ml_schema = int * ml_type
+
+(*s ML inductive types. *)
+
+type inductive_kind =
+  | Singleton
+  | Coinductive
+  | Standard
+  | Record of NReference.reference list
+
+(* A [ml_ind_packet] is the miniml counterpart of a [one_inductive_body].
+   If the inductive is logical ([ip_logical = false]), then all other fields
+   are unused. Otherwise,
+   [ip_sign] is a signature concerning the arguments of the inductive,
+   [ip_vars] contains the names of the type variables surviving in ML,
+   [ip_types] contains the ML types of all constructors.
+*)
+
+type ml_ind_packet = {
+  ip_reference : NReference.reference;
+  ip_consreferences : NReference.reference array;
+  ip_typename : identifier;
+  ip_consnames : identifier array;
+  ip_logical : bool;
+  ip_sign : signature;
+  ip_vars : identifier list;
+  ip_types : (ml_type list) array
+}
+
+(* [ip_nparams] contains the number of parameters. *)
+
+type ml_ind = {
+  ind_kind : inductive_kind;
+  ind_nparams : int;
+  ind_packets : ml_ind_packet array;
+}
+
+(*s ML terms. *)
+
+type ml_ident =
+  | Dummy
+  | Id of identifier
+  | Tmp of identifier
+
+(** We now store some typing information on constructors
+    and cases to avoid type-unsafe optimisations.
+    For cases, we also store the set of branches to merge
+    in a common pattern, either "_ -> c" or "x -> f x"
+*)
+
+type constructor_info = {
+  c_kind : inductive_kind;
+  c_typs : ml_type list;
+}
+
+type branch_same =
+  | BranchNone
+  | BranchFun of Intset.t
+  | BranchCst of Intset.t
+
+type match_info = {
+  m_kind : inductive_kind;
+  m_typs : ml_type list;
+  m_same : branch_same
+}
+
+type ml_branch = NReference.reference * ml_ident list * ml_ast
+
+and ml_ast =
+  | MLrel    of int
+  | MLapp    of ml_ast * ml_ast list
+  | MLlam    of ml_ident * ml_ast
+  | MLletin  of ml_ident * ml_ast * ml_ast
+  | MLglob   of NReference.reference
+  | MLcons   of constructor_info * NReference.reference * ml_ast list
+  | MLcase   of match_info * ml_ast * ml_branch array
+  | MLfix    of int * identifier array * ml_ast array
+  | MLexn    of string
+  | MLdummy
+  | MLaxiom
+  | MLmagic  of ml_ast
+
+(*s ML declarations. *)
+
+type ml_decl =
+  | Dind  of ml_ind
+  | Dtype of NReference.reference * identifier list * ml_type
+  | Dterm of NReference.reference * ml_ast * ml_type
+  | Dfix  of NReference.reference array * ml_ast array * ml_type array
+
+type ml_spec =
+  | Sind  of ml_ind
+  | Stype of NReference.reference * identifier list * ml_type option
+  | Sval  of NReference.reference * ml_type
+
+type ml_specif =
+  | Spec of ml_spec
+
+and ml_module_sig = (label * ml_specif) list
+
+type ml_structure_elem =
+  | SEdecl of ml_decl
+
+and ml_module_structure = (label * ml_structure_elem) list
+
+type ml_structure = module_path * ml_module_structure
+
+type ml_signature = module_path * ml_module_sig
+
+type unsafe_needs = {
+  mldummy : bool;
+  tdummy : bool;
+  tunknown : bool;
+  magic : bool
+}
+
+type language_descr = {
+  keywords : Idset.t;
+
+  (* Concerning the source file *)
+  file_suffix : string;
+  preamble : identifier -> module_path list -> unsafe_needs -> std_ppcmds;
+  pp_struct : ml_structure -> std_ppcmds;
+
+  (* Concerning a possible interface file *)
+  sig_suffix : string option;
+  sig_preamble : identifier -> module_path list -> unsafe_needs -> std_ppcmds;
+  pp_sig : ml_signature -> std_ppcmds;
+
+  (* for an isolated declaration print *)
+  pp_decl : ml_decl -> std_ppcmds;
+
+}
diff --git a/matita/components/ng_extraction/mlutil.ml b/matita/components/ng_extraction/mlutil.ml
new file mode 100644 (file)
index 0000000..0d5e89f
--- /dev/null
@@ -0,0 +1,1333 @@
+(************************************************************************)
+(*  v      *   The Coq Proof Assistant  /  The Coq Development Team     *)
+(* <O___,, *   INRIA - CNRS - LIX - LRI - PPS - Copyright 1999-2011     *)
+(*   \VV/  **************************************************************)
+(*    //   *      This file is distributed under the terms of the       *)
+(*         *       GNU Lesser General Public License Version 2.1        *)
+(************************************************************************)
+
+(*i $Id: mlutil.ml 14786 2011-12-10 12:55:19Z letouzey $ i*)
+
+(*i*)
+
+open Coq
+open OcamlExtractionTable
+open Miniml
+(*i*)
+
+(*s Exceptions. *)
+
+exception Found
+exception Impossible
+
+(*S Names operations. *)
+
+let anonymous_name = "x"
+let dummy_name = "_"
+
+let anonymous = Id anonymous_name
+
+let id_of_name = function
+  | "_" -> anonymous_name
+  | id -> id
+
+let id_of_mlid = function
+  | Dummy -> dummy_name
+  | Id id -> id
+  | Tmp id -> id
+
+let tmp_id = function
+  | Id id -> Tmp id
+  | a -> a
+
+let is_tmp = function Tmp _ -> true | _ -> false
+
+(*S Operations upon ML types (with meta). *)
+
+let meta_count = ref 0
+
+let reset_meta_count () = meta_count := 0
+
+let new_meta _ =
+  incr meta_count;
+  Tmeta {id = !meta_count; contents = None}
+
+(*s Sustitution of [Tvar i] by [t] in a ML type. *)
+
+let type_subst i t0 t =
+  let rec subst t = match t with
+    | Tvar j when i = j -> t0
+    | Tmeta {contents=None} -> t
+    | Tmeta {contents=Some u} -> subst u
+    | Tarr (a,b) -> Tarr (subst a, subst b)
+    | Tglob (r, l) -> Tglob (r, List.map subst l)
+    | a -> a
+  in subst t
+
+(* Simultaneous substitution of [[Tvar 1; ... ; Tvar n]] by [l] in a ML type. *)
+
+let type_subst_list l t =
+  let rec subst t = match t with
+    | Tvar j -> List.nth l (j-1)
+    | Tmeta {contents=None} -> t
+    | Tmeta {contents=Some u} -> subst u
+    | Tarr (a,b) -> Tarr (subst a, subst b)
+    | Tglob (r, l) -> Tglob (r, List.map subst l)
+    | a -> a
+  in subst t
+
+(* Simultaneous substitution of [[|Tvar 1; ... ; Tvar n|]] by [v] in a ML type. *)
+
+let type_subst_vect v t =
+  let rec subst t = match t with
+    | Tvar j -> v.(j-1)
+    | Tmeta {contents=None} -> t
+    | Tmeta {contents=Some u} -> subst u
+    | Tarr (a,b) -> Tarr (subst a, subst b)
+    | Tglob (r, l) -> Tglob (r, List.map subst l)
+    | a -> a
+  in subst t
+
+(*s From a type schema to a type. All [Tvar] become fresh [Tmeta]. *)
+
+let instantiation (nb,t) = type_subst_vect (Array.init nb new_meta) t
+
+(*s Occur-check of a free meta in a type *)
+
+let rec type_occurs alpha t =
+  match t with
+  | Tmeta {id=beta; contents=None} -> alpha = beta
+  | Tmeta {contents=Some u} -> type_occurs alpha u
+  | Tarr (t1, t2) -> type_occurs alpha t1 || type_occurs alpha t2
+  | Tglob (_r,l) -> List.exists (type_occurs alpha) l
+  | _ -> false
+
+(*s Most General Unificator *)
+
+let rec mgu = function
+  | Tmeta m, Tmeta m' when m.id = m'.id -> ()
+  | Tmeta m, t | t, Tmeta m ->
+    (match m.contents with
+      | Some u -> mgu (u, t)
+      | None when type_occurs m.id t -> raise Impossible
+      | None -> m.contents <- Some t)
+  | Tarr(a, b), Tarr(a', b') ->
+      mgu (a, a'); mgu (b, b')
+  | Tglob (r,l), Tglob (r',l') when r = r' ->
+       List.iter mgu (List.combine l l')
+  | Tdummy _, Tdummy _ -> ()
+  | t, u when t = u -> () (* for Tvar, Tvar', Tunknown, Taxiom *)
+  | _ -> raise Impossible
+
+let needs_magic p = try mgu p; false with Impossible -> true
+
+let put_magic_if b a = if b then MLmagic a else a
+
+let put_magic p a = if needs_magic p then MLmagic a else a
+
+let generalizable a =
+    match a with
+      | MLapp _ -> false
+      | _ -> true (* TODO, this is just an approximation for the moment *)
+
+(*S ML type env. *)
+
+module Mlenv = struct
+
+  let meta_cmp m m' = compare m.id m'.id
+  module Metaset = Set.Make(struct type t = ml_meta let compare = meta_cmp end)
+
+  (* Main MLenv type. [env] is the real environment, whereas [free]
+     (tries to) record the free meta variables occurring in [env]. *)
+
+  type t = { env : ml_schema list; mutable free : Metaset.t}
+
+  (* Empty environment. *)
+
+  let empty = { env = []; free = Metaset.empty }
+
+  (* [get] returns a instantiated copy of the n-th most recently added
+     type in the environment. *)
+
+  let get mle n =
+    assert (List.length mle.env >= n);
+    instantiation (List.nth mle.env (n-1))
+
+  (* [find_free] finds the free meta in a type. *)
+
+  let rec find_free set = function
+    | Tmeta m when m.contents = None -> Metaset.add m set
+    | Tmeta {contents = Some t} -> find_free set t
+    | Tarr (a,b) -> find_free (find_free set a) b
+    | Tglob (_,l) -> List.fold_left find_free set l
+    | _ -> set
+
+  (* The [free] set of an environment can be outdate after
+     some unifications. [clean_free] takes care of that. *)
+
+  let clean_free mle =
+    let rem = ref Metaset.empty
+    and add = ref Metaset.empty in
+    let clean m = match m.contents with
+      | None -> ()
+      | Some u -> rem := Metaset.add m !rem; add := find_free !add u
+    in
+    Metaset.iter clean mle.free;
+    mle.free <- Metaset.union (Metaset.diff mle.free !rem) !add
+
+  (* From a type to a type schema. If a [Tmeta] is still uninstantiated
+     and does appears in the [mle], then it becomes a [Tvar]. *)
+
+  let generalization mle t =
+    let c = ref 0 in
+    let map = ref (Intmap.empty : int Intmap.t) in
+    let add_new i = incr c; map := Intmap.add i !c !map; !c in
+    let rec meta2var t = match t with
+      | Tmeta {contents=Some u} -> meta2var u
+      | Tmeta ({id=i} as m) ->
+         (try Tvar (Intmap.find i !map)
+          with Not_found ->
+            if Metaset.mem m mle.free then t
+            else Tvar (add_new i))
+      | Tarr (t1,t2) -> Tarr (meta2var t1, meta2var t2)
+      | Tglob (r,l) -> Tglob (r, List.map meta2var l)
+      | t -> t
+    in !c, meta2var t
+
+  (* Adding a type in an environment, after generalizing. *)
+
+  let push_gen mle t =
+    clean_free mle;
+    { env = generalization mle t :: mle.env; free = mle.free }
+
+  (* Adding a type with no [Tvar], hence no generalization needed. *)
+
+  let push_type {env=e;free=f} t =
+    { env = (0,t) :: e; free = find_free f t}
+
+  (* Adding a type with no [Tvar] nor [Tmeta]. *)
+
+  let push_std_type {env=e;free=f} t =
+    { env = (0,t) :: e; free = f}
+
+end
+
+(*S Operations upon ML types (without meta). *)
+
+(*s Does a section path occur in a ML type ? *)
+
+let rec type_mem_kn uri = 
+ function
+  | Tmeta {contents = Some t} -> type_mem_kn uri t
+  | Tglob (r,l) ->
+     let NReference.Ref (uri',_) = r in
+      NUri.eq uri uri' || List.exists (type_mem_kn uri) l
+  | Tarr (a,b) -> (type_mem_kn uri a) || (type_mem_kn uri b)
+  | _ -> false
+
+(*s Greatest variable occurring in [t]. *)
+
+let type_maxvar t =
+  let rec parse n = function
+    | Tmeta {contents = Some t} -> parse n t
+    | Tvar i -> max i n
+    | Tarr (a,b) -> parse (parse n a) b
+    | Tglob (_,l) -> List.fold_left parse n l
+    | _ -> n
+  in parse 0 t
+
+(*s What are the type variables occurring in [t]. *)
+
+let intset_union_map_list f l =
+  List.fold_left (fun s t -> Intset.union s (f t)) Intset.empty l
+
+let intset_union_map_array f a =
+  Array.fold_left (fun s t -> Intset.union s (f t)) Intset.empty a
+
+let rec type_listvar = function
+  | Tmeta {contents = Some t} -> type_listvar t
+  | Tvar i | Tvar' i -> Intset.singleton i
+  | Tarr (a,b) -> Intset.union (type_listvar a) (type_listvar b)
+  | Tglob (_,l) -> intset_union_map_list type_listvar l
+  | _ -> Intset.empty
+
+(*s From [a -> b -> c] to [[a;b],c]. *)
+
+let rec type_decomp = function
+  | Tmeta {contents = Some t} -> type_decomp t
+  | Tarr (a,b) -> let l,h = type_decomp b in a::l, h
+  | a -> [],a
+
+(*s The converse: From [[a;b],c] to [a -> b -> c]. *)
+
+let rec type_recomp (l,t) = match l with
+  | [] -> t
+  | a::l -> Tarr (a, type_recomp (l,t))
+
+(*s Translating [Tvar] to [Tvar'] to avoid clash. *)
+
+let rec var2var' = function
+  | Tmeta {contents = Some t} -> var2var' t
+  | Tvar i -> Tvar' i
+  | Tarr (a,b) -> Tarr (var2var' a, var2var' b)
+  | Tglob (r,l) -> Tglob (r, List.map var2var' l)
+  | a -> a
+
+type 'status abbrev_map =
+ 'status -> NReference.reference -> ('status * ml_type) option
+
+(*s Delta-reduction of type constants everywhere in a ML type [t].
+   [env] is a function of type [ml_type_env]. *)
+
+let type_expand status env t =
+  let rec expand status = function
+    | Tmeta {contents = Some t} -> expand status t
+    | Tglob (r,l) ->
+       (match env status r with
+          | Some (status,mlt) -> expand status (type_subst_list l mlt)
+          | None ->
+              let status,l =
+               List.fold_right
+                (fun t (status,res) ->
+                  let status,res' = expand status t in
+                   status,res'::res)
+                l (status,[])
+              in
+               status,Tglob (r, l))
+    | Tarr (a,b) ->
+       let status,a = expand status a in
+       let status,b = expand status b in
+        status,Tarr (a,b)
+    | a -> status,a in
+  if OcamlExtractionTable.type_expand () then
+   expand status t
+  else
+   status,t
+
+let type_simpl status = type_expand status (fun _ _ -> None)
+
+(*s Generating a signature from a ML type. *)
+
+let type_to_sign status env t =
+ let status,res = type_expand status env t in
+  status,
+   match res with
+    | Tdummy d -> Kill d
+    | _ -> Keep
+
+let type_to_signature status env t =
+  let rec f = function
+    | Tmeta {contents = Some t} -> f t
+    | Tarr (Tdummy d, b) -> Kill d :: f b
+    | Tarr (_, b) -> Keep :: f b
+    | _ -> []
+  in
+   let status,res = type_expand status env t in
+    status,f res
+
+let isKill = function Kill _ -> true | _ -> false
+
+let isDummy = function Tdummy _ -> true | _ -> false
+
+let sign_of_id = function
+  | Dummy -> Kill Kother
+  | _ -> Keep
+
+(* Classification of signatures *)
+
+type sign_kind =
+  | EmptySig
+  | NonLogicalSig (* at least a [Keep] *)
+  | UnsafeLogicalSig (* No [Keep], at least a [Kill Kother] *)
+  | SafeLogicalSig (* only [Kill Ktype] *)
+
+let rec sign_kind = function
+  | [] -> EmptySig
+  | Keep :: _ -> NonLogicalSig
+  | Kill k :: s ->
+      match sign_kind s with
+       | NonLogicalSig -> NonLogicalSig
+       | UnsafeLogicalSig -> UnsafeLogicalSig
+       | SafeLogicalSig | EmptySig ->
+           if k = Kother then UnsafeLogicalSig else SafeLogicalSig
+
+(* Removing the final [Keep] in a signature *)
+
+let rec sign_no_final_keeps = function
+  | [] -> []
+  | k :: s ->
+      let s' = k :: sign_no_final_keeps s in
+      if s' = [Keep] then [] else s'
+
+(*s Removing [Tdummy] from the top level of a ML type. *)
+
+let type_expunge_from_sign status env s t =
+  let rec expunge status s t =
+    if s = [] then status,t else match t with
+      | Tmeta {contents = Some t} -> expunge status s t
+      | Tarr (a,b) ->
+         let status,t = expunge status (List.tl s) b in
+         status, if List.hd s = Keep then Tarr (a, t) else t
+      | Tglob (r,l) ->
+         (match env status r with
+            | Some (status,mlt) -> expunge status s (type_subst_list l mlt)
+            | None -> assert false)
+      | _ -> assert false
+  in
+  let status,t = expunge status (sign_no_final_keeps s) t in
+  status,
+   if sign_kind s = UnsafeLogicalSig then
+     Tarr (Tdummy Kother, t)
+   else t
+
+let type_expunge status env t =
+ let status,res = type_to_signature status env t in
+  type_expunge_from_sign status env res t
+
+(*S Generic functions over ML ast terms. *)
+
+let mlapp f a = if a = [] then f else MLapp (f,a)
+
+(*s [ast_iter_rel f t] applies [f] on every [MLrel] in t. It takes care
+   of the number of bingings crossed before reaching the [MLrel]. *)
+
+let ast_iter_rel f =
+  let rec iter n = function
+    | MLrel i -> f (i-n)
+    | MLlam (_,a) -> iter (n+1) a
+    | MLletin (_,a,b) -> iter n a; iter (n+1) b
+    | MLcase (_,a,v) ->
+       iter n a; Array.iter (fun (_,l,t) -> iter (n + (List.length l)) t) v
+    | MLfix (_,ids,v) -> let k = Array.length ids in Array.iter (iter (n+k)) v
+    | MLapp (a,l) -> iter n a; List.iter (iter n) l
+    | MLcons (_,_,l) ->  List.iter (iter n) l
+    | MLmagic a -> iter n a
+    | MLglob _ | MLexn _ | MLdummy | MLaxiom -> ()
+  in iter 0
+
+(*s Map over asts. *)
+
+let ast_map_case f (c,ids,a) = (c,ids,f a)
+
+let ast_map f = function
+  | MLlam (i,a) -> MLlam (i, f a)
+  | MLletin (i,a,b) -> MLletin (i, f a, f b)
+  | MLcase (i,a,v) -> MLcase (i,f a, Array.map (ast_map_case f) v)
+  | MLfix (i,ids,v) -> MLfix (i, ids, Array.map f v)
+  | MLapp (a,l) -> MLapp (f a, List.map f l)
+  | MLcons (i,c,l) -> MLcons (i,c, List.map f l)
+  | MLmagic a -> MLmagic (f a)
+  | MLrel _ | MLglob _ | MLexn _ | MLdummy | MLaxiom as a -> a
+
+(*s Map over asts, with binding depth as parameter. *)
+
+let ast_map_lift_case f n (c,ids,a) = (c,ids, f (n+(List.length ids)) a)
+
+let ast_map_lift f n = function
+  | MLlam (i,a) -> MLlam (i, f (n+1) a)
+  | MLletin (i,a,b) -> MLletin (i, f n a, f (n+1) b)
+  | MLcase (i,a,v) -> MLcase (i,f n a,Array.map (ast_map_lift_case f n) v)
+  | MLfix (i,ids,v) ->
+      let k = Array.length ids in MLfix (i,ids,Array.map (f (k+n)) v)
+  | MLapp (a,l) -> MLapp (f n a, List.map (f n) l)
+  | MLcons (i,c,l) -> MLcons (i,c, List.map (f n) l)
+  | MLmagic a -> MLmagic (f n a)
+  | MLrel _ | MLglob _ | MLexn _ | MLdummy | MLaxiom as a -> a
+
+(*s Iter over asts. *)
+
+let ast_iter_case f (_c,_ids,a) = f a
+
+let ast_iter f = function
+  | MLlam (_i,a) -> f a
+  | MLletin (_i,a,b) -> f a; f b
+  | MLcase (_,a,v) -> f a; Array.iter (ast_iter_case f) v
+  | MLfix (_i,_ids,v) -> Array.iter f v
+  | MLapp (a,l) -> f a; List.iter f l
+  | MLcons (_,_c,l) -> List.iter f l
+  | MLmagic a -> f a
+  | MLrel _ | MLglob _ | MLexn _ | MLdummy | MLaxiom  -> ()
+
+(*S Operations concerning De Bruijn indices. *)
+
+(*s [ast_occurs k t] returns [true] if [(Rel k)] occurs in [t]. *)
+
+let ast_occurs k t =
+  try
+    ast_iter_rel (fun i -> if i = k then raise Found) t; false
+  with Found -> true
+
+(*s [occurs_itvl k k' t] returns [true] if there is a [(Rel i)]
+   in [t] with [k<=i<=k'] *)
+
+let ast_occurs_itvl k k' t =
+  try
+    ast_iter_rel (fun i -> if (k <= i) && (i <= k') then raise Found) t; false
+  with Found -> true
+
+(*s Number of occurences of [Rel k] (resp. [Rel 1]) in [t]. *)
+
+let nb_occur_k k t =
+  let cpt = ref 0 in
+  ast_iter_rel (fun i -> if i = k then incr cpt) t;
+  !cpt
+
+let nb_occur t = nb_occur_k 1 t
+
+(* Number of occurences of [Rel 1] in [t], with special treatment of match:
+   occurences in different branches aren't added, but we rather use max. *)
+
+let nb_occur_match =
+  let rec nb k = function
+    | MLrel i -> if i = k then 1 else 0
+    | MLcase(_,a,v) ->
+        (nb k a) +
+       Array.fold_left
+         (fun r (_,ids,a) -> max r (nb (k+(List.length ids)) a)) 0 v
+    | MLletin (_,a,b) -> (nb k a) + (nb (k+1) b)
+    | MLfix (_,ids,v) -> let k = k+(Array.length ids) in
+      Array.fold_left (fun r a -> r+(nb k a)) 0 v
+    | MLlam (_,a) -> nb (k+1) a
+    | MLapp (a,l) -> List.fold_left (fun r a -> r+(nb k a)) (nb k a) l
+    | MLcons (_,_,l) -> List.fold_left (fun r a -> r+(nb k a)) 0 l
+    | MLmagic a -> nb k a
+    | MLglob _ | MLexn _ | MLdummy | MLaxiom -> 0
+  in nb 1
+
+(*s Lifting on terms.
+    [ast_lift k t] lifts the binding depth of [t] across [k] bindings. *)
+
+let ast_lift k t =
+  let rec liftrec n = function
+    | MLrel i as a -> if i-n < 1 then a else MLrel (i+k)
+    | a -> ast_map_lift liftrec n a
+  in if k = 0 then t else liftrec 0 t
+
+let ast_pop t = ast_lift (-1) t
+
+(*s [permut_rels k k' c] translates [Rel 1 ... Rel k] to [Rel (k'+1) ...
+  Rel (k'+k)] and [Rel (k+1) ... Rel (k+k')] to [Rel 1 ... Rel k'] *)
+
+let permut_rels k k' =
+  let rec permut n = function
+    | MLrel i as a ->
+       let i' = i-n in
+       if i'<1 || i'>k+k' then a
+       else if i'<=k then MLrel (i+k')
+       else MLrel (i-k)
+    | a -> ast_map_lift permut n a
+  in permut 0
+
+(*s Substitution. [ml_subst e t] substitutes [e] for [Rel 1] in [t].
+    Lifting (of one binder) is done at the same time. *)
+
+let ast_subst e =
+  let rec subst n = function
+    | MLrel i as a ->
+       let i' = i-n in
+       if i'=1 then ast_lift n e
+       else if i'<1 then a
+       else MLrel (i-1)
+    | a -> ast_map_lift subst n a
+  in subst 0
+
+(*s Generalized substitution.
+   [gen_subst v d t] applies to [t] the substitution coded in the
+   [v] array: [(Rel i)] becomes [v.(i-1)]. [d] is the correction applies
+   to [Rel] greater than [Array.length v]. *)
+
+let gen_subst v d t =
+  let rec subst n = function
+    | MLrel i as a ->
+       let i'= i-n in
+       if i' < 1 then a
+       else if i' <= Array.length v then
+         match v.(i'-1) with
+           | None -> MLexn ("UNBOUND " ^ string_of_int i')
+           | Some u -> ast_lift n u
+       else MLrel (i+d)
+    | a -> ast_map_lift subst n a
+  in subst 0 t
+
+(*S Operations concerning lambdas. *)
+
+(*s [collect_lams MLlam(id1,...MLlam(idn,t)...)] returns
+    [[idn;...;id1]] and the term [t]. *)
+
+let collect_lams =
+  let rec collect acc = function
+    | MLlam(id,t) -> collect (id::acc) t
+    | x           -> acc,x
+  in collect []
+
+(*s [collect_n_lams] does the same for a precise number of [MLlam]. *)
+
+let collect_n_lams =
+  let rec collect acc n t =
+    if n = 0 then acc,t
+    else match t with
+      | MLlam(id,t) -> collect (id::acc) (n-1) t
+      | _ -> assert false
+  in collect []
+
+(*s [remove_n_lams] just removes some [MLlam]. *)
+
+let rec remove_n_lams n t =
+  if n = 0 then t
+  else match t with
+      | MLlam(_,t) -> remove_n_lams (n-1) t
+      | _ -> assert false
+
+(*s [nb_lams] gives the number of head [MLlam]. *)
+
+let rec nb_lams = function
+  | MLlam(_,t) -> succ (nb_lams t)
+  | _ -> 0
+
+(*s [named_lams] does the converse of [collect_lams]. *)
+
+let rec named_lams ids a = match ids with
+  | [] -> a
+  | id :: ids -> named_lams ids (MLlam (id,a))
+
+(*s The same for a specific identifier (resp. anonymous, dummy) *)
+
+let rec many_lams id a = function
+  | 0 -> a
+  | n -> many_lams id (MLlam (id,a)) (pred n)
+
+let anonym_lams a n = many_lams anonymous a n
+let anonym_tmp_lams a n = many_lams (Tmp anonymous_name) a n
+let dummy_lams a n = many_lams Dummy a n
+
+(*s mixed according to a signature. *)
+
+let rec anonym_or_dummy_lams a = function
+  | [] -> a
+  | Keep :: s -> MLlam(anonymous, anonym_or_dummy_lams a s)
+  | Kill _ :: s -> MLlam(Dummy, anonym_or_dummy_lams a s)
+
+(*S Operations concerning eta. *)
+
+(*s The following function creates [MLrel n;...;MLrel 1] *)
+
+let rec eta_args n =
+  if n = 0 then [] else (MLrel n)::(eta_args (pred n))
+
+(*s Same, but filtered by a signature. *)
+
+let rec eta_args_sign n = function
+  | [] -> []
+  | Keep :: s -> (MLrel n) :: (eta_args_sign (n-1) s)
+  | Kill _ :: s -> eta_args_sign (n-1) s
+
+(*s This one tests [MLrel (n+k); ... ;MLrel (1+k)] *)
+
+let rec test_eta_args_lift k n = function
+  | [] -> n=0
+  | a :: q -> (a = (MLrel (k+n))) && (test_eta_args_lift k (pred n) q)
+
+(*s Computes an eta-reduction. *)
+
+let eta_red e =
+  let ids,t = collect_lams e in
+  let n = List.length ids in
+  if n = 0 then e
+  else match t with
+    | MLapp (f,a) ->
+       let m = List.length a in
+       let ids,body,args =
+         if m = n then
+           [], f, a
+         else if m < n then
+           list_skipn m ids, f, a
+         else (* m > n *)
+           let a1,a2 = list_chop (m-n) a in
+           [], MLapp (f,a1), a2
+       in
+       let p = List.length args in
+       if test_eta_args_lift 0 p args && not (ast_occurs_itvl 1 p body)
+       then named_lams ids (ast_lift (-p) body)
+       else e
+    | _ -> e
+
+(*s Computes all head linear beta-reductions possible in [(t a)].
+  Non-linear head beta-redex become let-in. *)
+
+let rec linear_beta_red a t = match a,t with
+  | [], _ -> t
+  | a0::a, MLlam (id,t) ->
+      (match nb_occur_match t with
+        | 0 -> linear_beta_red a (ast_pop t)
+        | 1 -> linear_beta_red a (ast_subst a0 t)
+        | _ ->
+            let a = List.map (ast_lift 1) a in
+            MLletin (id, a0, linear_beta_red a t))
+  | _ -> MLapp (t, a)
+
+let rec tmp_head_lams = function
+  | MLlam (id, t) -> MLlam (tmp_id id, tmp_head_lams t)
+  | e -> e
+
+(*s Applies a substitution [s] of constants by their body, plus
+  linear beta reductions at modified positions.
+  Moreover, we mark some lambdas as suitable for later linear
+  reduction (this helps the inlining of recursors).
+*)
+
+let rec ast_glob_subst _s _t = assert false (*CSC: reimplement match t with
+  | MLapp ((MLglob ((ConstRef kn) as refe)) as f, a) ->
+      let a = List.map (fun e -> tmp_head_lams (ast_glob_subst s e)) a in
+      (try linear_beta_red a (Refmap'.find refe s)
+       with Not_found -> MLapp (f, a))
+  | MLglob ((ConstRef kn) as refe) ->
+      (try Refmap'.find refe s with Not_found -> t)
+  | _ -> ast_map (ast_glob_subst s) t *)
+
+
+(*S Auxiliary functions used in simplification of ML cases. *)
+
+(* Factorisation of some match branches into a common "x -> f x"
+   branch may break types sometimes. Example: [type 'x a = A].
+   Then [let id = function A -> A] has type ['x a -> 'y a],
+   which is incompatible with the type of [let id x = x].
+   We now check that the type arguments of the inductive are
+   preserved by our transformation.
+
+   TODO: this verification should be done someday modulo
+   expansion of type definitions.
+*)
+
+(*s [branch_as_function b typs (r,l,c)] tries to see branch [c]
+  as a function [f] applied to [MLcons(r,l)]. For that it transforms
+  any [MLcons(r,l)] in [MLrel 1] and raises [Impossible]
+  if any variable in [l] occurs outside such a [MLcons] *)
+
+let branch_as_fun typs (r,l,c) =
+  let nargs = List.length l in
+  let rec genrec n = function
+    | MLrel i as c ->
+       let i' = i-n in
+       if i'<1 then c
+       else if i'>nargs then MLrel (i-nargs+1)
+       else raise Impossible
+    | MLcons(i,r',args) when
+       r=r' && (test_eta_args_lift n nargs args) && typs = i.c_typs ->
+       MLrel (n+1)
+    | a -> ast_map_lift genrec n a
+  in genrec 0 c
+
+(*s [branch_as_cst (r,l,c)] tries to see branch [c] as a constant
+   independent from the pattern [MLcons(r,l)]. For that is raises [Impossible]
+   if any variable in [l] occurs in [c], and otherwise returns [c] lifted to
+   appear like a function with one arg (for uniformity with [branch_as_fun]).
+   NB: [MLcons(r,l)] might occur nonetheless in [c], but only when [l] is
+   empty, i.e. when [r] is a constant constructor
+*)
+
+let branch_as_cst (_,l,c) =
+  let n = List.length l in
+  if ast_occurs_itvl 1 n c then raise Impossible;
+  ast_lift (1-n) c
+
+(* A branch [MLcons(r,l)->c] can be seen at the same time as a function
+   branch and a constant branch, either because:
+   - [MLcons(r,l)] doesn't occur in [c]. For example : "A -> B"
+   - this constructor is constant (i.e. [l] is empty). For example "A -> A"
+   When searching for the best factorisation below, we'll try both.
+*)
+
+(* The following structure allows to record which element occurred
+   at what position, and then finally return the most frequent
+   element and its positions. *)
+
+let census_add, census_max, census_clean =
+  let h = Hashtbl.create 13 in
+  let clear () = Hashtbl.clear h in
+  let add e i =
+    let s = try Hashtbl.find h e with Not_found -> Intset.empty in
+    Hashtbl.replace h e (Intset.add i s)
+  in
+  let max e0 =
+    let len = ref 0 and lst = ref Intset.empty and elm = ref e0 in
+    Hashtbl.iter
+      (fun e s ->
+        let n = Intset.cardinal s in
+        if n > !len then begin len := n; lst := s; elm := e end)
+      h;
+    (!elm,!lst)
+  in
+  (add,max,clear)
+
+(* [factor_branches] return the longest possible list of branches
+   that have the same factorization, either as a function or as a
+   constant.
+*)
+
+let factor_branches o typs br =
+  census_clean ();
+  for i = 0 to Array.length br - 1 do
+    if o.opt_case_idr then
+      (try census_add (branch_as_fun typs br.(i)) i with Impossible -> ());
+    if o.opt_case_cst then
+      (try census_add (branch_as_cst br.(i)) i with Impossible -> ());
+  done;
+  let br_factor, br_set = census_max MLdummy in
+  census_clean ();
+  let n = Intset.cardinal br_set in
+  if n = 0 then None
+  else if Array.length br >= 2 && n < 2 then None
+  else Some (br_factor, br_set)
+
+(*s If all branches are functions, try to permut the case and the functions. *)
+
+let rec merge_ids ids ids' = match ids,ids' with
+  | [],l -> l
+  | l,[] -> l
+  | i::ids, i'::ids' ->
+      (if i = Dummy then i' else i) :: (merge_ids ids ids')
+
+let is_exn = function MLexn _ -> true | _ -> false
+
+let rec permut_case_fun br _acc =
+  let nb = ref max_int in
+  Array.iter (fun (_,_,t) ->
+               let ids, c = collect_lams t in
+               let n = List.length ids in
+               if (n < !nb) && (not (is_exn c)) then nb := n) br;
+  if !nb = max_int || !nb = 0 then ([],br)
+  else begin
+    let br = Array.copy br in
+    let ids = ref [] in
+    for i = 0 to Array.length br - 1 do
+      let (r,l,t) = br.(i) in
+      let local_nb = nb_lams t in
+      if local_nb < !nb then (* t = MLexn ... *)
+       br.(i) <- (r,l,remove_n_lams local_nb t)
+      else begin
+       let local_ids,t = collect_n_lams !nb t in
+       ids := merge_ids !ids local_ids;
+       br.(i) <- (r,l,permut_rels !nb (List.length l) t)
+      end
+    done;
+    (!ids,br)
+  end
+
+(*S Generalized iota-reduction. *)
+
+(* Definition of a generalized iota-redex: it's a [MLcase(e,_)]
+   with [(is_iota_gen e)=true]. Any generalized iota-redex is
+   transformed into beta-redexes. *)
+
+let rec is_iota_gen = function
+  | MLcons _ -> true
+  | MLcase(_,_,br)-> array_for_all (fun (_,_,t)->is_iota_gen t) br
+  | _ -> false
+
+let constructor_index _ = assert false (*CSC: function
+  | ConstructRef (_,j) -> pred j
+  | _ -> assert false*)
+
+let iota_gen br =
+  let rec iota k = function
+    | MLcons (_i,r,a) ->
+       let (_,ids,c) = br.(constructor_index r) in
+       let c = List.fold_right (fun id t -> MLlam (id,t)) ids c in
+       let c = ast_lift k c in
+       MLapp (c,a)
+    | MLcase(i,e,br') ->
+       let new_br =
+         Array.map (fun (n,i,c)->(n,i,iota (k+(List.length i)) c)) br'
+       in MLcase(i,e, new_br)
+    | _ -> assert false
+  in iota 0
+
+let is_atomic = function
+  | MLrel _ | MLglob _ | MLexn _ | MLdummy -> true
+  | _ -> false
+
+let is_imm_apply = function MLapp (MLrel 1, _) -> true | _ -> false
+
+(** Program creates a let-in named "program_branch_NN" for each branch of match.
+    Unfolding them leads to more natural code (and more dummy removal) *)
+
+let is_program_branch = function
+  | Id id ->
+    let s = id in
+    let br = "program_branch_" in
+    let n = String.length br in
+    (try
+       ignore (int_of_string (String.sub s n (String.length s - n)));
+       String.sub s 0 n = br
+     with _ -> false)
+  | Tmp _ | Dummy -> false
+
+let expand_linear_let o id e =
+   o.opt_lin_let || is_tmp id || is_program_branch id || is_imm_apply e
+
+(*S The main simplification function. *)
+
+(* Some beta-iota reductions + simplifications. *)
+
+let rec simpl o = function
+  | MLapp (f, []) -> simpl o f
+  | MLapp (f, a) -> simpl_app o (List.map (simpl o) a) (simpl o f)
+  | MLcase (i,e,br) ->
+      let br = Array.map (fun (n,l,t) -> (n,l,simpl o t)) br in
+      simpl_case o i br (simpl o e)
+  | MLletin(Dummy,_,e) -> simpl o (ast_pop e)
+  | MLletin(id,c,e) ->
+      let e = simpl o e in
+      if
+       (is_atomic c) || (is_atomic e) ||
+       (let n = nb_occur_match e in
+        (n = 0 || (n=1 && expand_linear_let o id e)))
+      then
+       simpl o (ast_subst c e)
+      else
+       MLletin(id, simpl o c, e)
+  | MLfix(i,ids,c) ->
+      let n = Array.length ids in
+      if ast_occurs_itvl 1 n c.(i) then
+       MLfix (i, ids, Array.map (simpl o) c)
+      else simpl o (ast_lift (-n) c.(i)) (* Dummy fixpoint *)
+  | a -> ast_map (simpl o) a
+
+(* invariant : list [a] of arguments is non-empty *)
+
+and simpl_app o a = function
+  | MLapp (f',a') -> simpl_app o (a'@a) f'
+  | MLlam (Dummy,t) ->
+      simpl o (MLapp (ast_pop t, List.tl a))
+  | MLlam (id,t) -> (* Beta redex *)
+      (match nb_occur_match t with
+        | 0 -> simpl o (MLapp (ast_pop t, List.tl a))
+        | 1 when (is_tmp id || o.opt_lin_beta) ->
+            simpl o (MLapp (ast_subst (List.hd a) t, List.tl a))
+        | _ ->
+            let a' = List.map (ast_lift 1) (List.tl a) in
+            simpl o (MLletin (id, List.hd a, MLapp (t, a'))))
+  | MLletin (id,e1,e2) when o.opt_let_app ->
+      (* Application of a letin: we push arguments inside *)
+      MLletin (id, e1, simpl o (MLapp (e2, List.map (ast_lift 1) a)))
+  | MLcase (i,e,br) when o.opt_case_app ->
+      (* Application of a case: we push arguments inside *)
+      let br' =
+       Array.map
+         (fun (n,l,t) ->
+            let k = List.length l in
+            let a' = List.map (ast_lift k) a in
+            (n, l, simpl o (MLapp (t,a')))) br
+      in simpl o (MLcase (i,e,br'))
+  | (MLdummy | MLexn _) as e -> e
+       (* We just discard arguments in those cases. *)
+  | f -> MLapp (f,a)
+
+(* Invariant : all empty matches should now be [MLexn] *)
+
+and simpl_case o i br e =
+  if o.opt_case_iot && (is_iota_gen e) then (* Generalized iota-redex *)
+    simpl o (iota_gen br e)
+  else
+    (* Swap the case and the lam if possible *)
+    let ids,br = if o.opt_case_fun then permut_case_fun br [] else [],br in
+    let n = List.length ids in
+    if n <> 0 then
+      simpl o (named_lams ids (MLcase (i,ast_lift n e, br)))
+    else
+      (* Can we merge several branches as the same constant or function ? *)
+      match factor_branches o i.m_typs br with
+       | Some (f,ints) when Intset.cardinal ints = Array.length br ->
+           (* If all branches have been factorized, we remove the match *)
+           simpl o (MLletin (Tmp anonymous_name, e, f))
+       | Some (f,ints) ->
+         let same = if ast_occurs 1 f then BranchFun ints else BranchCst ints
+         in MLcase ({i with m_same=same}, e, br)
+       | None -> MLcase (i, e, br)
+
+(*S Local prop elimination. *)
+(* We try to eliminate as many [prop] as possible inside an [ml_ast]. *)
+
+(*s In a list, it selects only the elements corresponding to a [Keep]
+   in the boolean list [l]. *)
+
+let rec select_via_bl l args = match l,args with
+  | [],_ -> args
+  | Keep::l,a::args -> a :: (select_via_bl l args)
+  | Kill _::l,_a::args -> select_via_bl l args
+  | _ -> assert false
+
+(*s [kill_some_lams] removes some head lambdas according to the signature [bl].
+   This list is build on the identifier list model: outermost lambda
+   is on the right.
+   [Rels] corresponding to removed lambdas are supposed not to occur, and
+   the other [Rels] are made correct via a [gen_subst].
+   Output is not directly a [ml_ast], compose with [named_lams] if needed. *)
+
+let kill_some_lams bl (ids,c) =
+  let n = List.length bl in
+  let n' = List.fold_left (fun n b -> if b=Keep then (n+1) else n) 0 bl in
+  if n = n' then ids,c
+  else if n' = 0 then [],ast_lift (-n) c
+  else begin
+    let v = Array.make n None in
+    let rec parse_ids i j = function
+      | [] -> ()
+      | Keep :: l -> v.(i) <- Some (MLrel j); parse_ids (i+1) (j+1) l
+      | Kill _ :: l -> parse_ids (i+1) j l
+    in parse_ids 0 1 bl;
+    select_via_bl bl ids, gen_subst v (n'-n) c
+  end
+
+(*s [kill_dummy_lams] uses the last function to kill the lambdas corresponding
+  to a [dummy_name]. It can raise [Impossible] if there is nothing to do, or
+  if there is no lambda left at all. *)
+
+let kill_dummy_lams c =
+  let ids,c = collect_lams c in
+  let bl = List.map sign_of_id ids in
+  if not (List.mem Keep bl) then raise Impossible;
+  let rec fst_kill n = function
+    | [] -> raise Impossible
+    | Kill _ :: _bl -> n
+    | Keep :: bl -> fst_kill (n+1) bl
+  in
+  let skip = max 0 ((fst_kill 0 bl) - 1) in
+  let ids_skip, ids = list_chop skip ids in
+  let _, bl = list_chop skip bl in
+  let c = named_lams ids_skip c in
+  let ids',c = kill_some_lams bl (ids,c) in
+  ids, named_lams ids' c
+
+(*s [eta_expansion_sign] takes a function [fun idn ... id1 -> c]
+   and a signature [s] and builds a eta-long version. *)
+
+(* For example, if [s = [Keep;Keep;Kill Prop;Keep]] then the output is :
+   [fun idn ... id1 x x _ x -> (c' 4 3 __ 1)]  with [c' = lift 4 c] *)
+
+let eta_expansion_sign s (ids,c) =
+  let rec abs ids rels i = function
+    | [] ->
+       let a = List.rev_map (function MLrel x -> MLrel (i-x) | a -> a) rels
+       in ids, MLapp (ast_lift (i-1) c, a)
+    | Keep :: l -> abs (anonymous :: ids) (MLrel i :: rels) (i+1) l
+    | Kill _ :: l -> abs (Dummy :: ids) (MLdummy :: rels) (i+1) l
+  in abs ids [] 1 s
+
+(*s If [s = [b1; ... ; bn]] then [case_expunge] decomposes [e]
+  in [n] lambdas (with eta-expansion if needed) and removes all dummy lambdas
+  corresponding to [Del] in [s]. *)
+
+let case_expunge s e =
+  let m = List.length s in
+  let n = nb_lams e in
+  let p = if m <= n then collect_n_lams m e
+  else eta_expansion_sign (list_skipn n s) (collect_lams e) in
+  kill_some_lams (List.rev s) p
+
+(*s [term_expunge] takes a function [fun idn ... id1 -> c]
+  and a signature [s] and remove dummy lams. The difference
+  with [case_expunge] is that we here leave one dummy lambda
+  if all lambdas are logical dummy and the target language is strict. *)
+
+let term_expunge s (ids,c) =
+  if s = [] then c
+  else
+    let ids,c = kill_some_lams (List.rev s) (ids,c) in
+    if ids = [] && List.mem (Kill Kother) s then
+      MLlam (Dummy, ast_lift 1 c)
+    else named_lams ids c
+
+(*s [kill_dummy_args ids r t] looks for occurences of [MLrel r] in [t] and
+  purge the args of [MLrel r] corresponding to a [dummy_name].
+  It makes eta-expansion if needed. *)
+
+let kill_dummy_args ids r t =
+  let m = List.length ids in
+  let bl = List.rev_map sign_of_id ids in
+  let rec found n = function
+    | MLrel r' when r' = r + n -> true
+    | MLmagic e -> found n e
+    | _ -> false
+  in
+  let rec killrec n = function
+    | MLapp(e, a) when found n e ->
+       let k = max 0 (m - (List.length a)) in
+       let a = List.map (killrec n) a in
+       let a = List.map (ast_lift k) a in
+       let a = select_via_bl bl (a @ (eta_args k)) in
+       named_lams (list_firstn k ids) (MLapp (ast_lift k e, a))
+    | e when found n e ->
+       let a = select_via_bl bl (eta_args m) in
+       named_lams ids (MLapp (ast_lift m e, a))
+    | e -> ast_map_lift killrec n e
+  in killrec 0 t
+
+(*s The main function for local [dummy] elimination. *)
+
+let rec kill_dummy = function
+  | MLfix(i,fi,c) ->
+      (try
+        let ids,c = kill_dummy_fix i c in
+        ast_subst (MLfix (i,fi,c)) (kill_dummy_args ids 1 (MLrel 1))
+       with Impossible -> MLfix (i,fi,Array.map kill_dummy c))
+  | MLapp (MLfix (i,fi,c),a) ->
+      let a = List.map kill_dummy a in
+      (try
+        let ids,c = kill_dummy_fix i c in
+        let fake = MLapp (MLrel 1, List.map (ast_lift 1) a) in
+        let fake' = kill_dummy_args ids 1 fake in
+        ast_subst (MLfix (i,fi,c)) fake'
+       with Impossible -> MLapp(MLfix(i,fi,Array.map kill_dummy c),a))
+  | MLletin(id, MLfix (i,fi,c),e) ->
+      (try
+        let ids,c = kill_dummy_fix i c in
+        let e = kill_dummy (kill_dummy_args ids 1 e) in
+        MLletin(id, MLfix(i,fi,c),e)
+      with Impossible ->
+       MLletin(id, MLfix(i,fi,Array.map kill_dummy c),kill_dummy e))
+  | MLletin(id,c,e) ->
+      (try
+        let ids,c = kill_dummy_lams (kill_dummy_hd c) in
+        let e = kill_dummy (kill_dummy_args ids 1 e) in
+        let c = kill_dummy c in
+        if is_atomic c then ast_subst c e else MLletin (id, c, e)
+       with Impossible -> MLletin(id,kill_dummy c,kill_dummy e))
+  | a -> ast_map kill_dummy a
+
+(* Similar function, but acting only on head lambdas and let-ins *)
+
+and kill_dummy_hd = function
+  | MLlam(id,e) -> MLlam(id, kill_dummy_hd e)
+  | MLletin(id,c,e) ->
+      (try
+        let ids,c = kill_dummy_lams (kill_dummy_hd c) in
+        let e = kill_dummy_hd (kill_dummy_args ids 1 e) in
+        let c = kill_dummy c in
+        if is_atomic c then ast_subst c e else MLletin (id, c, e)
+       with Impossible -> MLletin(id,kill_dummy c,kill_dummy_hd e))
+  | a -> a
+
+and kill_dummy_fix i c =
+  let n = Array.length c in
+  let ids,ci = kill_dummy_lams (kill_dummy_hd c.(i)) in
+  let c = Array.copy c in c.(i) <- ci;
+  for j = 0 to (n-1) do
+    c.(j) <- kill_dummy (kill_dummy_args ids (n-i) c.(j))
+  done;
+  ids,c
+
+(*s Putting things together. *)
+
+let normalize a =
+  let o = optims () in
+  let rec norm a =
+    let a' = if o.opt_kill_dum then kill_dummy (simpl o a) else simpl o a in
+    if a = a' then a else norm a'
+  in norm a
+
+(*S Special treatment of fixpoint for pretty-printing purpose. *)
+
+let general_optimize_fix f ids n args m c =
+  let v = Array.make n 0 in
+  for i=0 to (n-1) do v.(i)<-i done;
+  let aux i = function
+    | MLrel j when v.(j-1)>=0 ->
+       if ast_occurs (j+1) c then raise Impossible else v.(j-1)<-(-i-1)
+    | _ -> raise Impossible
+  in list_iter_i aux args;
+  let args_f = List.rev_map (fun i -> MLrel (i+m+1)) (Array.to_list v) in
+  let new_f = anonym_tmp_lams (MLapp (MLrel (n+m+1),args_f)) m in
+  let new_c = named_lams ids (normalize (MLapp ((ast_subst new_f c),args))) in
+  MLfix(0,[|f|],[|new_c|])
+
+let optimize_fix a =
+  if not (optims()).opt_fix_fun then a
+  else
+    let ids,a' = collect_lams a in
+    let n = List.length ids in
+    if n = 0 then a
+    else match a' with
+      | MLfix(_,[|f|],[|c|]) ->
+         let new_f = MLapp (MLrel (n+1),eta_args n) in
+         let new_c = named_lams ids (normalize (ast_subst new_f c))
+         in MLfix(0,[|f|],[|new_c|])
+      | MLapp(a',args) ->
+         let m = List.length args in
+         (match a' with
+            | MLfix(_,_,_) when
+                (test_eta_args_lift 0 n args) && not (ast_occurs_itvl 1 m a')
+                -> a'
+            | MLfix(_,[|f|],[|c|]) ->
+                (try general_optimize_fix f ids n args m c
+                 with Impossible -> a)
+            | _ -> a)
+      | _ -> a
+
+(*S Inlining. *)
+
+(* Utility functions used in the decision of inlining. *)
+
+let rec ml_size = function
+  | MLapp(t,l) -> List.length l + ml_size t + ml_size_list l
+  | MLlam(_,t) -> 1 + ml_size t
+  | MLcons(_,_,l) -> ml_size_list l
+  | MLcase(_,t,pv) ->
+      1 + ml_size t + (Array.fold_right (fun (_,_,t) a -> a + ml_size t) pv 0)
+  | MLfix(_,_,f) -> ml_size_array f
+  | MLletin (_,_,t) -> ml_size t
+  | MLmagic t -> ml_size t
+  | _ -> 0
+
+and ml_size_list l = List.fold_left (fun a t -> a + ml_size t) 0 l
+
+and ml_size_array l = Array.fold_left (fun a t -> a + ml_size t) 0 l
+
+let is_fix = function MLfix _ -> true | _ -> false
+
+let rec is_constr = function
+  | MLcons _   -> true
+  | MLlam(_,t) -> is_constr t
+  | _          -> false
+
+(*s Strictness *)
+
+(* A variable is strict if the evaluation of the whole term implies
+   the evaluation of this variable. Non-strict variables can be found
+   behind Match, for example. Expanding a term [t] is a good idea when
+   it begins by at least one non-strict lambda, since the corresponding
+   argument to [t] might be unevaluated in the expanded code. *)
+
+exception Toplevel
+
+let lift n l = List.map ((+) n) l
+
+let pop n l = List.map (fun x -> if x<=n then raise Toplevel else x-n) l
+
+(* This function returns a list of de Bruijn indices of non-strict variables,
+   or raises [Toplevel] if it has an internal non-strict variable.
+   In fact, not all variables are checked for strictness, only the ones which
+   de Bruijn index is in the candidates list [cand]. The flag [add] controls
+   the behaviour when going through a lambda: should we add the corresponding
+   variable to the candidates?  We use this flag to check only the external
+   lambdas, those that will correspond to arguments. *)
+
+let rec non_stricts add cand = function
+  | MLlam (_id,t) ->
+      let cand = lift 1 cand in
+      let cand = if add then 1::cand else cand in
+      pop 1 (non_stricts add cand t)
+  | MLrel n ->
+      List.filter ((<>) n) cand
+  | MLapp (t,l)->
+      let cand = non_stricts false cand t in
+      List.fold_left (non_stricts false) cand l
+  | MLcons (_,_,l) ->
+      List.fold_left (non_stricts false) cand l
+  | MLletin (_,t1,t2) ->
+      let cand = non_stricts false cand t1 in
+      pop 1 (non_stricts add (lift 1 cand) t2)
+  | MLfix (_,i,f)->
+      let n = Array.length i in
+      let cand = lift n cand in
+      let cand = Array.fold_left (non_stricts false) cand f in
+      pop n cand
+  | MLcase (_,t,v) ->
+      (* The only interesting case: for a variable to be non-strict, *)
+      (* it is sufficient that it appears non-strict in at least one branch, *)
+      (* so we make an union (in fact a merge). *)
+      let cand = non_stricts false cand t in
+      Array.fold_left
+       (fun c (_,i,t)->
+          let n = List.length i in
+          let cand = lift n cand in
+          let cand = pop n (non_stricts add cand t) in
+          Sort.merge (<=) cand c) [] v
+       (* [merge] may duplicates some indices, but I don't mind. *)
+  | MLmagic t ->
+      non_stricts add cand t
+  | _ ->
+      cand
+
+(* The real test: we are looking for internal non-strict variables, so we start
+   with no candidates, and the only positive answer is via the [Toplevel]
+   exception. *)
+
+let is_not_strict t =
+  try let _ = non_stricts true [] t in false
+  with Toplevel -> true
+
+(*s Inlining decision *)
+
+(* [inline_test] answers the following question:
+   If we could inline [t] (the user said nothing special),
+   should we inline ?
+
+   We expand small terms with at least one non-strict
+   variable (i.e. a variable that may not be evaluated).
+
+   Futhermore we don't expand fixpoints.
+
+   Moreover, as mentionned by X. Leroy (bug #2241),
+   inling a constant from inside an opaque module might
+   break types. To avoid that, we require below that
+   both [r] and its body are globally visible. This isn't
+   fully satisfactory, since [r] might not be visible (functor),
+   and anyway it might be interesting to inline [r] at least
+   inside its own structure. But to be safe, we adopt this
+   restriction for the moment.
+*)
+
+let inline_test _r _t =
+  (*CSC:if not (auto_inline ()) then*) false
+(*
+  else
+    let c = match r with ConstRef c -> c | _ -> assert false in
+    let body = try (Global.lookup_constant c).const_body with _ -> None in
+    if body = None then false
+    else
+      let t1 = eta_red t in
+      let t2 = snd (collect_lams t1) in
+      not (is_fix t2) && ml_size t < 12 && is_not_strict t
+*)
+
+(*CSC: (not) reimplemented
+let con_of_string s =
+  let null = empty_dirpath in
+  match repr_dirpath (dirpath_of_string s) with
+    | id :: d -> make_con (MPfile (make_dirpath d)) null (label_of_id id)
+    | [] -> assert false
+
+let manual_inline_set =
+  List.fold_right (fun x -> Cset_env.add (con_of_string x))
+    [ "Coq.Init.Wf.well_founded_induction_type";
+      "Coq.Init.Wf.well_founded_induction";
+      "Coq.Init.Wf.Acc_iter";
+      "Coq.Init.Wf.Fix_F";
+      "Coq.Init.Wf.Fix";
+      "Coq.Init.Datatypes.andb";
+      "Coq.Init.Datatypes.orb";
+      "Coq.Init.Logic.eq_rec_r";
+      "Coq.Init.Logic.eq_rect_r";
+      "Coq.Init.Specif.proj1_sig";
+    ]
+    Cset_env.empty*)
+
+let manual_inline = function (*CSC:
+  | ConstRef c -> Cset_env.mem c manual_inline_set
+  |*) _ -> false
+
+(* If the user doesn't say he wants to keep [t], we inline in two cases:
+   \begin{itemize}
+   \item the user explicitly requests it
+   \item [expansion_test] answers that the inlining is a good idea, and
+   we are free to act (AutoInline is set)
+   \end{itemize} *)
+
+let inline _r _t = false (*CSC: we never inline atm
+  (*CSC:not (to_keep r) (* The user DOES want to keep it *)
+  && not (is_inline_custom r)
+  &&*) (false(*to_inline r*) (* The user DOES want to inline it *)
+     || (not (is_projection r) &&
+         (is_recursor r || manual_inline r || inline_test r t)))
+*)
diff --git a/matita/components/ng_extraction/mlutil.mli b/matita/components/ng_extraction/mlutil.mli
new file mode 100644 (file)
index 0000000..a04dc29
--- /dev/null
@@ -0,0 +1,138 @@
+(************************************************************************)
+(*  v      *   The Coq Proof Assistant  /  The Coq Development Team     *)
+(* <O___,, *   INRIA - CNRS - LIX - LRI - PPS - Copyright 1999-2011     *)
+(*   \VV/  **************************************************************)
+(*    //   *      This file is distributed under the terms of the       *)
+(*         *       GNU Lesser General Public License Version 2.1        *)
+(************************************************************************)
+
+(*i $Id: mlutil.mli 14786 2011-12-10 12:55:19Z letouzey $ i*)
+
+open OcamlExtractionTable
+open Miniml
+open Coq
+
+(*s Utility functions over ML types with meta. *)
+
+val reset_meta_count : unit -> unit
+val new_meta : 'a -> ml_type
+
+val type_subst : int -> ml_type -> ml_type -> ml_type
+val type_subst_list : ml_type list -> ml_type -> ml_type
+val type_subst_vect : ml_type array -> ml_type -> ml_type
+
+val instantiation : ml_schema -> ml_type
+
+val needs_magic : ml_type * ml_type -> bool
+val put_magic_if : bool -> ml_ast -> ml_ast
+val put_magic : ml_type * ml_type -> ml_ast -> ml_ast
+
+val generalizable : ml_ast -> bool
+
+(*s ML type environment. *)
+
+module Mlenv : sig
+  type t
+  val empty : t
+
+  (* get the n-th more recently entered schema and instantiate it. *)
+  val get : t -> int -> ml_type
+
+  (* Adding a type in an environment, after generalizing free meta *)
+  val push_gen : t -> ml_type -> t
+
+  (* Adding a type with no [Tvar] *)
+  val push_type : t -> ml_type -> t
+
+  (* Adding a type with no [Tvar] nor [Tmeta] *)
+  val push_std_type : t -> ml_type -> t
+end
+
+(*s Utility functions over ML types without meta *)
+
+val type_mem_kn : NUri.uri -> ml_type -> bool
+
+val type_maxvar : ml_type -> int
+
+val type_decomp : ml_type -> ml_type list * ml_type
+val type_recomp : ml_type list * ml_type -> ml_type
+
+val var2var' : ml_type -> ml_type
+
+type 'status abbrev_map =
+ 'status -> NReference.reference -> ('status * ml_type) option
+
+val type_expand :
+ #status as 'status -> 'status abbrev_map -> ml_type -> 'status * ml_type
+val type_simpl : #status as 'status -> ml_type -> 'status * ml_type
+val type_to_sign :
+ #status as 'status -> 'status abbrev_map -> ml_type -> 'status * sign
+val type_to_signature :
+ #status as 'status -> 'status abbrev_map -> ml_type -> 'status * signature
+val type_expunge :
+ #status as 'status -> 'status abbrev_map -> ml_type -> 'status * ml_type
+val type_expunge_from_sign :
+ #status as 'status -> 'status abbrev_map -> signature -> ml_type -> 'status * ml_type
+
+val isDummy : ml_type -> bool
+val isKill : sign -> bool
+
+val case_expunge : signature -> ml_ast -> ml_ident list * ml_ast
+val term_expunge : signature -> ml_ident list * ml_ast -> ml_ast
+
+
+(*s Special identifiers. [dummy_name] is to be used for dead code
+    and will be printed as [_] in concrete (Caml) code. *)
+
+val anonymous_name : identifier
+val dummy_name : identifier
+val id_of_name : string -> identifier
+val id_of_mlid : ml_ident -> identifier
+val tmp_id : ml_ident -> ml_ident
+
+(*s [collect_lambda MLlam(id1,...MLlam(idn,t)...)] returns
+    the list [idn;...;id1] and the term [t]. *)
+
+val collect_lams : ml_ast -> ml_ident list * ml_ast
+val collect_n_lams : int -> ml_ast -> ml_ident list * ml_ast
+val remove_n_lams : int -> ml_ast -> ml_ast
+val nb_lams : ml_ast -> int
+val named_lams : ml_ident list -> ml_ast -> ml_ast
+val dummy_lams : ml_ast -> int -> ml_ast
+val anonym_or_dummy_lams : ml_ast -> signature -> ml_ast
+
+val eta_args_sign : int -> signature -> ml_ast list
+
+(*s Utility functions over ML terms. *)
+
+val mlapp : ml_ast -> ml_ast list -> ml_ast
+val ast_map : (ml_ast -> ml_ast) -> ml_ast -> ml_ast
+val ast_map_lift : (int -> ml_ast -> ml_ast) -> int -> ml_ast -> ml_ast
+val ast_iter : (ml_ast -> unit) -> ml_ast -> unit
+val ast_occurs : int -> ml_ast -> bool
+val ast_occurs_itvl : int -> int -> ml_ast -> bool
+val ast_lift : int -> ml_ast -> ml_ast
+val ast_pop : ml_ast -> ml_ast
+val ast_subst : ml_ast -> ml_ast -> ml_ast
+
+val ast_glob_subst : ml_ast Refmap.t -> ml_ast -> ml_ast
+
+val normalize : ml_ast -> ml_ast
+val optimize_fix : ml_ast -> ml_ast
+val inline : NReference.reference -> ml_ast -> bool
+
+exception Impossible
+val branch_as_fun : ml_type list -> ml_branch -> ml_ast
+val branch_as_cst : ml_branch -> ml_ast
+
+(* Classification of signatures *)
+
+type sign_kind =
+  | EmptySig
+  | NonLogicalSig (* at least a [Keep] *)
+  | UnsafeLogicalSig (* No [Keep], at least a [Kill Kother] *)
+  | SafeLogicalSig (* only [Kill Ktype] *)
+
+val sign_kind : signature -> sign_kind
+
+val sign_no_final_keeps : signature -> signature
diff --git a/matita/components/ng_extraction/nCicExtraction.ml b/matita/components/ng_extraction/nCicExtraction.ml
new file mode 100644 (file)
index 0000000..4e16700
--- /dev/null
@@ -0,0 +1,1270 @@
+(* Copyright (C) 2000, HELM Team.
+ * 
+ * This file is part of HELM, an Hypertextual, Electronic
+ * Library of Mathematics, developed at the Computer Science
+ * Department, University of Bologna, Italy.
+ * 
+ * HELM is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * as published by the Free Software Foundation; either version 2
+ * of the License, or (at your option) any later version.
+ * 
+ * HELM is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with HELM; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place - Suite 330, Boston,
+ * MA  02111-1307, USA.
+ * 
+ * For details, see the HELM World-Wide-Web page,
+ * http://cs.unibo.it/helm/.
+ *)
+
+(* $Id: cicPp.ml 7413 2007-05-29 15:30:53Z tassi $ *)
+
+let fix_sorts t = t;;
+let apply_subst subst t = assert (subst=[]); t;;
+
+type typformerreference = NReference.reference
+type reference = NReference.reference
+
+type kind =
+  | Type
+  | KArrow of kind * kind
+  | KSkip of kind (* dropped abstraction *)
+
+let rec size_of_kind =
+  function
+    | Type -> 1
+    | KArrow (l, r) -> 1 + size_of_kind l + size_of_kind r
+    | KSkip k -> size_of_kind k
+;;
+
+let bracket ?(prec=1) size_of pp o =
+  if size_of o > prec then
+    "(" ^ pp o ^ ")"
+  else
+    pp o
+;;
+
+let rec pretty_print_kind =
+  function
+    | Type -> "*"
+    | KArrow (l, r) -> bracket size_of_kind pretty_print_kind l ^ " -> " ^ pretty_print_kind r
+    | KSkip k -> pretty_print_kind k
+;;
+
+type typ =
+  | Var of int
+  | Unit
+  | Top
+  | TConst of typformerreference
+  | Arrow of typ * typ
+  | TSkip of typ
+  | Forall of string * kind * typ
+  | TAppl of typ list
+
+let rec size_of_type =
+  function
+    | Var _ -> 0
+    | Unit -> 0
+    | Top -> 0
+    | TConst _ -> 0
+    | Arrow _ -> 2
+    | TSkip t -> size_of_type t
+    | Forall _ -> 2
+    | TAppl _ -> 1
+;;
+
+(* None = dropped abstraction *)
+type typ_context = (string * kind) option list
+type term_context = (string * [`OfKind of kind | `OfType of typ]) option list
+
+type typ_former_decl = typ_context * kind
+type typ_former_def = typ_former_decl * typ
+
+type term =
+  | Rel of int
+  | UnitTerm
+  | Const of reference
+  | Lambda of string * (* typ **) term
+  | Appl of term list
+  | LetIn of string * (* typ **) term * term
+  | Match of reference * term * (term_context * term) list
+  | BottomElim
+  | TLambda of string * term
+  | Inst of (*typ_former **) term
+  | Skip of term
+  | UnsafeCoerce of term
+;;
+
+type term_former_decl = term_context * typ
+type term_former_def = term_former_decl * term
+
+let mk_appl f x =
+ match f with
+    Appl args -> Appl (args@[x])
+  | _ -> Appl [f;x]
+
+let mk_tappl f l =
+ match f with
+    TAppl args -> TAppl (args@l)
+  | _ -> TAppl (f::l)
+
+let rec size_of_term =
+  function
+    | Rel _ -> 1
+    | UnitTerm -> 1
+    | Const _ -> 1
+    | Lambda (_, body) -> 1 + size_of_term body
+    | Appl l -> List.length l
+    | LetIn (_, def, body) -> 1 + size_of_term def + size_of_term body
+    | Match (_, case, pats) -> 1 + size_of_term case + List.length pats
+    | BottomElim -> 1
+    | TLambda (_,t) -> size_of_term t
+    | Inst t -> size_of_term t
+    | Skip t -> size_of_term t
+    | UnsafeCoerce t -> 1 + size_of_term t
+;;
+
+module ReferenceMap = Map.Make(struct type t = NReference.reference let compare = NReference.compare end)
+
+module GlobalNames = Set.Make(String)
+
+type info_el =
+ string * [`Type of typ_context * typ option | `Constructor of typ | `Function of typ ]
+type info = (NReference.reference * info_el) list
+type db = info_el ReferenceMap.t * GlobalNames.t
+
+let empty_info = []
+
+type obj_kind =
+   TypeDeclaration of typ_former_decl
+ | TypeDefinition of typ_former_def
+ | TermDeclaration of term_former_decl
+ | TermDefinition of term_former_def
+ | LetRec of (info * NReference.reference * obj_kind) list
+   (* reference, left, right, constructors *)
+ | Algebraic of (info * NReference.reference * typ_context * typ_context * (NReference.reference * typ) list) list
+
+type obj = info * NReference.reference * obj_kind
+
+(* For LetRec and Algebraic blocks *)
+let dummyref =
+ NReference.reference_of_string "cic:/matita/dummy/dummy.ind(1,1,1)"
+
+type not_term = [`Kind | `KindOrType | `PropKind | `Proposition | `Type];;
+
+let max_not_term t1 t2 =
+ match t1,t2 with
+    `KindOrType,_
+  | _,`KindOrType -> `KindOrType
+  | `Kind,_
+  | _,`Kind -> `Kind
+  | `Type,_
+  | _,`Type -> `Type
+  | `PropKind,_
+  | _,`PropKind -> `PropKind
+  | `Proposition,`Proposition -> `Proposition
+
+let sup = List.fold_left max_not_term `Proposition
+
+let rec classify_not_term status context t =
+ match NCicReduction.whd status ~subst:[] context t with
+  | NCic.Sort s ->
+     (match s with
+         NCic.Prop
+       | NCic.Type [`CProp,_] -> `PropKind
+       | NCic.Type [`Type,_] -> `Kind
+       | NCic.Type _ -> assert false)
+  | NCic.Prod (b,s,t) ->
+     (*CSC: using invariant on "_" *)
+     classify_not_term status ((b,NCic.Decl s)::context) t
+  | NCic.Implicit _
+  | NCic.LetIn _
+  | NCic.Const (NReference.Ref (_,NReference.CoFix _))
+  | NCic.Appl [] ->
+     assert false (* NOT POSSIBLE *)
+  | NCic.Lambda (n,s,t) ->
+     (* Lambdas can me met in branches of matches, expecially when the
+        output type is a product *)
+     classify_not_term status ((n,NCic.Decl s)::context) t
+  | NCic.Match (_,_,_,pl) ->
+     let classified_pl = List.map (classify_not_term status context) pl in
+      sup classified_pl
+  | NCic.Const (NReference.Ref (_,NReference.Fix _)) ->
+     assert false (* IMPOSSIBLE *)
+  | NCic.Meta _ -> assert false (* TODO *)
+  | NCic.Appl (NCic.Const (NReference.Ref (_,NReference.Fix (i,_,_)) as r)::_)->
+     let l,_,_ = NCicEnvironment.get_checked_fixes_or_cofixes status r in
+     let _,_,_,_,bo = List.nth l i in
+      classify_not_term status [] bo
+  | NCic.Appl (he::_) -> classify_not_term status context he
+  | NCic.Rel n ->
+     let rec find_sort typ =
+      match NCicReduction.whd status ~subst:[] context (NCicSubstitution.lift status n typ) with
+        NCic.Sort NCic.Prop -> `Proposition
+      | NCic.Sort (NCic.Type [`CProp,_]) -> `Proposition
+      | NCic.Sort (NCic.Type [`Type,_]) ->
+         (*CSC: we could be more precise distinguishing the user provided
+                minimal elements of the hierarchies and classify these
+                as `Kind *)
+         `KindOrType
+      | NCic.Sort (NCic.Type _) -> assert false (* ALGEBRAIC *)
+      | NCic.Prod (_,_,t) ->
+         (* we skipped arguments of applications, so here we need to skip
+            products *)
+         find_sort t
+      | _ -> assert false (* NOT A SORT *)
+     in
+      (match List.nth context (n-1) with
+          _,NCic.Decl typ -> find_sort typ
+        | _,NCic.Def _ -> assert false (* IMPOSSIBLE *))
+  | NCic.Const (NReference.Ref (_,NReference.Decl) as ref) ->
+     let _,_,ty,_,_ = NCicEnvironment.get_checked_decl status ref in
+      (match classify_not_term status [] ty with
+        | `Proposition
+        | `Type -> assert false (* IMPOSSIBLE *)
+        | `Kind
+        | `KindOrType -> `Type
+        | `PropKind -> `Proposition)
+  | NCic.Const (NReference.Ref (_,NReference.Ind _) as ref) ->
+     let _,_,ityl,_,i = NCicEnvironment.get_checked_indtys status ref in
+     let _,_,arity,_ = List.nth ityl i in
+      (match classify_not_term status [] arity with
+        | `Proposition
+        | `Type
+        | `KindOrType -> assert false (* IMPOSSIBLE *)
+        | `Kind -> `Type
+        | `PropKind -> `Proposition)
+  | NCic.Const (NReference.Ref (_,NReference.Con _))
+  | NCic.Const (NReference.Ref (_,NReference.Def _)) ->
+     assert false (* IMPOSSIBLE *)
+;;
+
+let classify status ~metasenv context t =
+ match NCicTypeChecker.typeof status ~metasenv ~subst:[] context t with
+  | NCic.Sort _ ->
+     (classify_not_term status context t : not_term :> [> not_term])
+  | ty ->
+     let ty = fix_sorts ty in
+      `Term
+        (match classify_not_term status context ty with
+          | `Proposition -> `Proof
+          | `Type -> `Term
+          | `KindOrType -> `TypeFormerOrTerm
+          | `Kind -> `TypeFormer
+          | `PropKind -> `PropFormer)
+;;
+      
+
+let rec kind_of status ~metasenv context k =
+ match NCicReduction.whd status ~subst:[] context k with
+  | NCic.Sort NCic.Type _ -> Type
+  | NCic.Sort _ -> assert false (* NOT A KIND *)
+  | NCic.Prod (b,s,t) ->
+     (match classify status ~metasenv context s with
+       | `Kind ->
+           KArrow (kind_of status ~metasenv context s,
+            kind_of ~metasenv status ((b,NCic.Decl s)::context) t)
+       | `Type
+       | `KindOrType
+       | `Proposition
+       | `PropKind ->
+           KSkip (kind_of status ~metasenv ((b,NCic.Decl s)::context) t)
+       | `Term _ -> assert false (* IMPOSSIBLE *))
+  | NCic.Implicit _
+  | NCic.LetIn _ -> assert false (* IMPOSSIBLE *)
+  | NCic.Lambda _
+  | NCic.Rel _
+  | NCic.Const _ -> assert false (* NOT A KIND *)
+  | NCic.Appl _ -> assert false (* TODO: when head is a match/let rec;
+                                   otherwise NOT A KIND *)
+  | NCic.Meta _
+  | NCic.Match (_,_,_,_) -> assert false (* TODO *)
+;;
+
+let rec skip_args status ~metasenv context =
+ function
+  | _,[] -> []
+  | [],_ -> assert false (* IMPOSSIBLE *)
+  | None::tl1,_::tl2 -> skip_args status ~metasenv context (tl1,tl2)
+  | _::tl1,arg::tl2 ->
+     match classify status ~metasenv context arg with
+      | `KindOrType
+      | `Type
+      | `Term `TypeFormer ->
+         Some arg::skip_args status ~metasenv context (tl1,tl2)
+      | `Kind
+      | `Proposition
+      | `PropKind -> None::skip_args status ~metasenv context (tl1,tl2)
+      | `Term _ -> assert false (* IMPOSSIBLE *)
+;;
+
+class type g_status =
+ object
+  method extraction_db: db
+ end
+
+class virtual status =
+ object
+  inherit NCic.status
+  val extraction_db = ReferenceMap.empty, GlobalNames.empty
+  method extraction_db = extraction_db
+  method set_extraction_db v = {< extraction_db = v >}
+  method set_extraction_status
+   : 'status. #g_status as 'status -> 'self
+   = fun o -> {< extraction_db = o#extraction_db >}
+ end
+
+let xdo_pretty_print_type = ref (fun _ _ -> assert false)
+let do_pretty_print_type status ctx t =
+ !xdo_pretty_print_type (status : #status :> status) ctx t
+
+let xdo_pretty_print_term = ref (fun _ _ -> assert false)
+let do_pretty_print_term status ctx t =
+ !xdo_pretty_print_term (status : #status :> status) ctx t
+
+let term_ctx_of_type_ctx =
+ List.map
+  (function
+      None -> None
+    | Some (name,k) -> Some (name,`OfKind k))
+
+let rec split_kind_prods context =
+ function
+  | KArrow (so,ta)-> split_kind_prods (Some ("_",so)::context) ta
+  | KSkip ta -> split_kind_prods (None::context) ta
+  | Type -> context,Type
+;;
+
+let rec split_typ_prods context =
+ function
+  | Arrow (so,ta)-> split_typ_prods (Some ("_",`OfType so)::context) ta
+  | Forall (name,so,ta)-> split_typ_prods (Some (name,`OfKind so)::context) ta
+  | TSkip ta -> split_typ_prods (None::context) ta
+  | _ as t -> context,t
+;;
+
+let rec glue_ctx_typ ctx typ =
+ match ctx with
+  | [] -> typ
+  | Some (_,`OfType so)::ctx -> glue_ctx_typ ctx (Arrow (so,typ))
+  | Some (name,`OfKind so)::ctx -> glue_ctx_typ ctx (Forall (name,so,typ))
+  | None::ctx -> glue_ctx_typ ctx (TSkip typ)
+;;
+
+let rec split_typ_lambdas status n ~metasenv context typ =
+ if n = 0 then context,typ
+ else
+  match NCicReduction.whd status ~delta:max_int ~subst:[] context typ with
+   | NCic.Lambda (name,s,t) ->
+      split_typ_lambdas status (n-1) ~metasenv ((name,NCic.Decl s)::context) t
+   | t ->
+      (* eta-expansion required *)
+      let ty = NCicTypeChecker.typeof status ~metasenv ~subst:[] context t in
+      match NCicReduction.whd status ~delta:max_int ~subst:[] context ty with
+       | NCic.Prod (name,typ,_) ->
+          split_typ_lambdas status (n-1) ~metasenv
+           ((name,NCic.Decl typ)::context)
+           (NCicUntrusted.mk_appl t [NCic.Rel 1])
+       | _ -> assert false (* IMPOSSIBLE *)
+;;
+
+
+let rev_context_of_typformer status ~metasenv context =
+ function
+    NCic.Const (NReference.Ref (_,NReference.Ind _) as ref)
+  | NCic.Const (NReference.Ref (_,NReference.Def _) as ref)
+  | NCic.Const (NReference.Ref (_,NReference.Decl) as ref)
+  | NCic.Const (NReference.Ref (_,NReference.Fix _) as ref) ->
+     (try
+       match snd (ReferenceMap.find ref (fst status#extraction_db)) with
+          `Type (ctx,_) -> List.rev ctx
+        | `Constructor _
+        | `Function _ -> assert false
+      with
+       Not_found ->
+        (* This can happen only when we are processing the type of
+           the constructor of a small singleton type. In this case
+           we are not interested in all the type, but only in its
+           backbone. That is why we can safely return the dummy context
+           here *)
+        let rec dummy = None::dummy in
+        dummy)
+  | NCic.Match _ -> assert false (* TODO ???? *)
+  | NCic.Rel n ->
+     let typ =
+      match List.nth context (n-1) with
+         _,NCic.Decl typ -> typ
+       | _,NCic.Def _ -> assert false (* IMPOSSIBLE *) in
+     let typ_ctx = snd (HExtlib.split_nth n context) in
+     let typ = kind_of status ~metasenv typ_ctx typ in
+      List.rev (fst (split_kind_prods [] typ))
+  | NCic.Meta _ -> assert false (* TODO *)
+  | NCic.Const (NReference.Ref (_,NReference.Con _))
+  | NCic.Const (NReference.Ref (_,NReference.CoFix _))
+  | NCic.Sort _ | NCic.Implicit _ | NCic.Lambda _ | NCic.LetIn _
+  | NCic.Appl _ | NCic.Prod _ ->
+     assert false (* IMPOSSIBLE *)
+
+let rec typ_of status ~metasenv context k =
+ match NCicReduction.whd status ~delta:max_int ~subst:[] context k with
+  | NCic.Prod (b,s,t) ->
+     (* CSC: non-invariant assumed here about "_" *)
+     (match classify status ~metasenv context s with
+       | `Kind ->
+           Forall (b, kind_of status ~metasenv context s,
+            typ_of ~metasenv status ((b,NCic.Decl s)::context) t)
+       | `Type
+       | `KindOrType -> (* ??? *)
+           Arrow (typ_of status ~metasenv context s,
+            typ_of status ~metasenv ((b,NCic.Decl s)::context) t)
+       | `PropKind
+       | `Proposition ->
+           TSkip (typ_of status ~metasenv ((b,NCic.Decl s)::context) t)
+       | `Term _ -> assert false (* IMPOSSIBLE *))
+  | NCic.Sort _
+  | NCic.Implicit _
+  | NCic.LetIn _ -> assert false (* IMPOSSIBLE *)
+  | NCic.Lambda _ -> Top (*assert false (* LAMBDA-LIFT INNER DECLARATION *)*)
+  | NCic.Rel n -> Var n
+  | NCic.Const ref -> TConst ref
+  | NCic.Match (_,_,_,_)
+  | NCic.Appl (NCic.Const (NReference.Ref (_,NReference.Fix _))::_) ->
+     Top
+  | NCic.Appl (he::args) ->
+     let rev_he_context= rev_context_of_typformer status ~metasenv context he in
+     TAppl (typ_of status ~metasenv context he ::
+      List.map
+       (function None -> Unit | Some ty -> typ_of status ~metasenv context ty)
+       (skip_args status ~metasenv context (rev_he_context,args)))
+  | NCic.Appl _ -> assert false (* TODO: when head is a match/let rec;
+                                   otherwise NOT A TYPE *)
+  | NCic.Meta _ -> assert false (*TODO*)
+;;
+
+let rec fomega_lift_type_from n k =
+ function
+  | Var m as t -> if m < k then t else Var (m + n)
+  | Top -> Top
+  | TConst _ as t -> t
+  | Unit -> Unit
+  | Arrow (ty1,ty2) -> Arrow (fomega_lift_type_from n k ty1,fomega_lift_type_from n (k+1) ty2)
+  | TSkip t -> TSkip (fomega_lift_type_from n (k+1) t)
+  | Forall (name,kind,t) -> Forall (name,kind,fomega_lift_type_from n (k+1) t)
+  | TAppl args -> TAppl (List.map (fomega_lift_type_from n k) args)
+
+let fomega_lift_type n t =
+ if n = 0 then t else fomega_lift_type_from n 0 t
+
+let fomega_lift_term n t =
+ let rec fomega_lift_term n k =
+  function
+   | Rel m as t -> if m < k then t else Rel (m + n)
+   | BottomElim
+   | UnitTerm
+   | Const _ as t -> t
+   | Lambda (name,t) -> Lambda (name,fomega_lift_term n (k+1) t)
+   | TLambda (name,t) -> TLambda (name,fomega_lift_term n (k+1) t)
+   | Appl args -> Appl (List.map (fomega_lift_term n k) args)
+   | LetIn (name,m,bo) ->
+      LetIn (name, fomega_lift_term n k m, fomega_lift_term n (k+1) bo)
+   | Match (ref,t,pl) ->
+      let lift_p (ctx,t) =
+       let lift_context ctx =
+        let len = List.length ctx in
+         HExtlib.list_mapi
+          (fun el i ->
+            let j = len - i - 1 in
+            match el with
+               None
+             | Some (_,`OfKind  _) as el -> el
+             | Some (name,`OfType t) ->
+                Some (name,`OfType (fomega_lift_type_from n (k+j) t))
+          ) ctx
+       in
+        lift_context ctx, fomega_lift_term n (k + List.length ctx) t
+      in
+      Match (ref,fomega_lift_term n k t,List.map lift_p pl)
+   | Inst t -> Inst (fomega_lift_term n k t)
+   | Skip t -> Skip (fomega_lift_term n (k+1) t)
+   | UnsafeCoerce t -> UnsafeCoerce (fomega_lift_term n k t)
+ in
+  if n = 0 then t else fomega_lift_term n 0 t
+;;
+
+let rec fomega_subst k t1 =
+ function
+  | Var n ->
+     if k=n then fomega_lift_type (k-1) t1
+     else if n < k then Var n
+     else Var (n-1)
+  | Top -> Top
+  | TConst ref -> TConst ref
+  | Unit -> Unit
+  | Arrow (ty1,ty2) -> Arrow (fomega_subst k t1 ty1, fomega_subst (k+1) t1 ty2)
+  | TSkip t -> TSkip (fomega_subst (k+1) t1 t)
+  | Forall (n,kind,t) -> Forall (n,kind,fomega_subst (k+1) t1 t)
+  | TAppl (he::args) ->
+     mk_tappl (fomega_subst k t1 he) (List.map (fomega_subst k t1) args)
+  | TAppl [] -> assert false
+
+let fomega_lookup status ref =
+ try
+  match snd (ReferenceMap.find ref (fst status#extraction_db)) with
+     `Type (_,bo) -> bo
+   | `Constructor _
+   | `Function _ -> assert false
+ with
+  Not_found ->
+prerr_endline ("BUG, THIS SHOULD NEVER HAPPEN " ^ NReference.string_of_reference ref); None
+
+let rec fomega_whd status ty =
+ match ty with
+ | TConst r ->
+    (match fomega_lookup status r with
+        None -> ty
+      | Some ty -> fomega_whd status ty)
+ | TAppl (TConst r::args) ->
+    (match fomega_lookup status r with
+        None -> ty
+      | Some ty -> fomega_whd status (List.fold_right (fomega_subst 1) args ty))
+ | _ -> ty
+
+let rec fomega_conv_kind k1 k2 =
+ match k1,k2 with
+    Type,Type -> true
+  | KArrow (s1,t1), KArrow (s2,t2) ->
+     fomega_conv_kind s1 s2 && fomega_conv_kind t1 t2
+  | KSkip k1, KSkip k2 -> fomega_conv_kind k1 k2
+  | _,_ -> false
+
+let rec fomega_conv status t1 t2 =
+ match fomega_whd status t1, fomega_whd status t2 with
+    Var n, Var m -> n=m
+  | Unit, Unit -> true
+  | Top, Top -> true
+  | TConst r1, TConst r2 -> NReference.eq r1 r2
+  | Arrow (s1,t1), Arrow (s2,t2) ->
+     fomega_conv status s1 s2 && fomega_conv status t1 t2
+  | TSkip t1, TSkip t2 -> fomega_conv status t1 t2
+  | Forall (_,k1,t1), Forall (_,k2,t2) ->
+     fomega_conv_kind k1 k2 && fomega_conv status t1 t2
+  | TAppl tl1, TAppl tl2 ->
+     (try
+       List.fold_left2 (fun b t1 t2 -> b && fomega_conv status t1 t2)
+        true tl1 tl2
+      with
+       Invalid_argument _ -> false)
+  | _,_ -> false
+
+exception PatchMe (* BUG: constructor of singleton type :-( *)
+
+let type_of_constructor status ref =
+ try
+  match snd (ReferenceMap.find ref (fst status#extraction_db)) with
+     `Constructor ty -> ty
+   | _ -> assert false
+ with
+  Not_found -> raise PatchMe (* BUG: constructor of singleton type :-( *)
+
+let type_of_appl_he status ~metasenv context =
+ function
+    NCic.Const (NReference.Ref (_,NReference.Con _) as ref)
+  | NCic.Const (NReference.Ref (_,NReference.Def _) as ref)
+  | NCic.Const (NReference.Ref (_,NReference.Decl) as ref)
+  | NCic.Const (NReference.Ref (_,NReference.Fix _) as ref)
+  | NCic.Const (NReference.Ref (_,NReference.CoFix _) as ref) ->
+     (try
+       match snd (ReferenceMap.find ref (fst status#extraction_db)) with
+          `Type _ -> assert false
+        | `Constructor ty
+        | `Function ty -> ty
+      with
+       Not_found -> assert false)
+  | NCic.Const (NReference.Ref (_,NReference.Ind _)) ->
+     assert false (* IMPOSSIBLE *)
+  | NCic.Rel n ->
+     (match List.nth context (n-1) with
+         _,NCic.Decl typ
+       | _,NCic.Def (_,typ) ->
+           (* recomputed every time *)
+           typ_of status ~metasenv context
+            (NCicSubstitution.lift status n typ))
+  | (NCic.Lambda _
+  | NCic.LetIn _
+  | NCic.Match _) as t ->
+     (* BUG: here we should implement a real type-checker since we are
+        trusting the translation of the Cic one that could be wrong
+        (e.g. pruned abstractions, etc.) *)
+     (typ_of status ~metasenv context
+      (NCicTypeChecker.typeof status ~metasenv ~subst:[] context t))
+  | NCic.Meta _ -> assert false (* TODO *)
+  | NCic.Sort _ | NCic.Implicit _ | NCic.Appl _ | NCic.Prod _ ->
+     assert false (* IMPOSSIBLE *)
+
+let rec term_of status ~metasenv context =
+ function
+  | NCic.Implicit _
+  | NCic.Sort _
+  | NCic.Prod _ -> assert false (* IMPOSSIBLE *)
+  | NCic.Lambda (b,ty,bo) ->
+     (* CSC: non-invariant assumed here about "_" *)
+     (match classify status ~metasenv context ty with
+       | `Kind ->
+           TLambda (b,term_of status ~metasenv ((b,NCic.Decl ty)::context) bo)
+       | `KindOrType (* ??? *)
+       | `Type ->
+           Lambda (b, term_of status ~metasenv ((b,NCic.Decl ty)::context) bo)
+       | `PropKind
+       | `Proposition ->
+           (* CSC: LAZY ??? *)
+           Skip (term_of status ~metasenv ((b,NCic.Decl ty)::context) bo)
+       | `Term _ -> assert false (* IMPOSSIBLE *))
+  | NCic.LetIn (b,ty,t,bo) ->
+     (match classify status ~metasenv context t with
+       | `Term `TypeFormerOrTerm (* ???? *)
+       | `Term `Term ->
+          LetIn (b,term_of status ~metasenv context t,
+           term_of status ~metasenv ((b,NCic.Def (t,ty))::context) bo)
+       | `Kind
+       | `Type
+       | `KindOrType
+       | `PropKind
+       | `Proposition
+       | `Term `PropFormer
+       | `Term `TypeFormer
+       | `Term `Proof ->
+         (* not in programming languages, we expand it *)
+         term_of status ~metasenv context
+          (NCicSubstitution.subst status ~avoid_beta_redexes:true t bo))
+  | NCic.Rel n -> Rel n
+  | NCic.Const ref -> Const ref
+  | NCic.Appl (he::args) ->
+     let hety = type_of_appl_he status ~metasenv context he in
+      eat_args status metasenv (term_of status ~metasenv context he) context
+       hety args
+  | NCic.Appl _ -> assert false (* TODO: when head is a match/let rec;
+                                   otherwise NOT A TYPE *)
+  | NCic.Meta _ -> assert false (* TODO *)
+  | NCic.Match (ref,_,t,pl) ->
+     let patterns_of pl =
+      let _,leftno,_,_,_ = NCicEnvironment.get_checked_indtys status ref in
+       let rec eat_branch n ty context ctx pat =
+         match (ty, pat) with
+         | TSkip t,_
+         | Forall (_,_,t),_
+         | Arrow (_, t), _ when n > 0 ->
+            eat_branch (pred n) t context ctx pat 
+         | _, _ when n > 0 -> assert false (*BUG: is Top possible here?*)
+         (*CSC: unify the three cases below? *)
+         | Arrow (_, t), NCic.Lambda (name, ty, t') ->
+           let ctx =
+            (Some (name,`OfType (typ_of status ~metasenv context ty)))::ctx in
+           let context = (name,NCic.Decl ty)::context in
+            eat_branch 0 t context ctx t'
+         | Forall (_,_,t),NCic.Lambda (name, ty, t') ->
+           let ctx =
+            (Some (name,`OfKind (kind_of status ~metasenv context ty)))::ctx in
+           let context = (name,NCic.Decl ty)::context in
+            eat_branch 0 t context ctx t'
+         | TSkip t,NCic.Lambda (name, ty, t') ->
+            let ctx = None::ctx in
+            let context = (name,NCic.Decl ty)::context in
+             eat_branch 0 t context ctx t'
+         | Top,_ -> assert false (* IMPOSSIBLE *)
+         | TSkip _, _
+         | Forall _,_
+         | Arrow _,_ -> assert false (*BUG here, eta-expand!*)
+         | _, _ -> context,ctx, pat
+       in
+        try
+         HExtlib.list_mapi
+          (fun pat i ->
+            let ref = NReference.mk_constructor (i+1) ref in
+            let ty = 
+             (* BUG HERE, QUICK BUG WRONG PATCH IN PLACE *)
+             try
+              type_of_constructor status ref
+             with
+              PatchMe ->
+               typ_of status ~metasenv context
+                (NCicTypeChecker.typeof status ~metasenv ~subst:[] context
+                 (NCic.Const ref))
+            in
+            let context,lhs,rhs = eat_branch leftno ty context [] pat in
+            let rhs =
+             (* UnsafeCoerce not always required *)
+             UnsafeCoerce (term_of status ~metasenv context rhs)
+            in
+             lhs,rhs
+          ) pl
+        with Invalid_argument _ -> assert false
+     in
+     (match classify_not_term status [] (NCic.Const ref) with
+      | `PropKind
+      | `KindOrType
+      | `Kind -> assert false (* IMPOSSIBLE *)
+      | `Proposition ->
+          (match patterns_of pl with
+              [] -> BottomElim
+            | [lhs,rhs] -> fomega_lift_term (- List.length lhs) rhs
+            | _ -> assert false)
+      | `Type ->
+          Match (ref,term_of status ~metasenv context t, patterns_of pl))
+and eat_args status metasenv acc context tyhe =
+ function
+    [] -> acc
+  | arg::tl ->
+     match fomega_whd status tyhe with
+        Arrow (s,t) ->
+         let acc =
+          match s with
+             Unit -> mk_appl acc UnitTerm
+           | _ ->
+             let foarg = term_of status ~metasenv context arg in
+              (* BUG HERE, we should implement a real type-checker instead of
+                 trusting the Cic type *)
+             let inferredty =
+              typ_of status ~metasenv context
+               (NCicTypeChecker.typeof status ~metasenv ~subst:[] context arg)in
+              if fomega_conv status inferredty s then
+               mk_appl acc foarg
+              else
+(
+prerr_endline ("ARG = " ^ status#ppterm ~metasenv ~subst:[] ~context arg);
+let context = List.map fst context in
+prerr_endline ("HE = " ^ do_pretty_print_term status context acc);
+prerr_endline ("CONTEXT= " ^ String.concat " " context);
+prerr_endline ("NOT CONV: " ^ do_pretty_print_type status context inferredty ^ " vs " ^ do_pretty_print_type status context s);
+               mk_appl acc (UnsafeCoerce foarg)
+)
+         in
+          eat_args status metasenv acc context (fomega_subst 1 Unit t) tl
+      | Top ->
+         let arg =
+          match classify status ~metasenv context arg with
+           | `PropKind
+           | `Proposition
+           | `Term `TypeFormer
+           | `Term `PropFormer
+           | `Term `Proof
+           | `Type
+           | `KindOrType
+           | `Kind -> UnitTerm
+           | `Term `TypeFormerOrTerm
+           | `Term `Term -> term_of status ~metasenv context arg
+         in
+          (* BUG: what if an argument of Top has been erased??? *)
+          eat_args status metasenv
+           (UnsafeCoerce (mk_appl acc (UnsafeCoerce arg)))
+           context Top tl
+      | Forall (_,_,t) ->
+(*
+prerr_endline "FORALL";
+let xcontext = List.map fst context in
+prerr_endline ("TYPE: " ^ do_pretty_print_type status xcontext (fomega_whd status tyhe));
+prerr_endline ("fARG = " ^ status#ppterm ~metasenv ~subst:[] ~context arg);
+prerr_endline ("fHE = " ^ do_pretty_print_term status xcontext acc);
+prerr_endline ("fCONTEXT= " ^ String.concat " " xcontext);
+*)
+         (match classify status ~metasenv context arg with
+           | `PropKind -> assert false (*TODO: same as below, coercion needed???*)
+           | `Proposition
+           | `Kind ->
+               eat_args status metasenv (UnsafeCoerce (Inst acc))
+                context (fomega_subst 1 Unit t) tl
+           | `KindOrType
+           | `Term `TypeFormer
+           | `Type ->
+               eat_args status metasenv (Inst acc)
+                context (fomega_subst 1 (typ_of status ~metasenv context arg) t)
+                 tl
+           | `Term _ -> assert false (*TODO: ????*))
+      | TSkip t ->
+         eat_args status metasenv acc context t tl
+      | Unit | Var _ | TConst _ | TAppl _ -> assert false (* NOT A PRODUCT *)
+;;
+
+type 'a result =
+  | Erased
+  | OutsideTheory
+  | Failure of string
+  | Success of 'a
+;;
+
+let fresh_name_of_ref status ref =
+ (*CSC: Patch while we wait for separate compilation *)
+ let candidate =
+  let name = NCicPp.r2s status true ref in
+  let NReference.Ref (uri,_) = ref in
+  let path = NUri.baseuri_of_uri uri in
+  let path = String.sub path 5 (String.length path - 5) in
+  let path = Str.global_replace (Str.regexp "/") "_" path in
+   path ^ "_" ^ name
+ in
+ let rec freshen candidate =
+  if GlobalNames.mem candidate (snd status#extraction_db) then
+   freshen (candidate ^ "'")
+  else
+   candidate
+ in
+  freshen candidate
+
+let register_info (db,names) (ref,(name,_ as info_el)) =
+ ReferenceMap.add ref info_el db,GlobalNames.add name names
+
+let register_name_and_info status (ref,info_el) =
+ let name = fresh_name_of_ref status ref in
+ let info = ref,(name,info_el) in
+ let infos,names = status#extraction_db in
+  status#set_extraction_db (register_info (infos,names) info), info
+
+let register_infos = List.fold_left register_info
+
+let object_of_constant status ~metasenv ref bo ty =
+  match classify status ~metasenv [] ty with
+    | `Kind ->
+        let ty = kind_of status ~metasenv [] ty in
+        let ctx0,res = split_kind_prods [] ty in
+        let ctx,bo =
+         split_typ_lambdas status ~metasenv (List.length ctx0) [] bo in
+        (match classify status ~metasenv ctx bo with
+          | `Type
+          | `KindOrType -> (* ?? no kind formers in System F_omega *)
+              let nicectx =
+               List.map2
+                (fun p1 n ->
+                  HExtlib.map_option (fun (_,k) ->
+                   (*CSC: BUG here, clashes*)
+                   String.uncapitalize (fst n),k) p1)
+                ctx0 ctx
+              in
+              let bo = typ_of status ~metasenv ctx bo in
+              let info = ref,`Type (nicectx,Some bo) in
+              let status,info = register_name_and_info status info in
+               status,Success ([info],ref,TypeDefinition((nicectx,res),bo))
+          | `Kind -> status, Erased (* DPM: but not really, more a failure! *)
+          | `PropKind
+          | `Proposition -> status, Erased
+          | `Term _ -> status, Failure "Body of type lambda classified as a term.  This is a bug.")
+    | `PropKind
+    | `Proposition -> status, Erased
+    | `KindOrType (* ??? *)
+    | `Type ->
+       let ty = typ_of status ~metasenv [] ty in
+       let info = ref,`Function ty in
+       let status,info = register_name_and_info status info in
+        status,
+         Success ([info],ref, TermDefinition (split_typ_prods [] ty,
+         term_of status ~metasenv [] bo))
+    | `Term _ -> status, Failure "Non-term classified as a term.  This is a bug."
+;;
+
+let object_of_inductive status ~metasenv uri ind leftno il =
+ let status,_,rev_tyl =
+  List.fold_left
+   (fun (status,i,res) (_,_,arity,cl) ->
+     match classify_not_term status [] arity with
+      | `Proposition
+      | `KindOrType
+      | `Type -> assert false (* IMPOSSIBLE *)
+      | `PropKind -> status,i+1,res
+      | `Kind ->
+          let arity = kind_of status ~metasenv [] arity in
+          let ctx,_ = split_kind_prods [] arity in
+          let right,left = HExtlib.split_nth (List.length ctx - leftno) ctx in
+          let ref =
+           NReference.reference_of_spec uri (NReference.Ind (ind,i,leftno)) in
+          let info = ref,`Type (ctx,None) in
+          let status,info = register_name_and_info status info in
+          let _,status,cl_rev,infos =
+           List.fold_left
+            (fun (j,status,res,infos) (_,_,ty) ->
+              let ctx,ty =
+               NCicReduction.split_prods status ~subst:[] [] leftno ty in
+              let ty = typ_of status ~metasenv ctx ty in
+              let left = term_ctx_of_type_ctx left in
+              let full_ty = glue_ctx_typ left ty in
+              let ref = NReference.mk_constructor j ref in
+              let info = ref,`Constructor full_ty in
+              let status,info = register_name_and_info status info in
+               j+1,status,((ref,ty)::res),info::infos
+            ) (1,status,[],[]) cl
+          in
+           status,i+1,(info::infos,ref,left,right,List.rev cl_rev)::res
+   ) (status,0,[]) il
+ in
+  match rev_tyl with
+     [] -> status,Erased
+   | _ -> status, Success ([], dummyref, Algebraic (List.rev rev_tyl))
+;;
+
+let object_of status (uri,height,metasenv,subst,obj_kind) =
+  let obj_kind = apply_subst subst obj_kind in
+      match obj_kind with
+        | NCic.Constant (_,_,None,ty,_) ->
+          let ref = NReference.reference_of_spec uri NReference.Decl in
+          (match classify status ~metasenv [] ty with
+            | `Kind ->
+              let ty = kind_of status ~metasenv [] ty in
+              let ctx,_ as res = split_kind_prods [] ty in
+              let info = ref,`Type (ctx,None) in
+              let status,info = register_name_and_info status info in
+               status, Success ([info],ref, TypeDeclaration res)
+            | `PropKind
+            | `Proposition -> status, Erased
+            | `Type
+            | `KindOrType (*???*) ->
+              let ty = typ_of status ~metasenv [] ty in
+              let info = ref,`Function ty in
+              let status,info = register_name_and_info status info in
+               status,Success ([info],ref,
+                TermDeclaration (split_typ_prods [] ty))
+            | `Term _ -> status, Failure "Type classified as a term.  This is a bug.")
+        | NCic.Constant (_,_,Some bo,ty,_) ->
+           let ref = NReference.reference_of_spec uri (NReference.Def height) in
+            object_of_constant status ~metasenv ref bo ty
+        | NCic.Fixpoint (fix_or_cofix,fs,_) ->
+          let _,status,objs =
+            List.fold_right
+            (fun (_,_name,recno,ty,bo) (i,status,res) ->
+              let ref =
+               if fix_or_cofix then
+                NReference.reference_of_spec
+                 uri (NReference.Fix (i,recno,height))
+               else
+                NReference.reference_of_spec uri (NReference.CoFix i)
+              in
+              let status,obj = object_of_constant ~metasenv status ref bo ty in
+                match obj with
+                  | Success (info,ref,obj) -> i+1,status, (info,ref,obj)::res
+                  | _ -> i+1,status, res) fs (0,status,[])
+          in
+            status, Success ([],dummyref,LetRec objs)
+        | NCic.Inductive (ind,leftno,il,_) ->
+           object_of_inductive status ~metasenv uri ind leftno il
+
+(************************ HASKELL *************************)
+
+(* -----------------------------------------------------------------------------
+ * Helper functions I can't seem to find anywhere in the OCaml stdlib?
+ * -----------------------------------------------------------------------------
+ *)
+let (|>) f g =
+  fun x -> g (f x)
+;;
+
+let curry f x y =
+  f (x, y)
+;;
+
+let uncurry f (x, y) =
+  f x y
+;;
+
+let rec char_list_of_string s =
+  let l = String.length s in
+  let rec aux buffer s =
+    function
+      | 0 -> buffer
+      | m -> aux (s.[m - 1]::buffer) s (m - 1)
+  in
+    aux [] s l
+;;
+
+let string_of_char_list s =
+  let rec aux buffer =
+    function
+      | []    -> buffer
+      | x::xs -> aux (String.make 1 x ^ buffer) xs
+  in
+    aux "" s
+;;
+
+(* ----------------------------------------------------------------------------
+ * Haskell name management: prettyfying valid and idiomatic Haskell identifiers
+ * and type variable names.
+ * ----------------------------------------------------------------------------
+ *)
+
+let remove_underscores_and_mark l =
+  let rec aux char_list_buffer positions_buffer position =
+    function
+      | []    -> (string_of_char_list char_list_buffer, positions_buffer)
+      | x::xs ->
+        if x == '_' then
+          aux char_list_buffer (position::positions_buffer) position xs
+        else
+          aux (x::char_list_buffer) positions_buffer (position + 1) xs
+  in
+   if l = ['_'] then "_",[] else aux [] [] 0 l
+;;
+
+let rec capitalize_marked_positions s =
+  function
+    | []    -> s
+    | x::xs ->
+      if x < String.length s then
+        let c = Char.uppercase (String.get s x) in
+        let _ = String.set s x c in
+          capitalize_marked_positions s xs
+      else
+        capitalize_marked_positions s xs
+;;
+
+let contract_underscores_and_capitalise =
+  char_list_of_string |>
+  remove_underscores_and_mark |>
+  uncurry capitalize_marked_positions
+;;
+
+let idiomatic_haskell_type_name_of_string =
+  contract_underscores_and_capitalise |>
+  String.capitalize
+;;
+
+let idiomatic_haskell_term_name_of_string =
+  contract_underscores_and_capitalise |>
+  String.uncapitalize
+;;
+
+let classify_reference status ref =
+ try
+  match snd (ReferenceMap.find ref (fst status#extraction_db)) with
+     `Type _ -> `TypeName
+   | `Constructor _ -> `Constructor
+   | `Function _ -> `FunctionName
+ with
+  Not_found ->
+prerr_endline ("BUG, THIS SHOULD NEVER HAPPEN " ^ NReference.string_of_reference ref); `FunctionName
+;;
+
+let capitalize classification name =
+  match classification with
+    | `Constructor
+    | `TypeName -> idiomatic_haskell_type_name_of_string name
+    | `TypeVariable
+    | `BoundVariable
+    | `FunctionName -> idiomatic_haskell_term_name_of_string name
+;;
+
+let pp_ref status ref =
+ capitalize (classify_reference status ref)
+  (try fst (ReferenceMap.find ref (fst status#extraction_db))
+   with Not_found ->
+prerr_endline ("BUG with coercions: " ^ NReference.string_of_reference ref);
+(*assert false*)
+ NCicPp.r2s status true ref (* BUG: this should never happen *)
+)
+
+(* cons avoid duplicates *)
+let rec (@:::) name l =
+ if name <> "" (* propositional things *) && name.[0] = '_' then
+  let name = String.sub name 1 (String.length name - 1) in
+  let name = if name = "" then "a" else name in
+   name @::: l
+ else if List.mem name l then (name ^ "'") @::: l
+ else name,l
+;;
+
+let (@::) x l = let x,l = x @::: l in x::l;;
+
+let rec pretty_print_type status ctxt =
+  function
+    | Var n -> List.nth ctxt (n-1)
+    | Unit -> "()"
+    | Top -> "GHC.Prim.Any"
+    | TConst ref -> pp_ref status ref
+    | Arrow (t1,t2) ->
+        bracket size_of_type (pretty_print_type status ctxt) t1 ^ " -> " ^
+         pretty_print_type status ("_"::ctxt) t2
+    | TSkip t -> pretty_print_type status ("_"::ctxt) t
+    | Forall (name, kind, t) ->
+      (*CSC: BUG HERE: avoid clashes due to uncapitalisation*)
+      let name = capitalize `TypeVariable name in
+      let name,ctxt = name@:::ctxt in
+        if size_of_kind kind > 1 then
+          "forall (" ^ name ^ " :: " ^ pretty_print_kind kind ^ "). " ^ pretty_print_type status (name::ctxt) t
+        else
+          "forall " ^ name ^ ". " ^ pretty_print_type status (name::ctxt) t
+   | TAppl tl ->
+      String.concat " "
+       (List.map
+         (fun t -> bracket ~prec:0 size_of_type
+          (pretty_print_type status ctxt) t) tl)
+;;
+
+xdo_pretty_print_type := pretty_print_type;;
+
+
+let pretty_print_term_context status ctx1 ctx2 =
+ let name_context, rev_res =
+  List.fold_right
+    (fun el (ctx1,rev_res) ->
+      match el with
+         None -> ""@::ctx1,rev_res
+       | Some (name,`OfKind _) ->
+          let name = capitalize `TypeVariable name in
+           name@::ctx1,rev_res
+       | Some (name,`OfType typ) ->
+          let name = capitalize `TypeVariable name in
+          let name,ctx1 = name@:::ctx1 in
+           name::ctx1,
+            ("(" ^ name ^ " :: " ^ pretty_print_type status ctx1 typ ^ ")")::rev_res
+    ) ctx2 (ctx1,[]) in
+  name_context, String.concat " " (List.rev rev_res)
+
+let rec pretty_print_term status ctxt =
+  function
+    | Rel n -> List.nth ctxt (n-1)
+    | UnitTerm -> "()"
+    | Const ref -> pp_ref status ref
+    | Lambda (name,t) ->
+       let name = capitalize `BoundVariable name in
+       let name,ctxt = name@:::ctxt in
+        "\\" ^ name ^ " -> " ^ pretty_print_term status (name::ctxt) t
+    | Appl tl -> String.concat " " (List.map (bracket size_of_term (pretty_print_term status ctxt)) tl)
+    | LetIn (name,s,t) ->
+       let name = capitalize `BoundVariable name in
+       let name,ctxt = name@:::ctxt in
+        "let " ^ name ^ " = " ^ pretty_print_term status ctxt s ^ " in " ^
+         pretty_print_term status (name::ctxt) t
+    | BottomElim ->
+       "error \"Unreachable code\""
+    | UnsafeCoerce t ->
+       "unsafeCoerce " ^ bracket size_of_term (pretty_print_term status ctxt) t
+    | Match (r,matched,pl) ->
+      if pl = [] then
+       "error \"Case analysis over empty type\""
+      else
+       "case " ^ pretty_print_term status ctxt matched ^ " of {\n" ^
+         String.concat " ;\n"
+           (HExtlib.list_mapi
+             (fun (bound_names,rhs) i ->
+               let ref = NReference.mk_constructor (i+1) r in
+               let name = pp_ref status ref in
+               let ctxt,bound_names =
+                pretty_print_term_context status ctxt bound_names in
+               let body =
+                pretty_print_term status ctxt rhs
+               in
+                 "  " ^ name ^ " " ^ bound_names ^ " -> " ^ body
+             ) pl) ^ "}\n  "
+    | Skip t -> pretty_print_term status ("[[skipped]]"@::ctxt) t
+    | TLambda (name,t) ->
+       let name = capitalize `TypeVariable name in
+        pretty_print_term status (name@::ctxt) t
+    | Inst t -> pretty_print_term status ctxt t
+;;
+
+xdo_pretty_print_term := pretty_print_term;;
+
+let rec pp_obj status (_,ref,obj_kind) =
+  let pretty_print_context ctx =
+    String.concat " " (List.rev (snd
+      (List.fold_right
+       (fun (x,kind) (l,res) ->
+         let x,l = x @:::l in
+         if size_of_kind kind > 1 then
+          x::l,("(" ^ x ^ " :: " ^ pretty_print_kind kind ^ ")")::res
+         else
+          x::l,x::res)
+       (HExtlib.filter_map (fun x -> x) ctx) ([],[]))))
+  in
+ let namectx_of_ctx ctx =
+  List.fold_right (@::)
+   (List.map (function None -> "" | Some (x,_) -> x) ctx) [] in
+ match obj_kind with
+   TypeDeclaration (ctx,_) ->
+    (* data?? unsure semantics: inductive type without constructor, but
+       not matchable apparently *)
+    if List.length ctx = 0 then
+      "data " ^ pp_ref status ref
+    else
+      "data " ^ pp_ref status ref ^ " " ^ pretty_print_context ctx
+ | TypeDefinition ((ctx, _),ty) ->
+    let namectx = namectx_of_ctx ctx in
+    if List.length ctx = 0 then
+      "type " ^ pp_ref status ref ^ " = " ^ pretty_print_type status namectx ty
+    else
+      "type " ^ pp_ref status ref ^ " " ^ pretty_print_context ctx ^ " = " ^ pretty_print_type status namectx ty
+ | TermDeclaration (ctx,ty) ->
+    let name = pp_ref status ref in
+      name ^ " :: " ^ pretty_print_type status [] (glue_ctx_typ ctx ty) ^ "\n" ^
+      name ^ " = error \"The declaration `" ^ name ^ "' has yet to be defined.\""
+ | TermDefinition ((ctx,ty),bo) ->
+    let name = pp_ref status ref in
+    let namectx = namectx_of_ctx ctx in
+    (*CSC: BUG here *)
+    name ^ " :: " ^ pretty_print_type status namectx (glue_ctx_typ ctx ty) ^ "\n" ^
+    name ^ " = " ^ pretty_print_term status namectx bo
+ | LetRec l ->
+    String.concat "\n" (List.map (pp_obj status) l)
+ | Algebraic il ->
+    String.concat "\n"
+     (List.map
+      (fun _,ref,left,right,cl ->
+        "data " ^ pp_ref status ref ^ " " ^
+        pretty_print_context (right@left) ^ " where\n  " ^
+        String.concat "\n  " (List.map
+         (fun ref,tys ->
+           let namectx = namectx_of_ctx left in
+            pp_ref status ref ^ " :: " ^
+             pretty_print_type status namectx tys
+         ) cl) (*^ "\n    deriving (Prelude.Show)"*)
+      ) il)
+ (* inductive and records missing *)
+
+let rec infos_of (info,_,obj_kind) =
+ info @
+  match obj_kind with
+     LetRec l -> List.concat (List.map (fun (infos,_,_) -> infos) l)
+   | Algebraic l -> List.concat (List.map (fun (infos,_,_,_,_) -> infos) l)
+   | _ -> []
+
+let haskell_of_obj status (uri,_,_,_,_ as obj) =
+ let status, obj = object_of status obj in
+  status,
+   match obj with
+      Erased -> "-- [?] " ^ NUri.name_of_uri uri ^ " erased due to term being propositionally irrelevant.\n",[]
+    | OutsideTheory -> "-- [?] " ^ NUri.name_of_uri uri ^ " erased due to image of term under extraction residing outside Fω.\n",[]
+    | Failure msg -> "-- [?] " ^ NUri.name_of_uri uri ^ " FAILURE: " ^ msg ^ "\n",[]
+    | Success o -> pp_obj status o ^ "\n", infos_of o
+
+let refresh_uri_in_typ ~refresh_uri_in_reference =
+ let rec refresh_uri_in_typ =
+  function
+   | Var _
+   | Unit
+   | Top as t -> t
+   | TConst r -> TConst (refresh_uri_in_reference r)
+   | Arrow (t1,t2) -> Arrow (refresh_uri_in_typ t1, refresh_uri_in_typ t2)
+   | TSkip t -> TSkip (refresh_uri_in_typ t)
+   | Forall (n,k,t) -> Forall (n,k,refresh_uri_in_typ t)
+   | TAppl tl -> TAppl (List.map refresh_uri_in_typ tl)
+ in
+  refresh_uri_in_typ
+
+let refresh_uri_in_info ~refresh_uri_in_reference infos =
+ List.map
+  (function (ref,el) ->
+    match el with
+       name,`Constructor typ ->
+        let typ = refresh_uri_in_typ ~refresh_uri_in_reference typ in
+         refresh_uri_in_reference ref, (name,`Constructor typ)
+     | name,`Function typ ->
+        let typ = refresh_uri_in_typ ~refresh_uri_in_reference typ in
+         refresh_uri_in_reference ref, (name,`Function typ)
+     | name,`Type (ctx,typ) ->
+         let typ =
+          match typ with
+             None -> None
+           | Some t -> Some (refresh_uri_in_typ ~refresh_uri_in_reference t)
+         in
+          refresh_uri_in_reference ref, (name,`Type (ctx,typ)))
+  infos
diff --git a/matita/components/ng_extraction/nCicExtraction.mli b/matita/components/ng_extraction/nCicExtraction.mli
new file mode 100644 (file)
index 0000000..d5cb663
--- /dev/null
@@ -0,0 +1,40 @@
+(*
+    ||M||  This file is part of HELM, an Hypertextual, Electronic        
+    ||A||  Library of Mathematics, developed at the Computer Science     
+    ||T||  Department, University of Bologna, Italy.                     
+    ||I||                                                                
+    ||T||  HELM is free software; you can redistribute it and/or         
+    ||A||  modify it under the terms of the GNU General Public License   
+    \   /  version 2 or (at your option) any later version.      
+     \ /   This software is distributed as is, NO WARRANTY.     
+      V_______________________________________________________________ *)
+
+(* $Id: nCicEnvironment.mli 11172 2011-01-11 21:06:37Z sacerdot $ *)
+
+type info
+type db
+
+class type g_status =
+ object
+  method extraction_db: db
+ end
+
+class virtual status :
+ object ('self)
+  inherit g_status
+  inherit NCic.status
+  method set_extraction_db: db -> 'self
+  method set_extraction_status: #g_status -> 'self
+ end
+
+val empty_info: info
+
+val refresh_uri_in_info:
+ refresh_uri_in_reference:(NReference.reference -> NReference.reference) ->
+  info -> info
+
+val register_infos: db -> info -> db
+
+(* Haskell *)
+val haskell_of_obj: (#status as 'status) -> NCic.obj ->
+ 'status * (string * info)
diff --git a/matita/components/ng_extraction/ocaml.ml b/matita/components/ng_extraction/ocaml.ml
new file mode 100644 (file)
index 0000000..a612c58
--- /dev/null
@@ -0,0 +1,652 @@
+(************************************************************************)
+(*  v      *   The Coq Proof Assistant  /  The Coq Development Team     *)
+(* <O___,, *   INRIA - CNRS - LIX - LRI - PPS - Copyright 1999-2011     *)
+(*   \VV/  **************************************************************)
+(*    //   *      This file is distributed under the terms of the       *)
+(*         *       GNU Lesser General Public License Version 2.1        *)
+(************************************************************************)
+
+(*i $Id: ocaml.ml 14641 2011-11-06 11:59:10Z herbelin $ i*)
+
+(*s Production of Ocaml syntax. *)
+
+open OcamlExtractionTable
+open Coq
+open Miniml
+open Mlutil
+open Common
+
+
+(*s Some utility functions. *)
+
+let pp_tvar id =
+  let s = id in
+  if String.length s < 2 || s.[1]<>'\''
+  then str ("'"^s)
+  else str ("' "^s)
+
+let pp_tuple_light status f = function
+  | [] -> status,mt ()
+  | [x] -> f status true x
+  | l ->
+     let status,res =
+      prlist_with_sep_status status
+       (fun () -> str "," ++ spc ()) (fun status -> f status false) l in
+     status, pp_par true res
+
+let pp_tuple status f = function
+  | [] -> status,mt ()
+  | [x] -> f status x
+  | l ->
+     let status,res =
+      prlist_with_sep_status status (fun () -> str "," ++ spc ()) f l in
+     status,pp_par true res
+
+let pp_boxed_tuple f = function
+  | [] -> mt ()
+  | [x] -> f x
+  | l -> pp_par true (hov 0 (prlist_with_sep (fun () -> str "," ++ spc ()) f l))
+
+let pp_abst = function
+  | [] -> mt ()
+  | l  ->
+      str "fun " ++ prlist_with_sep (fun () -> str " ") pr_id l ++
+      str " ->" ++ spc ()
+
+let pp_parameters l =
+  (pp_boxed_tuple pp_tvar l ++ space_if (l<>[]))
+
+(*s Ocaml renaming issues. *)
+
+let keywords =
+  List.fold_right Idset.add
+  [ "and"; "as"; "assert"; "begin"; "class"; "constraint"; "do";
+    "done"; "downto"; "else"; "end"; "exception"; "external"; "false";
+    "for"; "fun"; "function"; "functor"; "if"; "in"; "include";
+    "inherit"; "initializer"; "lazy"; "let"; "match"; "method";
+    "module"; "mutable"; "new"; "object"; "of"; "open"; "or";
+    "parser"; "private"; "rec"; "sig"; "struct"; "then"; "to"; "true";
+    "try"; "type"; "val"; "virtual"; "when"; "while"; "with"; "mod";
+    "land"; "lor"; "lxor"; "lsl"; "lsr"; "asr" ; "unit" ; "_" ; "__" ]
+  Idset.empty
+;;
+
+set_keywords keywords;;
+
+let pp_open status filename =
+ let status,res = modname_of_filename status true filename in
+ status, str ("open " ^ res  ^ "\n") ++ fnl ()
+
+(*s The pretty-printer for Ocaml syntax*)
+
+(* Beware of the side-effects of [pp_global] and [pp_modname].
+   They are used to update table of content for modules. Many [let]
+   below should not be altered since they force evaluation order.
+*)
+
+let str_global status k r =
+ (*CSC: if is_inline_custom r then find_custom r else*) Common.pp_global status k r
+
+let pp_global status k r =
+ let status,res = str_global status k r in
+  status,str res
+
+(*CSC
+let pp_modname mp = str (Common.pp_module mp)
+
+let is_infix r =
+  is_inline_custom r &&
+  (let s = find_custom r in
+   let l = String.length s in
+   l >= 2 && s.[0] = '(' && s.[l-1] = ')')
+
+let get_infix r =
+  let s = find_custom r in
+  String.sub s 1 (String.length s - 2)
+*)
+
+let pp_one_field status _r _i r = pp_global status Term r
+
+let pp_field status r fields i = pp_one_field status r i (List.nth fields i)
+
+let pp_fields status r fields =
+ list_map_i_status status (fun status -> pp_one_field status r) 0 fields
+
+(*s Pretty-printing of types. [par] is a boolean indicating whether parentheses
+    are needed or not. *)
+
+let rec pp_type status par vl t =
+  let rec pp_rec status par = function
+    | Tmeta _ | Tvar' _ | Taxiom -> assert false
+    | Tvar i -> (try status,pp_tvar (List.nth vl (pred i))
+                with _ -> status,(str "'a" ++ int i))
+(*CSC:
+    | Tglob (r,[a1;a2]) when is_infix r ->
+       pp_par par (pp_rec true a1 ++ str (get_infix r) ++ pp_rec true a2)
+*)
+    | Tglob (r,[]) -> pp_global status Type r
+(*CSC:
+    | Tglob (IndRef(kn,0),l) when kn = mk_ind "Coq.Init.Specif" "sig" ->
+       pp_tuple_light pp_rec l
+*)
+    | Tglob (r,l) ->
+       let status,res = pp_tuple_light status pp_rec l in
+       let status,res2 = pp_global status Type r in
+       status,res ++ spc () ++ res2
+    | Tarr (t1,t2) ->
+       let status,res = pp_rec status true t1 in
+       let status,res2 = pp_rec status false t2 in
+       status,pp_par par (res ++ spc () ++ str "->" ++ spc () ++ res2)
+    | Tdummy _ -> status,str "__"
+    | Tunknown -> status,str "__"
+  in
+  let status,res = pp_rec status par t in
+   status,hov 0 res
+
+(*s Pretty-printing of expressions. [par] indicates whether
+    parentheses are needed or not. [env] is the list of names for the
+    de Bruijn variables. [args] is the list of collected arguments
+    (already pretty-printed). *)
+
+let is_ifthenelse = function
+(*CSC:
+  | [|(r1,[],_);(r2,[],_)|] ->
+      (try (find_custom r1 = "true") && (find_custom r2 = "false")
+       with Not_found -> false)*)
+  | _ -> false
+
+let expr_needs_par = function
+  | MLlam _  -> true
+  | MLcase (_,_,[|_|]) -> false
+  | MLcase (_,_,pv) -> not (is_ifthenelse pv)
+  | _        -> false
+
+let rec pp_expr status par env args =
+  let par' = args <> [] || par
+  and apply st = pp_apply st par args in
+  function
+    | MLrel n ->
+       let id = get_db_name n env in status,apply (pr_id id)
+    | MLapp (f,args') ->
+       let status,stl = map_status status (fun status -> pp_expr status true env []) args' in
+        pp_expr status par env (stl @ args) f
+    | MLlam _ as a ->
+       let fl,a' = collect_lams a in
+       let fl = List.map id_of_mlid fl in
+       let fl,env' = push_vars fl env in
+        let status,res = pp_expr status false env' [] a' in
+       let st = (pp_abst (List.rev fl) ++ res) in
+       status,apply (pp_par par' st)
+    | MLletin (id,a1,a2) ->
+       let i,env' = push_vars [id_of_mlid id] env in
+       let pp_id = pr_id (List.hd i) in
+       let status,pp_a1 = pp_expr status false env [] a1 in
+       let status,pp_a2 =
+         pp_expr status (not par && expr_needs_par a2) env' [] a2 in
+        status,
+       hv 0
+         (apply
+            (pp_par par'
+               (hv 0
+                  (hov 2
+                     (str "let " ++ pp_id ++ str " =" ++ spc () ++ pp_a1) ++
+                   spc () ++ str "in") ++
+                spc () ++ hov 0 pp_a2)))
+    | MLglob r ->
+       (try
+          let args = list_skipn (projection_arity status r) args in
+          let record = List.hd args in
+          let status,res = pp_global status Term r in
+          status,pp_apply (record ++ str "." ++ res) par (List.tl args)
+        with _ ->
+          let status,res = pp_global status Term r in
+           status,apply res)
+(*CSC:    | MLcons _ as c when is_native_char c -> assert (args=[]); pp_native_char c*)
+    | MLcons ({c_kind = Coinductive},r,[]) ->
+       assert (args=[]);
+        let status,res = pp_global status Cons r in
+       status,pp_par par (str "lazy " ++ res)
+    | MLcons ({c_kind = Coinductive},r,args') ->
+       assert (args=[]);
+       let status,tuple =
+         pp_tuple status (fun status -> pp_expr status true env []) args' in
+        let status,res = pp_global status Cons r in
+       status,
+        pp_par par (str "lazy (" ++ res ++ spc() ++ tuple ++str ")")
+    | MLcons (_,r,[]) ->
+       assert (args=[]);
+       pp_global status Cons r
+    | MLcons ({c_kind = Record fields}, r, args') ->
+       assert (args=[]);
+        let status,res = pp_fields status r fields in
+        let status,res2 =
+         map_status status (fun status -> pp_expr status true env []) args' in
+       status,pp_record_pat (res, res2)
+(*CSC:    | MLcons (_,r,[arg1;arg2]) when is_infix r ->
+       assert (args=[]);
+       pp_par par
+         ((pp_expr status true env [] arg1) ++ str (get_infix r) ++
+          (pp_expr status true env [] arg2))*)
+    | MLcons (_,r,args') ->
+       assert (args=[]);
+       let status,tuple =
+         pp_tuple status (fun status -> pp_expr status true env []) args' in
+        let status,res = str_global status Cons r in
+       if res = "" (* hack Extract Inductive prod *)
+       then status,tuple
+       else
+         let status,res = pp_global status Cons r in
+         status,pp_par par (res ++ spc () ++ tuple)
+(*CSC:    | MLcase (_, t, pv) when is_custom_match pv ->
+       let mkfun (_,ids,e) =
+         if ids <> [] then named_lams (List.rev ids) e
+         else dummy_lams (ast_lift 1 e) 1
+       in
+       apply
+         (pp_par par'
+            (hov 2
+               (str (find_custom_match pv) ++ fnl () ++
+                prvect (fun tr -> pp_expr status true env [] (mkfun tr) ++ fnl ()) pv
+                ++ pp_expr status true env [] t)))*)
+    | MLcase (info, t, pv) ->
+       let status,expr = if info.m_kind = Coinductive then
+         let status,res = pp_expr status true env [] t in
+         status,(str "Lazy.force" ++ spc () ++ res)
+       else
+         (pp_expr status false env [] t)
+       in
+       (try
+          (* First, can this match be printed as a mere record projection ? *)
+          let fields =
+            match info.m_kind with Record f -> f | _ -> raise Impossible
+          in
+          let (r, ids, c) = pv.(0) in
+          let n = List.length ids in
+          let free_of_patvar a = not (List.exists (ast_occurs_itvl 1 n) a) in
+          let proj_hd status i =
+            let status,res = pp_expr status true env [] t in
+            let status,res2 = pp_field status r fields i in
+             status,res ++ str "." ++ res2
+          in
+          match c with
+            | MLrel i when i <= n ->
+                let status,res = proj_hd status (n-i) in
+                status,apply (pp_par par' res)
+            | MLapp (MLrel i, a) when (i <= n) && (free_of_patvar a) ->
+              let _ids,env' = push_vars (List.rev_map id_of_mlid ids) env in
+               let status,res = proj_hd status (n-i) in
+               let status,res2 =
+                map_status status (fun status -> pp_expr status true env' []) a
+               in
+              status,(pp_apply res par (res2 @ args))
+            | _ -> raise Impossible
+        with Impossible ->
+          (* Second, can this match be printed as a let-in ? *)
+          if Array.length pv = 1 then
+            let status,s1,s2 = pp_one_pat status env info pv.(0) in
+             status,
+            apply
+              (hv 0
+                 (pp_par par'
+                    (hv 0
+                       (hov 2 (str "let " ++ s1 ++ str " =" ++ spc () ++ expr)
+                        ++ spc () ++ str "in") ++
+                     spc () ++ hov 0 s2)))
+          else
+            let status,res =
+             try status,pp_ifthenelse par' env expr pv
+             with Not_found ->
+              let status,res = pp_pat status env info pv in
+               status,
+                v 0 (str "match " ++ expr ++ str " with" ++ fnl () ++ res)
+            in
+            (* Otherwise, standard match *)
+             status,
+            apply (pp_par par' res))
+    | MLfix (i,ids,defs) ->
+       let ids',env' = push_vars (List.rev (Array.to_list ids)) env in
+       pp_fix status par env' i (Array.of_list (List.rev ids'),defs) args
+    | MLexn s ->
+       (* An [MLexn] may be applied, but I don't really care. *)
+       status,pp_par par (str "assert false" ++ spc () ++ str ("(* "^s^" *)"))
+    | MLdummy ->
+       status,str "__" (*An [MLdummy] may be applied, but I don't really care.*)
+    | MLmagic a ->
+       let status,res = pp_expr status true env [] a in
+       status,pp_apply (str "Obj.magic") par (res :: args)
+    | MLaxiom ->
+       status,pp_par par (str "failwith \"AXIOM TO BE REALIZED\"")
+
+
+and pp_record_pat (fields, args) =
+   str "{ " ++
+   prlist_with_sep (fun () -> str ";" ++ spc ())
+     (fun (f,a) -> f ++ str " =" ++ spc () ++ a)
+     (List.combine fields args) ++
+   str " }"
+
+and pp_ifthenelse _par _env _expr pv = match pv with
+(*CSC:  | [|(tru,[],the);(fal,[],els)|] when
+      (find_custom tru = "true") && (find_custom fal = "false")
+      ->
+      hv 0 (hov 2 (str "if " ++ expr) ++ spc () ++
+            hov 2 (str "then " ++
+                  hov 2 (pp_expr status (expr_needs_par the) env [] the)) ++ spc () ++
+           hov 2 (str "else " ++
+                  hov 2 (pp_expr status (expr_needs_par els) env [] els)))*)
+  | _ -> raise Not_found
+
+and pp_one_pat status env info (r,ids,t) =
+  let ids,env' = push_vars (List.rev_map id_of_mlid ids) env in
+  let status,expr = pp_expr status (expr_needs_par t) env' [] t in
+  let status,patt = match info.m_kind with
+    | Record fields ->
+      let status,res = pp_fields status r fields in
+      status,pp_record_pat (res, List.rev_map pr_id ids)
+    | _ -> match List.rev ids with
+(*CSC: | [i1;i2] when is_infix r -> pr_id i1 ++ str (get_infix r) ++ pr_id i2*)
+       | [] -> pp_global status Cons r
+       | ids ->
+         (* hack Extract Inductive prod *)
+          let status,res = str_global status Cons r in
+         let status,res2 =
+           if res = "" then status,mt()
+           else
+            let status,res = pp_global status Cons r in
+             status, res ++ spc () in
+         status,res2 ++ pp_boxed_tuple pr_id ids
+  in
+  status, patt, expr
+
+and pp_pat status env info pv =
+  let factor_br, factor_set = try match info.m_same with
+    | BranchFun ints ->
+        let i = Intset.choose ints in
+        branch_as_fun info.m_typs pv.(i), ints
+    | BranchCst ints ->
+        let i = Intset.choose ints in
+       ast_pop (branch_as_cst pv.(i)), ints
+    | BranchNone -> MLdummy, Intset.empty
+  with _ -> MLdummy, Intset.empty
+  in
+  let last = Array.length pv - 1 in
+  let status,res =
+  prvecti_status status
+    (fun status i x -> if Intset.mem i factor_set then status,mt () else
+       let status,s1,s2 = pp_one_pat status env info x in
+       status,
+       hv 2 (hov 4 (str "| " ++ s1 ++ str " ->") ++ spc () ++ hov 2 s2) ++
+       if i = last && Intset.is_empty factor_set then mt () else fnl ())
+    pv
+  in
+  let status,res2 =
+   if Intset.is_empty factor_set then status,mt () else
+   let par = expr_needs_par factor_br in
+   match info.m_same with
+     | BranchFun _ ->
+         let ids, env' = push_vars [anonymous_name] env in
+         let status,res = pp_expr status par env' [] factor_br in
+         status,hv 2 (str "| " ++ pr_id (List.hd ids) ++ str " ->" ++ spc () ++
+                 hov 2 res)
+     | BranchCst _ ->
+         let status,res = pp_expr status par env [] factor_br in
+          status,hv 2 (str "| _ ->" ++ spc () ++ hov 2 res)
+     | BranchNone -> status,mt ()
+  in
+   status, res ++ res2
+
+and pp_function status env t =
+  let bl,t' = collect_lams t in
+  let bl,env' = push_vars (List.map id_of_mlid bl) env in
+  match t' with
+    | MLcase(i,MLrel 1,pv) when
+       i.m_kind = Standard (*CSC:&& not (is_custom_match pv)*) ->
+       if not (ast_occurs 1 (MLcase(i,MLdummy,pv))) then
+          let status,res = pp_pat status env' i pv in
+         status,pr_binding (List.rev (List.tl bl)) ++
+                 str " = function" ++ fnl () ++ v 0 res
+       else
+          let status,res = pp_pat status env' i pv in
+          status,
+          pr_binding (List.rev bl) ++
+          str " = match " ++ pr_id (List.hd bl) ++ str " with" ++ fnl () ++
+         v 0 res
+    | _ ->
+          let status,res = pp_expr status false env' [] t' in
+          status,
+          pr_binding (List.rev bl) ++
+         str " =" ++ fnl () ++ str "  " ++
+         hov 2 res
+
+(*s names of the functions ([ids]) are already pushed in [env],
+    and passed here just for convenience. *)
+
+and pp_fix status par env i (ids,bl) args =
+ let status,res =
+  prvect_with_sep_status status
+   (fun () -> fnl () ++ str "and ")
+   (fun status (fi,ti) ->
+     let status,res = pp_function status env ti in
+     status, pr_id fi ++ res)
+   (array_map2 (fun id b -> (id,b)) ids bl)
+ in
+  status,
+  pp_par par
+    (v 0 (str "let rec " ++ res ++ fnl () ++
+         hov 2 (str "in " ++ pp_apply (pr_id ids.(i)) false args)))
+
+let pp_val status e typ =
+ let status,res = pp_type status false [] typ in
+  status,
+  hov 4 (str "(** val " ++ e ++ str " :" ++ spc ()++res++ str " **)") ++ fnl2 ()
+
+(*s Pretty-printing of [Dfix] *)
+
+let pp_Dfix status (rv,c,t) =
+  let status,names = array_map_status status
+    (fun status r -> (*CSC:if is_inline_custom r then mt () else*) pp_global status Term r) rv
+  in
+  let rec pp status init i =
+    if i >= Array.length rv then
+      (if init then failwith "empty phrase" else status,mt ())
+    else
+      let void = false(*CSC:is_inline_custom rv.(i)*) ||
+       (not false(*CSC:(is_custom rv.(i))*) && c.(i) = MLexn "UNUSED")
+      in
+      if void then pp status init (i+1)
+      else
+       let status,def =
+         (*CSC:if is_custom rv.(i) then str " = " ++ str (find_custom rv.(i))
+         else*) pp_function status (empty_env status) c.(i) in
+        let status,res = pp_val status names.(i) t.(i) in
+        let status,res2 = pp status false (i+1) in
+        status,
+       (if init then mt () else fnl2 ()) ++ res ++
+       str (if init then "let rec " else "and ") ++ names.(i) ++ def ++ res2
+  in pp status true 0
+
+(*s Pretty-printing of inductive types declaration. *)
+
+let pp_comment s = str "(* " ++ s ++ str " *)"
+
+let pp_one_ind status prefix pl name cnames ctyps =
+  let pl = rename_tvars keywords pl in
+  let pp_constructor status i typs =
+   let status,res =
+    prlist_with_sep_status status
+     (fun () -> spc () ++ str "* ") (fun status -> pp_type status true pl) typs
+   in
+    status,
+    (if i=0 then mt () else fnl ()) ++
+    hov 3 (str "| " ++ cnames.(i) ++
+          (if typs = [] then mt () else str " of ") ++ res) in
+  let status,res =
+   if Array.length ctyps = 0 then status,str " unit (* empty inductive *)"
+   else
+    let status,res = prvecti_status status pp_constructor ctyps in
+     status, fnl () ++ v 0 res
+  in
+   status,
+   pp_parameters pl ++ str prefix ++ name ++
+   str " =" ++ res
+
+let pp_logical_ind packet =
+  pp_comment (pr_id packet.ip_typename ++ str " : logical inductive") ++
+  fnl () ++
+  pp_comment (str "with constructors : " ++
+             prvect_with_sep spc pr_id packet.ip_consnames) ++
+  fnl ()
+
+let pp_singleton status packet =
+  let status,name = pp_global status Type packet.ip_reference in
+  let l = rename_tvars keywords packet.ip_vars in
+  let status,res = pp_type status false l (List.hd packet.ip_types.(0)) in
+  status,
+  hov 2 (str "type " ++ pp_parameters l ++ name ++ str " =" ++ spc () ++
+        res ++ fnl () ++
+        pp_comment (str "singleton inductive, whose constructor was " ++
+                    pr_id packet.ip_consnames.(0)))
+
+let pp_record status fields packet =
+  let ind = packet.ip_reference in
+  let status,name = pp_global status Type ind in
+  let status,fieldnames = pp_fields status ind fields in
+  let l = List.combine fieldnames packet.ip_types.(0) in
+  let pl = rename_tvars keywords packet.ip_vars in
+  let status,res =
+   prlist_with_sep_status status (fun () -> str ";" ++ spc ())
+    (fun status (p,t) ->
+      let status,res = pp_type status true pl t in
+       status, p ++ str " : " ++ res) l in
+  status,
+  str "type " ++ pp_parameters pl ++ name ++ str " = { "++ hov 0 res ++ str " }"
+
+let pp_coind pl name =
+  let pl = rename_tvars keywords pl in
+  pp_parameters pl ++ name ++ str " = " ++
+  pp_parameters pl ++ str "__" ++ name ++ str " Lazy.t" ++
+  fnl() ++ str "and "
+
+let pp_ind status co ind =
+  let prefix = if co then "__" else "" in
+  let some = ref false in
+  let init= ref (str "type ") in
+  let status,names =
+    array_map_status status
+     (fun status p ->
+       if p.ip_logical then status,mt ()
+       else pp_global status Type p.ip_reference)
+      ind.ind_packets
+  in
+  let status,cnames =
+    array_map_status status
+      (fun status p -> if p.ip_logical then status,[||] else
+        array_mapi_status status
+          (fun status j _ -> pp_global status Cons p.ip_consreferences.(j))
+          p.ip_types)
+      ind.ind_packets
+  in
+  let rec pp status i =
+    if i >= Array.length ind.ind_packets then status,mt ()
+    else
+      let p = ind.ind_packets.(i) in
+      (*CSC:
+      let ip = assert false(*CSC: (mind_of_kn kn,i)*) in
+      if is_custom (IndRef ip) then pp (i+1)
+      else*) begin
+       some := true;
+       if p.ip_logical then
+         let status,res = pp status (i+1) in
+          status, pp_logical_ind p ++ res
+       else
+         let s = !init in
+          let status,res =
+           pp_one_ind
+             status prefix p.ip_vars names.(i) cnames.(i) p.ip_types in
+          let status,res2 = pp status (i+1) in
+         begin
+           init := (fnl () ++ str "and ");
+            status,
+           s ++
+           (if co then pp_coind p.ip_vars names.(i) else mt ()) ++ res ++ res2
+         end
+      end
+  in
+  let st = pp status 0 in if !some then st else failwith "empty phrase"
+
+
+(*s Pretty-printing of a declaration. *)
+
+let pp_mind status i =
+  match i.ind_kind with
+    | Singleton -> pp_singleton status i.ind_packets.(0)
+    | Coinductive -> pp_ind status true i
+    | Record fields -> pp_record status fields i.ind_packets.(0)
+    | Standard -> pp_ind status false i
+
+let pp_decl status = function
+(*CSC:    | Dtype (r,_,_) when is_inline_custom r -> failwith "empty phrase"
+    | Dterm (r,_,_) when is_inline_custom r -> failwith "empty phrase"*)
+    | Dind i -> pp_mind status i
+    | Dtype (r, l, t) ->
+        let status,name = pp_global status Type r in
+       let l = rename_tvars keywords l in
+        let ids, (status, def) =
+(*CSC:    try
+           let ids,s = find_type_custom r in
+           pp_string_parameters ids, str "=" ++ spc () ++ str s
+         with Not_found ->*)
+           pp_parameters l,
+           if t = Taxiom then status, str "(* AXIOM TO BE REALIZED *)"
+           else
+             let status,res = pp_type status false l t in
+              status, str "=" ++ spc () ++ res
+       in
+       status, hov 2 (str "type " ++ ids ++ name ++ spc () ++ def)
+    | Dterm (r, a, t) ->
+       let status,name = pp_global status Term r in
+       let status,def =
+         (*if is_custom r then str (" = " ^ find_custom r)
+         else*) if is_projection status r then
+            status,
+           (prvect str (Array.make (projection_arity status r) " _")) ++
+           str " x = x." ++ name
+         else
+           let status,res = pp_function status (empty_env status) a in
+            status, res ++ mt ()
+       in
+       let status,res = pp_val status name t in
+         status, res ++ hov 0 (str "let " ++ name ++ def)
+    | Dfix (rv,defs,typs) ->
+       pp_Dfix status (rv,defs,typs)
+
+let pp_spec status = function
+(*  | Sval (r,_) when is_inline_custom r -> failwith "empty phrase"
+  | Stype (r,_,_) when is_inline_custom r -> failwith "empty phrase"*)
+  | Sind i -> pp_mind status i
+  | Sval (r,t) ->
+      let status,def = pp_type status false [] t in
+      let status,name = pp_global status Term r in
+      status, hov 2 (str "val " ++ name ++ str " :" ++ spc () ++ def)
+  | Stype (r,vl,ot) ->
+      let status, name = pp_global status Type r in
+      let l = rename_tvars keywords vl in
+      let status, ids, def =
+(*CSC:
+       try
+         let ids, s = find_type_custom r in
+         pp_string_parameters ids,  str "= " ++ str s
+       with Not_found ->*)
+         let ids = pp_parameters l in
+         match ot with
+           | None -> status, ids, mt ()
+           | Some Taxiom -> status, ids, str "(* AXIOM TO BE REALIZED *)"
+           | Some t ->
+               let status,res = pp_type status false l t in
+                status, ids, str "=" ++ spc () ++ res
+      in
+      status, hov 2 (str "type " ++ ids ++ name ++ spc () ++ def)
+
+let pp_decl status d =
+ try pp_decl status d with Failure "empty phrase" -> status, mt ()
+;;
diff --git a/matita/components/ng_extraction/ocaml.mli b/matita/components/ng_extraction/ocaml.mli
new file mode 100644 (file)
index 0000000..c257804
--- /dev/null
@@ -0,0 +1,17 @@
+(************************************************************************)
+(*  v      *   The Coq Proof Assistant  /  The Coq Development Team     *)
+(* <O___,, *   INRIA - CNRS - LIX - LRI - PPS - Copyright 1999-2011     *)
+(*   \VV/  **************************************************************)
+(*    //   *      This file is distributed under the terms of the       *)
+(*         *       GNU Lesser General Public License Version 2.1        *)
+(************************************************************************)
+
+(*i $Id: ocaml.mli 14641 2011-11-06 11:59:10Z herbelin $ i*)
+
+open Coq
+open Miniml
+open OcamlExtractionTable
+
+val pp_decl : #status as 'status -> ml_decl -> 'status * std_ppcmds
+val pp_spec : #status as 'status -> ml_spec -> 'status * std_ppcmds
+val pp_open : #status as 'status -> string -> 'status * std_ppcmds
diff --git a/matita/components/ng_extraction/ocamlExtraction.ml b/matita/components/ng_extraction/ocamlExtraction.ml
new file mode 100644 (file)
index 0000000..1d672c4
--- /dev/null
@@ -0,0 +1,57 @@
+open OcamlExtractionTable
+open Coq
+
+let print_ocaml_of_obj0 status ((_uri,_,_,_,_) as obj) =
+ try
+  let status,res,resl = Extraction.extract status obj in
+  let status,_ =
+   map_status status
+    (fun status ml ->
+      let status,cmds = Ocaml.pp_spec status ml in
+      print_ppcmds ~in_ml:false status (cmds ++ fnl () ++ fnl ());
+      status,()) resl in
+  match res with
+     None ->
+(*    print_ppcmds status
+       (str("(* " ^ NUri.string_of_uri uri ^ " non informative *)\n")++ fnl ());*)
+      status
+   | Some ml ->
+      let status,std_ppcmds = Ocaml.pp_decl status ml in
+      print_ppcmds status ~in_ml:true (std_ppcmds ++ fnl ());
+      status
+ with
+  HExtlib.Localized (_,exn) ->
+   prerr_endline (Printexc.to_string exn); assert false
+
+let do_if_ocaml_set f status =
+ if try ignore (Helm_registry.get "extract_ocaml"); true
+    with Helm_registry.Key_not_found _ -> false
+ then f status else status
+
+let print_open status uris =
+ do_if_ocaml_set
+  (fun status ->
+    let status,uris =
+     map_status status
+      (fun status uri ->
+        let status,b = to_be_included status uri in
+         status, if b then Some uri else None
+      ) uris in
+    let uris = HExtlib.filter_map (fun x -> x) uris in
+    let fnames =
+     List.map (fun uri -> Filename.basename (NUri.string_of_uri uri)) uris in
+    let status,cmds = map_status status Ocaml.pp_open fnames in
+    List.iter (print_ppcmds status ~in_ml:true) cmds;
+    List.iter (print_ppcmds status ~in_ml:false) cmds;
+    status
+  ) status
+
+let print_ocaml_of_obj status cmds =
+ do_if_ocaml_set (fun status -> print_ocaml_of_obj0 status cmds) status
+
+let open_file status ~baseuri fname =
+ do_if_ocaml_set
+  (fun status -> OcamlExtractionTable.open_file status ~baseuri fname) status
+
+let close_file status =
+ do_if_ocaml_set OcamlExtractionTable.close_file status
diff --git a/matita/components/ng_extraction/ocamlExtraction.mli b/matita/components/ng_extraction/ocamlExtraction.mli
new file mode 100644 (file)
index 0000000..a714bd1
--- /dev/null
@@ -0,0 +1,8 @@
+open OcamlExtractionTable
+
+(* These commands have an effect iff OCAML_EXTRACTION is set *)
+
+val print_open: #status as 'status -> NUri.uri list -> 'status
+val print_ocaml_of_obj: #status as 'status -> NCic.obj -> 'status
+val open_file: #status as 'status -> baseuri:string -> string -> 'status
+val close_file: #status as 'status -> 'status
diff --git a/matita/components/ng_extraction/ocamlExtractionTable.ml b/matita/components/ng_extraction/ocamlExtractionTable.ml
new file mode 100644 (file)
index 0000000..148377e
--- /dev/null
@@ -0,0 +1,398 @@
+(************************************************************************)
+(*  v      *   The Coq Proof Assistant  /  The Coq Development Team     *)
+(* <O___,, *   INRIA - CNRS - LIX - LRI - PPS - Copyright 1999-2011     *)
+(*   \VV/  **************************************************************)
+(*    //   *      This file is distributed under the terms of the       *)
+(*         *       GNU Lesser General Public License Version 2.1        *)
+(************************************************************************)
+
+(*i $Id: table.ml 14641 2011-11-06 11:59:10Z herbelin $ i*)
+
+open Coq
+open Miniml
+
+type info_el =
+   TypeInfo of NReference.reference * ml_schema 
+ | TermInfo of NReference.reference * ml_decl
+ | InductiveInfo of NUri.uri * ml_ind
+ | GuessProjectionInfo of NUri.uri * int
+ | ConfirmProjectionInfo of NReference.reference
+ | RegisterId of string
+ | ReferenceNameInfo of NReference.reference * string
+ | RegisterModname of string
+ | ModnameInfo of string * string
+
+type info = info_el list
+
+type db =
+ ml_schema Refmap.t *
+ ml_decl Refmap.t *
+ ml_ind NUri.UriMap.t *
+ int NUri.UriMap.t *
+ int Refmap.t *
+ Idset.t *
+ string Refmap.t *
+ ((out_channel * Format.formatter) * (out_channel * Format.formatter)) option *
+ Idset.t *
+ string Stringmap.t *
+ Uriset.t *
+ string *
+ info
+
+let set_keywords,get_keywords =
+ let keywords = ref Idset.empty in
+  ((:=) keywords),(fun () -> !keywords)
+
+let preamble = "preamble.ml"
+let upreamble = "Preamble"
+let empty_info = []
+let empty_modset = Idset.add preamble Idset.empty
+let empty_db () =
+ Refmap.empty,Refmap.empty,NUri.UriMap.empty,NUri.UriMap.empty,Refmap.empty,get_keywords (),Refmap.empty,None,empty_modset,Stringmap.empty,Uriset.empty,"",empty_info
+
+let register_info (dbty,dbt,dbi,dbgp,dbp,dbids,dbrefs,ch,dbmn1,dbmn2,dbo,curi,infos) info =
+ match info with
+    TypeInfo (ref,schema) ->
+     Refmap.add ref schema dbty,dbt,dbi,dbgp,dbp,dbids,dbrefs,ch,dbmn1,dbmn2,dbo,curi,infos
+  | TermInfo (ref,schema) ->
+     dbty,Refmap.add ref schema dbt,dbi,dbgp,dbp,dbids,dbrefs,ch,dbmn1,dbmn2,dbo,curi,infos
+  | InductiveInfo (uri,ind) ->
+     dbty,dbt,NUri.UriMap.add uri ind dbi,dbgp,dbp,dbids,dbrefs,ch,dbmn1,dbmn2,dbo,curi,infos
+  | GuessProjectionInfo (uri,n) ->
+     dbty,dbt,dbi,NUri.UriMap.add uri n dbgp,dbp,dbids,dbrefs,ch,dbmn1,dbmn2,dbo,curi,infos
+  | ConfirmProjectionInfo (NReference.Ref (uri,_) as ref) ->
+     (try
+       let n = NUri.UriMap.find uri dbgp in
+       let dbgp = NUri.UriMap.remove uri dbgp in
+        dbty,dbt,dbi,dbgp,Refmap.add ref n dbp,dbids,dbrefs,ch,dbmn1,dbmn2,dbo,curi,infos
+      with Not_found -> dbty,dbt,dbi,dbgp,dbp,dbids,dbrefs,ch,dbmn1,dbmn2,dbo,curi,infos)
+  | RegisterId s ->
+     dbty,dbt,dbi,dbgp,dbp,Idset.add s dbids,dbrefs,ch,dbmn1,dbmn2,dbo,curi,infos
+  | ReferenceNameInfo (ref,name) ->
+     dbty,dbt,dbi,dbgp,dbp,dbids,Refmap.add ref name dbrefs,ch,dbmn1,dbmn2,dbo,curi,infos
+  | RegisterModname s ->
+     dbty,dbt,dbi,dbgp,dbp,dbids,dbrefs,ch,Idset.add s dbmn1,dbmn2,dbo,curi,infos
+  | ModnameInfo (s,name) ->
+     dbty,dbt,dbi,dbgp,dbp,dbids,dbrefs,ch,dbmn1,Stringmap.add s name dbmn2,dbo,curi,infos
+
+let add_info_to_db (dbty,dbt,dbi,dbgp,dbp,dbids,dbrefs,ch,dbmn1,dbmn2,dbo,curi,infos) info =
+ dbty,dbt,dbi,dbgp,dbp,dbids,dbrefs,ch,dbmn1,dbmn2,dbo,curi,info::infos
+
+let register_and_add_info ?(dummy=false) status info =
+ let db = status#ocaml_extraction_db in
+ let db = register_info db info in
+ let db = if dummy then db else add_info_to_db db info in
+  status#set_ocaml_extraction_db db
+
+let register_infos = List.fold_left register_info
+
+let refresh_uri_in_type ~refresh_uri_in_reference =
+ let rec aux =
+  function
+   | Tarr (t1,t2) -> Tarr (aux t1, aux t2)
+   | Tglob (r,tl) -> Tglob (refresh_uri_in_reference r, List.map aux tl)
+   | Tmeta { id=id; contents=contents } ->
+      let contents' =
+       match contents with
+          None -> None
+        | Some typ -> Some (aux typ)
+       in
+        Tmeta { id=id; contents=contents' }
+   | t -> t
+ in
+  aux
+
+let refresh_uri_in_kind ~refresh_uri_in_reference =
+ function
+    Singleton
+  | Coinductive
+  | Standard as k -> k
+  | Record rl -> Record (List.map refresh_uri_in_reference rl) 
+
+let refresh_uri_in_packet ~refresh_uri_in_reference
+ { ip_reference = r;
+   ip_consreferences = rs;
+   ip_typename = n;
+   ip_consnames = ns;
+   ip_logical = l;
+   ip_sign = s;
+   ip_vars = v;
+   ip_types = tys } =
+ { ip_reference = refresh_uri_in_reference r;
+   ip_consreferences = Array.map refresh_uri_in_reference rs;
+   ip_typename = n;
+   ip_consnames = ns;
+   ip_logical = l;
+   ip_sign = s;
+   ip_vars = v;
+   ip_types = Array.map (List.map (refresh_uri_in_type ~refresh_uri_in_reference)) tys }
+
+let refresh_uri_in_ind ~refresh_uri_in_reference
+ {ind_kind=k; ind_nparams=n; ind_packets=pa}
+=
+ let k = refresh_uri_in_kind ~refresh_uri_in_reference k in
+ let pa = Array.map (refresh_uri_in_packet ~refresh_uri_in_reference) pa in
+ {ind_kind=k; ind_nparams=n; ind_packets=pa}
+
+let refresh_uri_in_ast ~refresh_uri_in_reference =
+ let rec aux =
+  function
+   | MLapp (t,tl) -> MLapp (aux t, List.map aux tl)
+   | MLlam (id,t) -> MLlam (id, aux t)
+   | MLletin (id,t1,t2) -> MLletin (id, aux t1, aux t2)
+   | MLglob r -> MLglob (refresh_uri_in_reference r)
+   | MLcons ({c_kind=ckind; c_typs=ctyps}, r, tl) ->
+      let cinfo =
+       {c_kind=refresh_uri_in_kind ~refresh_uri_in_reference ckind;
+        c_typs=List.map (refresh_uri_in_type ~refresh_uri_in_reference) ctyps}
+      in
+       MLcons (cinfo, refresh_uri_in_reference r, List.map aux tl)
+   | MLcase ({m_kind=k; m_typs=typs; m_same=same},t,ba) ->
+      let info =
+       {m_kind=refresh_uri_in_kind ~refresh_uri_in_reference k;
+        m_typs=List.map (refresh_uri_in_type ~refresh_uri_in_reference) typs;
+        m_same=same} in
+      let ba =
+       Array.map
+        (fun (r,il,t) -> refresh_uri_in_reference r,il,aux t) ba in
+      MLcase (info,aux t,ba)
+   | MLfix (n,ida,ta) -> MLfix (n,ida,Array.map aux ta)
+   | MLmagic t -> MLmagic (aux t)
+   | MLrel _
+   | MLexn _
+   | MLdummy
+   | MLaxiom as t -> t
+ in
+  aux
+
+let refresh_uri_in_decl ~refresh_uri_in_reference =
+ function
+    Dind ind -> Dind (refresh_uri_in_ind ~refresh_uri_in_reference ind)
+  | Dtype (ref,il,ty) ->
+     Dtype
+      (refresh_uri_in_reference ref, il,
+       refresh_uri_in_type ~refresh_uri_in_reference ty)
+  | Dterm (ref,ast,ty) ->
+     Dterm
+      (refresh_uri_in_reference ref,
+       refresh_uri_in_ast ~refresh_uri_in_reference ast,
+       refresh_uri_in_type ~refresh_uri_in_reference ty)
+  | Dfix (refa, asta, tya) ->
+     Dfix
+      (Array.map refresh_uri_in_reference refa,
+       Array.map (refresh_uri_in_ast ~refresh_uri_in_reference) asta,
+       Array.map (refresh_uri_in_type ~refresh_uri_in_reference) tya)
+
+let refresh_uri_in_info_el ~refresh_uri_in_reference ~refresh_uri =
+ function
+    TypeInfo (ref,(n,typ)) ->
+     TypeInfo
+      (refresh_uri_in_reference ref,
+       (n,refresh_uri_in_type ~refresh_uri_in_reference typ))
+  | TermInfo (ref,decl) ->
+     TermInfo
+      (refresh_uri_in_reference ref,
+       refresh_uri_in_decl ~refresh_uri_in_reference decl)
+  | InductiveInfo (uri,ind) ->
+     InductiveInfo
+      (refresh_uri uri, refresh_uri_in_ind ~refresh_uri_in_reference ind)
+  | GuessProjectionInfo (uri,n) ->
+     GuessProjectionInfo (refresh_uri uri, n)
+  | ConfirmProjectionInfo ref ->
+     ConfirmProjectionInfo (refresh_uri_in_reference ref)
+  | RegisterId s -> RegisterId s
+  | ReferenceNameInfo (ref,name) ->
+     ReferenceNameInfo (refresh_uri_in_reference ref,name)
+  | RegisterModname s -> RegisterModname s
+  | ModnameInfo (s,name) -> ModnameInfo (s,name)
+
+let refresh_uri_in_info ~refresh_uri_in_reference ~refresh_uri infos =
+ List.map
+  (refresh_uri_in_info_el ~refresh_uri_in_reference ~refresh_uri)
+  infos
+
+class type g_status =
+ object ('self)
+  method ocaml_extraction_db: db
+  method get_info: info * 'self
+ end
+
+class virtual status =
+ object (self)
+  inherit NCic.status
+  val ocaml_extraction_db = empty_db ()
+  method ocaml_extraction_db = ocaml_extraction_db
+  method get_info =
+   let db1,db2,dbi,dbgp,dbp,dbids,dbrefs,ch,dbmn1,dbmn2,dbo,curi,infos = self#ocaml_extraction_db in
+    infos,{< ocaml_extraction_db =
+              db1,db2,dbi,dbgp,dbp,dbids,dbrefs,ch,dbmn1,dbmn2,dbo,curi,empty_info >}
+  method set_ocaml_extraction_db v = {< ocaml_extraction_db = v >}
+  method set_ocaml_extraction_status
+   : 'status. #g_status as 'status -> 'self
+   = fun o -> {< ocaml_extraction_db = o#ocaml_extraction_db >}
+ end
+
+let open_file status ~baseuri filename =
+ let db1,db2,dbi,dbgp,dbp,dbids,dbrefs,ch,dbmn1,dbmn2,dbo,_,infos = status#ocaml_extraction_db in
+ assert (ch=None);
+ let chml = open_out filename in
+ let chml = chml,Format.formatter_of_out_channel chml in
+ let chmli = open_out (filename ^ "i") in
+ let chmli = chmli,Format.formatter_of_out_channel chmli in
+ pp_with (snd chml) (str ("open " ^ upreamble ^ "\n") ++ fnl ());
+ pp_with (snd chmli) (str ("open " ^ upreamble ^ "\n") ++ fnl ());
+ let db = db1,db2,dbi,dbgp,dbp,dbids,dbrefs,Some (chml,chmli),dbmn1,dbmn2,dbo,baseuri,infos in
+ status#set_ocaml_extraction_db db
+
+let close_file status =
+ let db1,db2,dbi,dbgp,dbp,dbids,dbrefs,ch,dbmn1,dbmn2,dbo,curi,infos = status#ocaml_extraction_db in
+ match ch with
+    None -> assert false
+  | Some ch ->
+     close_out (fst (fst ch));
+     close_out (fst (snd ch));
+     let ch = None in
+     let db = db1,db2,dbi,dbgp,dbp,dbids,dbrefs,ch,dbmn1,dbmn2,dbo,curi,infos in
+     status#set_ocaml_extraction_db db
+
+let print_ppcmds status ~in_ml cmds =
+ let _,_,_,_,_,_,_,ch,_,_,_,_,_ = status#ocaml_extraction_db in
+ match ch with
+    None -> assert false
+  | Some ch ->
+     let ch = if in_ml then fst ch else snd ch in
+     pp_with (snd ch) cmds
+
+let to_be_included status uri =
+ let dbty,dbt,dbi,dbgp,dbp,dbids,dbrefs,ch,dbmn1,dbmn2,dbo,curi,infos =
+  status#ocaml_extraction_db
+ in
+  if Uriset.mem uri dbo then
+   status,false
+  else
+   let dbo = Uriset.add uri dbo in
+   let status =
+    status#set_ocaml_extraction_db
+     (dbty,dbt,dbi,dbgp,dbp,dbids,dbrefs,ch,dbmn1,dbmn2,dbo,curi,infos) in
+   status,true
+
+let add_term status ref decl =
+ let info = TermInfo (ref,decl) in
+  register_and_add_info status info
+
+let lookup_term status ref =
+ let _,dbt,_,_,_,_,_,_,_,_,_,_,_ = status#ocaml_extraction_db in
+  Refmap.find ref dbt
+
+let add_type status ref schema =
+ let info = TypeInfo (ref,schema) in
+  register_and_add_info status info
+
+let lookup_type status ref =
+ let dbty,_,_,_,_,_,_,_,_,_,_,_,_ = status#ocaml_extraction_db in
+  Refmap.find ref dbty
+
+let add_name_for_reference status ref name =
+ let info = ReferenceNameInfo (ref,name) in
+  register_and_add_info status info
+
+let name_of_reference status ref =
+ let _,_,_,_,_,_,dbrefs,_,_,_,_,_,_ = status#ocaml_extraction_db in
+  Refmap.find ref dbrefs
+
+let add_modname_for_filename status ref name =
+ let info = ModnameInfo (ref,name) in
+  register_and_add_info status info
+
+let modname_of_filename status ref =
+ let _,_,_,_,_,_,_,_,_,dbmn2,_,_,_ = status#ocaml_extraction_db in
+  Stringmap.find ref dbmn2
+
+let add_global_ids status id =
+ let info = RegisterId id in
+  register_and_add_info status info
+
+let get_global_ids status =
+ let _,_,_,_,_,dbids,_,_,_,_,_,_,_ = status#ocaml_extraction_db in
+  dbids
+
+let add_modname status id =
+ let info = RegisterModname id in
+  register_and_add_info status info
+
+let get_modnames status =
+ let _,_,_,_,_,_,_,_,dbmn1,_,_,_,_ = status#ocaml_extraction_db in
+  dbmn1
+
+let add_ind status ?dummy uri ind =
+ let info = InductiveInfo (uri,ind) in
+  register_and_add_info ?dummy status info
+
+let lookup_ind status uri =
+ let _,_,dbi,_,_,_,_,_,_,_,_,_,_ = status#ocaml_extraction_db in
+  NUri.UriMap.find uri dbi
+
+let current_baseuri status =
+ let _,_,_,_,_,_,_,_,_,_,_,suri,_ = status#ocaml_extraction_db in suri
+
+let guess_projection status ref n =
+ let info = GuessProjectionInfo (ref,n) in
+  register_and_add_info status info
+
+let confirm_projection status ref =
+ let info = ConfirmProjectionInfo ref in
+  register_and_add_info status info
+
+let is_projection status ref =
+ let _,_,_,_,dbp,_,_,_,_,_,_,_,_ = status#ocaml_extraction_db in
+  Refmap.mem ref dbp
+
+let projection_arity status ref =
+ let _,_,_,_,dbp,_,_,_,_,_,_,_,_ = status#ocaml_extraction_db in
+  Refmap.find ref dbp
+
+let type_expand () = true
+
+(*s Extraction Optimize *)
+
+type opt_flag =
+    { opt_kill_dum : bool; (* 1 *)
+      opt_fix_fun : bool;   (* 2 *)
+      opt_case_iot : bool;  (* 4 *)
+      opt_case_idr : bool;  (* 8 *)
+      opt_case_idg : bool;  (* 16 *)
+      opt_case_cst : bool;  (* 32 *)
+      opt_case_fun : bool;  (* 64 *)
+      opt_case_app : bool;  (* 128 *)
+      opt_let_app : bool;   (* 256 *)
+      opt_lin_let : bool;   (* 512 *)
+      opt_lin_beta : bool } (* 1024 *)
+
+let kth_digit n k = (n land (1 lsl k) <> 0)
+
+let flag_of_int n =
+    { opt_kill_dum = kth_digit n 0;
+      opt_fix_fun = kth_digit n 1;
+      opt_case_iot = kth_digit n 2;
+      opt_case_idr = kth_digit n 3;
+      opt_case_idg = kth_digit n 4;
+      opt_case_cst = kth_digit n 5;
+      opt_case_fun = kth_digit n 6;
+      opt_case_app = kth_digit n 7;
+      opt_let_app = kth_digit n 8;
+      opt_lin_let = kth_digit n 9;
+      opt_lin_beta = kth_digit n 10 }
+
+(* For the moment, we allow by default everything except :
+   - the type-unsafe optimization [opt_case_idg], which anyway
+     cannot be activated currently (cf [Mlutil.branch_as_fun])
+   - the linear let and beta reduction [opt_lin_let] and [opt_lin_beta]
+     (may lead to complexity blow-up, subsumed by finer reductions
+      when inlining recursors).
+*)
+
+let int_flag_init = 1 + 2 + 4 + 8 (*+ 16*) + 32 + 64 + 128 + 256 (*+ 512 + 1024*)
+
+let opt_flag_ref = ref (flag_of_int int_flag_init)
+
+let optims () = !opt_flag_ref
diff --git a/matita/components/ng_extraction/ocamlExtractionTable.mli b/matita/components/ng_extraction/ocamlExtractionTable.mli
new file mode 100644 (file)
index 0000000..6fdf440
--- /dev/null
@@ -0,0 +1,93 @@
+(************************************************************************)
+(*  v      *   The Coq Proof Assistant  /  The Coq Development Team     *)
+(* <O___,, *   INRIA - CNRS - LIX - LRI - PPS - Copyright 1999-2011     *)
+(*   \VV/  **************************************************************)
+(*    //   *      This file is distributed under the terms of the       *)
+(*         *       GNU Lesser General Public License Version 2.1        *)
+(************************************************************************)
+
+(*i $Id: table.mli 14641 2011-11-06 11:59:10Z herbelin $ i*)
+
+open Coq
+open Miniml
+
+type info
+type db
+
+class type g_status =
+ object ('self)
+  method ocaml_extraction_db: db
+  method get_info: info * 'self
+ end
+
+class virtual status :
+ object ('self)
+  inherit g_status
+  inherit NCic.status
+  method set_ocaml_extraction_db: db -> 'self
+  method set_ocaml_extraction_status: #g_status -> 'self
+ end
+
+val refresh_uri_in_info:
+ refresh_uri_in_reference:(NReference.reference -> NReference.reference) ->
+ refresh_uri:(NUri.uri -> NUri.uri) ->
+  info -> info
+
+val set_keywords : Idset.t -> unit
+
+val register_infos: db -> info -> db
+
+val to_be_included : #status as 'status -> NUri.uri -> 'status * bool
+
+val open_file: #status as 'status -> baseuri:string -> string -> 'status
+val print_ppcmds : #status -> in_ml:bool -> std_ppcmds -> unit
+val close_file: #status as 'status -> 'status
+
+val current_baseuri: #status -> string
+
+val add_term : #status as 'status -> NReference.reference -> ml_decl -> 'status
+val lookup_term : #status -> NReference.reference -> ml_decl
+
+val add_type: #status as 'status -> NReference.reference -> ml_schema -> 'status
+val lookup_type : #status -> NReference.reference -> ml_schema
+
+val add_ind : #status as 'status -> ?dummy:bool -> NUri.uri -> ml_ind -> 'status
+val lookup_ind : #status -> NUri.uri -> ml_ind
+
+val add_global_ids: #status as 'status -> string -> 'status
+val get_global_ids : #status -> Idset.t
+
+val add_name_for_reference:
+ #status as 'status -> NReference.reference -> string -> 'status
+val name_of_reference : #status -> NReference.reference -> string
+
+val add_modname: #status as 'status -> string -> 'status
+val get_modnames : #status -> Idset.t
+
+val add_modname_for_filename:
+ #status as 'status -> string -> string -> 'status
+val modname_of_filename : #status -> string -> string
+
+val guess_projection:
+ #status as 'status -> NUri.uri -> int -> 'status
+val confirm_projection:
+ #status as 'status -> NReference.reference -> 'status
+val is_projection : #status -> NReference.reference -> bool
+val projection_arity : #status -> NReference.reference -> int
+
+val type_expand : unit -> bool
+
+type opt_flag =
+    { opt_kill_dum : bool; (* 1 *)
+      opt_fix_fun : bool;   (* 2 *)
+      opt_case_iot : bool;  (* 4 *)
+      opt_case_idr : bool;  (* 8 *)
+      opt_case_idg : bool;  (* 16 *)
+      opt_case_cst : bool;  (* 32 *)
+      opt_case_fun : bool;  (* 64 *)
+      opt_case_app : bool;  (* 128 *)
+      opt_let_app : bool;   (* 256 *)
+      opt_lin_let : bool;   (* 512 *)
+      opt_lin_beta : bool } (* 1024 *)
+
+val optims :  unit -> opt_flag