src/Pure/General/exn.scala
author wenzelm
Fri, 22 Sep 2023 16:11:18 +0200
changeset 78683 cde40295ffd6
parent 78674 88f47c70187a
child 78705 fde0b195cb7d
permissions -rw-r--r--
clarified signature; update component;
Ignore whitespace changes - Everywhere: Within whitespace: At end of lines:
62508
d0b68218ea55 discontinued RAW session: bootstrap directly from isabelle_process RAW_ML_SYSTEM;
wenzelm
parents: 62492
diff changeset
     1
/*  Title:      Pure/General/exn.scala
34136
3dcb46ae6185 added basic library -- Scala version;
wenzelm
parents:
diff changeset
     2
    Author:     Makarius
3dcb46ae6185 added basic library -- Scala version;
wenzelm
parents:
diff changeset
     3
43761
e72ba84ae58f tuned signature -- corresponding to Scala version;
wenzelm
parents: 34313
diff changeset
     4
Support for exceptions (arbitrary throwables).
34136
3dcb46ae6185 added basic library -- Scala version;
wenzelm
parents:
diff changeset
     5
*/
3dcb46ae6185 added basic library -- Scala version;
wenzelm
parents:
diff changeset
     6
3dcb46ae6185 added basic library -- Scala version;
wenzelm
parents:
diff changeset
     7
package isabelle
3dcb46ae6185 added basic library -- Scala version;
wenzelm
parents:
diff changeset
     8
3dcb46ae6185 added basic library -- Scala version;
wenzelm
parents:
diff changeset
     9
75393
87ebf5a50283 clarified formatting, for the sake of scala3;
wenzelm
parents: 74068
diff changeset
    10
object Exn {
62492
0e53fade87fe clarified modules;
wenzelm
parents: 61925
diff changeset
    11
  /* user errors */
0e53fade87fe clarified modules;
wenzelm
parents: 61925
diff changeset
    12
75393
87ebf5a50283 clarified formatting, for the sake of scala3;
wenzelm
parents: 74068
diff changeset
    13
  class User_Error(message: String) extends RuntimeException(message) {
62492
0e53fade87fe clarified modules;
wenzelm
parents: 61925
diff changeset
    14
    override def equals(that: Any): Boolean =
0e53fade87fe clarified modules;
wenzelm
parents: 61925
diff changeset
    15
      that match {
0e53fade87fe clarified modules;
wenzelm
parents: 61925
diff changeset
    16
        case other: User_Error => message == other.getMessage
0e53fade87fe clarified modules;
wenzelm
parents: 61925
diff changeset
    17
        case _ => false
0e53fade87fe clarified modules;
wenzelm
parents: 61925
diff changeset
    18
      }
0e53fade87fe clarified modules;
wenzelm
parents: 61925
diff changeset
    19
    override def hashCode: Int = message.hashCode
0e53fade87fe clarified modules;
wenzelm
parents: 61925
diff changeset
    20
65828
02dd430d80c5 tuned signature;
wenzelm
parents: 65716
diff changeset
    21
    override def toString: String = "\n" + Output.error_message_text(message)
62492
0e53fade87fe clarified modules;
wenzelm
parents: 61925
diff changeset
    22
  }
0e53fade87fe clarified modules;
wenzelm
parents: 61925
diff changeset
    23
75393
87ebf5a50283 clarified formatting, for the sake of scala3;
wenzelm
parents: 74068
diff changeset
    24
  object ERROR {
62492
0e53fade87fe clarified modules;
wenzelm
parents: 61925
diff changeset
    25
    def apply(message: String): User_Error = new User_Error(message)
0e53fade87fe clarified modules;
wenzelm
parents: 61925
diff changeset
    26
    def unapply(exn: Throwable): Option[String] = user_message(exn)
0e53fade87fe clarified modules;
wenzelm
parents: 61925
diff changeset
    27
  }
0e53fade87fe clarified modules;
wenzelm
parents: 61925
diff changeset
    28
0e53fade87fe clarified modules;
wenzelm
parents: 61925
diff changeset
    29
  def error(message: String): Nothing = throw ERROR(message)
0e53fade87fe clarified modules;
wenzelm
parents: 61925
diff changeset
    30
68131
62a3294edda3 tuned signature;
wenzelm
parents: 65828
diff changeset
    31
  def cat_message(msgs: String*): String =
62a3294edda3 tuned signature;
wenzelm
parents: 65828
diff changeset
    32
    cat_lines(msgs.iterator.filterNot(_ == ""))
62492
0e53fade87fe clarified modules;
wenzelm
parents: 61925
diff changeset
    33
68131
62a3294edda3 tuned signature;
wenzelm
parents: 65828
diff changeset
    34
  def cat_error(msgs: String*): Nothing =
62a3294edda3 tuned signature;
wenzelm
parents: 65828
diff changeset
    35
    error(cat_message(msgs:_*))
62492
0e53fade87fe clarified modules;
wenzelm
parents: 61925
diff changeset
    36
0e53fade87fe clarified modules;
wenzelm
parents: 61925
diff changeset
    37
44158
fe6d1ae7a065 clarified Exn.message;
wenzelm
parents: 43762
diff changeset
    38
  /* exceptions as values */
34136
3dcb46ae6185 added basic library -- Scala version;
wenzelm
parents:
diff changeset
    39
75393
87ebf5a50283 clarified formatting, for the sake of scala3;
wenzelm
parents: 74068
diff changeset
    40
  sealed abstract class Result[A] {
59698
d4ce901f20c5 value-oriented user error, for well-defined Thy_Syntax.chop_common;
wenzelm
parents: 59697
diff changeset
    41
    def user_error: Result[A] =
d4ce901f20c5 value-oriented user error, for well-defined Thy_Syntax.chop_common;
wenzelm
parents: 59697
diff changeset
    42
      this match {
d4ce901f20c5 value-oriented user error, for well-defined Thy_Syntax.chop_common;
wenzelm
parents: 59697
diff changeset
    43
        case Exn(ERROR(msg)) => Exn(ERROR(msg))
d4ce901f20c5 value-oriented user error, for well-defined Thy_Syntax.chop_common;
wenzelm
parents: 59697
diff changeset
    44
        case _ => this
d4ce901f20c5 value-oriented user error, for well-defined Thy_Syntax.chop_common;
wenzelm
parents: 59697
diff changeset
    45
      }
71142
d6688677a784 clarified signature -- more explicit types;
wenzelm
parents: 68806
diff changeset
    46
d6688677a784 clarified signature -- more explicit types;
wenzelm
parents: 68806
diff changeset
    47
    def map[B](f: A => B): Result[B] =
d6688677a784 clarified signature -- more explicit types;
wenzelm
parents: 68806
diff changeset
    48
      this match {
d6688677a784 clarified signature -- more explicit types;
wenzelm
parents: 68806
diff changeset
    49
        case Res(res) => Res(f(res))
d6688677a784 clarified signature -- more explicit types;
wenzelm
parents: 68806
diff changeset
    50
        case Exn(exn) => Exn(exn)
d6688677a784 clarified signature -- more explicit types;
wenzelm
parents: 68806
diff changeset
    51
      }
59698
d4ce901f20c5 value-oriented user error, for well-defined Thy_Syntax.chop_common;
wenzelm
parents: 59697
diff changeset
    52
  }
43762
wenzelm
parents: 43761
diff changeset
    53
  case class Res[A](res: A) extends Result[A]
wenzelm
parents: 43761
diff changeset
    54
  case class Exn[A](exn: Throwable) extends Result[A]
34136
3dcb46ae6185 added basic library -- Scala version;
wenzelm
parents:
diff changeset
    55
78674
88f47c70187a clarified signature;
wenzelm
parents: 78428
diff changeset
    56
  def is_res[A](result: Result[A]): Boolean = result.isInstanceOf[Res[A]]
88f47c70187a clarified signature;
wenzelm
parents: 78428
diff changeset
    57
  def is_exn[A](result: Result[A]): Boolean = result.isInstanceOf[Exn[A]]
88f47c70187a clarified signature;
wenzelm
parents: 78428
diff changeset
    58
78428
48cbee2a6f2e clarified signature: more operations;
wenzelm
parents: 76568
diff changeset
    59
  def the_res[A]: PartialFunction[Result[A], A] = { case Res(res) => res }
48cbee2a6f2e clarified signature: more operations;
wenzelm
parents: 76568
diff changeset
    60
  def the_exn[A]: PartialFunction[Result[A], Throwable] = { case Exn(exn) => exn }
48cbee2a6f2e clarified signature: more operations;
wenzelm
parents: 76568
diff changeset
    61
34136
3dcb46ae6185 added basic library -- Scala version;
wenzelm
parents:
diff changeset
    62
  def capture[A](e: => A): Result[A] =
3dcb46ae6185 added basic library -- Scala version;
wenzelm
parents:
diff changeset
    63
    try { Res(e) }
34313
2f890016afab treat *all* JVM throwables as "exceptions", cf. ML version;
wenzelm
parents: 34300
diff changeset
    64
    catch { case exn: Throwable => Exn[A](exn) }
34136
3dcb46ae6185 added basic library -- Scala version;
wenzelm
parents:
diff changeset
    65
3dcb46ae6185 added basic library -- Scala version;
wenzelm
parents:
diff changeset
    66
  def release[A](result: Result[A]): A =
3dcb46ae6185 added basic library -- Scala version;
wenzelm
parents:
diff changeset
    67
    result match {
3dcb46ae6185 added basic library -- Scala version;
wenzelm
parents:
diff changeset
    68
      case Res(x) => x
3dcb46ae6185 added basic library -- Scala version;
wenzelm
parents:
diff changeset
    69
      case Exn(exn) => throw exn
3dcb46ae6185 added basic library -- Scala version;
wenzelm
parents:
diff changeset
    70
    }
44158
fe6d1ae7a065 clarified Exn.message;
wenzelm
parents: 43762
diff changeset
    71
59136
c2b23cb8a677 added Par_List in Scala, in accordance to ML version;
wenzelm
parents: 57831
diff changeset
    72
  def release_first[A](results: List[Result[A]]): List[A] =
59138
wenzelm
parents: 59136
diff changeset
    73
    results.find({ case Exn(exn) => !is_interrupt(exn) case _ => false }) match {
wenzelm
parents: 59136
diff changeset
    74
      case Some(Exn(exn)) => throw exn
71601
97ccf48c2f0c misc tuning based on hints by IntelliJ IDEA;
wenzelm
parents: 71142
diff changeset
    75
      case _ => results.map(release)
59138
wenzelm
parents: 59136
diff changeset
    76
    }
59136
c2b23cb8a677 added Par_List in Scala, in accordance to ML version;
wenzelm
parents: 57831
diff changeset
    77
44158
fe6d1ae7a065 clarified Exn.message;
wenzelm
parents: 43762
diff changeset
    78
56667
65e84b0ef974 more abstract Exn.Interrupt and POSIX return code;
wenzelm
parents: 52066
diff changeset
    79
  /* interrupts */
65e84b0ef974 more abstract Exn.Interrupt and POSIX return code;
wenzelm
parents: 52066
diff changeset
    80
78683
cde40295ffd6 clarified signature;
wenzelm
parents: 78674
diff changeset
    81
  def cause(exn: Throwable): Throwable =
cde40295ffd6 clarified signature;
wenzelm
parents: 78674
diff changeset
    82
    isabelle.setup.Exn.cause(exn)
cde40295ffd6 clarified signature;
wenzelm
parents: 78674
diff changeset
    83
56667
65e84b0ef974 more abstract Exn.Interrupt and POSIX return code;
wenzelm
parents: 52066
diff changeset
    84
  def is_interrupt(exn: Throwable): Boolean =
73963
59b6f0462086 clarified modules;
wenzelm
parents: 73729
diff changeset
    85
    isabelle.setup.Exn.is_interrupt(exn)
56667
65e84b0ef974 more abstract Exn.Interrupt and POSIX return code;
wenzelm
parents: 52066
diff changeset
    86
74068
62e4ec8cff38 clarified signature;
wenzelm
parents: 74067
diff changeset
    87
  def failure_rc(exn: Throwable): Int =
62e4ec8cff38 clarified signature;
wenzelm
parents: 74067
diff changeset
    88
    isabelle.setup.Exn.failure_rc(exn)
62e4ec8cff38 clarified signature;
wenzelm
parents: 74067
diff changeset
    89
76568
1c1d7b3478b1 tuned GUI behaviour;
wenzelm
parents: 75393
diff changeset
    90
  def is_interrupt_exn[A](result: Result[A]): Boolean =
1c1d7b3478b1 tuned GUI behaviour;
wenzelm
parents: 75393
diff changeset
    91
    result match {
1c1d7b3478b1 tuned GUI behaviour;
wenzelm
parents: 75393
diff changeset
    92
      case Exn(exn) if is_interrupt(exn) => true
1c1d7b3478b1 tuned GUI behaviour;
wenzelm
parents: 75393
diff changeset
    93
      case _ => false
1c1d7b3478b1 tuned GUI behaviour;
wenzelm
parents: 75393
diff changeset
    94
    }
1c1d7b3478b1 tuned GUI behaviour;
wenzelm
parents: 75393
diff changeset
    95
68315
d088799fd278 more operations (as in ML);
wenzelm
parents: 68131
diff changeset
    96
  def interruptible_capture[A](e: => A): Result[A] =
d088799fd278 more operations (as in ML);
wenzelm
parents: 68131
diff changeset
    97
    try { Res(e) }
d088799fd278 more operations (as in ML);
wenzelm
parents: 68131
diff changeset
    98
    catch { case exn: Throwable if !is_interrupt(exn) => Exn[A](exn) }
d088799fd278 more operations (as in ML);
wenzelm
parents: 68131
diff changeset
    99
75393
87ebf5a50283 clarified formatting, for the sake of scala3;
wenzelm
parents: 74068
diff changeset
   100
  object Interrupt {
87ebf5a50283 clarified formatting, for the sake of scala3;
wenzelm
parents: 74068
diff changeset
   101
    object ERROR {
72596
b2bbe2e6575d tuned signature;
wenzelm
parents: 72335
diff changeset
   102
      def unapply(exn: Throwable): Option[String] =
b2bbe2e6575d tuned signature;
wenzelm
parents: 72335
diff changeset
   103
        if (is_interrupt(exn)) Some(message(exn)) else user_message(exn)
b2bbe2e6575d tuned signature;
wenzelm
parents: 72335
diff changeset
   104
    }
b2bbe2e6575d tuned signature;
wenzelm
parents: 72335
diff changeset
   105
72335
b8708212bdd5 clarified message;
wenzelm
parents: 71705
diff changeset
   106
    def apply(): Throwable = new InterruptedException("Interrupt")
56667
65e84b0ef974 more abstract Exn.Interrupt and POSIX return code;
wenzelm
parents: 52066
diff changeset
   107
    def unapply(exn: Throwable): Boolean = is_interrupt(exn)
65e84b0ef974 more abstract Exn.Interrupt and POSIX return code;
wenzelm
parents: 52066
diff changeset
   108
73367
77ef8bef0593 clarified signature --- fewer warnings;
wenzelm
parents: 73340
diff changeset
   109
    def dispose(): Unit = Thread.interrupted()
77ef8bef0593 clarified signature --- fewer warnings;
wenzelm
parents: 73340
diff changeset
   110
    def expose(): Unit = if (Thread.interrupted()) throw apply()
77ef8bef0593 clarified signature --- fewer warnings;
wenzelm
parents: 73340
diff changeset
   111
    def impose(): Unit = Thread.currentThread.interrupt()
56667
65e84b0ef974 more abstract Exn.Interrupt and POSIX return code;
wenzelm
parents: 52066
diff changeset
   112
  }
65e84b0ef974 more abstract Exn.Interrupt and POSIX return code;
wenzelm
parents: 52066
diff changeset
   113
65e84b0ef974 more abstract Exn.Interrupt and POSIX return code;
wenzelm
parents: 52066
diff changeset
   114
44158
fe6d1ae7a065 clarified Exn.message;
wenzelm
parents: 43762
diff changeset
   115
  /* message */
fe6d1ae7a065 clarified Exn.message;
wenzelm
parents: 43762
diff changeset
   116
48479
819f7a5f3e7f more general notion of user ERROR (cf. 44f56fe01528);
wenzelm
parents: 48476
diff changeset
   117
  def user_message(exn: Throwable): Option[String] =
75393
87ebf5a50283 clarified formatting, for the sake of scala3;
wenzelm
parents: 74068
diff changeset
   118
    if (exn.isInstanceOf[User_Error] || exn.getClass == classOf[RuntimeException]) {
65716
wenzelm
parents: 65275
diff changeset
   119
      Some(proper_string(exn.getMessage) getOrElse "Error")
44158
fe6d1ae7a065 clarified Exn.message;
wenzelm
parents: 43762
diff changeset
   120
    }
75393
87ebf5a50283 clarified formatting, for the sake of scala3;
wenzelm
parents: 74068
diff changeset
   121
    else if (exn.isInstanceOf[java.sql.SQLException]) {
65716
wenzelm
parents: 65275
diff changeset
   122
      Some(proper_string(exn.getMessage) getOrElse "SQL error")
63782
aced4f0d1ad4 clarified exceptions;
wenzelm
parents: 62508
diff changeset
   123
    }
75393
87ebf5a50283 clarified formatting, for the sake of scala3;
wenzelm
parents: 74068
diff changeset
   124
    else if (exn.isInstanceOf[java.io.IOException]) {
59697
43e14b0e2ef8 more explicit exception User_Error, with value-oriented equality;
wenzelm
parents: 59138
diff changeset
   125
      val msg = exn.getMessage
43e14b0e2ef8 more explicit exception User_Error, with value-oriented equality;
wenzelm
parents: 59138
diff changeset
   126
      Some(if (msg == null || msg == "") "I/O error" else "I/O error: " + msg)
43e14b0e2ef8 more explicit exception User_Error, with value-oriented equality;
wenzelm
parents: 59138
diff changeset
   127
    }
48479
819f7a5f3e7f more general notion of user ERROR (cf. 44f56fe01528);
wenzelm
parents: 48476
diff changeset
   128
    else if (exn.isInstanceOf[RuntimeException]) Some(exn.toString)
819f7a5f3e7f more general notion of user ERROR (cf. 44f56fe01528);
wenzelm
parents: 48476
diff changeset
   129
    else None
819f7a5f3e7f more general notion of user ERROR (cf. 44f56fe01528);
wenzelm
parents: 48476
diff changeset
   130
819f7a5f3e7f more general notion of user ERROR (cf. 44f56fe01528);
wenzelm
parents: 48476
diff changeset
   131
  def message(exn: Throwable): String =
56667
65e84b0ef974 more abstract Exn.Interrupt and POSIX return code;
wenzelm
parents: 52066
diff changeset
   132
    user_message(exn) getOrElse (if (is_interrupt(exn)) "Interrupt" else exn.toString)
68806
4597812d5182 tuned message;
wenzelm
parents: 68315
diff changeset
   133
4597812d5182 tuned message;
wenzelm
parents: 68315
diff changeset
   134
73963
59b6f0462086 clarified modules;
wenzelm
parents: 73729
diff changeset
   135
  /* print */
59b6f0462086 clarified modules;
wenzelm
parents: 73729
diff changeset
   136
59b6f0462086 clarified modules;
wenzelm
parents: 73729
diff changeset
   137
  def debug(): Boolean = isabelle.setup.Exn.debug()
68806
4597812d5182 tuned message;
wenzelm
parents: 68315
diff changeset
   138
73963
59b6f0462086 clarified modules;
wenzelm
parents: 73729
diff changeset
   139
  def trace(exn: Throwable): String = isabelle.setup.Exn.trace(exn)
59b6f0462086 clarified modules;
wenzelm
parents: 73729
diff changeset
   140
59b6f0462086 clarified modules;
wenzelm
parents: 73729
diff changeset
   141
  def print(exn: Throwable): String =
59b6f0462086 clarified modules;
wenzelm
parents: 73729
diff changeset
   142
    if (debug()) message(exn) + "\n" + trace(exn) else message(exn)
34136
3dcb46ae6185 added basic library -- Scala version;
wenzelm
parents:
diff changeset
   143
}