aboutsummaryrefslogtreecommitdiff
path: root/src/main/scala/firrtl/options/phases
diff options
context:
space:
mode:
authorSchuyler Eldridge2018-11-15 21:50:29 -0500
committerSchuyler Eldridge2018-11-21 23:22:11 -0500
commit696bc256a90cc80bcb094aaeada8eea51a643ae0 (patch)
tree8435ab570e88b60ca6af127e607794c64565bb9c /src/main/scala/firrtl/options/phases
parent4a2211c1602b37a65b4e44c3b7ebe82e8bfeedc0 (diff)
Change firrtl.options API, add Phase
This breaks firrtl.options.Stage into a small type hierarchy: * Phase: something that transforms an AnnotationSeq * Stage extends Phase: a Phase with a Command Line Interface Some of the old "common options" (input annotation file and target directory) are moved into firrtl.options and provided as part of the Stage class. Stage will automatically preprocess an input annotation sequence to resolve all input annotation files and add a default target directory. Minor changes: * Adds ViewException * Stops mixing in the DoNotTerminateOnExit trait into the default Shell parser * Add StageOptionsView Signed-off-by: Schuyler Eldridge <schuyler.eldridge@ibm.com>
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)
+
+}