interpreter.scala

来自「JAVA 语言的函数式编程扩展」· SCALA 代码 · 共 960 行 · 第 1/3 页

SCALA
960
字号
      val rhpairs = for {        req <- prevRequests.toList.reverse        handler <- req.handlers      } yield (req, handler)      select(rhpairs, wanted).reverse    }    val code = new StringBuffer    val trailingBraces = new StringBuffer    val accessPath = new StringBuffer    val impname = compiler.nme.INTERPRETER_IMPORT_WRAPPER    val currentImps = mutable.Set.empty[Name]    // add code for a new object to hold some imports    def addWrapper() {      code.append("object " + impname + "{\n")      trailingBraces.append("}\n")      accessPath.append("." + impname)      currentImps.clear    }    addWrapper()    // loop through previous requests, adding imports    // for each one    for ((req,handler) <- reqsToUse) {          // If the user entered an import, then just use it          // add an import wrapping level if the import might          // conflict with some other import          if(handler.importsWildcard ||             currentImps.exists(handler.importedNames.contains))            if(!currentImps.isEmpty)              addWrapper()                if (handler.member.isInstanceOf[Import])            code.append(handler.member.toString + ";\n")          // give wildcard imports a import wrapper all to their own          if(handler.importsWildcard)             addWrapper()            else            currentImps ++= handler.importedNames          // For other requests, import each bound variable.          // import them explicitly instead of with _, so that          // ambiguity errors will not be generated. Also, quote  	  // the name of the variable, so that we don't need to  	  // handle quoting keywords separately.           for (imv <- handler.boundNames) {            if (currentImps.contains(imv))              addWrapper()            code.append("import ")            code.append(req.objectName + req.accessPath + ".`" + imv + "`;\n")            currentImps += imv          }    }    addWrapper() // Add one extra wrapper, to prevent warnings                 // in the frequent case of redefining                 // the value bound in the last interpreter                 // request.    (code.toString, trailingBraces.toString, accessPath.toString)  }  /** Parse a line into a sequence of trees. Returns None if the input    * is incomplete. */  private def parse(line: String): Option[List[Tree]] = {    var justNeedsMore = false    reporter.withIncompleteHandler((pos,msg) => {justNeedsMore = true}) {      // simple parse: just parse it, nothing else      def simpleParse(code: String): List[Tree] = {        reporter.reset        val unit =          new CompilationUnit(            new BatchSourceFile("<console>", code.toCharArray()))        val scanner = new compiler.syntaxAnalyzer.UnitParser(unit);        val xxx = scanner.templateStatSeq;        (xxx._2)      }      val (trees) = simpleParse(line)      if (reporter.hasErrors) {        Some(Nil) // the result did not parse, so stop      } else if (justNeedsMore) {        None      } else {        Some(trees)      }    }  }  /** Compile an nsc SourceFile.  Returns true if there are   *  no compilation errors, or false othrewise.   */  def compileSources(sources: List[SourceFile]): Boolean = {    val cr = new compiler.Run    reporter.reset    cr.compileSources(sources)    !reporter.hasErrors  }  /** Compile a string.  Returns true if there are no   *  compilation errors, or false otherwise.   */  def compileString(code: String): Boolean =    compileSources(List(new BatchSourceFile("<script>", code.toCharArray)))  /** Build a request from the user. <code>trees</code> is <code>line</code>   *  after being parsed.   */  private def buildRequest(trees: List[Tree], line: String, lineName: String): Request =    new Request(line, lineName)  private def chooseHandler(member: Tree): Option[MemberHandler] =    member match {      case member: DefDef =>          Some(new DefHandler(member))      case member: ValDef =>          Some(new ValHandler(member))      case member@Assign(Ident(_), _) => Some(new AssignHandler(member))      case member: ModuleDef => Some(new ModuleHandler(member))      case member: ClassDef => Some(new ClassHandler(member))      case member: TypeDef => Some(new TypeAliasHandler(member))      case member: Import => Some(new ImportHandler(member))      case DocDef(_, documented) => chooseHandler(documented)      case member => Some(new GenericHandler(member))    }  /** <p>   *    Interpret one line of input.  All feedback, including parse errors   *    and evaluation results, are printed via the supplied compiler's    *    reporter.  Values defined are available for future interpreted   *    strings.   *  </p>   *  <p>   *    The return value is whether the line was interpreter successfully,   *    e.g. that there were no parse errors.   *  </p>   *   *  @param line ...   *  @return     ...   */  def interpret(line: String): IR.Result = {    if (prevRequests.isEmpty)      new compiler.Run // initialize the compiler    // parse    val trees = parse(indentCode(line)) match {      case None => return IR.Incomplete      case (Some(Nil)) => return IR.Error // parse error or empty input      case Some(trees) => trees    }    trees match {      case List(_:Assign) => ()      case List(_:TermTree) | List(_:Ident) | List(_:Select) =>        // Treat a single bare expression specially.        // This is necessary due to it being hard to modify        // code at a textual level, and it being hard to        // submit an AST to the compiler.        return interpret("val "+newVarName()+" = \n"+line)      case _ => ()    }    val lineName = newLineName    // figure out what kind of request    val req = buildRequest(trees, line, lineName)    if (req eq null) return IR.Error  // a disallowed statement type    if (!req.compile)      return IR.Error  // an error happened during compilation, e.g. a type error    val (interpreterResultString, succeeded) = req.loadAndRun    if (printResults || !succeeded) {      // print the result      out.print(clean(interpreterResultString))    }    // book-keeping    if (succeeded)      prevRequests += req    if (succeeded) IR.Success else IR.Error  }  /** A counter used for numbering objects created by <code>bind()</code>. */  private var binderNum = 0  /** Bind a specified name to a specified value.  The name may   *  later be used by expressions passed to interpret.   *   *  @param name      the variable name to bind   *  @param boundType the type of the variable, as a string   *  @param value     the object value to bind to it   *  @return          an indication of whether the binding succeeded   */  def bind(name: String, boundType: String, value: Any): IR.Result = {    val binderName = "binder" + binderNum    binderNum += 1    compileString(        "object " + binderName +        "{ var value: " + boundType + " = _; " +        " def set(x: Any) = value=x.asInstanceOf[" + boundType + "]; }")    val binderObject =      Class.forName(binderName, true, classLoader)    val setterMethod =      (binderObject          .getDeclaredMethods          .toList          .find(meth => meth.getName == "set")          .get)    var argsHolder: Array[Any] = null // this roundabout approach is to try and                                       // make sure the value is boxed    argsHolder = List(value).toArray    setterMethod.invoke(null, argsHolder.asInstanceOf[Array[AnyRef]])    interpret("val " + name + " = " + binderName + ".value")  }  /** <p>   *    This instance is no longer needed, so release any resources   *    it is using.   *  </p>   *  <p>   *    Specifically, this deletes the temporary directory used for holding   *    class files for this instance.  This cannot safely be done after   *    each command is executed because of Java's demand loading.   *  </p>   *  <p>   *    Also, this flushes the reporter's output.   *  </p>   */  def close() {    Interpreter.deleteRecursively(classfilePath)    reporter.flush()  }  /** A traverser that finds all mentioned identifiers, i.e. things   *  that need to be imported.   *  It might return extra names.   */  private class ImportVarsTraverser(definedVars: List[Name]) extends Traverser {    val importVars = new HashSet[Name]()    override def traverse(ast: Tree) {      ast match {        case Ident(name) => importVars += name        case _ => super.traverse(ast)      }    }  }  /** Class to handle one member among all the members included   *  in a single interpreter request.   */  private sealed abstract class MemberHandler(val member: Tree) {    val usedNames: List[Name] = {      val ivt = new ImportVarsTraverser(boundNames)      ivt.traverseTrees(List(member))      ivt.importVars.toList    }    val boundNames: List[Name] = Nil    def valAndVarNames: List[Name] = Nil    def defNames: List[Name] = Nil    val importsWildcard = false    val importedNames: Seq[Name] = Nil    val definesImplicit =       member match {        case tree:MemberDef =>                tree.mods.hasFlag(symtab.Flags.IMPLICIT)        case _ => false      }    def extraCodeToEvaluate(req: Request, code: PrintWriter) { }    def resultExtractionCode(req: Request, code: PrintWriter) { }  }  private class GenericHandler(member: Tree) extends MemberHandler(member)  private class ValHandler(member: ValDef) extends MemberHandler(member) {    override val boundNames = List(member.name)    override def valAndVarNames = boundNames        override def resultExtractionCode(req: Request, code: PrintWriter) {      val vname = member.name      if (member.mods.isPublic &&          !(isGeneratedVarName(vname) &&            req.typeOf(compiler.encode(vname)) == "Unit"))      {        val prettyName = NameTransformer.decode(vname)        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\") ")      }    }  }  private class DefHandler(defDef: DefDef) extends MemberHandler(defDef) {    override val boundNames = List(defDef.name)    override def defNames = boundNames    override def resultExtractionCode(req: Request, code: PrintWriter) {

⌨️ 快捷键说明

复制代码Ctrl + C
搜索代码Ctrl + F
全屏模式F11
增大字号Ctrl + =
减小字号Ctrl + -
显示快捷键?