@@ -6,13 +6,20 @@ import io.kaitai.struct.datatype.DataType.{ArrayTypeInStream, SwitchType, UserTy
66import io .kaitai .struct .format ._
77import io .kaitai .struct .translators .TypeDetector
88
9+ /**
10+ * Precompile step that calculates actual parent types of KSY-defined types
11+ * (the type of the `_parent` built-in property).
12+ */
913class ParentTypes (classSpecs : ClassSpecs ) {
1014 def run (): Unit = {
1115 classSpecs.foreach { case (_, curClass) => markup(curClass) }
16+ classSpecs.forEachTopLevel((_, spec) => {
17+ spec.parentClass = GenericStructClassSpec
18+ })
1219 }
1320
1421 def markup (curClass : ClassSpec ): Unit = {
15- Log .typeProcParent.info(() => s " markupParentTypes ( ${curClass.nameAsStr}) " )
22+ Log .typeProcParent.info(() => s " ParentTypes.markup ( ${curClass.nameAsStr}) " )
1623
1724 if (curClass.seq.nonEmpty)
1825 Log .typeProcParent.info(() => s " ... seq " )
@@ -30,30 +37,42 @@ class ParentTypes(classSpecs: ClassSpecs) {
3037 // value instances have no effect on parenting, just do nothing
3138 }
3239 }
40+
41+ if (curClass.types.nonEmpty)
42+ Log .typeProcParent.info(() => s " ... types " )
43+ curClass.types.foreach { case (_, ty) =>
44+ // If parent is not decided yet, calculate it
45+ if (ty.parentClass == UnknownClassSpec ) {
46+ markup(ty)
47+ }
48+ }
3349 }
3450
51+ /** Calculates `parent` of `dt` */
3552 private
3653 def markupParentTypesAdd (curClass : ClassSpec , dt : DataType ): Unit = {
3754 dt match {
3855 case userType : UserType =>
39- (userType.forcedParent match {
56+ userType.forcedParent match {
57+ // `parent` key is not specified in attribute
4058 case None =>
41- Some (curClass)
59+ markupParentAs(curClass, userType)
60+ // `parent: false` specified in attribute
4261 case Some (DataType .USER_TYPE_NO_PARENT ) =>
4362 Log .typeProcParent.info(() => s " ..... no parent type added " )
44- None
63+ // `parent: <expression>` specified in attribute
4564 case Some (parent) =>
4665 val provider = new ClassTypeProvider (classSpecs, curClass)
4766 val detector = new TypeDetector (provider)
4867 val parentType = detector.detectType(parent)
4968 Log .typeProcParent.info(() => s " ..... enforced parent type = $parentType" )
5069 parentType match {
5170 case ut : UserType =>
52- Some (ut.classSpec.get)
71+ markupParentAs (ut.classSpec.get, userType )
5372 case other =>
5473 throw new TypeMismatchError (s " parent= $parent is expected to be either of user type or `false`, but $other found " )
5574 }
56- }).foreach((parentClass) => markupParentAs(parentClass, userType))
75+ }
5776 case switchType : SwitchType =>
5877 switchType.cases.foreach {
5978 case (_, ut : UserType ) =>
@@ -77,6 +96,11 @@ class ParentTypes(classSpecs: ClassSpecs) {
7796 }
7897 }
7998
99+ /**
100+ * If parent of `child` is not calculated yet, makes `parent` the parent
101+ * type. Otherwise, if `parent` is different from existing parent, replaces
102+ * parent type with the most generic KS type for user types.
103+ */
80104 def markupParentAs (parent : ClassSpec , child : ClassSpec ): Unit = {
81105 // Don't allow type usages across spec boundaries to affect parent resolution
82106 if (child.isExternal(parent)) {
0 commit comments