src/Pure/Isar/outer_syntax.ML
changeset 6247 e8bbe64861b8
parent 6229 f839b261b87f
child 6332 7cee353c7f2a
equal deleted inserted replaced
6246:0aa2e536bc20 6247:e8bbe64861b8
     1 (*  Title:      Pure/Isar/outer_syntax.ML
     1 (*  Title:      Pure/Isar/outer_syntax.ML
     2     ID:         $Id$
     2     ID:         $Id$
     3     Author:     Markus Wenzel, TU Muenchen
     3     Author:     Markus Wenzel, TU Muenchen
     4 
     4 
     5 The global Isabelle/Isar outer syntax.
     5 The global Isabelle/Isar outer syntax.
       
     6 
       
     7 TODO:
       
     8   - cleanup;
       
     9   - avoid string constants;
     6 *)
    10 *)
     7 
    11 
     8 signature BASIC_OUTER_SYNTAX =
    12 signature BASIC_OUTER_SYNTAX =
     9 sig
    13 sig
    10   val main: unit -> unit
    14   val main: unit -> unit
    21     (token list -> (Toplevel.transition -> Toplevel.transition) * token list) -> parser
    25     (token list -> (Toplevel.transition -> Toplevel.transition) * token list) -> parser
    22   val print_outer_syntax: unit -> unit
    26   val print_outer_syntax: unit -> unit
    23   val commands: unit -> string list
    27   val commands: unit -> string list
    24   val add_keywords: string list -> unit
    28   val add_keywords: string list -> unit
    25   val add_parsers: parser list -> unit
    29   val add_parsers: parser list -> unit
       
    30   val theory_header: token list -> (string * string list * (string * bool) list) * token list
    26   val deps_thy: string -> bool -> Path.T -> string list * Path.T list
    31   val deps_thy: string -> bool -> Path.T -> string list * Path.T list
    27   val load_thy: string -> bool -> bool -> Path.T -> unit
    32   val load_thy: string -> bool -> bool -> Path.T -> unit
    28   val isar: Toplevel.isar
    33   val isar: Toplevel.isar
    29 end;
    34 end;
    30 
    35 
   115 fun get_parser () = apsome snd o curry Symtab.lookup (! global_parsers);
   120 fun get_parser () = apsome snd o curry Symtab.lookup (! global_parsers);
   116 
   121 
   117 
   122 
   118 
   123 
   119 (** read theory **)
   124 (** read theory **)
       
   125 
       
   126 (* theory keyword *)
       
   127 
       
   128 val theoryN = "theory";
       
   129 val theory_keyword = OuterParse.$$$ theoryN;
       
   130 
   120 
   131 
   121 (* source *)
   132 (* source *)
   122 
   133 
   123 fun no_command cmd =
   134 fun no_command cmd =
   124   Scan.one ((not o OuterLex.keyword_pred ((is_some o cmd) orf equal ";")) andf OuterLex.not_eof);
   135   Scan.one ((not o OuterLex.keyword_pred ((is_some o cmd) orf equal ";")) andf OuterLex.not_eof);
   140   |> Symbol.source false
   151   |> Symbol.source false
   141   |> OuterLex.source false get_lexicon pos
   152   |> OuterLex.source false get_lexicon pos
   142   |> Source.source OuterLex.stopper (Scan.single scan) None
   153   |> Source.source OuterLex.stopper (Scan.single scan) None
   143   |> (fst o the o Source.get_single);
   154   |> (fst o the o Source.get_single);
   144 
   155 
   145 val check_header_lexicon = Scan.make_lexicon [Symbol.explode "theory"];
   156 val check_header_lexicon = Scan.make_lexicon [Symbol.explode theoryN];
   146 
   157 
   147 fun is_old_theory src =
   158 fun is_old_theory src =
   148   is_none (scan_header (K check_header_lexicon) (Scan.option (OuterParse.$$$ "theory")) src);
   159   is_none (scan_header (K check_header_lexicon) (Scan.option theory_keyword) src);
   149 
   160 
   150 fun warn_theory_style path is_old =
   161 fun warn_theory_style path is_old =
   151   let
   162   let
   152     val style = if is_old then "old" else "new";
   163     val style = if is_old then "old" else "new";
   153     val _ = warning ("Assuming " ^ style ^ "-style theory format for " ^ quote (Path.pack path));
   164     val _ = warning ("Assuming " ^ style ^ "-style theory format for " ^ quote (Path.pack path));
   154   in is_old end;
   165   in is_old end;
   155 
   166 
   156 
   167 
   157 (* deps_thy --- inspect theory header *)
   168 (* deps_thy --- inspect theory header *)
   158 
   169 
   159 val new_header_lexicon =
   170 val header_lexicon =
   160   Scan.make_lexicon (map Symbol.explode ["+", ":", "=", "files", "theory"]);
   171   Scan.make_lexicon (map Symbol.explode ["(", ")", "+", ":", "=", "files", theoryN]);
   161 
   172 
   162 local open OuterParse in
   173 local open OuterParse in
   163 
   174 
   164 val new_header =
   175 val file_name = ($$$ "(" |-- !!! (name --| $$$ ")")) >> rpair false || name >> rpair true;
   165   $$$ "theory" |-- !!! (name -- ($$$ "=" |-- enum1 "+" name) --
   176 
   166     Scan.optional ($$$ "files" |-- !!! (Scan.repeat1 name)) [] --| (Scan.ahead eof || $$$ ":"));
   177 val theory_head =
       
   178   (name -- ($$$ "=" |-- enum1 "+" name) --
       
   179     Scan.optional ($$$ "files" |-- !!! (Scan.repeat1 file_name)) [])
       
   180   >> (fn ((A, Bs), files) => (A, Bs, files));
       
   181 
       
   182 val theory_header = theory_head --| (Scan.ahead eof || $$$ ":");
       
   183 val only_header = theory_keyword |-- theory_head --| Scan.ahead eof;
       
   184 val new_header = theory_keyword |-- !!! theory_header;
   167 
   185 
   168 val old_header =
   186 val old_header =
   169   name -- ($$$ "=" |-- name -- Scan.repeat ($$$ "+" |-- name))
   187   name -- ($$$ "=" |-- name -- Scan.repeat ($$$ "+" |-- name))
   170   >> (fn (A, (B, Bs)) => ((A, B :: Bs), []: string list));
   188   >> (fn (A, (B, Bs)) => (A, B :: Bs, []: (string * bool) list));
   171 
   189 
   172 end;
   190 end;
   173 
   191 
   174 fun deps_thy name ml path =
   192 fun deps_thy name ml path =
   175   let
   193   let
   176     val src = Source.of_file path;
   194     val src = Source.of_file path;
   177     val is_old = warn_theory_style path (is_old_theory src);
   195     val is_old = warn_theory_style path (is_old_theory src);
   178     val ((name', parents), files) =
   196     val (name', parents, files) =
   179       (*Note: old style headers dynamically depend on the current lexicon :-( *)
   197       (*Note: old style headers dynamically depend on the current lexicon :-( *)
   180       if is_old then scan_header ThySyn.get_lexicon (Scan.error old_header) src
   198       if is_old then scan_header ThySyn.get_lexicon (Scan.error old_header) src
   181       else scan_header (K new_header_lexicon) (Scan.error new_header) src;
   199       else scan_header (K header_lexicon) (Scan.error new_header) src;
   182 
   200 
   183     val ml_path = ThyLoad.ml_path name;
   201     val ml_path = ThyLoad.ml_path name;
   184     val ml_file = if not ml orelse is_none (ThyLoad.check_file ml_path) then [] else [ml_path];
   202     val ml_file = if not ml orelse is_none (ThyLoad.check_file ml_path) then [] else [ml_path];
   185   in
   203   in
   186     if name <> name' then
   204     if name <> name' then
   187       error ("Filename " ^ quote (Path.pack path) ^ " does not match theory name " ^ quote name)
   205       error ("Filename " ^ quote (Path.pack path) ^ " does not match theory name " ^ quote name)
   188     else (parents, map Path.unpack files @ ml_file)
   206     else (parents, map (Path.unpack o #1) files @ ml_file)
   189   end;
   207   end;
   190 
   208 
   191 
   209 
   192 (* load_thy --- read text (including header) *)
   210 (* load_thy --- read text (including header) *)
   193 
   211 
   194 fun try_ml_file name ml =
   212 fun try_ml_file name ml time =
   195   let
   213   let
   196     val path = ThyLoad.ml_path name;
   214     val path = ThyLoad.ml_path name;
   197     val tr = Toplevel.imperative (fn () => ThyInfo.load_file path);
   215     val tr = Toplevel.imperative (fn () => ThyInfo.load_file time path);
       
   216     val tr_name = if time then "time_use" else "use";
   198   in
   217   in
   199     if not ml orelse is_none (ThyLoad.check_file path) then ()
   218     if not ml orelse is_none (ThyLoad.check_file path) then ()
   200     else Toplevel.excursion [Toplevel.empty |> Toplevel.name "use" |> tr]
   219     else Toplevel.excursion [Toplevel.empty |> Toplevel.name tr_name |> tr]
   201   end;
   220   end;
   202 
   221 
   203 fun parse_thy (src, pos) =
   222 fun parse_thy (src, pos) =
   204   src
   223   let
   205   |> Symbol.source false
   224     val lex_src =
   206   |> OuterLex.source false (K (get_lexicon ())) pos
   225       src
   207   |> source false (K (get_parser ()))
   226       |> Symbol.source false
   208   |> Source.exhaust;
   227       |> OuterLex.source false (K (get_lexicon ())) pos;
   209 
   228     val only_head =
   210 fun read_thy name ml path =
   229       lex_src
   211   let
   230       |> Source.source OuterLex.stopper (Scan.single (Scan.option only_header)) None
   212     val (src, pos) = Source.of_file path;
   231       |> (fst o the o Source.get_single);
   213     val _ =
   232   in
   214       if is_old_theory (src, pos) then ThySyn.load_thy name (Source.exhaust src)
   233     (case only_head of
   215       else (Toplevel.excursion (parse_thy (src, pos))
   234       None =>
   216         handle exn => error (Toplevel.exn_message exn));
   235         lex_src
   217   in Context.context (ThyInfo.get_theory name); try_ml_file name ml end;
   236         |> source false (K (get_parser ()))
       
   237         |> Source.exhaust
       
   238     | Some spec =>
       
   239         [Toplevel.empty |> Toplevel.name theoryN |> IsarThy.theory spec,
       
   240           Toplevel.empty |> Toplevel.name "end" |> Toplevel.exit])
       
   241   end;
       
   242 
       
   243 fun run_thy name path =
       
   244   let val (src, pos) = Source.of_file path in
       
   245     if is_old_theory (src, pos) then ThySyn.load_thy name (Source.exhaust src)
       
   246     else (Toplevel.excursion (parse_thy (src, pos))
       
   247       handle exn => error (Toplevel.exn_message exn))
       
   248   end;
   218 
   249 
   219 fun load_thy name ml time path =
   250 fun load_thy name ml time path =
   220   if not time then read_thy name ml path
   251  (if time then
   221   else timeit (fn () =>
   252     timeit (fn () =>
   222    (writeln ("\n**** Starting Theory " ^ quote name ^ " ****");
   253      (writeln ("\n**** Starting theory " ^ quote name ^ " ****");
   223     setmp Goals.proof_timing true (read_thy name ml) path;
   254       setmp Goals.proof_timing true (run_thy name) path;
   224     writeln ("**** Finished Theory " ^ quote name ^ " ****\n")));
   255       writeln ("**** Finished theory " ^ quote name ^ " ****\n")))
       
   256   else run_thy name path;
       
   257   Context.context (ThyInfo.get_theory name);
       
   258   try_ml_file name ml time);
   225 
   259 
   226 
   260 
   227 (* interactive source of state transformers *)
   261 (* interactive source of state transformers *)
   228 
   262 
   229 val isar =
   263 val isar =