summaryrefslogblamecommitdiff
path: root/examples/scala-js/cli/src/main/scala/scala/scalajs/cli/Scalajsp.scala
blob: 0d64b9398778a0671931ca3670d2c358a347938d (plain) (tree)





























































































































































                                                                              
/*                     __                                               *\
**     ________ ___   / /  ___      __ ____  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)
  }

}