| author | wenzelm | 
| Thu, 17 Mar 2016 10:54:28 +0100 | |
| changeset 62659 | bb29cc00c31f | 
| parent 62590 | 0c837beeb5e7 | 
| child 63734 | 133e3e84e6fb | 
| permissions | -rw-r--r-- | 
| 34136 | 1 | /* Title: Pure/library.scala | 
| 45673 
cd41e3903fbf
separate compilation of PIDE vs. Pure sources, which enables independent Scala library;
 wenzelm parents: 
45667diff
changeset | 2 | Module: PIDE | 
| 34136 | 3 | Author: Makarius | 
| 4 | ||
| 5 | Basic library. | |
| 6 | */ | |
| 7 | ||
| 8 | package isabelle | |
| 9 | ||
| 38258 | 10 | |
| 51981 
a8ffd3692f57
more scalable Library.separate -- NB: JVM has tiny fixed-size stack;
 wenzelm parents: 
51616diff
changeset | 11 | import scala.collection.mutable | 
| 59224 | 12 | import scala.util.matching.Regex | 
| 51981 
a8ffd3692f57
more scalable Library.separate -- NB: JVM has tiny fixed-size stack;
 wenzelm parents: 
51616diff
changeset | 13 | |
| 37018 | 14 | |
| 34136 | 15 | object Library | 
| 16 | {
 | |
| 57909 
0fb331032f02
more compact representation of special string values;
 wenzelm parents: 
57831diff
changeset | 17 | /* integers */ | 
| 
0fb331032f02
more compact representation of special string values;
 wenzelm parents: 
57831diff
changeset | 18 | |
| 
0fb331032f02
more compact representation of special string values;
 wenzelm parents: 
57831diff
changeset | 19 | private val small_int = 10000 | 
| 
0fb331032f02
more compact representation of special string values;
 wenzelm parents: 
57831diff
changeset | 20 | private lazy val small_int_table = | 
| 
0fb331032f02
more compact representation of special string values;
 wenzelm parents: 
57831diff
changeset | 21 |   {
 | 
| 
0fb331032f02
more compact representation of special string values;
 wenzelm parents: 
57831diff
changeset | 22 | val array = new Array[String](small_int) | 
| 
0fb331032f02
more compact representation of special string values;
 wenzelm parents: 
57831diff
changeset | 23 | for (i <- 0 until small_int) array(i) = i.toString | 
| 
0fb331032f02
more compact representation of special string values;
 wenzelm parents: 
57831diff
changeset | 24 | array | 
| 
0fb331032f02
more compact representation of special string values;
 wenzelm parents: 
57831diff
changeset | 25 | } | 
| 
0fb331032f02
more compact representation of special string values;
 wenzelm parents: 
57831diff
changeset | 26 | |
| 
0fb331032f02
more compact representation of special string values;
 wenzelm parents: 
57831diff
changeset | 27 | def is_small_int(s: String): Boolean = | 
| 
0fb331032f02
more compact representation of special string values;
 wenzelm parents: 
57831diff
changeset | 28 |   {
 | 
| 
0fb331032f02
more compact representation of special string values;
 wenzelm parents: 
57831diff
changeset | 29 | val len = s.length | 
| 
0fb331032f02
more compact representation of special string values;
 wenzelm parents: 
57831diff
changeset | 30 | 1 <= len && len <= 4 && | 
| 
0fb331032f02
more compact representation of special string values;
 wenzelm parents: 
57831diff
changeset | 31 | s.forall(c => '0' <= c && c <= '9') && | 
| 
0fb331032f02
more compact representation of special string values;
 wenzelm parents: 
57831diff
changeset | 32 | (len == 1 || s(0) != '0') | 
| 
0fb331032f02
more compact representation of special string values;
 wenzelm parents: 
57831diff
changeset | 33 | } | 
| 
0fb331032f02
more compact representation of special string values;
 wenzelm parents: 
57831diff
changeset | 34 | |
| 
0fb331032f02
more compact representation of special string values;
 wenzelm parents: 
57831diff
changeset | 35 | def signed_string_of_long(i: Long): String = | 
| 
0fb331032f02
more compact representation of special string values;
 wenzelm parents: 
57831diff
changeset | 36 | if (0 <= i && i < small_int) small_int_table(i.toInt) | 
| 
0fb331032f02
more compact representation of special string values;
 wenzelm parents: 
57831diff
changeset | 37 | else i.toString | 
| 
0fb331032f02
more compact representation of special string values;
 wenzelm parents: 
57831diff
changeset | 38 | |
| 
0fb331032f02
more compact representation of special string values;
 wenzelm parents: 
57831diff
changeset | 39 | def signed_string_of_int(i: Int): String = | 
| 
0fb331032f02
more compact representation of special string values;
 wenzelm parents: 
57831diff
changeset | 40 | if (0 <= i && i < small_int) small_int_table(i) | 
| 
0fb331032f02
more compact representation of special string values;
 wenzelm parents: 
57831diff
changeset | 41 | else i.toString | 
| 
0fb331032f02
more compact representation of special string values;
 wenzelm parents: 
57831diff
changeset | 42 | |
| 
0fb331032f02
more compact representation of special string values;
 wenzelm parents: 
57831diff
changeset | 43 | |
| 48996 | 44 | /* separated chunks */ | 
| 36688 | 45 | |
| 46 | def separate[A](s: A, list: List[A]): List[A] = | |
| 51981 
a8ffd3692f57
more scalable Library.separate -- NB: JVM has tiny fixed-size stack;
 wenzelm parents: 
51616diff
changeset | 47 |   {
 | 
| 
a8ffd3692f57
more scalable Library.separate -- NB: JVM has tiny fixed-size stack;
 wenzelm parents: 
51616diff
changeset | 48 | val result = new mutable.ListBuffer[A] | 
| 
a8ffd3692f57
more scalable Library.separate -- NB: JVM has tiny fixed-size stack;
 wenzelm parents: 
51616diff
changeset | 49 | var first = true | 
| 
a8ffd3692f57
more scalable Library.separate -- NB: JVM has tiny fixed-size stack;
 wenzelm parents: 
51616diff
changeset | 50 |     for (x <- list) {
 | 
| 
a8ffd3692f57
more scalable Library.separate -- NB: JVM has tiny fixed-size stack;
 wenzelm parents: 
51616diff
changeset | 51 |       if (first) {
 | 
| 
a8ffd3692f57
more scalable Library.separate -- NB: JVM has tiny fixed-size stack;
 wenzelm parents: 
51616diff
changeset | 52 | first = false | 
| 
a8ffd3692f57
more scalable Library.separate -- NB: JVM has tiny fixed-size stack;
 wenzelm parents: 
51616diff
changeset | 53 | result += x | 
| 
a8ffd3692f57
more scalable Library.separate -- NB: JVM has tiny fixed-size stack;
 wenzelm parents: 
51616diff
changeset | 54 | } | 
| 
a8ffd3692f57
more scalable Library.separate -- NB: JVM has tiny fixed-size stack;
 wenzelm parents: 
51616diff
changeset | 55 |       else {
 | 
| 
a8ffd3692f57
more scalable Library.separate -- NB: JVM has tiny fixed-size stack;
 wenzelm parents: 
51616diff
changeset | 56 | result += s | 
| 
a8ffd3692f57
more scalable Library.separate -- NB: JVM has tiny fixed-size stack;
 wenzelm parents: 
51616diff
changeset | 57 | result += x | 
| 
a8ffd3692f57
more scalable Library.separate -- NB: JVM has tiny fixed-size stack;
 wenzelm parents: 
51616diff
changeset | 58 | } | 
| 36688 | 59 | } | 
| 51981 
a8ffd3692f57
more scalable Library.separate -- NB: JVM has tiny fixed-size stack;
 wenzelm parents: 
51616diff
changeset | 60 | result.toList | 
| 
a8ffd3692f57
more scalable Library.separate -- NB: JVM has tiny fixed-size stack;
 wenzelm parents: 
51616diff
changeset | 61 | } | 
| 36688 | 62 | |
| 56600 | 63 | def separated_chunks(sep: Char => Boolean, source: CharSequence): Iterator[CharSequence] = | 
| 48996 | 64 |     new Iterator[CharSequence] {
 | 
| 65 | private val end = source.length | |
| 66 | private def next_chunk(i: Int): Option[(CharSequence, Int)] = | |
| 67 |       {
 | |
| 68 |         if (i < end) {
 | |
| 56600 | 69 | var j = i; do j += 1 while (j < end && !sep(source.charAt(j))) | 
| 48996 | 70 | Some((source.subSequence(i + 1, j), j)) | 
| 71 | } | |
| 72 | else None | |
| 43598 | 73 | } | 
| 48996 | 74 | private var state: Option[(CharSequence, Int)] = if (end == 0) None else next_chunk(-1) | 
| 75 | ||
| 76 | def hasNext(): Boolean = state.isDefined | |
| 77 | def next(): CharSequence = | |
| 78 |         state match {
 | |
| 60215 | 79 | case Some((s, i)) => state = next_chunk(i); s | 
| 48996 | 80 | case None => Iterator.empty.next() | 
| 81 | } | |
| 43598 | 82 | } | 
| 83 | ||
| 48996 | 84 | def space_explode(sep: Char, str: String): List[String] = | 
| 56600 | 85 | separated_chunks(_ == sep, str).map(_.toString).toList | 
| 48996 | 86 | |
| 87 | ||
| 88 | /* lines */ | |
| 89 | ||
| 51983 
32692ce4c61a
more frugal line termination, to cope with huge log files (see also 016cb7d8f297);
 wenzelm parents: 
51981diff
changeset | 90 | def terminate_lines(lines: Iterable[CharSequence]): Iterable[CharSequence] = | 
| 
32692ce4c61a
more frugal line termination, to cope with huge log files (see also 016cb7d8f297);
 wenzelm parents: 
51981diff
changeset | 91 |     new Iterable[CharSequence] {
 | 
| 
32692ce4c61a
more frugal line termination, to cope with huge log files (see also 016cb7d8f297);
 wenzelm parents: 
51981diff
changeset | 92 | def iterator: Iterator[CharSequence] = | 
| 
32692ce4c61a
more frugal line termination, to cope with huge log files (see also 016cb7d8f297);
 wenzelm parents: 
51981diff
changeset | 93 | lines.iterator.map(line => new Line_Termination(line)) | 
| 
32692ce4c61a
more frugal line termination, to cope with huge log files (see also 016cb7d8f297);
 wenzelm parents: 
51981diff
changeset | 94 | } | 
| 
32692ce4c61a
more frugal line termination, to cope with huge log files (see also 016cb7d8f297);
 wenzelm parents: 
51981diff
changeset | 95 | |
| 48996 | 96 |   def cat_lines(lines: TraversableOnce[String]): String = lines.mkString("\n")
 | 
| 97 | ||
| 43670 
7f933761764b
prefer space_explode/split_lines as in Isabelle/ML;
 wenzelm parents: 
43652diff
changeset | 98 |   def split_lines(str: String): List[String] = space_explode('\n', str)
 | 
| 
7f933761764b
prefer space_explode/split_lines as in Isabelle/ML;
 wenzelm parents: 
43652diff
changeset | 99 | |
| 62590 | 100 | def prefix_lines(prfx: String, str: String): String = | 
| 101 | if (str == "") str | |
| 102 | else cat_lines(split_lines(str).map(s => prfx + s)) | |
| 103 | ||
| 48996 | 104 | def first_line(source: CharSequence): String = | 
| 105 |   {
 | |
| 56600 | 106 | val lines = separated_chunks(_ == '\n', source) | 
| 48996 | 107 | if (lines.hasNext) lines.next.toString | 
| 108 | else "" | |
| 109 | } | |
| 110 | ||
| 50847 | 111 | |
| 112 | /* strings */ | |
| 113 | ||
| 114 | def try_unprefix(prfx: String, s: String): Option[String] = | |
| 115 | if (s.startsWith(prfx)) Some(s.substring(prfx.length)) else None | |
| 116 | ||
| 55033 | 117 | def try_unsuffix(sffx: String, s: String): Option[String] = | 
| 118 | if (s.endsWith(sffx)) Some(s.substring(0, s.length - sffx.length)) else None | |
| 119 | ||
| 52444 
2cfe6656d6d6
slightly improved "isabelle doc" based on Isabelle/Scala;
 wenzelm parents: 
51983diff
changeset | 120 | def trim_line(s: String): String = | 
| 
2cfe6656d6d6
slightly improved "isabelle doc" based on Isabelle/Scala;
 wenzelm parents: 
51983diff
changeset | 121 |     if (s.endsWith("\r\n")) s.substring(0, s.length - 2)
 | 
| 
2cfe6656d6d6
slightly improved "isabelle doc" based on Isabelle/Scala;
 wenzelm parents: 
51983diff
changeset | 122 |     else if (s.endsWith("\r") || s.endsWith("\n")) s.substring(0, s.length - 1)
 | 
| 
2cfe6656d6d6
slightly improved "isabelle doc" based on Isabelle/Scala;
 wenzelm parents: 
51983diff
changeset | 123 | else s | 
| 
2cfe6656d6d6
slightly improved "isabelle doc" based on Isabelle/Scala;
 wenzelm parents: 
51983diff
changeset | 124 | |
| 43598 | 125 | |
| 48996 | 126 | /* quote */ | 
| 46196 | 127 | |
| 43598 | 128 | def quote(s: String): String = "\"" + s + "\"" | 
| 56843 
b2bfcd8cda80
support for path completion based on file-system content;
 wenzelm parents: 
56730diff
changeset | 129 | |
| 
b2bfcd8cda80
support for path completion based on file-system content;
 wenzelm parents: 
56730diff
changeset | 130 | def try_unquote(s: String): Option[String] = | 
| 
b2bfcd8cda80
support for path completion based on file-system content;
 wenzelm parents: 
56730diff
changeset | 131 |     if (s.startsWith("\"") && s.endsWith("\"")) Some(s.substring(1, s.length - 1))
 | 
| 
b2bfcd8cda80
support for path completion based on file-system content;
 wenzelm parents: 
56730diff
changeset | 132 | else None | 
| 
b2bfcd8cda80
support for path completion based on file-system content;
 wenzelm parents: 
56730diff
changeset | 133 | |
| 58592 | 134 | def perhaps_unquote(s: String): String = try_unquote(s) getOrElse s | 
| 135 | ||
| 43598 | 136 |   def commas(ss: Iterable[String]): String = ss.iterator.mkString(", ")
 | 
| 48362 | 137 |   def commas_quote(ss: Iterable[String]): String = ss.iterator.map(quote).mkString(", ")
 | 
| 43598 | 138 | |
| 36688 | 139 | |
| 51983 
32692ce4c61a
more frugal line termination, to cope with huge log files (see also 016cb7d8f297);
 wenzelm parents: 
51981diff
changeset | 140 | /* CharSequence */ | 
| 34141 | 141 | |
| 142 | class Reverse(text: CharSequence, start: Int, end: Int) extends CharSequence | |
| 143 |   {
 | |
| 144 | require(0 <= start && start <= end && end <= text.length) | |
| 145 | ||
| 146 | def this(text: CharSequence) = this(text, 0, text.length) | |
| 147 | ||
| 148 | def length: Int = end - start | |
| 149 | def charAt(i: Int): Char = text.charAt(end - i - 1) | |
| 150 | ||
| 151 | def subSequence(i: Int, j: Int): CharSequence = | |
| 152 | if (0 <= i && i <= j && j <= length) new Reverse(text, end - j, end - i) | |
| 153 | else throw new IndexOutOfBoundsException | |
| 154 | ||
| 155 | override def toString: String = | |
| 156 |     {
 | |
| 157 | val buf = new StringBuilder(length) | |
| 158 | for (i <- 0 until length) | |
| 159 | buf.append(charAt(i)) | |
| 160 | buf.toString | |
| 161 | } | |
| 162 | } | |
| 163 | ||
| 51983 
32692ce4c61a
more frugal line termination, to cope with huge log files (see also 016cb7d8f297);
 wenzelm parents: 
51981diff
changeset | 164 | class Line_Termination(text: CharSequence) extends CharSequence | 
| 
32692ce4c61a
more frugal line termination, to cope with huge log files (see also 016cb7d8f297);
 wenzelm parents: 
51981diff
changeset | 165 |   {
 | 
| 
32692ce4c61a
more frugal line termination, to cope with huge log files (see also 016cb7d8f297);
 wenzelm parents: 
51981diff
changeset | 166 | def length: Int = text.length + 1 | 
| 
32692ce4c61a
more frugal line termination, to cope with huge log files (see also 016cb7d8f297);
 wenzelm parents: 
51981diff
changeset | 167 | def charAt(i: Int): Char = if (i == text.length) '\n' else text.charAt(i) | 
| 
32692ce4c61a
more frugal line termination, to cope with huge log files (see also 016cb7d8f297);
 wenzelm parents: 
51981diff
changeset | 168 | def subSequence(i: Int, j: Int): CharSequence = | 
| 
32692ce4c61a
more frugal line termination, to cope with huge log files (see also 016cb7d8f297);
 wenzelm parents: 
51981diff
changeset | 169 | if (j == text.length + 1) new Line_Termination(text.subSequence(i, j - 1)) | 
| 
32692ce4c61a
more frugal line termination, to cope with huge log files (see also 016cb7d8f297);
 wenzelm parents: 
51981diff
changeset | 170 | else text.subSequence(i, j) | 
| 
32692ce4c61a
more frugal line termination, to cope with huge log files (see also 016cb7d8f297);
 wenzelm parents: 
51981diff
changeset | 171 | override def toString: String = text.toString + "\n" | 
| 
32692ce4c61a
more frugal line termination, to cope with huge log files (see also 016cb7d8f297);
 wenzelm parents: 
51981diff
changeset | 172 | } | 
| 
32692ce4c61a
more frugal line termination, to cope with huge log files (see also 016cb7d8f297);
 wenzelm parents: 
51981diff
changeset | 173 | |
| 34141 | 174 | |
| 59224 | 175 | /* regular expressions */ | 
| 176 | ||
| 177 | def make_regex(s: String): Option[Regex] = | |
| 178 |     try { Some(new Regex(s)) } catch { case ERROR(_) => None }
 | |
| 179 | ||
| 180 | ||
| 61883 
c0f34fe6aa61
clarified length of block with pre-existant forced breaks;
 wenzelm parents: 
60215diff
changeset | 181 | /* lists */ | 
| 
c0f34fe6aa61
clarified length of block with pre-existant forced breaks;
 wenzelm parents: 
60215diff
changeset | 182 | |
| 
c0f34fe6aa61
clarified length of block with pre-existant forced breaks;
 wenzelm parents: 
60215diff
changeset | 183 | def take_prefix[A](pred: A => Boolean, xs: List[A]): (List[A], List[A]) = | 
| 
c0f34fe6aa61
clarified length of block with pre-existant forced breaks;
 wenzelm parents: 
60215diff
changeset | 184 | (xs.takeWhile(pred), xs.dropWhile(pred)) | 
| 56686 | 185 | |
| 60215 | 186 | def member[A, B](xs: List[A])(x: B): Boolean = xs.contains(x) | 
| 56688 | 187 | def insert[A](x: A)(xs: List[A]): List[A] = if (xs.contains(x)) xs else x :: xs | 
| 188 | def remove[A, B](x: B)(xs: List[A]): List[A] = if (member(xs)(x)) xs.filterNot(_ == x) else xs | |
| 189 | def update[A](x: A)(xs: List[A]): List[A] = x :: remove(x)(xs) | |
| 34136 | 190 | } |