aboutsummaryrefslogtreecommitdiff
path: root/src/main
diff options
context:
space:
mode:
authorJack Koenig2018-03-22 11:53:51 -0700
committerGitHub2018-03-22 11:53:51 -0700
commitebb6847e9d01b424424ae11a0067448a4094e46d (patch)
treefc87aa9d7b7d437914f6a4c9e20487c0973a1fc3 /src/main
parent6ea4ac666e4ce8dfaca1545660f372fccff610f5 (diff)
Better bad annotation file error reporting (#771)
* Propagate exceptions from JsonProtocol deserialization * Add AnnotationFileNotFoundException for better error reporting * Add AnnotationClassNotFoundException for better error reporting * Better propagate JSON parsing errors Also report the file if there is a error deserializing a JSON file * Make exception for non-array JSON file more explicit
Diffstat (limited to 'src/main')
-rw-r--r--src/main/scala/firrtl/Driver.scala25
-rw-r--r--src/main/scala/firrtl/annotations/AnnotationUtils.scala12
-rw-r--r--src/main/scala/firrtl/annotations/JsonProtocol.scala34
3 files changed, 40 insertions, 31 deletions
diff --git a/src/main/scala/firrtl/Driver.scala b/src/main/scala/firrtl/Driver.scala
index 3ff465e2..f9ba6141 100644
--- a/src/main/scala/firrtl/Driver.scala
+++ b/src/main/scala/firrtl/Driver.scala
@@ -116,23 +116,22 @@ object Driver {
val loadedAnnos = annoFiles.flatMap { file =>
if (!file.exists) {
- throw new FileNotFoundException(s"Annotation file $file not found!")
+ throw new AnnotationFileNotFoundException(file)
}
// Try new protocol first
- JsonProtocol.deserializeTry(file).getOrElse {
- val annos = Try {
+ JsonProtocol.deserializeTry(file).recoverWith { case jsonException =>
+ // Try old protocol if new one fails
+ Try {
val yaml = io.Source.fromFile(file).getLines().mkString("\n").parseYaml
- yaml.convertTo[List[LegacyAnnotation]]
+ val result = yaml.convertTo[List[LegacyAnnotation]]
+ val msg = s"$file is a YAML file!\n" +
+ (" "*9) + "YAML Annotation files are deprecated! Use JSON"
+ Driver.dramaticWarning(msg)
+ result
+ }.orElse { // Propagate original JsonProtocol exception if YAML also fails
+ Failure(jsonException)
}
- annos match {
- case Success(result) =>
- val msg = s"$file is a YAML file!\n" +
- (" "*9) + "YAML Annotation files are deprecated! Use JSON"
- Driver.dramaticWarning(msg)
- result
- case Failure(_) => throw new InvalidAnnotationFileException(file.toString)
- }
- }
+ }.get
}
val targetDirAnno = List(BlackBoxTargetDirAnno(optionsManager.targetDirName))
diff --git a/src/main/scala/firrtl/annotations/AnnotationUtils.scala b/src/main/scala/firrtl/annotations/AnnotationUtils.scala
index 6b7f9a60..517cea26 100644
--- a/src/main/scala/firrtl/annotations/AnnotationUtils.scala
+++ b/src/main/scala/firrtl/annotations/AnnotationUtils.scala
@@ -3,6 +3,8 @@
package firrtl
package annotations
+import java.io.File
+
import org.json4s._
import org.json4s.native.JsonMethods._
import org.json4s.native.Serialization
@@ -14,7 +16,15 @@ import firrtl.annotations.AnnotationYamlProtocol._
import firrtl.ir._
import firrtl.Utils.error
-class InvalidAnnotationFileException(msg: String) extends FIRRTLException(msg)
+case class InvalidAnnotationFileException(file: File, cause: Throwable = null)
+ extends FIRRTLException(s"$file, see cause below", cause)
+case class InvalidAnnotationJSONException(msg: String) extends FIRRTLException(msg)
+case class AnnotationFileNotFoundException(file: File) extends FIRRTLException(
+ s"Annotation file $file not found!"
+)
+case class AnnotationClassNotFoundException(className: String) extends FIRRTLException(
+ s"Annotation class $className not found! Please check spelling and classpath"
+)
object AnnotationUtils {
def toYaml(a: LegacyAnnotation): String = a.toYaml.prettyPrint
diff --git a/src/main/scala/firrtl/annotations/JsonProtocol.scala b/src/main/scala/firrtl/annotations/JsonProtocol.scala
index 5005ccb0..7b2617f5 100644
--- a/src/main/scala/firrtl/annotations/JsonProtocol.scala
+++ b/src/main/scala/firrtl/annotations/JsonProtocol.scala
@@ -2,7 +2,7 @@
package firrtl
package annotations
-import scala.util.Try
+import scala.util.{Try, Failure}
import org.json4s._
import org.json4s.native.JsonMethods._
@@ -13,18 +13,6 @@ import firrtl.ir._
import firrtl.Utils.error
object JsonProtocol {
-
- // Helper for error messages
- private def prettifyJsonInput(in: JsonInput): String = {
- def defaultToString(base: String, obj: Any): String = s"$base@${obj.hashCode.toHexString}"
- in match {
- case FileInput(file) => file.toString
- case StringInput(o) => defaultToString("String", o)
- case ReaderInput(o) => defaultToString("Reader", o)
- case StreamInput(o) => defaultToString("Stream", o)
- }
- }
-
class TransformClassSerializer extends CustomSerializer[Class[_ <: Transform]](format => (
{ case JString(s) => Class.forName(s).asInstanceOf[Class[_ <: Transform]] },
{ case x: Class[_] => JString(x.getName) }
@@ -66,19 +54,31 @@ object JsonProtocol {
def deserialize(in: JsonInput): Seq[Annotation] = deserializeTry(in).get
def deserializeTry(in: JsonInput): Try[Seq[Annotation]] = Try({
- def throwError() = throw new InvalidAnnotationFileException(prettifyJsonInput(in))
val parsed = parse(in)
val annos = parsed match {
case JArray(objs) => objs
- case _ => throwError()
+ case x => throw new InvalidAnnotationJSONException(
+ s"Annotations must be serialized as a JArray, got ${x.getClass.getSimpleName} instead!")
}
// Gather classes so we can deserialize arbitrary Annotations
val classes = annos.map({
case JObject(("class", JString(c)) :: tail) => c
- case _ => throwError()
+ case obj => throw new InvalidAnnotationJSONException(s"Expected field 'class' not found! $obj")
}).distinct
val loaded = classes.map(Class.forName(_).asInstanceOf[Class[_ <: Annotation]])
implicit val formats = jsonFormat(loaded)
read[List[Annotation]](in)
- })
+ }).recoverWith {
+ // Translate some generic errors to specific ones
+ case e: java.lang.ClassNotFoundException =>
+ Failure(new AnnotationClassNotFoundException(e.getMessage))
+ case e: org.json4s.ParserUtil.ParseException =>
+ Failure(new InvalidAnnotationJSONException(e.getMessage))
+ }.recoverWith { // If the input is a file, wrap in InvalidAnnotationFileException
+ case e => in match {
+ case FileInput(file) =>
+ Failure(new InvalidAnnotationFileException(file, e))
+ case _ => Failure(e)
+ }
+ }
}