]> matita.cs.unibo.it Git - helm.git/blob - helm/ocaml/tactics/continuationals.ml
ocaml 3.09 transition
[helm.git] / helm / ocaml / tactics / continuationals.ml
1 (* Copyright (C) 2005, 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 open Printf
27
28 let debug = false
29 let debug_print s = if debug then prerr_endline (Lazy.force s) else ()
30
31 exception Error of string lazy_t
32 let fail msg = raise (Error msg)
33
34 type goal = ProofEngineTypes.goal
35
36 module Stack =
37 struct
38   type switch = Open of goal | Closed of goal
39   type locator = int * switch
40   type tag = [ `BranchTag | `FocusTag | `NoTag ]
41   type entry = locator list * locator list * locator list * tag
42   type t = entry list
43
44   let empty = [ [], [], [], `NoTag ]
45
46   let fold ~env ~cont ~todo init stack =
47     let rec aux acc depth =
48       function
49       | [] -> acc
50       | (locs, todos, conts, tag) :: tl ->
51           let acc = List.fold_left (fun acc -> env acc depth tag)  acc locs in
52           let acc = List.fold_left (fun acc -> cont acc depth tag) acc conts in
53           let acc = List.fold_left (fun acc -> todo acc depth tag) acc todos in
54           aux acc (depth + 1) tl
55     in
56     assert (stack <> []);
57     aux init 0 stack
58
59   let iter ~env ~cont ~todo =
60     fold ~env:(fun _ -> env) ~cont:(fun _ -> cont) ~todo:(fun _ -> todo) ()
61
62   let map ~env ~cont ~todo =
63     let depth = ref ~-1 in
64     List.map
65       (fun (s, t, c, tag) ->
66         incr depth;
67         let d = !depth in
68         env d tag s, todo d tag t, cont d tag c, tag)
69
70   let is_open = function _, Open _ -> true | _ -> false
71   let close = function n, Open g -> n, Closed g | l -> l
72   let filter_open = List.filter is_open
73   let is_fresh = function n, Open _ when n > 0 -> true | _ -> false
74   let goal_of_loc = function _, Open g | _, Closed g -> g
75   let goal_of_switch = function Open g | Closed g -> g
76   let switch_of_loc = snd
77
78   let zero_pos = List.map (fun g -> 0, Open g)
79
80   let init_pos locs =
81     let pos = ref 0 in  (* positions are 1-based *)
82     List.map (function _, sw -> incr pos; !pos, sw) locs
83
84   let extract_pos i =
85     let rec aux acc =
86       function
87       | [] -> fail (lazy (sprintf "relative position %d not found" i))
88       | (i', _) as loc :: tl when i = i' -> loc, (List.rev acc) @ tl
89       | hd :: tl -> aux (hd :: acc) tl
90     in
91     aux []
92
93   let deep_close gs =
94     let close _ _ =
95       List.map (fun l -> if List.mem (goal_of_loc l) gs then close l else l)
96     in
97     let rm _ _ = List.filter (fun l -> not (List.mem (goal_of_loc l) gs)) in
98     map ~env:close ~cont:rm ~todo:rm
99
100   let rec find_goal =
101     function
102     | [] -> raise (Failure "Continuationals.find_goal")
103     | (l :: _,   _   ,   _   , _) :: _ -> goal_of_loc l
104     | (  _   ,   _   , l :: _, _) :: _ -> goal_of_loc l
105     | (  _   , l :: _,   _   , _) :: _ -> goal_of_loc l
106     | _ :: tl -> find_goal tl
107
108   let is_empty =
109     function
110     | [] -> assert false
111     | [ [], [], [], `NoTag ] -> true
112     | _ -> false
113
114   let of_metasenv metasenv =
115     let goals = List.map (fun (g, _, _) -> g) metasenv in
116     [ zero_pos goals, [], [], `NoTag ]
117
118   let head_switches =
119     function
120     | (locs, _, _, _) :: _ -> List.map switch_of_loc locs
121     | [] -> assert false
122
123   let head_goals =
124     function
125     | (locs, _, _, _) :: _ -> List.map goal_of_loc locs
126     | [] -> assert false
127
128   let head_tag =
129     function
130     | (_, _, _, tag) :: _ -> tag
131     | [] -> assert false
132
133   let shift_goals =
134     function
135     | _ :: (locs, _, _, _) :: _ -> List.map goal_of_loc locs
136     | [] -> assert false
137     | _ -> []
138
139   let open_goals stack =
140     let add_open acc _ _ l = if is_open l then goal_of_loc l :: acc else acc in
141     List.rev (fold ~env:add_open ~cont:add_open ~todo:add_open [] stack)
142
143   let (@+) = (@)  (* union *)
144
145   let (@-) s1 s2 =  (* difference *)
146     List.fold_right
147       (fun e acc -> if List.mem e s2 then acc else e :: acc)
148       s1 []
149
150   let (@~-) locs gs = (* remove some goals from a locators list *)
151     List.fold_right
152       (fun loc acc -> if List.mem (goal_of_loc loc) gs then acc else loc :: acc)
153       locs []
154
155   let pp stack =
156     let pp_goal = string_of_int in
157     let pp_switch =
158       function Open g -> "o" ^ pp_goal g | Closed g -> "c" ^ pp_goal g
159     in
160     let pp_loc (i, s) = string_of_int i ^ pp_switch s in
161     let pp_env env = sprintf "[%s]" (String.concat ";" (List.map pp_loc env)) in
162     let pp_tag = function `BranchTag -> "B" | `FocusTag -> "F" | `NoTag -> "N" in
163     let pp_stack_entry (env, todo, cont, tag) =
164       sprintf "(%s, %s, %s, %s)" (pp_env env) (pp_env todo) (pp_env cont)
165         (pp_tag tag)
166     in
167     String.concat " :: " (List.map pp_stack_entry stack)
168 end
169
170 module type Status =
171 sig
172   type input_status
173   type output_status
174
175   type tactic
176
177   val id_tactic : tactic
178   val mk_tactic : (input_status -> output_status) -> tactic
179   val apply_tactic : tactic -> input_status -> output_status
180
181   val goals : output_status -> goal list * goal list (** opened, closed goals *)
182   val set_goals: goal list * goal list -> output_status -> output_status
183   val get_stack : input_status -> Stack.t
184   val set_stack : Stack.t -> output_status -> output_status
185
186   val inject : input_status -> output_status
187   val focus : goal -> output_status -> input_status
188 end
189
190 module type C =
191 sig
192   type input_status
193   type output_status
194   type tactic
195
196   type tactical =
197     | Tactic of tactic
198     | Skip
199
200   type t =
201     | Dot
202     | Semicolon
203
204     | Branch
205     | Shift
206     | Pos of int
207     | Merge
208
209     | Focus of goal list
210     | Unfocus
211
212     | Tactical of tactical
213
214   val eval: t -> input_status -> output_status
215 end
216
217 module Make (S: Status) =
218 struct
219   open Stack
220
221   type input_status = S.input_status
222   type output_status = S.output_status
223   type tactic = S.tactic
224
225   type tactical =
226     | Tactic of tactic
227     | Skip
228
229   type t =
230     | Dot
231     | Semicolon
232     | Branch
233     | Shift
234     | Pos of int
235     | Merge
236     | Focus of goal list
237     | Unfocus
238     | Tactical of tactical
239
240   let pp_t =
241     function
242     | Dot -> "Dot"
243     | Semicolon -> "Semicolon"
244     | Branch -> "Branch"
245     | Shift -> "Shift"
246     | Pos i -> "Pos " ^ string_of_int i
247     | Merge -> "Merge"
248     | Focus gs ->
249         sprintf "Focus [%s]" (String.concat "; " (List.map string_of_int gs))
250     | Unfocus -> "Unfocus"
251     | Tactical _ -> "Tactical <abs>"
252
253   let eval_tactical tactical ostatus switch =
254     match tactical, switch with
255     | Tactic tac, Open n ->
256         let ostatus = S.apply_tactic tac (S.focus n ostatus) in
257         let opened, closed = S.goals ostatus in
258         ostatus, opened, closed
259     | Skip, Closed n -> ostatus, [], [n]
260     | Tactic _, Closed _ -> fail (lazy "can't apply tactic to a closed goal")
261     | Skip, Open _ -> fail (lazy "can't skip an open goal")
262
263   let eval cmd istatus =
264     let stack = S.get_stack istatus in
265     debug_print (lazy (sprintf "EVAL CONT %s <- %s" (pp_t cmd) (pp stack)));
266     let new_stack stack = S.inject istatus, stack in
267     let ostatus, stack =
268       match cmd, stack with
269       | _, [] -> assert false
270       | Tactical tac, (g, t, k, tag) :: s ->
271           if g = [] then fail (lazy "can't apply a tactic to zero goals");
272           debug_print (lazy ("context length " ^string_of_int (List.length g)));
273           let rec aux s go gc =
274             function
275             | [] -> s, go, gc
276             | loc :: loc_tl ->
277                 debug_print (lazy "inner eval tactical");
278                 let s, go, gc =
279                   if List.exists ((=) (goal_of_loc loc)) gc then
280                     s, go, gc
281                   else
282                     let s, go', gc' = eval_tactical tac s (switch_of_loc loc) in
283                     s, (go @- gc') @+ go', gc @+ gc'
284                 in
285                 aux s go gc loc_tl
286           in
287           let s0, go0, gc0 = S.inject istatus, [], [] in
288           let sn, gon, gcn = aux s0 go0 gc0 g in
289           debug_print (lazy ("opened: "
290             ^ String.concat " " (List.map string_of_int gon)));
291           debug_print (lazy ("closed: "
292             ^ String.concat " " (List.map string_of_int gcn)));
293           let stack =
294             (zero_pos gon, t @~- gcn, k @~- gon, tag) :: deep_close gcn s
295           in
296           sn, stack
297       | Dot, ([], _, [], _) :: _ ->
298           (* backward compatibility: do-nothing-dot *)
299           new_stack stack
300       | Dot, (g, t, k, tag) :: s ->
301           (match filter_open g, k with
302           | loc :: loc_tl, _ -> new_stack (([ loc ], t, loc_tl @+ k, tag) :: s)
303           | [], loc :: k ->
304               assert (is_open loc);
305               new_stack (([ loc ], t, k, tag) :: s)
306           | _ -> fail (lazy "can't use \".\" here"))
307       | Semicolon, _ -> new_stack stack
308       | Branch, (g, t, k, tag) :: s ->
309           (match init_pos g with
310           | [] | [ _ ] -> fail (lazy "too few goals to branch");
311           | loc :: loc_tl ->
312               new_stack
313                 (([ loc ], [], [], `BranchTag) :: (loc_tl, t, k, tag) :: s))
314       | Shift, (g, t, k, `BranchTag) :: (g', t', k', tag) :: s ->
315           (match g' with
316           | [] -> fail (lazy "no more goals to shift")
317           | loc :: loc_tl ->
318               new_stack
319                 (([ loc ], t @+ filter_open g, [],`BranchTag)
320                 :: (loc_tl, t', k', tag) :: s))
321       | Shift, _ -> fail (lazy "can't shift goals here")
322       | Pos i, ([ loc ], [], [],`BranchTag) :: (g', t', k', tag) :: s
323         when is_fresh loc ->
324           let loc_i, g' = extract_pos i g' in
325           new_stack
326             (([ loc_i ], [], [],`BranchTag)
327              :: ([ loc ] @+ g', t', k', tag) :: s)
328       | Pos i, (g, t, k,`BranchTag) :: (g', t', k', tag) :: s ->
329           let loc_i, g' = extract_pos i g' in
330           new_stack
331             (([ loc_i ], [], [],`BranchTag)
332              :: (g', t' @+ filter_open g, k', tag) :: s)
333       | Pos _, _ -> fail (lazy "can't use relative positioning here")
334       | Merge, (g, t, k,`BranchTag) :: (g', t', k', tag) :: s ->
335           new_stack ((t @+ filter_open g @+ g' @+ k, t', k', tag) :: s)
336       | Merge, _ -> fail (lazy "can't merge goals here")
337       | Focus [], _ -> assert false
338       | Focus gs, s ->
339           let stack_locs =
340             let add_l acc _ _ l = if is_open l then l :: acc else acc in
341             Stack.fold ~env:add_l ~cont:add_l ~todo:add_l [] s
342           in
343           List.iter
344             (fun g ->
345               if not (List.exists (fun l -> goal_of_loc l = g) stack_locs) then
346                 fail (lazy (sprintf "goal %d not found (or closed)" g)))
347             gs;
348           new_stack ((zero_pos gs, [], [], `FocusTag) :: deep_close gs s)
349       | Unfocus, ([], [], [], `FocusTag) :: s -> new_stack s
350       | Unfocus, _ -> fail (lazy "can't unfocus, some goals are still open")
351     in
352     debug_print (lazy (sprintf "EVAL CONT %s -> %s" (pp_t cmd) (pp stack)));
353     S.set_stack stack ostatus
354 end
355