aboutsummaryrefslogtreecommitdiff
path: root/src/main/scala/firrtl/options/phases
diff options
context:
space:
mode:
Diffstat (limited to 'src/main/scala/firrtl/options/phases')
-rw-r--r--src/main/scala/firrtl/options/phases/AddDefaults.scala26
-rw-r--r--src/main/scala/firrtl/options/phases/ConvertLegacyAnnotations.scala14
-rw-r--r--src/main/scala/firrtl/options/phases/GetIncludes.scala65
3 files changed, 105 insertions, 0 deletions
diff --git a/src/main/scala/firrtl/options/phases/AddDefaults.scala b/src/main/scala/firrtl/options/phases/AddDefaults.scala
new file mode 100644
index 00000000..f0749b22
--- /dev/null
+++ b/src/main/scala/firrtl/options/phases/AddDefaults.scala
@@ -0,0 +1,26 @@
+// See LICENSE for license details.
+
+package firrtl.options.phases
+
+import firrtl.AnnotationSeq
+import firrtl.options.{Phase, StageOption, TargetDirAnnotation}
+
+/** Add default annotations for a [[Stage]]
+ *
+ * This currently only adds a [[TargetDirAnnotation]]. This isn't necessary for a [[StageOptionsView]], but downstream
+ * tools may expect a [[TargetDirAnnotation]] to exist.
+ */
+object AddDefaults extends Phase {
+
+ def transform(annotations: AnnotationSeq): AnnotationSeq = {
+ var td = true
+ annotations.collect { case a: StageOption => a }.map {
+ case _: TargetDirAnnotation => td = false
+ case _ =>
+ }
+
+ (if (td) Seq(TargetDirAnnotation()) else Seq()) ++
+ annotations
+ }
+
+}
diff --git a/src/main/scala/firrtl/options/phases/ConvertLegacyAnnotations.scala b/src/main/scala/firrtl/options/phases/ConvertLegacyAnnotations.scala
new file mode 100644
index 00000000..37667160
--- /dev/null
+++ b/src/main/scala/firrtl/options/phases/ConvertLegacyAnnotations.scala
@@ -0,0 +1,14 @@
+// See LICENSE for license details.
+
+package firrtl.options.phases
+
+import firrtl.AnnotationSeq
+import firrtl.annotations.LegacyAnnotation
+import firrtl.options.Phase
+
+/** Convert any [[LegacyAnnotation]]s to non-legacy variants */
+object ConvertLegacyAnnotations extends Phase {
+
+ def transform(annotations: AnnotationSeq): AnnotationSeq = LegacyAnnotation.convertLegacyAnnos(annotations)
+
+}
diff --git a/src/main/scala/firrtl/options/phases/GetIncludes.scala b/src/main/scala/firrtl/options/phases/GetIncludes.scala
new file mode 100644
index 00000000..8156dbbf
--- /dev/null
+++ b/src/main/scala/firrtl/options/phases/GetIncludes.scala
@@ -0,0 +1,65 @@
+// See LICENSE for license details.
+
+package firrtl.options.phases
+
+import net.jcazevedo.moultingyaml._
+
+import firrtl.AnnotationSeq
+import firrtl.annotations.{AnnotationFileNotFoundException, DeletedAnnotation, JsonProtocol, LegacyAnnotation}
+import firrtl.annotations.AnnotationYamlProtocol._
+import firrtl.options.{InputAnnotationFileAnnotation, Phase, StageUtils}
+
+import java.io.File
+
+import scala.collection.mutable
+import scala.util.{Try, Failure}
+
+/** Recursively expand all [[InputAnnotationFileAnnotation]]s in an [[AnnotationSeq]] */
+object GetIncludes extends Phase {
+
+ /** Read all [[annotations.Annotation]] from a file in JSON or YAML format
+ * @param filename a JSON or YAML file of [[annotations.Annotation]]
+ * @throws annotations.AnnotationFileNotFoundException if the file does not exist
+ */
+ private def readAnnotationsFromFile(filename: String): AnnotationSeq = {
+ val file = new File(filename).getCanonicalFile
+ if (!file.exists) { throw new AnnotationFileNotFoundException(file) }
+ JsonProtocol.deserializeTry(file).recoverWith { case jsonException =>
+ // Try old protocol if new one fails
+ Try {
+ val yaml = io.Source.fromFile(file).getLines().mkString("\n").parseYaml
+ val result = yaml.convertTo[List[LegacyAnnotation]]
+ val msg = s"$file is a YAML file!\n" + (" "*9) + "YAML Annotation files are deprecated! Use JSON"
+ StageUtils.dramaticWarning(msg)
+ result
+ }.orElse { // Propagate original JsonProtocol exception if YAML also fails
+ Failure(jsonException)
+ }
+ }.get
+ }
+
+ /** Recursively read all [[Annotation]]s from any [[InputAnnotationFileAnnotation]]s while making sure that each file is
+ * only read once
+ * @param includeGuard filenames that have already been read
+ * @param annos a sequence of annotations
+ * @return the original annotation sequence with any discovered annotations added
+ */
+ private def getIncludes(includeGuard: mutable.Set[String] = mutable.Set())
+ (annos: AnnotationSeq): AnnotationSeq = {
+ val phaseName = this.getClass.getName
+ annos.flatMap {
+ case a @ InputAnnotationFileAnnotation(value) =>
+ if (includeGuard.contains(value)) {
+ StageUtils.dramaticWarning("Tried to import the same annotation file twice! (Did you include it twice?)")
+ Seq(DeletedAnnotation(phaseName, a))
+ } else {
+ includeGuard += value
+ DeletedAnnotation(phaseName, a) +: getIncludes(includeGuard)(readAnnotationsFromFile(value))
+ }
+ case x => Seq(x)
+ }
+ }
+
+ def transform(annotations: AnnotationSeq): AnnotationSeq = getIncludes()(annotations)
+
+}