src/Pure/Tools/generated_files.ML
changeset 69385 be9f187dcd50
parent 69383 747f8b052e59
child 69628 a2fbfdc5e62d
equal deleted inserted replaced
69384:0c7d8b1b6594 69385:be9f187dcd50
     4 Generated source files for other languages: with antiquotations, without Isabelle symbols.
     4 Generated source files for other languages: with antiquotations, without Isabelle symbols.
     5 *)
     5 *)
     6 
     6 
     7 signature GENERATED_FILES =
     7 signature GENERATED_FILES =
     8 sig
     8 sig
       
     9   val add_files: (Path.T * Position.T) * string -> theory -> theory
       
    10   val get_files: theory -> (Path.T * string) list
       
    11   val write_files: theory -> Path.T -> Path.T list
     9   type file_type =
    12   type file_type =
    10     {name: string, ext: string, make_comment: string -> string, make_string: string -> string}
    13     {name: string, ext: string, make_comment: string -> string, make_string: string -> string}
    11   val file_type:
    14   val file_type:
    12     binding -> {ext: string, make_comment: string -> string, make_string: string -> string} ->
    15     binding -> {ext: string, make_comment: string -> string, make_string: string -> string} ->
    13     theory -> theory
    16     theory -> theory
    14   val antiquotation: binding -> 'a Token.context_parser ->
    17   val antiquotation: binding -> 'a Token.context_parser ->
    15     ({context: Proof.context, source: Token.src, file_type: file_type, argument: 'a} -> string) ->
    18     ({context: Proof.context, source: Token.src, file_type: file_type, argument: 'a} -> string) ->
    16     theory -> theory
    19     theory -> theory
    17   val set_string: string -> Proof.context -> Proof.context
    20   val set_string: string -> Proof.context -> Proof.context
    18   val generate_file_cmd: (string * Position.T) * Input.source -> local_theory -> local_theory
    21   val generate_file_cmd: (string * Position.T) * Input.source -> local_theory -> local_theory
    19   val write: theory -> Path.T -> Path.T list
       
    20   val export: theory -> string -> Path.T list
       
    21 end;
    22 end;
    22 
    23 
    23 structure Generated_Files: GENERATED_FILES =
    24 structure Generated_Files: GENERATED_FILES =
    24 struct
    25 struct
    25 
    26 
    31 type antiquotation = Token.src -> Proof.context -> file_type -> string;
    32 type antiquotation = Token.src -> Proof.context -> file_type -> string;
    32 
    33 
    33 structure Data = Theory_Data
    34 structure Data = Theory_Data
    34 (
    35 (
    35   type T =
    36   type T =
       
    37     (Path.T * (Position.T * string)) list *  (*files for current theory*)
    36     file_type Name_Space.table *  (*file types*)
    38     file_type Name_Space.table *  (*file types*)
    37     antiquotation Name_Space.table *  (*antiquotations*)
    39     antiquotation Name_Space.table;  (*antiquotations*)
    38     (Path.T * (Position.T * string)) list;  (*generated files for current theory*)
       
    39   val empty =
    40   val empty =
    40     (Name_Space.empty_table Markup.file_typeN,
    41     ([],
    41      Name_Space.empty_table Markup.antiquotationN,
    42      Name_Space.empty_table Markup.file_typeN,
    42      []);
    43      Name_Space.empty_table Markup.antiquotationN);
    43   val extend = @{apply 3(3)} (K []);
    44   val extend = @{apply 3(1)} (K []);
    44   fun merge ((types1, antiqs1, _), (types2, antiqs2, _)) =
    45   fun merge ((_, types1, antiqs1), (_, types2, antiqs2)) =
    45     (Name_Space.merge_tables (types1, types2),
    46     ([],
    46      Name_Space.merge_tables (antiqs1, antiqs2),
    47      Name_Space.merge_tables (types1, types2),
    47      []);
    48      Name_Space.merge_tables (antiqs1, antiqs2));
    48 );
    49 );
    49 
    50 
    50 val get_files = rev o #3 o Data.get;
    51 
    51 
    52 (* files *)
    52 fun add_files (path, (pos, text)) =
    53 
    53   (Data.map o @{apply 3(3)}) (fn files =>
    54 fun add_files ((path0, pos), text) =
    54     (case AList.lookup (op =) files path of
    55   let
    55       SOME (pos', _) =>
    56     val path = Path.expand path0;
    56         error ("Duplicate generated file " ^ Path.print path ^ Position.here_list [pos, pos'])
    57     fun err msg ps = error (msg ^ ": " ^ Path.print path ^ Position.here_list ps);
    57     | NONE => (path, (pos, text)) :: files));
    58     val _ =
       
    59       if Path.is_absolute path then err "Illegal absolute path" [pos]
       
    60       else if Path.has_parent path then err "Illegal parent path" [pos]
       
    61       else ();
       
    62   in
       
    63     (Data.map o @{apply 3(1)}) (fn files =>
       
    64       (case AList.lookup (op =) files path of
       
    65         SOME (pos', _) => err "Duplicate generated file" [pos, pos']
       
    66       | NONE => (path, (pos, text)) :: files))
       
    67   end;
       
    68 
       
    69 val get_files = map (apsnd #2) o rev o #1 o Data.get;
       
    70 
       
    71 fun write_files thy dir =
       
    72   get_files thy |> map (fn (path, text) =>
       
    73     let
       
    74       val path' = Path.expand (Path.append dir path);
       
    75       val _ = Isabelle_System.mkdirs (Path.dir path');
       
    76       val _ = File.generate path' text;
       
    77     in path end);
    58 
    78 
    59 
    79 
    60 (* file types *)
    80 (* file types *)
    61 
    81 
    62 fun the_file_type thy ext =
    82 fun the_file_type thy ext =
    63   if ext = "" then error "Bad file extension"
    83   if ext = "" then error "Bad file extension"
    64   else
    84   else
    65     (#1 (Data.get thy), NONE) |-> Name_Space.fold_table
    85     (#2 (Data.get thy), NONE) |-> Name_Space.fold_table
    66       (fn (_, file_type) => fn res =>
    86       (fn (_, file_type) => fn res =>
    67         if #ext file_type = ext then SOME file_type else res)
    87         if #ext file_type = ext then SOME file_type else res)
    68     |> (fn SOME file_type => file_type
    88     |> (fn SOME file_type => file_type
    69          | NONE => error ("Unknown file type for extension " ^ quote ext));
    89          | NONE => error ("Unknown file type for extension " ^ quote ext));
    70 
    90 
    72   let
    92   let
    73     val name = Binding.name_of binding;
    93     val name = Binding.name_of binding;
    74     val pos = Binding.pos_of binding;
    94     val pos = Binding.pos_of binding;
    75     val file_type = {name = name, ext = ext, make_comment = make_comment, make_string = make_string};
    95     val file_type = {name = name, ext = ext, make_comment = make_comment, make_string = make_string};
    76 
    96 
    77     val table = #1 (Data.get thy);
    97     val table = #2 (Data.get thy);
    78     val space = Name_Space.space_of_table table;
    98     val space = Name_Space.space_of_table table;
    79     val context = Context.Theory thy |> Name_Space.map_naming (K Name_Space.global_naming);
    99     val context = Context.Theory thy |> Name_Space.map_naming (K Name_Space.global_naming);
    80     val (_, data') = table |> Name_Space.define context true (Binding.make (name, pos), file_type);
   100     val (_, data') = table |> Name_Space.define context true (Binding.make (name, pos), file_type);
    81 
   101 
    82     val _ =
   102     val _ =
    83       (case try (#name o the_file_type thy) ext of
   103       (case try (#name o the_file_type thy) ext of
    84         NONE => ()
   104         NONE => ()
    85       | SOME name' =>
   105       | SOME name' =>
    86           error ("Extension " ^ quote ext ^ " already registered for file type " ^
   106           error ("Extension " ^ quote ext ^ " already registered for file type " ^
    87             quote (Markup.markup (Name_Space.markup space name') name') ^ Position.here pos));
   107             quote (Markup.markup (Name_Space.markup space name') name') ^ Position.here pos));
    88   in thy |> (Data.map o @{apply 3(1)}) (K data') end;
   108   in thy |> (Data.map o @{apply 3(2)}) (K data') end;
    89 
   109 
    90 
   110 
    91 (* antiquotations *)
   111 (* antiquotations *)
    92 
   112 
    93 val get_antiquotations = #2 o Data.get o Proof_Context.theory_of;
   113 val get_antiquotations = #3 o Data.get o Proof_Context.theory_of;
    94 
   114 
    95 fun antiquotation name scan body thy =
   115 fun antiquotation name scan body thy =
    96   let
   116   let
    97     fun ant src ctxt file_type : string =
   117     fun ant src ctxt file_type : string =
    98       let val (x, ctxt') = Token.syntax scan src ctxt
   118       let val (x, ctxt') = Token.syntax scan src ctxt
    99       in body {context = ctxt', source = src, file_type = file_type, argument = x} end;
   119       in body {context = ctxt', source = src, file_type = file_type, argument = x} end;
   100   in
   120   in
   101     thy
   121     thy
   102     |> (Data.map o @{apply 3(2)}) (Name_Space.define (Context.Theory thy) true (name, ant) #> #2)
   122     |> (Data.map o @{apply 3(3)}) (Name_Space.define (Context.Theory thy) true (name, ant) #> #2)
   103   end;
   123   end;
   104 
   124 
   105 val scan_antiq =
   125 val scan_antiq =
   106   Antiquote.scan_control >> Antiquote.Control ||
   126   Antiquote.scan_control >> Antiquote.Control ||
   107   Scan.one (Symbol.not_eof o Symbol_Pos.symbol) >> (Antiquote.Text o Symbol_Pos.symbol);
   127   Scan.one (Symbol.not_eof o Symbol_Pos.symbol) >> (Antiquote.Text o Symbol_Pos.symbol);
   136 
   156 
   137 fun generate_file_cmd ((file, pos), source) lthy =
   157 fun generate_file_cmd ((file, pos), source) lthy =
   138   let
   158   let
   139     val thy = Proof_Context.theory_of lthy;
   159     val thy = Proof_Context.theory_of lthy;
   140 
   160 
   141     val path = Path.expand (Path.explode file);
   161     val path = Path.explode file;
   142     fun err_path msg = error (msg ^ ": " ^ Path.print path ^ Position.here pos);
       
   143     val _ =
       
   144       if Path.is_absolute path then err_path "Illegal absolute path"
       
   145       else if Path.has_parent path then err_path "Illegal parent path"
       
   146       else ();
       
   147 
       
   148     val file_type =
   162     val file_type =
   149       the_file_type thy (#2 (Path.split_ext path))
   163       the_file_type thy (#2 (Path.split_ext path))
   150         handle ERROR msg => error (msg ^ Position.here pos);
   164         handle ERROR msg => error (msg ^ Position.here pos);
   151 
   165 
   152     val header = #make_comment file_type " generated by Isabelle ";
   166     val header = #make_comment file_type " generated by Isabelle ";
   153     val text = header ^ "\n" ^ read_source lthy file_type source;
   167     val text = header ^ "\n" ^ read_source lthy file_type source;
   154   in lthy |> (Local_Theory.background_theory o add_files) (path, (pos, text)) end;
   168   in lthy |> (Local_Theory.background_theory o add_files) ((path, pos), text) end;
   155 
       
   156 fun write thy dir =
       
   157   get_files thy |> map (fn (path, (_, text)) =>
       
   158     let
       
   159       val path' = Path.expand (Path.append dir path);
       
   160       val _ = Isabelle_System.mkdirs (Path.dir path');
       
   161       val _ = File.generate path' text;
       
   162     in path end);
       
   163 
       
   164 fun export thy prefix =
       
   165   get_files thy |> map (fn (path, (_, text)) =>
       
   166     let
       
   167       val name = (if prefix = "" then "" else prefix ^ "/") ^ Path.implode path;
       
   168       val _ = Export.export thy name [text];
       
   169     in path end);
       
   170 
   169 
   171  
   170  
   172 
   171 
   173 (** concrete file types **)
   172 (** concrete file types **)
   174 
   173