src/Pure/PIDE/byte_message.ML
author wenzelm
Wed, 12 Dec 2018 17:34:29 +0100
changeset 69454 ef051edd4d10
parent 69452 704915cf59fa
child 69467 e8893c893241
permissions -rw-r--r--
more uniform multi-language operations; misc tuning and clarification;
Ignore whitespace changes - Everywhere: Within whitespace: At end of lines:
69448
51e696887b81 more uniform multi-language operations;
wenzelm
parents:
diff changeset
     1
(*  Title:      Pure/General/byte_message.ML
51e696887b81 more uniform multi-language operations;
wenzelm
parents:
diff changeset
     2
    Author:     Makarius
51e696887b81 more uniform multi-language operations;
wenzelm
parents:
diff changeset
     3
51e696887b81 more uniform multi-language operations;
wenzelm
parents:
diff changeset
     4
Byte-oriented messages.
51e696887b81 more uniform multi-language operations;
wenzelm
parents:
diff changeset
     5
*)
51e696887b81 more uniform multi-language operations;
wenzelm
parents:
diff changeset
     6
51e696887b81 more uniform multi-language operations;
wenzelm
parents:
diff changeset
     7
signature BYTE_MESSAGE =
51e696887b81 more uniform multi-language operations;
wenzelm
parents:
diff changeset
     8
sig
69454
ef051edd4d10 more uniform multi-language operations;
wenzelm
parents: 69452
diff changeset
     9
  val write: BinIO.outstream -> string list -> unit
69451
387894c2fb2c more uniform multi-language operations;
wenzelm
parents: 69449
diff changeset
    10
  val flush: BinIO.outstream -> unit
69449
b516fdf8005c more uniform multi-language operations;
wenzelm
parents: 69448
diff changeset
    11
  val read: BinIO.instream -> int -> string
69452
704915cf59fa more uniform multi-language operations;
wenzelm
parents: 69451
diff changeset
    12
  val read_block: BinIO.instream -> int -> string option * int
69451
387894c2fb2c more uniform multi-language operations;
wenzelm
parents: 69449
diff changeset
    13
  val read_line: BinIO.instream -> string option
387894c2fb2c more uniform multi-language operations;
wenzelm
parents: 69449
diff changeset
    14
  val write_message: BinIO.outstream -> string list -> unit
69449
b516fdf8005c more uniform multi-language operations;
wenzelm
parents: 69448
diff changeset
    15
  val read_message: BinIO.instream -> string list option
69451
387894c2fb2c more uniform multi-language operations;
wenzelm
parents: 69449
diff changeset
    16
  val write_line_message: BinIO.outstream -> string -> unit
387894c2fb2c more uniform multi-language operations;
wenzelm
parents: 69449
diff changeset
    17
  val read_line_message: BinIO.instream -> string option
69448
51e696887b81 more uniform multi-language operations;
wenzelm
parents:
diff changeset
    18
end;
51e696887b81 more uniform multi-language operations;
wenzelm
parents:
diff changeset
    19
51e696887b81 more uniform multi-language operations;
wenzelm
parents:
diff changeset
    20
structure Byte_Message: BYTE_MESSAGE =
51e696887b81 more uniform multi-language operations;
wenzelm
parents:
diff changeset
    21
struct
51e696887b81 more uniform multi-language operations;
wenzelm
parents:
diff changeset
    22
69451
387894c2fb2c more uniform multi-language operations;
wenzelm
parents: 69449
diff changeset
    23
(* output operations *)
387894c2fb2c more uniform multi-language operations;
wenzelm
parents: 69449
diff changeset
    24
69454
ef051edd4d10 more uniform multi-language operations;
wenzelm
parents: 69452
diff changeset
    25
fun write stream = List.app (fn s => BinIO.output (stream, Byte.stringToBytes s));
69451
387894c2fb2c more uniform multi-language operations;
wenzelm
parents: 69449
diff changeset
    26
387894c2fb2c more uniform multi-language operations;
wenzelm
parents: 69449
diff changeset
    27
fun flush stream = ignore (try BinIO.flushOut stream);
387894c2fb2c more uniform multi-language operations;
wenzelm
parents: 69449
diff changeset
    28
387894c2fb2c more uniform multi-language operations;
wenzelm
parents: 69449
diff changeset
    29
387894c2fb2c more uniform multi-language operations;
wenzelm
parents: 69449
diff changeset
    30
(* input operations *)
387894c2fb2c more uniform multi-language operations;
wenzelm
parents: 69449
diff changeset
    31
69449
b516fdf8005c more uniform multi-language operations;
wenzelm
parents: 69448
diff changeset
    32
fun read stream n = Byte.bytesToString (BinIO.inputN (stream, n));
b516fdf8005c more uniform multi-language operations;
wenzelm
parents: 69448
diff changeset
    33
b516fdf8005c more uniform multi-language operations;
wenzelm
parents: 69448
diff changeset
    34
fun read_block stream n =
69452
704915cf59fa more uniform multi-language operations;
wenzelm
parents: 69451
diff changeset
    35
  let
704915cf59fa more uniform multi-language operations;
wenzelm
parents: 69451
diff changeset
    36
    val msg = read stream n;
704915cf59fa more uniform multi-language operations;
wenzelm
parents: 69451
diff changeset
    37
    val len = size msg;
704915cf59fa more uniform multi-language operations;
wenzelm
parents: 69451
diff changeset
    38
  in (if len = n then SOME msg else NONE, len) end;
69449
b516fdf8005c more uniform multi-language operations;
wenzelm
parents: 69448
diff changeset
    39
69448
51e696887b81 more uniform multi-language operations;
wenzelm
parents:
diff changeset
    40
fun read_line stream =
51e696887b81 more uniform multi-language operations;
wenzelm
parents:
diff changeset
    41
  let
51e696887b81 more uniform multi-language operations;
wenzelm
parents:
diff changeset
    42
    val result = trim_line o String.implode o rev;
69452
704915cf59fa more uniform multi-language operations;
wenzelm
parents: 69451
diff changeset
    43
    fun read_body cs =
69448
51e696887b81 more uniform multi-language operations;
wenzelm
parents:
diff changeset
    44
      (case BinIO.input1 stream of
51e696887b81 more uniform multi-language operations;
wenzelm
parents:
diff changeset
    45
        NONE => if null cs then NONE else SOME (result cs)
51e696887b81 more uniform multi-language operations;
wenzelm
parents:
diff changeset
    46
      | SOME b =>
51e696887b81 more uniform multi-language operations;
wenzelm
parents:
diff changeset
    47
          (case Byte.byteToChar b of
51e696887b81 more uniform multi-language operations;
wenzelm
parents:
diff changeset
    48
            #"\n" => SOME (result cs)
69452
704915cf59fa more uniform multi-language operations;
wenzelm
parents: 69451
diff changeset
    49
          | c => read_body (c :: cs)));
704915cf59fa more uniform multi-language operations;
wenzelm
parents: 69451
diff changeset
    50
  in read_body [] end;
69448
51e696887b81 more uniform multi-language operations;
wenzelm
parents:
diff changeset
    51
69449
b516fdf8005c more uniform multi-language operations;
wenzelm
parents: 69448
diff changeset
    52
69454
ef051edd4d10 more uniform multi-language operations;
wenzelm
parents: 69452
diff changeset
    53
(* messages with multiple chunks (arbitrary content) *)
69451
387894c2fb2c more uniform multi-language operations;
wenzelm
parents: 69449
diff changeset
    54
69454
ef051edd4d10 more uniform multi-language operations;
wenzelm
parents: 69452
diff changeset
    55
fun make_header stream ns =
ef051edd4d10 more uniform multi-language operations;
wenzelm
parents: 69452
diff changeset
    56
  [space_implode "," (map Value.print_int ns), "\n"];
69451
387894c2fb2c more uniform multi-language operations;
wenzelm
parents: 69449
diff changeset
    57
69454
ef051edd4d10 more uniform multi-language operations;
wenzelm
parents: 69452
diff changeset
    58
fun write_message stream chunks =
ef051edd4d10 more uniform multi-language operations;
wenzelm
parents: 69452
diff changeset
    59
  (write stream (make_header stream (map size chunks) @ chunks); flush stream);
69451
387894c2fb2c more uniform multi-language operations;
wenzelm
parents: 69449
diff changeset
    60
387894c2fb2c more uniform multi-language operations;
wenzelm
parents: 69449
diff changeset
    61
fun parse_header line =
387894c2fb2c more uniform multi-language operations;
wenzelm
parents: 69449
diff changeset
    62
  map Value.parse_nat (space_explode "," line)
69454
ef051edd4d10 more uniform multi-language operations;
wenzelm
parents: 69452
diff changeset
    63
    handle Fail _ => error ("Malformed message header: " ^ quote line);
69451
387894c2fb2c more uniform multi-language operations;
wenzelm
parents: 69449
diff changeset
    64
69449
b516fdf8005c more uniform multi-language operations;
wenzelm
parents: 69448
diff changeset
    65
fun read_chunk stream n =
69452
704915cf59fa more uniform multi-language operations;
wenzelm
parents: 69451
diff changeset
    66
  (case read_block stream n of
704915cf59fa more uniform multi-language operations;
wenzelm
parents: 69451
diff changeset
    67
    (SOME chunk, _) => chunk
704915cf59fa more uniform multi-language operations;
wenzelm
parents: 69451
diff changeset
    68
  | (NONE, len) =>
69449
b516fdf8005c more uniform multi-language operations;
wenzelm
parents: 69448
diff changeset
    69
      error ("Malformed message chunk: unexpected EOF after " ^
69452
704915cf59fa more uniform multi-language operations;
wenzelm
parents: 69451
diff changeset
    70
        string_of_int len ^ " of " ^ string_of_int n ^ " bytes"));
69449
b516fdf8005c more uniform multi-language operations;
wenzelm
parents: 69448
diff changeset
    71
b516fdf8005c more uniform multi-language operations;
wenzelm
parents: 69448
diff changeset
    72
fun read_message stream =
69454
ef051edd4d10 more uniform multi-language operations;
wenzelm
parents: 69452
diff changeset
    73
  read_line stream |> Option.map (parse_header #> map (read_chunk stream));
69451
387894c2fb2c more uniform multi-language operations;
wenzelm
parents: 69449
diff changeset
    74
387894c2fb2c more uniform multi-language operations;
wenzelm
parents: 69449
diff changeset
    75
387894c2fb2c more uniform multi-language operations;
wenzelm
parents: 69449
diff changeset
    76
(* hybrid messages: line or length+block (with content restriction) *)
387894c2fb2c more uniform multi-language operations;
wenzelm
parents: 69449
diff changeset
    77
69452
704915cf59fa more uniform multi-language operations;
wenzelm
parents: 69451
diff changeset
    78
fun is_length msg =
704915cf59fa more uniform multi-language operations;
wenzelm
parents: 69451
diff changeset
    79
  msg <> "" andalso forall_string Symbol.is_ascii_digit msg;
69451
387894c2fb2c more uniform multi-language operations;
wenzelm
parents: 69449
diff changeset
    80
69452
704915cf59fa more uniform multi-language operations;
wenzelm
parents: 69451
diff changeset
    81
fun is_terminated msg =
704915cf59fa more uniform multi-language operations;
wenzelm
parents: 69451
diff changeset
    82
  let val len = size msg
704915cf59fa more uniform multi-language operations;
wenzelm
parents: 69451
diff changeset
    83
  in len > 0 andalso Symbol.is_ascii_line_terminator (str (String.sub (msg, len - 1))) end;
69451
387894c2fb2c more uniform multi-language operations;
wenzelm
parents: 69449
diff changeset
    84
387894c2fb2c more uniform multi-language operations;
wenzelm
parents: 69449
diff changeset
    85
fun write_line_message stream msg =
69452
704915cf59fa more uniform multi-language operations;
wenzelm
parents: 69451
diff changeset
    86
  if is_length msg orelse is_terminated msg then
69451
387894c2fb2c more uniform multi-language operations;
wenzelm
parents: 69449
diff changeset
    87
    error ("Bad content for line message:\n" ^ implode (take 100 (Symbol.explode msg)))
387894c2fb2c more uniform multi-language operations;
wenzelm
parents: 69449
diff changeset
    88
  else
387894c2fb2c more uniform multi-language operations;
wenzelm
parents: 69449
diff changeset
    89
    let val n = size msg in
69454
ef051edd4d10 more uniform multi-language operations;
wenzelm
parents: 69452
diff changeset
    90
      write stream
ef051edd4d10 more uniform multi-language operations;
wenzelm
parents: 69452
diff changeset
    91
        ((if n > 100 orelse exists_string (fn s => s = "\n") msg
ef051edd4d10 more uniform multi-language operations;
wenzelm
parents: 69452
diff changeset
    92
          then make_header stream [n + 1] else []) @ [msg, "\n"]);
69451
387894c2fb2c more uniform multi-language operations;
wenzelm
parents: 69449
diff changeset
    93
      flush stream
387894c2fb2c more uniform multi-language operations;
wenzelm
parents: 69449
diff changeset
    94
    end;
387894c2fb2c more uniform multi-language operations;
wenzelm
parents: 69449
diff changeset
    95
387894c2fb2c more uniform multi-language operations;
wenzelm
parents: 69449
diff changeset
    96
fun read_line_message stream =
387894c2fb2c more uniform multi-language operations;
wenzelm
parents: 69449
diff changeset
    97
  (case read_line stream of
69452
704915cf59fa more uniform multi-language operations;
wenzelm
parents: 69451
diff changeset
    98
    NONE => NONE
704915cf59fa more uniform multi-language operations;
wenzelm
parents: 69451
diff changeset
    99
  | SOME line =>
69451
387894c2fb2c more uniform multi-language operations;
wenzelm
parents: 69449
diff changeset
   100
      (case try Value.parse_nat line of
387894c2fb2c more uniform multi-language operations;
wenzelm
parents: 69449
diff changeset
   101
        NONE => SOME line
69452
704915cf59fa more uniform multi-language operations;
wenzelm
parents: 69451
diff changeset
   102
      | SOME n => Option.map trim_line (#1 (read_block stream n))));
69448
51e696887b81 more uniform multi-language operations;
wenzelm
parents:
diff changeset
   103
51e696887b81 more uniform multi-language operations;
wenzelm
parents:
diff changeset
   104
end;