src/Pure/Thy/thy_header.ML
author wenzelm
Thu, 15 Mar 2012 00:10:45 +0100
changeset 46938 cda018294515
parent 46737 09ab89658a5d
child 46939 5b67ac48b384
permissions -rw-r--r--
some support for outer syntax keyword declarations within theory header; more uniform Thy_Header.header as argument for begin_theory etc.;

(*  Title:      Pure/Thy/thy_header.ML
    Author:     Markus Wenzel, TU Muenchen

Theory headers -- independent of outer syntax.
*)

signature THY_HEADER =
sig
  type header =
   {name: string, imports: string list,
    keywords: (string * (string * string list) option) list,
    uses: (Path.T * bool) list}
  val make: string -> string list -> (string * (string * string list) option) list ->
    (Path.T * bool) list -> header
  val declare_keyword: string * (string * string list) option -> theory -> theory
  val the_keyword: theory -> string -> Keyword.T option
  val args: header parser
  val read: Position.T -> string -> header
end;

structure Thy_Header: THY_HEADER =
struct

type header =
 {name: string, imports: string list,
  keywords: (string * (string * string list) option) list,
  uses: (Path.T * bool) list};

fun make name imports keywords uses : header =
  {name = name, imports = imports, keywords = keywords, uses = uses};



(** keyword declarations **)

fun err_dup name = error ("Inconsistent declaration of outer syntax keyword " ^ quote name);

structure Data = Theory_Data
(
  type T = Keyword.T option Symtab.table;
  val empty = Symtab.empty;
  val extend = I;
  fun merge data : T = Symtab.merge (op =) data handle Symtab.DUP name => err_dup name;
);

fun declare_keyword (name, kind) =
  Data.map (fn data =>
    Symtab.update_new (name, Option.map Keyword.make kind) data
      handle Symtab.DUP name => err_dup name);

fun the_keyword thy name =
  (case Symtab.lookup (Data.get thy) name of
    SOME decl => decl
  | NONE => error ("Unknown outer syntax keyword " ^ quote name));



(** concrete syntax **)

(* header keywords *)

val headerN = "header";
val theoryN = "theory";
val importsN = "imports";
val keywordsN = "keywords";
val usesN = "uses";
val beginN = "begin";

val header_lexicon =
  Scan.make_lexicon
    (map Symbol.explode
      ["%", "(", ")", "::", ";", "and", beginN, headerN, importsN, keywordsN, theoryN, usesN]);


(* header args *)

local

val file_name = Parse.group (fn () => "file name") Parse.path;
val theory_name = Parse.group (fn () => "theory name") Parse.name;

val keyword_kind = Parse.group (fn () => "outer syntax keyword kind") (Parse.name -- Parse.tags);
val keyword_decl = Parse.name -- Scan.option (Parse.$$$ "::" |-- Parse.!!! keyword_kind);

val file =
  Parse.$$$ "(" |-- Parse.!!! (file_name --| Parse.$$$ ")") >> rpair false ||
  file_name >> rpair true;

in

val args =
  theory_name --
  (Parse.$$$ importsN |-- Parse.!!! (Scan.repeat1 theory_name)) --
  Scan.optional (Parse.$$$ keywordsN |-- Parse.!!! (Parse.and_list1 keyword_decl)) [] --
  Scan.optional (Parse.$$$ usesN |-- Parse.!!! (Scan.repeat1 file)) [] --|
  Parse.$$$ beginN >>
  (fn (((name, imports), keywords), uses) => make name imports keywords uses);

end;


(* read header *)

val header =
  (Parse.$$$ headerN -- Parse.tags) |--
    (Parse.!!! (Parse.doc_source -- Scan.repeat Parse.semicolon --
      (Parse.$$$ theoryN -- Parse.tags) |-- args)) ||
  (Parse.$$$ theoryN -- Parse.tags) |-- Parse.!!! args;

fun read pos str =
  let val res =
    str
    |> Source.of_string_limited 8000
    |> Symbol.source
    |> Token.source {do_recover = NONE} (fn () => (header_lexicon, Scan.empty_lexicon)) pos
    |> Token.source_proper
    |> Source.source Token.stopper (Scan.single (Scan.error (Parse.!!! header))) NONE
    |> Source.get_single;
  in
    (case res of
      SOME (h, _) => h
    | NONE => error ("Unexpected end of input" ^ Position.str_of pos))
  end;

end;