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/cli/src/main/scala/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/cli/src/main/scala/scala')
-rw-r--r-- | examples/scala-js/cli/src/main/scala/scala/scalajs/cli/Scalajsld.scala | 180 | ||||
-rw-r--r-- | examples/scala-js/cli/src/main/scala/scala/scalajs/cli/Scalajsp.scala | 158 |
2 files changed, 338 insertions, 0 deletions
diff --git a/examples/scala-js/cli/src/main/scala/scala/scalajs/cli/Scalajsld.scala b/examples/scala-js/cli/src/main/scala/scala/scalajs/cli/Scalajsld.scala new file mode 100644 index 0000000..55e61af --- /dev/null +++ b/examples/scala-js/cli/src/main/scala/scala/scalajs/cli/Scalajsld.scala @@ -0,0 +1,180 @@ +/* __ *\ +** ________ ___ / / ___ __ ____ Scala.js CLI ** +** / __/ __// _ | / / / _ | __ / // __/ (c) 2013-2014, LAMP/EPFL ** +** __\ \/ /__/ __ |/ /__/ __ |/_// /_\ \ http://scala-js.org/ ** +** /____/\___/_/ |_/____/_/ | |__/ /____/ ** +** |/____/ ** +\* */ + + +package scala.scalajs.cli + +import scala.scalajs.ir.ScalaJSVersions + +import scala.scalajs.tools.sem._ +import scala.scalajs.tools.io._ +import scala.scalajs.tools.logging._ +import scala.scalajs.tools.classpath._ +import scala.scalajs.tools.classpath.builder._ + +import CheckedBehavior.Compliant + +import scala.scalajs.tools.optimizer.{ + ScalaJSOptimizer, + ScalaJSClosureOptimizer, + ParIncOptimizer +} + +import scala.collection.immutable.Seq + +import java.io.File +import java.net.URI + +object Scalajsld { + + case class Options( + cp: Seq[File] = Seq.empty, + output: File = null, + jsoutput: Option[File] = None, + semantics: Semantics = Semantics.Defaults, + noOpt: Boolean = false, + fullOpt: Boolean = false, + prettyPrint: Boolean = false, + sourceMap: Boolean = false, + relativizeSourceMap: Option[URI] = None, + checkIR: Boolean = false, + stdLib: Option[File] = None, + logLevel: Level = Level.Info) + + def main(args: Array[String]): Unit = { + val parser = new scopt.OptionParser[Options]("scalajsld") { + head("scalajsld", ScalaJSVersions.current) + arg[File]("<value> ...") + .unbounded() + .action { (x, c) => c.copy(cp = c.cp :+ x) } + .text("Entries of Scala.js classpath to link") + opt[File]('o', "output") + .valueName("<file>") + .required() + .action { (x, c) => c.copy(output = x) } + .text("Output file of linker (required)") + opt[File]("jsoutput") + .valueName("<file>") + .abbr("jo") + .action { (x, c) => c.copy(jsoutput = Some(x)) } + .text("Concatenate all JavaScript libary dependencies to this file") + opt[Unit]('f', "fastOpt") + .action { (_, c) => c.copy(noOpt = false, fullOpt = false) } + .text("Optimize code (this is the default)") + opt[Unit]('n', "noOpt") + .action { (_, c) => c.copy(noOpt = true, fullOpt = false) } + .text("Don't optimize code") + opt[Unit]('u', "fullOpt") + .action { (_, c) => c.copy(noOpt = false, fullOpt = true) } + .text("Fully optimize code (uses Google Closure Compiler)") + opt[Unit]('p', "prettyPrint") + .action { (_, c) => c.copy(prettyPrint = true) } + .text("Pretty print full opted code (meaningful with -u)") + opt[Unit]('s', "sourceMap") + .action { (_, c) => c.copy(sourceMap = true) } + .text("Produce a source map for the produced code") + opt[Unit]("compliantAsInstanceOfs") + .action { (_, c) => c.copy(semantics = + c.semantics.withAsInstanceOfs(Compliant)) + } + .text("Use compliant asInstanceOfs") + opt[Unit]('c', "checkIR") + .action { (_, c) => c.copy(checkIR = true) } + .text("Check IR before optimizing") + opt[File]('r', "relativizeSourceMap") + .valueName("<path>") + .action { (x, c) => c.copy(relativizeSourceMap = Some(x.toURI)) } + .text("Relativize source map with respect to given path (meaningful with -s)") + opt[Unit]("noStdlib") + .action { (_, c) => c.copy(stdLib = None) } + .text("Don't automatcially include Scala.js standard library") + opt[File]("stdlib") + .valueName("<scala.js stdlib jar>") + .hidden() + .action { (x, c) => c.copy(stdLib = Some(x)) } + .text("Location of Scala.js standard libarary. This is set by the " + + "runner script and automatically prepended to the classpath. " + + "Use -n to not include it.") + opt[Unit]('d', "debug") + .action { (_, c) => c.copy(logLevel = Level.Debug) } + .text("Debug mode: Show full log") + opt[Unit]('q', "quiet") + .action { (_, c) => c.copy(logLevel = Level.Warn) } + .text("Only show warnings & errors") + opt[Unit]("really-quiet") + .abbr("qq") + .action { (_, c) => c.copy(logLevel = Level.Error) } + .text("Only show errors") + version("version") + .abbr("v") + .text("Show scalajsld version") + help("help") + .abbr("h") + .text("prints this usage text") + + override def showUsageOnError = true + } + + for (options <- parser.parse(args, Options())) { + val cpFiles = options.stdLib.toList ++ options.cp + // Load and resolve classpath + val cp = PartialClasspathBuilder.build(cpFiles).resolve() + + // Write JS dependencies if requested + for (jsout <- options.jsoutput) + IO.concatFiles(WritableFileVirtualJSFile(jsout), cp.jsLibs.map(_.lib)) + + // Link Scala.js code + val outFile = WritableFileVirtualJSFile(options.output) + if (options.fullOpt) + fullOpt(cp, outFile, options) + else + fastOpt(cp, outFile, options) + } + } + + private def fullOpt(cp: IRClasspath, + output: WritableVirtualJSFile, options: Options) = { + import ScalaJSClosureOptimizer._ + + val semantics = options.semantics.optimized + + new ScalaJSClosureOptimizer(semantics).optimizeCP( + newScalaJSOptimizer(semantics), + Inputs(ScalaJSOptimizer.Inputs(cp)), + OutputConfig( + output = output, + wantSourceMap = options.sourceMap, + relativizeSourceMapBase = options.relativizeSourceMap, + checkIR = options.checkIR, + prettyPrint = options.prettyPrint), + newLogger(options)) + } + + private def fastOpt(cp: IRClasspath, + output: WritableVirtualJSFile, options: Options) = { + import ScalaJSOptimizer._ + + newScalaJSOptimizer(options.semantics).optimizeCP( + Inputs(cp), + OutputConfig( + output = output, + wantSourceMap = options.sourceMap, + checkIR = options.checkIR, + disableOptimizer = options.noOpt, + relativizeSourceMapBase = options.relativizeSourceMap), + newLogger(options)) + } + + private def newLogger(options: Options) = + new ScalaConsoleLogger(options.logLevel) + + private def newScalaJSOptimizer(semantics: Semantics) = + new ScalaJSOptimizer(semantics, new ParIncOptimizer(_)) + +} diff --git a/examples/scala-js/cli/src/main/scala/scala/scalajs/cli/Scalajsp.scala b/examples/scala-js/cli/src/main/scala/scala/scalajs/cli/Scalajsp.scala new file mode 100644 index 0000000..0d64b93 --- /dev/null +++ b/examples/scala-js/cli/src/main/scala/scala/scalajs/cli/Scalajsp.scala @@ -0,0 +1,158 @@ +/* __ *\ +** ________ ___ / / ___ __ ____ Scala.js CLI ** +** / __/ __// _ | / / / _ | __ / // __/ (c) 2013-2014, LAMP/EPFL ** +** __\ \/ /__/ __ |/ /__/ __ |/_// /_\ \ http://scala-js.org/ ** +** /____/\___/_/ |_/____/_/ | |__/ /____/ ** +** |/____/ ** +\* */ + + +package scala.scalajs.cli + +import scala.scalajs.ir +import ir.ScalaJSVersions +import ir.Trees.{Tree, ClassDef} +import ir.Printers.{InfoPrinter, IRTreePrinter} + +import scala.scalajs.tools.sem.Semantics +import scala.scalajs.tools.javascript +import javascript.ScalaJSClassEmitter +import javascript.Printers.JSTreePrinter + +import scala.scalajs.tools.io._ +import scala.collection.immutable.Seq + +import java.io.{Console => _, _} +import java.util.zip.{ZipFile, ZipEntry} + +object Scalajsp { + + case class Options( + infos: Boolean = false, + desugar: Boolean = false, + showReflProxy: Boolean = false, + jar: Option[File] = None, + fileNames: Seq[String] = Seq.empty) + + def main(args: Array[String]): Unit = { + val parser = new scopt.OptionParser[Options]("scalajsp") { + head("scalajsp", ScalaJSVersions.current) + arg[String]("<file> ...") + .unbounded() + .action { (x, c) => c.copy(fileNames = c.fileNames :+ x) } + .text("*.sjsir file to display content of") + opt[File]('j', "jar") + .valueName("<jar>") + .action { (x, c) => c.copy(jar = Some(x)) } + .text("Read *.sjsir file(s) from the given JAR.") + opt[Unit]('d', "desugar") + .action { (_, c) => c.copy(desugar = true) } + .text("Desugar JS trees. This yields runnable JavaScript") + opt[Unit]('i', "infos") + .action { (_, c) => c.copy(infos = true) } + .text("Show DCE infos instead of trees") + opt[Unit]('p', "reflProxies") + .action { (_, c) => c.copy(showReflProxy = true) } + .text("Show reflective call proxies") + opt[Unit]('s', "supported") + .action { (_,_) => printSupported(); sys.exit() } + .text("Show supported Scala.js IR versions") + version("version") + .abbr("v") + .text("Show scalajsp version") + help("help") + .abbr("h") + .text("prints this usage text") + + override def showUsageOnError = true + } + + for { + options <- parser.parse(args, Options()) + fileName <- options.fileNames + } { + val vfile = options.jar map { jar => + readFromJar(jar, fileName) + } getOrElse { + readFromFile(fileName) + } + + displayFileContent(vfile, options) + } + } + + def printSupported(): Unit = { + import ScalaJSVersions._ + println(s"Emitted Scala.js IR version is: $binaryEmitted") + println("Supported Scala.js IR versions are") + binarySupported.foreach(v => println(s"* $v")) + } + + def displayFileContent(vfile: VirtualScalaJSIRFile, opts: Options): Unit = { + if (opts.infos) + new InfoPrinter(stdout).printClassInfo(vfile.info) + else { + val outTree = { + if (opts.showReflProxy) vfile.tree + else filterOutReflProxies(vfile.tree) + } + + if (opts.desugar) + new JSTreePrinter(stdout).printTopLevelTree( + new ScalaJSClassEmitter(Semantics.Defaults).genClassDef(outTree)) + else + new IRTreePrinter(stdout).printTopLevelTree(outTree) + } + + stdout.flush() + } + + private def fail(msg: String) = { + Console.err.println(msg) + sys.exit(1) + } + + private def readFromFile(fileName: String) = { + val file = new File(fileName) + + if (!file.exists) + fail(s"No such file: $fileName") + else if (!file.canRead) + fail(s"Unable to read file: $fileName") + else + FileVirtualScalaJSIRFile(file) + } + + private def readFromJar(jar: File, name: String) = { + val jarFile = + try { new ZipFile(jar) } + catch { case _: FileNotFoundException => fail(s"No such JAR: $jar") } + try { + val entry = jarFile.getEntry(name) + if (entry == null) + fail(s"No such file in jar: $name") + else { + val name = jarFile.getName + "#" + entry.getName + val content = + IO.readInputStreamToByteArray(jarFile.getInputStream(entry)) + new MemVirtualSerializedScalaJSIRFile(name).withContent(content) + } + } finally { + jarFile.close() + } + } + + private val stdout = + new BufferedWriter(new OutputStreamWriter(Console.out, "UTF-8")) + + private def filterOutReflProxies(tree: ClassDef): ClassDef = { + import ir.Trees._ + import ir.Definitions.isReflProxyName + val newDefs = tree.defs.filter { + case MethodDef(Ident(name, _), _, _, _) => !isReflProxyName(name) + case _ => true + } + tree.copy(defs = newDefs)(tree.pos) + } + +} |