libisabelle-protocol/common/codec.ML
changeset 59216 f4693c6f4bb2
parent 59209 907ce624bd20
equal deleted inserted replaced
59215:35e792bef15f 59216:f4693c6f4bb2
     1 signature CODEC = sig
       
     2   datatype 'a result = Success of 'a | Failure of string * XML.body
       
     3   datatype ('a, 'b) either = Left of 'a | Right of 'b
       
     4   type 'a codec
       
     5 
       
     6   val the_success: 'a result -> 'a
       
     7 
       
     8   val map_result: ('a -> 'b) -> 'a result -> 'b result
       
     9   val bind_result: ('a -> 'b result) -> 'a result -> 'b result
       
    10   val sequence_results: 'a result list -> 'a list result
       
    11   val traverse_results: ('a -> 'b result) -> 'a list -> 'b list result
       
    12 
       
    13   val transform: ('a -> 'b) -> ('b -> 'a) -> 'a codec -> 'b codec
       
    14   val encode: 'a codec -> 'a -> XML.tree
       
    15   val decode: 'a codec -> XML.tree -> 'a result
       
    16 
       
    17   val basic: {encode: 'a -> XML.tree, decode: XML.tree -> 'a result} -> 'a codec
       
    18 
       
    19   val variant: ('a -> (int * XML.tree)) -> (int -> (XML.tree -> 'a result) option) -> string -> 'a codec
       
    20   val tagged: string -> 'a codec -> 'a codec
       
    21 
       
    22   val unit: unit codec
       
    23   val bool: bool codec
       
    24   val string: string codec
       
    25   val int: int codec
       
    26   val list: 'a codec -> 'a list codec
       
    27   val tuple: 'a codec -> 'b codec -> ('a * 'b) codec
       
    28   val triple: 'a codec -> 'b codec -> 'c codec -> ('a * 'b * 'c) codec
       
    29   val either: 'a codec -> 'b codec -> ('a, 'b) either codec
       
    30   val option: 'a codec -> 'a option codec
       
    31   val tree: XML.tree codec
       
    32 
       
    33   val sort: sort codec
       
    34   val typ: typ codec
       
    35   val term: term codec
       
    36 
       
    37   exception GENERIC of string
       
    38   val exn: exn codec
       
    39   val exn_result: 'a codec -> 'a Exn.result codec
       
    40 
       
    41   val id: XML.tree codec (* internal *)
       
    42 end
       
    43 
       
    44 structure Codec: CODEC = struct
       
    45 
       
    46 datatype 'a result = Success of 'a | Failure of string * XML.body
       
    47 datatype ('a, 'b) either = Left of 'a | Right of 'b
       
    48 
       
    49 fun map_result f (Success a) = Success (f a)
       
    50   | map_result _ (Failure (msg, body)) = Failure (msg, body)
       
    51 
       
    52 fun bind_result f (Success a) = f a
       
    53   | bind_result _ (Failure (msg, body)) = Failure (msg, body)
       
    54 
       
    55 fun traverse_results _ [] = Success []
       
    56   | traverse_results f (x :: xs) =
       
    57       case f x of
       
    58         Success y => map_result (fn ys => y :: ys) (traverse_results f xs)
       
    59       | Failure (msg, body) => Failure (msg, body)
       
    60 
       
    61 fun sequence_results xs = traverse_results I xs
       
    62 
       
    63 fun the_success (Success a) = a
       
    64   | the_success _ = raise Fail "unexpected failure"
       
    65 
       
    66 fun add_tag tag idx body =
       
    67   let
       
    68     val attrs = case idx of SOME i => [("idx", XML.Encode.int_atom i)] | _ => []
       
    69   in XML.Elem (("tag", ("type", tag) :: attrs), body) end
       
    70 
       
    71 fun expect_tag tag tree =
       
    72   case tree of
       
    73     XML.Elem (("tag", [("type", tag')]), body) =>
       
    74       if tag = tag' then
       
    75         Success body
       
    76       else
       
    77         Failure ("tag mismatch: expected " ^ tag ^ ", got " ^ tag', [tree])
       
    78   | _ =>
       
    79       Failure ("tag " ^ tag ^ " expected", [tree])
       
    80 
       
    81 fun expect_tag' tag tree =
       
    82   case tree of
       
    83     XML.Elem (("tag", [("type", tag'), ("idx", i)]), body) =>
       
    84       if tag = tag' then
       
    85         Success (XML.Decode.int_atom i, body)
       
    86           handle XML.XML_ATOM err => Failure (err, [tree])
       
    87       else
       
    88         Failure ("tag mismatch: expected " ^ tag ^ ", got " ^ tag', [tree])
       
    89   | _ =>
       
    90       Failure ("indexed tag " ^ tag ^ " expected", [tree])
       
    91 
       
    92 
       
    93 abstype 'a codec = Codec of {encode: 'a -> XML.tree, decode: XML.tree -> 'a result} with
       
    94 
       
    95 val basic = Codec
       
    96 
       
    97 fun encode (Codec {encode, ...}) = encode
       
    98 fun decode (Codec {decode, ...}) = decode
       
    99 
       
   100 fun transform f g (Codec {encode, decode}) = Codec
       
   101   {encode = g #> encode,
       
   102    decode = decode #> map_result f}
       
   103 
       
   104 fun list a = Codec
       
   105   {encode = map (encode a) #> add_tag "list" NONE,
       
   106    decode = expect_tag "list" #> bind_result (traverse_results (decode a))}
       
   107 
       
   108 fun tuple a b = Codec
       
   109   {encode = (fn (x, y) => add_tag "tuple" NONE [encode a x, encode b y]),
       
   110    decode = expect_tag "tuple" #> bind_result (fn body =>
       
   111      case body of
       
   112        [x, y] => decode a x |> bind_result (fn x' => decode b y |> map_result (pair x'))
       
   113      | _ => Failure ("invalid structure", body))}
       
   114 
       
   115 fun variant enc dec tag = Codec
       
   116   {encode = (fn a => let val (idx, tree) = enc a in add_tag tag (SOME idx) [tree] end),
       
   117    decode = (fn tree => expect_tag' tag tree |> bind_result (fn (idx, body) =>
       
   118      case (body, dec idx) of
       
   119        ([tree'], SOME res) => res tree'
       
   120      | (_, SOME _) => Failure ("invalid structure", [tree])
       
   121      | (_, NONE) => Failure ("invalid index " ^ Markup.print_int idx, [tree])))}
       
   122 
       
   123 fun tagged tag a = Codec
       
   124   {encode = encode a #> single #> add_tag tag NONE,
       
   125    decode = expect_tag tag #> bind_result (fn body =>
       
   126      case body of
       
   127        [tree] => decode a tree
       
   128      | _ => Failure ("invalid structure", body))}
       
   129 
       
   130 val unit = Codec
       
   131   {encode = K (add_tag "unit" NONE []),
       
   132    decode = expect_tag "unit" #> bind_result (fn body =>
       
   133      case body of
       
   134        [] => Success ()
       
   135      | _ => Failure ("expected nothing", body))}
       
   136 
       
   137 fun text to from = Codec
       
   138   {encode = XML.Text o to,
       
   139    decode =
       
   140     (fn tree as XML.Text content =>
       
   141           (case from content of
       
   142             NONE => Failure ("decoding failed", [tree]) |
       
   143             SOME a => Success a)
       
   144       | tree => Failure ("expected text tree", [tree]))}
       
   145 
       
   146 val id = Codec {encode = I, decode = Success}
       
   147 
       
   148 end
       
   149 
       
   150 val int = tagged "int" (text Markup.print_int (Exn.get_res o Exn.capture Markup.parse_int))
       
   151 val bool = tagged "bool" (text Markup.print_bool (Exn.get_res o Exn.capture Markup.parse_bool))
       
   152 val string = tagged "string" (text I SOME)
       
   153 
       
   154 val tree = tagged "XML.tree" id
       
   155 
       
   156 fun option a =
       
   157   let
       
   158     fun enc (SOME x) = (0, encode a x)
       
   159       | enc NONE = (1, encode unit ())
       
   160     fun dec 0 = SOME (decode a #> map_result SOME)
       
   161       | dec 1 = SOME (decode unit #> map_result (K NONE))
       
   162       | dec _ = NONE
       
   163   in variant enc dec "option" end
       
   164 
       
   165 val content_of =
       
   166   XML.content_of o YXML.parse_body
       
   167 
       
   168 (* slightly fishy codec, doesn't preserve exception type *)
       
   169 exception GENERIC of string
       
   170 val exn = tagged "exn" (text (fn exn => (content_of (@{make_string} exn))) (SOME o GENERIC))
       
   171 
       
   172 fun exn_result a =
       
   173   let
       
   174     fun enc (Exn.Res t) = (0, encode a t)
       
   175       | enc (Exn.Exn e) = (1, encode exn e)
       
   176     fun dec 0 = SOME (decode a #> map_result Exn.Res)
       
   177       | dec 1 = SOME (decode exn #> map_result Exn.Exn)
       
   178       | dec _ = NONE
       
   179   in variant enc dec "Exn.result" end
       
   180 
       
   181 fun triple a b c =
       
   182   tuple a (tuple b c)
       
   183   |> transform (fn (a, (b, c)) => (a, b, c)) (fn (a, b, c) => (a, (b, c)))
       
   184 
       
   185 fun either a b =
       
   186   let
       
   187     fun enc (Left l)  = (0, encode a l)
       
   188       | enc (Right r) = (1, encode b r)
       
   189     fun dec 0 = SOME (decode a #> map_result Left)
       
   190       | dec 1 = SOME (decode b #> map_result Right)
       
   191       | dec _ = NONE
       
   192   in variant enc dec "either" end
       
   193 
       
   194 val sort: sort codec = list string
       
   195 val indexname: indexname codec = tuple string int
       
   196 
       
   197 fun typ () =
       
   198   let
       
   199     fun typ_type () = tuple string (list (typ ()))
       
   200     val typ_tfree = tuple string sort
       
   201     val typ_tvar = tuple indexname sort
       
   202 
       
   203     fun enc (Type arg) =  (0, encode (typ_type ()) arg)
       
   204       | enc (TFree arg) = (1, encode typ_tfree arg)
       
   205       | enc (TVar arg) =  (2, encode typ_tvar arg)
       
   206     fun dec 0 = SOME (decode (typ_type ()) #> map_result Type)
       
   207       | dec 1 = SOME (decode typ_tfree #> map_result TFree)
       
   208       | dec 2 = SOME (decode typ_tvar #> map_result TVar)
       
   209       | dec _ = NONE
       
   210   in variant enc dec "Pure.typ" end
       
   211 
       
   212 val typ = typ ()
       
   213 
       
   214 fun term () =
       
   215   let
       
   216     val term_const = tuple string typ
       
   217     val term_free = tuple string typ
       
   218     val term_var = tuple indexname typ
       
   219     val term_bound = int
       
   220     fun term_abs () = triple string typ (term ())
       
   221     fun term_app () = tuple (term ()) (term ())
       
   222 
       
   223     fun enc (Const arg) = (0, encode term_const arg)
       
   224       | enc (Free arg) =  (1, encode term_free arg)
       
   225       | enc (Var arg) =   (2, encode term_var arg)
       
   226       | enc (Bound arg) = (3, encode term_bound arg)
       
   227       | enc (Abs arg) =   (4, encode (term_abs ()) arg)
       
   228       | enc (op $ arg) =  (5, encode (term_app ()) arg)
       
   229     fun dec 0 = SOME (decode term_const #> map_result Const)
       
   230       | dec 1 = SOME (decode term_free #> map_result Free)
       
   231       | dec 2 = SOME (decode term_var #> map_result Var)
       
   232       | dec 3 = SOME (decode term_bound #> map_result Bound)
       
   233       | dec 4 = SOME (decode (term_abs ()) #> map_result Abs)
       
   234       | dec 5 = SOME (decode (term_app ()) #> map_result op $)
       
   235       | dec _ = NONE
       
   236   in variant enc dec "Pure.term" end
       
   237 
       
   238 val term = term ()
       
   239 
       
   240 end
       
   241 
       
   242 type 'a codec = 'a Codec.codec