| 9139 |      1 | (*  Title:      Pure/Isar/thy_header.ML
 | 
|  |      2 |     ID:         $Id$
 | 
|  |      3 |     Author:     Markus Wenzel, TU Muenchen
 | 
|  |      4 |     License:    GPL (GNU GENERAL PUBLIC LICENSE)
 | 
|  |      5 | 
 | 
|  |      6 | Theory headers (old and new-style).
 | 
|  |      7 | *)
 | 
|  |      8 | 
 | 
|  |      9 | signature THY_HEADER =
 | 
|  |     10 | sig
 | 
|  |     11 |   val is_old: (string, 'a) Source.source * Position.T -> bool
 | 
|  |     12 |   val args: OuterLex.token list ->
 | 
|  |     13 |     (string * string list * (string * bool) list) * OuterLex.token list
 | 
|  |     14 |   val scan: (string, 'a) Source.source * Position.T -> string * string list * (string * bool) list
 | 
|  |     15 | end;
 | 
|  |     16 | 
 | 
|  |     17 | structure ThyHeader: THY_HEADER =
 | 
|  |     18 | struct
 | 
|  |     19 | 
 | 
|  |     20 | structure T = OuterLex;
 | 
|  |     21 | structure P = OuterParse;
 | 
|  |     22 | 
 | 
|  |     23 | 
 | 
|  |     24 | (* scan header *)
 | 
|  |     25 | 
 | 
|  |     26 | fun scan_header get_lex scan (src, pos) =
 | 
| 12840 |     27 |   let val res =
 | 
|  |     28 |     src
 | 
|  |     29 |     |> Symbol.source false
 | 
|  |     30 |     |> T.source false (fn () => (get_lex (), Scan.empty_lexicon)) pos
 | 
|  |     31 |     |> T.source_proper
 | 
|  |     32 |     |> Source.source T.stopper (Scan.single scan) None
 | 
|  |     33 |     |> Source.get_single;
 | 
|  |     34 |   in
 | 
|  |     35 |     (case res of Some (x, _) => x
 | 
|  |     36 |     | None => error ("Unexpected end of input" ^ Position.str_of pos))
 | 
|  |     37 |   end;
 | 
| 9139 |     38 | 
 | 
|  |     39 | 
 | 
|  |     40 | (* keywords *)
 | 
|  |     41 | 
 | 
|  |     42 | val headerN = "header";
 | 
|  |     43 | val theoryN = "theory";
 | 
|  |     44 | 
 | 
|  |     45 | val theory_keyword = P.$$$ theoryN;
 | 
|  |     46 | val header_keyword = P.$$$ headerN;
 | 
|  |     47 | 
 | 
|  |     48 | 
 | 
|  |     49 | (* detect new/old headers *)
 | 
|  |     50 | 
 | 
|  |     51 | val check_header_lexicon = T.make_lexicon [headerN, theoryN];
 | 
|  |     52 | val check_header = Scan.option (header_keyword || theory_keyword);
 | 
|  |     53 | 
 | 
|  |     54 | fun is_old src_pos =
 | 
|  |     55 |   Library.is_none (scan_header (K check_header_lexicon) check_header src_pos);
 | 
|  |     56 | 
 | 
|  |     57 | 
 | 
|  |     58 | (* scan old/new headers *)
 | 
|  |     59 | 
 | 
|  |     60 | val header_lexicon =
 | 
|  |     61 |   T.make_lexicon ["(", ")", "+", ":", ";", "=", "files", headerN, theoryN];
 | 
|  |     62 | 
 | 
|  |     63 | val file_name =
 | 
|  |     64 |   (P.$$$ "(" |-- P.!!! (P.name --| P.$$$ ")")) >> rpair false || P.name >> rpair true;
 | 
|  |     65 | 
 | 
|  |     66 | 
 | 
|  |     67 | val args =
 | 
|  |     68 |   (P.name -- (P.$$$ "=" |-- P.enum1 "+" P.name) --
 | 
|  |     69 |     Scan.optional (P.$$$ "files" |-- P.!!! (Scan.repeat1 file_name)) [] --|  P.$$$ ":")
 | 
|  |     70 |   >> (fn ((A, Bs), files) => (A, Bs, files));
 | 
|  |     71 | 
 | 
|  |     72 | 
 | 
|  |     73 | val new_header =
 | 
|  |     74 |   header_keyword |-- (P.!!! (P.text -- Scan.repeat P.semicolon -- theory_keyword |-- args)) ||
 | 
|  |     75 |   theory_keyword |-- P.!!! args;
 | 
|  |     76 | 
 | 
|  |     77 | val old_header =
 | 
|  |     78 |   P.!!! (P.group "theory header"
 | 
|  |     79 |     (P.name -- (P.$$$ "=" |-- P.name -- Scan.repeat (P.$$$ "+" |-- P.name))))
 | 
|  |     80 |   >> (fn (A, (B, Bs)) => (A, B :: Bs, []: (string * bool) list));
 | 
|  |     81 | 
 | 
|  |     82 | fun scan src_pos =
 | 
|  |     83 |   (*sadly, old-style headers depend on the current (dynamic!) lexicon*)
 | 
|  |     84 |   if is_old src_pos then
 | 
|  |     85 |     scan_header ThySyn.get_lexicon (Scan.error old_header) src_pos
 | 
|  |     86 |   else scan_header (K header_lexicon) (Scan.error new_header) src_pos;
 | 
|  |     87 | 
 | 
|  |     88 | 
 | 
|  |     89 | end;
 |