5 */ |
5 */ |
6 |
6 |
7 package isabelle |
7 package isabelle |
8 |
8 |
9 |
9 |
10 object XML |
10 object XML { |
11 { |
|
12 /** XML trees **/ |
11 /** XML trees **/ |
13 |
12 |
14 /* datatype representation */ |
13 /* datatype representation */ |
15 |
14 |
16 type Attribute = Properties.Entry |
15 type Attribute = Properties.Entry |
17 type Attributes = Properties.T |
16 type Attributes = Properties.T |
18 |
17 |
19 sealed abstract class Tree { override def toString: String = string_of_tree(this) } |
18 sealed abstract class Tree { override def toString: String = string_of_tree(this) } |
20 type Body = List[Tree] |
19 type Body = List[Tree] |
21 case class Elem(markup: Markup, body: Body) extends Tree |
20 case class Elem(markup: Markup, body: Body) extends Tree { |
22 { |
|
23 private lazy val hash: Int = (markup, body).hashCode() |
21 private lazy val hash: Int = (markup, body).hashCode() |
24 override def hashCode(): Int = hash |
22 override def hashCode(): Int = hash |
25 |
23 |
26 def name: String = markup.name |
24 def name: String = markup.name |
27 |
25 |
29 if (more_attributes.isEmpty) this |
27 if (more_attributes.isEmpty) this |
30 else Elem(markup.update_properties(more_attributes), body) |
28 else Elem(markup.update_properties(more_attributes), body) |
31 |
29 |
32 def + (att: Attribute): Elem = Elem(markup + att, body) |
30 def + (att: Attribute): Elem = Elem(markup + att, body) |
33 } |
31 } |
34 case class Text(content: String) extends Tree |
32 case class Text(content: String) extends Tree { |
35 { |
|
36 private lazy val hash: Int = content.hashCode() |
33 private lazy val hash: Int = content.hashCode() |
37 override def hashCode(): Int = hash |
34 override def hashCode(): Int = hash |
38 } |
35 } |
39 |
36 |
40 def elem(markup: Markup): XML.Elem = XML.Elem(markup, Nil) |
37 def elem(markup: Markup): XML.Elem = XML.Elem(markup, Nil) |
50 string(bg) ::: body ::: string(en) |
47 string(bg) ::: body ::: string(en) |
51 |
48 |
52 |
49 |
53 /* name space */ |
50 /* name space */ |
54 |
51 |
55 object Namespace |
52 object Namespace { |
56 { |
|
57 def apply(prefix: String, target: String): Namespace = |
53 def apply(prefix: String, target: String): Namespace = |
58 new Namespace(prefix, target) |
54 new Namespace(prefix, target) |
59 } |
55 } |
60 |
56 |
61 final class Namespace private(prefix: String, target: String) |
57 final class Namespace private(prefix: String, target: String) { |
62 { |
|
63 def apply(name: String): String = prefix + ":" + name |
58 def apply(name: String): String = prefix + ":" + name |
64 val attribute: XML.Attribute = ("xmlns:" + prefix, target) |
59 val attribute: XML.Attribute = ("xmlns:" + prefix, target) |
65 |
60 |
66 override def toString: String = attribute.toString |
61 override def toString: String = attribute.toString |
67 } |
62 } |
71 |
66 |
72 val XML_ELEM = "xml_elem" |
67 val XML_ELEM = "xml_elem" |
73 val XML_NAME = "xml_name" |
68 val XML_NAME = "xml_name" |
74 val XML_BODY = "xml_body" |
69 val XML_BODY = "xml_body" |
75 |
70 |
76 object Wrapped_Elem |
71 object Wrapped_Elem { |
77 { |
|
78 def apply(markup: Markup, body1: Body, body2: Body): XML.Elem = |
72 def apply(markup: Markup, body1: Body, body2: Body): XML.Elem = |
79 XML.Elem(Markup(XML_ELEM, (XML_NAME, markup.name) :: markup.properties), |
73 XML.Elem(Markup(XML_ELEM, (XML_NAME, markup.name) :: markup.properties), |
80 XML.Elem(Markup(XML_BODY, Nil), body1) :: body2) |
74 XML.Elem(Markup(XML_BODY, Nil), body1) :: body2) |
81 |
75 |
82 def unapply(tree: Tree): Option[(Markup, Body, Body)] = |
76 def unapply(tree: Tree): Option[(Markup, Body, Body)] = |
87 Some(Markup(name, props), body1, body2) |
81 Some(Markup(name, props), body1, body2) |
88 case _ => None |
82 case _ => None |
89 } |
83 } |
90 } |
84 } |
91 |
85 |
92 object Root_Elem |
86 object Root_Elem { |
93 { |
|
94 def apply(body: Body): XML.Elem = XML.Elem(Markup(XML_ELEM, Nil), body) |
87 def apply(body: Body): XML.Elem = XML.Elem(Markup(XML_ELEM, Nil), body) |
95 def unapply(tree: Tree): Option[Body] = |
88 def unapply(tree: Tree): Option[Body] = |
96 tree match { |
89 tree match { |
97 case XML.Elem(Markup(XML_ELEM, Nil), body) => Some(body) |
90 case XML.Elem(Markup(XML_ELEM, Nil), body) => Some(body) |
98 case _ => None |
91 case _ => None |
100 } |
93 } |
101 |
94 |
102 |
95 |
103 /* traverse text */ |
96 /* traverse text */ |
104 |
97 |
105 def traverse_text[A](body: Body)(a: A)(op: (A, String) => A): A = |
98 def traverse_text[A](body: Body)(a: A)(op: (A, String) => A): A = { |
106 { |
|
107 def traverse(x: A, t: Tree): A = |
99 def traverse(x: A, t: Tree): A = |
108 t match { |
100 t match { |
109 case XML.Wrapped_Elem(_, _, ts) => ts.foldLeft(x)(traverse) |
101 case XML.Wrapped_Elem(_, _, ts) => ts.foldLeft(x)(traverse) |
110 case XML.Elem(_, ts) => ts.foldLeft(x)(traverse) |
102 case XML.Elem(_, ts) => ts.foldLeft(x)(traverse) |
111 case XML.Text(s) => op(x, s) |
103 case XML.Text(s) => op(x, s) |
117 def symbol_length(body: Body): Int = traverse_text(body)(0) { case (n, s) => n + Symbol.length(s) } |
109 def symbol_length(body: Body): Int = traverse_text(body)(0) { case (n, s) => n + Symbol.length(s) } |
118 |
110 |
119 |
111 |
120 /* text content */ |
112 /* text content */ |
121 |
113 |
122 def content(body: Body): String = |
114 def content(body: Body): String = { |
123 { |
|
124 val text = new StringBuilder(text_length(body)) |
115 val text = new StringBuilder(text_length(body)) |
125 traverse_text(body)(()) { case (_, s) => text.append(s) } |
116 traverse_text(body)(()) { case (_, s) => text.append(s) } |
126 text.toString |
117 text.toString |
127 } |
118 } |
128 |
119 |
132 |
123 |
133 /** string representation **/ |
124 /** string representation **/ |
134 |
125 |
135 val header: String = "<?xml version=\"1.0\" encoding=\"utf-8\"?>\n" |
126 val header: String = "<?xml version=\"1.0\" encoding=\"utf-8\"?>\n" |
136 |
127 |
137 def output_char(s: StringBuilder, c: Char, permissive: Boolean = false): Unit = |
128 def output_char(s: StringBuilder, c: Char, permissive: Boolean = false): Unit = { |
138 { |
|
139 c match { |
129 c match { |
140 case '<' => s ++= "<" |
130 case '<' => s ++= "<" |
141 case '>' => s ++= ">" |
131 case '>' => s ++= ">" |
142 case '&' => s ++= "&" |
132 case '&' => s ++= "&" |
143 case '"' if !permissive => s ++= """ |
133 case '"' if !permissive => s ++= """ |
144 case '\'' if !permissive => s ++= "'" |
134 case '\'' if !permissive => s ++= "'" |
145 case _ => s += c |
135 case _ => s += c |
146 } |
136 } |
147 } |
137 } |
148 |
138 |
149 def output_string(s: StringBuilder, str: String, permissive: Boolean = false): Unit = |
139 def output_string(s: StringBuilder, str: String, permissive: Boolean = false): Unit = { |
150 { |
|
151 if (str == null) s ++= str |
140 if (str == null) s ++= str |
152 else str.iterator.foreach(output_char(s, _, permissive = permissive)) |
141 else str.iterator.foreach(output_char(s, _, permissive = permissive)) |
153 } |
142 } |
154 |
143 |
155 def output_elem(s: StringBuilder, markup: Markup, end: Boolean = false): Unit = |
144 def output_elem(s: StringBuilder, markup: Markup, end: Boolean = false): Unit = { |
156 { |
|
157 s += '<' |
145 s += '<' |
158 s ++= markup.name |
146 s ++= markup.name |
159 for ((a, b) <- markup.properties) { |
147 for ((a, b) <- markup.properties) { |
160 s += ' ' |
148 s += ' ' |
161 s ++= a |
149 s ++= a |
166 } |
154 } |
167 if (end) s += '/' |
155 if (end) s += '/' |
168 s += '>' |
156 s += '>' |
169 } |
157 } |
170 |
158 |
171 def output_elem_end(s: StringBuilder, name: String): Unit = |
159 def output_elem_end(s: StringBuilder, name: String): Unit = { |
172 { |
|
173 s += '<' |
160 s += '<' |
174 s += '/' |
161 s += '/' |
175 s ++= name |
162 s ++= name |
176 s += '>' |
163 s += '>' |
177 } |
164 } |
178 |
165 |
179 def string_of_body(body: Body): String = |
166 def string_of_body(body: Body): String = { |
180 { |
|
181 val s = new StringBuilder |
167 val s = new StringBuilder |
182 |
168 |
183 def tree(t: Tree): Unit = |
169 def tree(t: Tree): Unit = |
184 t match { |
170 t match { |
185 case XML.Elem(markup, Nil) => |
171 case XML.Elem(markup, Nil) => |
199 def text(s: String): String = string_of_tree(XML.Text(s)) |
185 def text(s: String): String = string_of_tree(XML.Text(s)) |
200 |
186 |
201 |
187 |
202 /** cache **/ |
188 /** cache **/ |
203 |
189 |
204 object Cache |
190 object Cache { |
205 { |
|
206 def make( |
191 def make( |
207 xz: XZ.Cache = XZ.Cache.make(), |
192 xz: XZ.Cache = XZ.Cache.make(), |
208 max_string: Int = isabelle.Cache.default_max_string, |
193 max_string: Int = isabelle.Cache.default_max_string, |
209 initial_size: Int = isabelle.Cache.default_initial_size): Cache = |
194 initial_size: Int = isabelle.Cache.default_initial_size): Cache = |
210 new Cache(xz, max_string, initial_size) |
195 new Cache(xz, max_string, initial_size) |
211 |
196 |
212 val none: Cache = make(XZ.Cache.none, max_string = 0) |
197 val none: Cache = make(XZ.Cache.none, max_string = 0) |
213 } |
198 } |
214 |
199 |
215 class Cache(val xz: XZ.Cache, max_string: Int, initial_size: Int) |
200 class Cache(val xz: XZ.Cache, max_string: Int, initial_size: Int) |
216 extends isabelle.Cache(max_string, initial_size) |
201 extends isabelle.Cache(max_string, initial_size) { |
217 { |
202 protected def cache_props(x: Properties.T): Properties.T = { |
218 protected def cache_props(x: Properties.T): Properties.T = |
|
219 { |
|
220 if (x.isEmpty) x |
203 if (x.isEmpty) x |
221 else |
204 else |
222 lookup(x) match { |
205 lookup(x) match { |
223 case Some(y) => y |
206 case Some(y) => y |
224 case None => store(x.map(p => (Library.isolate_substring(p._1).intern, cache_string(p._2)))) |
207 case None => store(x.map(p => (Library.isolate_substring(p._1).intern, cache_string(p._2)))) |
225 } |
208 } |
226 } |
209 } |
227 |
210 |
228 protected def cache_markup(x: Markup): Markup = |
211 protected def cache_markup(x: Markup): Markup = { |
229 { |
|
230 lookup(x) match { |
212 lookup(x) match { |
231 case Some(y) => y |
213 case Some(y) => y |
232 case None => |
214 case None => |
233 x match { |
215 x match { |
234 case Markup(name, props) => |
216 case Markup(name, props) => |
235 store(Markup(cache_string(name), cache_props(props))) |
217 store(Markup(cache_string(name), cache_props(props))) |
236 } |
218 } |
237 } |
219 } |
238 } |
220 } |
239 |
221 |
240 protected def cache_tree(x: XML.Tree): XML.Tree = |
222 protected def cache_tree(x: XML.Tree): XML.Tree = { |
241 { |
|
242 lookup(x) match { |
223 lookup(x) match { |
243 case Some(y) => y |
224 case Some(y) => y |
244 case None => |
225 case None => |
245 x match { |
226 x match { |
246 case XML.Elem(markup, body) => |
227 case XML.Elem(markup, body) => |
283 |
263 |
284 abstract class Error(s: String) extends Exception(s) |
264 abstract class Error(s: String) extends Exception(s) |
285 class XML_Atom(s: String) extends Error(s) |
265 class XML_Atom(s: String) extends Error(s) |
286 class XML_Body(body: XML.Body) extends Error("") |
266 class XML_Body(body: XML.Body) extends Error("") |
287 |
267 |
288 object Encode |
268 object Encode { |
289 { |
|
290 type T[A] = A => XML.Body |
269 type T[A] = A => XML.Body |
291 type V[A] = PartialFunction[A, (List[String], XML.Body)] |
270 type V[A] = PartialFunction[A, (List[String], XML.Body)] |
292 type P[A] = PartialFunction[A, List[String]] |
271 type P[A] = PartialFunction[A, List[String]] |
293 |
272 |
294 |
273 |
338 (x => List(node(f(x._1)), node(g(x._2)), node(h(x._3)))) |
317 (x => List(node(f(x._1)), node(g(x._2)), node(h(x._3)))) |
339 |
318 |
340 def list[A](f: T[A]): T[List[A]] = |
319 def list[A](f: T[A]): T[List[A]] = |
341 (xs => xs.map((x: A) => node(f(x)))) |
320 (xs => xs.map((x: A) => node(f(x)))) |
342 |
321 |
343 def option[A](f: T[A]): T[Option[A]] = |
322 def option[A](f: T[A]): T[Option[A]] = { |
344 { |
|
345 case None => Nil |
323 case None => Nil |
346 case Some(x) => List(node(f(x))) |
324 case Some(x) => List(node(f(x))) |
347 } |
325 } |
348 |
326 |
349 def variant[A](fs: List[V[A]]): T[A] = |
327 def variant[A](fs: List[V[A]]): T[A] = { |
350 { |
|
351 case x => |
328 case x => |
352 val (f, tag) = fs.iterator.zipWithIndex.find(p => p._1.isDefinedAt(x)).get |
329 val (f, tag) = fs.iterator.zipWithIndex.find(p => p._1.isDefinedAt(x)).get |
353 List(tagged(tag, f(x))) |
330 List(tagged(tag, f(x))) |
354 } |
331 } |
355 } |
332 } |
356 |
333 |
357 object Decode |
334 object Decode { |
358 { |
|
359 type T[A] = XML.Body => A |
335 type T[A] = XML.Body => A |
360 type V[A] = (List[String], XML.Body) => A |
336 type V[A] = (List[String], XML.Body) => A |
361 type P[A] = PartialFunction[List[String], A] |
337 type P[A] = PartialFunction[List[String], A] |
362 |
338 |
363 |
339 |
399 } |
375 } |
400 |
376 |
401 |
377 |
402 /* representation of standard types */ |
378 /* representation of standard types */ |
403 |
379 |
404 val tree: T[XML.Tree] = |
380 val tree: T[XML.Tree] = { |
405 { |
|
406 case List(t) => t |
381 case List(t) => t |
407 case ts => throw new XML_Body(ts) |
382 case ts => throw new XML_Body(ts) |
408 } |
383 } |
409 |
384 |
410 val properties: T[Properties.T] = |
385 val properties: T[Properties.T] = { |
411 { |
|
412 case List(XML.Elem(Markup(":", props), Nil)) => props |
386 case List(XML.Elem(Markup(":", props), Nil)) => props |
413 case ts => throw new XML_Body(ts) |
387 case ts => throw new XML_Body(ts) |
414 } |
388 } |
415 |
389 |
416 val string: T[String] = |
390 val string: T[String] = { |
417 { |
|
418 case Nil => "" |
391 case Nil => "" |
419 case List(XML.Text(s)) => s |
392 case List(XML.Text(s)) => s |
420 case ts => throw new XML_Body(ts) |
393 case ts => throw new XML_Body(ts) |
421 } |
394 } |
422 |
395 |
426 |
399 |
427 val bool: T[Boolean] = (x => bool_atom(string(x))) |
400 val bool: T[Boolean] = (x => bool_atom(string(x))) |
428 |
401 |
429 val unit: T[Unit] = (x => unit_atom(string(x))) |
402 val unit: T[Unit] = (x => unit_atom(string(x))) |
430 |
403 |
431 def pair[A, B](f: T[A], g: T[B]): T[(A, B)] = |
404 def pair[A, B](f: T[A], g: T[B]): T[(A, B)] = { |
432 { |
|
433 case List(t1, t2) => (f(node(t1)), g(node(t2))) |
405 case List(t1, t2) => (f(node(t1)), g(node(t2))) |
434 case ts => throw new XML_Body(ts) |
406 case ts => throw new XML_Body(ts) |
435 } |
407 } |
436 |
408 |
437 def triple[A, B, C](f: T[A], g: T[B], h: T[C]): T[(A, B, C)] = |
409 def triple[A, B, C](f: T[A], g: T[B], h: T[C]): T[(A, B, C)] = { |
438 { |
|
439 case List(t1, t2, t3) => (f(node(t1)), g(node(t2)), h(node(t3))) |
410 case List(t1, t2, t3) => (f(node(t1)), g(node(t2)), h(node(t3))) |
440 case ts => throw new XML_Body(ts) |
411 case ts => throw new XML_Body(ts) |
441 } |
412 } |
442 |
413 |
443 def list[A](f: T[A]): T[List[A]] = |
414 def list[A](f: T[A]): T[List[A]] = |
444 (ts => ts.map(t => f(node(t)))) |
415 (ts => ts.map(t => f(node(t)))) |
445 |
416 |
446 def option[A](f: T[A]): T[Option[A]] = |
417 def option[A](f: T[A]): T[Option[A]] = { |
447 { |
|
448 case Nil => None |
418 case Nil => None |
449 case List(t) => Some(f(node(t))) |
419 case List(t) => Some(f(node(t))) |
450 case ts => throw new XML_Body(ts) |
420 case ts => throw new XML_Body(ts) |
451 } |
421 } |
452 |
422 |
453 def variant[A](fs: List[V[A]]): T[A] = |
423 def variant[A](fs: List[V[A]]): T[A] = { |
454 { |
|
455 case List(t) => |
424 case List(t) => |
456 val (tag, (xs, ts)) = tagged(t) |
425 val (tag, (xs, ts)) = tagged(t) |
457 val f = |
426 val f = |
458 try { fs(tag) } |
427 try { fs(tag) } |
459 catch { case _: IndexOutOfBoundsException => throw new XML_Body(List(t)) } |
428 catch { case _: IndexOutOfBoundsException => throw new XML_Body(List(t)) } |