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 |
|