diff options
author | Haoyi Li <haoyi@haoyi-mbp.corp.dropbox.com> | 2014-11-26 00:45:31 -0800 |
---|---|---|
committer | Haoyi Li <haoyi@haoyi-mbp.corp.dropbox.com> | 2014-11-26 00:45:31 -0800 |
commit | 24f31e120f9537faede7a174bb09ee35f64e1ce4 (patch) | |
tree | 06ffc3ecc7847789008352b7e2b7c040dad48907 /examples/scala-js/partest/src/main/scala/scala/tools/nsc/MainGenericRunner.scala | |
parent | b89ce9cbf79363f8cab09186a5d7ba94bc0af02a (diff) | |
parent | 2c4b142503bd2d871e6818b5cab8c38627d9e4a0 (diff) | |
download | hands-on-scala-js-24f31e120f9537faede7a174bb09ee35f64e1ce4.tar.gz hands-on-scala-js-24f31e120f9537faede7a174bb09ee35f64e1ce4.tar.bz2 hands-on-scala-js-24f31e120f9537faede7a174bb09ee35f64e1ce4.zip |
Merge commit '2c4b142503bd2d871e6818b5cab8c38627d9e4a0' as 'examples/scala-js'
Diffstat (limited to 'examples/scala-js/partest/src/main/scala/scala/tools/nsc/MainGenericRunner.scala')
-rw-r--r-- | examples/scala-js/partest/src/main/scala/scala/tools/nsc/MainGenericRunner.scala | 220 |
1 files changed, 220 insertions, 0 deletions
diff --git a/examples/scala-js/partest/src/main/scala/scala/tools/nsc/MainGenericRunner.scala b/examples/scala-js/partest/src/main/scala/scala/tools/nsc/MainGenericRunner.scala new file mode 100644 index 0000000..6857142 --- /dev/null +++ b/examples/scala-js/partest/src/main/scala/scala/tools/nsc/MainGenericRunner.scala @@ -0,0 +1,220 @@ +package scala.tools.nsc + +/* Super hacky overriding of the MainGenericRunner used by partest */ + +import scala.scalajs.ir + +import scala.scalajs.tools.sem.Semantics +import scala.scalajs.tools.classpath._ +import scala.scalajs.tools.classpath.builder._ +import scala.scalajs.tools.logging._ +import scala.scalajs.tools.io._ +import scala.scalajs.tools.optimizer.ScalaJSOptimizer +import scala.scalajs.tools.optimizer.ScalaJSClosureOptimizer +import scala.scalajs.tools.optimizer.ParIncOptimizer +import scala.scalajs.tools.env.JSConsole + +import scala.scalajs.sbtplugin.env.rhino.RhinoJSEnv +import scala.scalajs.sbtplugin.env.nodejs.NodeJSEnv +import scala.scalajs.sbtplugin.JSUtils._ + +import scala.tools.partest.scalajs.ScalaJSPartestOptions._ + +import java.io.File +import scala.io.Source + +import Properties.{ versionString, copyrightString } +import GenericRunnerCommand._ + +class ScalaConsoleJSConsole extends JSConsole { + def log(msg: Any) = scala.Console.out.println(msg.toString) +} + +class MainGenericRunner { + def errorFn(ex: Throwable): Boolean = { + ex.printStackTrace() + false + } + def errorFn(str: String): Boolean = { + scala.Console.err println str + false + } + + val optMode = OptMode.fromId(sys.props("scalajs.partest.optMode")) + + def noWarnMissing = { + import ScalaJSOptimizer._ + + for { + fname <- sys.props.get("scalajs.partest.noWarnFile").toList + line <- Source.fromFile(fname).getLines + if !line.startsWith("#") + } yield line.split('.') match { + case Array(className) => NoWarnClass(className) + case Array(className, methodName) => NoWarnMethod(className, methodName) + } + } + + def readSemantics() = { + val opt = sys.props.get("scalajs.partest.compliantSems") + opt.fold(Semantics.Defaults) { str => + val sems = str.split(',') + Semantics.compliantTo(sems.toList) + } + } + + def process(args: Array[String]): Boolean = { + val command = new GenericRunnerCommand(args.toList, (x: String) => errorFn(x)) + import command.{ settings, howToRun, thingToRun } + + if (!command.ok) return errorFn("\n" + command.shortUsageMsg) + else if (settings.version) return errorFn("Scala code runner %s -- %s".format(versionString, copyrightString)) + else if (command.shouldStopWithInfo) return errorFn("shouldStopWithInfo") + + if (howToRun != AsObject) + return errorFn("Scala.js runner can only run an object") + + // Load basic Scala.js classpath (used for running or further packaging) + val usefulClasspathEntries = for { + url <- settings.classpathURLs + f = urlToFile(url) + if (f.isDirectory || f.getName.startsWith("scalajs-library")) + } yield f + val classpath = + PartialClasspathBuilder.build(usefulClasspathEntries).resolve() + + val logger = new ScalaConsoleLogger(Level.Warn) + val jsConsole = new ScalaConsoleJSConsole + + val mainObjName = ir.Definitions.encodeClassName(thingToRun) + val baseRunner = runnerJSFile(mainObjName, command.arguments) + val semantics = readSemantics() + + def fastOpted = fastOptimize(classpath, mainObjName, logger, semantics) + def fullOpted = fullOptimize(classpath, mainObjName, logger, + baseRunner, semantics.optimized) + + val runner = { + if (optMode == FullOpt) + fullOptRunner() + else + baseRunner + } + + val env = + if (optMode == NoOpt) new RhinoJSEnv(semantics) + else new NodeJSEnv + + val runClasspath = optMode match { + case NoOpt => classpath + case FastOpt => fastOpted + case FullOpt => fullOpted + } + + env.jsRunner(runClasspath, runner, logger, jsConsole).run() + + true + } + + private def runnerJSFile(mainObj: String, args: List[String]) = { + val jsObj = "ScalaJS.m." + mainObj + val jsArgs = argArray(args) + new MemVirtualJSFile("Generated launcher file"). + withContent(s"$jsObj().main__AT__V($jsArgs);") + } + + /** constructs a scala.Array[String] with the given elements */ + private def argArray(args: List[String]) = { + s"""ScalaJS.makeNativeArrayWrapper( + ScalaJS.d.T.getArrayOf(), + ${listToJS(args)})""" + } + + private def fastOptimize( + classpath: IRClasspath, + mainObjName: String, + logger: Logger, + semantics: Semantics) = { + import ScalaJSOptimizer._ + + val optimizer = newScalaJSOptimizer(semantics) + val output = WritableMemVirtualJSFile("partest fastOpt file") + + optimizer.optimizeCP( + Inputs(classpath, + manuallyReachable = fastOptReachable(mainObjName), + noWarnMissing = noWarnMissing + ), + OutputConfig( + output = output, + wantSourceMap = false, + checkIR = true + ), + logger) + } + + private def fastOptReachable(mainObjName: String) = { + import ScalaJSOptimizer._ + List( + ReachObject(mainObjName), + ReachMethod(mainObjName + '$', "main__AT__V", static = false) + ) + } + + private def fullOptimize( + classpath: IRClasspath, + mainObjName: String, + logger: Logger, + runner: VirtualJSFile, + semantics: Semantics) = { + import ScalaJSClosureOptimizer._ + + val fastOptimizer = newScalaJSOptimizer(semantics) + val fullOptimizer = new ScalaJSClosureOptimizer(semantics) + val output = WritableMemVirtualJSFile("partest fullOpt file") + val exportFile = fullOptExportFile(runner) + + fullOptimizer.optimizeCP(fastOptimizer, Inputs( + input = ScalaJSOptimizer.Inputs( + classpath, + manuallyReachable = fastOptReachable(mainObjName), + noWarnMissing = noWarnMissing), + additionalExports = exportFile :: Nil), + OutputConfig( + output, + checkIR = true, + wantSourceMap = false), + logger) + + } + + private def newScalaJSOptimizer(semantics: Semantics) = + new ScalaJSOptimizer(semantics, new ParIncOptimizer(_)) + + /** generates an exporter statement for the google closure compiler that runs + * what the normal test would + */ + private def fullOptExportFile(runnerFile: VirtualJSFile) = { + new MemVirtualJSFile("partest fullOpt exports").withContent( + s"""this["runFullOptPartest"] = function() { ${runnerFile.content} };""" + ) + } + + private def fullOptRunner() = new MemVirtualJSFile("partest fullOpt runner"). + withContent("runFullOptPartest();") + + private def urlToFile(url: java.net.URL) = { + try { + new File(url.toURI()) + } catch { + case e: java.net.URISyntaxException => new File(url.getPath()) + } + } +} + +object MainGenericRunner extends MainGenericRunner { + def main(args: Array[String]) { + if (!process(args)) + sys.exit(1) + } +} |