Skip to content

HTTPS clone URL

Subversion checkout URL

You can clone with
or
.
Download ZIP
Newer
Older
100644 784 lines (678 sloc) 22.579 kB
fccc685 Initial open-source release
MLstate authored
1 (*
2 Copyright © 2011 MLstate
3
4 This file is part of OPA.
5
6 OPA is free software: you can redistribute it and/or modify it under the
7 terms of the GNU Affero General Public License, version 3, as published by
8 the Free Software Foundation.
9
10 OPA is distributed in the hope that it will be useful, but WITHOUT ANY
11 WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS
12 FOR A PARTICULAR PURPOSE. See the GNU Affero General Public License for
13 more details.
14
15 You should have received a copy of the GNU Affero General Public License
16 along with OPA. If not, see <http://www.gnu.org/licenses/>.
17 *)
18 (* CF mli *)
19
20 (* type alias *)
21 type filename = string
22 type contents = string
23 type item_number = int
24
25 (* depends *)
26 module String = Base.String
27
28 (* refactoring *)
29
30 (* shorthands *)
31 module Q = QmlAst
32 module CP = ConsoleParser
33 module P = OpaTopProperties
34
35 (* Selection of modules *)
36 module Schema = QmlDbGen.Schema
37 module DbGen = QmlDbGen.DbGen(QmlDbGen.DbGenByPass.BSLDbGenAlpha)
38 module Typer = QmlTyper.DyTyper.HighTyper
39
40 (* go *)
41
42 (* error reporting *)
43
44 exception OManagerException
45
46 let set_OManager_at_exit () =
47 let at_exit =
48 { OManager.at_exit =
49 (fun i ->
50 if P.greedy_get () then
51 raise OManagerException
52 else
53 exit i)
54 } in
55 OManager.CompilerAsLib.at_exit at_exit
56
57 (* output *)
58 (* FIXME: clarification in OManager,
59 let rename the formatter OManager.stderr and OManager.stdout,
60 and use there OManager.stdout instead of P.stdout (and remove P.stdout)
61 *)
62 let std = P.stdout
63
64 (*
65 Private Console Parser
66 *)
67 let t_CP = CP.create ()
68 let console_parser () = t_CP
69
70 (* printer *)
71 let pp =
72 #<If:OPATOP_ANNOT>
73 QmlPrint.pp_annotation
74 #<Else>
75 (QmlPrint.pp :> QmlPrint.base_printer_with_sugared_types)
76 #<End>
77
78 (* env *)
79
80 type schema = Building of Schema.t | Finalized of Schema.t
81
82 type env = {
83 (*
84 Db stuff
85 *)
86 dbinfo : QmlDbGen.dbinfo StringListMap.t option;
87 open_db : bool;
88 schema : schema;
89
90 (*
91 Environments
92 *)
93 bypass_map : OpaTopBsl.bypass_map ;
94 env_types : QmlTyper.env ;
95 env_values : OpaTopEval.env ;
96
97 (*
98 Context of input
99 *)
100 input_filename : filename ; (** Name of the file parsed. *)
101 input_item_number : item_number ; (** The number of toplevel item parsed.
102 Attention, this is not the line number since some items may span on
103 several lines. *)
104 }
105
106 (*
107 Directive handler. In practice, updated with OpaTopDirective.handler
108 *)
109 let directive_handler =
110 ref ( ( ConsoleParser.Directive.empty ()) : env ConsoleParser.Directive.handler )
111
112 let set_directive_handler handler =
113 directive_handler := handler
114
115 let cache_initial = ref ( None : env option )
116
117 let ty_null = Q.TypeConst Q.TyNull
118 let value_null = OpaTopValue.t_null ()
119
120 let find_opt ident env =
121 let ty =
122 match QmlTypes.Env.Ident.find_opt ident env.env_types.QmlTypes.gamma with
123 | None -> None
124 | Some type_scheme ->
125 let ty = QmlTypes.Scheme.instantiate type_scheme in
126 Some ty
127 in
128 let value = IdentMap.find_opt ident env.env_values in
129 match ty, value with
130 | None, None -> None
131 | _, _ ->
132 let ty = Option.default ty_null ty in
133 let value = Option.default value_null value in
134 Some (ty, value)
135
136 let iter iter env =
137 let iter ident value =
138 let ty =
139 match QmlTypes.Env.Ident.find_opt ident env.env_types.QmlTypes.gamma with
140 | Some type_scheme ->
141 let ty = QmlTypes.Scheme.instantiate type_scheme in
142 ty
143 | None ->
144 ty_null
145 in
146 iter ident ty value
147 in
148 IdentMap.iter iter env.env_values
149
150 let fold fold env acc =
151 let fold ident value acc =
152 let ty =
153 match QmlTypes.Env.Ident.find_opt ident env.env_types.QmlTypes.gamma with
154 | Some type_scheme ->
155 let ty = QmlTypes.Scheme.instantiate type_scheme in
156 ty
157 | None ->
158 ty_null
159 in
160 fold ident ty value acc
161 in
162 IdentMap.fold fold env.env_values acc
163
164 let set_schema env schema =
165 { env with
166 schema = Finalized schema;
167 open_db = true
168 }
169
170 let set_filename env filename =
171 { env with
172 input_filename = filename
173 }
174
175 let set_item_number env item_number =
176 { env with
177 input_item_number = item_number
178 }
179
180
181 let schema env = match env.schema with Building s | Finalized s -> s
182
183 let types env = env.env_types
184 let values env = env.env_values
185 let bypass_map env = env.bypass_map
186
187 (* INPUT *)
188 (*
189 Note: the code is splitten for lisibility, and avoid a too big function.
190 *)
191
192 (*
193 New design : simple.
194
195 We have only 2 functions, working on expressions,
196 one for the typer, one for the evaluater.
197
198 No more typer off, the typer should work, that's all.
199 Whenever we need to access types or values, we can use the annotmap.
200 *)
201
202 let try_infer typer env arg =
203 try typer env arg with
204 | (QmlTyperException.Exception _ | QmlTypes.Exception _) as exn ->
205 OManager.error "%a"
206 (QmlTyperErrHandling.pp_report_from_typer_exception
ed8052e @fpessaux [cleanup] Typer exceptions: Removed no more raised exceptions and rel…
fpessaux authored
207 env.QmlTypes.annotmap) exn
fccc685 Initial open-source release
MLstate authored
208
209
210
211 let fold_type_wrap fold env arg =
212 let env_types = env.env_types in
213 let env_types = (try_infer fold) env_types arg in
214 { env with env_types = env_types }
215
216 let fold_type_expr env expr = fold_type_wrap Typer.fold_expr env expr
217 let fold_type_elt env elt = fold_type_wrap Typer.fold_elt env elt
218
219 (*
220 FIXME: use a functionnal annotmap for values.
221 Currently, this is done with a side effect in an imperative
222 table in OpaTopEval.
223 *)
224 let fold_eval_expr env expr =
225 let env_values = env.env_values in
226 let _ = OpaTopEval.eval env_values expr in
227 env
228
229 (* after a UnValRec, the env need to be enriched *)
230 let fold_eval_val_list env val_list =
231 if P.noeval_get() then env else
232 let fold env_values (id, expr) =
233 let annot = Q.QAnnot.expr expr in
234 let value =
235 match OpaTopEval.getValueOfAnnot annot with
236 | None ->
237 (* TODO: citation, with field0(expr) *)
238 OManager.i_error "id,expr : (%s, %a), annotation not found"
239 (Ident.to_string id) pp#expr expr
240 | Some value -> value
241 in
242 let env_values = IdentMap.add id value env_values in
243 env_values
244 in
245 let env_values = List.fold_left fold env.env_values val_list in
246 let env =
247 { env with
248 env_values = env_values ;
249 }
250 in
251 env
252
253 let input_code_elt_Database env database =
254 match database with
255 | Q.Database (label, ident, p, opts) -> (
256 match env.schema with
257 | Building schema ->
258 let (schema, gamma) =
259 Schema.register_db_declaration schema env.env_types.QmlTypes.gamma (label, ident, p, opts)
260 in
261 { env with
262 schema = Building schema ;
263 open_db = true ;
264 env_types = { env.env_types with QmlTypes.gamma = gamma } ;
265 }
266 | _ ->
267 OManager.error
268 "DB: The schema of the database is already @{<bright>finalized@}@\nYou cannot change its file anymore"
269 )
270 | _ -> assert false
271
272 let input_code_elt_NewDbValue env newDbValue =
273 match env.schema with
274 | Building schema -> (
275 let (env, dbdef, schema) =
276 match newDbValue with
277 | Q.NewDbValue (label, (Q.Db.Db_Default _ as dbdef)) ->
278 let schema, o =
279 Schema.register_new_db_value ~name_default_values:false
280 schema env.env_types.QmlTypes.gamma (label, dbdef)
281 in
282 assert (o = None);
283 (* Note: we retype all previous defaults, for each new default,
284 which is unnecessarily costly, but has very simple code. *)
285 let env = Schema.fold_expr fold_type_expr env schema in
286 (env, dbdef, schema)
287 | Q.NewDbValue (label, dbdef) ->
288 let schema, o =
289 Schema.register_new_db_value ~name_default_values:false
290 schema env.env_types.QmlTypes.gamma (label, dbdef)
291 in
292 assert (o = None);
293 (env, dbdef, schema)
294 | _ -> assert false
295 in
296 let env, _ =
297 Q.Db.foldmap_expr (fun env e -> let env = fold_eval_expr env e in env, e) env dbdef in
298 { env with
299 schema = Building schema ;
300 open_db = true ;
301 }
302 )
303 | Finalized _ ->
304 OManager.error
305 "DB: The schema of the database is already @{<bright>finalized@}@\nYou cannot add new db declarations anymore"
306
307 let dbgen_pass env code_elt =
308 match env.dbinfo, env.schema with
309 | Some dbinfo, Finalized schema -> (
310
311 let _ =
312 #<If:OPATOP_HOOK>
313 prerr_endline "dbgen_pass: HOOK-A-01";
314 #<End>
315 in
316
317 let annotmap = env.env_types.QmlTypes.annotmap in
318 let gamma = env.env_types.QmlTypes.gamma in
319 let annotmap_opt, code_elt, gamma =
320 DbGen.replace_path_code_elt schema dbinfo gamma ~annotmap:(Some annotmap) code_elt
321 in
322
323 let _ =
324 #<If:OPATOP_HOOK>
325 prerr_endline "dbgen_pass: HOOK-A-02";
326 #<End>
327 in
328
329 let dbgen_annotmap = match annotmap_opt with Some a -> a | None -> assert false in
330 let annotmap =
331 QmlAnnotMap.merge annotmap dbgen_annotmap
332 in
333 let env_types =
334 { env.env_types with QmlTypes.
335 annotmap;
336 gamma;
337 }
338 in
339 let env =
340 { env with
341 env_types = env_types
342 }
343 in
344 if OpaTopProperties.dddbgen_get ()
345 then (
346 OManager.printf "/* ================================================ */@\n";
347 OManager.printf "/* dddben : db read/write resolution */@\n";
348 OManager.printf "%a@\n" pp#code_elt code_elt;
349 OManager.printf "/* ================================================ */@\n";
350 OManager.printf "@.";
351 ()
352 );
353 env, code_elt
354 )
355 | _ ->
356 (* the expression does not use the db, because the db is still not finalized *)
357 let _ =
358 #<If:OPATOP_HOOK>
359 prerr_endline "dbgen_pass: HOOK-B-01";
360 #<End>
361 in
362 env, code_elt
363
364 (*
365 TODO: merge pos for a better error report,
366 by using a pos IdentMap.t instead of a IdentSet
367 *)
368 let check_no_duplicate val_list =
369 let fold_check check (ident, _) =
370 if IdentSet.mem ident check
371 then OManager.error "The ident @{<bright>%s@} is bound several time in this @{<bright>val and@}" (Ident.to_string ident)
372 else IdentSet.add ident check
373 in
374 let _ = List.fold_left fold_check IdentSet.empty val_list in
375 ()
376
377 let input_code_elt_NewType env code_elt = fold_type_elt env code_elt
378
379 let initialize_dbgen env val_list =
380 let env =
381 match env.dbinfo, env.open_db with
382 | None, true ->
383 let use_db = List.exists (fun (_, exp) -> QmlAstWalk.UseDb.expr exp) val_list in
384 if not use_db then env
385 else (
386 let env =
387 match env.schema with
388 | Finalized _ -> env
389 | Building schema -> (
390 OManager.verbose "I guess you've finished your db-declarations: DB schema finalisation";
391 let env =
392 Schema.fold_expr fold_type_expr env schema
393 in
394 match (
395 Schema.finalize schema
396 ) with
397 | None -> OManager.error "cannot finalize the database schema, the database is not defined"
398 | Some schema -> { env with schema = Finalized schema }
399 )
400 in
401 let annotmap = env.env_types.QmlTypes.annotmap in
402 let dbinfo, dbgen_gamma, dbgen_annotmap, dbgen_init_code, dbgen_accessors_code =
403 DbGen.initialize ~annotmap:(Some annotmap) (schema env)
404 in
405 let dbgen_code = dbgen_init_code @ dbgen_accessors_code in
406 let dbgen_annotmap = match dbgen_annotmap with Some a -> a | None -> assert false in
407 let annotmap =
408 QmlAnnotMap.merge annotmap dbgen_annotmap
409 in
410 let gamma = QmlTypes.Env.append env.env_types.QmlTypes.gamma dbgen_gamma in
411 let env_types =
412 { env.env_types with QmlTypes.
413 annotmap = annotmap ;
414 gamma = gamma ;
415 }
416 in
417 let env =
418 { env with
419 dbinfo = Some dbinfo ;
420 env_types = env_types ;
421 }
422 in
423
424 if OpaTopProperties.dddbgen_get ()
425 then (
426 OManager.printf "/* ================================================ */@\n";
427 OManager.printf "/* dddben : Initial dbgen code */@\n";
428 OManager.printf "%a@\n" pp#code dbgen_code ;
429 OManager.printf "/* ================================================ */@\n";
430 OManager.printf "@." ;
431 ()
432 );
433
434 (* no typing of dbgen init code *)
435 (* no dbgen of dbgen init code *)
436 let just_eval_dbgen_code_elt env code_elt =
437 let _, letrec, _, _ = QmlAstCons.UnValRec.make_let code_elt in
438 let env = fold_eval_expr env letrec in
439 let env =
440 match code_elt with
441 | Q.NewVal (_, val_list) | Q.NewValRec (_, val_list) ->
442 fold_eval_val_list env val_list
443 | _ -> env
444 in
445 env
446 in
447 let env = List.fold_left just_eval_dbgen_code_elt env dbgen_code in
448 env
449 )
450
451 | _ ->
452 (* the db was already finalized *)
453 env
454 in
455 env
456
457 let input_code_elt_Values env code_elt =
458 match code_elt with
459 | Q.NewVal (_, val_list) | Q.NewValRec (_, val_list) -> (
460
461 (* dbgen 1: generate init code if needed and not already done *)
462 let env = initialize_dbgen env val_list in
463
464 let _ =
465 #<If:OPATOP_HOOK>
466 prerr_endline "input_code_elt_Values: HOOK-01";
467 #<End>
468 in
469
470 (* syntactic check: opatop does not use name analysis for simplicity *)
471 let _ = check_no_duplicate val_list in
472
473 let _ =
474 #<If:OPATOP_HOOK>
475 prerr_endline "input_code_elt_Values: HOOK-02";
476 #<End>
477 in
478
479 if OpaTopProperties.dddbgen_get ()
480 then (
481 match env.schema with
482 | Finalized _ ->
483 OManager.printf "/* ================================================ */@\n";
484 OManager.printf "/* dddben : UN-Preprocess paths code elt */@\n";
485 OManager.printf "%a@\n" pp#code_elt code_elt ;
486 OManager.printf "/* ================================================ */@\n";
487 OManager.printf "@." ;
488 ()
489 | _ -> ()
490 );
491
492 (* dbgen 2: path preprocessing for helping the typer *)
493 let _, code_elt =
494 Schema.preprocess_paths_code_elt (schema env) code_elt
495 in
496
497 let _ =
498 #<If:OPATOP_HOOK>
499 prerr_endline "input_code_elt_Values: HOOK-03";
500 #<End>
501 in
502
503 if OpaTopProperties.dddbgen_get ()
504 then (
505 match env.schema with
506 | Finalized _ ->
507 OManager.printf "/* ================================================ */@\n";
508 OManager.printf "/* dddben : Preprocess paths code elt */@\n";
509 OManager.printf "%a@\n" pp#code_elt code_elt ;
510 OManager.printf "/* ================================================ */@\n";
511 OManager.printf "@." ;
512 ()
513 | _ -> ()
514 );
515
516 (* typing *)
517 let env = fold_type_elt env code_elt in
518
519 let _ =
520 #<If:OPATOP_HOOK>
521 prerr_endline "input_code_elt_Values: HOOK-04";
522 #<End>
523 in
524
525 (* dbgen 3: resolve db read/write *)
526 let env, code_elt = dbgen_pass env code_elt in
527
528 (* dddbgen is already in dbgen_pass *)
529
530 let _ =
531 #<If:OPATOP_HOOK>
532 prerr_endline "input_code_elt_Values: HOOK-05";
533 #<End>
534 in
535
536 (* evaluation *)
537 (* eval as a let(rec)in (it is enough thanks to side-effect in Eval) *)
538 (* The Letrec is val letrec = let rec a = ... and b = ... in { a = a; b = b } *)
539 let _, letrec, _, _ = QmlAstCons.UnValRec.make_let code_elt in
540
541 let _ =
542 #<If:OPATOP_UNVALREC>
543 OManager.printf "/* ================================================ */@\n";
544 OManager.printf "UNVALREC:@\n";
545 OManager.printf "%a@\n" pp#expr letrec ;
546 OManager.printf "/* ================================================ */@\n";
547 OManager.printf "@.";
548 ()
549 #<End>
550 in
551
552 let env = fold_eval_expr env letrec in
553
554 (* extract the bindings / annotation returned after dbgen pass *)
555 let val_list =
556 match code_elt with
557 | Q.NewVal (_, val_list) | Q.NewValRec (_, val_list) -> val_list
558 | _ -> assert false
559 in
560
561 let _ =
562 #<If:OPATOP_HOOK>
563 prerr_endline "input_code_elt_Values: HOOK-06";
564 #<End>
565 in
566
567 let env = fold_eval_val_list env val_list in
568
569 let _ =
570 #<If:OPATOP_HOOK>
571 prerr_endline "input_code_elt_Values: HOOK-07";
572 #<End>
573 in
574
575 env
576 )
577
578 | _ -> assert false
579
580 (*
581 assert: this function is called once the env is updated, and annotmap enriched.
582 *)
583 let dump_code_elt env code_elt =
584 if P.dump_get () then (
585 let annotmap = env.env_types.QmlTypes.annotmap in
586 let dump_val ident annot =
587 let ty =
588 match QmlAnnotMap.find_ty_opt annot annotmap with
589 | Some ty -> ty
590 | None -> ty_null
591 in
592 let value =
593 match OpaTopEval.getValueOfAnnot annot with
594 | Some value -> value
595 | None -> value_null
596 in
597 pp#reset_typevars;
598 Format.fprintf !std "%s : %a = %a@."
599 (Ident.to_string ident)
600 pp#ty ty
601 OpaTopValue.pp value
602 in
603 match code_elt with
604 | Q.NewVal (_, val_list) | Q.NewValRec (_, val_list) -> (
605 let iter (ident, expr) = dump_val ident (Q.QAnnot.expr expr) in
606 List.iter iter val_list
607 )
608 | _ ->
609 (* other cases: just an echo of the parsed element *)
610 Format.fprintf !std "%a@." pp#code_elt code_elt
611 )
612
613 let input_code_elt env code_elt =
614 let fold =
615 match code_elt with
616 | Q.Database _ -> input_code_elt_Database
617 | Q.NewDbValue _ -> input_code_elt_NewDbValue
618 | Q.NewType _ -> input_code_elt_NewType
619 | Q.NewVal _
620 | Q.NewValRec _ -> input_code_elt_Values
621 in
622 try
623 let env = fold env code_elt in
624 let _ = dump_code_elt env code_elt in
625 env
626 with
627
628 (* Non-standard Exceptions *)
629
630 | Pervasives.Exit ->
631 (* The server has been exited, and an error message has already been printed. *)
632 env
633
634 | Invalid_argument s ->
635 OManager.printf "Invalid_argument: %S@." s;
636 env
637
638 (* Standard Errors *)
639 | OManagerException ->
640 (* A corresponding error message has already been printed by OManager *)
641 (*
642 If we end-up there, that means that we are in greedy-mode, so, simply
643 ignore the error, and continue the execution with the previous env
644 *)
645 env
646
647
648
649 (* env -> contents -> env *)
650 let input_contents env str =
651 let env = { env with input_item_number = succ env.input_item_number } in
652 let filename =
653 Printf.sprintf "%s, input #%d" env.input_filename (#<If:TESTING>0#<Else>env.input_item_number#<End>) in
654 let annotmap_n_code_opt =
655 try Some (OpaTopParser.parse ~filename str)
656 with OManagerException -> None in
657 match annotmap_n_code_opt with
658 | Some code ->
659 List.fold_left input_code_elt env code
660 | None -> env
661
662
663
664 let input_directive env = function
665 | CP.Directive dir -> (
666 match CP.Directive.parse !directive_handler env dir with
667 | Some env -> env
668 | None -> Format.fprintf !std "[!] unknown directive %S (ignored)@." dir; env
669 )
670 | CP.Code contents -> input_contents env contents
671
672 let prompt () =
673 if P.prompt_get () then (
674 Format.fprintf !std "# ";
675 Format.pp_print_flush !std ();
676 ()
677 )
678
679 let input_line env ic =
680 let input =
681 let input = String.ltrim (Pervasives.input_line ic) in
682 (* bsl preprocessing *)
683 if String.is_substring "##" input 0
684 then (
685 let input = String.rtrim input in
686 let dot, input =
687 if String.is_suffix ";;" input then (true, Filename.chop_suffix input ";;") else false, input in
688 let line = env.input_item_number in
689 let filename = env.input_filename in
690 let input = BslLib.BSL.ByPassMap.Browser.preprocess_line env.bypass_map ~filename ~line input in
691 (* FIXME: remove this print when everything is checked *)
692 Format.fprintf !std "%s@." input;
693 input^(if dot then ";;" else "")
694 )
695 else
696 input
697 in
698 match CP.accumulate t_CP input with
699 | None -> env
700 | Some input ->
701 let env = input_directive env input in
702 prompt ();
703 env
704
705 let input_loop env ic =
706 CP.reset t_CP ;
707 let _ =
708 let unix_ic = Unix.descr_of_in_channel ic in
709 let tty = Unix.isatty unix_ic in
710 P.prompt_set tty
711 in
712 prompt ();
713 let rec aux env =
714 try
715 let env = input_line env ic in
716 aux env
717 with
718 | End_of_file -> (
719 match CP.flush t_CP with
720 | None -> env
721 | Some input -> input_directive env input
722 )
723 in
724 aux env
725
726 let input_file env filename =
727 let env = { env with input_filename = filename } in
728 OManager.verbose "load file @{<bright>%S@} ..." filename;
729 let ic = open_in filename in
730 let prompt = P.prompt_get () in
731 P.prompt_set false;
732 let env = input_loop env ic in
733 P.prompt_set prompt;
734 close_in ic;
735 env
736
737 (* not exported *)
738 let restart () =
739 let dbinfo = None in
740 let open_db = false in
741 let schema = Building Schema.initial in
742
743 (* Feature: An error during bypass_map would be fatal *)
744 let bypass_map = OpaTopBsl.bypass_map () in
745 let bypass_typer = OpaTopBsl.bypass_typer bypass_map in
746
747 let env_types =
5e2359f @fpessaux [cleanup] qml level typer: Cleanup in obscure options never set.
fpessaux authored
748 Typer.initial
c2096c3 @fpessaux [cleanup] qml level typer: removed arguments always used with the sam…
fpessaux authored
749 ~bypass_typer ~explicit_instantiation:true
5e2359f @fpessaux [cleanup] qml level typer: Cleanup in obscure options never set.
fpessaux authored
750 ~value_restriction: (P.value_restriction_get ())
fccc685 Initial open-source release
MLstate authored
751 ~exported_values_idents: IdentSet.empty () in
752 let env_values = IdentMap.empty in
753 (* Reset (in fact, init to "empty") the type of exceptions. *)
754 Typer_w.reset_type_exception () ;
755
756 let input_filename = "stdin" in
757 let input_item_number = 0 in
758
759 let env = {
760 dbinfo = dbinfo ;
761 open_db = open_db ;
762 schema = schema ;
763
764 bypass_map = bypass_map ;
765 env_types = env_types ;
766 env_values = env_values ;
767
768 input_filename = input_filename ;
769 input_item_number = input_item_number ;
770 }
771 in
772 (* From there, errors may be not fatal *)
773 set_OManager_at_exit () ;
774 env
775
776 let start () =
777 ConsoleParser.reset t_CP ;
778 match cache_initial.contents with
779 | Some env -> env
780 | None ->
781 let env = restart () in
782 cache_initial.contents <- Some env;
783 env
Something went wrong with that request. Please try again.