diff options
| author | Adam Izraelevitz | 2016-11-23 11:57:02 -0800 |
|---|---|---|
| committer | Jack Koenig | 2016-11-23 11:57:02 -0800 |
| commit | 66d3ec0498a73319a914eeffcb4e0b1109b5f4c5 (patch) | |
| tree | 325066fd05cc72b544d3b4d78d646e1a864119f3 /src/main/scala/firrtl/annotations/AnnotationUtils.scala | |
| parent | 9a967a27aa8bb51f4b62969d2889f9a9caa48e31 (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.scala | 74 |
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.") + } +} + |
