All Downloads are FREE. Search and download functionalities are using the official Maven repository.

scala.tools.tasty.TastyName.scala Maven / Gradle / Ivy

The newest version!
/*
 * Scala (https://www.scala-lang.org)
 *
 * Copyright EPFL and Lightbend, Inc. dba Akka
 *
 * Licensed under Apache License 2.0
 * (http://www.apache.org/licenses/LICENSE-2.0).
 *
 * See the NOTICE file distributed with this work for
 * additional information regarding copyright ownership.
 */

package scala.tools.tasty

import scala.reflect.NameTransformer

object TastyName {

  // TODO [tasty]: cache chars for Names. SimpleName acts as a cursor

  final case class SimpleName(raw: String)                                                    extends TastyName
  final case class ObjectName(base: TastyName)                                                extends TastyName
  final case class QualifiedName(qual: TastyName, sep: SimpleName, selector: SimpleName)      extends TastyName
  final case class UniqueName(qual: TastyName, sep: SimpleName, num: Int)                     extends TastyName
  final case class DefaultName(qual: TastyName, num: Int)                                     extends TastyName
  final case class PrefixName(prefix: SimpleName, qual: TastyName)                            extends TastyName
  final case class SuffixName(qual: TastyName, suffix: SimpleName)                            extends TastyName
  final case class TypeName private (base: TastyName)                                         extends TastyName
  final case class SignedName(
    qual: TastyName,
    sig: Signature.MethodSignature[ErasedTypeRef],
    target: TastyName) extends TastyName

  object TypeName {
    private[TastyName] def apply(base: TastyName): TypeName = base match {
      case name: TypeName => name
      case name           => new TypeName(name)
    }
  }

  // Separators
  final val PathSep: SimpleName = SimpleName(".")
  final val ExpandedSep: SimpleName = SimpleName("$$")
  final val ExpandPrefixSep: SimpleName = SimpleName("$")
  final val WildcardSep: SimpleName = SimpleName("_$")
  final val InlinePrefix: SimpleName = SimpleName("inline$")
  final val SuperPrefix: SimpleName = SimpleName("super$")
  final val BodyRetainerSuffix: SimpleName = SimpleName("$retainedBody")

  // TermNames
  final val Empty: SimpleName = SimpleName("")
  final val Constructor: SimpleName = SimpleName("")
  final val MixinConstructor: SimpleName = SimpleName("$init$")
  final val EmptyPkg: SimpleName = SimpleName("")
  final val Root: SimpleName = SimpleName("")
  final val RootPkg: SimpleName = SimpleName("_root_")

  // TypeNames
  final val RepeatedClass: TypeName = SimpleName("").toTypeName
  final val EmptyTpe: TypeName = Empty.toTypeName

  object WildcardName {
    def unapply(name: TastyName): Boolean = name match {
      case UniqueName(Empty, WildcardSep, _) => true
      case _                                 => false
    }
  }

  final val DefaultGetterStr     = "$default$"
  final val DefaultGetterInitStr = NameTransformer.encode("") + DefaultGetterStr

  trait NameEncoder[U] {
    final def encode[O](name: TastyName)(init: => U, finish: U => O): O = finish(traverse(init, name))
    def traverse(u: U, name: TastyName): U
  }

  trait StringBuilderEncoder extends NameEncoder[StringBuilder] {
    final def encode(name: TastyName): String = name match {
      case SimpleName(raw) => raw
      case _               => super.encode(name)(new StringBuilder(25), _.toString)
    }
  }

  /** Converts a name to a representation closest to source code.
   */
  object SourceEncoder extends StringBuilderEncoder {
    def traverse(sb: StringBuilder, name: TastyName): StringBuilder = name match {
      case name: SimpleName    => sb append (name.raw)
      case name: ObjectName    => traverse(sb, name.base)
      case name: TypeName      => traverse(sb, name.base)
      case name: SignedName    => traverse(sb, name.qual)
      case name: UniqueName    => traverse(sb, name.qual) append (name.sep.raw) append (name.num)
      case name: QualifiedName => traverse(traverse(sb, name.qual) append (name.sep.raw), name.selector)
      case name: PrefixName    => traverse(sb append (name.prefix.raw), name.qual)
      case name: SuffixName    => traverse(sb, name.qual) append (name.suffix.raw)

      case name: DefaultName if name.qual == Constructor  =>
        sb append DefaultGetterInitStr append (name.num + 1)

      case name: DefaultName => traverse(sb, name.qual) append DefaultGetterStr append (name.num + 1)
    }
  }

  /** Displays formatted information about the structure of the name
   */
  object DebugEncoder extends StringBuilderEncoder {
    import Signature.merge

    def traverse(sb: StringBuilder, name: TastyName): StringBuilder = name match {

      case SimpleName(raw)               => sb append raw
      case DefaultName(qual, num)        => traverse(sb, qual) append "[Default " append (num + 1) append ']'
      case PrefixName(prefix, qual)      => traverse(sb, qual) append "[Prefix " append (prefix.raw) append ']'
      case SuffixName(qual, suffix)      => traverse(sb, qual) append "[Suffix " append (suffix.raw) append ']'
      case ObjectName(name)              => traverse(sb, name) append "[ModuleClass]"
      case TypeName(name)                => traverse(sb, name) append "[Type]"
      case SignedName(name, sig, target) => merge(traverse(sb, name) append "[Signed ", sig.map(_.signature)) append " @" append target.source append ']'

      case QualifiedName(qual, sep, name) =>
        traverse(sb, qual) append "[Qualified " append (sep.raw) append ' ' append (name.raw) append ']'

      case UniqueName(qual, sep, num) =>
        traverse(sb, qual) append "[Unique " append (sep.raw) append ' ' append num append ']'

    }

  }

  /** Encodes names as expected by the Scala Reflect SymbolTable
   */
  object ScalaNameEncoder extends NameEncoder[StringBuilder] {

    /** Escapes all symbolic characters. Special names should be handled before calling this.
      */
    final def encode(name: TastyName): String = name match {
      case SimpleName(raw) => NameTransformer.encode(raw)
      case _               => super.encode(name)(new StringBuilder(25), _.toString)
    }

    def traverse(sb: StringBuilder, name: TastyName): StringBuilder = name match {
      case name: SimpleName    => sb.append(NameTransformer.encode(name.raw))
      case name: ObjectName    => traverse(sb, name.base)
      case name: TypeName      => traverse(sb, name.base)
      case name: SignedName    => traverse(sb, name.qual)
      case name: UniqueName    => traverse(sb, name.qual) append (name.sep.raw) append (name.num)
      case name: QualifiedName => traverse(traverse(sb, name.qual) append (name.sep.raw), name.selector)
      case name: PrefixName    => traverse(sb append (name.prefix.raw), name.qual)
      case name: SuffixName    => traverse(sb, name.qual) append (name.suffix.raw)

      case name: DefaultName if name.qual == Constructor => sb append DefaultGetterInitStr append (name.num + 1)

      case name: DefaultName => traverse(sb, name.qual) append DefaultGetterStr append (name.num + 1)
    }

  }

  def deepEncode(name: TastyName): TastyName = name match {
    case SimpleName(raw) => SimpleName(NameTransformer.encode(raw))
    case QualifiedName(qual, sep, selector) => QualifiedName(deepEncode(qual), sep, deepEncode(selector).asSimpleName)
    case ObjectName(base) => ObjectName(deepEncode(base))
    case UniqueName(qual, sep, num) => UniqueName(deepEncode(qual), sep, num)
    case DefaultName(qual, num) => DefaultName(deepEncode(qual), num)
    case PrefixName(prefix, qual) => PrefixName(prefix, deepEncode(qual))
    case SuffixName(qual, suffix) => SuffixName(deepEncode(qual), suffix)
    case TypeName(base) => TypeName(deepEncode(base))
    case SignedName(qual, sig, target) => SignedName(deepEncode(qual), sig.map(_.encode), target)
  }

}

/**This is a data structure representing semantic names. `TastyName` is the interface that TASTy uses to select
 * members from a type, providing more information than simple strings, such as selecting types over terms,
 * companion module instead of a class, or signals if a term is a default getter.
 * Names can also be a `SignedName`, which is used to select an overloaded method, and pairs a name with a
 * `MethodSignature` with types are represented by `ErasedTypeRef`.
 */
sealed abstract class TastyName extends Product with Serializable { self =>
  import TastyName._

  final override def toString: String = source

  final def isObjectName: Boolean = self.isInstanceOf[ObjectName]
  final def isDefaultName: Boolean = self.isInstanceOf[DefaultName]
  final def isTypeName: Boolean = self.isInstanceOf[TypeName]
  final def isTermName: Boolean = !isTypeName
  final def isEmpty: Boolean = toTermName == Empty
  final def isConstructorName = self == TastyName.Constructor || self == TastyName.MixinConstructor

  final def asSimpleName: SimpleName = self match {
    case self: SimpleName => self
    case _                => throw new AssertionError(s"not simplename: ${self.debug}")
  }

  /** The name as as expected by the Scala Reflect SymbolTable
   */
  final def encoded: String = ScalaNameEncoder.encode(self)

  /** The name as represented in source code
   */
  final def source: String = SourceEncoder.encode(self)

  /** Debug information about the structure of the name.
   */
  final def debug: String = DebugEncoder.encode(self)

  final def toTermName: TastyName = self match {
    case TypeName(name) => name
    case name           => name
  }

  final def toTypeName: TypeName = TypeName(self)

  final def stripSignedPart: TastyName = self match {
    case SignedName(pre, _, _) => pre
    case name                  => name
  }

  final def isSignedConstructor = self match {
    case SignedName(TastyName.Constructor, sig, _) if isMethodSignature(sig) => true
    case _                                                                   => false
  }

  /** Guard against API change to SignedName */
  @inline private final def isMethodSignature(sig: Signature.MethodSignature[ErasedTypeRef]): true = true

}




© 2015 - 2025 Weber Informatics LLC | Privacy Policy