aboutsummaryrefslogtreecommitdiff
path: root/src/main/scala/firrtl/options
diff options
context:
space:
mode:
Diffstat (limited to 'src/main/scala/firrtl/options')
-rw-r--r--src/main/scala/firrtl/options/Phase.scala16
-rw-r--r--src/main/scala/firrtl/options/Registration.scala58
-rw-r--r--src/main/scala/firrtl/options/Shell.scala12
-rw-r--r--src/main/scala/firrtl/options/Stage.scala11
-rw-r--r--src/main/scala/firrtl/options/StageAnnotations.scala66
-rw-r--r--src/main/scala/firrtl/options/phases/DeletedWrapper.scala43
6 files changed, 138 insertions, 68 deletions
diff --git a/src/main/scala/firrtl/options/Phase.scala b/src/main/scala/firrtl/options/Phase.scala
index a660d08a..34739053 100644
--- a/src/main/scala/firrtl/options/Phase.scala
+++ b/src/main/scala/firrtl/options/Phase.scala
@@ -39,22 +39,6 @@ abstract class Phase extends TransformLike[AnnotationSeq] {
*/
lazy val name: String = this.getClass.getName
- /** Perform the transform of [[transform]] on an [[firrtl.AnnotationSeq AnnotationSeq]] and add
- * [[firrtl.annotations.DeletedAnnotation DeletedAnnotation]]s for any deleted [[firrtl.annotations.Annotation
- * Annotation]]s.
- * @param a
- */
- final def runTransform(annotations: AnnotationSeq): AnnotationSeq = {
- val ax = transform(annotations)
-
- val (in, out) = (mutable.LinkedHashSet() ++ annotations, mutable.LinkedHashSet() ++ ax)
-
- (in -- out).map {
- case DeletedAnnotation(n, a) => DeletedAnnotation(s"$n+$name", a)
- case a => DeletedAnnotation(name, a)
- }.toSeq ++ ax
- }
-
}
/** A [[TransformLike]] that internally ''translates'' the input type to some other type, transforms the internal type,
diff --git a/src/main/scala/firrtl/options/Registration.scala b/src/main/scala/firrtl/options/Registration.scala
index a826ec50..c832ec7c 100644
--- a/src/main/scala/firrtl/options/Registration.scala
+++ b/src/main/scala/firrtl/options/Registration.scala
@@ -4,40 +4,70 @@ package firrtl.options
import firrtl.{AnnotationSeq, Transform}
-import scopt.OptionParser
+import scopt.{OptionDef, OptionParser, Read}
+
+/** Contains information about a [[Shell]] command line option
+ * @tparam the type of the command line argument
+ * @param longOption a long, double-dash option
+ * @param toAnnotationSeq a function to convert the type into an [[firrtl.AnnotationSeq AnnotationSeq]]
+ * @param helpText help text
+ * @param shortOption an optional single-dash option
+ * @param helpValueName a string to show as a placeholder argument in help text
+ */
+final class ShellOption[A: Read] (
+ val longOption: String,
+ val toAnnotationSeq: A => AnnotationSeq,
+ val helpText: String,
+ val shortOption: Option[String] = None,
+ val helpValueName: Option[String] = None
+) {
+
+ /** Add this specific shell (command line) option to an option parser
+ * @param p an option parser
+ */
+ final def addOption(p: OptionParser[AnnotationSeq]): Unit = {
+ val f = Seq(
+ (p: OptionDef[A, AnnotationSeq]) => p.action( (x, c) => toAnnotationSeq(x).reverse ++ c ),
+ (p: OptionDef[A, AnnotationSeq]) => p.text(helpText),
+ (p: OptionDef[A, AnnotationSeq]) => p.unbounded()) ++
+ shortOption.map( a => (p: OptionDef[A, AnnotationSeq]) => p.abbr(a) ) ++
+ helpValueName.map( a => (p: OptionDef[A, AnnotationSeq]) => p.valueName(a) )
+
+ f.foldLeft(p.opt[A](longOption))( (a, b) => b(a) )
+ }
+}
/** Indicates that this class/object includes options (but does not add these as a registered class)
*/
-trait HasScoptOptions {
+trait HasShellOptions {
- /** This method will be called to add options to an OptionParser ('''OPTIONS SHOULD BE PREPENDED''')
- *
- *
- * '''The ordering of [[firrtl.annotations.Annotation Annotation]] is important and has meaning for parallel
- * compilations. For deterministic behavior, you should always prepend any annotations to the [[firrtl.AnnotationSeq
- * AnnotationSeq]]. The [[firrtl.AnnotationSeq AnnotationSeq]] will be automatically reversed after a [[Stage]]
- * parses it.'''
- *
+ /** A sequence of options provided
+ */
+ def options: Seq[ShellOption[_]]
+
+ /** Add all shell (command line) options to an option parser
* @param p an option parser
*/
- def addOptions(p: OptionParser[AnnotationSeq]): Unit
+ final def addOptions(p: OptionParser[AnnotationSeq]): Unit = options.foreach(_.addOption(p))
+
}
-/** A [[Transform]] that includes options that should be exposed at the top level.
+/** A [[Transform]] that includes an option that should be exposed at the top level.
*
* @note To complete registration, include an entry in
* src/main/resources/META-INF/services/firrtl.options.RegisteredTransform */
-trait RegisteredTransform extends HasScoptOptions { this: Transform => }
+trait RegisteredTransform extends HasShellOptions { this: Transform => }
/** A class that includes options that should be exposed as a group at the top level.
*
* @note To complete registration, include an entry in
* src/main/resources/META-INF/services/firrtl.options.RegisteredLibrary */
-trait RegisteredLibrary extends HasScoptOptions {
+trait RegisteredLibrary extends HasShellOptions {
/** The name of this library.
*
* This will be used when generating help text.
*/
def name: String
+
}
diff --git a/src/main/scala/firrtl/options/Shell.scala b/src/main/scala/firrtl/options/Shell.scala
index dbc403a5..28c0554a 100644
--- a/src/main/scala/firrtl/options/Shell.scala
+++ b/src/main/scala/firrtl/options/Shell.scala
@@ -16,10 +16,10 @@ import java.util.ServiceLoader
class Shell(val applicationName: String) {
/** Command line argument parser (OptionParser) with modifications */
- final val parser = new OptionParser[AnnotationSeq](applicationName) with DuplicateHandling with ExceptOnError
+ protected val parser = new OptionParser[AnnotationSeq](applicationName) with DuplicateHandling with ExceptOnError
/** Contains all discovered [[RegisteredLibrary]] */
- lazy val registeredLibraries: Seq[RegisteredLibrary] = {
+ final lazy val registeredLibraries: Seq[RegisteredLibrary] = {
val libraries = scala.collection.mutable.ArrayBuffer[RegisteredLibrary]()
val iter = ServiceLoader.load(classOf[RegisteredLibrary]).iterator()
while (iter.hasNext) {
@@ -33,7 +33,7 @@ class Shell(val applicationName: String) {
}
/** Contains all discovered [[RegisteredTransform]] */
- lazy val registeredTransforms: Seq[RegisteredTransform] = {
+ final lazy val registeredTransforms: Seq[RegisteredTransform] = {
val transforms = scala.collection.mutable.ArrayBuffer[RegisteredTransform]()
val iter = ServiceLoader.load(classOf[RegisteredTransform]).iterator()
if (iter.hasNext) { parser.note("FIRRTL Transform Options") }
@@ -61,11 +61,11 @@ class Shell(val applicationName: String) {
}
parser.note("Shell Options")
+ ProgramArgsAnnotation.addOptions(parser)
Seq( TargetDirAnnotation,
- ProgramArgsAnnotation,
InputAnnotationFileAnnotation,
OutputAnnotationFileAnnotation )
- .map(_.addOptions(parser))
+ .foreach(_.addOptions(parser))
parser.opt[Unit]("show-registrations")
.action{ (_, c) =>
@@ -85,5 +85,5 @@ class Shell(val applicationName: String) {
ClassLogLevelAnnotation,
LogFileAnnotation,
LogClassNamesAnnotation )
- .map(_.addOptions(parser))
+ .foreach(_.addOptions(parser))
}
diff --git a/src/main/scala/firrtl/options/Stage.scala b/src/main/scala/firrtl/options/Stage.scala
index 38cc9d42..f2780761 100644
--- a/src/main/scala/firrtl/options/Stage.scala
+++ b/src/main/scala/firrtl/options/Stage.scala
@@ -31,16 +31,19 @@ abstract class Stage extends Phase {
* @throws OptionsException if command line or annotation validation fails
*/
final def transform(annotations: AnnotationSeq): AnnotationSeq = {
- val annotationsx = Seq( new phases.GetIncludes,
- new phases.ConvertLegacyAnnotations )
- .foldLeft(annotations)((a, p) => p.runTransform(a))
+ val annotationsx =
+ Seq( new phases.GetIncludes,
+ new phases.ConvertLegacyAnnotations )
+ .map(phases.DeletedWrapper(_))
+ .foldLeft(annotations)((a, p) => p.transform(a))
Logger.makeScope(annotationsx) {
Seq( new phases.AddDefaults,
new phases.Checks,
new Phase { def transform(a: AnnotationSeq) = run(a) },
new phases.WriteOutputAnnotations )
- .foldLeft(annotationsx)((a, p) => p.runTransform(a))
+ .map(phases.DeletedWrapper(_))
+ .foldLeft(annotationsx)((a, p) => p.transform(a))
}
}
diff --git a/src/main/scala/firrtl/options/StageAnnotations.scala b/src/main/scala/firrtl/options/StageAnnotations.scala
index e8a1a288..e35a6afa 100644
--- a/src/main/scala/firrtl/options/StageAnnotations.scala
+++ b/src/main/scala/firrtl/options/StageAnnotations.scala
@@ -21,13 +21,16 @@ trait Unserializable { this: Annotation => }
*/
case class TargetDirAnnotation(directory: String = ".") extends NoTargetAnnotation with StageOption
-object TargetDirAnnotation extends HasScoptOptions {
- def addOptions(p: OptionParser[AnnotationSeq]): Unit = p.opt[String]("target-dir")
- .abbr("td")
- .valueName("<target-directory>")
- .action( (x, c) => TargetDirAnnotation(x) +: c )
- .unbounded() // See [Note 1]
- .text(s"Work directory for intermediate files/blackboxes, default is '.' (current directory)")
+object TargetDirAnnotation extends HasShellOptions {
+
+ val options = Seq(
+ new ShellOption[String](
+ longOption = "target-dir",
+ toAnnotationSeq = (a: String) => Seq(TargetDirAnnotation(a)),
+ helpText = "Work directory (default: '.')",
+ shortOption = Some("td"),
+ helpValueName = Some("<directory>") ) )
+
}
/** Additional arguments
@@ -36,7 +39,8 @@ object TargetDirAnnotation extends HasScoptOptions {
*/
case class ProgramArgsAnnotation(arg: String) extends NoTargetAnnotation with StageOption
-object ProgramArgsAnnotation extends HasScoptOptions {
+object ProgramArgsAnnotation {
+
def addOptions(p: OptionParser[AnnotationSeq]): Unit = p.arg[String]("<arg>...")
.unbounded()
.optional()
@@ -51,13 +55,16 @@ object ProgramArgsAnnotation extends HasScoptOptions {
*/
case class InputAnnotationFileAnnotation(file: String) extends NoTargetAnnotation with StageOption
-object InputAnnotationFileAnnotation extends HasScoptOptions {
- def addOptions(p: OptionParser[AnnotationSeq]): Unit = p.opt[String]("annotation-file")
- .abbr("faf")
- .unbounded()
- .valueName("<input-anno-file>")
- .action( (x, c) => InputAnnotationFileAnnotation(x) +: c )
- .text("Used to specify annotation file")
+object InputAnnotationFileAnnotation extends HasShellOptions {
+
+ val options = Seq(
+ new ShellOption[String](
+ longOption = "annotation-file",
+ toAnnotationSeq = (a: String) => Seq(InputAnnotationFileAnnotation(a)),
+ helpText = "An input annotation file",
+ shortOption = Some("faf"),
+ helpValueName = Some("<file>") ) )
+
}
/** An explicit output _annotation_ file to write to
@@ -66,13 +73,16 @@ object InputAnnotationFileAnnotation extends HasScoptOptions {
*/
case class OutputAnnotationFileAnnotation(file: String) extends NoTargetAnnotation with StageOption
-object OutputAnnotationFileAnnotation extends HasScoptOptions {
- def addOptions(p: OptionParser[AnnotationSeq]): Unit = p.opt[String]("output-annotation-file")
- .abbr("foaf")
- .valueName ("<output-anno-file>")
- .action( (x, c) => OutputAnnotationFileAnnotation(x) +: c )
- .unbounded()
- .text("use this to set the annotation output file")
+object OutputAnnotationFileAnnotation extends HasShellOptions {
+
+ val options = Seq(
+ new ShellOption[String](
+ longOption = "output-annotation-file",
+ toAnnotationSeq = (a: String) => Seq(OutputAnnotationFileAnnotation(a)),
+ helpText = "An output annotation file",
+ shortOption = Some("foaf"),
+ helpValueName = Some("<file>") ) )
+
}
/** If this [[firrtl.annotations.Annotation Annotation]] exists in an [[firrtl.AnnotationSeq AnnotationSeq]], then a
@@ -80,12 +90,12 @@ object OutputAnnotationFileAnnotation extends HasScoptOptions {
* [[firrtl.annotations.DeletedAnnotation DeletedAnnotation]]s when it writes to a file.
* - set with '--write-deleted'
*/
-case object WriteDeletedAnnotation extends NoTargetAnnotation with StageOption with HasScoptOptions {
+case object WriteDeletedAnnotation extends NoTargetAnnotation with StageOption with HasShellOptions {
- def addOptions(p: OptionParser[AnnotationSeq]): Unit = p
- .opt[Unit]("write-deleted")
- .unbounded()
- .action( (_, c) => WriteDeletedAnnotation +: c )
- .text("Include deleted annotations in the output annotation file")
+ val options = Seq(
+ new ShellOption[Unit](
+ longOption = "write-deleted",
+ toAnnotationSeq = (_: Unit) => Seq(WriteDeletedAnnotation),
+ helpText = "Include deleted annotations in the output annotation file" ) )
}
diff --git a/src/main/scala/firrtl/options/phases/DeletedWrapper.scala b/src/main/scala/firrtl/options/phases/DeletedWrapper.scala
new file mode 100644
index 00000000..0a959f32
--- /dev/null
+++ b/src/main/scala/firrtl/options/phases/DeletedWrapper.scala
@@ -0,0 +1,43 @@
+// See LICENSE for license details.
+
+package firrtl.options.phases
+
+import firrtl.AnnotationSeq
+import firrtl.annotations.DeletedAnnotation
+import firrtl.options.{Phase, Translator}
+
+import scala.collection.mutable
+
+/** Wrap a [[firrtl.options.Phase Phase]] such that any [[firrtl.annotations.Annotation Annotation]] removed by the
+ * wrapped [[firrtl.options.Phase Phase]] will be added as [[firrtl.annotations.DeletedAnnotation DeletedAnnotation]]s.
+ * @param p a [[firrtl.options.Phase Phase]] to wrap
+ */
+class DeletedWrapper(p: Phase) extends Phase with Translator[AnnotationSeq, (AnnotationSeq, AnnotationSeq)] {
+
+ override lazy val name: String = p.name
+
+ def aToB(a: AnnotationSeq): (AnnotationSeq, AnnotationSeq) = (a, a)
+
+ def bToA(b: (AnnotationSeq, AnnotationSeq)): AnnotationSeq = {
+
+ val (in, out) = (mutable.LinkedHashSet() ++ b._1, mutable.LinkedHashSet() ++ b._2)
+
+ (in -- out).map {
+ case DeletedAnnotation(n, a) => DeletedAnnotation(s"$n+$name", a)
+ case a => DeletedAnnotation(name, a)
+ }.toSeq ++ b._2
+
+ }
+
+ def internalTransform(b: (AnnotationSeq, AnnotationSeq)): (AnnotationSeq, AnnotationSeq) = (b._1, p.transform(b._2))
+
+}
+
+object DeletedWrapper {
+
+ /** Wrap a [[firrtl.options.Phase Phase]] in a [[DeletedWrapper]]
+ * @param p a [[firrtl.options.Phase Phase]] to wrap
+ */
+ def apply(p: Phase): DeletedWrapper = new DeletedWrapper(p)
+
+}