
scala.tools.selectivecps.CPSUtils.scala Maven / Gradle / Ivy
Go to download
Show more of this group Show more artifacts with this name
Show all versions of continuations Show documentation
Show all versions of continuations Show documentation
Delimited continuations compilation for Scala
// $Id$
package scala.tools.selectivecps
import scala.tools.nsc.Global
import scala.tools.nsc.ast.TreeGen
import scala.tools.nsc.symtab.Flags._
trait CPSUtils {
val global: Global
import global._
import definitions._
var cpsEnabled = false
val verbose: Boolean = System.getProperty("cpsVerbose", "false") == "true"
def vprintln(x: =>Any): Unit = if (verbose) println(x)
object cpsNames {
val catches = newTermName("$catches")
val ex = newTermName("$ex")
val flatMapCatch = newTermName("flatMapCatch")
val getTrivialValue = newTermName("getTrivialValue")
val isTrivial = newTermName("isTrivial")
val reify = newTermName("reify")
val reifyR = newTermName("reifyR")
val shift = newTermName("shift")
val shiftR = newTermName("shiftR")
val shiftSuffix = newTermName("$shift")
val shiftUnit0 = newTermName("shiftUnit0")
val shiftUnit = newTermName("shiftUnit")
val shiftUnitR = newTermName("shiftUnitR")
}
lazy val MarkerCPSSym = definitions.getClass("scala.util.continuations.cpsSym")
lazy val MarkerCPSTypes = definitions.getClass("scala.util.continuations.cpsParam")
lazy val MarkerCPSSynth = definitions.getClass("scala.util.continuations.cpsSynth")
lazy val MarkerCPSAdaptPlus = definitions.getClass("scala.util.continuations.cpsPlus")
lazy val MarkerCPSAdaptMinus = definitions.getClass("scala.util.continuations.cpsMinus")
lazy val Context = definitions.getClass("scala.util.continuations.ControlContext")
lazy val ModCPS = definitions.getModule("scala.util.continuations")
lazy val MethShiftUnit = definitions.getMember(ModCPS, cpsNames.shiftUnit)
lazy val MethShiftUnit0 = definitions.getMember(ModCPS, cpsNames.shiftUnit0)
lazy val MethShiftUnitR = definitions.getMember(ModCPS, cpsNames.shiftUnitR)
lazy val MethShift = definitions.getMember(ModCPS, cpsNames.shift)
lazy val MethShiftR = definitions.getMember(ModCPS, cpsNames.shiftR)
lazy val MethReify = definitions.getMember(ModCPS, cpsNames.reify)
lazy val MethReifyR = definitions.getMember(ModCPS, cpsNames.reifyR)
lazy val allCPSAnnotations = List(MarkerCPSSym, MarkerCPSTypes, MarkerCPSSynth,
MarkerCPSAdaptPlus, MarkerCPSAdaptMinus)
def debuglog(s: => String): Unit = {
//Console.err.println(s)
}
class TypeOps(tpe: Type) {
def getAnnotation(cls: Symbol): Option[AnnotationInfo] = tpe.annotations find (matches(_, cls))
}
implicit def toTypeOps(tpe: Type) = new TypeOps(tpe)
class SymbolOps(val sym: Symbol) {
/** Modifies this symbol's info in place. */
def modifyInfo(f: Type => Type): sym.type = sym.setInfo(f(sym.info))
}
implicit def toSymbolOps(sym: Symbol) = new SymbolOps(sym)
class TreeOps(tree: Tree) {
/** Sets the tree's type to the result of the given function.
* If the type is null, it remains null - the function is not called.
*/
def modifyType(f: Type => Type): Tree =
if (tree.tpe eq null) tree
else tree setType f(tree.tpe)
}
implicit def toTreeOps(from: Tree) = new TreeOps(from)
class AnnotationInfoOps {
def marker(atp: Type): AnnotationInfo = new CompleteAnnotationInfo(atp, Nil, Nil)
}
implicit def toAnnotationInfoOps(annObj: AnnotationInfo.type) = new AnnotationInfoOps
class TreeGenOps {
def hasSynthCaseSymbol(t: Tree) = (t.symbol ne null) && (t.symbol hasFlag (CASE | SYNTHETIC))
}
implicit def toTreeGenOps(gen: TreeGen) = new TreeGenOps
class CompleteAnnotationInfo(
override val atp: Type,
override val args: List[Tree],
override val assocs: List[(Name, ClassfileAnnotArg)]
) extends AnnotationInfo(atp, args, assocs) {
// Classfile annot: args empty. Scala annot: assocs empty.
assert(args.isEmpty || assocs.isEmpty, atp)
// necessary for reification, see Reifiers.scala for more info
private var orig: Tree = EmptyTree
def original = orig
def setOriginal(t: Tree): this.type = {
orig = t
this setPos t.pos
this
}
override def toString = (
atp +
(if (!args.isEmpty) args.mkString("(", ", ", ")") else "") +
(if (!assocs.isEmpty) (assocs map { case (x, y) => x+" = "+y } mkString ("(", ", ", ")")) else "")
)
}
// TODO - needed? Can these all use the same annotation info?
protected def newSynthMarker() = newMarker(MarkerCPSSynth)
protected def newPlusMarker() = newMarker(MarkerCPSAdaptPlus)
protected def newMinusMarker() = newMarker(MarkerCPSAdaptMinus)
protected def newMarker(tpe: Type): AnnotationInfo = AnnotationInfo marker tpe
protected def newMarker(sym: Symbol): AnnotationInfo = AnnotationInfo marker sym.tpe
protected def newCpsParamsMarker(tp1: Type, tp2: Type) =
newMarker(appliedType(MarkerCPSTypes.tpe, List(tp1, tp2)))
// annotation checker
protected def annTypes(ann: AnnotationInfo): (Type, Type) = {
val tp0 :: tp1 :: Nil = ann.atp.normalize.typeArgs
((tp0, tp1))
}
protected def hasMinusMarker(tpe: Type) = tpe hasAnnotation MarkerCPSAdaptMinus
protected def hasPlusMarker(tpe: Type) = tpe hasAnnotation MarkerCPSAdaptPlus
protected def hasSynthMarker(tpe: Type) = tpe hasAnnotation MarkerCPSSynth
protected def hasCpsParamTypes(tpe: Type) = tpe hasAnnotation MarkerCPSTypes
protected def cpsParamTypes(tpe: Type) = tpe getAnnotation MarkerCPSTypes map annTypes
// Test whether the typeSymbol of atp conforms to the given class.
def matches(annotationInfo: AnnotationInfo, clazz: Symbol) = annotationInfo.atp.typeSymbol isNonBottomSubClass clazz
def filterAnnotations(tpe: Type, p: AnnotationInfo => Boolean): Type = tpe match {
case atp @ AnnotatedType(annotations, underlying, selfsym) =>
val (yes, no) = annotations partition p
if (yes.isEmpty) underlying
else if (no.isEmpty) tpe
else atp.copy(annotations = yes)
case _ => tpe
}
def filterAttribs(tpe:Type, cls:Symbol) =
tpe.annotations filter (matches(_, cls))
def removeAttribs(tpe: Type, classes: Symbol*) =
filterAnnotations(tpe, (ann => !(classes exists (matches(ann, _)))))
def removeAllCPSAnnotations(tpe: Type) = removeAttribs(tpe, allCPSAnnotations:_*)
def cpsParamAnnotation(tpe: Type) = filterAttribs(tpe, MarkerCPSTypes)
def linearize(ann: List[AnnotationInfo]): AnnotationInfo = {
ann reduceLeft { (a, b) =>
val (u0,v0) = annTypes(a)
val (u1,v1) = annTypes(b)
// vprintln("check lin " + a + " andThen " + b)
if (v1 <:< u0)
newCpsParamsMarker(u1, v0)
else
throw new TypeError("illegal answer type modification: " + a + " andThen " + b)
}
}
// anf transform
def getExternalAnswerTypeAnn(tp: Type) = {
cpsParamTypes(tp) orElse {
if (hasPlusMarker(tp))
global.warning("trying to instantiate type " + tp + " to unknown cps type")
None
}
}
def getAnswerTypeAnn(tp: Type): Option[(Type, Type)] =
cpsParamTypes(tp) filterNot (_ => hasPlusMarker(tp))
def hasAnswerTypeAnn(tp: Type) =
hasCpsParamTypes(tp) && !hasPlusMarker(tp)
def updateSynthFlag(tree: Tree) = { // remove annotations if *we* added them (@synth present)
if (hasSynthMarker(tree.tpe)) {
log("removing annotation from " + tree)
tree modifyType removeAllCPSAnnotations
} else
tree
}
type CPSInfo = Option[(Type,Type)]
def linearize(a: CPSInfo, b: CPSInfo)(implicit unit: CompilationUnit, pos: Position): CPSInfo = {
(a,b) match {
case (Some((u0,v0)), Some((u1,v1))) =>
vprintln("check lin " + a + " andThen " + b)
if (!(v1 <:< u0)) {
unit.error(pos,"cannot change answer type in composition of cps expressions " +
"from " + u1 + " to " + v0 + " because " + v1 + " is not a subtype of " + u0 + ".")
throw new Exception("check lin " + a + " andThen " + b)
}
Some((u1,v0))
case (Some(_), _) => a
case (_, Some(_)) => b
case _ => None
}
}
}
© 2015 - 2025 Weber Informatics LLC | Privacy Policy