summaryrefslogtreecommitdiff
path: root/macros/src
diff options
context:
space:
mode:
Diffstat (limited to 'macros/src')
-rw-r--r--macros/src/main/scala/chisel3/SourceInfoDoc.scala38
-rw-r--r--macros/src/main/scala/chisel3/internal/RangeTransform.scala197
-rw-r--r--macros/src/main/scala/chisel3/internal/RuntimeDeprecationTransform.scala42
-rw-r--r--macros/src/main/scala/chisel3/internal/naming/NamingAnnotations.scala205
-rw-r--r--macros/src/main/scala/chisel3/internal/sourceinfo/SourceInfoTransform.scala186
5 files changed, 668 insertions, 0 deletions
diff --git a/macros/src/main/scala/chisel3/SourceInfoDoc.scala b/macros/src/main/scala/chisel3/SourceInfoDoc.scala
new file mode 100644
index 00000000..c44da915
--- /dev/null
+++ b/macros/src/main/scala/chisel3/SourceInfoDoc.scala
@@ -0,0 +1,38 @@
+// See LICENSE for license details.
+
+package chisel3
+
+/** Provides ScalaDoc information for "hidden" `do_*` methods
+ *
+ * Mix this into classes/objects that have `do_*` methods to get access to the shared `SourceInfoTransformMacro`
+ * ScalaDoc group and the lengthy `groupdesc` below.
+ *
+ * @groupdesc SourceInfoTransformMacro
+ *
+ * <p>
+ * '''These internal methods are not part of the public-facing API!'''
+ * <br>
+ * <br>
+ *
+ * The equivalent public-facing methods do not have the `do_` prefix or have the same name. Use and look at the
+ * documentation for those. If you want left shift, use `<<`, not `do_<<`. If you want conversion to a
+ * [[scala.collection.Seq Seq]] of [[Bool]]s look at the `asBools` above, not the one below. Users can safely ignore
+ * every method in this group! <br> <br>
+ *
+ * 🐉🐉🐉 '''Here be dragons...''' 🐉🐉🐉
+ * <br>
+ * <br>
+ *
+ * These `do_X` methods are used to enable both implicit passing of SourceInfo and [[chisel3.CompileOptions]]
+ * while also supporting chained apply methods. In effect all "normal" methods that you, as a user, will use in your
+ * designs, are converted to their "hidden", `do_*`, via macro transformations. Without using macros here, only one
+ * of the above wanted behaviors is allowed (implicit passing and chained applies)---the compiler interprets a
+ * chained apply as an explicit 'implicit' argument and will throw type errors. <br> <br>
+ *
+ * The "normal", public-facing methods then take no SourceInfo. However, a macro transforms this public-facing method
+ * into a call to an internal, hidden `do_*` that takes an explicit SourceInfo by inserting an
+ * `implicitly[SourceInfo]` as the explicit argument. </p>
+ *
+ * @groupprio SourceInfoTransformMacro 1001
+ */
+trait SourceInfoDoc
diff --git a/macros/src/main/scala/chisel3/internal/RangeTransform.scala b/macros/src/main/scala/chisel3/internal/RangeTransform.scala
new file mode 100644
index 00000000..0fdbff81
--- /dev/null
+++ b/macros/src/main/scala/chisel3/internal/RangeTransform.scala
@@ -0,0 +1,197 @@
+// See LICENSE for license details.
+
+// Macro transforms that statically (at compile time) parse range specifiers and emit the raw
+// (non-human-friendly) range constructor calls.
+
+package chisel3.internal
+
+import scala.language.experimental.macros
+import scala.reflect.macros.blackbox
+import scala.util.matching.Regex
+
+// Workaround for https://github.com/sbt/sbt/issues/3966
+object RangeTransform {
+ val UnspecifiedNumber: Regex = """(\?).*""".r
+ val IntegerNumber: Regex = """(-?\d+).*""".r
+ val DecimalNumber: Regex = """(-?\d+\.\d+).*""".r
+}
+
+/** Convert the string to IntervalRange, with unknown, open or closed endpoints and a binary point
+ * ranges looks like
+ * range"[0,4].1" range starts at 0 inclusive ends at 4.inclusively with a binary point of 1
+ * range"(0,4).1" range starts at 0 exclusive ends at 4.exclusively with a binary point of 1
+ *
+ * the min and max of the range are the actually min and max values, thus the binary point
+ * becomes a sort of multiplier for the number of bits.
+ * E.g. range"[0,3].2" will require at least 4 bits two provide the two decimal places
+ *
+ * @param c contains the string context to be parsed
+ */
+//scalastyle:off cyclomatic.complexity method.length
+class RangeTransform(val c: blackbox.Context) {
+ import c.universe._
+ def apply(args: c.Tree*): c.Tree = {
+ val stringTrees = c.prefix.tree match {
+ case q"$_(scala.StringContext.apply(..$strings))" => strings
+ case _ =>
+ c.abort(
+ c.enclosingPosition,
+ s"Range macro unable to parse StringContext, got: ${showCode(c.prefix.tree)}"
+ )
+ }
+ val strings = stringTrees.map {
+ case Literal(Constant(string: String)) => string
+ case tree =>
+ c.abort(
+ c.enclosingPosition,
+ s"Range macro unable to parse StringContext element, got: ${showRaw(tree)}"
+ )
+ }
+
+ var nextStringIndex: Int = 1
+ var nextArgIndex: Int = 0
+ var currString: String = strings.head
+
+ /** Mutably gets the next numeric value in the range specifier.
+ */
+ def computeNextValue(): c.Tree = {
+ currString = currString.dropWhile(_ == ' ') // allow whitespace
+ if (currString.isEmpty) {
+ if (nextArgIndex >= args.length) {
+ c.abort(c.enclosingPosition, s"Incomplete range specifier")
+ }
+ val nextArg = args(nextArgIndex)
+ nextArgIndex += 1
+
+ if (nextStringIndex >= strings.length) {
+ c.abort(c.enclosingPosition, s"Incomplete range specifier")
+ }
+ currString = strings(nextStringIndex)
+ nextStringIndex += 1
+
+ nextArg
+ } else {
+ val nextStringVal = currString match {
+ case RangeTransform.DecimalNumber(numberString) => numberString
+ case RangeTransform.IntegerNumber(numberString) => numberString
+ case RangeTransform.UnspecifiedNumber(_) => "?"
+ case _ =>
+ c.abort(
+ c.enclosingPosition,
+ s"Bad number or unspecified bound $currString"
+ )
+ }
+ currString = currString.substring(nextStringVal.length)
+
+ if (nextStringVal == "?") {
+ Literal(Constant("?"))
+ } else {
+ c.parse(nextStringVal)
+ }
+ }
+ }
+
+ // Currently, not allowed to have the end stops (inclusive / exclusive) be interpolated.
+ currString = currString.dropWhile(_ == ' ')
+ val startInclusive = currString.headOption match {
+ case Some('[') => true
+ case Some('(') => false
+ case Some('?') =>
+ c.abort(
+ c.enclosingPosition,
+ s"start of range as unknown s must be '[?' or '(?' not '?'"
+ )
+ case Some(other) =>
+ c.abort(
+ c.enclosingPosition,
+ s"Unknown start inclusive/exclusive specifier, got: '$other'"
+ )
+ case None =>
+ c.abort(
+ c.enclosingPosition,
+ s"No initial inclusive/exclusive specifier"
+ )
+ }
+
+ currString = currString.substring(1) // eat the inclusive/exclusive specifier
+ val minArg = computeNextValue()
+ currString = currString.dropWhile(_ == ' ')
+ if (currString(0) != ',') {
+ c.abort(c.enclosingPosition, s"Incomplete range specifier, expected ','")
+ }
+ if (currString.head != ',') {
+ c.abort(
+ c.enclosingPosition,
+ s"Incomplete range specifier, expected ',', got $currString"
+ )
+ }
+
+ currString = currString.substring(1) // eat the comma
+
+ val maxArg = computeNextValue()
+ currString = currString.dropWhile(_ == ' ')
+
+ val endInclusive = currString.headOption match {
+ case Some(']') => true
+ case Some(')') => false
+ case Some('?') =>
+ c.abort(
+ c.enclosingPosition,
+ s"start of range as unknown s must be '[?' or '(?' not '?'"
+ )
+ case Some(other) =>
+ c.abort(
+ c.enclosingPosition,
+ s"Unknown end inclusive/exclusive specifier, got: '$other' expecting ')' or ']'"
+ )
+ case None =>
+ c.abort(
+ c.enclosingPosition,
+ s"Incomplete range specifier, missing end inclusive/exclusive specifier"
+ )
+ }
+ currString = currString.substring(1) // eat the inclusive/exclusive specifier
+ currString = currString.dropWhile(_ == ' ')
+
+ val binaryPointString = currString.headOption match {
+ case Some('.') =>
+ currString = currString.substring(1)
+ computeNextValue()
+ case Some(other) =>
+ c.abort(
+ c.enclosingPosition,
+ s"Unknown end binary point prefix, got: '$other' was expecting '.'"
+ )
+ case None =>
+ Literal(Constant(0))
+ }
+
+ if (nextArgIndex < args.length) {
+ val unused = args.mkString("")
+ c.abort(
+ c.enclosingPosition,
+ s"Unused interpolated values in range specifier: '$unused'"
+ )
+ }
+ if (!currString.isEmpty || nextStringIndex < strings.length) {
+ val unused = currString + strings
+ .slice(nextStringIndex, strings.length)
+ .mkString(", ")
+ c.abort(
+ c.enclosingPosition,
+ s"Unused characters in range specifier: '$unused'"
+ )
+ }
+
+ val startBound =
+ q"_root_.chisel3.internal.firrtl.IntervalRange.getBound($startInclusive, $minArg)"
+
+ val endBound =
+ q"_root_.chisel3.internal.firrtl.IntervalRange.getBound($endInclusive, $maxArg)"
+
+ val binaryPoint =
+ q"_root_.chisel3.internal.firrtl.IntervalRange.getBinaryPoint($binaryPointString)"
+
+ q"_root_.chisel3.internal.firrtl.IntervalRange($startBound, $endBound, $binaryPoint)"
+ }
+}
diff --git a/macros/src/main/scala/chisel3/internal/RuntimeDeprecationTransform.scala b/macros/src/main/scala/chisel3/internal/RuntimeDeprecationTransform.scala
new file mode 100644
index 00000000..e1f528b3
--- /dev/null
+++ b/macros/src/main/scala/chisel3/internal/RuntimeDeprecationTransform.scala
@@ -0,0 +1,42 @@
+// See LICENSE for license details.
+
+package chisel3.internal
+
+import scala.reflect.macros.whitebox.Context
+import scala.annotation.{StaticAnnotation, compileTimeOnly}
+import scala.language.experimental.macros
+
+// Workaround for https://github.com/sbt/sbt/issues/3966
+object RuntimeDeprecatedTransform
+class RuntimeDeprecatedTransform(val c: Context) {
+ import c.universe._
+
+ /** Adds a Builder.deprecated(...) call based on the contents of a plain @deprecated annotation.
+ */
+ def runtimeDeprecated(annottees: c.Tree*): c.Tree = {
+ val transformed = annottees.map(annottee => annottee match {
+ case q"$mods def $tname[..$tparams](...$paramss): $tpt = $expr" => {
+ val Modifiers(_, _, annotations) = mods
+ val annotationMessage = annotations.collect { // get all messages from deprecated annotations
+ case q"new deprecated($desc, $since)" => desc
+ } match { // ensure there's only one and return it
+ case msg :: Nil => msg
+ case _ => c.abort(c.enclosingPosition, s"@chiselRuntimeDeprecated annotion must be used with exactly one @deprecated annotation, got annotations $annotations") // scalastyle:ignore line.size.limit
+ }
+ val message = s"$tname is deprecated: $annotationMessage"
+ val transformedExpr = q""" {
+ _root_.chisel3.internal.Builder.deprecated($message)
+ $expr
+ } """
+ q"$mods def $tname[..$tparams](...$paramss): $tpt = $transformedExpr"
+ }
+ case other => c.abort(c.enclosingPosition, s"@chiselRuntimeDeprecated annotion may only be used on defs, got ${showCode(other)}") // scalastyle:ignore line.size.limit
+ })
+ q"..$transformed"
+ }
+}
+
+@compileTimeOnly("enable macro paradise to expand macro annotations")
+class chiselRuntimeDeprecated extends StaticAnnotation {
+ def macroTransform(annottees: Any*): Any = macro chisel3.internal.RuntimeDeprecatedTransform.runtimeDeprecated
+}
diff --git a/macros/src/main/scala/chisel3/internal/naming/NamingAnnotations.scala b/macros/src/main/scala/chisel3/internal/naming/NamingAnnotations.scala
new file mode 100644
index 00000000..bf4879ec
--- /dev/null
+++ b/macros/src/main/scala/chisel3/internal/naming/NamingAnnotations.scala
@@ -0,0 +1,205 @@
+// See LICENSE for license details.
+
+// Transform implementations for name-propagation related annotations.
+//
+// Helpful references:
+// http://docs.scala-lang.org/overviews/quasiquotes/syntax-summary.html#definitions
+// for quasiquote structures of various Scala structures
+// http://jsuereth.com/scala/2009/02/05/leveraging-annotations-in-scala.html
+// use of Transformer
+// http://www.scala-lang.org/old/sites/default/files/sids/rytz/Wed,%202010-01-27,%2015:10/annots.pdf
+// general annotations reference
+
+package chisel3.internal.naming
+
+import scala.reflect.macros.whitebox.Context
+import scala.annotation.{StaticAnnotation, compileTimeOnly}
+import scala.language.experimental.macros
+
+// Workaround for https://github.com/sbt/sbt/issues/3966
+object DebugTransforms
+class DebugTransforms(val c: Context) {
+ import c.universe._
+
+ /** Passthrough transform that prints the annottee for debugging purposes.
+ * No guarantees are made on what this annotation does, and it may very well change over time.
+ *
+ * The print is warning level to make it visually easier to spot, as well as a reminder that
+ * this annotation should not make it to production / committed code.
+ */
+ def dump(annottees: c.Tree*): c.Tree = {
+ val combined = annottees.map({ tree => show(tree) }).mkString("\r\n\r\n")
+ annottees.foreach(tree => c.warning(c.enclosingPosition, s"Debug dump:\n$combined"))
+ q"..$annottees"
+ }
+
+ /** Passthrough transform that prints the annottee as a tree for debugging purposes.
+ * No guarantees are made on what this annotation does, and it may very well change over time.
+ *
+ * The print is warning level to make it visually easier to spot, as well as a reminder that
+ * this annotation should not make it to production / committed code.
+ */
+ def treedump(annottees: c.Tree*): c.Tree = {
+ val combined = annottees.map({ tree => showRaw(tree) }).mkString("\r\n")
+ annottees.foreach(tree => c.warning(c.enclosingPosition, s"Debug tree dump:\n$combined"))
+ q"..$annottees"
+ }
+}
+
+// Workaround for https://github.com/sbt/sbt/issues/3966
+object NamingTransforms
+class NamingTransforms(val c: Context) {
+ import c.universe._
+
+ val globalNamingStack = q"_root_.chisel3.internal.DynamicNamingStack"
+
+ /** Base transformer that provides the val name transform.
+ * Should not be instantiated, since by default this will recurse everywhere and break the
+ * naming context variable bounds.
+ */
+ trait ValNameTransformer extends Transformer {
+ val contextVar: TermName
+
+ override def transform(tree: Tree): Tree = tree match {
+ // Intentionally not prefixed with $mods, since modifiers usually mean the val definition
+ // is in a non-transformable location, like as a parameter list.
+ // TODO: is this exhaustive / correct in all cases?
+ case q"val $tname: $tpt = $expr" => {
+ val TermName(tnameStr: String) = tname
+ val transformedExpr = super.transform(expr)
+ q"val $tname: $tpt = $contextVar.name($transformedExpr, $tnameStr)"
+ }
+ case other => super.transform(other)
+ }
+ }
+
+ /** Module-specific val name transform, containing logic to prevent from recursing into inner
+ * classes and applies the naming transform on inner functions.
+ */
+ class ClassBodyTransformer(val contextVar: TermName) extends ValNameTransformer {
+ override def transform(tree: Tree): Tree = tree match {
+ case q"$mods class $tpname[..$tparams] $ctorMods(...$paramss) extends { ..$earlydefns } with ..$parents { $self => ..$stats }" => // scalastyle:ignore line.size.limit
+ tree // don't recurse into inner classes
+ case q"$mods trait $tpname[..$tparams] extends { ..$earlydefns } with ..$parents { $self => ..$stats }" =>
+ tree // don't recurse into inner classes
+ case q"$mods def $tname[..$tparams](...$paramss): $tpt = $expr" => {
+ val Modifiers(_, _, annotations) = mods
+ // don't apply naming transform twice
+ val containsChiselName = annotations.map({q"new chiselName()" equalsStructure _}).fold(false)({_||_})
+ // transforming overloaded initializers causes errors, and the transform isn't helpful
+ val isInitializer = tname == TermName("<init>")
+ if (containsChiselName || isInitializer) {
+ tree
+ } else {
+ // apply chiselName transform by default
+ val transformedExpr = transformHierarchicalMethod(expr)
+ q"$mods def $tname[..$tparams](...$paramss): $tpt = $transformedExpr"
+ }
+ }
+ case other => super.transform(other)
+ }
+ }
+
+ /** Method-specific val name transform, handling the return case.
+ */
+ class MethodTransformer(val contextVar: TermName) extends ValNameTransformer {
+ override def transform(tree: Tree): Tree = tree match {
+ // TODO: better error messages when returning nothing
+ case q"return $expr" => q"return $globalNamingStack.popReturnContext($expr, $contextVar)"
+ // Do not recurse into methods
+ case q"$mods def $tname[..$tparams](...$paramss): $tpt = $expr" => tree
+ case other => super.transform(other)
+ }
+ }
+
+ /** Applies the val name transform to a class body.
+ * Closes context on top level or return local context to englobing context.
+ * Closing context only makes sense when top level a Module.
+ * A Module is always the naming top level.
+ * Transformed classes can be either Module or standard class.
+ */
+ def transformClassBody(stats: List[c.Tree]): Tree = {
+ val contextVar = TermName(c.freshName("namingContext"))
+ val transformedBody = (new ClassBodyTransformer(contextVar)).transformTrees(stats)
+ // Note: passing "this" to popReturnContext is mandatory for propagation through non-module classes
+ q"""
+ val $contextVar = $globalNamingStack.pushContext()
+ ..$transformedBody
+ if($globalNamingStack.length == 1){
+ $contextVar.namePrefix("")
+ }
+ $globalNamingStack.popReturnContext(this, $contextVar)
+ """
+ }
+
+ /** Applies the val name transform to a method body, doing additional bookkeeping with the
+ * context to allow names to propagate and prefix through the function call stack.
+ */
+ def transformHierarchicalMethod(expr: c.Tree): Tree = {
+ val contextVar = TermName(c.freshName("namingContext"))
+ val transformedBody = (new MethodTransformer(contextVar)).transform(expr)
+
+ q"""{
+ val $contextVar = $globalNamingStack.pushContext()
+ $globalNamingStack.popReturnContext($transformedBody, $contextVar)
+ }
+ """
+ }
+
+ /** Applies naming transforms to vals in the annotated module or method.
+ *
+ * For methods, a hierarchical naming transform is used, where it will try to give objects names
+ * based on the call stack, assuming all functions on the stack are annotated as such and return
+ * a non-AnyVal object. Does not recurse into inner functions.
+ *
+ * For modules, this serves as the root of the call stack hierarchy for naming purposes. Methods
+ * will have chiselName annotations (non-recursively), but this does NOT affect inner classes.
+ *
+ * Basically rewrites all instances of:
+ * val name = expr
+ * to:
+ * val name = context.name(expr, name)
+ */
+ def chiselName(annottees: c.Tree*): c.Tree = {
+ var namedElts: Int = 0
+
+ val transformed = annottees.map(annottee => annottee match {
+ // scalastyle:off line.size.limit
+ case q"$mods class $tpname[..$tparams] $ctorMods(...$paramss) extends { ..$earlydefns } with ..$parents { $self => ..$stats }" => {
+ val transformedStats = transformClassBody(stats)
+ namedElts += 1
+ q"$mods class $tpname[..$tparams] $ctorMods(...$paramss) extends { ..$earlydefns } with ..$parents { $self => ..$transformedStats }"
+ }
+ case q"$mods object $tname extends { ..$earlydefns } with ..$parents { $self => ..$body }" => {
+ annottee // Don't fail noisly when a companion object is passed in with the actual class def
+ }
+ // Currently disallow on traits, this won't work well with inheritance.
+ case q"$mods def $tname[..$tparams](...$paramss): $tpt = $expr" => {
+ val transformedExpr = transformHierarchicalMethod(expr)
+ namedElts += 1
+ q"$mods def $tname[..$tparams](...$paramss): $tpt = $transformedExpr"
+ }
+ case other => c.abort(c.enclosingPosition, s"@chiselName annotion may only be used on classes and methods, got ${showCode(other)}")
+ })
+
+ if (namedElts != 1) {
+ c.abort(c.enclosingPosition, s"@chiselName annotation did not match exactly one valid tree, got:\r\n${annottees.map(tree => showCode(tree)).mkString("\r\n\r\n")}")
+ }
+ // scalastyle:on line.size.limit
+
+ q"..$transformed"
+ }
+}
+
+@compileTimeOnly("enable macro paradise to expand macro annotations")
+class dump extends StaticAnnotation { // scalastyle:ignore class.name
+ def macroTransform(annottees: Any*): Any = macro chisel3.internal.naming.DebugTransforms.dump
+}
+@compileTimeOnly("enable macro paradise to expand macro annotations")
+class treedump extends StaticAnnotation { // scalastyle:ignore class.name
+ def macroTransform(annottees: Any*): Any = macro chisel3.internal.naming.DebugTransforms.treedump
+}
+@compileTimeOnly("enable macro paradise to expand macro annotations")
+class chiselName extends StaticAnnotation { // scalastyle:ignore class.name
+ def macroTransform(annottees: Any*): Any = macro chisel3.internal.naming.NamingTransforms.chiselName
+}
diff --git a/macros/src/main/scala/chisel3/internal/sourceinfo/SourceInfoTransform.scala b/macros/src/main/scala/chisel3/internal/sourceinfo/SourceInfoTransform.scala
new file mode 100644
index 00000000..6d7c3411
--- /dev/null
+++ b/macros/src/main/scala/chisel3/internal/sourceinfo/SourceInfoTransform.scala
@@ -0,0 +1,186 @@
+// See LICENSE for license details.
+
+// This file transform macro definitions to explicitly add implicit source info to Chisel method
+// calls.
+
+package chisel3.internal.sourceinfo
+
+import scala.language.experimental.macros
+import scala.reflect.macros.blackbox.Context
+import scala.reflect.macros.whitebox
+
+
+/** Transforms a function call so that it can both provide implicit-style source information and
+ * have a chained apply call. Without macros, only one is possible, since having a implicit
+ * argument in the definition will cause the compiler to interpret a chained apply as an
+ * explicit implicit argument and give type errors.
+ *
+ * Instead of an implicit argument, the public-facing function no longer takes a SourceInfo at all.
+ * The macro transforms the public-facing function into a call to an internal function that takes
+ * an explicit SourceInfo by inserting an implicitly[SourceInfo] as the explicit argument.
+ */
+trait SourceInfoTransformMacro {
+ val c: Context
+ import c.universe._
+ def thisObj: Tree = c.prefix.tree
+ def implicitSourceInfo = q"implicitly[_root_.chisel3.internal.sourceinfo.SourceInfo]"
+ def implicitCompileOptions = q"implicitly[_root_.chisel3.CompileOptions]"
+}
+
+// Workaround for https://github.com/sbt/sbt/issues/3966
+object UIntTransform
+class UIntTransform(val c: Context) extends SourceInfoTransformMacro {
+ import c.universe._
+ def bitset(off: c.Tree, dat: c.Tree): c.Tree = {
+ q"$thisObj.do_bitSet($off, $dat)($implicitSourceInfo, $implicitCompileOptions)"
+ }
+}
+
+// Workaround for https://github.com/sbt/sbt/issues/3966
+object InstTransform
+// Module instantiation transform
+class InstTransform(val c: Context) extends SourceInfoTransformMacro {
+ import c.universe._
+ def apply[T: c.WeakTypeTag](bc: c.Tree): c.Tree = {
+ q"$thisObj.do_apply($bc)($implicitSourceInfo, $implicitCompileOptions)"
+ }
+}
+
+// Workaround for https://github.com/sbt/sbt/issues/3966
+object MemTransform
+class MemTransform(val c: Context) extends SourceInfoTransformMacro {
+ import c.universe._
+ def apply[T: c.WeakTypeTag](size: c.Tree, t: c.Tree): c.Tree = {
+ q"$thisObj.do_apply($size, $t)($implicitSourceInfo, $implicitCompileOptions)"
+ }
+ def apply_ruw[T: c.WeakTypeTag](size: c.Tree, t: c.Tree, ruw: c.Tree): c.Tree = {
+ q"$thisObj.do_apply($size, $t, $ruw)($implicitSourceInfo, $implicitCompileOptions)"
+ }
+}
+
+// Workaround for https://github.com/sbt/sbt/issues/3966
+object MuxTransform
+class MuxTransform(val c: Context) extends SourceInfoTransformMacro {
+ import c.universe._
+ def apply[T: c.WeakTypeTag](cond: c.Tree, con: c.Tree, alt: c.Tree): c.Tree = {
+ val tpe = weakTypeOf[T]
+ q"$thisObj.do_apply[$tpe]($cond, $con, $alt)($implicitSourceInfo, $implicitCompileOptions)"
+ }
+}
+
+// Workaround for https://github.com/sbt/sbt/issues/3966
+object VecTransform
+class VecTransform(val c: Context) extends SourceInfoTransformMacro {
+ import c.universe._
+ def apply_elts(elts: c.Tree): c.Tree = {
+ q"$thisObj.do_apply($elts)($implicitSourceInfo, $implicitCompileOptions)"
+ }
+ def apply_elt0(elt0: c.Tree, elts: c.Tree*): c.Tree = {
+ q"$thisObj.do_apply($elt0, ..$elts)($implicitSourceInfo, $implicitCompileOptions)"
+ }
+ def tabulate(n: c.Tree)(gen: c.Tree): c.Tree = {
+ q"$thisObj.do_tabulate($n)($gen)($implicitSourceInfo, $implicitCompileOptions)"
+ }
+ def fill(n: c.Tree)(gen: c.Tree): c.Tree = {
+ q"$thisObj.do_fill($n)($gen)($implicitSourceInfo, $implicitCompileOptions)"
+ }
+ def contains(x: c.Tree)(ev: c.Tree): c.Tree = {
+ q"$thisObj.do_contains($x)($implicitSourceInfo, $ev, $implicitCompileOptions)"
+ }
+ def reduceTree(redOp: c.Tree, layerOp: c.Tree): c.Tree = {
+ q"$thisObj.do_reduceTree($redOp,$layerOp)($implicitSourceInfo, $implicitCompileOptions)"
+ }
+ def reduceTreeDefault(redOp: c.Tree ): c.Tree = {
+ q"$thisObj.do_reduceTree($redOp)($implicitSourceInfo, $implicitCompileOptions)"
+ }
+}
+
+/** "Automatic" source information transform / insertion macros, which generate the function name
+ * based on the macro invocation (instead of explicitly writing out every transform).
+ */
+abstract class AutoSourceTransform extends SourceInfoTransformMacro {
+ import c.universe._
+ /** Returns the TermName of the transformed function, which is the applied function name with do_
+ * prepended.
+ */
+ def doFuncTerm: TermName = {
+ val funcName = c.macroApplication match {
+ case q"$_.$funcName[..$_](...$_)" => funcName
+ case _ => throw new Exception(s"Chisel Internal Error: Could not resolve function name from macro application: ${showCode(c.macroApplication)}") // scalastyle:ignore line.size.limit
+ }
+ TermName("do_" + funcName)
+ }
+}
+
+// Workaround for https://github.com/sbt/sbt/issues/3966
+object SourceInfoTransform
+class SourceInfoTransform(val c: Context) extends AutoSourceTransform {
+ import c.universe._
+
+ def noArg(): c.Tree = {
+ q"$thisObj.$doFuncTerm($implicitSourceInfo, $implicitCompileOptions)"
+ }
+
+ def thatArg(that: c.Tree): c.Tree = {
+ q"$thisObj.$doFuncTerm($that)($implicitSourceInfo, $implicitCompileOptions)"
+ }
+
+ def nArg(n: c.Tree): c.Tree = {
+ q"$thisObj.$doFuncTerm($n)($implicitSourceInfo, $implicitCompileOptions)"
+ }
+
+ def pArg(p: c.Tree): c.Tree = {
+ q"$thisObj.$doFuncTerm($p)($implicitSourceInfo, $implicitCompileOptions)"
+ }
+
+ def inArg(in: c.Tree): c.Tree = {
+ q"$thisObj.$doFuncTerm($in)($implicitSourceInfo, $implicitCompileOptions)"
+ }
+
+ def xArg(x: c.Tree): c.Tree = {
+ q"$thisObj.$doFuncTerm($x)($implicitSourceInfo, $implicitCompileOptions)"
+ }
+
+ def xyArg(x: c.Tree, y: c.Tree): c.Tree = {
+ q"$thisObj.$doFuncTerm($x, $y)($implicitSourceInfo, $implicitCompileOptions)"
+ }
+
+ def xEnArg(x: c.Tree, en: c.Tree): c.Tree = {
+ q"$thisObj.$doFuncTerm($x, $en)($implicitSourceInfo, $implicitCompileOptions)"
+ }
+}
+
+// Workaround for https://github.com/sbt/sbt/issues/3966
+object CompileOptionsTransform
+class CompileOptionsTransform(val c: Context) extends AutoSourceTransform {
+ import c.universe._
+
+ def thatArg(that: c.Tree): c.Tree = {
+ q"$thisObj.$doFuncTerm($that)($implicitCompileOptions)"
+ }
+
+ def inArg(in: c.Tree): c.Tree = {
+ q"$thisObj.$doFuncTerm($in)($implicitCompileOptions)"
+ }
+
+ def pArg(p: c.Tree): c.Tree = {
+ q"$thisObj.$doFuncTerm($p)($implicitCompileOptions)"
+ }
+}
+
+// Workaround for https://github.com/sbt/sbt/issues/3966
+object SourceInfoWhiteboxTransform
+/** Special whitebox version of the blackbox SourceInfoTransform, used when fun things need to
+ * happen to satisfy the type system while preventing the use of macro overrides.
+ */
+class SourceInfoWhiteboxTransform(val c: whitebox.Context) extends AutoSourceTransform {
+ import c.universe._
+
+ def noArg(): c.Tree = {
+ q"$thisObj.$doFuncTerm($implicitSourceInfo, $implicitCompileOptions)"
+ }
+
+ def thatArg(that: c.Tree): c.Tree = {
+ q"$thisObj.$doFuncTerm($that)($implicitSourceInfo, $implicitCompileOptions)"
+ }
+}