alvinalexander.com | career | drupal | java | mac | mysql | perl | scala | uml | unix  

Scala example source code file (Changes.scala)

This example Scala source code file (Changes.scala) is included in the DevDaily.com "Java Source Code Warehouse" project. The intent of this project is to help you "Learn Java by Example" TM.

Java - Scala tags/keywords

boolean, boolean, change, change, changed, entity, entity, list, long, private, string, symbol, symbol, type

The Scala Changes.scala source code

package scala.tools.nsc
package dependencies

import symtab.Flags

import collection._

/** A component that describes the possible changes between successive 
 *  compilations of a class.
 */
abstract class Changes {

  /** A compiler instance used to compile files on demand. */
  val compiler: Global

  import compiler._
  import symtab.Flags._

  abstract class Change

  private lazy val annotationsChecked =
      List(definitions.getClass("scala.specialized")) // Any others that should be checked?
      
  private val flagsToCheck = IMPLICIT | FINAL | PRIVATE | PROTECTED | SEALED | 
                             OVERRIDE | CASE | ABSTRACT | DEFERRED | METHOD |
                             MODULE | INTERFACE | PARAM | BYNAMEPARAM | CONTRAVARIANT |
                             DEFAULTPARAM | ACCESSOR | LAZY | SPECIALIZED

  /** Are the new modifiers more restrictive than the old ones? */
  private def moreRestrictive(from: Long, to: Long): Boolean =
    ((((to & PRIVATE) != 0L) && (from & PRIVATE) == 0L)
     || (((to & PROTECTED) != 0L) && (from & PROTECTED) == 0L))
    
  /** Check if flags have changed **/
  private def modifiedFlags(from: Long, to: Long): Boolean =
    (from & IMPLICIT) != (to & IMPLICIT)

  /** An entity in source code, either a class or a member definition.
   *  Name is fully-qualified.
   */
  abstract class Entity
  case class Class(name: String) extends Entity
  case class Definition(name: String) extends Entity
  
  case class Added(e: Entity) extends Change
  case class Removed(e: Entity) extends Change
  case class Changed(e: Entity)(implicit val reason: String) extends Change {
    override def toString = "Changed(" + e + ")[" + reason + "]"
  }
  case class ParentChanged(e: Entity) extends Change
  
  private val changedTypeParams = new mutable.HashSet[String]

  private def sameParameterSymbolNames(sym1: Symbol, sym2: Symbol): Boolean =
  	sameSymbol(sym1, sym2, true) || sym2.encodedName.startsWith(sym1.encodedName + "$") // see #3140
  private def sameSymbol(sym1: Symbol, sym2: Symbol, simple: Boolean = false): Boolean =
    if (simple) sym1.encodedName == sym2.encodedName else sym1.fullName == sym2.fullName
  private def sameFlags(sym1: Symbol, sym2: Symbol): Boolean =
    	(sym1.flags & flagsToCheck) == (sym2.flags & flagsToCheck) 
  private def sameAnnotations(sym1: Symbol, sym2: Symbol): Boolean =
    annotationsChecked.forall(a =>
      (sym1.hasAnnotation(a) == sym2.hasAnnotation(a)))

  private def sameType(tp1: Type, tp2: Type)(implicit strict: Boolean) = {
    def typeOf(tp: Type): String = tp.toString + "[" + tp.getClass + "]"
    val res = sameType0(tp1, tp2)
    //if (!res) println("\t different types: " + typeOf(tp1) + " : " + typeOf(tp2))
    res
  }
  
  private def sameType0(tp1: Type, tp2: Type)(implicit strict: Boolean): Boolean = ((tp1, tp2) match {
    /*case (ErrorType, _) => false
    case (WildcardType, _) => false
    case (_, ErrorType) => false
    case (_, WildcardType) => false
    */
    case (NoType, _) => false
    case (NoPrefix, NoPrefix) => true
    case (_, NoType) => false
    case (_, NoPrefix) => false

    case (ThisType(sym1), ThisType(sym2))
      if sameSymbol(sym1, sym2) => true

    case (SingleType(pre1, sym1), SingleType(pre2, sym2))
      if sameType(pre1, pre2) && sameSymbol(sym1, sym2) => true
    case (ConstantType(value1), ConstantType(value2)) =>
      value1 == value2
    case (TypeRef(pre1, sym1, args1), TypeRef(pre2, sym2, args2)) =>
      val testSymbols = 
        if (!sameSymbol(sym1, sym2)) {
          val v = (!strict && sym1.isType && sym2.isType && sameType(sym1.info, sym2.info))
          if (v) changedTypeParams += sym1.fullName
          v
        } else
          !sym1.isTypeParameter || !changedTypeParams.contains(sym1.fullName)

      testSymbols && sameType(pre1, pre2) && 
        (sym1.variance == sym2.variance) &&
        ((tp1.isHigherKinded && tp2.isHigherKinded && tp1.normalize =:= tp2.normalize) || 
           sameTypes(args1, args2))
         // @M! normalize reduces higher-kinded case to PolyType's

    case (RefinedType(parents1, ref1), RefinedType(parents2, ref2)) =>
      def isSubScope(s1: Scope, s2: Scope): Boolean = s2.toList.forall {
        sym2 =>
          var e1 = s1.lookupEntry(sym2.name)
          (e1 ne null) && {
            var isEqual = false
            while (!isEqual && (e1 ne null)) { 
              isEqual = sameType(e1.sym.info, sym2.info)
              e1 = s1.lookupNextEntry(e1)
            }
            isEqual
          }
      }
      sameTypes(parents1, parents2) && isSubScope(ref1, ref2) && isSubScope(ref2, ref1)
    case (mt1 @ MethodType(params1, res1), mt2 @ MethodType(params2, res2)) =>
      // new dependent types: probably fix this, use substSym as done for PolyType
      sameTypes(tp1.paramTypes, tp2.paramTypes) &&
      (tp1.params corresponds tp2.params)((t1, t2) => sameParameterSymbolNames(t1, t2) && sameFlags(t1, t2)) &&
      sameType(res1, res2) &&
      mt1.isImplicit == mt2.isImplicit
    case (PolyType(tparams1, res1), PolyType(tparams2, res2)) =>
      sameTypeParams(tparams1, tparams2) && sameType(res1, res2)
    case (NullaryMethodType(res1), NullaryMethodType(res2)) =>
      sameType(res1, res2)
    case (ExistentialType(tparams1, res1), ExistentialType(tparams2, res2)) =>
      sameTypeParams(tparams1, tparams2)(false) && sameType(res1, res2)(false)
    case (TypeBounds(lo1, hi1), TypeBounds(lo2, hi2)) =>
      sameType(lo1, lo2) && sameType(hi1, hi2)
    case (BoundedWildcardType(bounds), _) =>
      bounds containsType tp2
    case (_, BoundedWildcardType(bounds)) =>
      bounds containsType tp1
    case (AnnotatedType(_,_,_), _) =>
      annotationsConform(tp1, tp2) && annotationsConform(tp2, tp1) &&
      sameType(tp1.withoutAnnotations, tp2.withoutAnnotations)
    case (_, AnnotatedType(_,_,_)) =>
      annotationsConform(tp1, tp2) && annotationsConform(tp2, tp1) &&
      sameType(tp1.withoutAnnotations, tp2.withoutAnnotations)
    case (_: SingletonType, _: SingletonType) =>
      var origin1 = tp1
      while (origin1.underlying.isInstanceOf[SingletonType]) {
        assert(origin1 ne origin1.underlying, origin1)
        origin1 = origin1.underlying
      }
      var origin2 = tp2
      while (origin2.underlying.isInstanceOf[SingletonType]) {
        assert(origin2 ne origin2.underlying, origin2)
        origin2 = origin2.underlying
      }
      ((origin1 ne tp1) || (origin2 ne tp2)) && sameType(origin1, origin2)
    case _ =>
      false
    }) || {
      val tp1n = normalizePlus(tp1)
      val tp2n = normalizePlus(tp2)
      ((tp1n ne tp1) || (tp2n ne tp2)) && sameType(tp1n, tp2n)
    }

  private def sameTypeParams(tparams1: List[Symbol], tparams2: List[Symbol])(implicit strict: Boolean) =
    sameTypes(tparams1 map (_.info), tparams2 map (_.info)) &&
    sameTypes(tparams1 map (_.tpe), tparams2 map (_.tpe)) &&
    (tparams1 corresponds tparams2)((t1, t2) => sameAnnotations(t1, t2))

  private def sameTypes(tps1: List[Type], tps2: List[Type])(implicit strict: Boolean) =
    (tps1 corresponds tps2)(sameType(_, _))

  /** Return the list of changes between 'from' and 'toSym.info'.
   */
  def changeSet(from: Type, toSym: Symbol): List[Change] = {
    implicit val defaultReason = "types"
    implicit val defaultStrictTypeRefTest = true
    
    val to = toSym.info
    changedTypeParams.clear
    def omitSymbols(s: Symbol): Boolean = !s.hasFlag(LOCAL | LIFTED | PRIVATE | SYNTHETIC)
    val cs = new mutable.ListBuffer[Change]

    if ((from.parents zip to.parents) exists { case (t1, t2) => !sameType(t1, t2) })
      cs += Changed(toEntity(toSym))(from.parents.zip(to.parents).toString)
    if (!sameTypeParams(from.typeParams, to.typeParams)(false))
      cs += Changed(toEntity(toSym))(" tparams: " + from.typeParams.zip(to.typeParams))

    // new members not yet visited
    val newMembers = mutable.HashSet[Symbol]()
    newMembers ++= to.decls.iterator filter omitSymbols

    for (o <- from.decls.iterator filter omitSymbols) {
      val n = to.decl(o.name)
      newMembers -= n

      if (o.isClass)
        cs ++= changeSet(o.info, n)
      else if (n == NoSymbol)
        cs += Removed(toEntity(o))
      else {
        val newSym =
            o match {
              case _:TypeSymbol if o.isAliasType =>
                n.suchThat(ov => sameType(ov.info, o.info))
              case _                             =>
                n.suchThat(ov => sameType(ov.tpe, o.tpe))
             }
        if (newSym == NoSymbol || moreRestrictive(o.flags, newSym.flags) || modifiedFlags(o.flags, newSym.flags))
          cs += Changed(toEntity(o))(n + " changed from " + o.tpe + " to " + n.tpe + " flags: " + Flags.flagsToString(o.flags))
        else if (newSym.isGetter && (o.accessed(from).hasFlag(MUTABLE) != newSym.accessed.hasFlag(MUTABLE)))
          // o.owner is already updated to newSym.owner
          // so o.accessed will return the accessed for the new owner
          cs += Changed(toEntity(o))(o.accessed(from) + " changed to " + newSym.accessed)
        else
          newMembers -= newSym
      }
    }: Unit // Give the type explicitly until #2281 is fixed

    cs ++= (newMembers map (Added compose toEntity))
    cs.toList
  }
  def removeChangeSet(sym: Symbol): Change = Removed(toEntity(sym))
  def changeChangeSet(sym: Symbol, msg: String): Change = Changed(toEntity(sym))(msg)
  def parentChangeSet(sym: Symbol): Change = ParentChanged(toEntity(sym))

  private def toEntity(sym: Symbol): Entity =
    if (sym.isClass) Class(sym.fullName)
    else Definition(sym.fullName)
}

Other Scala examples (source code examples)

Here is a short list of links related to this Scala Changes.scala source code file:

... this post is sponsored by my books ...

#1 New Release!

FP Best Seller

 

new blog posts

 

Copyright 1998-2021 Alvin Alexander, alvinalexander.com
All Rights Reserved.

A percentage of advertising revenue from
pages under the /java/jwarehouse URI on this website is
paid back to open source projects.