1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
|
// SPDX-License-Identifier: Apache-2.0
package chisel3.experimental.hierarchy
import chisel3._
import scala.collection.mutable.{HashMap, HashSet}
import scala.reflect.runtime.universe.TypeTag
import chisel3.internal.BaseModule.IsClone
import chisel3.experimental.BaseModule
import _root_.firrtl.annotations.IsModule
import scala.annotation.implicitNotFound
/** Super-trait for Instance and Definition
*
* Enables writing functions which are Instance/Definition agnostic
*/
sealed trait Hierarchy[+A] {
private[chisel3] def underlying: Underlying[A]
private[chisel3] def proto: A = underlying match {
case Proto(value: A) => value
case Clone(i: IsClone[A]) => i.getProto
}
/** Updated by calls to [[_lookup]], to avoid recloning returned Data's */
private[chisel3] val cache = HashMap[Data, Data]()
private[chisel3] def getInnerDataContext: Option[BaseModule]
/** Determine whether underlying proto is of type provided.
*
* @note IMPORTANT: this function requires summoning a TypeTag[B], which will fail if B is an inner class.
* @note IMPORTANT: this function IGNORES type parameters, akin to normal type erasure.
* @note IMPORTANT: this function relies on Java reflection for underlying proto, but Scala reflection for provided type
*
* E.g. isA[List[Int]] will return true, even if underlying proto is of type List[String]
* @return Whether underlying proto is of provided type (with caveats outlined above)
*/
def isA[B: TypeTag]: Boolean = {
val tptag = implicitly[TypeTag[B]]
// drop any type information for the comparison, because the proto will not have that information.
val name = tptag.tpe.toString.takeWhile(_ != '[')
inBaseClasses(name)
}
// This code handles a special-case where, within an mdoc context, the type returned from
// scala reflection (typetag) looks different than when returned from java reflection.
// This function detects this case and reshapes the string to match.
private def modifyReplString(clz: String): String = {
if (clz != null) {
clz.split('.').toList match {
case "repl" :: "MdocSession" :: app :: rest => s"$app.this." + rest.mkString(".")
case other => clz
}
} else clz
}
private lazy val superClasses = calculateSuperClasses(proto.getClass())
private def calculateSuperClasses(clz: Class[_]): Set[String] = {
if (clz != null) {
Set(modifyReplString(clz.getCanonicalName())) ++
clz.getInterfaces().flatMap(i => calculateSuperClasses(i)) ++
calculateSuperClasses(clz.getSuperclass())
} else {
Set.empty[String]
}
}
private def inBaseClasses(clz: String): Boolean = superClasses.contains(clz)
/** Used by Chisel's internal macros. DO NOT USE in your normal Chisel code!!!
* Instead, mark the field you are accessing with [[@public]]
*
* Given a selector function (that) which selects a member from the original, return the
* corresponding member from the hierarchy.
*
* Our @instantiable and @public macros generate the calls to this apply method
*
* By calling this function, we summon the proper Lookupable typeclass from our implicit scope.
*
* @param that a user-specified lookup function
* @param lookup typeclass which contains the correct lookup function, based on the types of A and B
* @param macroGenerated a value created in the macro, to make it harder for users to use this API
*/
def _lookup[B, C](
that: A => B
)(
implicit lookup: Lookupable[B],
macroGenerated: chisel3.internal.MacroGenerated
): lookup.C
/** @return Return the underlying Definition[A] of this Hierarchy[A] */
def toDefinition: Definition[A]
/** @return Convert this Hierarchy[A] as a top-level Instance[A] */
def toInstance: Instance[A]
}
// Used to effectively seal Hierarchy, without requiring Definition and Instance to be in this file.
private[chisel3] trait SealedHierarchy[+A] extends Hierarchy[A]
object Hierarchy {
implicit class HierarchyBaseModuleExtensions[T <: BaseModule](i: Hierarchy[T]) {
/** Returns the toTarget of this hierarchy
* @return target of this hierarchy
*/
def toTarget: IsModule = i match {
case d: Definition[T] => new Definition.DefinitionBaseModuleExtensions(d).toTarget
case i: Instance[T] => new Instance.InstanceBaseModuleExtensions(i).toTarget
}
/** Returns the toAbsoluteTarget of this hierarchy
* @return absoluteTarget of this Hierarchy
*/
def toAbsoluteTarget: IsModule = i match {
case d: Definition[T] => new Definition.DefinitionBaseModuleExtensions(d).toAbsoluteTarget
case i: Instance[T] => new Instance.InstanceBaseModuleExtensions(i).toAbsoluteTarget
}
}
}
|