Many resources are needed to download a project. Please understand that we have to compensate our server costs. Thank you in advance. Project price only 1 $
You can buy this project and download/modify it how often you want.
/*
* Scala (https://www.scala-lang.org)
*
* Copyright EPFL and Lightbend, Inc.
*
* 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.
*/
// Copyright 2005-2017 LAMP/EPFL and Lightbend, Inc.
package scala.tools.nsc.interpreter
import java.io.{Closeable, PrintWriter, StringWriter}
import java.net.URL
import scala.collection.mutable, mutable.ListBuffer
import scala.language.implicitConversions
import scala.reflect.{ClassTag, classTag}
import scala.reflect.internal.util.ScalaClassLoader.URLClassLoader
import scala.reflect.internal.util.{AbstractFileClassLoader, BatchSourceFile, ListOfNil, Position, ReplBatchSourceFile, SourceFile}
import scala.reflect.internal.{FatalError, Flags, MissingRequirementError, NoPhase}
import scala.reflect.runtime.{universe => ru}
import scala.tools.nsc.{Global, Settings}
import scala.tools.nsc.interpreter.Results.{Error, Incomplete, Result, Success}
import scala.tools.nsc.interpreter.StdReplTags.tagOfStdReplVals
import scala.tools.nsc.io.AbstractFile
import scala.tools.nsc.reporters.StoreReporter
import scala.tools.nsc.typechecker.{StructuredTypeStrings, TypeStrings}
import scala.tools.nsc.util.Exceptional.rootCause
import scala.tools.nsc.util.{stackTraceString, stringFromWriter}
import scala.tools.util.PathResolver
import scala.util.{Try => Trying}
import scala.util.chaining._
import scala.util.control.NonFatal
/** An interpreter for Scala code.
*
* The main public entry points are compile(), interpret(), and bind().
* The compile() method loads a complete Scala file. The interpret() method
* executes one line of Scala code at the request of the user. The bind()
* method binds an object to a variable that can then be used by later
* interpreted code.
*
* The overall approach is based on compiling the requested code and then
* using a Java classloader and Java reflection to run the code
* and access its results.
*
* In more detail, a single compiler instance is used
* to accumulate all successfully compiled or interpreted Scala code. To
* "interpret" a line of code, the compiler generates a fresh object that
* includes the line of code and which has public member(s) to export
* all variables defined by that code. To extract the result of an
* interpreted line to show the user, a second "result object" is created
* which imports the variables exported by the above object and then
* exports members called "\$eval" and "\$print". To accommodate user expressions
* that read from variables or methods defined in previous statements, "import"
* statements are used.
*
* This interpreter shares the strengths and weaknesses of using the
* full compiler-to-Java. The main strength is that interpreted code
* behaves exactly as does compiled code, including running at full speed.
* The main weakness is that redefining classes and methods is not handled
* properly, because rebinding at the Java level is technically difficult.
*/
class IMain(val settings: Settings, parentClassLoaderOverride: Option[ClassLoader], compilerSettings: Settings, val reporter: ReplReporter)
extends Repl with Imports with PresentationCompilation with Closeable {
def this(interpreterSettings: Settings, reporter: ReplReporter) = this(interpreterSettings, None, interpreterSettings, reporter)
import reporter.{debug => repldbg}
private[interpreter] lazy val useMagicImport: Boolean = settings.YreplMagicImport.value
private var bindExceptions = true // whether to bind the lastException variable
private var _executionWrapper = "" // code to be wrapped around all lines
private var label = "" // compilation unit name for reporting
/** We're going to go to some trouble to initialize the compiler asynchronously.
* It's critical that nothing call into it until it's been initialized or we will
* run into unrecoverable issues, but the perceived repl startup time goes
* through the roof if we wait for it. So we initialize it with a future and
* use a lazy val to ensure that any attempt to use the compiler object waits
* on the future.
*/
private var _classLoader: AbstractFileClassLoader = null // active classloader
private var _runtimeMirror: ru.Mirror = null
private var _runtimeClassLoader: URLClassLoader = null // wrapper exposing addURL
def compilerClasspath: Seq[java.net.URL] = (
if (_initializeComplete) global.classPath.asURLs
else new PathResolver(settings, global.closeableRegistry).resultAsURLs // the compiler's classpath
)
// Run the code body with the given boolean settings flipped to true.
def withoutWarnings[T](body: => T): T =
reporter.withoutPrintingResults(IMain.withSuppressedSettings(settings, global)(body))
def withSuppressedSettings(body: => Unit): Unit =
IMain.withSuppressedSettings(settings, global)(body)
// Apply a temporary label for compilation (for example, script name)
override def withLabel[A](temp: String)(body: => A): A = {
val saved = label
label = temp
try body finally label = saved
}
override def visibleSettings: List[Setting] = settings.visibleSettings
override def userSetSettings: List[Setting] = settings.userSetSettings
override def updateSettings(arguments: List[String]): Boolean = {
val (ok, rest) = settings.processArguments(arguments, processAll = false)
ok && rest.isEmpty
}
object replOutput extends ReplOutput(settings.Yreploutdir) { }
override def outputDir = replOutput.dir
// Used in a test case.
def showDirectory: String = {
val writer = new StringWriter()
replOutput.show(new PrintWriter(writer))
writer.toString
}
lazy val isClassBased: Boolean = settings.Yreplclassbased.value
override def initializeComplete = _initializeComplete
private[this] var _initializeComplete = false
// initializes the compiler, returning false if something went wrong
override def initializeCompiler(): Boolean = global != null
lazy val global: Global = {
compilerSettings.outputDirs.setSingleOutput(replOutput.dir)
compilerSettings.exposeEmptyPackage.value = true
// Can't use our own reporter until global is initialized
val startupReporter = new StoreReporter(compilerSettings)
val compiler = new Global(compilerSettings, startupReporter) with ReplGlobal
try {
val run = new compiler.Run()
assert(run.typerPhase != NoPhase, "REPL requires a typer phase.")
IMain.withSuppressedSettings(compilerSettings, compiler) {
run compileSources List(new BatchSourceFile("", "class $repl_$init { }"))
}
// there shouldn't be any errors yet; just in case, print them if we're debugging
if (reporter.isDebug)
startupReporter.infos foreach { Console.err.println }
compiler.reporter = reporter
_initializeComplete = true
compiler
}
catch AbstractOrMissingHandler()
}
import global._
import definitions.{ ObjectClass, termMember, dropNullaryMethod}
override def classPathString = global.classPath.asClassPathString
private def noFatal(body: => Symbol): Symbol = try body catch { case _: FatalError => NoSymbol }
def getClassIfDefined(path: String) = (
noFatal(runtimeMirror staticClass path)
orElse noFatal(rootMirror staticClass path)
)
def getModuleIfDefined(path: String) = (
noFatal(runtimeMirror staticModule path)
orElse noFatal(rootMirror staticModule path)
)
implicit class ReplTypeOps(tp: Type) {
def andAlso(fn: Type => Type): Type = if (tp eq NoType) tp else fn(tp)
}
// TODO: If we try to make naming a lazy val, we run into big time
// scalac unhappiness with what look like cycles. It has not been easy to
// reduce, but name resolution clearly takes different paths.
object naming extends {
val global: IMain.this.global.type = IMain.this.global
} with Naming {
// make sure we don't overwrite their unwisely named res3 etc.
def freshUserTermName(): TermName = {
val name = newTermName(freshUserVarName())
if (replScope containsName name) freshUserTermName()
else name
}
def isInternalTermName(name: Name) = isInternalVarName("" + name)
}
import naming._
import Naming._
object deconstruct extends {
val global: IMain.this.global.type = IMain.this.global
} with StructuredTypeStrings
lazy val memberHandlers = new {
val intp: IMain.this.type = IMain.this
} with MemberHandlers
import memberHandlers._
override def quietRun(code: String): Result = reporter.withoutPrintingResults(interpret(code))
/** takes AnyRef because it may be binding a Throwable or an Exceptional */
private def withLastExceptionLock[T](body: => T, alt: => T): T = {
assert(bindExceptions, "withLastExceptionLock called incorrectly.")
bindExceptions = false
try reporter.withoutPrintingResults(body) catch { case NonFatal(t) =>
repldbg("withLastExceptionLock: " + rootCause(t))
reporter.trace(stackTraceString(rootCause(t)))
alt
} finally bindExceptions = true
}
def executionWrapper = _executionWrapper
def setExecutionWrapper(code: String) = _executionWrapper = code
override def clearExecutionWrapper() = _executionWrapper = ""
/**
* Adds all specified jars to the compile and runtime classpaths.
*
* @note Currently only supports jars, not directories.
* @param urls The list of items to add to the compile and runtime classpaths.
*/
override def addUrlsToClassPath(urls: URL*): Unit = {
new Run // force some initialization
urls.foreach(_runtimeClassLoader.addURL) // Add jars to runtime classloader
global.extendCompilerClassPath(urls: _*) // Add jars to compile-time classpath
}
protected def replClass: Class[_] = this.getClass
/** Parent classloader. Overridable. */
protected def parentClassLoader: ClassLoader = {
// might be null if we're on the boot classpath
parentClassLoaderOverride.
orElse(settings.explicitParentLoader).
orElse(Option(replClass.getClassLoader())).
getOrElse(ClassLoader.getSystemClassLoader)
}
/* A single class loader is used for all commands interpreted by this Interpreter.
It would also be possible to create a new class loader for each command
to interpret. The advantages of the current approach are:
- Expressions are only evaluated one time. This is especially
significant for I/O, e.g. "val x = Console.readLine"
The main disadvantage is:
- Objects, classes, and methods cannot be rebound. Instead, definitions
shadow the old ones, and old code objects refer to the old
definitions.
*/
def resetClassLoader() = {
repldbg("Setting new classloader: was " + _classLoader)
_classLoader = null
_runtimeMirror = null
ensureClassLoader()
}
final def ensureClassLoader(): Unit =
if (_classLoader == null)
_classLoader = makeClassLoader()
override def classLoader: AbstractFileClassLoader = {
ensureClassLoader()
_classLoader
}
def runtimeMirror = {
if (_runtimeMirror == null)
_runtimeMirror = ru.runtimeMirror(classLoader)
_runtimeMirror
}
def backticked(s: String): String = (
(s split '.').toList map {
case "_" => "`_`"
case s if nme.keywords(newTermName(s)) => s"`$s`"
case s => s
} mkString "."
)
def readRootPath(readPath: String) = getModuleIfDefined(readPath)
abstract class PhaseDependentOps {
def shift[T](op: => T): T
def path(name: => Name): String = shift(path(symbolOfName(name)))
def path(sym: Symbol): String = backticked(shift(sym.fullName))
def sig(sym: Symbol): String = shift(sym.defString)
}
object typerOp extends PhaseDependentOps {
def shift[T](op: => T): T = exitingTyper(op)
}
object flatOp extends PhaseDependentOps {
def shift[T](op: => T): T = exitingFlatten(op)
}
override def originalPath(name: String): String = originalPath(TermName(name))
def originalPath(name: Name): String = translateOriginalPath(typerOp path name)
def originalPath(sym: Symbol): String = translateOriginalPath(typerOp path sym)
val readInstanceName = ".INSTANCE"
def translateOriginalPath(p: String): String = {
p.replace(sessionNames.read, sessionNames.read + readInstanceName)
}
def flatPath(sym: Symbol): String = {
val sym1 = if (sym.isModule) sym.moduleClass else sym
flatOp shift sym1.javaClassName
}
override def translatePath(path: String): Option[String] = {
val sym = if (path endsWith "$") symbolOfTerm(path.init) else symbolOfIdent(path)
sym.toOption map flatPath
}
/** If path represents a class resource in the default package,
* see if the corresponding symbol has a class file that is a REPL artifact
* residing at a different resource path. Translate X.class to \$line3/\$read\$\$iw\$\$iw\$X.class.
*/
def translateSimpleResource(path: String): Option[String] = {
if (!(path contains '/') && (path endsWith ".class")) {
val name = path stripSuffix ".class"
val sym = if (name endsWith "$") symbolOfTerm(name.init) else symbolOfIdent(name)
def pathOf(s: String) = s"${s.replace('.', '/')}.class"
sym.toOption map (s => pathOf(flatPath(s)))
} else {
None
}
}
override def translateEnclosingClass(n: String): Option[String] = symbolOfTerm(n).enclClass.toOption map flatPath
/** If unable to find a resource foo.class, try taking foo as a symbol in scope
* and use its java class name as a resource to load.
*
* \$intp.classLoader classBytes "Bippy" or \$intp.classLoader getResource "Bippy.class" just work.
*/
private class TranslatingClassLoader(parent: ClassLoader) extends AbstractFileClassLoader(replOutput.dir, parent) {
override protected def findAbstractFile(name: String): AbstractFile = super.findAbstractFile(name) match {
case null if _initializeComplete => translateSimpleResource(name).map(super.findAbstractFile).orNull
case file => file
}
// if the name was mapped by findAbstractFile, supply null name to avoid name check in defineClass
override protected def findClass(name: String): Class[_] = {
val bytes = classBytes(name)
if (bytes.length == 0)
throw new ClassNotFoundException(name)
else
defineClass(/*name=*/null, bytes, 0, bytes.length, protectionDomain)
}
}
private def makeClassLoader(): AbstractFileClassLoader =
new TranslatingClassLoader({
_runtimeClassLoader = new URLClassLoader(compilerClasspath, parentClassLoader)
_runtimeClassLoader
})
def allDefinedNames: List[Name] = exitingTyper(replScope.toList.map(_.name).sorted)
def unqualifiedIds: List[String] = allDefinedNames.map(_.decode).sorted
/** Most recent tree handled which wasn't wholly synthetic. */
private def mostRecentlyHandledTree: Option[Tree] = {
prevRequests.reverseIterator.map(_.handlers.reverseIterator.collectFirst {
case x: MemberDefHandler if x.definesValue && !isInternalTermName(x.name) => x.member
}).find(_.isDefined).flatten
}
private val logScope = scala.sys.props contains "scala.repl.scope"
private def scopelog(msg: String) = if (logScope) Console.err.println(msg)
private def updateReplScope(sym: Symbol, isDefined: Boolean): Unit = {
def log(what: String): Unit = {
val mark = if (sym.isType) "t " else "v "
val name = exitingTyper(sym.nameString)
val info = cleanTypeAfterTyper(sym)
val defn = sym defStringSeenAs info
scopelog(f"[$mark$what%6s] $name%-25s $defn%s")
}
if (ObjectClass isSubClass sym.owner) return
// unlink previous
replScope lookupAll sym.name foreach { sym =>
log("unlink")
replScope unlink sym
}
val what = if (isDefined) "define" else "import"
log(what)
replScope enter sym
}
def recordRequest(req: Request): Unit = {
if (req == null)
return
prevRequests += req
// warning about serially defining companions. It'd be easy
// enough to just redefine them together but that may not always
// be what people want so I'm waiting until I can do it better.
exitingTyper {
req.defines filterNot (s => req.defines contains s.companionSymbol) foreach { newSym =>
val oldSym = replScope lookup newSym.name.companionName
if (Seq(oldSym, newSym).permutations exists { case Seq(s1, s2) => s1.isClass && s2.isModule case _ => false }) {
replwarn(s"warning: previously defined $oldSym is not a companion to $newSym.")
replwarn("Companions must be defined together; you may wish to use :paste mode for this.")
}
}
}
exitingTyper {
req.imports foreach (sym => updateReplScope(sym, isDefined = false))
req.defines foreach (sym => updateReplScope(sym, isDefined = true))
}
}
private[nsc] def replwarn(msg: => String): Unit = {
if (!settings.nowarnings.value)
reporter.printMessage(msg)
}
def compileSourcesKeepingRun(sources: SourceFile*) = {
val run = new Run()
assert(run.typerPhase != NoPhase, "REPL requires a typer phase.")
run compileSources sources.toList
(!reporter.hasErrors, run)
}
/** Compile an nsc SourceFile. Returns true if there are
* no compilation errors, or false otherwise.
*/
override def compileSources(sources: SourceFile*): Boolean =
compileSourcesKeepingRun(sources: _*)._1
/** Compile a string. Returns true if there are no
* compilation errors, or false otherwise.
*/
override def compileString(code: String): Boolean =
compileSources(new BatchSourceFile("