libisabelle-protocol/libisabelle/protocol/protocol.ML
changeset 59469 5c56f14bea53
parent 59340 097347b8910e
     1.1 --- /dev/null	Thu Jan 01 00:00:00 1970 +0000
     1.2 +++ b/libisabelle-protocol/libisabelle/protocol/protocol.ML	Tue Sep 04 14:50:30 2018 +0200
     1.3 @@ -0,0 +1,119 @@
     1.4 +signature LIBISABELLE_PROTOCOL = sig
     1.5 +  type name = string
     1.6 +  type ('i, 'o) operation =
     1.7 +    {from_lib : 'i codec,
     1.8 +     to_lib : 'o codec,
     1.9 +     action : 'i -> 'o}
    1.10 +
    1.11 +  type flags = {sequential: bool, bracket: bool, auto: bool (* ignored *)}
    1.12 +
    1.13 +  val default_flags : flags
    1.14 +  val join_flags : flags -> flags -> flags
    1.15 +  val print_flags : flags -> string
    1.16 +
    1.17 +  val add_operation : name -> ('i, 'o) operation -> flags -> unit
    1.18 +  val get_operation : name -> int -> XML.tree -> XML.tree
    1.19 +end
    1.20 +
    1.21 +structure Libisabelle_Protocol: LIBISABELLE_PROTOCOL = struct
    1.22 +
    1.23 +type name = string
    1.24 +type ('i, 'o) operation =
    1.25 +  {from_lib : 'i codec,
    1.26 +   to_lib : 'o codec,
    1.27 +   action : 'i -> 'o}
    1.28 +
    1.29 +type flags = {sequential: bool, bracket: bool, auto: bool}
    1.30 +
    1.31 +val default_flags = {sequential = false, bracket = false, auto = false}
    1.32 +
    1.33 +fun join_flags
    1.34 +  {sequential = seq1, bracket = br1, auto = a1}
    1.35 +  {sequential = seq2, bracket = br2, auto = a2} =
    1.36 +  {sequential = seq1 orelse seq2, bracket = br1 orelse br2, auto = a1 orelse a2}
    1.37 +
    1.38 +fun print_flags {sequential, bracket, auto} =
    1.39 +  "({sequential=" ^ print_bool sequential ^ "," ^
    1.40 +    "bracket=" ^ print_bool bracket ^ "," ^
    1.41 +    "auto=" ^ print_bool auto ^ "})"
    1.42 +
    1.43 +type raw_operation = int -> XML.tree -> XML.tree
    1.44 +
    1.45 +exception GENERIC of string
    1.46 +
    1.47 +val operations =
    1.48 +  Synchronized.var "libisabelle.operations" (Symtab.empty: raw_operation Symtab.table)
    1.49 +
    1.50 +val requests =
    1.51 +  Synchronized.var "libisabelle.requests" (Inttab.empty: (unit -> unit) Inttab.table)
    1.52 +
    1.53 +fun sequentialize name f =
    1.54 +  let
    1.55 +    val var = Synchronized.var ("libisabelle." ^ name) ()
    1.56 +  in
    1.57 +    fn x => Synchronized.change_result var (fn _ => (f x, ()))
    1.58 +  end
    1.59 +
    1.60 +fun bracketize f id x =
    1.61 +  let
    1.62 +    val start = [(Markup.functionN, "libisabelle_start"), ("id", print_int id)]
    1.63 +    val stop = [(Markup.functionN, "libisabelle_stop"), ("id", print_int id)]
    1.64 +    val _ = Output.protocol_message start []
    1.65 +    val res = f id x
    1.66 +    val _ = Output.protocol_message stop []
    1.67 +  in res end
    1.68 +
    1.69 +fun add_operation name {from_lib, to_lib, action} {sequential, bracket, ...} =
    1.70 +  let
    1.71 +    fun raw _ tree =
    1.72 +      case Codec.decode from_lib tree of
    1.73 +        Codec.Success i => Codec.encode to_lib (action i)
    1.74 +      | Codec.Failure (msg, _) => raise Fail ("decoding input failed for operation " ^ name ^ ": " ^ msg)
    1.75 +    val raw' = raw
    1.76 +      |> (if bracket then bracketize else I)
    1.77 +      |> (if sequential then sequentialize name else I)
    1.78 +  in
    1.79 +    Synchronized.change operations (Symtab.update (name, raw'))
    1.80 +  end
    1.81 +
    1.82 +fun get_operation name =
    1.83 +  case Symtab.lookup (Synchronized.value operations) name of
    1.84 +    SOME operation => operation
    1.85 +  | NONE => fn _ => error "libisabelle: unknown command"
    1.86 +
    1.87 +val _ = Isabelle_Process.protocol_command "libisabelle"
    1.88 +  (fn id :: name :: [arg] =>
    1.89 +    let
    1.90 +      val id = parse_int id
    1.91 +      val response = [(Markup.functionN, "libisabelle_response"), ("id", print_int id)]
    1.92 +      val args = YXML.parse arg
    1.93 +      fun exec f =
    1.94 +        let
    1.95 +          val future = Future.fork (fn () =>
    1.96 +            let
    1.97 +              val res = Exn.interruptible_capture (fn () => f id args) ()
    1.98 +              val yxml = YXML.string_of (Codec.encode (Codec.exn_result Codec.id) res)
    1.99 +            in
   1.100 +              Output.protocol_message response [yxml]
   1.101 +            end)
   1.102 +        in
   1.103 +          Synchronized.change requests (Inttab.update_new (id, fn () => Future.cancel future))
   1.104 +        end
   1.105 +    in
   1.106 +      exec (get_operation name)
   1.107 +    end)
   1.108 +
   1.109 +val _ = Isabelle_Process.protocol_command "libisabelle_cancel"
   1.110 +  (fn ids =>
   1.111 +    let
   1.112 +      fun remove id tab = (Inttab.lookup tab id, Inttab.delete_safe id tab)
   1.113 +      val _ =
   1.114 +        map parse_int ids
   1.115 +        |> fold_map remove
   1.116 +        |> Synchronized.change_result requests
   1.117 +        |> map (fn NONE => () | SOME f => f ())
   1.118 +    in
   1.119 +      ()
   1.120 +    end)
   1.121 +
   1.122 +end