@@ -6,13 +6,20 @@ import io.kaitai.struct.datatype.DataType.{ArrayTypeInStream, SwitchType, UserTy
6
6
import io .kaitai .struct .format ._
7
7
import io .kaitai .struct .translators .TypeDetector
8
8
9
+ /**
10
+ * Precompile step that calculates actual parent types of KSY-defined types
11
+ * (the type of the `_parent` built-in property).
12
+ */
9
13
class ParentTypes (classSpecs : ClassSpecs ) {
10
14
def run (): Unit = {
11
15
classSpecs.foreach { case (_, curClass) => markup(curClass) }
16
+ classSpecs.forEachTopLevel((_, spec) => {
17
+ spec.parentClass = GenericStructClassSpec
18
+ })
12
19
}
13
20
14
21
def markup (curClass : ClassSpec ): Unit = {
15
- Log .typeProcParent.info(() => s " markupParentTypes ( ${curClass.nameAsStr}) " )
22
+ Log .typeProcParent.info(() => s " ParentTypes.markup ( ${curClass.nameAsStr}) " )
16
23
17
24
if (curClass.seq.nonEmpty)
18
25
Log .typeProcParent.info(() => s " ... seq " )
@@ -30,30 +37,42 @@ class ParentTypes(classSpecs: ClassSpecs) {
30
37
// value instances have no effect on parenting, just do nothing
31
38
}
32
39
}
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
+ }
33
49
}
34
50
51
+ /** Calculates `parent` of `dt` */
35
52
private
36
53
def markupParentTypesAdd (curClass : ClassSpec , dt : DataType ): Unit = {
37
54
dt match {
38
55
case userType : UserType =>
39
- (userType.forcedParent match {
56
+ userType.forcedParent match {
57
+ // `parent` key is not specified in attribute
40
58
case None =>
41
- Some (curClass)
59
+ markupParentAs(curClass, userType)
60
+ // `parent: false` specified in attribute
42
61
case Some (DataType .USER_TYPE_NO_PARENT ) =>
43
62
Log .typeProcParent.info(() => s " ..... no parent type added " )
44
- None
63
+ // `parent: <expression>` specified in attribute
45
64
case Some (parent) =>
46
65
val provider = new ClassTypeProvider (classSpecs, curClass)
47
66
val detector = new TypeDetector (provider)
48
67
val parentType = detector.detectType(parent)
49
68
Log .typeProcParent.info(() => s " ..... enforced parent type = $parentType" )
50
69
parentType match {
51
70
case ut : UserType =>
52
- Some (ut.classSpec.get)
71
+ markupParentAs (ut.classSpec.get, userType )
53
72
case other =>
54
73
throw new TypeMismatchError (s " parent= $parent is expected to be either of user type or `false`, but $other found " )
55
74
}
56
- }).foreach((parentClass) => markupParentAs(parentClass, userType))
75
+ }
57
76
case switchType : SwitchType =>
58
77
switchType.cases.foreach {
59
78
case (_, ut : UserType ) =>
@@ -77,6 +96,11 @@ class ParentTypes(classSpecs: ClassSpecs) {
77
96
}
78
97
}
79
98
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
+ */
80
104
def markupParentAs (parent : ClassSpec , child : ClassSpec ): Unit = {
81
105
// Don't allow type usages across spec boundaries to affect parent resolution
82
106
if (child.isExternal(parent)) {
0 commit comments