Skip to content

Commit

Permalink
Make repl output source compatible
Browse files Browse the repository at this point in the history
ValDef repl output is source compatible

Side effecting repl output is source compatible

Method definition repl output is source compatible

Lazy val repl output is source compatible

REPL print remove comments from definitions, print macro as def

also removed `= <method>` from def and `= <lazy>` from lazy val
refactored implementation of withoutImplicit

REPL print restore string2code use for types of valdefs

REPL print, refactor quoted strings

revert partest run/t7455 check for JDK 8

REPL print, add unevaluated comment to lazy val
  • Loading branch information
bishabosha committed Sep 12, 2019
1 parent 64a5a5d commit 11a932b
Show file tree
Hide file tree
Showing 105 changed files with 673 additions and 634 deletions.
29 changes: 29 additions & 0 deletions src/repl/scala/tools/nsc/interpreter/IMain.scala
Expand Up @@ -37,6 +37,7 @@ import scala.tools.nsc.util.{stackTraceString, stringFromWriter}
import scala.tools.nsc.interpreter.Results.{Error, Incomplete, Result, Success}
import scala.tools.nsc.util.Exceptional.rootCause
import scala.util.control.NonFatal
import scala.annotation.tailrec


/** An interpreter for Scala code.
Expand Down Expand Up @@ -710,6 +711,30 @@ class IMain(val settings: Settings, parentClassLoaderOverride: Option[ClassLoade
}
}

@inline private final def tyParens[T](ts: Iterable[T]): String = ts.mkString("[", ", ", "]")
@inline private final def implicitParens[T](ts: Iterable[T]): String = ts.mkString("(implicit ", ", ", ")")
@inline private final def parens[T](ts: Iterable[T]): String = ts.mkString("(", ", ", ")")

private def methodTypeAsDef(tp: Type): String = {

def withoutImplicit(sym: Symbol): Symbol = sym.cloneSymbol(sym.owner, sym.flags & ~Flag.IMPLICIT)

def formatParams(params: List[Symbol]): String = {
if (params.headOption.exists(_.isImplicit)) implicitParens(params.map(withoutImplicit(_).defString))
else parens(params.map(_.defString))
}

@tailrec
def loop(tpe: Type, acc: StringBuilder): StringBuilder = tpe match {
case NullaryMethodType(resultType) => acc ++= s": $resultType"
case PolyType(tyParams, resultType) => loop(resultType, acc ++= tyParens(tyParams.map(_.defString)))
case MethodType(params, resultType) => loop(resultType, acc ++= formatParams(params))
case other => acc ++= s": $other"
}

loop(tp, new StringBuilder).toString
}

/** One line of code submitted by the user for interpretation */
class Request(val line: String, origTrees: List[Tree], firstXmlPos: Position = NoPosition, generousImports: Boolean = false, synthetic: Boolean = false) extends ReplRequest {
def defines = defHandlers flatMap (_.definedSymbols)
Expand Down Expand Up @@ -933,6 +958,10 @@ class IMain(val settings: Settings, parentClassLoaderOverride: Option[ClassLoade
lazy val compilerTypeOf = typeMap[Type](x => x) withDefaultValue NoType
/** String representations of same. */
lazy val typeOf = typeMap[String](tp => exitingTyper(tp.toString))
/** String representations as if a method type. */
private[this] lazy val defTypeOfMap = typeMap[String](tp => exitingTyper(methodTypeAsDef(tp)))

def defTypeOf(name: Name)(implicit show: Name => String): String = show(name) + defTypeOfMap(name)

lazy val definedSymbols = (
termNames.map(x => x -> applyToResultMember(x, x => x)) ++
Expand Down
43 changes: 25 additions & 18 deletions src/repl/scala/tools/nsc/interpreter/MemberHandlers.scala
Expand Up @@ -26,7 +26,7 @@ trait MemberHandlers {
import global._
import naming._

import ReplStrings.{string2codeQuoted, string2code, any2stringOf}
import ReplStrings.{string2codeQuoted, string2code, any2stringOf, quotedString}

private def codegenln(leadingPlus: Boolean, xs: String*): String = codegen(leadingPlus, (xs ++ Array("\n")): _*)
private def codegenln(xs: String*): String = codegenln(true, xs: _*)
Expand Down Expand Up @@ -133,23 +133,32 @@ trait MemberHandlers {
else {
// if this is a lazy val we avoid evaluating it here
val resultString =
if (mods.isLazy) codegenln(false, "<lazy>")
else any2stringOf(path, maxStringElements)
if (mods.isLazy) quotedString(" // unevaluated")
else quotedString(" = ") + " + " + any2stringOf(path, maxStringElements)

val varOrValOrLzy =
if (mods.isMutable) "var"
else if (mods.isLazy) "lazy val"
else "val"

val nameString = {
string2code(prettyName) + (
if (showObjIds) s"""" + f"@$${System.identityHashCode($path)}%8x" + """"
else ""
)
}

val typeString = string2code(req.typeOf(name))

val nameString = string2code(prettyName) + (if (showObjIds) s"""" + f"@$${System.identityHashCode($path)}%8x" + """" else "")
val typeString = string2code(req typeOf name)
s""" + "$nameString: $typeString = " + $resultString"""
s""" + "$varOrValOrLzy $nameString: $typeString" + $resultString"""
}
}
}

class DefHandler(member: DefDef) extends MemberDefHandler(member) {
override def definesValue = flattensToEmpty(member.vparamss) // true if 0-arity
override def resultExtractionCode(req: Request) = {
val nameString = string2code(name)
val typeString = string2code(req typeOf name)
if (mods.isPublic) s""" + "$nameString: $typeString\\n"""" else ""
}
override def resultExtractionCode(req: Request) =
if (mods.isPublic) codegenln(s"def ${req.defTypeOf(name)}") else ""
}

abstract class MacroHandler(member: DefDef) extends MemberDefHandler(member) {
Expand All @@ -162,36 +171,34 @@ trait MemberHandlers {
}

class TermMacroHandler(member: DefDef) extends MacroHandler(member) {
def notification(req: Request) = s"defined term macro $name: ${req.typeOf(name)}"
def notification(req: Request) = s"def ${req.defTypeOf(name)}"
}

class AssignHandler(member: Assign) extends MemberHandler(member) {
override def resultExtractionCode(req: Request) =
codegenln(s"mutated ${member.lhs}")
codegenln(s"// mutated ${member.lhs}")
}

class ModuleHandler(module: ModuleDef) extends MemberDefHandler(module) {
override def definesTerm = Some(name.toTermName)
override def definesValue = true

override def resultExtractionCode(req: Request) = codegenln("defined object ", name)
override def resultExtractionCode(req: Request) = codegenln(s"object $name")
}

class ClassHandler(member: ClassDef) extends MemberDefHandler(member) {
override def definedSymbols = List(symbol, symbol.companionSymbol) filterNot (_ == NoSymbol)
override def definesType = Some(name.toTypeName)
override def definesTerm = Some(name.toTermName) filter (_ => mods.isCase)

override def resultExtractionCode(req: Request) =
codegenln("defined %s %s".format(keyword, name))
override def resultExtractionCode(req: Request) = codegenln(s"$keyword $name")
}

class TypeAliasHandler(member: TypeDef) extends MemberDefHandler(member) {
private def isAlias = mods.isPublic && treeInfo.isAliasTypeDef(member)
override def definesType = Some(name.toTypeName) filter (_ => isAlias)

override def resultExtractionCode(req: Request) =
codegenln("defined type alias ", name) + "\n"
override def resultExtractionCode(req: Request) = codegenln(s"type $name")
}

class ImportHandler(imp: Import) extends MemberHandler(imp) {
Expand Down
7 changes: 5 additions & 2 deletions src/repl/scala/tools/nsc/interpreter/ReplStrings.scala
Expand Up @@ -37,11 +37,14 @@ object ReplStrings {
res.toString
}

@inline final def quotedString(str: String) =
"\"" + str + "\""

def string2codeQuoted(str: String) =
"\"" + string2code(str) + "\""
quotedString(string2code(str))

def any2stringOf(x: Any, maxlen: Int) =
"_root_.scala.runtime.ScalaRunTime.replStringOf(%s, %s)".format(x, maxlen)
s"_root_.scala.runtime.ScalaRunTime.replStringOf($x, $maxlen)"

// no escaped or nested quotes
private[this] val inquotes = """(['"])(.*?)\1""".r
Expand Down

0 comments on commit 11a932b

Please sign in to comment.