Skip to content

Commit

Permalink
Merge pull request scala#1436 from cswinter/wip-repl-patdef-fix
Browse files Browse the repository at this point in the history
Fix scala#1372: Add handler for `PatDef`s to REPL
  • Loading branch information
smarter authored Aug 8, 2016
2 parents be1f099 + 17ba942 commit 62348de
Show file tree
Hide file tree
Showing 3 changed files with 73 additions and 21 deletions.
5 changes: 5 additions & 0 deletions src/dotty/tools/dotc/ast/untpd.scala
Original file line number Diff line number Diff line change
Expand Up @@ -456,6 +456,11 @@ object untpd extends Trees.Instance[Untyped] with UntypedTreeInfo {
}
}

/** Fold `f` over all tree nodes, in depth-first, prefix order */
class UntypedDeepFolder[X](f: (X, Tree) => X) extends UntypedTreeAccumulator[X] {
def apply(x: X, tree: Tree)(implicit ctx: Context): X = foldOver(f(x, tree), tree)
}

override def rename(tree: NameTree, newName: Name)(implicit ctx: Context): tree.ThisTree[Untyped] = tree match {
case t: PolyTypeDef =>
cpy.PolyTypeDef(t)(newName.asTypeName, t.tparams, t.rhs).asInstanceOf[tree.ThisTree[Untyped]]
Expand Down
79 changes: 58 additions & 21 deletions src/dotty/tools/dotc/repl/CompilingInterpreter.scala
Original file line number Diff line number Diff line change
Expand Up @@ -222,7 +222,7 @@ class CompilingInterpreter(
if (delayOutput)
previousOutput ++= resultStrings.map(clean)
else if (printResults || !succeeded)
resultStrings.map(x => out.print(clean(x)))
resultStrings.foreach(x => out.print(clean(x)))
if (succeeded) {
prevRequests += req
Interpreter.Success
Expand Down Expand Up @@ -328,6 +328,7 @@ class CompilingInterpreter(
private def chooseHandler(stat: Tree): StatementHandler = stat match {
case stat: DefDef => new DefHandler(stat)
case stat: ValDef => new ValHandler(stat)
case stat: PatDef => new PatHandler(stat)
case stat @ Assign(Ident(_), _) => new AssignHandler(stat)
case stat: ModuleDef => new ModuleHandler(stat)
case stat: TypeDef if stat.isClassDef => new ClassHandler(stat)
Expand Down Expand Up @@ -662,29 +663,65 @@ class CompilingInterpreter(

private class GenericHandler(statement: Tree) extends StatementHandler(statement)

private class ValHandler(statement: ValDef) extends StatementHandler(statement) {
override val boundNames = List(statement.name)
private abstract class ValOrPatHandler(statement: Tree)
extends StatementHandler(statement) {
override val boundNames: List[Name] = _boundNames
override def valAndVarNames = boundNames

override def resultExtractionCode(req: Request, code: PrintWriter): Unit = {
val vname = statement.name
if (!statement.mods.is(Flags.AccessFlags) &&
!(isGeneratedVarName(vname.toString) &&
req.typeOf(vname.encode) == "Unit")) {
val prettyName = vname.decode
code.print(" + \"" + prettyName + ": " +
string2code(req.typeOf(vname)) +
" = \" + " +
" (if(" +
req.fullPath(vname) +
".asInstanceOf[AnyRef] != null) " +
" ((if(" +
req.fullPath(vname) +
".toString().contains('\\n')) " +
" \"\\n\" else \"\") + " +
req.fullPath(vname) + ".toString() + \"\\n\") else \"null\\n\") ")
}
if (!shouldShowResult(req)) return
val resultExtractors = boundNames.map(name => resultExtractor(req, name))
code.print(resultExtractors.mkString(""))
}

private def resultExtractor(req: Request, varName: Name): String = {
val prettyName = varName.decode
val varType = string2code(req.typeOf(varName))
val fullPath = req.fullPath(varName)

s""" + "$prettyName: $varType = " + {
| if ($fullPath.asInstanceOf[AnyRef] != null) {
| (if ($fullPath.toString().contains('\\n')) "\\n" else "") +
| $fullPath.toString() + "\\n"
| } else {
| "null\\n"
| }
|}""".stripMargin
}

protected def _boundNames: List[Name]
protected def shouldShowResult(req: Request): Boolean
}

private class ValHandler(statement: ValDef) extends ValOrPatHandler(statement) {
override def _boundNames = List(statement.name)

override def shouldShowResult(req: Request): Boolean =
!statement.mods.is(Flags.AccessFlags) &&
!(isGeneratedVarName(statement.name.toString) &&
req.typeOf(statement.name.encode) == "Unit")
}


private class PatHandler(statement: PatDef) extends ValOrPatHandler(statement) {
override def _boundNames = statement.pats.flatMap(findVariableNames)

override def shouldShowResult(req: Request): Boolean =
!statement.mods.is(Flags.AccessFlags)

private def findVariableNames(tree: Tree): List[Name] = tree match {
case Ident(name) if name.toString != "_" => List(name)
case _ => VariableNameFinder(Nil, tree).reverse
}

private object VariableNameFinder extends UntypedDeepFolder[List[Name]](
(acc: List[Name], t: Tree) => t match {
case _: BackquotedIdent => acc
case Ident(name) if name.isVariableName && name.toString != "_" => name :: acc
case Bind(name, _) if name.isVariableName => name :: acc
case _ => acc
}
)
}

private class DefHandler(defDef: DefDef) extends StatementHandler(defDef) {
Expand Down Expand Up @@ -836,7 +873,7 @@ class CompilingInterpreter(
val stringWriter = new StringWriter()
val stream = new NewLinePrintWriter(stringWriter)
writer(stream)
stream.close
stream.close()
stringWriter.toString
}

Expand Down
10 changes: 10 additions & 0 deletions tests/repl/patdef.check
Original file line number Diff line number Diff line change
@@ -0,0 +1,10 @@
scala> val Const,x = 0
Const: Int = 0
x: Int = 0
scala> val (Const, List(`x`, _, a), b) = (0, List(0, 1337, 1), 2)
a: Int = 1
b: Int = 2
scala> val a@b = 0
a: Int @unchecked = 0
b: Int @unchecked = 0
scala> :quit

0 comments on commit 62348de

Please sign in to comment.