diff options
Diffstat (limited to 'src/repl')
6 files changed, 71 insertions, 84 deletions
diff --git a/src/repl/scala/tools/nsc/interpreter/ExprTyper.scala b/src/repl/scala/tools/nsc/interpreter/ExprTyper.scala index 9353215e1e..6406dacc24 100644 --- a/src/repl/scala/tools/nsc/interpreter/ExprTyper.scala +++ b/src/repl/scala/tools/nsc/interpreter/ExprTyper.scala @@ -16,32 +16,6 @@ trait ExprTyper { import syntaxAnalyzer.UnitParser import naming.freshInternalVarName - object codeParser { - val global: repl.global.type = repl.global - def applyRule[T](code: String, rule: UnitParser => T): T = { - reporter.reset() - val scanner = newUnitParser(code) - val result = rule(scanner) - - if (!reporter.hasErrors) - scanner.accept(EOF) - - result - } - def stmts(code: String) = applyRule(code, _.templateStats()) - } - - /** Parse a line into a sequence of trees. Returns None if the input is incomplete. */ - def parse(line: String): Option[List[Tree]] = debugging(s"""parse("$line")""") { - var isIncomplete = false - reporter.withIncompleteHandler((_, _) => isIncomplete = true) { - val trees = codeParser.stmts(line) - if (reporter.hasErrors) Some(Nil) - else if (isIncomplete) None - else Some(trees) - } - } - def symbolOfLine(code: String): Symbol = { def asExpr(): Symbol = { val name = freshInternalVarName() diff --git a/src/repl/scala/tools/nsc/interpreter/IMain.scala b/src/repl/scala/tools/nsc/interpreter/IMain.scala index b35f71aeef..ae318697ec 100644 --- a/src/repl/scala/tools/nsc/interpreter/IMain.scala +++ b/src/repl/scala/tools/nsc/interpreter/IMain.scala @@ -7,30 +7,23 @@ package scala package tools.nsc package interpreter -import Predef.{ println => _, _ } -import util.stringFromWriter -import scala.reflect.internal.util._ -import java.net.URL -import scala.sys.BooleanProp -import scala.tools.nsc.io.AbstractFile -import reporters._ +import scala.language.implicitConversions + +import scala.collection.mutable + +import scala.concurrent.{ Future, ExecutionContext } + +import scala.reflect.runtime.{ universe => ru } +import scala.reflect.{ BeanProperty, ClassTag, classTag } +import scala.reflect.internal.util.{ BatchSourceFile, SourceFile } + import scala.tools.util.PathResolver -import scala.tools.nsc.util.ScalaClassLoader +import scala.tools.nsc.io.AbstractFile import scala.tools.nsc.typechecker.{ TypeStrings, StructuredTypeStrings } -import ScalaClassLoader.URLClassLoader +import scala.tools.nsc.util.{ ScalaClassLoader, stringFromWriter } import scala.tools.nsc.util.Exceptional.unwrap -import scala.collection.{ mutable, immutable } -import scala.reflect.BeanProperty -import scala.util.Properties.versionString + import javax.script.{AbstractScriptEngine, Bindings, ScriptContext, ScriptEngine, ScriptEngineFactory, ScriptException, CompiledScript, Compilable} -import java.io.{ StringWriter, Reader } -import java.util.Arrays -import IMain._ -import java.util.concurrent.Future -import scala.reflect.runtime.{ universe => ru } -import scala.reflect.{ ClassTag, classTag } -import StdReplTags._ -import scala.language.implicitConversions /** An interpreter for Scala code. * @@ -92,7 +85,7 @@ class IMain(@BeanProperty val factory: ScriptEngineFactory, initialSettings: Set private var _classLoader: util.AbstractFileClassLoader = null // active classloader private val _compiler: ReplGlobal = newCompiler(settings, reporter) // our private compiler - def compilerClasspath: Seq[URL] = ( + def compilerClasspath: Seq[java.net.URL] = ( if (isInitializeComplete) global.classPath.asURLs else new PathResolver(settings).result.asURLs // the compiler's classpath ) @@ -142,10 +135,8 @@ class IMain(@BeanProperty val factory: ScriptEngineFactory, initialSettings: Set def initialize(postInitSignal: => Unit) { synchronized { if (_isInitialized == null) { - _isInitialized = io.spawn { - try _initialize() - finally postInitSignal - } + _isInitialized = + Future(try _initialize() finally postInitSignal)(ExecutionContext.global) } } } @@ -241,7 +232,7 @@ class IMain(@BeanProperty val factory: ScriptEngineFactory, initialSettings: Set lazy val isettings = new ISettings(this) /** Instantiate a compiler. Overridable. */ - protected def newCompiler(settings: Settings, reporter: Reporter): ReplGlobal = { + protected def newCompiler(settings: Settings, reporter: reporters.Reporter): ReplGlobal = { settings.outputDirs setSingleOutput replOutput.dir settings.exposeEmptyPackage.value = true new Global(settings, reporter) with ReplGlobal { override def toString: String = "<global>" } @@ -334,7 +325,7 @@ class IMain(@BeanProperty val factory: ScriptEngineFactory, initialSettings: Set private def makeClassLoader(): util.AbstractFileClassLoader = new TranslatingClassLoader(parentClassLoader match { case null => ScalaClassLoader fromURLs compilerClasspath - case p => new URLClassLoader(compilerClasspath, p) + case p => new ScalaClassLoader.URLClassLoader(compilerClasspath, p) }) // Set the current Java "context" class loader to this interpreter's class loader @@ -446,9 +437,9 @@ class IMain(@BeanProperty val factory: ScriptEngineFactory, initialSettings: Set private def requestFromLine(line: String, synthetic: Boolean): Either[IR.Result, Request] = { val content = indentCode(line) val trees = parse(content) match { - case None => return Left(IR.Incomplete) - case Some(Nil) => return Left(IR.Error) // parse error or empty input - case Some(trees) => trees + case parse.Incomplete => return Left(IR.Incomplete) + case parse.Error => return Left(IR.Error) + case parse.Success(trees) => trees } repltrace( trees map (t => { @@ -466,7 +457,8 @@ class IMain(@BeanProperty val factory: ScriptEngineFactory, initialSettings: Set // If the last tree is a bare expression, pinpoint where it begins using the // AST node position and snap the line off there. Rewrite the code embodied // by the last tree as a ValDef instead, so we can access the value. - trees.last match { + val last = trees.lastOption.getOrElse(EmptyTree) + last match { case _:Assign => // we don't want to include assignments case _:TermTree | _:Ident | _:Select => // ... but do want other unnamed terms. val varName = if (synthetic) freshInternalVarName() else freshUserVarName() @@ -478,7 +470,7 @@ class IMain(@BeanProperty val factory: ScriptEngineFactory, initialSettings: Set if (trees.size == 1) "val " + varName + " =\n" + content else { // The position of the last tree - val lastpos0 = earliestPosition(trees.last) + val lastpos0 = earliestPosition(last) // Oh boy, the parser throws away parens so "(2+2)" is mispositioned, // with increasingly hard to decipher positions as we move on to "() => 5", // (x: Int) => x + 1, and more. So I abandon attempts to finesse and just @@ -554,7 +546,7 @@ class IMain(@BeanProperty val factory: ScriptEngineFactory, initialSettings: Set var code = "" var bound = false - @throws(classOf[ScriptException]) + @throws[ScriptException] def compile(script: String): CompiledScript = { if (!bound) { quietBind("engine" -> this.asInstanceOf[ScriptEngine]) @@ -582,9 +574,9 @@ class IMain(@BeanProperty val factory: ScriptEngineFactory, initialSettings: Set } } - @throws(classOf[ScriptException]) - def compile(reader: Reader): CompiledScript = { - val writer = new StringWriter() + @throws[ScriptException] + def compile(reader: java.io.Reader): CompiledScript = { + val writer = new java.io.StringWriter() var c = reader.read() while(c != -1) { writer.write(c) @@ -604,7 +596,7 @@ class IMain(@BeanProperty val factory: ScriptEngineFactory, initialSettings: Set * escape. We could have wrapped runtime exceptions just like other * exceptions in ScriptException, this is a choice. */ - @throws(classOf[ScriptException]) + @throws[ScriptException] def eval(context: ScriptContext): Object = { val result = req.lineRep.evalEither match { case Left(e: RuntimeException) => throw e @@ -737,7 +729,7 @@ class IMain(@BeanProperty val factory: ScriptEngineFactory, initialSettings: Set val unwrapped = unwrap(t) withLastExceptionLock[String]({ - directBind[Throwable]("lastException", unwrapped)(tagOfThrowable, classTag[Throwable]) + directBind[Throwable]("lastException", unwrapped)(StdReplTags.tagOfThrowable, classTag[Throwable]) util.stackTraceString(unwrapped) }, util.stackTraceString(unwrapped)) } @@ -873,7 +865,7 @@ class IMain(@BeanProperty val factory: ScriptEngineFactory, initialSettings: Set def fullPath(vname: String) = s"${lineRep.readPath}$accessPath.`$vname`" /** generate the source code for the object that computes this request */ - private object ObjectSourceCode extends CodeAssembler[MemberHandler] { + private object ObjectSourceCode extends IMain.CodeAssembler[MemberHandler] { def path = originalPath("$intp") def envLines = { if (!isReplPower) Nil // power mode only for now @@ -896,7 +888,7 @@ class IMain(@BeanProperty val factory: ScriptEngineFactory, initialSettings: Set val generate = (m: MemberHandler) => m extraCodeToEvaluate Request.this } - private object ResultObjectSourceCode extends CodeAssembler[MemberHandler] { + private object ResultObjectSourceCode extends IMain.CodeAssembler[MemberHandler] { /** We only want to generate this code when the result * is a value which can be referred to as-is. */ @@ -995,11 +987,11 @@ class IMain(@BeanProperty val factory: ScriptEngineFactory, initialSettings: Set } } - @throws(classOf[ScriptException]) + @throws[ScriptException] def eval(script: String, context: ScriptContext): Object = compile(script).eval(context) - @throws(classOf[ScriptException]) - def eval(reader: Reader, context: ScriptContext): Object = compile(reader).eval(context) + @throws[ScriptException] + def eval(reader: java.io.Reader, context: ScriptContext): Object = compile(reader).eval(context) override def finalize = close @@ -1098,7 +1090,24 @@ class IMain(@BeanProperty val factory: ScriptEngineFactory, initialSettings: Set val repl: IMain.this.type = imain } with ExprTyper { } - def parse(line: String): Option[List[Tree]] = exprTyper.parse(line) + /** Parse a line into and return parsing result (error, incomplete or success with list of trees) */ + object parse { + abstract sealed class Result + case object Error extends Result + case object Incomplete extends Result + case class Success(trees: List[Tree]) extends Result + + def apply(line: String): Result = debugging(s"""parse("$line")""") { + var isIncomplete = false + reporter.withIncompleteHandler((_, _) => isIncomplete = true) { + reporter.reset() + val trees = newUnitParser(line).parseStats() + if (reporter.hasErrors) Error + else if (isIncomplete) Incomplete + else Success(trees) + } + } + } def symbolOfLine(code: String): Symbol = exprTyper.symbolOfLine(code) @@ -1157,10 +1166,12 @@ class IMain(@BeanProperty val factory: ScriptEngineFactory, initialSettings: Set */ def isShow = code.lines exists (_.trim endsWith "// show") if (isReplDebug || isShow) { - beSilentDuring(parse(code)) foreach { ts => - ts foreach { t => - withoutUnwrapping(echo(asCompactString(t))) - } + beSilentDuring(parse(code)) match { + case parse.Success(ts) => + ts foreach { t => + withoutUnwrapping(echo(asCompactString(t))) + } + case _ => } } } @@ -1174,6 +1185,8 @@ class IMain(@BeanProperty val factory: ScriptEngineFactory, initialSettings: Set /** Utility methods for the Interpreter. */ object IMain { + import java.util.Arrays.{ asList => asJavaList } + class Factory extends ScriptEngineFactory { @BeanProperty val engineName = "Scala Interpreter" @@ -1182,21 +1195,21 @@ object IMain { val engineVersion = "1.0" @BeanProperty - val extensions: JList[String] = Arrays.asList("scala") + val extensions: JList[String] = asJavaList("scala") @BeanProperty val languageName = "Scala" @BeanProperty - val languageVersion = versionString + val languageVersion = scala.util.Properties.versionString def getMethodCallSyntax(obj: String, m: String, args: String*): String = null @BeanProperty - val mimeTypes: JList[String] = Arrays.asList("application/x-scala") + val mimeTypes: JList[String] = asJavaList("application/x-scala") @BeanProperty - val names: JList[String] = Arrays.asList("scala") + val names: JList[String] = asJavaList("scala") def getOutputStatement(toDisplay: String): String = null diff --git a/src/repl/scala/tools/nsc/interpreter/JLineCompletion.scala b/src/repl/scala/tools/nsc/interpreter/JLineCompletion.scala index 8b8b668c9f..61db8d1748 100644 --- a/src/repl/scala/tools/nsc/interpreter/JLineCompletion.scala +++ b/src/repl/scala/tools/nsc/interpreter/JLineCompletion.scala @@ -190,10 +190,10 @@ class JLineCompletion(val intp: IMain) extends Completion with CompletionOutput // literal Ints, Strings, etc. object literals extends CompletionAware { - def simpleParse(code: String): Tree = newUnitParser(code).templateStats().last + def simpleParse(code: String): Option[Tree] = newUnitParser(code).parseStats().lastOption def completions(verbosity: Int) = Nil - override def follow(id: String) = simpleParse(id) match { + override def follow(id: String) = simpleParse(id).flatMap { case x: Literal => Some(new LiteralCompletion(x)) case _ => None } diff --git a/src/repl/scala/tools/nsc/interpreter/Power.scala b/src/repl/scala/tools/nsc/interpreter/Power.scala index da6d271a68..f69a5b487d 100644 --- a/src/repl/scala/tools/nsc/interpreter/Power.scala +++ b/src/repl/scala/tools/nsc/interpreter/Power.scala @@ -316,7 +316,7 @@ class Power[ReplValsImpl <: ReplVals : ru.TypeTag: ClassTag](val intp: IMain, re lazy val phased: Phased = new { val global: intp.global.type = intp.global } with Phased { } def unit(code: String) = newCompilationUnit(code) - def trees(code: String) = parse(code) getOrElse Nil + def trees(code: String) = parse(code) match { case parse.Success(trees) => trees; case _ => Nil } override def toString = s""" |** Power mode status ** diff --git a/src/repl/scala/tools/nsc/interpreter/Results.scala b/src/repl/scala/tools/nsc/interpreter/Results.scala index e400906a58..a4e1e25cbb 100644 --- a/src/repl/scala/tools/nsc/interpreter/Results.scala +++ b/src/repl/scala/tools/nsc/interpreter/Results.scala @@ -19,4 +19,4 @@ object Results { /** The input was incomplete. The caller should request more input. */ case object Incomplete extends Result -} +}
\ No newline at end of file diff --git a/src/repl/scala/tools/nsc/interpreter/package.scala b/src/repl/scala/tools/nsc/interpreter/package.scala index f82c38f5e7..5dc9b65436 100644 --- a/src/repl/scala/tools/nsc/interpreter/package.scala +++ b/src/repl/scala/tools/nsc/interpreter/package.scala @@ -145,8 +145,8 @@ package object interpreter extends ReplConfig with ReplStrings { case sym: TypeSymbol => Some(sym) case _ => None } - (typeFromTypeString orElse typeFromNameTreatedAsTerm orElse typeFromFullName orElse typeOfTerm) foreach { sym => - val (kind, tpe) = exitingTyper { + (typeFromTypeString orElse typeFromNameTreatedAsTerm orElse typeFromFullName orElse typeOfTerm) foreach { sym => + val (kind, tpe) = exitingTyper { val tpe = sym.tpeHK (intp.global.inferKind(NoPrefix)(tpe, sym.owner), tpe) } |