aboutsummaryrefslogblamecommitdiff
path: root/compiler/src/dotty/tools/dotc/core/NameExtractors.scala
blob: 1439ce002a2e4382c2ddcac0f79d6d0fc7b0b2f2 (plain) (tree)
1
2
3
4
5
6
7
8
9

                   





                    
                          
                   
                       
                         


                       


                                                                                                 
 
                                            
                                



                                                                 
                                                                       

                                                   
                          


                                                                          









                                                                                










                                                                                                       
                                

   

                                                                                                         
                                                        
                                                                     

   

                                                                                                         






                                                                                      

                                                               










                                                                                             


                                      

                                                        


                                            


                           
                                                                                         
                                                        
                                          





                      
                                

   
                                                                                                             









                                                                                               

   






















                                                                                      

   
































                                                                                                   
 
                                                                                          





                                                                                            
                                                                        






                                                             




                                                                                                



















                                                                                        


                                                                                                         
 
package dotty.tools
package dotc
package core

import Names._
import NameOps._
import StdNames._
import util.DotClass
import tasty.TastyFormat._
import Decorators._
import Contexts.Context
import collection.mutable

object NameExtractors {

  @sharable private val simpleExtractors = new mutable.HashMap[Int, ClassifiedNameExtractor]
  @sharable private val uniqueExtractors = new mutable.HashMap[String, UniqueNameExtractor]
  @sharable private val qualifiedExtractors = new mutable.HashMap[String, QualifiedNameExtractor]

  abstract class NameInfo extends DotClass {
    def extractor: NameExtractor
    def mkString(underlying: TermName): String
    def map(f: SimpleTermName => SimpleTermName): NameInfo = this
  }

  abstract class NameExtractor(val tag: Int) extends DotClass { self =>
    type ThisInfo <: Info
    class Info extends NameInfo { this: ThisInfo =>
      def extractor = self
      def mkString(underlying: TermName) = self.mkString(underlying, this)
      override def toString = infoString
    }
    def definesNewName = false
    def mkString(underlying: TermName, info: ThisInfo): String
    def infoString: String
  }

  object SimpleTermNameExtractor extends NameExtractor(UTF8) { self =>
    type ThisInfo = Info
    val info = new Info
    def mkString(underlying: TermName, info: ThisInfo) = unsupported("mkString")
    def infoString = unsupported("infoString")
  }

  abstract class ClassifiedNameExtractor(tag: Int, val infoString: String) extends NameExtractor(tag) {
    type ThisInfo = Info
    val info = new Info
    def apply(qual: TermName) =
      qual.derived(info)
    def unapply(name: DerivedTermName): Option[TermName] =  name match {
      case DerivedTermName(underlying, `info`) => Some(underlying)
      case _ => None
    }
    simpleExtractors(tag) = this
  }

  class PrefixNameExtractor(tag: Int, prefix: String, optInfoString: String = "")
  extends ClassifiedNameExtractor(tag, if (optInfoString.isEmpty) s"Prefix $prefix" else optInfoString) {
    def mkString(underlying: TermName, info: ThisInfo) =
      underlying.mapLast(n => termName(prefix + n.toString)).toString
  }

  class SuffixNameExtractor(tag: Int, suffix: String, optInfoString: String = "")
  extends ClassifiedNameExtractor(tag, if (optInfoString.isEmpty) s"Suffix $suffix" else optInfoString) {
    def mkString(underlying: TermName, info: ThisInfo) = underlying.toString ++ suffix
  }

  trait QualifiedInfo extends NameInfo {
    val name: SimpleTermName
  }

  class QualifiedNameExtractor(tag: Int, val separator: String)
  extends NameExtractor(tag) {
    type ThisInfo = QualInfo
    case class QualInfo(val name: SimpleTermName) extends Info with QualifiedInfo {
      override def map(f: SimpleTermName => SimpleTermName): NameInfo = new QualInfo(f(name))
      override def toString = s"$infoString $name"
    }
    def apply(qual: TermName, name: SimpleTermName) =
      qual.derived(new QualInfo(name))
    def unapply(name: DerivedTermName): Option[(TermName, SimpleTermName)] = name match {
      case DerivedTermName(qual, info: this.QualInfo) => Some((qual, info.name))
      case _ => None
    }

    override def definesNewName = true

    def mkString(underlying: TermName, info: ThisInfo) =
      s"$underlying$separator${info.name}"
    def infoString = s"Qualified $separator"

    qualifiedExtractors(separator) = this
  }

  object AnyQualifiedName {
    def unapply(name: DerivedTermName): Option[(TermName, SimpleTermName)] = name match {
      case DerivedTermName(qual, info: QualifiedInfo) =>
        Some((name.underlying, info.name))
      case _ => None
    }
  }

  trait NumberedInfo {
    def num: Int
    def extractor: NameExtractor
  }

  abstract class NumberedNameExtractor(tag: Int, val infoString: String) extends NameExtractor(tag) { self =>
    type ThisInfo = NumberedInfo
    case class NumberedInfo(val num: Int) extends Info with NameExtractors.NumberedInfo {
      override def toString = s"$infoString $num"
    }
    def apply(qual: TermName, num: Int) =
      qual.derived(new NumberedInfo(num))
    def unapply(name: DerivedTermName): Option[(TermName, Int)] = name match {
      case DerivedTermName(underlying, info: this.NumberedInfo) => Some((underlying, info.num))
      case _ => None
    }
  }

  case class UniqueNameExtractor(val separator: String)
  extends NumberedNameExtractor(UNIQUE, s"Unique $separator") {
    override def definesNewName = true
    def mkString(underlying: TermName, info: ThisInfo) = {
      val safePrefix = str.sanitize(underlying.toString + separator)
      safePrefix + info.num
    }

    def fresh(prefix: TermName = EmptyTermName)(implicit ctx: Context): TermName =
      ctx.freshNames.newName(prefix, this)

    uniqueExtractors(separator) = this
  }

  object AnyUniqueName {
    def unapply(name: DerivedTermName): Option[(TermName, String, Int)] = name match {
      case DerivedTermName(qual, info: NumberedInfo) =>
        info.extractor match {
          case unique: UniqueNameExtractor => Some((qual, unique.separator, info.num))
          case _ => None
        }
      case _ => None
    }
  }

  val QualifiedName           = new QualifiedNameExtractor(QUALIFIED, ".")
  val FlattenedName           = new QualifiedNameExtractor(FLATTENED, "$")
  val ExpandedName            = new QualifiedNameExtractor(EXPANDED, str.EXPAND_SEPARATOR)
  val TraitSetterName         = new QualifiedNameExtractor(TRAITSETTER, str.TRAIT_SETTER_SEPARATOR)

  val UniqueName = new UniqueNameExtractor("$") {
    override def mkString(underlying: TermName, info: ThisInfo) =
      if (underlying.isEmpty) "$" + info.num + "$" else super.mkString(underlying, info)
  }

  val InlineAccessorName      = new UniqueNameExtractor("$_inlineAccessor_$")
  val TempResultName          = new UniqueNameExtractor("ev$")
  val EvidenceParamName       = new UniqueNameExtractor("evidence$")
  val DepParamName            = new UniqueNameExtractor("<param>")
  val LazyImplicitName        = new UniqueNameExtractor("$_lazy_implicit_$")
  val LazyLocalName           = new UniqueNameExtractor("$lzy")
  val LazyLocalInitName       = new UniqueNameExtractor("$lzyINIT")
  val LazyFieldOffsetName     = new UniqueNameExtractor("$OFFSET")
  val LazyBitMapName          = new UniqueNameExtractor(nme.BITMAP_PREFIX.toString)
  val NonLocalReturnKeyName   = new UniqueNameExtractor("nonLocalReturnKey")
  val WildcardParamName       = new UniqueNameExtractor("_$")
  val TailLabelName           = new UniqueNameExtractor("tailLabel")
  val ExceptionBinderName     = new UniqueNameExtractor("ex")
  val SkolemName              = new UniqueNameExtractor("?")
  val LiftedTreeName          = new UniqueNameExtractor("liftedTree")

  val PatMatStdBinderName     = new UniqueNameExtractor("x")
  val PatMatPiName            = new UniqueNameExtractor("pi") // FIXME: explain what this is
  val PatMatPName             = new UniqueNameExtractor("p")  // FIXME: explain what this is
  val PatMatOName             = new UniqueNameExtractor("o")  // FIXME: explain what this is
  val PatMatCaseName          = new UniqueNameExtractor("case")
  val PatMatMatchFailName     = new UniqueNameExtractor("matchFail")
  val PatMatSelectorName      = new UniqueNameExtractor("selector")

  object DefaultGetterName extends NumberedNameExtractor(DEFAULTGETTER, "DefaultGetter") {
    def mkString(underlying: TermName, info: ThisInfo) = {
      val prefix = if (underlying.isConstructorName) nme.DEFAULT_GETTER_INIT else underlying
      prefix.toString + nme.DEFAULT_GETTER + (info.num + 1)
    }
  }

  object VariantName extends NumberedNameExtractor(VARIANT, "Variant") {
    val varianceToPrefix = Map(-1 -> '-', 0 -> '=', 1 -> '+')
    val prefixToVariance = Map('-' -> -1, '=' -> 0, '+' -> 1)
    def mkString(underlying: TermName, info: ThisInfo) = {
      varianceToPrefix(info.num).toString + underlying
    }
  }

  val SuperAccessorName = new PrefixNameExtractor(SUPERACCESSOR, "super$")
  val InitializerName = new PrefixNameExtractor(INITIALIZER, "initial$")
  val ShadowedName = new PrefixNameExtractor(SHADOWED, "(shadowed)")
  val AvoidClashName = new SuffixNameExtractor(AVOIDCLASH, "$_avoid_name_clash_$")
  val ModuleClassName = new SuffixNameExtractor(OBJECTCLASS, "$", optInfoString = "ModuleClass")

  object SignedName extends NameExtractor(63) {

    /** @param parts  resultSig followed by paramsSig */
    case class SignedInfo(sig: Signature) extends Info {
      override def toString = s"$infoString $sig"
    }
    type ThisInfo = SignedInfo

    def apply(qual: TermName, sig: Signature) =
      qual.derived(new SignedInfo(sig))
    def unapply(name: DerivedTermName): Option[(TermName, Signature)] = name match {
      case DerivedTermName(underlying, info: SignedInfo) => Some((underlying, info.sig))
      case _ => None
    }

    def mkString(underlying: TermName, info: ThisInfo): String = unsupported("mkString")
    def infoString: String = "Signed"
  }

  def simpleExtractorOfTag         : collection.Map[Int, ClassifiedNameExtractor]   = simpleExtractors
  def qualifiedExtractorOfSeparator: collection.Map[String, QualifiedNameExtractor] = qualifiedExtractors
  def uniqueExtractorOfSeparator   : collection.Map[String, UniqueNameExtractor]    = uniqueExtractors
}