aboutsummaryrefslogtreecommitdiff
path: root/src/main/scala/firrtl/annotations/AnnotationUtils.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/AnnotationUtils.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/AnnotationUtils.scala')
-rw-r--r--src/main/scala/firrtl/annotations/AnnotationUtils.scala74
1 files changed, 74 insertions, 0 deletions
diff --git a/src/main/scala/firrtl/annotations/AnnotationUtils.scala b/src/main/scala/firrtl/annotations/AnnotationUtils.scala
new file mode 100644
index 00000000..6e6af81d
--- /dev/null
+++ b/src/main/scala/firrtl/annotations/AnnotationUtils.scala
@@ -0,0 +1,74 @@
+// See LICENSE for license details.
+
+package firrtl
+package annotations
+
+import firrtl.ir._
+
+object AnnotationUtils {
+ /** 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))
+ s.slice(0, i) match {
+ case "" => Seq(s(i).toString) ++ tokenize(s.drop(i + 1))
+ case x => Seq(x, s(i).toString) ++ tokenize(s.drop(i + 1))
+ }
+ case None if s == "" => Nil
+ case None => Seq(s)
+ }
+
+ /** Given a serialized component/subcomponent reference, subindex, subaccess,
+ * or subfield, return the corresponding IR expression.
+ * E.g. "foo.bar" becomes SubField(Reference("foo", UnknownType), "bar", UnknownType)
+ */
+ 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 - 1)
+ case _ => findClose(tokens, index + 1, nOpen)
+ }
+ }
+ def buildup(e: Expression, tokens: Seq[String]): Expression = tokens match {
+ case "[" :: tail =>
+ val indexOrAccess = findClose(tokens, 0, 0)
+ val exp = indexOrAccess.head match {
+ case DecPattern(d) => SubIndex(e, d.toInt, UnknownType)
+ case _ => SubAccess(e, parse(indexOrAccess), UnknownType)
+ }
+ buildup(exp, tokens.drop(2 + 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.")
+ }
+}
+