]> matita.cs.unibo.it Git - helm.git/blobdiff - helm/ocaml/cic_disambiguation/disambiguate.ml
first moogle template checkin
[helm.git] / helm / ocaml / cic_disambiguation / disambiguate.ml
index 827bbe2d4ea96af5ae8971588dee05d15d9035b9..f7cfce144d7b6daacbceaafdc16ef71cdbc4286d 100644 (file)
  * http://helm.cs.unibo.it/
  *)
 
-open Disambiguate_struct
-open Disambiguate_types
+open Printf
 
-let debug = true
-let debug_print = if debug then prerr_endline else ignore
+open DisambiguateTypes
+open UriManager
+
+exception No_choices of domain_item
+exception NoWellTypedInterpretation
 
-type interpretation_domain = Domain.t
-type domain_and_interpretation = interpretation_domain * interpretation
+  (** raised when an environment is not enough informative to decide *)
+exception Try_again
 
-let string_of_interpretation_domain_item = function
-  | Id s -> "ID " ^ s
-  | Symbol (s, i) -> "SYMBOL " ^ s ^ " " ^ string_of_int i
-  | Num (s, i) -> "NUM " ^ s ^ " " ^ string_of_int i
+let debug = true
+let debug_print = if debug then prerr_endline else ignore
 
 let descr_of_domain_item = function
  | Id s -> s
  | Symbol (s, _) -> s
- | Num (s, _) -> s
-
-let rec build_natural =
-  function
-  | 0 -> HelmLibraryObjects.Datatypes.zero
-  | n -> Cic.Appl [ HelmLibraryObjects.Datatypes.succ; (build_natural (n - 1)) ]
-
-exception Invalid_choice
-
-let symbol_choices: (string, interpretation_codomain_item list) Hashtbl.t = Hashtbl.create 1023
-let _ =
-  Hashtbl.add symbol_choices "eq"
-    [ ("Leibnitz's equality",
-     (fun interp args ->
-       let t1, t2 =
-         match args with
-         | [t1; t2] -> t1, t2
-         | _ -> raise Invalid_choice
-       in
-       Cic.Appl [
-         Cic.MutInd (HelmLibraryObjects.Logic.eq_URI, 0, []);
-           Cic.Implicit; t1; t2
-       ])) ]
-(*
-let add_symbol_choice = Hashtbl.add symbol_choices
-let add_symbol_choices symbol = List.iter (add_symbol_choice symbol)
-*)
-let num_choices =
-  ref [
-    "natural number",
-    (fun num ->
-      let num = int_of_string num in
-      assert (num >= 0);
-      build_natural num)
-  ]
-
-let add_num_choice choice =
-  num_choices := choice :: !num_choices
+ | Num i -> string_of_int i
 
 type test_result =
   | Ok of Cic.term * Cic.metasenv
@@ -86,286 +49,123 @@ type test_result =
 
 let refine metasenv context term =
   let metasenv, term = CicMkImplicit.expand_implicits metasenv context term in
+  debug_print (sprintf "TEST_INTERPRETATION: %s" (CicPp.ppterm term));
   try
-    let term', _, _, metasenv' = CicRefine.type_of_aux' metasenv context term in
+    let term', _, metasenv' = CicRefine.type_of_aux' metasenv context term in
     Ok (term', metasenv')
   with
-    | CicRefine.MutCaseFixAndCofixRefineNotImplemented ->
-        (* TODO remove this case as soon as refine is fully implemented *)
-        (try
-          let term' = CicTypeChecker.type_of_aux' metasenv context term in
-          Ok (term',metasenv)
-        with _ -> Ko)
     | CicRefine.Uncertain _ ->
         debug_print ("%%% UNCERTAIN!!! " ^ CicPp.ppterm term) ;
         Uncertain
-    | _ ->
+    | CicRefine.RefineFailure _ ->
         debug_print ("%%% PRUNED!!! " ^ CicPp.ppterm term) ;
         Ko
 
-open Printf
-
-open UriManager
-
-let indtyuri_of_uri uri =
-  let index_sharp =  String.index uri '#' in
-  let index_num = index_sharp + 3 in
-  (UriManager.uri_of_string (String.sub uri 0 index_sharp),
-   int_of_string(String.sub uri index_num (String.length uri - index_num)) - 1)
-
-let indconuri_of_uri uri =
-  let index_sharp =  String.index uri '#' in
-  let index_div = String.rindex uri '/' in
-  let index_con = index_div + 1 in
-    (UriManager.uri_of_string (String.sub uri 0 index_sharp),
-    int_of_string
-      (String.sub uri (index_sharp + 3) (index_div - index_sharp - 3)) - 1,
-    int_of_string
-      (String.sub uri index_con (String.length uri - index_con)))
-
-  (* TODO move it to Cic *)
-let term_of_uri uri =
+let resolve (env: environment) (item: domain_item) ?(num = "") ?(args = []) () =
   try
-  (* Constant *)
-  (* TODO explicit substitutions? *)
-  let len = String.length uri in
-  if String.sub uri (len - 4) 4 = ".con" then
-    Cic.Const (uri_of_string uri, [])
-  else if String.sub uri (len - 4) 4 = ".var" then
-    Cic.Var (uri_of_string uri, [])
-  else
-    (try
-      (* Inductive Type *)
-      let uri',typeno = indtyuri_of_uri uri in
-      Cic.MutInd (uri', typeno, [])
-     with
-      | UriManager.IllFormedUri _ | Failure _ | Invalid_argument _ ->
-          (* Constructor of an Inductive Type *)
-          let uri',typeno,consno = indconuri_of_uri uri in
-          Cic.MutConstruct (uri', typeno, consno, []))
- with
- | Invalid_argument _ -> raise (UriManager.IllFormedUri uri)
-
-module Make (C: Callbacks) =
-  struct
-    exception NoWellTypedInterpretation
-
-    let choices_of_id mqi_handle id =
-     let query  =  MQueryGenerator.locate id in
-     let result = MQueryInterpreter.execute mqi_handle query in
-     let uris =
-      List.map
-       (function uri,_ ->
-         MQueryMisc.wrong_xpointer_format_from_wrong_xpointer_format' uri
-       ) result in
-      C.output_html (`Msg (`T "Locate query:"));
-      MQueryUtil.text_of_query
-       (fun s -> C.output_html ~append_NL:false (`Msg (`T s)))
-       "" query; 
-      C.output_html (`Msg (`T "Result:"));
-      MQueryUtil.text_of_result
-        (fun s -> C.output_html (`Msg (`T s))) "" result;
-      let uris' =
-       match uris with
-        | [] ->
-           [UriManager.string_of_uri (C.input_or_locate_uri
-            ~title:("URI matching \"" ^ id ^ "\" unknown."))]
-        | [uri] -> [uri]
-        | _ ->
-            C.interactive_user_uri_choice ~selection_mode:`MULTIPLE
-             ~ok:"Try every selection." ~enable_button_for_non_vars:true
-             ~title:"Ambiguous input." ~id
-             ~msg: ("Ambiguous input \"" ^ id ^
-                "\". Please, choose one or more interpretations:")
-             uris
-      in
-      List.map (fun uri -> (uri, term_of_uri uri)) uris'
-
-    let disambiguate_input
-      mqi_handle context metasenv parser_dom parser_mk_term
-      (current_dom, current_interpretation)
-    =
-      debug_print "NEW DISAMBIGUATE INPUT";
-      let todo_dom = Domain.diff parser_dom current_dom in
-      (* (1) for each item in todo_dom we get the associated list of choices *)
-      let id_choices = Hashtbl.create 1023 in
-      let _ =
-        Domain.iter
-          (function
-            | Id id ->
-                  (* pairs <description, term> *)
-                let choices = choices_of_id mqi_handle id in
-                debug_print (sprintf
-                  "CHOICES_OF_ID di %s ha restituito %d scelte"
-                  id (List.length choices));
-                Hashtbl.add id_choices id choices
-            | _ -> assert false)
-          (Domain.filter (function Id _ -> true | _ -> false) todo_dom)
-      in
-      (* (2) lookup function for any item (Id/Symbol/Num) *)
-      let lookup_choices item =
-        try
-          (match item with
-          | Id id ->
-              let choices = Hashtbl.find id_choices id in
-              List.map (fun (descr, term) -> (descr, fun _ _ -> term)) choices
-          | Symbol (symb, _) -> Hashtbl.find symbol_choices symb
-          | Num (num, _) ->
-              List.map
-                (fun (descr, f) -> (descr, let term = f num in fun _ _ -> term))
-                !num_choices)
-        with Not_found -> assert false
-      in
-      (* (3) test an interpretation filling with meta uninterpreted identifiers
-       *)
-      let test_interpretation current_interpretation todo_dom =
-        let filled_interpretation =
-          Domain.fold
-            (fun item' interpretation ->
-              fun item ->
-                if item = item' then
-                  "Implicit", fun _ _ -> Cic.Implicit
-                else
-                  interpretation item)
-            todo_dom current_interpretation
-        in
-        let term' = parser_mk_term filled_interpretation in
-        refine metasenv context term'
-      in
-      (* (4) build all possible interpretations *)
-      let rec aux current_interpretation todo_dom =
-        if Domain.is_empty todo_dom then
-          match test_interpretation current_interpretation Domain.empty with
-          | Ok (term, metasenv) -> [ current_interpretation, term, metasenv ]
-          | Ko | Uncertain -> []
-        else
-          let item = Domain.choose todo_dom in
-          debug_print (sprintf "CHOOSED ITEM: %s"
-            (string_of_interpretation_domain_item item));
-          let remaining_dom = Domain.remove item todo_dom in
-          let choices = lookup_choices item in
-          let rec filter = function
-            | [] -> []
-            | codomain_item :: tl ->
-                let new_interpretation =
-                  fun item' ->
-                    if item' = item then
-                      codomain_item
-                    else
-                      current_interpretation item'
-                in
-                (match test_interpretation new_interpretation remaining_dom with
-                | Ok (term, metasenv) ->
-                    (if Domain.is_empty remaining_dom then
-                      [ new_interpretation, term, metasenv ]
-                    else
-                      aux new_interpretation remaining_dom)
-                    @ filter tl
-                | Uncertain ->
-                    (if Domain.is_empty remaining_dom then
-                      []
-                    else
-                      aux new_interpretation remaining_dom)
-                    @ filter tl
-                | Ko -> filter tl)
-          in
-          filter choices
-      in
-      let (choosed_interpretation, choosed_term, choosed_metasenv) =
-        match aux current_interpretation todo_dom with
-        | [] -> raise NoWellTypedInterpretation
-        | [ x ] ->
-            debug_print "UNA SOLA SCELTA";
-            x
-        | l ->
-            debug_print "PIU' SCELTE";
-            let choices =
-              List.map
-                (fun (interpretation, _, _) ->
-                  List.map
-                    (fun domain_item ->
-                      let description = fst (interpretation domain_item) in
-(*
-                        match interpretation domain_item with
-                        | None -> assert false
-                        | Some (descr, _) -> descr
-                      in
-*)
-                      (descr_of_domain_item domain_item, description))
-                    (Domain.elements parser_dom))
-                l
-            in
-            let choosed = C.interactive_interpretation_choice choices in
-            List.nth l choosed
-      in
-      (Domain.union current_dom todo_dom, choosed_interpretation),
-       choosed_metasenv, choosed_term
+    snd (Environment.find item env) env num args
+  with Not_found -> assert false
 
-  end
-
-let apply_interp (interp: interpretation) item = snd (interp item)
+  (* TODO move it to Cic *)
+let find_in_environment name context =
+  let rec aux acc = function
+    | [] -> raise Not_found
+    | Cic.Name hd :: tl when hd = name -> acc
+    | _ :: tl ->  aux (acc + 1) tl
+  in
+  aux 1 context
 
-let interpretate ~context ~interp ast =
+let interpretate ~context ~env ast =
   let rec aux loc context = function
-    | Ast.LocatedTerm (loc, term) -> aux loc context term
-    | Ast.Appl terms -> Cic.Appl (List.map (aux loc context) terms)
-    | Ast.Appl_symbol (symb, args) ->
+    | CicAst.AttributedTerm (`Loc loc, term) ->
+        aux loc context term
+    | CicAst.AttributedTerm (_, term) -> aux loc context term
+    | CicAst.Appl (CicAst.Symbol (symb, i) :: args) ->
         let cic_args = List.map (aux loc context) args in
-        apply_interp interp (Symbol (symb, 0)) interp cic_args
-    | Ast.Binder (binder_kind, var, typ, body) ->
+        resolve env (Symbol (symb, i)) ~args:cic_args ()
+    | CicAst.Appl terms -> Cic.Appl (List.map (aux loc context) terms)
+    | CicAst.Binder (binder_kind, (var, typ), body) ->
         let cic_type = aux_option loc context typ in
-        let cic_body = aux loc (Some var :: context) body in
+        let cic_body = aux loc (var :: context) body in
         (match binder_kind with
         | `Lambda -> Cic.Lambda (var, cic_type, cic_body)
         | `Pi | `Forall -> Cic.Prod (var, cic_type, cic_body)
         | `Exists ->
-            apply_interp interp (Symbol ("exists", 0)) interp
-              [ cic_type; Cic.Lambda (var, cic_type, cic_body) ])
-    | Ast.Case (term, indty_ident, outtype, branches) ->
+            resolve env (Symbol ("exists", 0))
+              ~args:[ cic_type; Cic.Lambda (var, cic_type, cic_body) ] ())
+    | CicAst.Case (term, indty_ident, outtype, branches) ->
         let cic_term = aux loc context term in
         let cic_outtype = aux_option loc context outtype in
-        let do_branch (pat, term) =
+        let do_branch ((head, args), term) =
           let rec do_branch' context = function
             | [] -> aux loc context term
-            | hd :: tl ->
-                let cic_body = do_branch' (Some (Cic.Name hd) :: context) tl in
-                Cic.Lambda (Cic.Name hd, Cic.Implicit, cic_body)
+            | (name, typ) :: tl ->
+                let cic_body = do_branch' (name :: context) tl in
+                let typ =
+                  match typ with
+                  | None -> Cic.Implicit (Some `Type)
+                  | Some typ -> aux loc context typ
+                in
+                Cic.Lambda (name, typ, cic_body)
           in
-          match pat with
-          | _ :: tl -> (* ignoring constructor *) do_branch' context tl
-          | [] -> assert false
+          do_branch' context args
         in
         let (indtype_uri, indtype_no) =
-          match apply_interp interp (Id indty_ident) interp [] with
-          | Cic.MutInd (uri, tyno, _) -> uri, tyno
-          | _ -> Parser.fail loc ("Not an inductive type: " ^ indty_ident)
+          match indty_ident with
+          | Some indty_ident ->
+              (match resolve env (Id indty_ident) () with
+              | Cic.MutInd (uri, tyno, _) -> (uri, tyno)
+              | Cic.Implicit _ -> raise Try_again
+              | _ -> raise DisambiguateChoices.Invalid_choice)
+          | None ->
+              let fst_constructor =
+                match branches with
+                | ((head, _), _) :: _ -> head
+                | [] -> raise DisambiguateChoices.Invalid_choice
+              in
+              (match resolve env (Id fst_constructor) () with
+              | Cic.MutConstruct (indtype_uri, indtype_no, _, _) ->
+                  (indtype_uri, indtype_no)
+              | Cic.Implicit _ -> raise Try_again
+              | _ -> raise DisambiguateChoices.Invalid_choice)
         in
         Cic.MutCase (indtype_uri, indtype_no, cic_outtype, cic_term,
           (List.map do_branch branches))
-    | Ast.LetIn (var, def, body) ->
+    | CicAst.LetIn ((name, typ), def, body) ->
         let cic_def = aux loc context def in
-        let name = Cic.Name var in
-        let cic_body = aux loc (Some name :: context) body in
+        let cic_def =
+          match typ with
+          | None -> cic_def
+          | Some t -> Cic.Cast (cic_def, aux loc context t)
+        in
+        let cic_body = aux loc (name :: context) body in
         Cic.LetIn (name, cic_def, cic_body)
-    | Ast.LetRec (kind, defs, body) ->
+    | CicAst.LetRec (kind, defs, body) ->
         let context' =
-          List.fold_left (fun acc (var, _, _, _) -> Some (Cic.Name var) :: acc)
+          List.fold_left (fun acc ((name, _), _, _) -> name :: acc)
             context defs
         in
         let cic_body = aux loc context' body in
         let inductiveFuns =
           List.map
-            (fun (var, body, typ, decr_idx) ->
+            (fun ((name, typ), body, decr_idx) ->
               let cic_body = aux loc context' body in
               let cic_type = aux_option loc context typ in
-              (var, decr_idx, cic_type, cic_body))
+              let name =
+                match name with
+                | Cic.Anonymous ->
+                    CicTextualParser2.fail loc
+                      "Recursive functions cannot be anonymous"
+                | Cic.Name name -> name
+              in
+              (name, decr_idx, cic_type, cic_body))
             defs
         in
-        let counter = ref 0 in
+        let counter = ref ~-1 in
         let build_term funs =
           (* this is the body of the fold_right function below. Rationale: Fix
            * and CoFix cases differs only in an additional index in the
-           * indcutiveFun list, see Cic.term *)
+           * inductiveFun list, see Cic.term *)
           match kind with
           | `Inductive ->
               (fun (var, _, _, _) cic ->
@@ -376,39 +176,366 @@ let interpretate ~context ~interp ast =
                 List.map (fun (name, _, typ, body) -> (name, typ, body)) funs
               in
               (fun (var, _, _, _) cic ->
+                incr counter;
                 Cic.LetIn (Cic.Name var, Cic.CoFix (!counter, funs), cic))
         in
         List.fold_right (build_term inductiveFuns) inductiveFuns cic_body
-    | Ast.Ident (name, subst) ->
-        let rec find acc e = function
-          | [] -> raise Not_found
-          | Some (Cic.Name hd) :: tl when e = hd -> acc
-          | _ :: tl ->  find (acc + 1) e tl
-        in
+    | CicAst.Ident (name, subst) ->
         (try
-          let index = find 1 name context in
-          if subst <> [] then
-            Parser.fail loc "Explicit substitutions not allowed here";
+          let index = find_in_environment name context in
+          if subst <> None then
+            CicTextualParser2.fail loc
+              "Explicit substitutions not allowed here";
           Cic.Rel index
         with Not_found ->
-          apply_interp interp (Id name) interp [])
-    | Ast.Num num -> apply_interp interp (Num (num, 0)) interp []
-    | Ast.Meta (index, subst) ->
+          let cic = resolve env (Id name) () in
+          let mk_subst uris =
+            let ids_to_uris =
+              List.map (fun uri -> UriManager.name_of_uri uri, uri) uris
+            in
+            (match subst with
+            | Some subst ->
+                List.map
+                  (fun (s, term) ->
+                    (try
+                      List.assoc s ids_to_uris, aux loc context term
+                     with Not_found ->
+                       raise DisambiguateChoices.Invalid_choice))
+                  subst
+            | None -> List.map (fun uri -> uri, Cic.Implicit None) uris)
+         in
+          (match cic with
+          | Cic.Const (uri, []) ->
+              let uris =
+                match CicEnvironment.get_obj uri with
+                | Cic.Constant (_, _, _, uris) -> uris
+                | _ -> assert false
+              in
+              Cic.Const (uri, mk_subst uris)
+          | Cic.Var (uri, []) ->
+              let uris =
+                match CicEnvironment.get_obj uri with
+                | Cic.Variable (_, _, _, uris) -> uris
+                | _ -> assert false
+              in
+              Cic.Var (uri, mk_subst uris)
+          | Cic.MutInd (uri, i, []) ->
+              let uris =
+                match CicEnvironment.get_obj uri with
+                | Cic.InductiveDefinition (_, uris, _) -> uris
+                | _ -> assert false
+              in
+              Cic.MutInd (uri, i, mk_subst uris)
+          | Cic.MutConstruct (uri, i, j, []) ->
+              let uris =
+                match CicEnvironment.get_obj uri with
+                | Cic.InductiveDefinition (_, uris, _) -> uris
+                | _ -> assert false
+              in
+              Cic.MutConstruct (uri, i, j, mk_subst uris)
+          | Cic.Meta _ | Cic.Implicit _ as t ->
+(*
+              prerr_endline (sprintf
+                "Warning: %s must be instantiated with _[%s] but we do not enforce it"
+                (CicPp.ppterm t)
+                (String.concat "; "
+                  (List.map
+                    (fun (s, term) -> s ^ " := " ^ CicAstPp.pp_term term)
+                    subst)));
+*)
+              t
+          | _ ->
+              raise DisambiguateChoices.Invalid_choice))
+    | CicAst.Implicit -> Cic.Implicit None
+    | CicAst.Num (num, i) -> resolve env (Num i) ~num ()
+    | CicAst.Meta (index, subst) ->
         let cic_subst =
           List.map
             (function None -> None | Some term -> Some (aux loc context term))
             subst
         in
         Cic.Meta (index, cic_subst)
-    | Ast.Sort `Prop -> Cic.Sort Cic.Prop
-    | Ast.Sort `Set -> Cic.Sort Cic.Set
-    | Ast.Sort `Type -> Cic.Sort Cic.Type
-    | Ast.Sort `CProp -> Cic.Sort Cic.CProp
+    | CicAst.Sort `Prop -> Cic.Sort Cic.Prop
+    | CicAst.Sort `Set -> Cic.Sort Cic.Set
+    | CicAst.Sort `Type -> Cic.Sort (Cic.Type (CicUniv.fresh())) (* TASSI *)
+    | CicAst.Sort `CProp -> Cic.Sort Cic.CProp
+    | CicAst.Symbol (symbol, instance) ->
+        resolve env (Symbol (symbol, instance)) ()
   and aux_option loc context = function
-    | None -> Cic.Implicit
+    | None -> Cic.Implicit (Some `Type)
     | Some term -> aux loc context term
   in
   match ast with
-  | Ast.LocatedTerm (loc, term) -> aux loc context term
-  | _ -> assert false
+  | CicAst.AttributedTerm (`Loc loc, term) -> aux loc context term
+  | term -> aux (-1, -1) context term
+
+let domain_of_term ~context ast =
+    (* "aux" keeps domain in reverse order and doesn't care about duplicates.
+     * Domain item more in deep in the list will be processed first.
+     *)
+  let rec aux loc context = function
+    | CicAst.AttributedTerm (`Loc loc, term) -> aux loc context term
+    | CicAst.AttributedTerm (_, term) -> aux loc context term
+    | CicAst.Appl terms ->
+        List.fold_left (fun dom term -> aux loc context term @ dom) [] terms
+    | CicAst.Binder (kind, (var, typ), body) ->
+        let kind_dom =
+          match kind with
+          | `Exists -> [ Symbol ("exists", 0) ]
+          | _ -> []
+        in
+        let type_dom = aux_option loc context typ in
+        let body_dom = aux loc (var :: context) body in
+        body_dom @ type_dom @ kind_dom
+    | CicAst.Case (term, indty_ident, outtype, branches) ->
+        let term_dom = aux loc context term in
+        let outtype_dom = aux_option loc context outtype in
+        let do_branch ((head, args), term) =
+          let (term_context, args_domain) =
+            List.fold_left
+              (fun (cont, dom) (name, typ) ->
+                (name :: cont,
+                 (match typ with
+                 | None -> dom
+                 | Some typ -> aux loc cont typ @ dom)))
+              (context, []) args
+          in
+          args_domain @ aux loc term_context term
+        in
+        let branches_dom =
+          List.fold_left (fun dom branch -> do_branch branch @ dom) [] branches
+        in
+        branches_dom @ outtype_dom @ term_dom @
+        (match indty_ident with None -> [] | Some ident -> [ Id ident ])
+    | CicAst.LetIn ((var, typ), body, where) ->
+        let body_dom = aux loc context body in
+        let type_dom = aux_option loc context typ in
+        let where_dom = aux loc (var :: context) where in
+        where_dom @ type_dom @ body_dom
+    | CicAst.LetRec (kind, defs, where) ->
+        let context' =
+          List.fold_left (fun acc ((var, typ), _, _) -> var :: acc)
+            context defs
+        in
+        let where_dom = aux loc context' where in
+        let defs_dom =
+          List.fold_left
+            (fun dom ((_, typ), body, _) ->
+              aux loc context' body @ aux_option loc context typ)
+            [] defs
+        in
+        where_dom @ defs_dom
+    | CicAst.Ident (name, subst) ->
+        (try
+          let index = find_in_environment name context in
+          if subst <> None then
+            CicTextualParser2.fail loc
+              "Explicit substitutions not allowed here"
+          else
+            []
+        with Not_found ->
+          (match subst with
+          | None -> [Id name]
+          | Some subst ->
+              List.fold_left
+                (fun dom (_, term) ->
+                  let dom' = aux loc context term in
+                  dom' @ dom)
+                [Id name] subst))
+    | CicAst.Implicit -> []
+    | CicAst.Num (num, i) -> [ Num i ]
+    | CicAst.Meta (index, local_context) ->
+        List.fold_left (fun dom term -> aux_option loc context term @ dom) []
+          local_context
+    | CicAst.Sort _ -> []
+    | CicAst.Symbol (symbol, instance) -> [ Symbol (symbol, instance) ]
+
+  and aux_option loc context = function
+    | None -> []
+    | Some t -> aux loc context t
+  in
+
+    (* e.g. [5;1;1;1;2;3;4;1;2] -> [2;1;4;3;5] *)
+  let rev_uniq =
+    let module SortedItem =
+      struct
+        type t = DisambiguateTypes.domain_item
+        let compare = Pervasives.compare
+      end
+    in
+    let module Set = Set.Make (SortedItem) in
+    fun l ->
+      let rev_l = List.rev l in
+      let (_, uniq_rev_l) =
+        List.fold_left
+          (fun (members, rev_l) elt ->
+            if Set.mem elt members then
+              (members, rev_l)
+            else
+              Set.add elt members, elt :: rev_l)
+          (Set.empty, []) rev_l
+      in
+      List.rev uniq_rev_l
+  in
+            
+  rev_uniq
+    (match ast with
+    | CicAst.AttributedTerm (`Loc loc, term) -> aux loc context term
+    | term -> aux (-1, -1) context term)
+
+
+  (* dom1 \ dom2 *)
+let domain_diff dom1 dom2 =
+(* let domain_diff = Domain.diff *)
+  let is_in_dom2 =
+    List.fold_left (fun pred elt -> (fun elt' -> elt' = elt || pred elt'))
+      (fun _ -> false) dom2
+  in
+  List.filter (fun elt -> not (is_in_dom2 elt)) dom1
+
+module Make (C: Callbacks) =
+  struct
+    let choices_of_id mqi_handle id =
+     let query  =  MQueryGenerator.locate id in
+     let result = MQueryInterpreter.execute mqi_handle query in
+     let uris =
+      List.map
+       (function uri,_ ->
+         MQueryMisc.wrong_xpointer_format_from_wrong_xpointer_format' uri
+       ) result in
+      let uris' =
+       match uris with
+        | [] ->
+           [UriManager.string_of_uri (C.input_or_locate_uri
+            ~title:("URI matching \"" ^ id ^ "\" unknown.") ~id ())]
+        | [uri] -> [uri]
+        | _ ->
+            C.interactive_user_uri_choice ~selection_mode:`MULTIPLE
+             ~ok:"Try selected." ~enable_button_for_non_vars:true
+             ~title:"Ambiguous input." ~id
+             ~msg: ("Ambiguous input \"" ^ id ^
+                "\". Please, choose one or more interpretations:")
+             uris
+      in
+      List.map
+        (fun uri ->
+          (uri,
+           let term =
+             try
+               HelmLibraryObjects.term_of_uri (UriManager.uri_of_string uri)
+             with _ -> assert false
+            in
+           fun _ _ _ -> term))
+        uris'
+
+    let disambiguate_term mqi_handle context metasenv term ~aliases:current_env
+    =
+      debug_print "NEW DISAMBIGUATE INPUT";
+      let disambiguate_context =  (* cic context -> disambiguate context *)
+        List.map
+          (function None -> Cic.Anonymous | Some (name, _) -> name)
+          context
+      in
+      let term_dom = domain_of_term ~context:disambiguate_context term in
+      debug_print (sprintf "DISAMBIGUATION DOMAIN: %s"
+        (string_of_domain term_dom));
+      let current_dom =
+        Environment.fold (fun item _ dom -> item :: dom) current_env []
+      in
+      let todo_dom = domain_diff term_dom current_dom in
+      (* (2) lookup function for any item (Id/Symbol/Num) *)
+      let lookup_choices =
+        let id_choices = Hashtbl.create 1023 in
+        fun item ->
+        let choices =
+          match item with
+          | Id id ->
+              (try
+                Hashtbl.find id_choices id
+              with Not_found ->
+                let choices = choices_of_id mqi_handle id in
+                Hashtbl.add id_choices id choices;
+                choices)
+          | Symbol (symb, _) -> DisambiguateChoices.lookup_symbol_choices symb
+          | Num instance -> DisambiguateChoices.lookup_num_choices ()
+        in
+        if choices = [] then raise (No_choices item);
+        choices
+      in
+      (* (3) test an interpretation filling with meta uninterpreted identifiers
+       *)
+      let test_env current_env todo_dom =
+        let filled_env =
+          List.fold_left
+            (fun env item ->
+              Environment.add item
+                ("Implicit",
+                 (match item with
+                 | Id _ | Num _ -> (fun _ _ _ -> Cic.Implicit (Some `Closed))
+                 | Symbol _ -> (fun _ _ _ -> Cic.Implicit None))) env)
+            current_env todo_dom 
+        in
+        try
+          let cic_term =
+            interpretate ~context:disambiguate_context ~env:filled_env term
+          in
+          refine metasenv context cic_term
+        with
+        | Try_again -> Uncertain
+        | DisambiguateChoices.Invalid_choice -> Ko
+      in
+      (* (4) build all possible interpretations *)
+      let rec aux current_env todo_dom =
+        match todo_dom with
+        | [] ->
+            (match test_env current_env [] with
+            | Ok (term, metasenv) -> [ current_env, metasenv, term ]
+            | Ko | Uncertain -> [])
+        | item :: remaining_dom ->
+            debug_print (sprintf "CHOOSED ITEM: %s"
+              (string_of_domain_item item));
+            let choices = lookup_choices item in
+            let rec filter = function
+              | [] -> []
+              | codomain_item :: tl ->
+                  debug_print (sprintf "%s CHOSEN" (fst codomain_item)) ;
+                  let new_env =
+                    Environment.add item codomain_item current_env
+                  in
+                  (match test_env new_env remaining_dom with
+                  | Ok (term, metasenv) ->
+                      (match remaining_dom with
+                      | [] -> [ new_env, metasenv, term ]
+                      | _ -> aux new_env remaining_dom) @ filter tl
+                  | Uncertain ->
+                      (match remaining_dom with
+                      | [] -> []
+                      | _ -> aux new_env remaining_dom) @ filter tl
+                  | Ko -> filter tl)
+            in
+            filter choices
+      in
+       match aux current_env todo_dom with
+       | [] -> raise NoWellTypedInterpretation
+       | [ _ ] as l ->
+           debug_print "UNA SOLA SCELTA";
+           l
+       | l ->
+           debug_print (sprintf "PIU' SCELTE (%d)" (List.length l));
+           let choices =
+             List.map
+               (fun (env, _, _) ->
+                 List.map
+                   (fun domain_item ->
+                     let description =
+                       fst (Environment.find domain_item env)
+                     in
+                     (descr_of_domain_item domain_item, description))
+                   term_dom)
+               l
+           in
+           let choosed = C.interactive_interpretation_choice choices in
+            List.map (List.nth l) choosed
+
+  end