/* BSD 2-Clause License - see OPAL/LICENSE for details. */
package org.opalj
package ai
package util
import scala.reflect.Selectable.reflectiveSelectable
import scala.xml.Node
import scala.xml.NodeSeq
import org.opalj.br.*
import org.opalj.collection.mutable.IntArrayStack
import org.opalj.io.process
/**
* 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.length == 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 + "
"
}
}