diff options
author | Paul Phillips <paulp@improving.org> | 2012-04-09 14:23:13 -0700 |
---|---|---|
committer | Paul Phillips <paulp@improving.org> | 2012-04-09 19:43:38 -0700 |
commit | bed400c5a8d4fc5f5ee4b270f757cdfae94c3f6a (patch) | |
tree | 8b0beea7121a276793220c735366089902f88854 /src/compiler/scala/tools/nsc/interpreter/IMain.scala | |
parent | c456bebbcddae490a2ab2860855e936adb60539e (diff) | |
download | scala-bed400c5a8d4fc5f5ee4b270f757cdfae94c3f6a.tar.gz scala-bed400c5a8d4fc5f5ee4b270f757cdfae94c3f6a.tar.bz2 scala-bed400c5a8d4fc5f5ee4b270f757cdfae94c3f6a.zip |
Cleaning up some repl mechanisms.
Diffstat (limited to 'src/compiler/scala/tools/nsc/interpreter/IMain.scala')
-rw-r--r-- | src/compiler/scala/tools/nsc/interpreter/IMain.scala | 94 |
1 files changed, 66 insertions, 28 deletions
diff --git a/src/compiler/scala/tools/nsc/interpreter/IMain.scala b/src/compiler/scala/tools/nsc/interpreter/IMain.scala index 9a12bc1471..0c64bb2901 100644 --- a/src/compiler/scala/tools/nsc/interpreter/IMain.scala +++ b/src/compiler/scala/tools/nsc/interpreter/IMain.scala @@ -93,6 +93,11 @@ class IMain(initialSettings: Settings, protected val out: JPrintWriter) extends private var _lineManager: Line.Manager = null // logic for individual lines private val _compiler: Global = newCompiler(settings, reporter) // our private compiler + private val nextReqId = { + var counter = 0 + () => { counter += 1 ; counter } + } + def compilerClasspath: Seq[URL] = ( if (isInitializeComplete) global.classPath.asURLs else new PathResolver(settings).result.asURLs // the compiler's classpath @@ -457,7 +462,10 @@ class IMain(initialSettings: Settings, protected val out: JPrintWriter) extends /** Build a request from the user. `trees` is `line` after being parsed. */ - private def buildRequest(line: String, trees: List[Tree]): Request = new Request(line, trees) + private def buildRequest(line: String, trees: List[Tree]): Request = { + executingRequest = new Request(line, trees) + executingRequest + } // rewriting "5 // foo" to "val x = { 5 // foo }" creates broken code because // the close brace is commented out. Strip single-line comments. @@ -556,17 +564,10 @@ class IMain(initialSettings: Settings, protected val out: JPrintWriter) extends Right(buildRequest(line, trees)) } - def typeCleanser(sym: Symbol, memberName: Name): Type = { - // the types are all =>T; remove the => - val tp1 = afterTyper(sym.info.nonPrivateDecl(memberName).tpe match { - case NullaryMethodType(tp) => tp - case tp => tp - }) - // normalize non-public types so we don't see protected aliases like Self - afterTyper(tp1 match { - case TypeRef(_, sym, _) if !sym.isPublic => tp1.normalize - case tp => tp - }) + // normalize non-public types so we don't see protected aliases like Self + def normalizeNonPublic(tp: Type) = tp match { + case TypeRef(_, sym, _) if sym.isAliasType && !sym.isPublic => tp.normalize + case _ => tp } /** @@ -623,7 +624,7 @@ class IMain(initialSettings: Settings, protected val out: JPrintWriter) extends * @param value the object value to bind to it * @return an indication of whether the binding succeeded */ - def bind(name: String, boundType: String, value: Any): IR.Result = { + def bind(name: String, boundType: String, value: Any, modifiers: List[String] = Nil): IR.Result = { val bindRep = new ReadEvalPrint() val run = bindRep.compile(""" |object %s { @@ -639,7 +640,7 @@ class IMain(initialSettings: Settings, protected val out: JPrintWriter) extends IR.Error case Right(_) => - val line = "val %s = %s.value".format(name, bindRep.evalPath) + val line = "%sval %s = %s.value".format(modifiers map (_ + " ") mkString, name, bindRep.evalPath) repldbg("Interpreting: " + line) interpret(line) } @@ -824,7 +825,7 @@ class IMain(initialSettings: Settings, protected val out: JPrintWriter) extends case xs => sys.error("Internal error: eval object " + evalClass + ", " + xs.mkString("\n", "\n", "")) } private def compileAndSaveRun(label: String, code: String) = { - showCodeIfDebugging(packaged(code)) + showCodeIfDebugging(code) val (success, run) = compileSourcesKeepingRun(new BatchSourceFile(label, packaged(code))) lastRun = run success @@ -834,6 +835,7 @@ class IMain(initialSettings: Settings, protected val out: JPrintWriter) extends /** One line of code submitted by the user for interpretation */ // private class Request(val line: String, val trees: List[Tree]) { + val reqId = nextReqId() val lineRep = new ReadEvalPrint() private var _originalLine: String = null @@ -882,14 +884,31 @@ class IMain(initialSettings: Settings, protected val out: JPrintWriter) extends /** generate the source code for the object that computes this request */ private object ObjectSourceCode extends CodeAssembler[MemberHandler] { + def path = pathToTerm("$intp") + def envLines = { + if (!isReplPower) Nil // power mode only for now + // $intp is not bound; punt, but include the line. + else if (path == "$intp") List( + "def $line = " + tquoted(originalLine), + "def $trees = Nil" + ) + else List( + "def $line = " + tquoted(originalLine), + "def $req = %s.requestForReqId(%s).orNull".format(path, reqId), + "def $trees = if ($req eq null) Nil else $req.trees".format(lineRep.readName, path, reqId) + ) + } + val preamble = """ |object %s { - |%s%s - """.stripMargin.format(lineRep.readName, importsPreamble, indentCode(toCompute)) + |%s%s%s + """.stripMargin.format(lineRep.readName, envLines.map(" " + _ + ";\n").mkString, importsPreamble, indentCode(toCompute)) val postamble = importsTrailer + "\n}" val generate = (m: MemberHandler) => m extraCodeToEvaluate Request.this } + def tquoted(s: String) = "\"\"\"" + s + "\"\"\"" + private object ResultObjectSourceCode extends CodeAssembler[MemberHandler] { /** We only want to generate this code when the result * is a value which can be referred to as-is. @@ -959,8 +978,9 @@ class IMain(initialSettings: Settings, protected val out: JPrintWriter) extends def lookupTypeOf(name: Name) = typeOf.getOrElse(name, typeOf(global.encode(name.toString))) def simpleNameOfType(name: TypeName) = (compilerTypeOf get name) map (_.typeSymbol.simpleName) - private def typeMap[T](f: Type => T): Map[Name, T] = - termNames ++ typeNames map (x => x -> f(typeCleanser(resultSymbol, x))) toMap + private def typeMap[T](f: Type => T): Map[Name, T] = { + termNames ++ typeNames map (x => x -> f(cleanMemberDecl(resultSymbol, x))) toMap + } /** Types of variables defined by this request. */ lazy val compilerTypeOf = typeMap[Type](x => x) @@ -1023,6 +1043,13 @@ class IMain(initialSettings: Settings, protected val out: JPrintWriter) extends getOrElse Nil ) + def treesForRequestId(id: Int): List[Tree] = + requestForReqId(id).toList flatMap (_.trees) + + def requestForReqId(id: Int): Option[Request] = + if (executingRequest != null && executingRequest.reqId == id) Some(executingRequest) + else prevRequests find (_.reqId == id) + def requestForName(name: Name): Option[Request] = { assert(definedNameMap != null, "definedNameMap is null") definedNameMap get name @@ -1072,6 +1099,14 @@ class IMain(initialSettings: Settings, protected val out: JPrintWriter) extends else NoType } } + def cleanMemberDecl(owner: Symbol, member: Name): Type = afterTyper { + normalizeNonPublic { + owner.info.nonPrivateDecl(member).tpe match { + case NullaryMethodType(tp) => tp + case tp => tp + } + } + } object replTokens extends { val global: imain.global.type = imain.global @@ -1118,15 +1153,18 @@ class IMain(initialSettings: Settings, protected val out: JPrintWriter) extends def apply[T: ClassManifest] : Symbol = apply(classManifest[T].erasure.getName) /** the previous requests this interpreter has processed */ - private lazy val prevRequests = mutable.ListBuffer[Request]() - private lazy val referencedNameMap = mutable.Map[Name, Request]() - private lazy val definedNameMap = mutable.Map[Name, Request]() - private lazy val directlyBoundNames = mutable.Set[Name]() - protected def prevRequestList = prevRequests.toList - private def allHandlers = prevRequestList flatMap (_.handlers) - def allSeenTypes = prevRequestList flatMap (_.typeOf.values.toList) distinct - def allImplicits = allHandlers filter (_.definesImplicit) flatMap (_.definedNames) - def importHandlers = allHandlers collect { case x: ImportHandler => x } + private var executingRequest: Request = _ + private val prevRequests = mutable.ListBuffer[Request]() + private val referencedNameMap = mutable.Map[Name, Request]() + private val definedNameMap = mutable.Map[Name, Request]() + private val directlyBoundNames = mutable.Set[Name]() + + private def allHandlers = prevRequestList flatMap (_.handlers) + def lastRequest = if (prevRequests.isEmpty) null else prevRequests.last + def prevRequestList = prevRequests.toList + def allSeenTypes = prevRequestList flatMap (_.typeOf.values.toList) distinct + def allImplicits = allHandlers filter (_.definesImplicit) flatMap (_.definedNames) + def importHandlers = allHandlers collect { case x: ImportHandler => x } def visibleTermNames: List[Name] = definedTerms ++ importedTerms distinct |