aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorClemens Winter <clemenswinter1@gmail.com>2016-07-29 16:58:30 +0200
committerClemens Winter <clemenswinter1@gmail.com>2016-08-02 14:42:33 +0200
commit17ba94221e4e120c1442b5611f8f339c0f642c65 (patch)
tree7b8db4f015db4e97f278864b10a259bee32999f1
parent765aecbe3ca4e05c987dde4e868dca08c7585666 (diff)
downloaddotty-17ba94221e4e120c1442b5611f8f339c0f642c65.tar.gz
dotty-17ba94221e4e120c1442b5611f8f339c0f642c65.tar.bz2
dotty-17ba94221e4e120c1442b5611f8f339c0f642c65.zip
Fix #1372: Add handler for `PatDef`s to REPL
-rw-r--r--src/dotty/tools/dotc/ast/untpd.scala5
-rw-r--r--src/dotty/tools/dotc/repl/CompilingInterpreter.scala79
-rw-r--r--tests/repl/patdef.check10
3 files changed, 73 insertions, 21 deletions
diff --git a/src/dotty/tools/dotc/ast/untpd.scala b/src/dotty/tools/dotc/ast/untpd.scala
index b3f8747dc..1fdfed0f4 100644
--- a/src/dotty/tools/dotc/ast/untpd.scala
+++ b/src/dotty/tools/dotc/ast/untpd.scala
@@ -447,6 +447,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]]
diff --git a/src/dotty/tools/dotc/repl/CompilingInterpreter.scala b/src/dotty/tools/dotc/repl/CompilingInterpreter.scala
index e05ecb328..163bbea16 100644
--- a/src/dotty/tools/dotc/repl/CompilingInterpreter.scala
+++ b/src/dotty/tools/dotc/repl/CompilingInterpreter.scala
@@ -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
@@ -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)
@@ -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) {
@@ -836,7 +873,7 @@ class CompilingInterpreter(
val stringWriter = new StringWriter()
val stream = new NewLinePrintWriter(stringWriter)
writer(stream)
- stream.close
+ stream.close()
stringWriter.toString
}
diff --git a/tests/repl/patdef.check b/tests/repl/patdef.check
new file mode 100644
index 000000000..0cb1c6d4f
--- /dev/null
+++ b/tests/repl/patdef.check
@@ -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