Many resources are needed to download a project. Please understand that we have to compensate our server costs. Thank you in advance. Project price only 1 $
You can buy this project and download/modify it how often you want.
>];")
}
val STYLE_EDGE_TYPE = "style=bold"
val STYLE_EDGE_MISC = "color=\"#404040\""
val STYLE_EDGE_POS = STYLE_EDGE_MISC
val STYLE_EDGE_SIZE = STYLE_EDGE_MISC
val STYLE_EDGE_REPEAT = STYLE_EDGE_MISC
val STYLE_EDGE_VALUE = STYLE_EDGE_MISC
def tableRow(curClass: List[String], pos: Option[String], attr: AttrLikeSpec, name: String): Unit = {
val dataType = attr.dataType
val sizeStr = dataTypeSizeAsString(dataType, name)
val dataTypeStr = dataType match {
case st: SwitchType =>
compileSwitch(name, st)
s"switch (${expressionType(st.on, name)})"
case _ =>
dataTypeName(dataType)
}
out.puts("
" +
"
" + pos.getOrElse("...") + "
" +
"
" + sizeStr + "
" +
s"
$dataTypeStr
" +
"
" + name + "
" +
"
")
// Add user type links
dataType match {
case ut: UserType =>
links += ((s"$currentTable:${name}_type", type2class(ut.name) + "__seq", STYLE_EDGE_TYPE))
case _ =>
// ignore, no links
}
val portName = name + "__repeat"
attr.cond.repeat match {
case RepeatExpr(ex) =>
out.puts("
repeat " +
expression(ex, s"$currentTable:$portName", STYLE_EDGE_REPEAT) +
" times
")
case RepeatUntil(ex) =>
provider._currentIteratorType = Some(dataType)
out.puts("
repeat until " +
expression(ex, s"$currentTable:$portName", STYLE_EDGE_REPEAT) +
"
")
case RepeatEos =>
out.puts("
repeat to end of stream
")
case NoRepeat =>
// no additional line
}
}
def tableValueInstance(curClass: List[String], name: String, inst: ValueInstanceSpec): Unit = {
currentTable = s"${type2class(curClass)}__inst__$name"
out.puts(s"$currentTable" + " [label=<
")
var lineNum = 0
st.cases.foreach { case (caseExpr, caseType) =>
caseType match {
case ut: UserType =>
val exprStr = htmlEscape(translator.translate(caseExpr))
val portName = s"case$lineNum"
lineNum += 1
extraClusterLines.puts(
"
" + exprStr + "
" + "" +
"
" + type2display(ut.name) + "
"
)
links += ((s"${currentTable}_${attrName}_switch:$portName", type2class(ut.name) + "__seq", STYLE_EDGE_TYPE))
case _ =>
// ignore, no links
}
}
extraClusterLines.dec
extraClusterLines.puts("
>];")
}
val END_OF_STREAM = "⇲"
val UNKNOWN = "..."
/**
* Determine visual interpretation of data type's size to be used in
* a displayed table.
*
* @param dataType data type to analyze
* @param attrName attribute name to be used to generate port name for affected vars linking
* @return a String that should be displayed in table's column "size"
*/
def dataTypeSizeAsString(dataType: DataType, attrName: String): String = {
dataType match {
case _: BytesEosType => END_OF_STREAM
case blt: BytesLimitType => expressionSize(blt.size, attrName)
case StrFromBytesType(basedOn, _) => dataTypeSizeAsString(basedOn, attrName)
case utb: UserTypeFromBytes => dataTypeSizeAsString(utb.bytes, attrName)
case EnumType(_, basedOn) => dataTypeSizeAsString(basedOn, attrName)
case _ =>
CalculateSeqSizes.dataTypeBitsSize(dataType) match {
case FixedSized(n) =>
if (n % 8 == 0) {
s"${n / 8}"
} else {
s"${n}b"
}
case DynamicSized => UNKNOWN
case NotCalculatedSized | StartedCalculationSized =>
throw new RuntimeException("Should never happen: problems with CalculateSeqSizes")
}
}
}
def expressionSize(ex: expr, attrName: String): String = {
expression(ex, getGraphvizNode(nowClassName, nowClass, attrName) + s":${attrName}_size", STYLE_EDGE_SIZE)
}
def expressionPos(ex: expr, attrName: String): String = {
expression(ex, getGraphvizNode(nowClassName, nowClass, attrName) + s":${attrName}_pos", STYLE_EDGE_POS)
}
def expressionType(ex: expr, attrName: String): String = {
expression(ex, getGraphvizNode(nowClassName, nowClass, attrName) + s":${attrName}_type", STYLE_EDGE_VALUE)
}
def expression(e: expr, portName: String, style: String): String = {
affectedVars(e).foreach((v) =>
links += ((v, portName, style))
)
htmlEscape(translator.translate(e))
}
def affectedVars(e: expr): List[String] = {
e match {
case expr.BoolOp(op, values) =>
values.flatMap(affectedVars).toList
case expr.BinOp(left, op, right) =>
affectedVars(left) ++ affectedVars(right)
case expr.UnaryOp(op, operand) =>
affectedVars(operand)
case expr.IfExp(condition, ifTrue, ifFalse) =>
affectedVars(condition) ++ affectedVars(ifTrue) ++ affectedVars(ifFalse)
// case expr.Dict(keys, values) =>
case expr.Compare(left, ops, right) =>
affectedVars(left) ++ affectedVars(right)
// case expr.Call(func, args) =>
case expr.IntNum(_) | expr.FloatNum(_) | expr.Str(_) | expr.Bool(_) =>
List()
case expr.EnumByLabel(enumName, label) =>
List()
case expr.EnumById(enumName, id) =>
affectedVars(id)
case expr.Attribute(value, attr) =>
val targetClass = translator.detectType(value)
targetClass match {
case t: UserType =>
// Although, technically, in a clause like "foo.bar" both "foo" and
// "bar" seem to be affecting the result, graphs seems to be more
// readable if we'll only use "bar" for referencing, without doing
// distinct link to all intermediate path walking nodes.
// Uncomment this one to get "affected" references to all
// intermediate nodes
//affectedVars(value) ++ List(resolveTypedNode(t, attr.name))
List(resolveTypedNode(t, attr.name))
case _ =>
affectedVars(value)
}
case expr.Subscript(value, idx) =>
affectedVars(value) ++ affectedVars(idx)
case SwitchType.ELSE_CONST =>
// "_" is a special const for
List()
case expr.Name(Ast.identifier("_io")) =>
// "_io" is a special const too
List()
case expr.Name(id) =>
List(resolveLocalNode(id.name))
case expr.List(elts) =>
elts.flatMap(affectedVars).toList
}
}
// def resolveNode(s: String): String = {
// s"$currentTable:${s}_type"
// }
/**
* Given a local name that should be pertinent to current class, resolve it into
* full-blown Graphviz port reference (i.e. given something `foo` should yield
* `stuff__seq:foo_type` is `foo` is a sequence element)
*
* @param s name to resolve
* @return
*/
def resolveLocalNode(s: String): String =
resolveNodeForClass(nowClassName, nowClass, s)
def resolveTypedNode(t: UserType, s: String): String = {
val className = t.name
val classSpec = t.classSpec.get
resolveNodeForClass(className, classSpec, s)
}
def resolveNodeForClass(className: List[String], cs: ClassSpec, s: String): String =
s"${getGraphvizNode(className, cs, s)}:${s}_type"
def getGraphvizNode(className: List[String], cs: ClassSpec, s: String): String = {
cs.seq.foreach { (attr) =>
val name = attr.id match {
case NamedIdentifier(attrName) =>
attrName
case NumberedIdentifier(n) =>
s"_${NumberedIdentifier.TEMPLATE}$n"
}
if (name == s) {
return s"${type2class(className)}__seq"
}
}
cs.params.foreach { (attr) =>
val name = attr.id match {
case NamedIdentifier(attrName) =>
attrName
case NumberedIdentifier(n) =>
s"_${NumberedIdentifier.TEMPLATE}$n"
}
if (name == s) {
return s"${type2class(className)}__params"
}
}
cs.instances.get(InstanceIdentifier(s)).foreach((inst) =>
return s"${type2class(className)}__inst__$s"
)
throw new RuntimeException(s"unable to resolve node '$s' in type '${type2display(className)}'")
}
def indent: String = "\t"
def outFileName(topClassName: String): String = s"$topClassName.dot"
}
object GraphvizClassCompiler extends LanguageCompilerStatic {
// FIXME: Unused, should be probably separated from LanguageCompilerStatic
override def getCompiler(
tp: ClassTypeProvider,
config: RuntimeConfig
): LanguageCompiler = ???
def type2class(name: List[String]) = name.last
def type2display(name: List[String]) = name.map(Utils.upperCamelCase).mkString("::")
def dataTypeName(dataType: DataType): String = {
dataType match {
case rt: ReadableType => rt.apiCall(None) // FIXME
case ut: UserType => type2display(ut.name)
case FixedBytesType(contents, _) => contents.map(_.formatted("%02X")).mkString(" ")
case BytesTerminatedType(terminator, include, consume, eosError, _) =>
val args = ListBuffer[String]()
if (terminator != 0)
args += s"term=$terminator"
if (include)
args += "include"
if (!consume)
args += "don't consume"
if (!eosError)
args += "ignore EOS"
args.mkString(", ")
case _: BytesType => ""
case StrFromBytesType(basedOn, encoding) =>
val bytesStr = dataTypeName(basedOn)
val comma = if (bytesStr.isEmpty) "" else ", "
s"str($bytesStr$comma$encoding)"
case EnumType(name, basedOn) =>
s"${dataTypeName(basedOn)}→${type2display(name)}"
case BitsType(width) => s"b$width"
case _ => dataType.toString
}
}
def htmlEscape(s: String): String = {
s.replaceAll("&", "&").replaceAll("<", "<").replaceAll(">", ">").replaceAll("\"", """)
}
}