/* BSD 2-Clause License - see OPAL/LICENSE for details. */
package org.opalj
package ai
package util
import scala.language.reflectiveCalls
import scala.xml.Node
import scala.xml.NodeSeq
import org.opalj.io.process
import org.opalj.br._
import org.opalj.collection.mutable.IntArrayStack
/**
* Several utility methods to facilitate the development of the abstract interpreter/
* new domains for the abstract interpreter, by creating various kinds of dumps of
* the state of the interpreter.
*
* ==Thread Safety==
* This object is thread-safe.
*
* @author Michael Eichberg
*/
object XHTML {
def styles: String =
process(this.getClass.getResourceAsStream("default.css"))(
scala.io.Source.fromInputStream(_).mkString
)
def jquery: String =
process(this.getClass.getResourceAsStream("jquery-3.6.1.min.js"))(
scala.io.Source.fromInputStream(_).mkString
)
def colResizable: String =
process(this.getClass.getResourceAsStream("colResizable-1.6.min.js"))(
scala.io.Source.fromInputStream(_).mkString
)
def createXHTML(
htmlTitle: Option[String] = None,
body: NodeSeq
): Node = {
val theTitle = htmlTitle.map(t => Seq(
{ t })).getOrElse(Seq.empty[Node])
// HTML 5 XML serialization (XHTML 5)
{ theTitle }
{ body }
}
def caption(classFile: Option[ClassFile], method: Option[Method]): String = {
val typeName = classFile.map(_.thisType.toJava).getOrElse("")
val methodName = method.map(m => m.signatureToJava(false)).getOrElse("< method >")
s"$typeName{ $methodName }"
}
def htmlify(s: String): Node = {
scala.xml.Unparsed(
s.replace("<", "<").replace(">", ">").replace("\n", "
").
replace("\t", " ")
)
}
def valueToString(value: AnyRef)(implicit ids: Option[AnyRef => Int]): String = {
if (value != null)
value.toString + ids.map("@"+_.apply(value)).getOrElse("")
else
"null@"
}
def throwableToXHTML(throwable: Throwable): scala.xml.Node = {
val node =
if (throwable.getStackTrace == null ||
throwable.getStackTrace.size == 0) {
{ throwable.getClass.getSimpleName+" "+throwable.getMessage }
} else {
val stackElements =
for { stackElement <- throwable.getStackTrace } yield {
{ stackElement.getClassName } |
{ stackElement.getMethodName } |
{ stackElement.getLineNumber } |
}
val summary = throwable.getClass.getSimpleName+" "+throwable.getMessage
{ summary }
}
if (throwable.getCause ne null) {
val causedBy = throwableToXHTML(throwable.getCause)
{ node }
caused by:
{ causedBy }
} else {
node
}
}
def instructionsToXHTML(
title: String,
instructions: { def mkString(sep: String): String }
): Node = {
{ title }: { instructions.mkString(", ") }
}
def evaluatedInstructionsToXHTML(evaluatedPCs: IntArrayStack) = {
val header = "Evaluated instructions: "+evaluatedPCs.count(_ >= 0)+"
"
val footer = ""
val subroutineStart = "Subroutine
"
val subroutineEnd = "
"
var openSubroutines = 0
val asStrings = evaluatedPCs.reverse.map {
case SUBROUTINE_START =>
openSubroutines += 1
subroutineStart
case SUBROUTINE_END =>
openSubroutines -= 1
subroutineEnd
case instruction => instruction.toString+" "
}
header+"Evaluation Order:
"+
asStrings.mkString("") +
(
if (openSubroutines > 0) {
var missingSubroutineEnds = subroutineEnd
openSubroutines -= 1
while (openSubroutines > 0) {
missingSubroutineEnds += subroutineEnd
openSubroutines -= 1
}
missingSubroutineEnds
} else
""
) +
footer+"
"
}
}