aboutsummaryrefslogtreecommitdiff
path: root/src/main/scala/firrtl/Annotations.scala
diff options
context:
space:
mode:
authorAdam Izraelevitz2016-11-23 11:57:02 -0800
committerJack Koenig2016-11-23 11:57:02 -0800
commit66d3ec0498a73319a914eeffcb4e0b1109b5f4c5 (patch)
tree325066fd05cc72b544d3b4d78d646e1a864119f3 /src/main/scala/firrtl/Annotations.scala
parent9a967a27aa8bb51f4b62969d2889f9a9caa48e31 (diff)
Stringified annotations (#367)
Restricts annotations to be string-based (and thus less typesafe) Makes annotations more easily serializable and interact with Chisel
Diffstat (limited to 'src/main/scala/firrtl/Annotations.scala')
-rw-r--r--src/main/scala/firrtl/Annotations.scala239
1 files changed, 0 insertions, 239 deletions
diff --git a/src/main/scala/firrtl/Annotations.scala b/src/main/scala/firrtl/Annotations.scala
deleted file mode 100644
index b502e055..00000000
--- a/src/main/scala/firrtl/Annotations.scala
+++ /dev/null
@@ -1,239 +0,0 @@
-// See LICENSE for license details.
-
-package firrtl
-
-import firrtl.ir._
-
-import scala.collection.mutable
-import java.io.Writer
-
-
-/**
- * Firrtl Annotation Library
- *
- * WARNING(izraelevitz): Untested, and requires unit tests, which require the
- * LowerTypes pass and ConstProp pass to correctly populate its RenameMap.
- *
- * The following tables explain how Tenacity and Permissibility interact
- * with different RenameMap scenarios:
- * x -> x : a component named "x" is renamed to the same name, "x"
- * x -> y : a component named "x" is renamed to a different name, "y"
- * x -> y,z : a component named "x" is split into two components named "y" and "z"
- * x -> () : a component named "x" is removed
- *
- * Tenacity Propagation Behavior:
- * ----------|----------|----------|------------|-----------|
- * | x -> x | x -> y | x -> y,z | x -> () |
- * ----------|----------|----------|------------|-----------|
- * Unstable | x | () | () | () |
- * Fickle | x | y | () | () |
- * Insistent | x | y | y | () |
- * Sticky | x | y | y,z | () |
- * ----------|----------|----------|------------|-----------|
- *
- * Permissibility Accepted Ranges:
- * ----------|----------|----------|------------|-----------|
- * | x -> x | x -> y | x -> y,z | x -> () |
- * ----------|----------|----------|------------|-----------|
- * Strict | ok | error | error | error |
- * Rigid | ok | ok | error | error |
- * Firm | ok | ok | ok | error |
- * Loose | ok | ok | ok | ok |
- * ----------|----------|----------|------------|-----------|
- */
-object Annotations {
- /** Returns true if a valid Module name */
- val SerializedModuleName = """([a-zA-Z_][a-zA-Z_0-9~!@#$%^*\-+=?/]*)""".r
- def validModuleName(s: String): Boolean = s match {
- case SerializedModuleName(name) => true
- case _ => false
- }
-
- /** Returns true if a valid component/subcomponent name */
- val SerializedComponentName = """([a-zA-Z_][a-zA-Z_0-9\[\]\.~!@#$%^*\-+=?/]*)""".r
- def validComponentName(s: String): Boolean = s match {
- case SerializedComponentName(name) => true
- case _ => false
- }
-
- /** Tokenizes a string with '[', ']', '.' as tokens, e.g.:
- * "foo.bar[boo.far]" becomes Seq("foo" "." "bar" "[" "boo" "." "far" "]")
- */
- def tokenize(s: String): Seq[String] = s.find(c => "[].".contains(c)) match {
- case Some(_) =>
- val i = s.indexWhere(c => "[].".contains(c))
- Seq(s.slice(0, i), s(i).toString) ++ tokenize(s.drop(i + 1))
- case None => Seq(s)
- }
-
- /** Given a serialized component/subcomponent reference, subindex, subaccess,
- * or subfield, return the corresponding IR expression.
- */
- def toExp(s: String): Expression = {
- def parse(tokens: Seq[String]): Expression = {
- val DecPattern = """([1-9]\d*)""".r
- def findClose(tokens: Seq[String], index: Int, nOpen: Int): Seq[String] =
- if(index >= tokens.size) {
- error("Cannot find closing bracket ]")
- } else tokens(index) match {
- case "[" => findClose(tokens, index + 1, nOpen + 1)
- case "]" if nOpen == 1 => tokens.slice(1, index)
- case _ => findClose(tokens, index + 1, nOpen)
- }
- def buildup(e: Expression, tokens: Seq[String]): Expression = tokens match {
- case "[" :: tail =>
- val indexOrAccess = findClose(tokens, 0, 0)
- indexOrAccess.head match {
- case DecPattern(d) => SubIndex(e, d.toInt, UnknownType)
- case _ => buildup(SubAccess(e, parse(indexOrAccess), UnknownType), tokens.slice(1, indexOrAccess.size))
- }
- case "." :: tail =>
- buildup(SubField(e, tokens(1), UnknownType), tokens.drop(2))
- case Nil => e
- }
- val root = Reference(tokens.head, UnknownType)
- buildup(root, tokens.tail)
- }
- if(validComponentName(s)) {
- parse(tokenize(s))
- } else error(s"Cannot convert $s into an expression.")
- }
-
- case class AnnotationException(message: String) extends Exception(message)
-
- /**
- * Named classes associate an annotation with a component in a Firrtl circuit
- */
- trait Named { def name: String }
- case class CircuitName(name: String) extends Named {
- if(!validModuleName(name)) throw AnnotationException(s"Illegal circuit name: $name")
- }
- case class ModuleName(name: String, circuit: CircuitName) extends Named {
- if(!validModuleName(name)) throw AnnotationException(s"Illegal module name: $name")
- }
- case class ComponentName(name: String, module: ModuleName) extends Named {
- if(!validComponentName(name)) throw AnnotationException(s"Illegal component name: $name")
- def expr: Expression = toExp(name)
- }
-
- /**
- * Permissibility defines the range of acceptable changes to the annotated component.
- */
- trait Permissibility {
- def check(from: Named, tos: Seq[Named], which: Annotation): Unit
- }
- /**
- * Annotated component cannot be renamed, expanded, or removed.
- */
- trait Strict extends Permissibility {
- def check(from: Named, tos: Seq[Named], which: Annotation): Unit = tos.size match {
- case 0 =>
- throw new AnnotationException(s"Cannot remove the strict annotation ${which.serialize} on ${from.name}")
- case 1 if from != tos.head =>
- throw new AnnotationException(s"Cannot rename the strict annotation ${which.serialize} on ${from.name} -> ${tos.head.name}")
- case _ =>
- throw new AnnotationException(s"Cannot expand a strict annotation on ${from.name} -> ${tos.map(_.name)}")
- }
- }
-
- /**
- * Annotated component can be renamed, but cannot be expanded or removed.
- */
- trait Rigid extends Permissibility {
- def check(from: Named, tos: Seq[Named], which: Annotation): Unit = tos.size match {
- case 0 => throw new AnnotationException(s"Cannot remove the rigid annotation ${which.serialize} on ${from.name}")
- case 1 =>
- case _ => throw new AnnotationException(s"Cannot expand a rigid annotation on ${from.name} -> ${tos.map(_.name)}")
- }
- }
-
- /**
- * Annotated component can be renamed, and expanded, but not removed.
- */
- trait Firm extends Permissibility {
- def check(from: Named, tos: Seq[Named], which: Annotation): Unit = tos.size match {
- case 0 => throw new AnnotationException(s"Cannot remove the firm annotation ${which.serialize} on ${from.name}")
- case _ =>
- }
- }
-
- /**
- * Annotated component can be renamed, and expanded, and removed.
- */
- trait Loose extends Permissibility {
- def check(from: Named, tos: Seq[Named], which: Annotation): Unit = {}
- }
-
- /**
- * Tenacity defines how the annotation propagates when changes to the
- * annotated component occur.
- */
- trait Tenacity {
- protected def propagate(from: Named, tos: Seq[Named], dup: Named=>Annotation): Seq[Annotation]
- }
-
- /**
- * Annotation propagates to all new components
- */
- trait Sticky extends Tenacity {
- protected def propagate(from: Named, tos: Seq[Named], dup: Named=>Annotation): Seq[Annotation] = tos.map(dup(_))
- }
-
- /**
- * Annotation propagates to the first of all new components
- */
- trait Insistent extends Tenacity {
- protected def propagate(from: Named, tos: Seq[Named], dup: Named=>Annotation): Seq[Annotation] = tos.headOption match {
- case None => Seq.empty
- case Some(n) => Seq(dup(n))
- }
- }
-
- /**
- * Annotation propagates only if there is one new component.
- */
- trait Fickle extends Tenacity {
- protected def propagate(from: Named, tos: Seq[Named], dup: Named=>Annotation): Seq[Annotation] = tos.size match {
- case 1 => Seq(dup(tos.head))
- case _ => Seq.empty
- }
- }
-
- /**
- * Annotation propagates only the new component shares the same name.
- */
- trait Unstable extends Tenacity {
- protected def propagate(from: Named, tos: Seq[Named], dup: Named=>Annotation): Seq[Annotation] = tos.size match {
- case 1 if tos.head == from => Seq(dup(tos.head))
- case _ => Seq.empty
- }
- }
-
- /**
- * Annotation associates with a given named circuit component (target) and a
- * given transformation (transform). Also defined are the legal ranges of changes
- * to the associated component (Permissibility) and how the annotation
- * propagates under such changes (Tenacity). Subclasses must implement the
- * duplicate function to create the same annotation associated with a new
- * component.
- */
- trait Annotation extends Permissibility with Tenacity {
- def target: Named
- def transform: Class[_ <: Transform]
- protected def duplicate(n: Named): Annotation
- def serialize: String = this.toString
- def update(tos: Seq[Named]): Seq[Annotation] = {
- check(target, tos, this)
- propagate(target, tos, duplicate)
- }
- }
-
- /**
- * Container of all annotations for a Firrtl compiler.
- */
- case class AnnotationMap(annotations: Seq[Annotation]) {
- def get(id: Class[_]): Seq[Annotation] = annotations.filter(a => a.transform == id)
- def get(named: Named): Seq[Annotation] = annotations.filter(n => n == named)
- }
-}
-