diff options
Diffstat (limited to 'macros')
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)" + } +} |
