Skip to content

Commit 689b4dd

Browse files
committed
Parse wrapper code in the REPL during tab completion
Working towards using the real typer for completion ``` % qscala Welcome to Scala version 2.11.7-20150526-102741-96571a9688 (Java HotSpot(TM) 64-Bit Server VM, Java 1.8.0_25). Type in expressions to have them evaluated. Type :help for more information. scala> val x = "" x: String = "" scala> x.<console>:8: error: identifier expected but '}' found. } ^ object $read { object $iw { object $iw { x.<error> } } } + codePointBefore concat getBytes isInstanceOf regionMatches startsWith toString asInstanceOf codePointCount contains getChars lastIndexOf replace subSequence toUpperCase charAt codePoints contentEquals indexOf length replaceAll substring trim chars compareTo endsWith intern matches replaceFirst toCharArray codePointAt compareToIgnoreCase equalsIgnoreCase isEmpty offsetByCodePoints split toLowerCase scala> :quit ```
1 parent 96571a9 commit 689b4dd

File tree

2 files changed

+38
-4
lines changed

2 files changed

+38
-4
lines changed

src/repl/scala/tools/nsc/interpreter/IMain.scala

Lines changed: 34 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -459,9 +459,12 @@ class IMain(@BeanProperty val factory: ScriptEngineFactory, initialSettings: Set
459459
pos
460460
}
461461

462-
private def requestFromLine(line: String, synthetic: Boolean): Either[IR.Result, Request] = {
462+
private def requestFromLine(line: String, synthetic: Boolean, forPresentationCompile: Boolean = false): Either[IR.Result, Request] = {
463463
val content = indentCode(line)
464-
val trees = parse(content) match {
464+
if (forPresentationCompile)
465+
return Right(buildRequest(line, Nil))
466+
467+
val trees: List[global.Tree] = parse(content) match {
465468
case parse.Incomplete => return Left(IR.Incomplete)
466469
case parse.Error => return Left(IR.Error)
467470
case parse.Success(trees) => trees
@@ -529,7 +532,7 @@ class IMain(@BeanProperty val factory: ScriptEngineFactory, initialSettings: Set
529532
// Rewriting "foo ; bar ; 123"
530533
// to "foo ; bar ; val resXX = 123"
531534
requestFromLine(rewrittenLine, synthetic) match {
532-
case Right(req) => return Right(req withOriginalLine line)
535+
case Right(req) if !forPresentationCompile => return Right(req withOriginalLine line)
533536
case x => return x
534537
}
535538
case _ =>
@@ -569,6 +572,17 @@ class IMain(@BeanProperty val factory: ScriptEngineFactory, initialSettings: Set
569572
}
570573
}
571574

575+
private[scala] def presentationCompile(line: String, synthetic: Boolean): Either[IR.Result, Request] = {
576+
if (global == null) Left(IR.Error)
577+
else requestFromLine(line, synthetic, forPresentationCompile = true) match {
578+
case Left(result) => Left(result)
579+
case Right(req) =>
580+
// null indicates a disallowed statement type; otherwise compile and
581+
// fail if false (implying e.g. a type error)
582+
if (req == null || !req.presentationCompile) Left(IR.Error) else Right(req)
583+
}
584+
}
585+
572586
var code = ""
573587
var bound = false
574588
def compiled(script: String): CompiledScript = {
@@ -994,6 +1008,23 @@ class IMain(@BeanProperty val factory: ScriptEngineFactory, initialSettings: Set
9941008
}
9951009
}
9961010

1011+
lazy val presentationCompile: Boolean = {
1012+
reporter.reset()
1013+
val wrappedCode: String = ObjectSourceCode(handlers)
1014+
parseAndTypeCheck(wrappedCode)
1015+
reporter.hasErrors
1016+
}
1017+
1018+
private[this] def parseAndTypeCheck(code: String): global.CompilationUnit = {
1019+
val unit = global.newCompilationUnit(code)
1020+
val parser = global.newUnitParser(unit)
1021+
val parserPhase = global.syntaxAnalyzer.newPhase(NoPhase)
1022+
val run: global.Run = new global.Run()
1023+
run.parserPhase.asInstanceOf[GlobalPhase].applyPhase(unit)
1024+
println(showCode(unit.body))
1025+
unit
1026+
}
1027+
9971028
lazy val resultSymbol = lineRep.resolvePathToSymbol(accessPath)
9981029
def applyToResultMember[T](name: Name, f: Symbol => T) = exitingTyper(f(resultSymbol.info.nonPrivateDecl(name)))
9991030

src/repl/scala/tools/nsc/interpreter/JLineCompletion.scala

Lines changed: 4 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -295,7 +295,10 @@ class JLineCompletion(val intp: IMain) extends Completion with CompletionOutput
295295
override def complete(buf: String, cursor: Int): Candidates = {
296296
verbosity = if (isConsecutiveTabs(buf, cursor)) verbosity + 1 else 0
297297
repldbg(f"%ncomplete($buf, $cursor%d) last = ($lastBuf, $lastCursor%d), verbosity: $verbosity")
298-
298+
intp.presentationCompile(buf, false) match {
299+
case Left(_) =>
300+
case Right(request) =>
301+
}
299302
// we don't try lower priority completions unless higher ones return no results.
300303
def tryCompletion(p: Parsed, completionFunction: Parsed => List[String]): Option[Candidates] = {
301304
val winners = completionFunction(p)

0 commit comments

Comments
 (0)