]> matita.cs.unibo.it Git - helm.git/blob - helm/software/helena/src/toplevel/top.ml
new semantics of the -g option completed
[helm.git] / helm / software / helena / src / toplevel / top.ml
1 (*
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.                     
5     ||I||                                                                
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_______________________________________________________________ *)
11
12 module KF = Filename
13 module KP = Printf
14 module KS = String
15
16 module U  = NUri
17 module C  = Cps
18 module L  = Log
19 module Y  = Time
20 module P  = Marks
21 module G  = Options
22 module H  = Hierarchy
23 module N  = Layer
24 module E  = Entity
25 module O  = Output
26 module DO = CrgOutput
27 module TD = TxtCrg
28 module AA = AutProcess
29 module AO = AutOutput
30 module AD = AutCrg
31 module XL = XmlLibrary
32 module XD = XmlCrg
33 module B  = Brg
34 module BD = BrgCrg
35 module BO = BrgOutput
36 module BR = BrgReduction
37 module BU = BrgUntrusted
38 module BG = BrgGrafite
39 module BA = BrgGallina
40 module BP = BrgLP
41 module ZD = BagCrg
42 module ZO = BagOutput
43 module ZT = BagType
44 module ZU = BagUntrusted
45
46 type status = {
47    kst: N.status;
48    tst: TD.status;
49    pst: AA.status;
50    ast: AD.status;
51    ac : AO.counters;
52    dc : DO.counters;
53    bc : BO.counters;
54    zc : ZO.counters;
55    mst: B.manager option;
56 }
57
58 let level = 0
59
60 let bag_error st s msg =
61    L.error st.kst ZO.specs (L.Warn s :: msg) 
62
63 let brg_error st s msg =
64    L.error st.kst BR.specs (L.Warn s :: msg)
65
66 let initial_status () = {
67    kst = N.initial_status ();
68    tst = TD.initial_status ();
69    pst = AA.initial_status ();
70    ast = AD.initial_status ();
71    ac  = AO.initial_counters;
72    dc  = DO.initial_counters;
73    bc  = BO.initial_counters;
74    zc  = ZO.initial_counters;
75    mst = None;
76 }
77
78 let refresh_status st = {st with
79    kst = N.refresh_status st.kst;
80    tst = TD.refresh_status st.tst;
81    ast = AD.refresh_status st.ast;
82 }
83
84 (* kernel related ***********************************************************)
85
86 type kernel_entity = BrgEntity of Brg.entity
87                    | BagEntity of Bag.entity
88                    | CrgEntity of Crg.entity
89
90 let print_counters st = function
91    | G.V4 -> DO.print_counters C.start st.dc
92    | G.V3 -> BO.print_counters C.start st.bc
93    | G.V0 -> ZO.print_counters C.start st.zc
94
95 let xlate_entity st entity = match !G.kernel, entity with
96    | G.V3, CrgEntity e -> 
97       let f e = (BrgEntity e) in E.xlate f BD.brg_of_crg e
98    | G.V0, CrgEntity e -> 
99       let f e = (BagEntity e) in E.xlate f (ZD.bag_of_crg st.kst) e
100    | _, entity          -> entity
101
102 let pp_progress e =
103    let f _ na u =
104       let s = U.string_of_uri u in
105       L.warn 2 (KP.sprintf "[%u] <%s>" na.E.n_apix s);
106    in
107    Y.utime_stamp "intermediate";
108    match e with
109       | CrgEntity e -> E.common f e
110       | BrgEntity e -> E.common f e
111       | BagEntity e -> E.common f e      
112
113 let count_entity st = function
114    | BrgEntity e -> {st with bc = BO.count_entity C.start st.bc e}
115    | BagEntity e -> {st with zc = ZO.count_entity C.start st.zc e}
116    | CrgEntity e -> {st with dc = DO.count_entity C.start st.dc e}
117
118 let export_entity st = function
119    | CrgEntity e -> XL.export_entity (XD.export_term st.kst) e
120    | BrgEntity e -> XL.export_entity (BO.export_term st.kst) e
121    | BagEntity e -> XL.export_entity (ZO.export_term st.kst) e
122
123 let type_check st k =
124    let brg_err msg = brg_error st "Type Error" msg; failwith "Interrupted" in
125    let bag_err msg = bag_error st "Type Error" msg; failwith "Interrupted" in
126    let ok _ _ = st in
127    match k with
128       | BrgEntity entity -> BU.type_check brg_err ok st.kst entity
129       | BagEntity entity -> ZU.type_check bag_err ok st.kst entity
130       | CrgEntity _      -> st
131
132 let validate st k =
133    let brg_err msg = brg_error st "Validation Error" msg; failwith "Interrupted" in
134    let ok _ = st in
135    match k with
136       | BrgEntity entity -> BU.validate brg_err ok st.kst entity
137       | BagEntity _      -> st
138       | CrgEntity _      -> st
139
140 let manager st output_entity = function
141    | BrgEntity entity -> 
142       if output_entity st.kst entity then st else
143       begin L.warn level "manager exportation stopped"; {st with mst = None} end
144    | BagEntity _      -> st
145    | CrgEntity _      -> st
146
147 (* extended lexer ***********************************************************)
148
149 type 'token lexer = {
150    parse : Lexing.lexbuf -> 'token;
151    mutable tokbuf: 'token option;
152    mutable unget : bool
153 }
154
155 let initial_lexer parse = {
156    parse = parse; tokbuf = None; unget = false
157 }
158
159 let token xl lexbuf = match xl.tokbuf with
160    | Some token when xl.unget ->   
161       xl.unget <- false; token
162    | _                        ->
163       let token = xl.parse lexbuf in
164       xl.tokbuf <- Some token; token
165
166 (* input related ************************************************************)
167
168 type input = Text | Automath
169
170 type input_entity = TxtEntity of Txt.command
171                   | AutEntity of Aut.command
172                   | NoEntity
173
174 let type_of_input name =
175    if KF.check_suffix name ".hln" then Text 
176    else if KF.check_suffix name ".aut" then 
177       let _ = H.set_sorts 0 ["Set"; "Prop"] in
178       assert (H.set_graph "Z2");
179       Automath
180    else begin
181       L.warn level (KP.sprintf "Unknown file type: %s" name); exit 2
182    end
183
184 let txt_xl = initial_lexer TxtLexer.token 
185
186 let aut_xl = initial_lexer AutLexer.token 
187
188 let parbuf = ref [] (* parser buffer *)
189
190 let gen_text command = 
191    parbuf := TxtEntity command :: !parbuf
192
193 let entity_of_input lexbuf i = match i, !parbuf with
194    | Automath, _    -> 
195       begin match AutParser.entry (token aut_xl) lexbuf with
196          | Some e -> aut_xl.unget <- true; AutEntity e
197          | None   -> NoEntity
198       end     
199    | Text, []       -> 
200       begin match TxtParser.entry (token txt_xl) lexbuf with
201          | Some e -> txt_xl.unget <- true; TxtEntity e
202          | None   -> NoEntity
203       end
204    | Text, hd :: tl ->
205       parbuf := tl; hd
206
207 let process_input f st = function 
208    | AutEntity e     ->
209       let f pst e = f {st with pst = pst} (AutEntity e) in
210       AA.process_command f st.pst e
211    | xe              -> f st xe
212
213 let count_input st = function
214    | AutEntity e -> {st with ac = AO.count_command C.start st.ac e}
215    | xe          -> st
216
217 (****************************************************************************)
218
219 let version = ref true
220 let preprocess = ref false
221 let root = ref ""
222 let st = ref (initial_status ())
223 let streaming = ref false (* parsing style (temporary) *)
224
225 let process_2 st entity =
226    let st = if !G.summary then count_entity st entity else st in
227    let st = 
228       if !G.stage >= 3 then 
229          let f = if !version then validate else type_check in f st entity
230       else st
231    in
232    if !G.export then export_entity st entity;
233    match st.mst with
234      | None                    -> st
235      | Some (export_entity, _) -> manager st export_entity entity
236
237 let process_1 st entity = 
238    if !G.ct >= 3 then pp_progress entity;
239    let st = if !G.summary then count_entity st entity else st in
240    if !G.export && !G.stage = 1 then export_entity st entity;
241    if !G.stage >= 2 then process_2 st (xlate_entity st entity) else st 
242
243 let process_0 st entity = 
244    let f st entity =
245       if !G.stage = 0 then st else
246       match entity with
247          | AutEntity e -> 
248             let err ast = {st with ast = ast} in
249             let g ast e = process_1 {st with ast = ast} (CrgEntity e) in
250             AD.crg_of_aut err g st.kst st.ast e
251          | TxtEntity e -> 
252             let crr tst = {st with tst = tst} in
253             let d tst e = process_1 {st with tst = tst} (CrgEntity e) in
254             TD.crg_of_txt crr d gen_text st.tst e
255          | NoEntity    -> assert false
256    in
257    let st = if !G.summary then count_input st entity else st in 
258    if !preprocess then process_input f st entity else f st entity
259
260 let process_nostreaming st lexbuf input =
261    let id x = x in
262    let rec aux1 book = match entity_of_input lexbuf input with
263       | NoEntity -> List.rev book
264       | e        -> aux1 (id e :: book)   
265    in
266    let rec aux2 st = function
267       | []           -> st
268       | entity :: tl -> aux2 (process_0 st entity) tl
269    in
270    aux2 st (aux1 [])
271
272 let process_streaming st lexbuf input =
273    let rec aux st = match entity_of_input lexbuf input with
274       | NoEntity -> st
275       | e        -> aux (process_0 st e)
276    in
277    aux st
278
279 (****************************************************************************)
280
281 let process st name =
282    let process = if !streaming then process_streaming else process_nostreaming in
283    let input = type_of_input name in
284    let ich = open_in name in
285    let lexbuf = Lexing.from_channel ich in 
286    let st = process st lexbuf input in
287    close_in ich;
288    st, input
289
290 let main = 
291    let print_version () = L.warn level (G.version_string ^ "\n"); exit 0 in
292    let set_hierarchy s = 
293       if H.set_graph s then () else 
294          L.warn level (KP.sprintf "Unknown type hierarchy: %s" s)
295    in
296    let set_kernel = function
297       | "V3" -> G.kernel := G.V3
298       | "V0" -> G.kernel := G.V0
299       | s    -> L.warn level (KP.sprintf "Unknown kernel version: %s" s)
300    in
301    let set_trace i = 
302       if !G.trace = 0 && i > 0 then Y.gmtime G.version_string;
303       if !G.trace > 0 && i = 0 then Y.utime_stamp "at exit";
304       G.trace := i;
305       if i <= 1 then G.summary := false;
306       if i <= 1 then preprocess := false
307    in
308    let set_summary () = 
309       if !G.trace >= 2 then G.summary := true
310    in 
311    let set_preprocess () = 
312       if !G.trace >= 2 then begin preprocess := true; G.summary := true end 
313    in
314    let set_manager s = match KS.lowercase s with
315       | "v8"  -> G.manager := G.Coq
316       | "ma2" -> G.manager := G.Matita
317       | "lp1" -> G.manager := G.LP1
318       | "lp2" -> G.manager := G.LP2
319       | "tj2" -> G.manager := G.TJ2
320       | "tj3" -> G.manager := G.TJ3
321       | s     -> L.warn level (KP.sprintf "Unknown manager: %s" s) 
322    in
323    let clear_options () =
324       preprocess := false;
325       root := "";
326       G.clear (); H.clear (); O.clear_reductions ();
327       streaming := false;
328       version := true
329    in
330    let process_file name =
331       if !G.trace >= 2 then L.warn 1 (KP.sprintf "Processing file: %s" name);
332       if !G.trace >= 2 then Y.utime_stamp "started";
333       let base_name = Filename.chop_extension (Filename.basename name) in
334       let cover = KF.concat !root base_name in
335       if !G.stage <= 1 then G.kernel := G.V4;
336       G.cover := cover;
337       begin match !G.manager with
338          | G.Coq    -> st := {!st with mst = Some (BA.open_out base_name)}
339          | G.Matita -> st := {!st with mst = Some (BG.open_out base_name)}
340          | G.LP1    -> st := {!st with mst = Some (BP.open_out_lp1 base_name)}
341          | G.LP2    -> st := {!st with mst = Some (BP.open_out_lp2 base_name)}
342          | G.TJ2    -> st := {!st with mst = Some (BP.open_out_tj2 base_name)}
343          | G.TJ3    -> st := {!st with mst = Some (BP.open_out_tj3 base_name)}
344          | G.Quiet  -> ()
345       end;
346       P.clear_marks ();
347       let sst, input = process (refresh_status !st) name in
348       st := begin match sst.mst with 
349          | None                -> sst
350          | Some (_, close_out) -> close_out (); {sst with mst = None}
351       end;
352       if !G.trace >= 2 then Y.utime_stamp "processed";
353       if !G.summary then begin
354          AO.print_counters C.start !st.ac;
355          if !preprocess then AO.print_process_counters C.start !st.pst;
356          if !G.stage >= 1 then print_counters !st G.V4;
357          if !G.stage >= 2 then print_counters !st !G.kernel;
358          if !G.stage >= 3 then O.print_reductions ()
359       end
360    in
361    let exit () =
362       if !G.trace >= 1 then Y.utime_stamp "at exit"
363    in
364    let help = 
365       "Usage: helena [ -LPVXdgilnoqtuxy01 | -Ts <number> | -MO <dir> | -p <file> | -ahkmr <string> | -be <age> ]* [ <file> ]*\n\n" ^
366       "Trace levels: 0 just errors (default), 1 time stamps, 2 processed files, 3 processed objects,\n" ^
367       "              4 typing information, 5 conversion information, 6 reduction information,\n" ^
368       "              7 level disambiguation\n\n" ^
369       "Stages: 0 parsing, 1 to intermediate, 2 to untrusted, 3 to trusted (default)\n\n" ^
370       "Supported manages: \"ma2\" (Grafite NG), \"v8\" (Gallina 8), \"lp1\" \"lp2\" \"tj2\" (lambda-Prolog)\n" 
371    in
372    let help_L = "         [lexer]     Show lexer debug information" in 
373    let help_M = "<dir>    [manager]   Set location of output directory (manager) to <dir> (default: current directory)" in
374    let help_O = "<dir>    [output]    Set location of output directory (XML) to <dir> (default: current directory)" in
375    let help_P = "         [parser]    Show parser debug information" in 
376    let help_T = "<number> [trace]     Set trace level (see above)" in
377    let help_V = "         [version]   Show version information" in
378    let help_X = "                     Clear options" in
379    
380    let help_a = "<string> [alpha]     Set prefix of numeric identifiers (default: empty)" in
381    let help_b = "<age>    [begin]     Begin trace at this global constant (default: first)" in
382    let help_d = "         [data]      Show summary information (requires trace >= 2)" in
383    let help_e = "<age>    [end]       End trace at this global constant (default: last)" in
384    let help_g = "         [global]    Disable age-driven expansion of global definitions (default: enable)" in
385    let help_h = "<string> [hierarchy] Set type hierarchy (default: \"Z1\")" in
386    let help_i = "         [indexes]   Show local references by index" in
387    let help_k = "<string> [kernel]    Set kernel version (default: \"V3\")" in
388    let help_l = "         [layer]     Disambiguate binders layer (Automath)" in
389    let help_m = "<string> [manager]   Export kernel entities for this manager (see above, default: no manager)" in
390    let help_n = "         [names]     Show short constants (default: qualified constants)" in
391    let help_o = "         [objects]   Export kernel entities (XML)" in
392    let help_p = "<file>   [preamble]  Set preamble to this file (default: empty)" in
393    let help_q = "         [quote]     Disable quotation of identifiers (default: enable)" in
394    let help_r = "<string> [root]      Set initial segment of URI hierarchy (default: empty)" in
395    let help_s = "<number> [stage]     Set translation stage (see above)" in
396    let help_t = "         [type]      Type check (default: validate)" in
397    let help_u = "         [upsilon]   Activate type comparison by sort inclusion (default: deactivate)" in
398    let help_x = "         [extended]  Use extended applications (Automath)" in
399    let help_y = "         [infinity]  Use ∞-abstractions in contexts" in
400    let help_0 = "         [zero]      Preprocess source (Automath)" in
401    let help_1 = "         [one]       parse files with streaming policy" in
402    at_exit exit;
403    Arg.parse [
404       ("-L", Arg.Set G.debug_lexer, help_L);
405       ("-M", Arg.String ((:=) G.manager_dir), help_M);
406       ("-O", Arg.String ((:=) G.xdir), help_O);
407       ("-P", Arg.Set G.debug_parser, help_P);
408       ("-T", Arg.Int set_trace, help_T);
409       ("-V", Arg.Unit print_version, help_V);
410       ("-X", Arg.Unit clear_options, help_X);
411       ("-a", Arg.String ((:=) G.alpha), help_a);
412       ("-b", Arg.Int ((:=) G.first), help_b);
413       ("-d", Arg.Unit set_summary, help_d);
414       ("-e", Arg.Int ((:=) G.last), help_e);
415       ("-g", Arg.Set G.expand, help_g);
416       ("-h", Arg.String set_hierarchy, help_h);
417       ("-i", Arg.Set G.indexes, help_i);
418       ("-k", Arg.String set_kernel, help_k);
419       ("-l", Arg.Set G.cc, help_l);
420       ("-m", Arg.String set_manager, help_m);      
421       ("-n", Arg.Set G.short, help_n);
422       ("-o", Arg.Set G.export, help_o);
423       ("-p", Arg.String ((:=) G.preamble), help_p);
424       ("-q", Arg.Set G.unquote, help_q);      
425       ("-r", Arg.String ((:=) root), help_r);
426       ("-s", Arg.Int ((:=) G.stage), help_s);
427       ("-t", Arg.Clear version, help_t);      
428       ("-u", Arg.Set G.si, help_u);
429       ("-x", Arg.Set G.extended, help_x);
430       ("-y", Arg.Set G.infinity, help_y);
431       ("-0", Arg.Unit set_preprocess, help_0);
432       ("-1", Arg.Set streaming, help_1);      
433    ] process_file help