10 import scala.annotation.tailrec |
10 import scala.annotation.tailrec |
11 import scala.collection.mutable |
11 import scala.collection.mutable |
12 import scala.util.matching.Regex |
12 import scala.util.matching.Regex |
13 |
13 |
14 |
14 |
15 object Library |
15 object Library { |
16 { |
|
17 /* resource management */ |
16 /* resource management */ |
18 |
17 |
19 def using[A <: AutoCloseable, B](a: A)(f: A => B): B = |
18 def using[A <: AutoCloseable, B](a: A)(f: A => B): B = { |
20 { |
|
21 try { f(a) } |
19 try { f(a) } |
22 finally { if (a != null) a.close() } |
20 finally { if (a != null) a.close() } |
23 } |
21 } |
24 |
22 |
25 |
23 |
26 /* integers */ |
24 /* integers */ |
27 |
25 |
28 private val small_int = 10000 |
26 private val small_int = 10000 |
29 private lazy val small_int_table = |
27 private lazy val small_int_table = { |
30 { |
|
31 val array = new Array[String](small_int) |
28 val array = new Array[String](small_int) |
32 for (i <- 0 until small_int) array(i) = i.toString |
29 for (i <- 0 until small_int) array(i) = i.toString |
33 array |
30 array |
34 } |
31 } |
35 |
32 |
36 def is_small_int(s: String): Boolean = |
33 def is_small_int(s: String): Boolean = { |
37 { |
|
38 val len = s.length |
34 val len = s.length |
39 1 <= len && len <= 4 && |
35 1 <= len && len <= 4 && |
40 s.forall(c => '0' <= c && c <= '9') && |
36 s.forall(c => '0' <= c && c <= '9') && |
41 (len == 1 || s(0) != '0') |
37 (len == 1 || s(0) != '0') |
42 } |
38 } |
70 } |
65 } |
71 |
66 |
72 def separated_chunks(sep: Char => Boolean, source: CharSequence): Iterator[CharSequence] = |
67 def separated_chunks(sep: Char => Boolean, source: CharSequence): Iterator[CharSequence] = |
73 new Iterator[CharSequence] { |
68 new Iterator[CharSequence] { |
74 private val end = source.length |
69 private val end = source.length |
75 private def next_chunk(i: Int): Option[(CharSequence, Int)] = |
70 private def next_chunk(i: Int): Option[(CharSequence, Int)] = { |
76 { |
|
77 if (i < end) { |
71 if (i < end) { |
78 var j = i |
72 var j = i |
79 var cont = true |
73 var cont = true |
80 while (cont) { |
74 while (cont) { |
81 j += 1 |
75 j += 1 |
113 isabelle.setup.Library.prefix_lines(prfx, str) |
107 isabelle.setup.Library.prefix_lines(prfx, str) |
114 |
108 |
115 def indent_lines(n: Int, str: String): String = |
109 def indent_lines(n: Int, str: String): String = |
116 prefix_lines(Symbol.spaces(n), str) |
110 prefix_lines(Symbol.spaces(n), str) |
117 |
111 |
118 def first_line(source: CharSequence): String = |
112 def first_line(source: CharSequence): String = { |
119 { |
|
120 val lines = separated_chunks(_ == '\n', source) |
113 val lines = separated_chunks(_ == '\n', source) |
121 if (lines.hasNext) lines.next().toString |
114 if (lines.hasNext) lines.next().toString |
122 else "" |
115 else "" |
123 } |
116 } |
124 |
117 |
172 def commas_quote(ss: Iterable[String]): String = ss.iterator.map(quote).mkString(", ") |
164 def commas_quote(ss: Iterable[String]): String = ss.iterator.map(quote).mkString(", ") |
173 |
165 |
174 |
166 |
175 /* CharSequence */ |
167 /* CharSequence */ |
176 |
168 |
177 class Reverse(text: CharSequence, start: Int, end: Int) extends CharSequence |
169 class Reverse(text: CharSequence, start: Int, end: Int) extends CharSequence { |
178 { |
|
179 require(0 <= start && start <= end && end <= text.length, "bad reverse range") |
170 require(0 <= start && start <= end && end <= text.length, "bad reverse range") |
180 |
171 |
181 def this(text: CharSequence) = this(text, 0, text.length) |
172 def this(text: CharSequence) = this(text, 0, text.length) |
182 |
173 |
183 def length: Int = end - start |
174 def length: Int = end - start |
185 |
176 |
186 def subSequence(i: Int, j: Int): CharSequence = |
177 def subSequence(i: Int, j: Int): CharSequence = |
187 if (0 <= i && i <= j && j <= length) new Reverse(text, end - j, end - i) |
178 if (0 <= i && i <= j && j <= length) new Reverse(text, end - j, end - i) |
188 else throw new IndexOutOfBoundsException |
179 else throw new IndexOutOfBoundsException |
189 |
180 |
190 override def toString: String = |
181 override def toString: String = { |
191 { |
|
192 val buf = new StringBuilder(length) |
182 val buf = new StringBuilder(length) |
193 for (i <- 0 until length) |
183 for (i <- 0 until length) |
194 buf.append(charAt(i)) |
184 buf.append(charAt(i)) |
195 buf.toString |
185 buf.toString |
196 } |
186 } |
197 } |
187 } |
198 |
188 |
199 class Line_Termination(text: CharSequence) extends CharSequence |
189 class Line_Termination(text: CharSequence) extends CharSequence { |
200 { |
|
201 def length: Int = text.length + 1 |
190 def length: Int = text.length + 1 |
202 def charAt(i: Int): Char = if (i == text.length) '\n' else text.charAt(i) |
191 def charAt(i: Int): Char = if (i == text.length) '\n' else text.charAt(i) |
203 def subSequence(i: Int, j: Int): CharSequence = |
192 def subSequence(i: Int, j: Int): CharSequence = |
204 if (j == text.length + 1) new Line_Termination(text.subSequence(i, j - 1)) |
193 if (j == text.length + 1) new Line_Termination(text.subSequence(i, j - 1)) |
205 else text.subSequence(i, j) |
194 else text.subSequence(i, j) |
225 /* lists */ |
214 /* lists */ |
226 |
215 |
227 def take_prefix[A](pred: A => Boolean, xs: List[A]): (List[A], List[A]) = |
216 def take_prefix[A](pred: A => Boolean, xs: List[A]): (List[A], List[A]) = |
228 (xs.takeWhile(pred), xs.dropWhile(pred)) |
217 (xs.takeWhile(pred), xs.dropWhile(pred)) |
229 |
218 |
230 def take_suffix[A](pred: A => Boolean, xs: List[A]): (List[A], List[A]) = |
219 def take_suffix[A](pred: A => Boolean, xs: List[A]): (List[A], List[A]) = { |
231 { |
|
232 val rev_xs = xs.reverse |
220 val rev_xs = xs.reverse |
233 (rev_xs.dropWhile(pred).reverse, rev_xs.takeWhile(pred).reverse) |
221 (rev_xs.dropWhile(pred).reverse, rev_xs.takeWhile(pred).reverse) |
234 } |
222 } |
235 |
223 |
236 def trim[A](pred: A => Boolean, xs: List[A]): List[A] = |
224 def trim[A](pred: A => Boolean, xs: List[A]): List[A] = |
244 def merge[A](xs: List[A], ys: List[A]): List[A] = |
232 def merge[A](xs: List[A], ys: List[A]): List[A] = |
245 if (xs.eq(ys)) xs |
233 if (xs.eq(ys)) xs |
246 else if (xs.isEmpty) ys |
234 else if (xs.isEmpty) ys |
247 else ys.foldRight(xs)(Library.insert(_)(_)) |
235 else ys.foldRight(xs)(Library.insert(_)(_)) |
248 |
236 |
249 def distinct[A](xs: List[A], eq: (A, A) => Boolean = (x: A, y: A) => x == y): List[A] = |
237 def distinct[A](xs: List[A], eq: (A, A) => Boolean = (x: A, y: A) => x == y): List[A] = { |
250 { |
|
251 val result = new mutable.ListBuffer[A] |
238 val result = new mutable.ListBuffer[A] |
252 xs.foreach(x => if (!result.exists(y => eq(x, y))) result += x) |
239 xs.foreach(x => if (!result.exists(y => eq(x, y))) result += x) |
253 result.toList |
240 result.toList |
254 } |
241 } |
255 |
242 |
256 def duplicates[A](lst: List[A], eq: (A, A) => Boolean = (x: A, y: A) => x == y): List[A] = |
243 def duplicates[A](lst: List[A], eq: (A, A) => Boolean = (x: A, y: A) => x == y): List[A] = { |
257 { |
|
258 val result = new mutable.ListBuffer[A] |
244 val result = new mutable.ListBuffer[A] |
259 @tailrec def dups(rest: List[A]): Unit = |
245 @tailrec def dups(rest: List[A]): Unit = |
260 rest match { |
246 rest match { |
261 case Nil => |
247 case Nil => |
262 case x :: xs => |
248 case x :: xs => |
295 if (list == null || list.isEmpty) None else Some(list) |
281 if (list == null || list.isEmpty) None else Some(list) |
296 |
282 |
297 |
283 |
298 /* reflection */ |
284 /* reflection */ |
299 |
285 |
300 def is_subclass[A, B](a: Class[A], b: Class[B]): Boolean = |
286 def is_subclass[A, B](a: Class[A], b: Class[B]): Boolean = { |
301 { |
|
302 import scala.language.existentials |
287 import scala.language.existentials |
303 @tailrec def subclass(c: Class[_]): Boolean = |
288 @tailrec def subclass(c: Class[_]): Boolean = { |
304 { |
289 c == b || { val d = c.getSuperclass; d != null && subclass(d) } |
305 c == b || |
|
306 { |
|
307 val d = c.getSuperclass |
|
308 d != null && subclass(d) |
|
309 } |
|
310 } |
290 } |
311 subclass(a) |
291 subclass(a) |
312 } |
292 } |
313 } |
293 } |