]> matita.cs.unibo.it Git - helm.git/blob - helm/software/helena/src/toplevel/top.ml
additional commit for version 0.8.2
[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 ZD = BagCrg
41 module ZO = BagOutput
42 module ZT = BagType
43 module ZU = BagUntrusted
44
45 type status = {
46    kst: N.status;
47    tst: TD.status;
48    pst: AA.status;
49    ast: AD.status;
50    ac : AO.counters;
51    dc : DO.counters;
52    bc : BO.counters;
53    zc : ZO.counters;
54    mst: B.manager option;
55 }
56
57 let level = 0
58
59 let bag_error st s msg =
60    L.error st.kst ZO.specs (L.Warn s :: msg) 
61
62 let brg_error st s msg =
63    L.error st.kst BR.specs (L.Warn s :: msg)
64
65 let initial_status () = {
66    kst = N.initial_status ();
67    tst = TD.initial_status ();
68    pst = AA.initial_status ();
69    ast = AD.initial_status ();
70    ac  = AO.initial_counters;
71    dc  = DO.initial_counters;
72    bc  = BO.initial_counters;
73    zc  = ZO.initial_counters;
74    mst = None;
75 }
76
77 let refresh_status st = {st with
78    kst = N.refresh_status st.kst;
79    tst = TD.refresh_status st.tst;
80    ast = AD.refresh_status st.ast;
81 }
82
83 (* kernel related ***********************************************************)
84
85 type kernel_entity = BrgEntity of Brg.entity
86                    | BagEntity of Bag.entity
87                    | CrgEntity of Crg.entity
88
89 let print_counters st = function
90    | G.V4 -> DO.print_counters C.start st.dc
91    | G.V3 -> BO.print_counters C.start st.bc
92    | G.V0 -> ZO.print_counters C.start st.zc
93
94 let xlate_entity st entity = match !G.kernel, entity with
95    | G.V3, CrgEntity e -> 
96       let f e = (BrgEntity e) in E.xlate f BD.brg_of_crg e
97    | G.V0, CrgEntity e -> 
98       let f e = (BagEntity e) in E.xlate f (ZD.bag_of_crg st.kst) e
99    | _, entity          -> entity
100
101 let pp_progress e =
102    let f _ na u =
103       let s = U.string_of_uri u in
104       L.warn 2 (KP.sprintf "[%u] <%s>" na.E.n_apix s);
105    in
106    Y.utime_stamp "intermediate";
107    match e with
108       | CrgEntity e -> E.common f e
109       | BrgEntity e -> E.common f e
110       | BagEntity e -> E.common f e      
111
112 let count_entity st = function
113    | BrgEntity e -> {st with bc = BO.count_entity C.start st.bc e}
114    | BagEntity e -> {st with zc = ZO.count_entity C.start st.zc e}
115    | CrgEntity e -> {st with dc = DO.count_entity C.start st.dc e}
116
117 let export_entity st = function
118    | CrgEntity e -> XL.export_entity (XD.export_term st.kst) e
119    | BrgEntity e -> XL.export_entity (BO.export_term st.kst) e
120    | BagEntity e -> XL.export_entity (ZO.export_term st.kst) e
121
122 let type_check st k =
123    let brg_err msg = brg_error st "Type Error" msg; failwith "Interrupted" in
124    let bag_err msg = bag_error st "Type Error" msg; failwith "Interrupted" in
125    let ok _ _ = st in
126    match k with
127       | BrgEntity entity -> BU.type_check brg_err ok st.kst entity
128       | BagEntity entity -> ZU.type_check bag_err ok st.kst entity
129       | CrgEntity _      -> st
130
131 let validate st k =
132    let brg_err msg = brg_error st "Validation Error" msg; failwith "Interrupted" in
133    let ok _ = st in
134    match k with
135       | BrgEntity entity -> BU.validate brg_err ok st.kst entity
136       | BagEntity _      -> st
137       | CrgEntity _      -> st
138
139 let manager st output_entity = function
140    | BrgEntity entity -> 
141       if output_entity st.kst entity then st else
142       begin L.warn level "manager exportation stopped"; {st with mst = None} end
143    | BagEntity _      -> st
144    | CrgEntity _      -> st
145
146 (* extended lexer ***********************************************************)
147
148 type 'token lexer = {
149    parse : Lexing.lexbuf -> 'token;
150    mutable tokbuf: 'token option;
151    mutable unget : bool
152 }
153
154 let initial_lexer parse = {
155    parse = parse; tokbuf = None; unget = false
156 }
157
158 let token xl lexbuf = match xl.tokbuf with
159    | Some token when xl.unget ->   
160       xl.unget <- false; token
161    | _                        ->
162       let token = xl.parse lexbuf in
163       xl.tokbuf <- Some token; token
164
165 (* input related ************************************************************)
166
167 type input = Text | Automath
168
169 type input_entity = TxtEntity of Txt.command
170                   | AutEntity of Aut.command
171                   | NoEntity
172
173 let type_of_input name =
174    if KF.check_suffix name ".hln" then Text 
175    else if KF.check_suffix name ".aut" then 
176       let _ = H.set_sorts 0 ["Set"; "Prop"] in
177       assert (H.set_graph "Z2");
178       Automath
179    else begin
180       L.warn level (KP.sprintf "Unknown file type: %s" name); exit 2
181    end
182
183 let txt_xl = initial_lexer TxtLexer.token 
184
185 let aut_xl = initial_lexer AutLexer.token 
186
187 let parbuf = ref [] (* parser buffer *)
188
189 let gen_text command = 
190    parbuf := TxtEntity command :: !parbuf
191
192 let entity_of_input lexbuf i = match i, !parbuf with
193    | Automath, _    -> 
194       begin match AutParser.entry (token aut_xl) lexbuf with
195          | Some e -> aut_xl.unget <- true; AutEntity e
196          | None   -> NoEntity
197       end     
198    | Text, []       -> 
199       begin match TxtParser.entry (token txt_xl) lexbuf with
200          | Some e -> txt_xl.unget <- true; TxtEntity e
201          | None   -> NoEntity
202       end
203    | Text, hd :: tl ->
204       parbuf := tl; hd
205
206 let process_input f st = function 
207    | AutEntity e     ->
208       let f pst e = f {st with pst = pst} (AutEntity e) in
209       AA.process_command f st.pst e
210    | xe              -> f st xe
211
212 let count_input st = function
213    | AutEntity e -> {st with ac = AO.count_command C.start st.ac e}
214    | xe          -> st
215
216 (****************************************************************************)
217
218 let version = ref true
219 let preprocess = ref false
220 let root = ref ""
221 let export = ref false
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 !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.trace >= 3 then pp_progress entity;
239    let st = if !G.summary then count_entity st entity else st in
240    if !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       | s     -> L.warn level (KP.sprintf "Unknown manager: %s" s) 
318    in
319    let clear_options () =
320       export := false; preprocess := false;
321       root := "";
322       G.clear (); H.clear (); O.clear_reductions ();
323       streaming := false;
324       version := true
325    in
326    let process_file name =
327       if !G.trace >= 2 then L.warn 1 (KP.sprintf "Processing file: %s" name);
328       if !G.trace >= 2 then Y.utime_stamp "started";
329       let base_name = Filename.chop_extension (Filename.basename name) in
330       let cover = KF.concat !root base_name in
331       if !G.stage <= 1 then G.kernel := G.V4;
332       G.cover := cover;
333       begin match !G.manager with
334          | G.Matita -> st := {!st with mst = Some (BG.open_out base_name)}
335          | G.Coq    -> st := {!st with mst = Some (BA.open_out base_name)}
336          | G.Quiet  -> ()
337       end;
338       P.clear_marks ();
339       let sst, input = process (refresh_status !st) name in
340       st := begin match sst.mst with 
341          | None                -> sst
342          | Some (_, close_out) -> close_out (); {sst with mst = None}
343       end;
344       if !G.trace >= 2 then Y.utime_stamp "processed";
345       if !G.summary then begin
346          AO.print_counters C.start !st.ac;
347          if !preprocess then AO.print_process_counters C.start !st.pst;
348          if !G.stage >= 1 then print_counters !st G.V4;
349          if !G.stage >= 2 then print_counters !st !G.kernel;
350          if !G.stage >= 3 then O.print_reductions ()
351       end
352    in
353    let exit () =
354       if !G.trace >= 1 then Y.utime_stamp "at exit"
355    in
356    let help = 
357       "Usage: helena [ -LPVXdgilopqtx1 | -Ts <number> | -MO <dir> | -c <file> | -ahkmr <string> ]* [ <file> ]*\n\n" ^
358       "Trace levels: 0 just errors (default), 1 time stamps, 2 processed files, 3 processed objects,\n" ^
359       "              4 typing information, 5 conversion information, 6 reduction information,\n" ^
360       "              7 level disambiguation\n\n" ^
361       "Stages: 0 parsing, 1 to intermediate, 2 to untrusted, 3 to trusted (default)\n"
362    in
363    let help_L = " show lexer debug information" in 
364    let help_M = "<dir>  set location of output directory (manager) to <dir> (default: current directory)" in
365    let help_O = "<dir>  set location of output directory (XML) to <dir> (default: current directory)" in
366    let help_P = " show parser debug information" in 
367    let help_T = "<number>  set trace level (see above)" in
368    let help_V = " show version information" in
369    let help_X = " clear options" in
370    
371    let help_a = "<string>  set prefix of numeric identifiers (default: empty)" in
372    let help_c = "<file>  set preamble to this file (default: empty)" in
373    let help_d = " show summary information (requires trace >= 2)" in
374    let help_g = " always expand global definitions" in
375    let help_h = "<string>  set type hierarchy (default: \"Z1\")" in
376    let help_i = " show local references by index" in
377    let help_k = "<string>  set kernel version (default: \"V3\")" in
378    let help_l = " disambiguate binders level (Automath)" in
379    let help_m = "<string>  export kernel entities for this manager (default: no manager, \"ma2\": Grafite NG, \"v8\": Gallina 8)" in
380    let help_o = " activate sort inclusion (default: false)" in
381    let help_p = " preprocess source (Automath)" in
382    let help_q = " disable quotation of identifiers" in
383    let help_r = "<string>  set initial segment of URI hierarchy (default: empty)" in
384    let help_s = "<number>  set translation stage (see above)" in
385    let help_t = " type check [version 1]" in
386    let help_x = " export kernel entities (XML)" in
387    
388    let help_1 = " parse files with streaming policy" in
389    at_exit exit;
390    Arg.parse [
391       ("-L", Arg.Set G.debug_lexer, help_L);
392       ("-M", Arg.String ((:=) G.manager_dir), help_M);
393       ("-O", Arg.String ((:=) G.xdir), help_O);
394       ("-P", Arg.Set G.debug_parser, help_P);
395       ("-T", Arg.Int set_trace, help_T);
396       ("-V", Arg.Unit print_version, help_V);
397       ("-X", Arg.Unit clear_options, help_X);
398       ("-a", Arg.String ((:=) G.alpha), help_a);
399       ("-c", Arg.String ((:=) G.preamble), help_c);
400       ("-d", Arg.Unit set_summary, help_d);
401       ("-g", Arg.Set G.expand, help_g);
402       ("-h", Arg.String set_hierarchy, help_h);
403       ("-i", Arg.Set G.indexes, help_i);
404       ("-k", Arg.String set_kernel, help_k);
405       ("-l", Arg.Set G.cc, help_l);
406       ("-m", Arg.String set_manager, help_m);      
407       ("-o", Arg.Set G.si, help_o);
408       ("-p", Arg.Unit set_preprocess, help_p);
409       ("-q", Arg.Set G.unquote, help_q);      
410       ("-r", Arg.String ((:=) root), help_r);
411       ("-s", Arg.Int ((:=) G.stage), help_s);
412       ("-t", Arg.Clear version, help_t);      
413       ("-x", Arg.Set export, help_x);
414       ("-1", Arg.Set streaming, help_1);      
415    ] process_file help