summaryrefslogtreecommitdiff
path: root/examples/scala-js/ir/src/main/scala/scala/scalajs/ir/Printers.scala
diff options
context:
space:
mode:
Diffstat (limited to 'examples/scala-js/ir/src/main/scala/scala/scalajs/ir/Printers.scala')
-rw-r--r--examples/scala-js/ir/src/main/scala/scala/scalajs/ir/Printers.scala709
1 files changed, 709 insertions, 0 deletions
diff --git a/examples/scala-js/ir/src/main/scala/scala/scalajs/ir/Printers.scala b/examples/scala-js/ir/src/main/scala/scala/scalajs/ir/Printers.scala
new file mode 100644
index 0000000..6208d5f
--- /dev/null
+++ b/examples/scala-js/ir/src/main/scala/scala/scalajs/ir/Printers.scala
@@ -0,0 +1,709 @@
+/* __ *\
+** ________ ___ / / ___ __ ____ Scala.js IR **
+** / __/ __// _ | / / / _ | __ / // __/ (c) 2014, LAMP/EPFL **
+** __\ \/ /__/ __ |/ /__/ __ |/_// /_\ \ http://scala-js.org/ **
+** /____/\___/_/ |_/____/_/ | |__/ /____/ **
+** |/____/ **
+\* */
+
+
+package scala.scalajs.ir
+
+import scala.annotation.{switch, tailrec}
+
+import java.io.Writer
+
+import Position._
+import Trees._
+import Types._
+import Infos._
+import Utils.escapeJS
+
+object Printers {
+
+ /** Basically copied from scala.reflect.internal.Printers */
+ trait IndentationManager {
+ protected val out: Writer
+
+ protected var indentMargin = 0
+ protected val indentStep = 2
+ protected var indentString = " " // 40
+
+ protected def indent(): Unit = indentMargin += indentStep
+ protected def undent(): Unit = indentMargin -= indentStep
+
+ protected def println(): Unit = {
+ out.write('\n')
+ while (indentMargin > indentString.length())
+ indentString += indentString
+ if (indentMargin > 0)
+ out.write(indentString, 0, indentMargin)
+ }
+
+ @tailrec
+ protected final def printSeq[A](ls: List[A])(printelem: A => Unit)(
+ printsep: A => Unit): Unit = {
+ ls match {
+ case Nil =>
+ case x :: Nil =>
+ printelem(x)
+ case x :: rest =>
+ printelem(x)
+ printsep(x)
+ printSeq(rest)(printelem)(printsep)
+ }
+ }
+
+ protected def printColumn(ts: List[Any], start: String, sep: String,
+ end: String): Unit = {
+ print(start); indent(); println()
+ printSeq(ts) { x =>
+ print(x)
+ } { _ =>
+ print(sep)
+ println()
+ }
+ undent(); println(); print(end)
+ }
+
+ protected def printRow(ts: List[Any], start: String, sep: String,
+ end: String): Unit = {
+ print(start)
+ printSeq(ts) { x =>
+ print(x)
+ } { _ =>
+ print(sep)
+ }
+ print(end)
+ }
+
+ protected def printRow(ts: List[Any], sep: String): Unit =
+ printRow(ts, "", sep, "")
+
+ protected def print(args: Any*): Unit =
+ args.foreach(printOne)
+
+ protected def printOne(arg: Any): Unit
+ }
+
+ class IRTreePrinter(protected val out: Writer) extends IndentationManager {
+ def printTopLevelTree(tree: Tree) {
+ tree match {
+ case Skip() =>
+ // do not print anything
+ case Block(stats) =>
+ for (stat <- stats)
+ printTopLevelTree(stat)
+ case _ =>
+ printTree(tree)
+ println()
+ }
+ }
+
+ protected def printBlock(tree: Tree): Unit = {
+ val trees = tree match {
+ case Block(trees) => trees
+ case _ => List(tree)
+ }
+ printColumn(trees, "{", ";", "}")
+ }
+
+ protected def printSig(args: List[ParamDef], resultType: Type): Unit = {
+ printRow(args, "(", ", ", ")")
+ if (resultType != NoType)
+ print(": ", resultType, " = ")
+ else
+ print(" ")
+ }
+
+ protected def printArgs(args: List[Tree]): Unit = {
+ printRow(args, "(", ", ", ")")
+ }
+
+ def printTree(tree: Tree): Unit = {
+ tree match {
+ case EmptyTree =>
+ print("<empty>")
+
+ // Definitions
+
+ case VarDef(ident, vtpe, mutable, rhs) =>
+ if (mutable)
+ print("var ")
+ else
+ print("val ")
+ print(ident, ": ", vtpe)
+ if (rhs != EmptyTree)
+ print(" = ", rhs)
+
+ case ParamDef(ident, ptpe, mutable) =>
+ if (mutable)
+ print("var ")
+ print(ident, ": ", ptpe)
+
+ // Control flow constructs
+
+ case Skip() =>
+ print("/*<skip>*/")
+
+ case tree: Block =>
+ printBlock(tree)
+
+ case Labeled(label, tpe, body) =>
+ print(label)
+ if (tpe != NoType)
+ print("[", tpe, "]")
+ print(": ")
+ printBlock(body)
+
+ case Assign(lhs, rhs) =>
+ print(lhs, " = ", rhs)
+
+ case Return(expr, label) =>
+ if (label.isEmpty) print("return ", expr)
+ else print("return(", label.get, ") ", expr)
+
+ case If(cond, BooleanLiteral(true), elsep) =>
+ print(cond, " || ", elsep)
+ case If(cond, thenp, BooleanLiteral(false)) =>
+ print(cond, " && ", thenp)
+
+ case If(cond, thenp, elsep) =>
+ print("if (", cond, ") ")
+ printBlock(thenp)
+ elsep match {
+ case Skip() => ()
+ case If(_, _, _) =>
+ print(" else ")
+ printTree(elsep)
+ case _ =>
+ print(" else ")
+ printBlock(elsep)
+ }
+
+ case While(cond, body, label) =>
+ if (label.isDefined)
+ print(label.get, ": ")
+ print("while (", cond, ") ")
+ printBlock(body)
+
+ case DoWhile(body, cond, label) =>
+ if (label.isDefined)
+ print(label.get, ": ")
+ print("do ")
+ printBlock(body)
+ print(" while (", cond, ")")
+
+ case Try(block, errVar, handler, finalizer) =>
+ print("try ")
+ printBlock(block)
+ if (handler != EmptyTree) {
+ print(" catch (", errVar, ") ")
+ printBlock(handler)
+ }
+ if (finalizer != EmptyTree) {
+ print(" finally ")
+ printBlock(finalizer)
+ }
+
+ case Throw(expr) =>
+ print("throw ", expr)
+
+ case Continue(label) =>
+ if (label.isEmpty) print("continue")
+ else print("continue ", label.get)
+
+ case Match(selector, cases, default) =>
+ print("match (", selector, ") ")
+ print("{"); indent
+ for ((values, body) <- cases) {
+ println()
+ printRow(values, "case ", " | ", ":"); indent; println()
+ printTree(body)
+ print(";")
+ undent
+ }
+ if (default != EmptyTree) {
+ println()
+ print("default:"); indent; println()
+ printTree(default)
+ print(";")
+ undent
+ }
+ undent; println(); print("}")
+
+ case Debugger() =>
+ print("debugger")
+
+ // Scala expressions
+
+ case New(cls, ctor, args) =>
+ print("new ", cls, "().", ctor)
+ printArgs(args)
+
+ case LoadModule(cls) =>
+ print("mod:", cls)
+
+ case StoreModule(cls, value) =>
+ print("mod:", cls, "<-", value)
+
+ case Select(qualifier, item, _) =>
+ print(qualifier, ".", item)
+
+ case Apply(receiver, method, args) =>
+ print(receiver, ".", method)
+ printArgs(args)
+
+ case StaticApply(receiver, cls, method, args) =>
+ print(receiver, ".", cls, "::", method)
+ printArgs(args)
+
+ case TraitImplApply(impl, method, args) =>
+ print(impl, "::", method)
+ printArgs(args)
+
+ case UnaryOp(op, lhs) =>
+ import UnaryOp._
+ print("(", (op: @switch) match {
+ case `typeof` => "typeof"
+ case Boolean_! => "!"
+ case IntToLong | DoubleToLong => "(long)"
+ case DoubleToInt | LongToInt => "(int)"
+ case DoubleToFloat => "(float)"
+ case LongToDouble => "(double)"
+ }, lhs, ")")
+
+ case BinaryOp(BinaryOp.Int_-, IntLiteral(0), rhs) =>
+ print("(-", rhs, ")")
+ case BinaryOp(BinaryOp.Int_^, IntLiteral(-1), rhs) =>
+ print("(~", rhs, ")")
+ case BinaryOp(BinaryOp.Long_-, LongLiteral(0L), rhs) =>
+ print("(-", rhs, ")")
+ case BinaryOp(BinaryOp.Long_^, LongLiteral(-1L), rhs) =>
+ print("(~", rhs, ")")
+ case BinaryOp(BinaryOp.Float_-, FloatLiteral(0.0f), rhs) =>
+ print("(-", rhs, ")")
+ case BinaryOp(BinaryOp.Double_-,
+ IntLiteral(0) | FloatLiteral(0.0f) | DoubleLiteral(0.0), rhs) =>
+ print("(-", rhs, ")")
+
+ case BinaryOp(op, lhs, rhs) =>
+ import BinaryOp._
+ print("(", lhs, " ", (op: @switch) match {
+ case === => "==="
+ case !== => "!=="
+
+ case String_+ => "+[string]"
+
+ case `in` => "in"
+ case `instanceof` => "instanceof"
+
+ case Int_+ => "+[int]"
+ case Int_- => "-[int]"
+ case Int_* => "*[int]"
+ case Int_/ => "/[int]"
+ case Int_% => "%[int]"
+
+ case Int_| => "|"
+ case Int_& => "&"
+ case Int_^ => "^"
+ case Int_<< => "<<"
+ case Int_>>> => ">>>"
+ case Int_>> => ">>"
+
+ case Float_+ => "+[float]"
+ case Float_- => "-[float]"
+ case Float_* => "*[float]"
+ case Float_/ => "/[float]"
+ case Float_% => "%[float]"
+
+ case Double_+ => "+"
+ case Double_- => "-"
+ case Double_* => "*"
+ case Double_/ => "/"
+ case Double_% => "%"
+
+ case Num_== => "=="
+ case Num_!= => "!="
+ case Num_< => "<"
+ case Num_<= => "<="
+ case Num_> => ">"
+ case Num_>= => ">="
+
+ case Long_+ => "+[long]"
+ case Long_- => "-[long]"
+ case Long_* => "*[long]"
+ case Long_/ => "/[long]"
+ case Long_% => "%[long]"
+
+ case Long_| => "|[long]"
+ case Long_& => "&[long]"
+ case Long_^ => "^[long]"
+ case Long_<< => "<<[long]"
+ case Long_>>> => ">>>[long]"
+ case Long_>> => ">>[long]"
+
+ case Long_== => "==[long]"
+ case Long_!= => "!=[long]"
+ case Long_< => "<[long]"
+ case Long_<= => "<=[long]"
+ case Long_> => ">[long]"
+ case Long_>= => ">=[long]"
+
+ case Boolean_== => "==[bool]"
+ case Boolean_!= => "!=[bool]"
+ case Boolean_| => "|[bool]"
+ case Boolean_& => "&[bool]"
+ }, " ", rhs, ")")
+
+ case NewArray(tpe, lengths) =>
+ print("new ", tpe.baseClassName)
+ for (length <- lengths)
+ print("[", length, "]")
+ for (dim <- lengths.size until tpe.dimensions)
+ print("[]")
+
+ case ArrayValue(tpe, elems) =>
+ print(tpe)
+ printArgs(elems)
+
+ case ArrayLength(array) =>
+ print(array, ".length")
+
+ case ArraySelect(array, index) =>
+ print(array, "[", index, "]")
+
+ case RecordValue(tpe, elems) =>
+ print("(")
+ var first = true
+ for ((field, value) <- tpe.fields zip elems) {
+ if (first) first = false
+ else print(", ")
+ print(field.name, " = ", value)
+ }
+ print(")")
+
+ case IsInstanceOf(expr, cls) =>
+ print(expr, ".isInstanceOf[", cls, "]")
+
+ case AsInstanceOf(expr, cls) =>
+ print(expr, ".asInstanceOf[", cls, "]")
+
+ case Unbox(expr, charCode) =>
+ print(expr, ".asInstanceOf[", charCode, "]")
+
+ case GetClass(expr) =>
+ print(expr, ".getClass()")
+
+ case CallHelper(helper, args) =>
+ print(helper)
+ printArgs(args)
+
+ // JavaScript expressions
+
+ case JSNew(ctor, args) =>
+ def containsOnlySelectsFromAtom(tree: Tree): Boolean = tree match {
+ case JSDotSelect(qual, _) => containsOnlySelectsFromAtom(qual)
+ case JSBracketSelect(qual, _) => containsOnlySelectsFromAtom(qual)
+ case VarRef(_, _) => true
+ case This() => true
+ case _ => false // in particular, Apply
+ }
+ if (containsOnlySelectsFromAtom(ctor))
+ print("new ", ctor)
+ else
+ print("new (", ctor, ")")
+ printArgs(args)
+
+ case JSDotSelect(qualifier, item) =>
+ print(qualifier, ".", item)
+
+ case JSBracketSelect(qualifier, item) =>
+ print(qualifier, "[", item, "]")
+
+ case JSFunctionApply(fun, args) =>
+ fun match {
+ case _:JSDotSelect | _:JSBracketSelect | _:Select =>
+ print("protect(", fun, ")")
+ case _ =>
+ print(fun)
+ }
+ printArgs(args)
+
+ case JSDotMethodApply(receiver, method, args) =>
+ print(receiver, ".", method)
+ printArgs(args)
+
+ case JSBracketMethodApply(receiver, method, args) =>
+ print(receiver, "[", method, "]")
+ printArgs(args)
+
+ case JSDelete(prop) =>
+ print("delete ", prop)
+
+ case JSUnaryOp("typeof", lhs) =>
+ print("typeof(", lhs, ")")
+
+ case JSUnaryOp(op, lhs) =>
+ print("(", op, lhs, ")")
+
+ case JSBinaryOp(op, lhs, rhs) =>
+ print("(", lhs, " ", op, " ", rhs, ")")
+
+ case JSArrayConstr(items) =>
+ printRow(items, "[", ", ", "]")
+
+ case JSObjectConstr(Nil) =>
+ print("{}")
+
+ case JSObjectConstr(fields) =>
+ print("{"); indent; println()
+ printSeq(fields) {
+ case (name, value) => print(name, ": ", value)
+ } { _ =>
+ print(",")
+ println()
+ }
+ undent; println(); print("}")
+
+ case JSEnvInfo() =>
+ print("<envinfo>")
+
+ // Literals
+
+ case Undefined() =>
+ print("(void 0)")
+
+ case UndefinedParam() =>
+ print("<undefined param>")
+
+ case Null() =>
+ print("null")
+
+ case BooleanLiteral(value) =>
+ print(if (value) "true" else "false")
+
+ case IntLiteral(value) =>
+ if (value >= 0)
+ print(value)
+ else
+ print("(", value, ")")
+
+ case FloatLiteral(value) =>
+ if (value == 0.0f && 1.0f / value < 0.0f)
+ print("(-0)")
+ else if (value >= 0.0f)
+ print(value)
+ else
+ print("(", value, ")")
+
+ case DoubleLiteral(value) =>
+ if (value == 0.0 && 1.0 / value < 0.0)
+ print("(-0)")
+ else if (value >= 0.0)
+ print(value)
+ else
+ print("(", value, ")")
+
+ case StringLiteral(value) =>
+ print("\"", escapeJS(value), "\"")
+
+ case ClassOf(cls) =>
+ print("classOf[", cls, "]")
+
+ // Atomic expressions
+
+ case VarRef(ident, _) =>
+ print(ident)
+
+ case This() =>
+ print("this")
+
+ case Closure(captureParams, params, body, captureValues) =>
+ print("(lambda")
+ printRow(captureValues, "<", ", ", ">")
+ printRow(captureParams ++ params, "(", ", ", ") = ")
+ printBlock(body)
+ print(")")
+
+ // Classes
+
+ case ClassDef(name, kind, parent, ancestors, defs) =>
+ kind match {
+ case ClassKind.Class => print("class ")
+ case ClassKind.ModuleClass => print("module class ")
+ case ClassKind.Interface => print("interface ")
+ case ClassKind.RawJSType => print("jstype ")
+ case ClassKind.HijackedClass => print("hijacked class ")
+ case ClassKind.TraitImpl => print("trait impl ")
+ }
+ print(name)
+ parent.foreach(print(" extends ", _))
+ if (ancestors.nonEmpty)
+ printRow(ancestors, " ancestors ", ", ", "")
+ print(" ")
+ printColumn(defs, "{", "", "}")
+ println()
+
+ case MethodDef(name, args, resultType, body) =>
+ print(name)
+ printSig(args, resultType)
+ printBlock(body)
+
+ case PropertyDef(name, _, _, _) =>
+ // TODO
+ print(s"<property: $name>")
+
+ case ConstructorExportDef(fullName, args, body) =>
+ print("export \"", escapeJS(fullName), "\"")
+ printSig(args, NoType) // NoType as trick not to display a type
+ printBlock(body)
+
+ case ModuleExportDef(fullName) =>
+ print("export \"", escapeJS(fullName), "\"")
+
+ case _ =>
+ print(s"<error, elem of class ${tree.getClass()}>")
+ }
+ }
+
+ def printType(tpe: Type): Unit = tpe match {
+ case AnyType => print("any")
+ case NothingType => print("nothing")
+ case UndefType => print("void")
+ case BooleanType => print("boolean")
+ case IntType => print("int")
+ case LongType => print("long")
+ case FloatType => print("float")
+ case DoubleType => print("number")
+ case StringType => print("string")
+ case NullType => print("null")
+ case ClassType(className) => print(className)
+ case NoType => print("<notype>")
+
+ case ArrayType(base, dims) =>
+ print(base)
+ for (i <- 1 to dims)
+ print("[]")
+
+ case RecordType(fields) =>
+ print("(")
+ var first = false
+ for (RecordType.Field(name, _, tpe, mutable) <- fields) {
+ if (first) first = false
+ else print(", ")
+ if (mutable)
+ print("var ")
+ print(name, ": ", tpe)
+ }
+ print(")")
+ }
+
+ protected def printIdent(ident: Ident): Unit =
+ printString(escapeJS(ident.name))
+
+ protected def printOne(arg: Any): Unit = arg match {
+ case tree: Tree =>
+ printTree(tree)
+ case tpe: Type =>
+ printType(tpe)
+ case ident: Ident =>
+ printIdent(ident)
+ case arg =>
+ printString(if (arg == null) "null" else arg.toString)
+ }
+
+ protected def printString(s: String): Unit = {
+ out.write(s)
+ }
+
+ // Make it public
+ override def println(): Unit = super.println()
+
+ def complete(): Unit = ()
+ }
+
+ class InfoPrinter(protected val out: Writer) extends IndentationManager {
+ def printClassInfo(classInfo: ClassInfo): Unit = {
+ import classInfo._
+ println("name: ", escapeJS(name))
+ println("encodedName: ", escapeJS(encodedName))
+ println("isExported: ", isExported)
+ println("ancestorCount: ", ancestorCount)
+ println("kind: ", kind)
+ println("superClass: ", superClass)
+
+ if (ancestors.nonEmpty) {
+ println("ancestors: ",
+ ancestors.map(escapeJS).mkString("[", ", ", "]"))
+ }
+
+ if (optimizerHints != OptimizerHints.empty)
+ println("optimizerHints: ", optimizerHints)
+
+ print("methods:")
+ indent(); println()
+ methods.foreach(printMethodInfo)
+ undent(); println()
+ }
+
+ def printMethodInfo(methodInfo: MethodInfo): Unit = {
+ import methodInfo._
+ print(escapeJS(encodedName), ":")
+ indent(); println()
+
+ if (isAbstract)
+ println("isAbstract: ", isAbstract)
+ if (isExported)
+ println("isExported: ", isExported)
+ if (calledMethods.nonEmpty) {
+ print("calledMethods:")
+ indent(); println()
+ printSeq(calledMethods.toList) { case (caller, callees) =>
+ print(escapeJS(caller), ": ")
+ print(callees.map(escapeJS).mkString("[", ", ", "]"))
+ } { _ => println() }
+ undent(); println()
+ }
+ if (calledMethodsStatic.nonEmpty) {
+ print("calledMethodsStatic:")
+ indent(); println()
+ printSeq(calledMethodsStatic.toList) { case (caller, callees) =>
+ print(escapeJS(caller), ": ")
+ print(callees.map(escapeJS).mkString("[", ", ", "]"))
+ } { _ => println() }
+ undent(); println()
+ }
+ if (instantiatedClasses.nonEmpty) {
+ println("instantiatedClasses: ",
+ instantiatedClasses.map(escapeJS).mkString("[", ", ", "]"))
+ }
+ if (accessedModules.nonEmpty) {
+ println("accessedModules: ",
+ accessedModules.map(escapeJS).mkString("[", ", ", "]"))
+ }
+ if (accessedClassData.nonEmpty) {
+ println("accessedClassData: ",
+ accessedClassData.map(escapeJS).mkString("[", ", ", "]"))
+ }
+ if (optimizerHints != OptimizerHints.empty)
+ println("optimizerHints: ", optimizerHints)
+
+ undent(); println()
+ }
+
+ private def println(arg1: Any, args: Any*): Unit = {
+ print((arg1 +: args): _*)
+ println()
+ }
+
+ protected def printOne(arg: Any): Unit = arg match {
+ case classInfo: ClassInfo => printClassInfo(classInfo)
+ case methodInfo: MethodInfo => printMethodInfo(methodInfo)
+ case arg => out.write(arg.toString())
+ }
+
+ def complete(): Unit = ()
+ }
+
+}