Skip to content

Commit

Permalink
#22: Support annotations in Java generator
Browse files Browse the repository at this point in the history
  • Loading branch information
Mingun committed Aug 11, 2022
1 parent 56d648b commit ccf8a0e
Show file tree
Hide file tree
Showing 3 changed files with 121 additions and 14 deletions.
62 changes: 48 additions & 14 deletions shared/src/main/scala/io/kaitai/struct/ClassCompiler.scala
Original file line number Diff line number Diff line change
Expand Up @@ -47,6 +47,7 @@ class ClassCompiler(

if (!lang.innerDocstrings)
compileClassDoc(curClass)
lang.classAnnotation(curClass)
lang.classHeader(curClass.name)
if (lang.innerDocstrings)
compileClassDoc(curClass)
Expand Down Expand Up @@ -92,14 +93,17 @@ class ClassCompiler(

// Attributes declarations and readers
val allAttrs: List[MemberSpec] =
curClass.seq ++
curClass.params ++
List(
AttrSpec(List(), RootIdentifier, CalcUserType(topClassName, None)),
AttrSpec(List(), ParentIdentifier, curClass.parentType)
) ++
ExtraAttrs.forClassSpec(curClass, lang)
compileIndexedAttrDeclarations(curClass.seq)
compileIndexedAttrDeclarations(curClass.params)
compileAttrDeclarations(allAttrs)

compileIndexedAttrReaders(curClass.seq)
compileIndexedAttrReaders(curClass.params)
compileAttrReaders(allAttrs)

curClass.toStringExpr.foreach(expr => lang.classToString(expr))
Expand Down Expand Up @@ -192,12 +196,7 @@ class ClassCompiler(
*/
def compileAttrDeclarations(attrs: List[MemberSpec]): Unit = {
attrs.foreach { (attr) =>
val isNullable = if (lang.switchBytesOnlyAsRaw) {
attr.isNullableSwitchRaw
} else {
attr.isNullable
}
lang.attributeDeclaration(attr.id, attr.dataTypeComposite, isNullable)
lang.attributeDeclaration(attr.id, attr.dataTypeComposite, isNullable(attr))
}
}

Expand All @@ -211,12 +210,45 @@ class ClassCompiler(
// FIXME: Python should have some form of attribute docs too
if (!attr.doc.isEmpty && !lang.innerDocstrings)
lang.attributeDoc(attr.id, attr.doc)
val isNullable = if (lang.switchBytesOnlyAsRaw) {
attr.isNullableSwitchRaw
} else {
attr.isNullable
}
lang.attributeReader(attr.id, attr.dataTypeComposite, isNullable)
lang.attributeReader(attr.id, attr.dataTypeComposite, isNullable(attr))
}
}

/**
* Iterates over a given list of attributes and generates attribute
* declarations for each of them, additionally annotate each field.
*
* @param attrs attribute list to traverse
*/
def compileIndexedAttrDeclarations(attrs: List[MemberSpec]): Unit = {
attrs.zipWithIndex.foreach { case (attr, index) =>
lang.attributeAnnotation(index, attr)
lang.attributeDeclaration(attr.id, attr.dataTypeComposite, isNullable(attr))
}
}

/**
* Iterates over a given list of attributes and generates attribute
* readers (AKA getters) for each of them, additionally annotate each
* getter.
*
* @param attrs attribute list to traverse
*/
def compileIndexedAttrReaders(attrs: List[MemberSpec]): Unit = {
attrs.zipWithIndex.foreach { case (attr, index) =>
// FIXME: Python should have some form of attribute docs too
if (!attr.doc.isEmpty && !lang.innerDocstrings)
lang.attributeDoc(attr.id, attr.doc)
lang.attributeAnnotation(index, attr)
lang.attributeReader(attr.id, attr.dataTypeComposite, isNullable(attr))
}
}

def isNullable(attr: MemberSpec): Boolean = {
if (lang.switchBytesOnlyAsRaw) {
attr.isNullableSwitchRaw
} else {
attr.isNullable
}
}

Expand Down Expand Up @@ -326,6 +358,7 @@ class ClassCompiler(

if (!lang.innerDocstrings)
compileInstanceDoc(instName, instSpec)
lang.instanceAnnotation(instName, instSpec, true)
lang.instanceHeader(className, instName, dataType, instSpec.isNullable)
if (lang.innerDocstrings)
compileInstanceDoc(instName, instSpec)
Expand Down Expand Up @@ -354,6 +387,7 @@ class ClassCompiler(
} else {
instSpec.isNullable
}
lang.instanceAnnotation(instName, instSpec, false)
lang.instanceDeclaration(instName, instSpec.dataTypeComposite, isNullable)
}

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -65,6 +65,21 @@ class JavaCompiler(typeProvider: ClassTypeProvider, config: RuntimeConfig)
out.puts
}

override def classAnnotation(spec: ClassSpec): Unit = {
if (!spec.isTopLevel) return;

importList.add("io.kaitai.struct.annotations.Generated")

out.puts("@Generated(")
out.inc
out.puts(s"""id = "${spec.name.last}",""")
out.puts(s"""version = "${KSVersion.current}",""")
out.puts(s"""posInfo = ${config.readStoresPos},""")
out.puts(s"""autoRead = ${config.autoRead}""")
out.dec
out.puts(")")
}

override def classHeader(name: String): Unit = {
val staticStr = if (out.indentLevel > 0) {
"static "
Expand Down Expand Up @@ -197,6 +212,32 @@ class JavaCompiler(typeProvider: ClassTypeProvider, config: RuntimeConfig)

override def readFooter(): Unit = universalFooter

override def attributeAnnotation(index: Int, attr: MemberSpec): Unit = {
attr match {
case param: ParamDefSpec => {
importList.add("io.kaitai.struct.annotations.Parameter")

out.puts(s"""@Parameter(index = ${index}, id = "${param.id.humanReadable}")""")
}
case field: AttrSpec => {
field.id match {
case NamedIdentifier(name) => {
importList.add("io.kaitai.struct.annotations.SeqItem")

out.puts(s"""@SeqItem(index = ${index}, id = "${name}")""")
}
case NumberedIdentifier(_) => {
importList.add("io.kaitai.struct.annotations.SeqItem")

out.puts(s"""@SeqItem(index = ${index})""")
}
case _ =>
}
}
case _ =>
}
}

override def attributeDeclaration(attrName: Identifier, attrType: DataType, isNullable: Boolean): Unit = {
out.puts(s"private ${kaitaiType2JavaType(attrType, isNullable)} ${idToStr(attrName)};")
}
Expand Down Expand Up @@ -656,6 +697,12 @@ class JavaCompiler(typeProvider: ClassTypeProvider, config: RuntimeConfig)

//</editor-fold>

override def instanceAnnotation(instName: InstanceIdentifier, spec: InstanceSpec, getter: Boolean): Unit = {
importList.add("io.kaitai.struct.annotations.Instance")

out.puts(s"""@Instance(id = "${instName.name}")""")
}

override def instanceDeclaration(instName: InstanceIdentifier, attrType: DataType, isNullable: Boolean): Unit = {
out.puts(s"private ${kaitaiType2JavaTypeBoxed(attrType)} ${idToStr(instName)};")
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -84,6 +84,14 @@ abstract class LanguageCompiler(
def opaqueClassDeclaration(classSpec: ClassSpec): Unit = {}

def classDoc(name: List[String], doc: DocSpec): Unit = {}
/**
* Generates additional meta-information for attribute, such as annotations in Java
* or attributes in C#. That annotations appears between documentation and main body
* of class.
*
* @param spec Specification of type
*/
def classAnnotation(spec: ClassSpec): Unit = {}
def classHeader(name: List[String]): Unit
def classFooter(name: List[String]): Unit
def classForwardDeclaration(name: List[String]): Unit = {}
Expand Down Expand Up @@ -114,6 +122,15 @@ abstract class LanguageCompiler(
*/
def readFooter(): Unit

/**
* Generates additional meta-information for an attribute or type parameter,
* such as annotations in Java or attributes in C#.
*
* @param index Sequential index of `seq` attribute/parameter in type, started from 0.
* Attributes and parameters have independent indexes
* @param attr Specification of attribute
*/
def attributeAnnotation(index: Int, attr: MemberSpec): Unit = {}
def attributeDeclaration(attrName: Identifier, attrType: DataType, isNullable: Boolean): Unit
def attributeReader(attrName: Identifier, attrType: DataType, isNullable: Boolean): Unit
def attributeDoc(id: Identifier, doc: DocSpec): Unit = {}
Expand Down Expand Up @@ -151,6 +168,15 @@ abstract class LanguageCompiler(
def popPos(io: String): Unit
def alignToByte(io: String): Unit

/**
* Generates additional meta-information for instance, such as annotations in Java
* or attributes in C#.
*
* @param instName Name of instance
* @param spec Specification of instance
* @param getter If `true`, method called for annotate value getter, otherwise for annotate storage variable
*/
def instanceAnnotation(instName: InstanceIdentifier, spec: InstanceSpec, getter: Boolean): Unit = {}
def instanceDeclHeader(className: List[String]): Unit = {}
def instanceClear(instName: InstanceIdentifier): Unit = {}
def instanceSetCalculated(instName: InstanceIdentifier): Unit = {}
Expand Down

0 comments on commit ccf8a0e

Please sign in to comment.