Skip to content

Commit

Permalink
Fix type resolution in expressions
Browse files Browse the repository at this point in the history
  • Loading branch information
Mingun committed Sep 26, 2024
1 parent 8d9a6ff commit 6d54108
Show file tree
Hide file tree
Showing 3 changed files with 60 additions and 9 deletions.
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
Expand Up @@ -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'")
}
}

Expand All @@ -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'")
}
}

Expand All @@ -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'")
}
}

Expand All @@ -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'")
}
}

Expand All @@ -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'")
}
}

Expand All @@ -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'")
}
}

Expand All @@ -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'")
}
}

Expand All @@ -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'")
}
}

Expand All @@ -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'")
}
}
}
Expand All @@ -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'")
}
}

Expand All @@ -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'") {
Expand All @@ -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'")
}
}

Expand All @@ -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'") {
Expand All @@ -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'")
}
}

Expand All @@ -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'") {
Expand All @@ -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'")
}
}

Expand All @@ -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'") {
Expand All @@ -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'")
}
}

Expand All @@ -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'") {
Expand All @@ -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'")
}
}

Expand All @@ -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'") {
Expand All @@ -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'")
}
}

Expand All @@ -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'") {
Expand All @@ -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'")
}
}

Expand All @@ -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'") {
Expand All @@ -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'")
}
}
}
Expand Down
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
Expand Up @@ -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 {
Expand Down Expand Up @@ -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 = {
Expand All @@ -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)
}
}
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -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)
Expand Down

0 comments on commit 6d54108

Please sign in to comment.