src/Pure/Tools/isabelle_process.ML
author wenzelm
Tue Aug 12 21:28:07 2008 +0200 (2008-08-12 ago)
changeset 27844 86f0f91471d0
parent 27604 6c347b96d941
child 27961 2cd133df7587
permissions -rw-r--r--
message: ignored if body empty;
wenzelm@25528
     1
(*  Title:      Pure/Tools/isabelle_process.ML
wenzelm@25528
     2
    ID:         $Id$
wenzelm@25528
     3
    Author:     Makarius
wenzelm@25528
     4
wenzelm@25528
     5
Isabelle process wrapper -- interaction via external program.
wenzelm@25631
     6
wenzelm@25631
     7
General format of process output:
wenzelm@25631
     8
wenzelm@25631
     9
  (a) unmarked stdout/stderr, no line structure (output should be
wenzelm@25842
    10
  processed immediately as it arrives);
wenzelm@25631
    11
wenzelm@25841
    12
  (b) properly marked-up messages, e.g. for writeln channel
wenzelm@25810
    13
wenzelm@25810
    14
  "\002A" ^ props ^ "\002,\n" ^ text ^ "\002.\n"
wenzelm@25810
    15
wenzelm@25841
    16
  where the props consist of name=value lines terminated by "\002,\n"
wenzelm@25810
    17
  each, and the remaining text is any number of lines (output is
wenzelm@25842
    18
  supposed to be processed in one piece);
wenzelm@25841
    19
wenzelm@25842
    20
  (c) special init message holds "pid" and "session" property.
wenzelm@25528
    21
*)
wenzelm@25528
    22
wenzelm@25528
    23
signature ISABELLE_PROCESS =
wenzelm@25528
    24
sig
wenzelm@26574
    25
  val isabelle_processN: string
wenzelm@26208
    26
  val full_markupN: string
wenzelm@26574
    27
  val yxmlN: string
wenzelm@25528
    28
  val init: unit -> unit
wenzelm@25528
    29
end;
wenzelm@25528
    30
wenzelm@25528
    31
structure IsabelleProcess: ISABELLE_PROCESS =
wenzelm@25528
    32
struct
wenzelm@25528
    33
wenzelm@26550
    34
(* print modes *)
wenzelm@25554
    35
wenzelm@25748
    36
val isabelle_processN = "isabelle_process";
wenzelm@26550
    37
val full_markupN = "full_markup";
wenzelm@26574
    38
val yxmlN = "YXML";
wenzelm@25748
    39
wenzelm@26550
    40
val _ = Output.add_mode isabelle_processN Output.default_output Output.default_escape;
wenzelm@25554
    41
wenzelm@26550
    42
val _ = Markup.add_mode isabelle_processN (fn (name, props) =>
wenzelm@26550
    43
  if print_mode_active full_markupN orelse name = Markup.positionN
wenzelm@26550
    44
  then YXML.output_markup (name, props) else ("", ""));
wenzelm@25841
    45
wenzelm@25841
    46
wenzelm@25841
    47
(* message markup *)
wenzelm@25841
    48
wenzelm@26527
    49
fun special ch = Symbol.STX ^ ch;
wenzelm@25810
    50
val special_sep = special ",";
wenzelm@25576
    51
val special_end = special ".";
wenzelm@25554
    52
wenzelm@25841
    53
local
wenzelm@25810
    54
wenzelm@26574
    55
fun clean_string bad str =
wenzelm@26574
    56
  if exists_string (member (op =) bad) str then
wenzelm@26574
    57
    translate_string (fn c => if member (op =) bad c then Symbol.DEL else c) str
wenzelm@26574
    58
  else str;
wenzelm@26574
    59
wenzelm@26550
    60
fun message_props props =
wenzelm@26574
    61
  let val clean = clean_string [Symbol.STX, "\n", "\r"]
wenzelm@25841
    62
  in implode (map (fn (x, y) => clean x ^ "=" ^ clean y ^ special_sep ^ "\n") props) end;
wenzelm@25841
    63
wenzelm@26550
    64
fun message_text ts =
wenzelm@26574
    65
  let
wenzelm@26574
    66
    val doc = XML.Elem ("message", [], ts);
wenzelm@26574
    67
    val msg =
wenzelm@26574
    68
      if not (print_mode_active full_markupN) then
wenzelm@26574
    69
        Buffer.content (fold XML.add_content ts Buffer.empty)
wenzelm@26574
    70
      else if print_mode_active yxmlN then YXML.string_of doc
wenzelm@26574
    71
      else XML.header ^ XML.string_of doc;
wenzelm@26574
    72
  in clean_string [Symbol.STX] msg end;
wenzelm@26550
    73
wenzelm@26550
    74
fun message_pos ts = get_first get_pos ts
wenzelm@26550
    75
and get_pos (elem as XML.Elem (name, atts, ts)) =
wenzelm@25841
    76
      if name = Markup.positionN then SOME (Position.of_properties atts)
wenzelm@26550
    77
      else message_pos ts
wenzelm@27434
    78
  | get_pos _ = NONE;
wenzelm@25554
    79
wenzelm@25554
    80
in
wenzelm@25554
    81
wenzelm@27844
    82
fun message _ "" = ()
wenzelm@27844
    83
  | message ch body =
wenzelm@27844
    84
      let
wenzelm@27844
    85
        val (txt, pos) =
wenzelm@27844
    86
          let val ts = YXML.parse_body body
wenzelm@27844
    87
          in (message_text ts, the_default Position.none (message_pos ts)) end
wenzelm@27844
    88
          handle Fail msg => ("*** MALFORMED MESSAGE ***\n" ^ msg, Position.none);
wenzelm@27844
    89
        val props =
wenzelm@27844
    90
          Position.properties_of (Position.thread_data ())
wenzelm@27844
    91
          |> Position.default_properties pos;
wenzelm@27844
    92
      in Output.writeln_default (special ch ^ message_props props ^ txt ^ special_end) end;
wenzelm@25554
    93
wenzelm@25841
    94
fun init_message () =
wenzelm@25841
    95
  let
wenzelm@25849
    96
    val pid = ("pid", string_of_pid (Posix.ProcEnv.getpid ()));
wenzelm@25849
    97
    val session = ("session", List.last (Session.id ()) handle List.Empty => "unknown");
wenzelm@25841
    98
    val welcome = Session.welcome ();
wenzelm@26550
    99
  in Output.writeln_default (special "H" ^ message_props [pid, session] ^ welcome ^ special_end) end;
wenzelm@25748
   100
wenzelm@25554
   101
end;
wenzelm@25554
   102
wenzelm@25554
   103
wenzelm@25841
   104
(* channels *)
wenzelm@25841
   105
wenzelm@25841
   106
fun setup_channels () =
wenzelm@25849
   107
 (Output.writeln_fn  := message "A";
wenzelm@25849
   108
  Output.priority_fn := message "B";
wenzelm@25849
   109
  Output.tracing_fn  := message "C";
wenzelm@25849
   110
  Output.warning_fn  := message "D";
wenzelm@25849
   111
  Output.error_fn    := message "E";
wenzelm@25849
   112
  Output.debug_fn    := message "F";
wenzelm@27604
   113
  Output.prompt_fn   := message "G";
wenzelm@27604
   114
  Output.status_fn   := message "I");
wenzelm@25841
   115
wenzelm@25841
   116
wenzelm@25554
   117
(* init *)
wenzelm@25554
   118
wenzelm@25528
   119
fun init () =
wenzelm@25841
   120
 (change print_mode (update (op =) isabelle_processN);
wenzelm@25554
   121
  setup_channels ();
wenzelm@25841
   122
  init_message ();
wenzelm@26643
   123
  Isar.toplevel_loop {init = true, welcome = false, sync = true, secure = true});
wenzelm@25528
   124
wenzelm@25528
   125
end;
wenzelm@25528
   126