Skip to content

Commit

Permalink
Fix enum resolution in expressions
Browse files Browse the repository at this point in the history
  • Loading branch information
Mingun committed Sep 26, 2024
1 parent f086b73 commit 196545b
Show file tree
Hide file tree
Showing 3 changed files with 58 additions and 6 deletions.
34 changes: 34 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 @@ -638,18 +638,22 @@ class ClassTypeProvider$Test extends AnyFunSpec {

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

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

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

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

Expand All @@ -667,14 +671,17 @@ class ClassTypeProvider$Test extends AnyFunSpec {

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

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

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

Expand All @@ -688,18 +695,22 @@ class ClassTypeProvider$Test extends AnyFunSpec {

it("doesn't resolve 'one::e'") {
val thrown = the[EnumNotFoundError] thrownBy resolver.resolveEnum(one, "e")
thrown.getMessage should be("unable to find enum 'e' in 'root::child_2::one'")
}

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

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

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

Expand All @@ -717,14 +728,17 @@ class ClassTypeProvider$Test extends AnyFunSpec {

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

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

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

Expand All @@ -738,18 +752,22 @@ class ClassTypeProvider$Test extends AnyFunSpec {

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

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

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

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

Expand All @@ -763,18 +781,22 @@ class ClassTypeProvider$Test extends AnyFunSpec {

it("doesn't resolve 'one::e'") {
val thrown = the[EnumNotFoundError] thrownBy resolver.resolveEnum(one, "e")
thrown.getMessage should be("unable to find enum 'e' in 'root::child_2::one'")
}

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

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

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

Expand All @@ -788,18 +810,22 @@ class ClassTypeProvider$Test extends AnyFunSpec {

it("doesn't resolve 'one::e'") {
val thrown = the[EnumNotFoundError] thrownBy resolver.resolveEnum(one, "e")
thrown.getMessage should be("unable to find enum 'e' in 'root::child_2::one'")
}

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

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

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

Expand All @@ -813,18 +839,22 @@ class ClassTypeProvider$Test extends AnyFunSpec {

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

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

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

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

Expand All @@ -838,18 +868,22 @@ class ClassTypeProvider$Test extends AnyFunSpec {

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

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

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

it("doesn't resolve 'unknown::e'") {
val thrown = the[TypeNotFoundError] thrownBy resolver.resolveEnum(unknown, "e")
thrown.getMessage should be("unable to find type 'unknown', searching from 'root::child_1::two::two'")
}
}
}
Expand Down
21 changes: 17 additions & 4 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, TypeNotFoundInHierarchyError, TypeNotFoundInTypeError, TypeUndecidedError}
import io.kaitai.struct.precompile.{EnumNotFoundInHierarchyError, EnumNotFoundInTypeError, FieldNotFoundError, TypeNotFoundInHierarchyError, TypeNotFoundInTypeError, TypeUndecidedError}
import io.kaitai.struct.translators.TypeProvider

class ClassTypeProvider(classSpecs: ClassSpecs, var topClass: ClassSpec) extends TypeProvider {
Expand Down Expand Up @@ -90,8 +90,21 @@ class ClassTypeProvider(classSpecs: ClassSpecs, var topClass: ClassSpec) extends
throw new FieldNotFoundError(attrName, inClass)
}

override def resolveEnum(inType: Ast.typeId, enumName: String): EnumSpec =
resolveEnumName(resolveClassSpec(inType), enumName)
override def resolveEnum(inType: Ast.typeId, enumName: String): EnumSpec = {
val inClass = if (inType.absolute) topClass else nowClass
// When concrete type is not defined, search enum definition in all enclosing types
if (inType.names.isEmpty) {
resolveEnumName(inClass, enumName)
} else {
val ty = resolveTypePath(inClass, inType.names)
ty.enums.get(enumName) match {
case Some(spec) =>
spec
case None =>
throw new EnumNotFoundInTypeError(enumName, ty)
}
}
}

private def resolveEnumName(inClass: ClassSpec, enumName: String): EnumSpec = {
inClass.enums.get(enumName) match {
Expand All @@ -102,7 +115,7 @@ class ClassTypeProvider(classSpecs: ClassSpecs, var topClass: ClassSpec) extends
inClass.upClass match {
case Some(upClass) => resolveEnumName(upClass, enumName)
case None =>
throw new EnumNotFoundError(enumName, nowClass)
throw new EnumNotFoundInHierarchyError(enumName, nowClass)
}
}
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -22,8 +22,13 @@ 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)
extends NotFoundError(s"unable to find enum '$name', searching from '${curClass.nameAsStr}'")

sealed abstract class EnumNotFoundError(msg: String) extends NotFoundError(msg)
class EnumNotFoundInHierarchyError(val name: String, val curClass: ClassSpec)
extends EnumNotFoundError(s"unable to find enum '$name', searching from '${curClass.nameAsStr}'")
class EnumNotFoundInTypeError(val name: String, val curClass: ClassSpec)
extends EnumNotFoundError(s"unable to find enum '$name' in '${curClass.nameAsStr}'")

class EnumMemberNotFoundError(val label: String, val enumName: String, val enumDefPath: String)
extends NotFoundError(s"unable to find enum member '$enumName::$label' (enum '$enumName' defined at /$enumDefPath)")

Expand Down

0 comments on commit 196545b

Please sign in to comment.