src/Pure/Thy/thy_load.ML
author wenzelm
Sat Nov 16 22:17:45 2013 +0100 (2013-11-16 ago)
changeset 54458 96ccc8972fc7
parent 54456 f4b1440d9880
child 54519 5fed81762406
permissions -rw-r--r--
prefer explicit "document" flag -- eliminated stateful Present.no_document;
     1 (*  Title:      Pure/Thy/thy_load.ML
     2     Author:     Makarius
     3 
     4 Loading files that contribute to a theory.
     5 *)
     6 
     7 signature THY_LOAD =
     8 sig
     9   val master_directory: theory -> Path.T
    10   val imports_of: theory -> (string * Position.T) list
    11   val thy_path: Path.T -> Path.T
    12   val read_files: Path.T -> string -> Path.T * Position.T -> Token.file list
    13   val parse_files: string -> (theory -> Token.file list) parser
    14   val check_thy: Path.T -> string ->
    15    {master: Path.T * SHA1.digest, text: string, theory_pos: Position.T,
    16     imports: (string * Position.T) list, keywords: Thy_Header.keywords}
    17   val provide: Path.T * SHA1.digest -> theory -> theory
    18   val provide_parse_files: string -> (theory -> Token.file list * theory) parser
    19   val load_file: theory -> Path.T -> (Path.T * SHA1.digest) * string
    20   val loaded_files: theory -> Path.T list
    21   val loaded_files_current: theory -> bool
    22   val begin_theory: Path.T -> Thy_Header.header -> theory list -> theory
    23   val load_thy: bool -> (Toplevel.transition -> Time.time option) -> int -> Path.T ->
    24     Thy_Header.header -> Position.T -> string -> theory list -> theory * (unit -> unit) * int
    25 end;
    26 
    27 structure Thy_Load: THY_LOAD =
    28 struct
    29 
    30 (* manage source files *)
    31 
    32 type files =
    33  {master_dir: Path.T,  (*master directory of theory source*)
    34   imports: (string * Position.T) list,  (*source specification of imports*)
    35   provided: (Path.T * SHA1.digest) list};  (*source path, digest*)
    36 
    37 fun make_files (master_dir, imports, provided): files =
    38  {master_dir = master_dir, imports = imports, provided = provided};
    39 
    40 structure Files = Theory_Data
    41 (
    42   type T = files;
    43   val empty = make_files (Path.current, [], []);
    44   fun extend _ = empty;
    45   fun merge _ = empty;
    46 );
    47 
    48 fun map_files f =
    49   Files.map (fn {master_dir, imports, provided} =>
    50     make_files (f (master_dir, imports, provided)));
    51 
    52 
    53 val master_directory = #master_dir o Files.get;
    54 val imports_of = #imports o Files.get;
    55 
    56 fun put_deps master_dir imports = map_files (fn _ => (master_dir, imports, []));
    57 
    58 
    59 (* auxiliary files *)
    60 
    61 fun check_file dir file = File.check_file (File.full_path dir file);
    62 
    63 fun read_files dir cmd (path, pos) =
    64   let
    65     fun make_file file =
    66       let
    67         val _ = Position.report pos (Markup.path (Path.implode file));
    68         val full_path = check_file dir file;
    69       in {src_path = file, text = File.read full_path, pos = Path.position full_path} end;
    70     val paths =
    71       (case Keyword.command_files cmd of
    72         [] => [path]
    73       | exts => map (fn ext => Path.ext ext path) exts);
    74   in map make_file paths end;
    75 
    76 fun parse_files cmd =
    77   Scan.ahead Parse.not_eof -- Parse.path >> (fn (tok, name) => fn thy =>
    78     (case Token.get_files tok of
    79       SOME files => files
    80     | NONE => read_files (master_directory thy) cmd (Path.explode name, Token.position_of tok)));
    81 
    82 
    83 (* theory files *)
    84 
    85 val thy_path = Path.ext "thy";
    86 
    87 fun check_thy dir thy_name =
    88   let
    89     val path = thy_path (Path.basic thy_name);
    90     val master_file = check_file dir path;
    91     val text = File.read master_file;
    92 
    93     val {name = (name, pos), imports, keywords} =
    94       Thy_Header.read (Path.position master_file) text;
    95     val _ = thy_name <> name andalso
    96       error ("Bad file name " ^ Path.print path ^ " for theory " ^ quote name ^ Position.here pos);
    97   in
    98    {master = (master_file, SHA1.digest text), text = text, theory_pos = pos,
    99     imports = imports, keywords = keywords}
   100   end;
   101 
   102 
   103 (* load files *)
   104 
   105 fun provide (src_path, id) =
   106   map_files (fn (master_dir, imports, provided) =>
   107     if AList.defined (op =) provided src_path then
   108       error ("Duplicate use of source file: " ^ Path.print src_path)
   109     else (master_dir, imports, (src_path, id) :: provided));
   110 
   111 fun provide_parse_files cmd =
   112   parse_files cmd >> (fn files => fn thy =>
   113     let
   114       val fs = files thy;
   115       val thy' = fold (fn {src_path, text, ...} => provide (src_path, SHA1.digest text)) fs thy;
   116     in (fs, thy') end);
   117 
   118 fun load_file thy src_path =
   119   let
   120     val full_path = check_file (master_directory thy) src_path;
   121     val text = File.read full_path;
   122     val id = SHA1.digest text;
   123   in ((full_path, id), text) end;
   124 
   125 fun loaded_files_current thy =
   126   #provided (Files.get thy) |>
   127     forall (fn (src_path, id) =>
   128       (case try (load_file thy) src_path of
   129         NONE => false
   130       | SOME ((_, id'), _) => id = id'));
   131 
   132 (*Proof General legacy*)
   133 fun loaded_files thy =
   134   let val {master_dir, provided, ...} = Files.get thy
   135   in map (File.full_path master_dir o #1) provided end;
   136 
   137 
   138 (* load_thy *)
   139 
   140 fun begin_theory master_dir {name, imports, keywords} parents =
   141   Theory.begin_theory name parents
   142   |> put_deps master_dir imports
   143   |> fold Thy_Header.declare_keyword keywords;
   144 
   145 fun excursion last_timing init elements =
   146   let
   147     fun prepare_span span =
   148       Thy_Syntax.span_content span
   149       |> Command.read init
   150       |> (fn tr => Toplevel.put_timing (last_timing tr) tr);
   151 
   152     fun element_result span_elem (st, _) =
   153       let
   154         val elem = Thy_Syntax.map_element prepare_span span_elem;
   155         val (results, st') = Toplevel.element_result elem st;
   156         val pos' = Toplevel.pos_of (Thy_Syntax.last_element elem);
   157       in (results, (st', pos')) end;
   158 
   159     val (results, (end_state, end_pos)) =
   160       fold_map element_result elements (Toplevel.toplevel, Position.none);
   161 
   162     val thy = Toplevel.end_theory end_pos end_state;
   163   in (results, thy) end;
   164 
   165 fun load_thy document last_timing update_time master_dir header text_pos text parents =
   166   let
   167     val time = ! Toplevel.timing;
   168 
   169     val {name = (name, _), ...} = header;
   170     val _ = Thy_Header.define_keywords header;
   171 
   172     val lexs = Keyword.get_lexicons ();
   173     val toks = Thy_Syntax.parse_tokens lexs text_pos text;
   174     val spans = map (Thy_Syntax.resolve_files (read_files master_dir)) (Thy_Syntax.parse_spans toks);
   175     val elements = Thy_Syntax.parse_elements spans;
   176 
   177     fun init () =
   178       begin_theory master_dir header parents
   179       |> Present.begin_theory update_time
   180           (fn () => HTML.html_mode (implode o map Thy_Syntax.present_span) spans);
   181 
   182     val _ = if time then writeln ("\n**** Starting theory " ^ quote name ^ " ****") else ();
   183     val (results, thy) = cond_timeit time "" (fn () => excursion last_timing init elements);
   184     val _ = if time then writeln ("**** Finished theory " ^ quote name ^ " ****\n") else ();
   185 
   186     fun present () =
   187       let
   188         val res = filter_out (Toplevel.is_ignored o #1) (maps Toplevel.join_results results);
   189         val ((minor, _), outer_syntax) = Outer_Syntax.get_syntax ();
   190       in
   191         if exists (Toplevel.is_skipped_proof o #2) res then
   192           warning ("Cannot present theory with skipped proofs: " ^ quote name)
   193         else
   194           let val tex_source =
   195             Thy_Output.present_thy minor Keyword.command_tags
   196               (Outer_Syntax.is_markup outer_syntax) res toks
   197             |> Buffer.content;
   198           in if document then Present.theory_output name tex_source else () end
   199       end;
   200 
   201   in (thy, present, size text) end;
   202 
   203 
   204 (* document antiquotation *)
   205 
   206 val _ = Theory.setup
   207   (Thy_Output.antiquotation (Binding.name "file") (Scan.lift (Parse.position Parse.path))
   208     (fn {context = ctxt, ...} => fn (name, pos) =>
   209       let
   210         val dir = master_directory (Proof_Context.theory_of ctxt);
   211         val path = Path.append dir (Path.explode name);
   212         val _ =
   213           if File.exists path then ()
   214           else error ("Bad file: " ^ Path.print (Path.expand path) ^ Position.here pos);
   215         val _ = Position.report pos (Markup.path name);
   216       in
   217         space_explode "/" name
   218         |> map Thy_Output.verb_text
   219         |> space_implode (Thy_Output.verb_text "/" ^ "\\discretionary{}{}{}")
   220       end));
   221 
   222 end;