Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Fix enum and type resolution #309

Open
wants to merge 12 commits into
base: master
Choose a base branch
from
Prev Previous commit
Next Next commit
Fix type resolution in expressions
Mingun committed Oct 4, 2024
commit 4ec107f5c65cbabd16b75edb58e12faf5fd30fd5
45 changes: 45 additions & 0 deletions jvm/src/test/scala/io/kaitai/struct/ClassTypeProvider$Test.scala
Original file line number Diff line number Diff line change
@@ -50,14 +50,17 @@ class ClassTypeProvider$Test extends AnyFunSpec {

it("doesn't resolve 'one'") {
val thrown = the[TypeNotFoundError] thrownBy resolver.resolveTypeName(root, "one")
thrown.getMessage should be("unable to find type 'one', searching from 'root'")
}

it("doesn't resolve 'two'") {
val thrown = the[TypeNotFoundError] thrownBy resolver.resolveTypeName(root, "two")
thrown.getMessage should be("unable to find type 'two', searching from 'root'")
}

it("doesn't resolve 'unknown'") {
val thrown = the[TypeNotFoundError] thrownBy resolver.resolveTypeName(root, "unknown")
thrown.getMessage should be("unable to find type 'unknown', searching from 'root'")
}
}

@@ -79,6 +82,7 @@ class ClassTypeProvider$Test extends AnyFunSpec {

it("doesn't resolve 'unknown'") {
val thrown = the[TypeNotFoundError] thrownBy resolver.resolveTypeName(child_1, "unknown")
thrown.getMessage should be("unable to find type 'unknown', searching from 'root::child_1'")
}
}

@@ -100,6 +104,7 @@ class ClassTypeProvider$Test extends AnyFunSpec {

it("doesn't resolve 'unknown'") {
val thrown = the[TypeNotFoundError] thrownBy resolver.resolveTypeName(child_2, "unknown")
thrown.getMessage should be("unable to find type 'unknown', searching from 'root::child_2'")
}
}

@@ -121,6 +126,7 @@ class ClassTypeProvider$Test extends AnyFunSpec {

it("doesn't resolve 'unknown'") {
val thrown = the[TypeNotFoundError] thrownBy resolver.resolveTypeName(child_11, "unknown")
thrown.getMessage should be("unable to find type 'unknown', searching from 'root::child_1::one'")
}
}

@@ -142,6 +148,7 @@ class ClassTypeProvider$Test extends AnyFunSpec {

it("doesn't resolve 'unknown'") {
val thrown = the[TypeNotFoundError] thrownBy resolver.resolveTypeName(child_12, "unknown")
thrown.getMessage should be("unable to find type 'unknown', searching from 'root::child_1::two'")
}
}

@@ -163,6 +170,7 @@ class ClassTypeProvider$Test extends AnyFunSpec {

it("doesn't resolve 'unknown'") {
val thrown = the[TypeNotFoundError] thrownBy resolver.resolveTypeName(child_21, "unknown")
thrown.getMessage should be("unable to find type 'unknown', searching from 'root::child_2::one'")
}
}

@@ -184,6 +192,7 @@ class ClassTypeProvider$Test extends AnyFunSpec {

it("doesn't resolve 'unknown'") {
val thrown = the[TypeNotFoundError] thrownBy resolver.resolveTypeName(child_22, "unknown")
thrown.getMessage should be("unable to find type 'unknown', searching from 'root::child_2::two'")
}
}

@@ -205,6 +214,7 @@ class ClassTypeProvider$Test extends AnyFunSpec {

it("doesn't resolve 'unknown'") {
val thrown = the[TypeNotFoundError] thrownBy resolver.resolveTypeName(child_121, "unknown")
thrown.getMessage should be("unable to find type 'unknown', searching from 'root::child_1::two::one'")
}
}

@@ -226,6 +236,7 @@ class ClassTypeProvider$Test extends AnyFunSpec {

it("doesn't resolve 'unknown'") {
val thrown = the[TypeNotFoundError] thrownBy resolver.resolveTypeName(child_122, "unknown")
thrown.getMessage should be("unable to find type 'unknown', searching from 'root::child_1::two::two'")
}
}
}
@@ -244,26 +255,32 @@ class ClassTypeProvider$Test extends AnyFunSpec {

it("doesn't resolve 'one'") {
val thrown = the[TypeNotFoundError] thrownBy resolver.resolveTypePath(root, Seq("one"))
thrown.getMessage should be("unable to find type 'one', searching from 'root'")
}

it("doesn't resolve 'one::two'") {
val thrown = the[TypeNotFoundError] thrownBy resolver.resolveTypePath(root, Seq("one", "two"))
thrown.getMessage should be("unable to find type 'one', searching from 'root'")
}

it("doesn't resolve 'one::unknown'") {
val thrown = the[TypeNotFoundError] thrownBy resolver.resolveTypePath(root, Seq("one", "unknown"))
thrown.getMessage should be("unable to find type 'one', searching from 'root'")
}

it("doesn't resolve 'two'") {
val thrown = the[TypeNotFoundError] thrownBy resolver.resolveTypePath(root, Seq("two"))
thrown.getMessage should be("unable to find type 'two', searching from 'root'")
}

it("doesn't resolve 'two::one'") {
val thrown = the[TypeNotFoundError] thrownBy resolver.resolveTypePath(root, Seq("two", "one"))
thrown.getMessage should be("unable to find type 'two', searching from 'root'")
}

it("doesn't resolve 'two::unknown'") {
val thrown = the[TypeNotFoundError] thrownBy resolver.resolveTypePath(root, Seq("two", "unknown"))
thrown.getMessage should be("unable to find type 'two', searching from 'root'")
}
}

@@ -285,10 +302,12 @@ class ClassTypeProvider$Test extends AnyFunSpec {

it("doesn't resolve 'one::two'") {
val thrown = the[TypeNotFoundError] thrownBy resolver.resolveTypePath(child_1, Seq("one", "two"))
thrown.getMessage should be("unable to find type 'two' in 'root::child_1::one'")
}

it("doesn't resolve 'one::unknown'") {
val thrown = the[TypeNotFoundError] thrownBy resolver.resolveTypePath(child_1, Seq("one", "unknown"))
thrown.getMessage should be("unable to find type 'unknown' in 'root::child_1::one'")
}

it("resolves 'two'") {
@@ -301,6 +320,7 @@ class ClassTypeProvider$Test extends AnyFunSpec {

it("doesn't resolve 'two::unknown'") {
val thrown = the[TypeNotFoundError] thrownBy resolver.resolveTypePath(child_1, Seq("two", "unknown"))
thrown.getMessage should be("unable to find type 'unknown' in 'root::child_1::two'")
}
}

@@ -322,10 +342,12 @@ class ClassTypeProvider$Test extends AnyFunSpec {

it("doesn't resolve 'one::two'") {
val thrown = the[TypeNotFoundError] thrownBy resolver.resolveTypePath(child_2, Seq("one", "two"))
thrown.getMessage should be("unable to find type 'two' in 'root::child_2::one'")
}

it("doesn't resolve 'one::unknown'") {
val thrown = the[TypeNotFoundError] thrownBy resolver.resolveTypePath(child_2, Seq("one", "unknown"))
thrown.getMessage should be("unable to find type 'unknown' in 'root::child_2::one'")
}

it("resolves 'two'") {
@@ -334,10 +356,12 @@ class ClassTypeProvider$Test extends AnyFunSpec {

it("doesn't resolve 'two::one'") {
val thrown = the[TypeNotFoundError] thrownBy resolver.resolveTypePath(child_2, Seq("two", "one"))
thrown.getMessage should be("unable to find type 'one' in 'root::child_2::two'")
}

it("doesn't resolve 'two::unknown'") {
val thrown = the[TypeNotFoundError] thrownBy resolver.resolveTypePath(child_2, Seq("two", "unknown"))
thrown.getMessage should be("unable to find type 'unknown' in 'root::child_2::two'")
}
}

@@ -359,10 +383,12 @@ class ClassTypeProvider$Test extends AnyFunSpec {

it("doesn't resolve 'one::two'") {
val thrown = the[TypeNotFoundError] thrownBy resolver.resolveTypePath(child_11, Seq("one", "two"))
thrown.getMessage should be("unable to find type 'two' in 'root::child_1::one'")
}

it("doesn't resolve 'one::unknown'") {
val thrown = the[TypeNotFoundError] thrownBy resolver.resolveTypePath(child_11, Seq("one", "unknown"))
thrown.getMessage should be("unable to find type 'unknown' in 'root::child_1::one'")
}

it("resolves 'two'") {
@@ -375,6 +401,7 @@ class ClassTypeProvider$Test extends AnyFunSpec {

it("doesn't resolve 'two::unknown'") {
val thrown = the[TypeNotFoundError] thrownBy resolver.resolveTypePath(child_11, Seq("two", "unknown"))
thrown.getMessage should be("unable to find type 'unknown' in 'root::child_1::two'")
}
}

@@ -396,10 +423,12 @@ class ClassTypeProvider$Test extends AnyFunSpec {

it("doesn't resolve 'one::two'") {
val thrown = the[TypeNotFoundError] thrownBy resolver.resolveTypePath(child_12, Seq("one", "two"))
thrown.getMessage should be("unable to find type 'two' in 'root::child_1::two::one'")
}

it("doesn't resolve 'one::unknown'") {
val thrown = the[TypeNotFoundError] thrownBy resolver.resolveTypePath(child_12, Seq("one", "unknown"))
thrown.getMessage should be("unable to find type 'unknown' in 'root::child_1::two::one'")
}

it("resolves 'two'") {
@@ -412,6 +441,7 @@ class ClassTypeProvider$Test extends AnyFunSpec {

it("doesn't resolve 'two::unknown'") {
val thrown = the[TypeNotFoundError] thrownBy resolver.resolveTypePath(child_12, Seq("two", "unknown"))
thrown.getMessage should be("unable to find type 'unknown' in 'root::child_1::two'")
}
}

@@ -433,10 +463,12 @@ class ClassTypeProvider$Test extends AnyFunSpec {

it("doesn't resolve 'one::two'") {
val thrown = the[TypeNotFoundError] thrownBy resolver.resolveTypePath(child_21, Seq("one", "two"))
thrown.getMessage should be("unable to find type 'two' in 'root::child_2::one'")
}

it("doesn't resolve 'one::unknown'") {
val thrown = the[TypeNotFoundError] thrownBy resolver.resolveTypePath(child_21, Seq("one", "unknown"))
thrown.getMessage should be("unable to find type 'unknown' in 'root::child_2::one'")
}

it("resolves 'two'") {
@@ -445,10 +477,12 @@ class ClassTypeProvider$Test extends AnyFunSpec {

it("doesn't resolve 'two::one'") {
val thrown = the[TypeNotFoundError] thrownBy resolver.resolveTypePath(child_21, Seq("two", "one"))
thrown.getMessage should be("unable to find type 'one' in 'root::child_2::two'")
}

it("doesn't resolve 'two::unknown'") {
val thrown = the[TypeNotFoundError] thrownBy resolver.resolveTypePath(child_21, Seq("two", "unknown"))
thrown.getMessage should be("unable to find type 'unknown' in 'root::child_2::two'")
}
}

@@ -470,10 +504,12 @@ class ClassTypeProvider$Test extends AnyFunSpec {

it("doesn't resolve 'one::two'") {
val thrown = the[TypeNotFoundError] thrownBy resolver.resolveTypePath(child_22, Seq("one", "two"))
thrown.getMessage should be("unable to find type 'two' in 'root::child_2::one'")
}

it("doesn't resolve 'one::unknown'") {
val thrown = the[TypeNotFoundError] thrownBy resolver.resolveTypePath(child_22, Seq("one", "unknown"))
thrown.getMessage should be("unable to find type 'unknown' in 'root::child_2::one'")
}

it("resolves 'two'") {
@@ -482,10 +518,12 @@ class ClassTypeProvider$Test extends AnyFunSpec {

it("doesn't resolve 'two::one'") {
val thrown = the[TypeNotFoundError] thrownBy resolver.resolveTypePath(child_22, Seq("two", "one"))
thrown.getMessage should be("unable to find type 'one' in 'root::child_2::two'")
}

it("doesn't resolve 'two::unknown'") {
val thrown = the[TypeNotFoundError] thrownBy resolver.resolveTypePath(child_22, Seq("two", "unknown"))
thrown.getMessage should be("unable to find type 'unknown' in 'root::child_2::two'")
}
}

@@ -507,10 +545,12 @@ class ClassTypeProvider$Test extends AnyFunSpec {

it("doesn't resolve 'one::two'") {
val thrown = the[TypeNotFoundError] thrownBy resolver.resolveTypePath(child_121, Seq("one", "two"))
thrown.getMessage should be("unable to find type 'two' in 'root::child_1::two::one'")
}

it("doesn't resolve 'one::unknown'") {
val thrown = the[TypeNotFoundError] thrownBy resolver.resolveTypePath(child_121, Seq("one", "unknown"))
thrown.getMessage should be("unable to find type 'unknown' in 'root::child_1::two::one'")
}

it("resolves 'two'") {
@@ -523,6 +563,7 @@ class ClassTypeProvider$Test extends AnyFunSpec {

it("doesn't resolve 'two::unknown'") {
val thrown = the[TypeNotFoundError] thrownBy resolver.resolveTypePath(child_121, Seq("two", "unknown"))
thrown.getMessage should be("unable to find type 'unknown' in 'root::child_1::two'")
}
}

@@ -544,10 +585,12 @@ class ClassTypeProvider$Test extends AnyFunSpec {

it("doesn't resolve 'one::two'") {
val thrown = the[TypeNotFoundError] thrownBy resolver.resolveTypePath(child_122, Seq("one", "two"))
thrown.getMessage should be("unable to find type 'two' in 'root::child_1::two::one'")
}

it("doesn't resolve 'one::unknown'") {
val thrown = the[TypeNotFoundError] thrownBy resolver.resolveTypePath(child_122, Seq("one", "unknown"))
thrown.getMessage should be("unable to find type 'unknown' in 'root::child_1::two::one'")
}

it("resolves 'two'") {
@@ -556,10 +599,12 @@ class ClassTypeProvider$Test extends AnyFunSpec {

it("doesn't resolve 'two::one'") {
val thrown = the[TypeNotFoundError] thrownBy resolver.resolveTypePath(child_122, Seq("two", "one"))
thrown.getMessage should be("unable to find type 'one' in 'root::child_1::two::two'")
}

it("doesn't resolve 'two::unknown'") {
val thrown = the[TypeNotFoundError] thrownBy resolver.resolveTypePath(child_122, Seq("two", "unknown"))
thrown.getMessage should be("unable to find type 'unknown' in 'root::child_1::two::two'")
}
}
}
17 changes: 10 additions & 7 deletions shared/src/main/scala/io/kaitai/struct/ClassTypeProvider.scala
Original file line number Diff line number Diff line change
@@ -4,7 +4,7 @@ import io.kaitai.struct.datatype.DataType
import io.kaitai.struct.datatype.DataType._
import io.kaitai.struct.exprlang.Ast
import io.kaitai.struct.format._
import io.kaitai.struct.precompile.{EnumNotFoundError, FieldNotFoundError, TypeNotFoundError, TypeUndecidedError}
import io.kaitai.struct.precompile.{EnumNotFoundError, FieldNotFoundError, TypeNotFoundInHierarchyError, TypeNotFoundInTypeError, TypeUndecidedError}
import io.kaitai.struct.translators.TypeProvider

class ClassTypeProvider(classSpecs: ClassSpecs, var topClass: ClassSpec) extends TypeProvider {
@@ -121,12 +121,15 @@ class ClassTypeProvider(classSpecs: ClassSpecs, var topClass: ClassSpec) extends
return inClass

val headTypeName :: restTypesNames = path.toList
val nextClass = resolveTypeName(inClass, headTypeName)
if (restTypesNames.isEmpty) {
nextClass
} else {
resolveTypePath(nextClass, restTypesNames)
var nextClass = resolveTypeName(inClass, headTypeName)
for (name <- restTypesNames) {
nextClass = nextClass.types.get(name) match {
case Some(spec) => spec
case None =>
throw new TypeNotFoundInTypeError(name, nextClass)
}
}
nextClass
}

def resolveTypeName(inClass: ClassSpec, typeName: String): ClassSpec = {
@@ -144,7 +147,7 @@ class ClassTypeProvider(classSpecs: ClassSpecs, var topClass: ClassSpec) extends
classSpecs.get(typeName) match {
case Some(spec) => spec
case None =>
throw new TypeNotFoundError(typeName, nowClass)
throw new TypeNotFoundInHierarchyError(typeName, nowClass)
}
}
}
Original file line number Diff line number Diff line change
@@ -15,8 +15,11 @@ class WrongMethodCall(val dataType: MethodArgType, val methodName: String, val e
extends ExpressionError(s"wrong arguments to method call `$methodName` on $dataType: expected ${expectedSigs.mkString(" or ")}, got $actualSig")

sealed abstract class NotFoundError(msg: String) extends ExpressionError(msg)
class TypeNotFoundError(val name: String, val curClass: ClassSpec)
extends NotFoundError(s"unable to find type '$name', searching from '${curClass.nameAsStr}'")
sealed abstract class TypeNotFoundError(msg: String) extends NotFoundError(msg)
class TypeNotFoundInHierarchyError(val name: String, val curClass: ClassSpec)
extends TypeNotFoundError(s"unable to find type '$name', searching from '${curClass.nameAsStr}'")
class TypeNotFoundInTypeError(val name: String, val curClass: ClassSpec)
extends TypeNotFoundError(s"unable to find type '$name' in '${curClass.nameAsStr}'")
class FieldNotFoundError(val name: String, val curClass: ClassSpec)
extends NotFoundError(s"unable to access '$name' in '${curClass.nameAsStr}' context")
class EnumNotFoundError(val name: String, val curClass: ClassSpec)