summaryrefslogtreecommitdiff
path: root/chiselFrontend/src/main/scala/chisel3/internal/Error.scala
diff options
context:
space:
mode:
Diffstat (limited to 'chiselFrontend/src/main/scala/chisel3/internal/Error.scala')
-rw-r--r--chiselFrontend/src/main/scala/chisel3/internal/Error.scala91
1 files changed, 91 insertions, 0 deletions
diff --git a/chiselFrontend/src/main/scala/chisel3/internal/Error.scala b/chiselFrontend/src/main/scala/chisel3/internal/Error.scala
new file mode 100644
index 00000000..6c4c0880
--- /dev/null
+++ b/chiselFrontend/src/main/scala/chisel3/internal/Error.scala
@@ -0,0 +1,91 @@
+// See LICENSE for license details.
+
+package Chisel.internal
+
+import scala.collection.mutable.ArrayBuffer
+
+import Chisel._
+
+class ChiselException(message: String, cause: Throwable) extends Exception(message, cause)
+
+private[Chisel] object throwException {
+ def apply(s: String, t: Throwable = null): Nothing =
+ throw new ChiselException(s, t)
+}
+
+/** Records and reports runtime errors and warnings. */
+private[Chisel] class ErrorLog {
+ def hasErrors: Boolean = errors.exists(_.isFatal)
+
+ /** Log an error message */
+ def error(m: => String): Unit =
+ errors += new Error(m, getUserLineNumber)
+
+ /** Log a warning message */
+ def warning(m: => String): Unit =
+ errors += new Warning(m, getUserLineNumber)
+
+ /** Emit an informational message */
+ def info(m: String): Unit =
+ println(new Info("[%2.3f] %s".format(elapsedTime/1e3, m), None)) // scalastyle:ignore regex
+
+ /** Prints error messages generated by Chisel at runtime. */
+ def report(): Unit = errors foreach println // scalastyle:ignore regex
+
+ /** Throw an exception if any errors have yet occurred. */
+ def checkpoint(): Unit = if(hasErrors) {
+ import Console._
+ throwException(errors.map(_ + "\n").reduce(_ + _) +
+ UNDERLINED + "CODE HAS " + errors.filter(_.isFatal).length + RESET +
+ UNDERLINED + " " + RED + "ERRORS" + RESET +
+ UNDERLINED + " and " + errors.filterNot(_.isFatal).length + RESET +
+ UNDERLINED + " " + YELLOW + "WARNINGS" + RESET)
+ }
+
+ private def findFirstUserFrame(stack: Array[StackTraceElement]): Option[StackTraceElement] = {
+ def isUserCode(ste: StackTraceElement): Boolean = {
+ def isUserModule(c: Class[_]): Boolean =
+ c != null && (c == classOf[Module] || isUserModule(c.getSuperclass))
+ isUserModule(Class.forName(ste.getClassName))
+ }
+
+ stack.indexWhere(isUserCode) match {
+ case x if x < 0 => None
+ case x => Some(stack(x))
+ }
+ }
+
+ private def getUserLineNumber =
+ findFirstUserFrame(Thread.currentThread().getStackTrace)
+
+ private val errors = ArrayBuffer[LogEntry]()
+
+ private val startTime = System.currentTimeMillis
+ private def elapsedTime: Long = System.currentTimeMillis - startTime
+}
+
+private abstract class LogEntry(msg: => String, line: Option[StackTraceElement]) {
+ def isFatal: Boolean = false
+ def format: String
+
+ override def toString: String = line match {
+ case Some(l) => s"${format} ${l.getFileName}:${l.getLineNumber}: ${msg} in class ${l.getClassName}"
+ case None => s"${format} ${msg}"
+ }
+
+ protected def tag(name: String, color: String): String =
+ s"[${color}${name}${Console.RESET}]"
+}
+
+private class Error(msg: => String, line: Option[StackTraceElement]) extends LogEntry(msg, line) {
+ override def isFatal: Boolean = true
+ def format: String = tag("error", Console.RED)
+}
+
+private class Warning(msg: => String, line: Option[StackTraceElement]) extends LogEntry(msg, line) {
+ def format: String = tag("warn", Console.YELLOW)
+}
+
+private class Info(msg: => String, line: Option[StackTraceElement]) extends LogEntry(msg, line) {
+ def format: String = tag("info", Console.MAGENTA)
+}