2 ||M|| This file is part of HELM, an Hypertextual, Electronic
3 ||A|| Library of Mathematics, developed at the Computer Science
4 ||T|| Department, University of Bologna, Italy.
6 ||T|| HELM is free software; you can redistribute it and/or
7 ||A|| modify it under the terms of the GNU General Public License
8 \ / version 2 or (at your option) any later version.
9 \ / This software is distributed as is, NO WARRANTY.
10 V_______________________________________________________________ *)
12 (* $Id: nCic.ml 9058 2008-10-13 17:42:30Z tassi $ *)
17 let debug_print s = if debug then prerr_endline (Lazy.force s) else ()
19 exception Error of string lazy_t
20 let fail msg = raise (Error msg)
22 type lowtac_status = {
24 lstatus : LexiconEngine.status
27 type lowtactic = lowtac_status * int -> lowtac_status * int list * int list
30 gstatus : Continuationals.Stack.t;
31 istatus : lowtac_status;
34 type tactic = tac_status -> tac_status
36 type tactic_term = CicNotationPt.term Disambiguate.disambiguator_input
38 let pp_tac_status status =
39 prerr_endline (NCicPp.ppobj status.istatus.pstatus)
42 open Continuationals.Stack
46 match status.gstatus with
48 | ([], _, [], _) :: _ as stack ->
49 (* backward compatibility: do-nothing-dot *)
51 | (g, t, k, tag) :: s ->
52 match filter_open g, k with
54 (([ loc ], t, loc_tl @+ k, tag) :: s)
57 (([ loc ], t, k, tag) :: s)
58 | _ -> fail (lazy "can't use \".\" here")
60 { status with gstatus = new_gstatus }
63 let branch_tac status =
65 match status.gstatus with
67 | (g, t, k, tag) :: s ->
68 match init_pos g with (* TODO *)
69 | [] | [ _ ] -> fail (lazy "too few goals to branch");
71 ([ loc ], [], [], `BranchTag) :: (loc_tl, t, k, tag) :: s
73 { status with gstatus = new_gstatus }
76 let shift_tac status =
78 match status.gstatus with
79 | (g, t, k, `BranchTag) :: (g', t', k', tag) :: s ->
81 | [] -> fail (lazy "no more goals to shift")
83 (([ loc ], t @+ filter_open g @+ k, [],`BranchTag)
84 :: (loc_tl, t', k', tag) :: s))
85 | _ -> fail (lazy "can't shift goals here")
87 { status with gstatus = new_gstatus }
90 let pos_tac i_s status =
92 match status.gstatus with
94 | ([ loc ], t, [],`BranchTag) :: (g', t', k', tag) :: s
96 let l_js = List.filter (fun (i, _) -> List.mem i i_s) ([loc] @+ g') in
97 ((l_js, t , [],`BranchTag)
98 :: (([ loc ] @+ g') @- l_js, t', k', tag) :: s)
99 | _ -> fail (lazy "can't use relative positioning here")
101 { status with gstatus = new_gstatus }
104 let wildcard_tac status =
106 match status.gstatus with
108 | ([ loc ] , t, [], `BranchTag) :: (g', t', k', tag) :: s
110 (([loc] @+ g', t, [], `BranchTag) :: ([], t', k', tag) :: s)
111 | _ -> fail (lazy "can't use wildcard here")
113 { status with gstatus = new_gstatus }
116 let merge_tac status =
118 match status.gstatus with
120 | (g, t, k,`BranchTag) :: (g', t', k', tag) :: s ->
121 ((t @+ filter_open g @+ g' @+ k, t', k', tag) :: s)
122 | _ -> fail (lazy "can't merge goals here")
124 { status with gstatus = new_gstatus }
127 let focus_tac gs status =
129 match status.gstatus with
131 | s -> assert(gs <> []);
133 let add_l acc _ _ l = if is_open l then l :: acc else acc in
134 fold ~env:add_l ~cont:add_l ~todo:add_l [] s
138 if not (List.exists (fun l -> goal_of_loc l = g) stack_locs) then
139 fail (lazy (sprintf "goal %d not found (or closed)" g)))
141 (zero_pos gs, [], [], `FocusTag) :: deep_close gs s
143 { status with gstatus = new_gstatus }
146 let unfocus_tac status =
148 match status.gstatus with
150 | ([], [], [], `FocusTag) :: s -> s
151 | _ -> fail (lazy "can't unfocus, some goals are still open")
153 { status with gstatus = new_gstatus }
156 let skip_tac status =
158 match status.gstatus with
160 | (gl, t, k, tag) :: s ->
161 let gl = List.map switch_of_loc gl in
162 if List.exists (function Open _ -> true | Closed _ -> false) gl then
163 fail (lazy "cannot skip an open goal")
167 { status with gstatus = new_gstatus }
170 let block_tac l status =
171 List.fold_left (fun status tac -> tac status) status l
174 let compare_menv ~past ~present =
175 List.map fst (List.filter (fun (i,_) -> not (List.mem_assoc i past)) present),
176 List.map fst (List.filter (fun (i,_) -> not (List.mem_assoc i present)) past)
179 (* Exec and distribute_tac form a retraction pair:
180 1) exec (distribute_tac low_tac) (s,i) = low_tac (s,i)
181 2) tac [s]::G = G1::...::Gn::G' && G' is G with some goals closed =>
182 distribute_tac (exec tac) [s]::G = (G1@...Gn)::G'
183 3) tac G = distribute_tac (exec tac) G if
184 tac = distribute_tac lowtac
186 Note that executing an high tactic on a set of goals may be stronger
187 than executing the same tactic on those goals, but once at a time
188 (e.g. the tactic could perform a global analysis of the set of goals)
191 let exec tac (low_status,g) =
192 let stack = [ [0,Open g], [], [], `NoTag ] in
193 let _,_,old_metasenv,_,_ = low_status.pstatus in
194 let status = tac { gstatus = stack ; istatus = low_status } in
195 let _,_,metasenv,_,_ = status.istatus.pstatus in
196 let open_goals, closed_goals =
197 compare_menv ~past:old_metasenv ~present:metasenv
199 status.istatus, open_goals, closed_goals
202 let distribute_tac tac status =
203 match status.gstatus with
205 | (g, t, k, tag) :: s ->
206 debug_print (lazy ("context length " ^string_of_int (List.length g)));
207 let rec aux s go gc =
211 debug_print (lazy "inner eval tactical");
213 if List.exists ((=) (goal_of_loc loc)) gc then
216 match switch_of_loc loc with
217 | Closed _ -> fail (lazy "cannot apply to a Closed goal")
219 let s, go', gc' = tac (s,n) in
220 s, (go @- gc') @+ go', gc @+ gc'
224 let s0, go0, gc0 = status.istatus, [], [] in
225 let sn, gon, gcn = aux s0 go0 gc0 g in
226 debug_print (lazy ("opened: "
227 ^ String.concat " " (List.map string_of_int gon)));
228 debug_print (lazy ("closed: "
229 ^ String.concat " " (List.map string_of_int gcn)));
231 (zero_pos gon, t @~- gcn, k @~- gcn, tag) :: deep_close gcn s
233 { gstatus = stack; istatus = sn }
236 type cic_term = NCic.conjecture
237 type ast_term = string * int * CicNotationPt.term
238 type position = Ctx of NCic.context | Term of cic_term
241 let relocate (name,ctx,t as term) context =
242 let is_prefix l1 l2 =
243 let rec aux = function
245 | x::xs, y::ys -> x=y && aux (xs,ys)
248 aux (List.rev l1, List.rev l2)
250 if ctx = context then term else
251 if is_prefix ctx context then
253 NCicSubstitution.lift (List.length context - List.length ctx) t)
258 let disambiguate (status : lowtac_status) (t : ast_term)
259 (ty : cic_term option) (where : position) =
260 let uri,height,metasenv,subst,obj = status.pstatus in
261 let context = match where with Ctx c -> c | Term (_,c,_) -> c in
264 | None -> None | Some ty -> let _,_,x = relocate ty context in Some x
266 let metasenv, subst, lexicon_status, t =
267 GrafiteDisambiguate.disambiguate_nterm expty
268 status.lstatus context metasenv subst t
270 let new_pstatus = uri,height,metasenv,subst,obj in
271 { lstatus = lexicon_status; pstatus = new_pstatus }, (None, context, t)
274 let select_term low_status (name,context,term) (path, matched) =
275 let eq context (status as old_status) t1 t2 =
276 let _,_,t2 = relocate t2 context in
277 if t2 = t1 then true, status else false, old_status
280 let rec aux ctx status t =
281 let b, status = eq ctx status t m in
283 let n,h,metasenv,subst,o = status.pstatus in
284 let ty = NCicTypeChecker.typeof ~subst ~metasenv ctx t in
285 let metasenv, instance, ty =
286 NCicMetaSubst.mk_meta ~name:"expanded" metasenv ctx (`WithType ty)
288 let metasenv, subst =
289 NCicUnification.unify (NCicUnifHint.db ()) metasenv subst ctx
292 let status = { status with pstatus = n,h,metasenv,subst,o } in
294 else NCicUntrusted.map_term_fold_a (fun e c -> e::c) ctx aux status t
298 let rec select status ctx pat cic =
300 | NCic.Prod (_,s1,t1), NCic.Prod (n,s2,t2) ->
301 let status, s = select status ctx s1 s2 in
302 let ctx = (n, NCic.Decl s2) :: ctx in
303 let status, t = select status ctx t1 t2 in
304 status, NCic.Prod (n,s,t)
305 | NCic.Appl l1, NCic.Appl l2 ->
308 (fun (status,l) x y ->
309 let status, x = select status ctx x y in
314 | NCic.Implicit `Hole, t -> status, t
315 | NCic.Implicit `Term, t ->
316 let status, matched = disambiguate status matched None (Ctx ctx) in
317 match_term matched ctx status t
320 let status, term = select low_status context path term in
321 let _,_,_,subst,_ = status.pstatus in
324 (function (i,(Some "expanded",c,_,_)) -> Some i | _ -> None)
327 status, (name, context, term), selections
330 let get_goal (status : lowtac_status) (g : int) =
331 let _,_,metasenv,_,_ = status.pstatus in
332 List.assoc g metasenv
335 let return ~orig status =
336 let _,_,past,_,_ = orig.pstatus in
337 let _,_,present,_,_ = status.pstatus in
338 let open_goals, closed_goals = compare_menv ~past ~present in
339 status, open_goals, closed_goals
342 let instantiate status i t =
343 let name,height,metasenv,subst,obj = status.pstatus in
344 let _, context, ty = List.assoc i metasenv in
345 let _,_,t = relocate t context in
346 let m = NCic.Meta (i,(0,NCic.Irl (List.length context))) in
347 let db = NCicUnifHint.db () in (* XXX fixme *)
348 let metasenv, subst = NCicUnification.unify db metasenv subst context m t in
349 { status with pstatus = (name,height,metasenv,subst,obj) }
352 let mkmeta name status (_,ctx,ty) =
353 let n,h,metasenv,s,o = status.pstatus in
354 let metasenv, instance, _ =
355 NCicMetaSubst.mk_meta ?name metasenv ctx (`WithType ty)
357 let status = { status with pstatus = n,h,metasenv,s,o } in
358 status, (name,ctx,instance)
361 let apply t (status as orig, goal) =
362 let goalty = get_goal status goal in
363 let status, t = disambiguate status t (Some goalty) (Term goalty) in
364 let status = instantiate status goal t in
368 let change what (*where*) with_what (status as orig, goal) =
369 let (name,_,_ as goalty) = get_goal status goal in
370 let status, newgoalty, selections =
371 select_term status goalty
372 (NCic.Prod ("_",NCic.Implicit `Hole,NCic.Implicit `Term), what)
375 let n,h,metasenv,subst,o = status.pstatus in
377 List.partition (fun i,_ -> not (List.mem i selections)) subst
379 let metasenv = List.map (fun (i,(n,c,_,t)) -> i,(n,c,t)) newm @ metasenv in
380 let status = { status with pstatus = n,h,metasenv,subst,o } in
382 let status = (* queste sono apply, usa un tatticale! *)
385 let x = get_goal status i in
386 let status, with_what =
387 disambiguate status with_what (Some x) (Term x)
389 instantiate status i with_what)
392 let status, m = mkmeta name status newgoalty in
393 let status = instantiate status goal m in
397 let apply t (status,goal) =
398 let uri,height,(metasenv as old_metasenv), subst,obj = status.pstatus in
399 let name,context,gty = List.assoc goal metasenv in
400 let metasenv, subst, lexicon_status, t =
401 GrafiteDisambiguate.disambiguate_nterm (Some gty)
402 status.lstatus context metasenv subst t
404 let subst, metasenv =
405 (goal, (name, context, t, gty)):: subst,
406 List.filter(fun (x,_) -> x <> goal) metasenv
408 let open_goals, closed_goals =
409 compare_menv ~past:old_metasenv ~present:metasenv in
410 let new_pstatus = uri,height,metasenv,subst,obj in
412 prerr_endline ("termine disambiguato: " ^
413 NCicPp.ppterm ~context ~metasenv ~subst t);
414 prerr_endline ("menv:" ^ NCicPp.ppmetasenv ~subst metasenv);
415 prerr_endline ("subst:" ^ NCicPp.ppsubst subst ~metasenv);
416 prerr_endline "fine napply";
418 { lstatus = lexicon_status; pstatus = new_pstatus }, open_goals, closed_goals
421 let apply_tac t = distribute_tac (apply t) ;;
422 let change_tac w ww = distribute_tac (change w ww) ;;