]> matita.cs.unibo.it Git - helm.git/blob - components/cic_disambiguation/disambiguate.ml
we parametrized CicNotationPt.obj on 'term
[helm.git] / components / cic_disambiguation / disambiguate.ml
1 (* Copyright (C) 2004, HELM Team.
2  * 
3  * This file is part of HELM, an Hypertextual, Electronic
4  * Library of Mathematics, developed at the Computer Science
5  * Department, University of Bologna, Italy.
6  * 
7  * HELM is free software; you can redistribute it and/or
8  * modify it under the terms of the GNU General Public License
9  * as published by the Free Software Foundation; either version 2
10  * of the License, or (at your option) any later version.
11  * 
12  * HELM is distributed in the hope that it will be useful,
13  * but WITHOUT ANY WARRANTY; without even the implied warranty of
14  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
15  * GNU General Public License for more details.
16  *
17  * You should have received a copy of the GNU General Public License
18  * along with HELM; if not, write to the Free Software
19  * Foundation, Inc., 59 Temple Place - Suite 330, Boston,
20  * MA  02111-1307, USA.
21  * 
22  * For details, see the HELM World-Wide-Web page,
23  * http://helm.cs.unibo.it/
24  *)
25
26 (* $Id$ *)
27
28 open Printf
29
30 open DisambiguateTypes
31 open UriManager
32
33 module Ast = CicNotationPt
34
35 (* the integer is an offset to be added to each location *)
36 exception NoWellTypedInterpretation of
37  int *
38  ((Token.flocation list * string * string) list *
39   (DisambiguateTypes.domain_item * DisambiguateTypes.codomain_item) list *
40   Token.flocation option * string Lazy.t * bool) list
41 exception PathNotWellFormed
42
43   (** raised when an environment is not enough informative to decide *)
44 exception Try_again of string Lazy.t
45
46 type aliases = bool * DisambiguateTypes.environment
47 type 'a disambiguator_input = string * int * 'a
48
49 type domain = domain_tree list
50 and domain_tree = Node of Token.flocation list * domain_item * domain
51
52 let rec string_of_domain =
53  function
54     [] -> ""
55   | Node (_,domain_item,l)::tl ->
56      DisambiguateTypes.string_of_domain_item domain_item ^
57       " [ " ^ string_of_domain l ^ " ] " ^ string_of_domain tl
58
59 let rec filter_map_domain f =
60  function
61     [] -> []
62   | Node (locs,domain_item,l)::tl ->
63      match f locs domain_item with
64         None -> filter_map_domain f l @ filter_map_domain f tl
65       | Some res -> res :: filter_map_domain f l @ filter_map_domain f tl
66
67 let rec map_domain f =
68  function
69     [] -> []
70   | Node (locs,domain_item,l)::tl ->
71      f locs domain_item :: map_domain f l @ map_domain f tl
72
73 let uniq_domain dom =
74  let rec aux seen =
75   function
76      [] -> seen,[]
77    | Node (locs,domain_item,l)::tl ->
78       if List.mem domain_item seen then
79        let seen,l = aux seen l in
80        let seen,tl = aux seen tl in
81         seen, l @ tl
82       else
83        let seen,l = aux (domain_item::seen) l in
84        let seen,tl = aux seen tl in
85         seen, Node (locs,domain_item,l)::tl
86  in
87   snd (aux [] dom)
88
89 let debug = false
90 let debug_print s = if debug then prerr_endline (Lazy.force s) else ()
91
92 (*
93   (** print benchmark information *)
94 let benchmark = true
95 let max_refinements = ref 0       (* benchmarking is not thread safe *)
96 let actual_refinements = ref 0
97 let domain_size = ref 0
98 let choices_avg = ref 0.
99 *)
100
101 let descr_of_domain_item = function
102  | Id s -> s
103  | Symbol (s, _) -> s
104  | Num i -> string_of_int i
105
106 type 'a test_result =
107   | Ok of 'a * Cic.metasenv
108   | Ko of Token.flocation option * string Lazy.t
109   | Uncertain of Token.flocation option * string Lazy.t
110
111 let refine_term metasenv context uri term ugraph ~localization_tbl =
112 (*   if benchmark then incr actual_refinements; *)
113   assert (uri=None);
114     debug_print (lazy (sprintf "TEST_INTERPRETATION: %s" (CicPp.ppterm term)));
115     try
116       let term', _, metasenv',ugraph1 = 
117         CicRefine.type_of_aux' metasenv context term ugraph ~localization_tbl in
118         (Ok (term', metasenv')),ugraph1
119     with
120      exn ->
121       let rec process_exn loc =
122        function
123           HExtlib.Localized (loc,exn) -> process_exn (Some loc) exn
124         | CicRefine.Uncertain msg ->
125             debug_print (lazy ("UNCERTAIN!!! [" ^ (Lazy.force msg) ^ "] " ^ CicPp.ppterm term)) ;
126             Uncertain (loc,msg),ugraph
127         | CicRefine.RefineFailure msg ->
128             debug_print (lazy (sprintf "PRUNED!!!\nterm%s\nmessage:%s"
129               (CicPp.ppterm term) (Lazy.force msg)));
130             Ko (loc,msg),ugraph
131        | exn -> raise exn
132       in
133        process_exn None exn
134
135 let refine_obj metasenv context uri obj ugraph ~localization_tbl =
136  assert (context = []);
137    debug_print (lazy (sprintf "TEST_INTERPRETATION: %s" (CicPp.ppobj obj))) ;
138    try
139      let obj', metasenv,ugraph =
140       CicRefine.typecheck metasenv uri obj ~localization_tbl
141      in
142        (Ok (obj', metasenv)),ugraph
143    with
144      exn ->
145       let rec process_exn loc =
146        function
147           HExtlib.Localized (loc,exn) -> process_exn (Some loc) exn
148         | CicRefine.Uncertain msg ->
149             debug_print (lazy ("UNCERTAIN!!! [" ^ (Lazy.force msg) ^ "] " ^ CicPp.ppobj obj)) ;
150             Uncertain (loc,msg),ugraph
151         | CicRefine.RefineFailure msg ->
152             debug_print (lazy (sprintf "PRUNED!!!\nterm%s\nmessage:%s"
153               (CicPp.ppobj obj) (Lazy.force msg))) ;
154             Ko (loc,msg),ugraph
155        | exn -> raise exn
156       in
157        process_exn None exn
158
159 let resolve (env: codomain_item Environment.t) (item: domain_item) ?(num = "") ?(args = []) () =
160   try
161     snd (Environment.find item env) env num args
162   with Not_found -> 
163     failwith ("Domain item not found: " ^ 
164       (DisambiguateTypes.string_of_domain_item item))
165
166   (* TODO move it to Cic *)
167 let find_in_context name context =
168   let rec aux acc = function
169     | [] -> raise Not_found
170     | Cic.Name hd :: tl when hd = name -> acc
171     | _ :: tl ->  aux (acc + 1) tl
172   in
173   aux 1 context
174
175 let interpretate_term ~(context: Cic.name list) ~env ~uri ~is_path ast
176      ~localization_tbl
177 =
178   assert (uri = None);
179   let rec aux ~localize loc (context: Cic.name list) = function
180     | CicNotationPt.AttributedTerm (`Loc loc, term) ->
181         let res = aux ~localize loc context term in
182          if localize then Cic.CicHash.add localization_tbl res loc;
183          res
184     | CicNotationPt.AttributedTerm (_, term) -> aux ~localize loc context term
185     | CicNotationPt.Appl (CicNotationPt.Symbol (symb, i) :: args) ->
186         let cic_args = List.map (aux ~localize loc context) args in
187         resolve env (Symbol (symb, i)) ~args:cic_args ()
188     | CicNotationPt.Appl terms ->
189        Cic.Appl (List.map (aux ~localize loc context) terms)
190     | CicNotationPt.Binder (binder_kind, (var, typ), body) ->
191         let cic_type = aux_option ~localize loc context (Some `Type) typ in
192         let cic_name = CicNotationUtil.cic_name_of_name var in
193         let cic_body = aux ~localize loc (cic_name :: context) body in
194         (match binder_kind with
195         | `Lambda -> Cic.Lambda (cic_name, cic_type, cic_body)
196         | `Pi
197         | `Forall -> Cic.Prod (cic_name, cic_type, cic_body)
198         | `Exists ->
199             resolve env (Symbol ("exists", 0))
200               ~args:[ cic_type; Cic.Lambda (cic_name, cic_type, cic_body) ] ())
201     | CicNotationPt.Case (term, indty_ident, outtype, branches) ->
202         let cic_term = aux ~localize loc context term in
203         let cic_outtype = aux_option ~localize loc context None outtype in
204         let do_branch ((head, _, args), term) =
205           let rec do_branch' context = function
206             | [] -> aux ~localize loc context term
207             | (name, typ) :: tl ->
208                 let cic_name = CicNotationUtil.cic_name_of_name name in
209                 let cic_body = do_branch' (cic_name :: context) tl in
210                 let typ =
211                   match typ with
212                   | None -> Cic.Implicit (Some `Type)
213                   | Some typ -> aux ~localize loc context typ
214                 in
215                 Cic.Lambda (cic_name, typ, cic_body)
216           in
217           do_branch' context args
218         in
219         let (indtype_uri, indtype_no) =
220           match indty_ident with
221           | Some (indty_ident, _) ->
222              (match resolve env (Id indty_ident) () with
223               | Cic.MutInd (uri, tyno, _) -> (uri, tyno)
224               | Cic.Implicit _ ->
225                  raise (Try_again (lazy "The type of the term to be matched
226                   is still unknown"))
227               | _ ->
228                 raise (Invalid_choice (lazy "The type of the term to be matched is not (co)inductive!")))
229           | None ->
230               let fst_constructor =
231                 match branches with
232                 | ((head, _, _), _) :: _ -> head
233                 | [] -> raise (Invalid_choice (lazy "The type of the term to be matched is an inductive type without constructors that cannot be determined"))
234               in
235               (match resolve env (Id fst_constructor) () with
236               | Cic.MutConstruct (indtype_uri, indtype_no, _, _) ->
237                   (indtype_uri, indtype_no)
238               | Cic.Implicit _ ->
239                  raise (Try_again (lazy "The type of the term to be matched
240                   is still unknown"))
241               | _ ->
242                 raise (Invalid_choice (lazy "The type of the term to be matched is not (co)inductive!")))
243         in
244         Cic.MutCase (indtype_uri, indtype_no, cic_outtype, cic_term,
245           (List.map do_branch branches))
246     | CicNotationPt.Cast (t1, t2) ->
247         let cic_t1 = aux ~localize loc context t1 in
248         let cic_t2 = aux ~localize loc context t2 in
249         Cic.Cast (cic_t1, cic_t2)
250     | CicNotationPt.LetIn ((name, typ), def, body) ->
251         let cic_def = aux ~localize loc context def in
252         let cic_name = CicNotationUtil.cic_name_of_name name in
253         let cic_def =
254           match typ with
255           | None -> cic_def
256           | Some t -> Cic.Cast (cic_def, aux ~localize loc context t)
257         in
258         let cic_body = aux ~localize loc (cic_name :: context) body in
259         Cic.LetIn (cic_name, cic_def, cic_body)
260     | CicNotationPt.LetRec (kind, defs, body) ->
261         let context' =
262           List.fold_left
263             (fun acc (_, (name, _), _, _) ->
264               CicNotationUtil.cic_name_of_name name :: acc)
265             context defs
266         in
267         let cic_body =
268          let unlocalized_body = aux ~localize:false loc context' body in
269          match unlocalized_body with
270             Cic.Rel 1 -> `AvoidLetInNoAppl
271           | Cic.Appl (Cic.Rel 1::l) ->
272              (try
273                let l' =
274                 List.map
275                  (function t ->
276                    let t',subst,metasenv =
277                     CicMetaSubst.delift_rels [] [] 1 t
278                    in
279                     assert (subst=[]);
280                     assert (metasenv=[]);
281                     t') l
282                in
283                 (* We can avoid the LetIn. But maybe we need to recompute l'
284                    so that it is localized *)
285                 if localize then
286                  match body with
287                     CicNotationPt.AttributedTerm (_,CicNotationPt.Appl(_::l)) ->
288                      let l' = List.map (aux ~localize loc context) l in
289                       `AvoidLetIn l'
290                   | _ -> assert false
291                 else
292                  `AvoidLetIn l'
293               with
294                CicMetaSubst.DeliftingARelWouldCaptureAFreeVariable ->
295                 if localize then
296                  `AddLetIn (aux ~localize loc context' body)
297                 else
298                  `AddLetIn unlocalized_body)
299           | _ ->
300              if localize then
301               `AddLetIn (aux ~localize loc context' body)
302              else
303               `AddLetIn unlocalized_body
304         in
305         let inductiveFuns =
306           List.map
307             (fun (params, (name, typ), body, decr_idx) ->
308               let add_binders kind t =
309                List.fold_right
310                 (fun var t -> CicNotationPt.Binder (kind, var, t)) params t
311               in
312               let cic_body =
313                aux ~localize loc context' (add_binders `Lambda body) in
314               let cic_type =
315                aux_option ~localize loc context (Some `Type)
316                 (HExtlib.map_option (add_binders `Pi) typ) in
317               let name =
318                 match CicNotationUtil.cic_name_of_name name with
319                 | Cic.Anonymous ->
320                     CicNotationPt.fail loc
321                       "Recursive functions cannot be anonymous"
322                 | Cic.Name name -> name
323               in
324               (name, decr_idx, cic_type, cic_body))
325             defs
326         in
327         let counter = ref ~-1 in
328         let build_term funs =
329           (* this is the body of the fold_right function below. Rationale: Fix
330            * and CoFix cases differs only in an additional index in the
331            * inductiveFun list, see Cic.term *)
332           match kind with
333           | `Inductive ->
334               (fun (var, _, _, _) cic ->
335                 incr counter;
336                 let fix = Cic.Fix (!counter,funs) in
337                  match cic with
338                     `Recipe (`AddLetIn cic) ->
339                       `Term (Cic.LetIn (Cic.Name var, fix, cic))
340                   | `Recipe (`AvoidLetIn l) -> `Term (Cic.Appl (fix::l))
341                   | `Recipe `AvoidLetInNoAppl -> `Term fix
342                   | `Term t -> `Term (Cic.LetIn (Cic.Name var, fix, t)))
343           | `CoInductive ->
344               let funs =
345                 List.map (fun (name, _, typ, body) -> (name, typ, body)) funs
346               in
347               (fun (var, _, _, _) cic ->
348                 incr counter;
349                 let cofix = Cic.CoFix (!counter,funs) in
350                  match cic with
351                     `Recipe (`AddLetIn cic) ->
352                       `Term (Cic.LetIn (Cic.Name var, cofix, cic))
353                   | `Recipe (`AvoidLetIn l) -> `Term (Cic.Appl (cofix::l))
354                   | `Recipe `AvoidLetInNoAppl -> `Term cofix
355                   | `Term t -> `Term (Cic.LetIn (Cic.Name var, cofix, t)))
356         in
357          (match
358            List.fold_right (build_term inductiveFuns) inductiveFuns
359             (`Recipe cic_body)
360           with
361              `Recipe _ -> assert false
362            | `Term t -> t)
363     | CicNotationPt.Ident _
364     | CicNotationPt.Uri _ when is_path -> raise PathNotWellFormed
365     | CicNotationPt.Ident (name, subst)
366     | CicNotationPt.Uri (name, subst) as ast ->
367         let is_uri = function CicNotationPt.Uri _ -> true | _ -> false in
368         (try
369           if is_uri ast then raise Not_found;(* don't search the env for URIs *)
370           let index = find_in_context name context in
371           if subst <> None then
372             CicNotationPt.fail loc "Explicit substitutions not allowed here";
373           Cic.Rel index
374         with Not_found ->
375           let cic =
376             if is_uri ast then  (* we have the URI, build the term out of it *)
377               try
378                 CicUtil.term_of_uri (UriManager.uri_of_string name)
379               with UriManager.IllFormedUri _ ->
380                 CicNotationPt.fail loc "Ill formed URI"
381             else
382               resolve env (Id name) ()
383           in
384           let mk_subst uris =
385             let ids_to_uris =
386               List.map (fun uri -> UriManager.name_of_uri uri, uri) uris
387             in
388             (match subst with
389             | Some subst ->
390                 List.map
391                   (fun (s, term) ->
392                     (try
393                       List.assoc s ids_to_uris, aux ~localize loc context term
394                      with Not_found ->
395                        raise (Invalid_choice (lazy "The provided explicit named substitution is trying to instantiate a named variable the object is not abstracted on"))))
396                   subst
397             | None -> List.map (fun uri -> uri, Cic.Implicit None) uris)
398           in
399           (try 
400             match cic with
401             | Cic.Const (uri, []) ->
402                 let o,_ = CicEnvironment.get_obj CicUniv.empty_ugraph uri in
403                 let uris = CicUtil.params_of_obj o in
404                 Cic.Const (uri, mk_subst uris)
405             | Cic.Var (uri, []) ->
406                 let o,_ = CicEnvironment.get_obj CicUniv.empty_ugraph uri in
407                 let uris = CicUtil.params_of_obj o in
408                 Cic.Var (uri, mk_subst uris)
409             | Cic.MutInd (uri, i, []) ->
410                (try
411                  let o,_ = CicEnvironment.get_obj CicUniv.empty_ugraph uri in
412                  let uris = CicUtil.params_of_obj o in
413                  Cic.MutInd (uri, i, mk_subst uris)
414                 with
415                  CicEnvironment.Object_not_found _ ->
416                   (* if we are here it is probably the case that during the
417                      definition of a mutual inductive type we have met an
418                      occurrence of the type in one of its constructors.
419                      However, the inductive type is not yet in the environment
420                   *)
421                   (*here the explicit_named_substituion is assumed to be of length 0 *)
422                   Cic.MutInd (uri,i,[]))
423             | Cic.MutConstruct (uri, i, j, []) ->
424                 let o,_ = CicEnvironment.get_obj CicUniv.empty_ugraph uri in
425                 let uris = CicUtil.params_of_obj o in
426                 Cic.MutConstruct (uri, i, j, mk_subst uris)
427             | Cic.Meta _ | Cic.Implicit _ as t ->
428 (*
429                 debug_print (lazy (sprintf
430                   "Warning: %s must be instantiated with _[%s] but we do not enforce it"
431                   (CicPp.ppterm t)
432                   (String.concat "; "
433                     (List.map
434                       (fun (s, term) -> s ^ " := " ^ CicNotationPtPp.pp_term term)
435                       subst))));
436 *)
437                 t
438             | _ ->
439               raise (Invalid_choice (lazy "??? Can this happen?"))
440            with 
441              CicEnvironment.CircularDependency _ -> 
442                raise (Invalid_choice (lazy "Circular dependency in the environment"))))
443     | CicNotationPt.Implicit -> Cic.Implicit None
444     | CicNotationPt.UserInput -> Cic.Implicit (Some `Hole)
445     | CicNotationPt.Num (num, i) -> resolve env (Num i) ~num ()
446     | CicNotationPt.Meta (index, subst) ->
447         let cic_subst =
448           List.map
449             (function
450                 None -> None
451               | Some term -> Some (aux ~localize loc context term))
452             subst
453         in
454         Cic.Meta (index, cic_subst)
455     | CicNotationPt.Sort `Prop -> Cic.Sort Cic.Prop
456     | CicNotationPt.Sort `Set -> Cic.Sort Cic.Set
457     | CicNotationPt.Sort (`Type u) -> Cic.Sort (Cic.Type u)
458     | CicNotationPt.Sort `CProp -> Cic.Sort Cic.CProp
459     | CicNotationPt.Symbol (symbol, instance) ->
460         resolve env (Symbol (symbol, instance)) ()
461     | _ -> assert false (* god bless Bologna *)
462   and aux_option ~localize loc (context: Cic.name list) annotation = function
463     | None -> Cic.Implicit annotation
464     | Some term -> aux ~localize loc context term
465   in
466    aux ~localize:true HExtlib.dummy_floc context ast
467
468 let interpretate_path ~context path =
469  let localization_tbl = Cic.CicHash.create 23 in
470   (* here we are throwing away useful localization informations!!! *)
471   fst (
472    interpretate_term ~context ~env:Environment.empty ~uri:None ~is_path:true
473     path ~localization_tbl, localization_tbl)
474
475 let interpretate_obj ~context ~env ~uri ~is_path obj ~localization_tbl =
476  assert (context = []);
477  assert (is_path = false);
478  let interpretate_term = interpretate_term ~localization_tbl in
479  match obj with
480   | CicNotationPt.Inductive (params,tyl) ->
481      let uri = match uri with Some uri -> uri | None -> assert false in
482      let context,params =
483       let context,res =
484        List.fold_left
485         (fun (context,res) (name,t) ->
486           let t =
487            match t with
488               None -> CicNotationPt.Implicit
489             | Some t -> t in
490           let name = CicNotationUtil.cic_name_of_name name in
491            name::context,(name, interpretate_term context env None false t)::res
492         ) ([],[]) params
493       in
494        context,List.rev res in
495      let add_params =
496       List.fold_right (fun (name,ty) t -> Cic.Prod (name,ty,t)) params in
497      let name_to_uris =
498       snd (
499        List.fold_left
500         (*here the explicit_named_substituion is assumed to be of length 0 *)
501         (fun (i,res) (name,_,_,_) ->
502           i + 1,(name,name,Cic.MutInd (uri,i,[]))::res
503         ) (0,[]) tyl) in
504      let con_env = DisambiguateTypes.env_of_list name_to_uris env in
505      let tyl =
506       List.map
507        (fun (name,b,ty,cl) ->
508          let ty' = add_params (interpretate_term context env None false ty) in
509          let cl' =
510           List.map
511            (fun (name,ty) ->
512              let ty' =
513               add_params (interpretate_term context con_env None false ty)
514              in
515               name,ty'
516            ) cl
517          in
518           name,b,ty',cl'
519        ) tyl
520      in
521       Cic.InductiveDefinition (tyl,[],List.length params,[])
522   | CicNotationPt.Record (params,name,ty,fields) ->
523      let uri = match uri with Some uri -> uri | None -> assert false in
524      let context,params =
525       let context,res =
526        List.fold_left
527         (fun (context,res) (name,t) ->
528           let t =
529            match t with
530               None -> CicNotationPt.Implicit
531             | Some t -> t in
532           let name = CicNotationUtil.cic_name_of_name name in
533            name::context,(name, interpretate_term context env None false t)::res
534         ) ([],[]) params
535       in
536        context,List.rev res in
537      let add_params =
538       List.fold_right
539        (fun (name,ty) t -> Cic.Prod (name,ty,t)) params in
540      let ty' = add_params (interpretate_term context env None false ty) in
541      let fields' =
542       snd (
543        List.fold_left
544         (fun (context,res) (name,ty,_coercion,arity) ->
545           let context' = Cic.Name name :: context in
546            context',(name,interpretate_term context env None false ty)::res
547         ) (context,[]) fields) in
548      let concl =
549       (*here the explicit_named_substituion is assumed to be of length 0 *)
550       let mutind = Cic.MutInd (uri,0,[]) in
551       if params = [] then mutind
552       else
553        Cic.Appl
554         (mutind::CicUtil.mk_rels (List.length params) (List.length fields)) in
555      let con =
556       List.fold_left
557        (fun t (name,ty) -> Cic.Prod (Cic.Name name,ty,t))
558        concl fields' in
559      let con' = add_params con in
560      let tyl = [name,true,ty',["mk_" ^ name,con']] in
561      let field_names = List.map (fun (x,_,y,z) -> x,y,z) fields in
562       Cic.InductiveDefinition
563        (tyl,[],List.length params,[`Class (`Record field_names)])
564   | CicNotationPt.Theorem (flavour, name, ty, bo) ->
565      let attrs = [`Flavour flavour] in
566      let ty' = interpretate_term [] env None false ty in
567      (match bo,flavour with
568         None,`Axiom ->
569          Cic.Constant (name,None,ty',[],attrs)
570       | Some bo,`Axiom -> assert false
571       | None,_ ->
572          Cic.CurrentProof (name,[],Cic.Implicit None,ty',[],attrs)
573       | Some bo,_ ->
574          let bo' = Some (interpretate_term [] env None false bo) in
575           Cic.Constant (name,bo',ty',[],attrs))
576           
577 let rec domain_of_term ?(loc = HExtlib.dummy_floc) ~context = function
578   | Ast.AttributedTerm (`Loc loc, term) ->
579      domain_of_term ~loc ~context term
580   | Ast.AttributedTerm (_, term) ->
581       domain_of_term ~loc ~context term
582   | Ast.Symbol (symbol, instance) ->
583       [ Node ([loc], Symbol (symbol, instance), []) ]
584       (* to be kept in sync with Ast.Appl (Ast.Symbol ...) *)
585   | Ast.Appl (Ast.Symbol (symbol, instance) as hd :: args)
586   | Ast.Appl (Ast.AttributedTerm (_,Ast.Symbol (symbol, instance)) as hd :: args)
587      ->
588       let args_dom =
589         List.fold_right
590           (fun term acc -> domain_of_term ~loc ~context term @ acc)
591           args [] in
592       let loc =
593        match hd with
594           Ast.AttributedTerm (`Loc loc,_)  -> loc
595         | _ -> loc
596       in
597        [ Node ([loc], Symbol (symbol, instance), args_dom) ]
598   | Ast.Appl (Ast.Ident (name, subst) as hd :: args)
599   | Ast.Appl (Ast.AttributedTerm (_,Ast.Ident (name, subst)) as hd :: args) ->
600       let args_dom =
601         List.fold_right
602           (fun term acc -> domain_of_term ~loc ~context term @ acc)
603           args [] in
604       let loc =
605        match hd with
606           Ast.AttributedTerm (`Loc loc,_)  -> loc
607         | _ -> loc
608       in
609       (try
610         (* the next line can raise Not_found *)
611         ignore(find_in_context name context);
612         if subst <> None then
613           Ast.fail loc "Explicit substitutions not allowed here"
614         else
615           args_dom
616       with Not_found ->
617         (match subst with
618         | None -> [ Node ([loc], Id name, args_dom) ]
619         | Some subst ->
620             let terms =
621               List.fold_left
622                 (fun dom (_, term) ->
623                   let dom' = domain_of_term ~loc ~context term in
624                   dom @ dom')
625                 [] subst in
626             [ Node ([loc], Id name, terms @ args_dom) ]))
627   | Ast.Appl terms ->
628       List.fold_right
629         (fun term acc -> domain_of_term ~loc ~context term @ acc)
630         terms []
631   | Ast.Binder (kind, (var, typ), body) ->
632       let type_dom = domain_of_term_option ~loc ~context typ in
633       let body_dom =
634         domain_of_term ~loc
635           ~context:(CicNotationUtil.cic_name_of_name var :: context) body in
636       (match kind with
637       | `Exists -> [ Node ([loc], Symbol ("exists", 0), (type_dom @ body_dom)) ]
638       | _ -> type_dom @ body_dom)
639   | Ast.Case (term, indty_ident, outtype, branches) ->
640       let term_dom = domain_of_term ~loc ~context term in
641       let outtype_dom = domain_of_term_option ~loc ~context outtype in
642       let get_first_constructor = function
643         | [] -> []
644         | ((head, _, _), _) :: _ -> [ Node ([loc], Id head, []) ] in
645       let do_branch ((head, _, args), term) =
646         let (term_context, args_domain) =
647           List.fold_left
648             (fun (cont, dom) (name, typ) ->
649               (CicNotationUtil.cic_name_of_name name :: cont,
650                (match typ with
651                | None -> dom
652                | Some typ -> dom @ domain_of_term ~loc ~context:cont typ)))
653             (context, []) args
654         in
655         domain_of_term ~loc ~context:term_context term @ args_domain
656       in
657       let branches_dom =
658         List.fold_left (fun dom branch -> dom @ do_branch branch) [] branches in
659       (match indty_ident with
660        | None -> get_first_constructor branches
661        | Some (ident, _) -> [ Node ([loc], Id ident, []) ])
662       @ term_dom @ outtype_dom @ branches_dom
663   | Ast.Cast (term, ty) ->
664       let term_dom = domain_of_term ~loc ~context term in
665       let ty_dom = domain_of_term ~loc ~context ty in
666       term_dom @ ty_dom
667   | Ast.LetIn ((var, typ), body, where) ->
668       let body_dom = domain_of_term ~loc ~context body in
669       let type_dom = domain_of_term_option ~loc ~context typ in
670       let where_dom =
671         domain_of_term ~loc
672           ~context:(CicNotationUtil.cic_name_of_name var :: context) where in
673       body_dom @ type_dom @ where_dom
674   | Ast.LetRec (kind, defs, where) ->
675       let add_defs context =
676         List.fold_left
677           (fun acc (_, (var, _), _, _) ->
678             CicNotationUtil.cic_name_of_name var :: acc
679           ) context defs in
680       let where_dom = domain_of_term ~loc ~context:(add_defs context) where in
681       let defs_dom =
682         List.fold_left
683           (fun dom (params, (_, typ), body, _) ->
684             let context' =
685              add_defs
686               (List.fold_left
687                 (fun acc (var,_) -> CicNotationUtil.cic_name_of_name var :: acc)
688                 context params)
689             in
690             List.rev
691              (snd
692                (List.fold_left
693                 (fun (context,res) (var,ty) ->
694                   CicNotationUtil.cic_name_of_name var :: context,
695                   domain_of_term_option ~loc ~context ty @ res)
696                 (add_defs context,[]) params))
697             @ domain_of_term_option ~loc ~context typ
698             @ domain_of_term ~loc ~context:context' body
699           ) [] defs
700       in
701       defs_dom @ where_dom
702   | Ast.Ident (name, subst) ->
703       (try
704         (* the next line can raise Not_found *)
705         ignore(find_in_context name context);
706         if subst <> None then
707           Ast.fail loc "Explicit substitutions not allowed here"
708         else
709           []
710       with Not_found ->
711         (match subst with
712         | None -> [ Node ([loc], Id name, []) ]
713         | Some subst ->
714             let terms =
715               List.fold_left
716                 (fun dom (_, term) ->
717                   let dom' = domain_of_term ~loc ~context term in
718                   dom @ dom')
719                 [] subst in
720             [ Node ([loc], Id name, terms) ]))
721   | Ast.Uri _ -> []
722   | Ast.Implicit -> []
723   | Ast.Num (num, i) -> [ Node ([loc], Num i, []) ]
724   | Ast.Meta (index, local_context) ->
725       List.fold_left
726        (fun dom term -> dom @ domain_of_term_option ~loc ~context term)
727        [] local_context
728   | Ast.Sort _ -> []
729   | Ast.UserInput
730   | Ast.Literal _
731   | Ast.Layout _
732   | Ast.Magic _
733   | Ast.Variable _ -> assert false
734
735 and domain_of_term_option ~loc ~context = function
736   | None -> []
737   | Some t -> domain_of_term ~loc ~context t
738
739 let domain_of_term ~context term = 
740  uniq_domain (domain_of_term ~context term)
741
742 let domain_of_obj ~context ast =
743  assert (context = []);
744   match ast with
745    | Ast.Theorem (_,_,ty,bo) ->
746       domain_of_term [] ty
747       @ (match bo with
748           None -> []
749         | Some bo -> domain_of_term [] bo)
750    | Ast.Inductive (params,tyl) ->
751       let context, dom = 
752        List.fold_left
753         (fun (context, dom) (var, ty) ->
754           let context' = CicNotationUtil.cic_name_of_name var :: context in
755           match ty with
756              None -> context', dom
757            | Some ty -> context', dom @ domain_of_term context ty
758         ) ([], []) params in
759       let context_w_types =
760         List.rev_map
761           (fun (var, _, _, _) -> Cic.Name var) tyl
762         @ context in
763       dom
764       @ List.flatten (
765          List.map
766           (fun (_,_,ty,cl) ->
767             domain_of_term context ty
768             @ List.flatten (
769                List.map
770                 (fun (_,ty) -> domain_of_term context_w_types ty) cl))
771                 tyl)
772    | CicNotationPt.Record (params,var,ty,fields) ->
773       let context, dom = 
774        List.fold_left
775         (fun (context, dom) (var, ty) ->
776           let context' = CicNotationUtil.cic_name_of_name var :: context in
777           match ty with
778              None -> context', dom
779            | Some ty -> context', dom @ domain_of_term context ty
780         ) ([], []) params in
781       let context_w_types = Cic.Name var :: context in
782       dom
783       @ domain_of_term context ty
784       @ snd
785          (List.fold_left
786           (fun (context,res) (name,ty,_,_) ->
787             Cic.Name name::context, res @ domain_of_term context ty
788           ) (context_w_types,[]) fields)
789
790 let domain_of_obj ~context obj = 
791  uniq_domain (domain_of_obj ~context obj)
792
793   (* dom1 \ dom2 *)
794 let domain_diff dom1 dom2 =
795 (* let domain_diff = Domain.diff *)
796   let is_in_dom2 elt =
797     List.exists
798      (function
799        | Symbol (symb, 0) ->
800           (match elt with
801               Symbol (symb',_) when symb = symb' -> true
802             | _ -> false)
803        | Num i ->
804           (match elt with
805               Num _ -> true
806             | _ -> false)
807        | item -> elt = item
808      ) dom2
809   in
810    let rec aux =
811     function
812        [] -> []
813      | Node (_,elt,l)::tl when is_in_dom2 elt -> aux (l @ tl)
814      | Node (loc,elt,l)::tl -> Node (loc,elt,aux l)::(aux tl)
815    in
816     aux dom1
817
818 module type Disambiguator =
819 sig
820   val disambiguate_term :
821     ?fresh_instances:bool ->
822     dbd:HMysql.dbd ->
823     context:Cic.context ->
824     metasenv:Cic.metasenv ->
825     ?initial_ugraph:CicUniv.universe_graph -> 
826     aliases:DisambiguateTypes.environment ->(* previous interpretation status *)
827     universe:DisambiguateTypes.multiple_environment option ->
828     CicNotationPt.term disambiguator_input ->
829     ((DisambiguateTypes.domain_item * DisambiguateTypes.codomain_item) list *
830      Cic.metasenv *                  (* new metasenv *)
831      Cic.term*
832      CicUniv.universe_graph) list *  (* disambiguated term *)
833     bool
834
835   val disambiguate_obj :
836     ?fresh_instances:bool ->
837     dbd:HMysql.dbd ->
838     aliases:DisambiguateTypes.environment ->(* previous interpretation status *)
839     universe:DisambiguateTypes.multiple_environment option ->
840     uri:UriManager.uri option ->     (* required only for inductive types *)
841     CicNotationPt.term CicNotationPt.obj disambiguator_input ->
842     ((DisambiguateTypes.domain_item * DisambiguateTypes.codomain_item) list *
843      Cic.metasenv *                  (* new metasenv *)
844      Cic.obj *
845      CicUniv.universe_graph) list *  (* disambiguated obj *)
846     bool
847 end
848
849 module Make (C: Callbacks) =
850   struct
851     let choices_of_id dbd id =
852       let uris = Whelp.locate ~dbd id in
853       let uris =
854        match uris with
855         | [] ->
856            (match 
857              (C.input_or_locate_uri 
858                ~title:("URI matching \"" ^ id ^ "\" unknown.") ~id ()) 
859            with
860            | None -> []
861            | Some uri -> [uri])
862         | [uri] -> [uri]
863         | _ ->
864             C.interactive_user_uri_choice ~selection_mode:`MULTIPLE
865              ~ok:"Try selected." ~enable_button_for_non_vars:true
866              ~title:"Ambiguous input." ~id
867              ~msg: ("Ambiguous input \"" ^ id ^
868                 "\". Please, choose one or more interpretations:")
869              uris
870       in
871       List.map
872         (fun uri ->
873           (UriManager.string_of_uri uri,
874            let term =
875              try
876                CicUtil.term_of_uri uri
877              with exn ->
878                debug_print (lazy (UriManager.string_of_uri uri));
879                debug_print (lazy (Printexc.to_string exn));
880                assert false
881             in
882            fun _ _ _ -> term))
883         uris
884
885 let refine_profiler = HExtlib.profile "disambiguate_thing.refine_thing"
886
887     let disambiguate_thing ~dbd ~context ~metasenv
888       ?(initial_ugraph = CicUniv.empty_ugraph) ~aliases ~universe
889       ~uri ~pp_thing ~domain_of_thing ~interpretate_thing ~refine_thing 
890       (thing_txt,thing_txt_prefix_len,thing)
891     =
892       debug_print (lazy "DISAMBIGUATE INPUT");
893       let disambiguate_context =  (* cic context -> disambiguate context *)
894         List.map
895           (function None -> Cic.Anonymous | Some (name, _) -> name)
896           context
897       in
898       debug_print (lazy ("TERM IS: " ^ (pp_thing thing)));
899       let thing_dom = domain_of_thing ~context:disambiguate_context thing in
900       debug_print
901        (lazy (sprintf "DISAMBIGUATION DOMAIN: %s"(string_of_domain thing_dom)));
902 (*
903       debug_print (lazy (sprintf "DISAMBIGUATION ENVIRONMENT: %s"
904         (DisambiguatePp.pp_environment aliases)));
905       debug_print (lazy (sprintf "DISAMBIGUATION UNIVERSE: %s"
906         (match universe with None -> "None" | Some _ -> "Some _")));
907 *)
908       let current_dom =
909         Environment.fold (fun item _ dom -> item :: dom) aliases [] in
910       let todo_dom = domain_diff thing_dom current_dom in
911       debug_print
912        (lazy (sprintf "DISAMBIGUATION DOMAIN AFTER DIFF: %s"(string_of_domain todo_dom)));
913       (* (2) lookup function for any item (Id/Symbol/Num) *)
914       let lookup_choices =
915         fun item ->
916           let choices =
917             let lookup_in_library () =
918               match item with
919               | Id id -> choices_of_id dbd id
920               | Symbol (symb, _) ->
921                  (try
922                    List.map DisambiguateChoices.mk_choice
923                     (TermAcicContent.lookup_interpretations symb)
924                   with
925                    TermAcicContent.Interpretation_not_found -> [])
926               | Num instance ->
927                   DisambiguateChoices.lookup_num_choices ()
928             in
929             match universe with
930             | None -> lookup_in_library ()
931             | Some e ->
932                 (try
933                   let item =
934                     match item with
935                     | Symbol (symb, _) -> Symbol (symb, 0)
936                     | item -> item
937                   in
938                   Environment.find item e
939                 with Not_found -> lookup_in_library ())
940           in
941           choices
942       in
943 (*
944       (* <benchmark> *)
945       let _ =
946         if benchmark then begin
947           let per_item_choices =
948             List.map
949               (fun dom_item ->
950                 try
951                   let len = List.length (lookup_choices dom_item) in
952                   debug_print (lazy (sprintf "BENCHMARK %s: %d"
953                     (string_of_domain_item dom_item) len));
954                   len
955                 with No_choices _ -> 0)
956               thing_dom
957           in
958           max_refinements := List.fold_left ( * ) 1 per_item_choices;
959           actual_refinements := 0;
960           domain_size := List.length thing_dom;
961           choices_avg :=
962             (float_of_int !max_refinements) ** (1. /. float_of_int !domain_size)
963         end
964       in
965       (* </benchmark> *)
966 *)
967
968       (* (3) test an interpretation filling with meta uninterpreted identifiers
969        *)
970       let test_env aliases todo_dom ugraph = 
971         let rec aux env = function
972           | [] -> env
973           | Node (_, item, l) :: tl ->
974               let env =
975                 Environment.add item
976                  ("Implicit",
977                    (match item with
978                       | Id _ | Num _ ->
979                           (fun _ _ _ -> Cic.Implicit (Some `Closed))
980                       | Symbol _ -> (fun _ _ _ -> Cic.Implicit None)))
981                  env in
982               aux (aux env l) tl in
983         let filled_env = aux aliases todo_dom in
984         try
985           let localization_tbl = Cic.CicHash.create 503 in
986           let cic_thing =
987             interpretate_thing ~context:disambiguate_context ~env:filled_env
988              ~uri ~is_path:false thing ~localization_tbl
989           in
990 let foo () =
991           let k,ugraph1 =
992            refine_thing metasenv context uri cic_thing ugraph ~localization_tbl
993           in
994             (k , ugraph1 )
995 in refine_profiler.HExtlib.profile foo ()
996         with
997         | Try_again msg -> Uncertain (None,msg), ugraph
998         | Invalid_choice msg -> Ko (None,msg), ugraph
999       in
1000       (* (4) build all possible interpretations *)
1001       let (@@) (l1,l2,l3) (l1',l2',l3') = l1@l1', l2@l2', l3@l3' in
1002       (* aux returns triples Ok/Uncertain/Ko *)
1003       (* rem_dom is the concatenation of all the remainin domains *)
1004       let rec aux aliases diff lookup_in_todo_dom todo_dom rem_dom base_univ =
1005         debug_print (lazy ("ZZZ: " ^ string_of_domain todo_dom));
1006         match todo_dom with
1007         | [] ->
1008             assert (lookup_in_todo_dom = None);
1009             (match test_env aliases rem_dom base_univ with
1010             | Ok (thing, metasenv),new_univ -> 
1011                [ aliases, diff, metasenv, thing, new_univ ], [], []
1012             | Ko (loc,msg),_ -> [],[],[aliases,diff,loc,msg,true]
1013             | Uncertain (loc,msg),new_univ ->
1014                [],[aliases,diff,loc,msg,new_univ],[])
1015         | Node (locs,item,inner_dom) :: remaining_dom ->
1016             debug_print (lazy (sprintf "CHOOSED ITEM: %s"
1017              (string_of_domain_item item)));
1018             let choices =
1019              match lookup_in_todo_dom with
1020                 None -> lookup_choices item
1021               | Some choices -> choices in
1022             match choices with
1023                [] ->
1024                 [], [],
1025                  [aliases, diff, Some (List.hd locs),
1026                   lazy ("No choices for " ^ string_of_domain_item item),
1027                   true]
1028 (*
1029              | [codomain_item] ->
1030                  (* just one choice. We perform a one-step look-up and
1031                     if the next set of choices is also a singleton we
1032                     skip this refinement step *)
1033                  debug_print(lazy (sprintf "%s CHOSEN" (fst codomain_item)));
1034                  let new_env = Environment.add item codomain_item aliases in
1035                  let new_diff = (item,codomain_item)::diff in
1036                  let lookup_in_todo_dom,next_choice_is_single =
1037                   match remaining_dom with
1038                      [] -> None,false
1039                    | (_,he)::_ ->
1040                       let choices = lookup_choices he in
1041                        Some choices,List.length choices = 1
1042                  in
1043                   if next_choice_is_single then
1044                    aux new_env new_diff lookup_in_todo_dom remaining_dom
1045                     base_univ
1046                   else
1047                     (match test_env new_env remaining_dom base_univ with
1048                     | Ok (thing, metasenv),new_univ ->
1049                         (match remaining_dom with
1050                         | [] ->
1051                            [ new_env, new_diff, metasenv, thing, new_univ ], []
1052                         | _ ->
1053                            aux new_env new_diff lookup_in_todo_dom
1054                             remaining_dom new_univ)
1055                     | Uncertain (loc,msg),new_univ ->
1056                         (match remaining_dom with
1057                         | [] -> [], [new_env,new_diff,loc,msg,true]
1058                         | _ ->
1059                            aux new_env new_diff lookup_in_todo_dom
1060                             remaining_dom new_univ)
1061                     | Ko (loc,msg),_ -> [], [new_env,new_diff,loc,msg,true])
1062 *)
1063              | _::_ ->
1064                  let mark_not_significant failures =
1065                    List.map
1066                     (fun (env, diff, loc, msg, _b) ->
1067                       env, diff, loc, msg, false)
1068                     failures in
1069                  let classify_errors ((ok_l,uncertain_l,error_l) as outcome) =
1070                   if ok_l <> [] || uncertain_l <> [] then
1071                    ok_l,uncertain_l,mark_not_significant error_l
1072                   else
1073                    outcome in
1074                let rec filter univ = function 
1075                 | [] -> [],[],[]
1076                 | codomain_item :: tl ->
1077                     debug_print(lazy (sprintf "%s CHOSEN" (fst codomain_item)));
1078                     let new_env = Environment.add item codomain_item aliases in
1079                     let new_diff = (item,codomain_item)::diff in
1080                     (match
1081                       test_env new_env (inner_dom@remaining_dom@rem_dom) univ
1082                      with
1083                     | Ok (thing, metasenv),new_univ ->
1084                         let res = 
1085                           (match inner_dom with
1086                           | [] ->
1087                              [new_env,new_diff,metasenv,thing,new_univ], [], []
1088                           | _ ->
1089                              aux new_env new_diff None inner_dom
1090                               (remaining_dom@rem_dom) new_univ
1091                           ) 
1092                         in
1093                          res @@ filter univ tl
1094                     | Uncertain (loc,msg),new_univ ->
1095                         let res =
1096                           (match inner_dom with
1097                           | [] -> [],[new_env,new_diff,loc,msg,new_univ],[]
1098                           | _ ->
1099                              aux new_env new_diff None inner_dom
1100                               (remaining_dom@rem_dom) new_univ
1101                           )
1102                         in
1103                          res @@ filter univ tl
1104                     | Ko (loc,msg),_ ->
1105                         let res = [],[],[new_env,new_diff,loc,msg,true] in
1106                          res @@ filter univ tl)
1107                in
1108                 let ok_l,uncertain_l,error_l =
1109                  classify_errors (filter base_univ choices)
1110                 in
1111                  let res_after_ok_l =
1112                   List.fold_right
1113                    (fun (env,diff,_,_,univ) res ->
1114                      aux env diff None remaining_dom rem_dom univ @@ res
1115                    ) ok_l ([],[],error_l)
1116                 in
1117                  List.fold_right
1118                   (fun (env,diff,_,_,univ) res ->
1119                     aux env diff None remaining_dom rem_dom univ @@ res
1120                   ) uncertain_l res_after_ok_l
1121       in
1122       let aux' aliases diff lookup_in_todo_dom todo_dom base_univ =
1123        match test_env aliases todo_dom base_univ with
1124         | Ok _,_
1125         | Uncertain _,_ ->
1126            aux aliases diff lookup_in_todo_dom todo_dom [] base_univ
1127         | Ko (loc,msg),_ -> [],[],[aliases,diff,loc,msg,true] in
1128       let base_univ = initial_ugraph in
1129       try
1130         let res =
1131          match aux' aliases [] None todo_dom base_univ with
1132          | [],uncertain,errors ->
1133             let errors =
1134              List.map
1135               (fun (env,diff,loc,msg,_) -> (env,diff,loc,msg,true)
1136               ) uncertain @ errors
1137             in
1138             let errors =
1139              List.map
1140               (fun (env,diff,loc,msg,significant) ->
1141                 let env' =
1142                  filter_map_domain
1143                    (fun locs domain_item ->
1144                      try
1145                       let description =
1146                        fst (Environment.find domain_item env)
1147                       in
1148                        Some (locs,descr_of_domain_item domain_item,description)
1149                      with
1150                       Not_found -> None)
1151                    thing_dom
1152                 in
1153                  env',diff,loc,msg,significant
1154               ) errors
1155             in
1156              raise (NoWellTypedInterpretation (0,errors))
1157          | [_,diff,metasenv,t,ugraph],_,_ ->
1158              debug_print (lazy "SINGLE INTERPRETATION");
1159              [diff,metasenv,t,ugraph], false
1160          | l,_,_ ->
1161              debug_print 
1162                (lazy (sprintf "MANY INTERPRETATIONS (%d)" (List.length l)));
1163              let choices =
1164                List.map
1165                  (fun (env, _, _, _, _) ->
1166                    map_domain
1167                      (fun locs domain_item ->
1168                        let description =
1169                          fst (Environment.find domain_item env)
1170                        in
1171                        locs,descr_of_domain_item domain_item, description)
1172                      thing_dom)
1173                  l
1174              in
1175              let choosed = 
1176                C.interactive_interpretation_choice 
1177                  thing_txt thing_txt_prefix_len choices 
1178              in
1179              (List.map (fun n->let _,d,m,t,u= List.nth l n in d,m,t,u) choosed),
1180               true
1181         in
1182          res
1183      with
1184       CicEnvironment.CircularDependency s -> 
1185         failwith "Disambiguate: circular dependency"
1186
1187     let disambiguate_term ?(fresh_instances=false) ~dbd ~context ~metasenv
1188       ?(initial_ugraph = CicUniv.empty_ugraph) ~aliases ~universe 
1189       (text,prefix_len,term)
1190     =
1191       let term =
1192         if fresh_instances then CicNotationUtil.freshen_term term else term
1193       in
1194       disambiguate_thing ~dbd ~context ~metasenv ~initial_ugraph ~aliases
1195         ~universe ~uri:None ~pp_thing:CicNotationPp.pp_term
1196         ~domain_of_thing:domain_of_term
1197         ~interpretate_thing:interpretate_term
1198         ~refine_thing:refine_term (text,prefix_len,term)
1199
1200     let disambiguate_obj ?(fresh_instances=false) ~dbd ~aliases ~universe ~uri
1201      (text,prefix_len,obj)
1202     =
1203       let obj =
1204         if fresh_instances then CicNotationUtil.freshen_obj obj else obj
1205       in
1206       disambiguate_thing ~dbd ~context:[] ~metasenv:[] ~aliases ~universe ~uri
1207         ~pp_thing:(CicNotationPp.pp_obj CicNotationPp.pp_term) ~domain_of_thing:domain_of_obj
1208         ~interpretate_thing:interpretate_obj ~refine_thing:refine_obj
1209         (text,prefix_len,obj)
1210   end
1211