diff --git a/jvm/src/test/scala/io/kaitai/struct/ClassTypeProvider$Test.scala b/jvm/src/test/scala/io/kaitai/struct/ClassTypeProvider$Test.scala new file mode 100644 index 000000000..2a97388e8 --- /dev/null +++ b/jvm/src/test/scala/io/kaitai/struct/ClassTypeProvider$Test.scala @@ -0,0 +1,890 @@ +package io.kaitai.struct + +import java.util.NoSuchElementException +import io.kaitai.struct.exprlang.Ast +import io.kaitai.struct.format.{ClassSpec, ClassSpecs} +import io.kaitai.struct.formats.{JavaClassSpecs, JavaKSYParser} +import io.kaitai.struct.precompile.{EnumNotFoundError, MarkupClassNames, TypeNotFoundError} +import org.scalatest.funspec.AnyFunSpec +import org.scalatest.matchers.should.Matchers._ + +class ClassTypeProvider$Test extends AnyFunSpec { + val root = ClassSpec.fromYaml(JavaKSYParser.stringToYaml(""" + meta: + id: root + enums: + e: {} # e_root + types: + child_1: + types: + one: # child_11 + enums: + e: {} # e_11 + two: # child_12 + enums: + e: {} # e_12 + types: + one: {} # child_121 + two: {} # child_122 + child_2: + enums: + e: {} # e_2 + types: + one: {} # child_21 + two: {} # child_22 + """), None) + val specs = new JavaClassSpecs("", Seq(), root) + // Calculates full class names needed for work of the provider + new MarkupClassNames(specs).run() + + val child_1 = root.types.get("child_1").getOrElse(throw new NoSuchElementException("'child_1' not found")) + val child_2 = root.types.get("child_2").getOrElse(throw new NoSuchElementException("'child_2' not found")) + + val child_11 = child_1.types.get("one").getOrElse(throw new NoSuchElementException("'child_11' not found")) + val child_12 = child_1.types.get("two").getOrElse(throw new NoSuchElementException("'child_12' not found")) + + val child_21 = child_2.types.get("one").getOrElse(throw new NoSuchElementException("'child_21' not found")) + val child_22 = child_2.types.get("two").getOrElse(throw new NoSuchElementException("'child_22' not found")) + + val child_121 = child_12.types.get("one").getOrElse(throw new NoSuchElementException("'child_121' not found")) + val child_122 = child_12.types.get("two").getOrElse(throw new NoSuchElementException("'child_122' not found")) + + describe("resolveTypeName") { + describe("in 'root' context") { + val resolver = new ClassTypeProvider(specs, root) + + it("resolves 'root'") { + resolver.resolveTypeName(root, "root") should be(root) // self-reference + } + + 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'") + } + } + + describe("in 'child_1' context") { + val resolver = new ClassTypeProvider(specs, root) + resolver.nowClass = child_1 // Influences the error messages ("searching from '...'" part) + + it("resolves 'root'") { + resolver.resolveTypeName(child_1, "root") should be(root) + } + + it("resolves 'one'") { + resolver.resolveTypeName(child_1, "one") should be(child_11) + } + + it("resolves 'two'") { + resolver.resolveTypeName(child_1, "two") should be(child_12) + } + + 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'") + } + } + + describe("in 'child_2' context") { + val resolver = new ClassTypeProvider(specs, root) + resolver.nowClass = child_2 // Influences the error messages ("searching from '...'" part) + + it("resolves 'root'") { + resolver.resolveTypeName(child_2, "root") should be(root) + } + + it("resolves 'one'") { + resolver.resolveTypeName(child_2, "one") should be(child_21) + } + + it("resolves 'two'") { + resolver.resolveTypeName(child_2, "two") should be(child_22) + } + + 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'") + } + } + + describe("in 'child_11' context") { + val resolver = new ClassTypeProvider(specs, root) + resolver.nowClass = child_11 // Influences the error messages ("searching from '...'" part) + + it("resolves 'root'") { + resolver.resolveTypeName(child_11, "root") should be(root) + } + + it("resolves 'one'") { + resolver.resolveTypeName(child_11, "one") should be(child_11) // self-reference + } + + it("resolves 'two'") { + resolver.resolveTypeName(child_11, "two") should be(child_12) + } + + 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'") + } + } + + describe("in 'child_12' context") { + val resolver = new ClassTypeProvider(specs, root) + resolver.nowClass = child_12 // Influences the error messages ("searching from '...'" part) + + it("resolves 'root'") { + resolver.resolveTypeName(child_12, "root") should be(root) + } + + it("resolves 'one'") { + resolver.resolveTypeName(child_12, "one") should be(child_121) + } + + it("resolves 'two'") { + resolver.resolveTypeName(child_12, "two") should be(child_12) // self-reference + } + + 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'") + } + } + + describe("in 'child_21' context") { + val resolver = new ClassTypeProvider(specs, root) + resolver.nowClass = child_21 // Influences the error messages ("searching from '...'" part) + + it("resolves 'root'") { + resolver.resolveTypeName(child_21, "root") should be(root) + } + + it("resolves 'one'") { + resolver.resolveTypeName(child_21, "one") should be(child_21) // self-reference + } + + it("resolves 'two'") { + resolver.resolveTypeName(child_21, "two") should be(child_22) + } + + 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'") + } + } + + describe("in 'child_22' context") { + val resolver = new ClassTypeProvider(specs, root) + resolver.nowClass = child_22 // Influences the error messages ("searching from '...'" part) + + it("resolves 'root'") { + resolver.resolveTypeName(child_22, "root") should be(root) + } + + it("resolves 'one'") { + resolver.resolveTypeName(child_22, "one") should be(child_21) + } + + it("resolves 'two'") { + resolver.resolveTypeName(child_22, "two") should be(child_22) // self-reference + } + + 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'") + } + } + + describe("in 'child_121' context") { + val resolver = new ClassTypeProvider(specs, root) + resolver.nowClass = child_121 // Influences the error messages ("searching from '...'" part) + + it("resolves 'root'") { + resolver.resolveTypeName(child_121, "root") should be(root) + } + + it("resolves 'one'") { + resolver.resolveTypeName(child_121, "one") should be(child_121) // self-reference + } + + it("resolves 'two'") { + resolver.resolveTypeName(child_121, "two") should be(child_12) + } + + 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'") + } + } + + describe("in 'child_122' context") { + val resolver = new ClassTypeProvider(specs, root) + resolver.nowClass = child_122 // Influences the error messages ("searching from '...'" part) + + it("resolves 'root'") { + resolver.resolveTypeName(child_122, "root") should be(root) + } + + it("resolves 'one'") { + resolver.resolveTypeName(child_122, "one") should be(child_121) + } + + it("resolves 'two'") { + resolver.resolveTypeName(child_122, "two") should be(child_122) // self-reference + } + + 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'") + } + } + } + + describe("resolveTypePath") { + describe("in 'root' context") { + val resolver = new ClassTypeProvider(specs, root) + + it("resolves empty path") { + resolver.resolveTypePath(root, Seq()) should be(root) // self-reference + } + + it("resolves 'root'") { + resolver.resolveTypePath(root, Seq("root")) should be(root) // self-reference + } + + 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'") + } + } + + describe("in 'child_1' context") { + val resolver = new ClassTypeProvider(specs, root) + resolver.nowClass = child_1 // Influences the error messages ("searching from '...'" part) + + it("resolves empty path") { + resolver.resolveTypePath(child_1, Seq()) should be(child_1) // self-reference + } + + it("resolves 'root'") { + resolver.resolveTypePath(child_1, Seq("root")) should be(root) + } + + it("resolves 'one'") { + resolver.resolveTypePath(child_1, Seq("one")) should be(child_11) + } + + 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'") { + resolver.resolveTypePath(child_1, Seq("two")) should be(child_12) + } + + it("resolves 'two::one'") { + resolver.resolveTypePath(child_1, Seq("two", "one")) should be(child_121) + } + + 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'") + } + } + + describe("in 'child_2' context") { + val resolver = new ClassTypeProvider(specs, root) + resolver.nowClass = child_2 // Influences the error messages ("searching from '...'" part) + + it("resolves empty path") { + resolver.resolveTypePath(child_2, Seq()) should be(child_2) // self-reference + } + + it("resolves 'root'") { + resolver.resolveTypePath(child_2, Seq("root")) should be(root) + } + + it("resolves 'one'") { + resolver.resolveTypePath(child_2, Seq("one")) should be(child_21) + } + + 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'") { + resolver.resolveTypePath(child_2, Seq("two")) should be(child_22) + } + + 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'") + } + } + + describe("in 'child_11' context") { + val resolver = new ClassTypeProvider(specs, root) + resolver.nowClass = child_11 // Influences the error messages ("searching from '...'" part) + + it("resolves empty path") { + resolver.resolveTypePath(child_11, Seq()) should be(child_11) // self-reference + } + + it("resolves 'root'") { + resolver.resolveTypePath(child_11, Seq("root")) should be(root) + } + + it("resolves 'one'") { + resolver.resolveTypePath(child_11, Seq("one")) should be(child_11) // self-reference + } + + 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'") { + resolver.resolveTypePath(child_11, Seq("two")) should be(child_12) + } + + it("resolves 'two::one'") { + resolver.resolveTypePath(child_11, Seq("two", "one")) should be(child_121) + } + + 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'") + } + } + + describe("in 'child_12' context") { + val resolver = new ClassTypeProvider(specs, root) + resolver.nowClass = child_12 // Influences the error messages ("searching from '...'" part) + + it("resolves empty path") { + resolver.resolveTypePath(child_12, Seq()) should be(child_12) // self-reference + } + + it("resolves 'root'") { + resolver.resolveTypePath(child_12, Seq("root")) should be(root) + } + + it("resolves 'one'") { + resolver.resolveTypePath(child_12, Seq("one")) should be(child_121) + } + + 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'") { + resolver.resolveTypePath(child_12, Seq("two")) should be(child_12) // self-reference + } + + it("resolves 'two::one'") { + resolver.resolveTypePath(child_12, Seq("two", "one")) should be(child_121) + } + + 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'") + } + } + + describe("in 'child_21' context") { + val resolver = new ClassTypeProvider(specs, root) + resolver.nowClass = child_21 // Influences the error messages ("searching from '...'" part) + + it("resolves empty path") { + resolver.resolveTypePath(child_21, Seq()) should be(child_21) // self-reference + } + + it("resolves 'root'") { + resolver.resolveTypePath(child_21, Seq("root")) should be(root) + } + + it("resolves 'one'") { + resolver.resolveTypePath(child_21, Seq("one")) should be(child_21) // self-reference + } + + 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'") { + resolver.resolveTypePath(child_21, Seq("two")) should be(child_22) + } + + 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'") + } + } + + describe("in 'child_22' context") { + val resolver = new ClassTypeProvider(specs, root) + resolver.nowClass = child_22 // Influences the error messages ("searching from '...'" part) + + it("resolves empty path") { + resolver.resolveTypePath(child_22, Seq()) should be(child_22) // self-reference + } + + it("resolves 'root'") { + resolver.resolveTypePath(child_22, Seq("root")) should be(root) + } + + it("resolves 'one'") { + resolver.resolveTypePath(child_22, Seq("one")) should be(child_21) + } + + 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'") { + resolver.resolveTypePath(child_22, Seq("two")) should be(child_22) // self-reference + } + + 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'") + } + } + + describe("in 'child_121' context") { + val resolver = new ClassTypeProvider(specs, root) + resolver.nowClass = child_121 // Influences the error messages ("searching from '...'" part) + + it("resolves empty path") { + resolver.resolveTypePath(child_121, Seq()) should be(child_121) // self-reference + } + + it("resolves 'root'") { + resolver.resolveTypePath(child_121, Seq("root")) should be(root) + } + + it("resolves 'one'") { + resolver.resolveTypePath(child_121, Seq("one")) should be(child_121) // self-reference + } + + 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'") { + resolver.resolveTypePath(child_121, Seq("two")) should be(child_12) + } + + it("doesn't resolve 'two::one'") { + resolver.resolveTypePath(child_121, Seq("two", "one")) should be(child_121) // self-reference + } + + 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'") + } + } + + describe("in 'child_122' context") { + val resolver = new ClassTypeProvider(specs, root) + resolver.nowClass = child_122 // Influences the error messages ("searching from '...'" part) + + it("resolves empty path") { + resolver.resolveTypePath(child_122, Seq()) should be(child_122) // self-reference + } + + it("resolves 'root'") { + resolver.resolveTypePath(child_122, Seq("root")) should be(root) + } + + it("resolves 'one'") { + resolver.resolveTypePath(child_122, Seq("one")) should be(child_121) + } + + 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'") { + resolver.resolveTypePath(child_122, Seq("two")) should be(child_122) // self-reference + } + + 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'") + } + } + } + + describe("resolveEnum") { + val e_root = root.enums.get("e").getOrElse(throw new NoSuchElementException("'e_root' not found")) + val e_11 = child_11.enums.get("e").getOrElse(throw new NoSuchElementException("'e_11' not found")) + val e_12 = child_12.enums.get("e").getOrElse(throw new NoSuchElementException("'e_12' not found")) + val e_2 = child_2.enums.get("e").getOrElse(throw new NoSuchElementException("'e_2' not found")) + + val none = Ast.typeId(false, Seq()) + val one = Ast.typeId(false, Seq("one")) + val one_two = Ast.typeId(false, Seq("one", "two")) + val unknown = Ast.typeId(false, Seq("unknown")) + + describe("in 'root' context") { + val resolver = new ClassTypeProvider(specs, root) + + it("resolves 'e'") { + resolver.resolveEnum(none, "e") should be(e_root) + } + + 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'") + } + } + + describe("in 'child_1' context") { + val resolver = new ClassTypeProvider(specs, root) + resolver.nowClass = child_1 + + it("resolves 'e'") { + resolver.resolveEnum(none, "e") should be(e_root) + } + + it("resolves 'one::e'") { + resolver.resolveEnum(one, "e") should be(e_11) + } + + 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'") + } + } + + describe("in 'child_2' context") { + val resolver = new ClassTypeProvider(specs, root) + resolver.nowClass = child_2 + + it("resolves 'e'") { + resolver.resolveEnum(none, "e") should be(e_2) + } + + 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'") + } + } + + describe("in 'child_11' context") { + val resolver = new ClassTypeProvider(specs, root) + resolver.nowClass = child_11 + + it("resolves 'e'") { + resolver.resolveEnum(none, "e") should be(e_11) + } + + it("resolves 'one::e'") { + resolver.resolveEnum(one, "e") should be(e_11) + } + + 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'") + } + } + + describe("in 'child_12' context") { + val resolver = new ClassTypeProvider(specs, root) + resolver.nowClass = child_12 + + it("resolves 'e'") { + resolver.resolveEnum(none, "e") should be(e_12) + } + + 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'") + } + } + + describe("in 'child_21' context") { + val resolver = new ClassTypeProvider(specs, root) + resolver.nowClass = child_21 + + it("resolves 'e'") { + resolver.resolveEnum(none, "e") should be(e_2) + } + + 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'") + } + } + + describe("in 'child_22' context") { + val resolver = new ClassTypeProvider(specs, root) + resolver.nowClass = child_22 + + it("resolves 'e'") { + resolver.resolveEnum(none, "e") should be(e_2) + } + + 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'") + } + } + + describe("in 'child_121' context") { + val resolver = new ClassTypeProvider(specs, root) + resolver.nowClass = child_121 + + it("resolves 'e'") { + resolver.resolveEnum(none, "e") should be(e_12) + } + + 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'") + } + } + + describe("in 'child_122' context") { + val resolver = new ClassTypeProvider(specs, root) + resolver.nowClass = child_122 + + it("resolves 'e'") { + resolver.resolveEnum(none, "e") should be(e_12) + } + + 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'") + } + } + } +} diff --git a/shared/src/main/scala/io/kaitai/struct/ClassTypeProvider.scala b/shared/src/main/scala/io/kaitai/struct/ClassTypeProvider.scala index 0dee55827..fd74cf236 100644 --- a/shared/src/main/scala/io/kaitai/struct/ClassTypeProvider.scala +++ b/shared/src/main/scala/io/kaitai/struct/ClassTypeProvider.scala @@ -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.{EnumNotFoundInHierarchyError, EnumNotFoundInTypeError, FieldNotFoundError, TypeNotFoundInHierarchyError, TypeNotFoundInTypeError, TypeUndecidedError} import io.kaitai.struct.translators.TypeProvider class ClassTypeProvider(classSpecs: ClassSpecs, var topClass: ClassSpec) extends TypeProvider { @@ -90,46 +90,59 @@ class ClassTypeProvider(classSpecs: ClassSpecs, var topClass: ClassSpec) extends throw new FieldNotFoundError(attrName, inClass) } - override def resolveEnum(inType: Ast.typeId, enumName: String): EnumSpec = - resolveEnum(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) + } + } + } - def resolveEnum(inClass: ClassSpec, enumName: String): EnumSpec = { + private def resolveEnumName(inClass: ClassSpec, enumName: String): EnumSpec = { inClass.enums.get(enumName) match { case Some(spec) => spec case None => // let's try upper levels of hierarchy inClass.upClass match { - case Some(upClass) => resolveEnum(upClass, enumName) + case Some(upClass) => resolveEnumName(upClass, enumName) case None => - throw new EnumNotFoundError(enumName, nowClass) + throw new EnumNotFoundInHierarchyError(enumName, nowClass) } } } override def resolveType(typeName: Ast.typeId): DataType = - resolveClassSpec(typeName).toDataType - - def resolveClassSpec(typeName: Ast.typeId): ClassSpec = - resolveClassSpec( + resolveTypePath( if (typeName.absolute) topClass else nowClass, typeName.names - ) + ).toDataType - def resolveClassSpec(inClass: ClassSpec, typeName: Seq[String]): ClassSpec = { - if (typeName.isEmpty) + def resolveTypePath(inClass: ClassSpec, path: Seq[String]): ClassSpec = { + if (path.isEmpty) return inClass - val headTypeName :: restTypesNames = typeName.toList - val nextClass = resolveClassSpec(inClass, headTypeName) - if (restTypesNames.isEmpty) { - nextClass - } else { - resolveClassSpec(nextClass, restTypesNames) + val headTypeName :: restTypesNames = path.toList + 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 resolveClassSpec(inClass: ClassSpec, typeName: String): ClassSpec = { + def resolveTypeName(inClass: ClassSpec, typeName: String): ClassSpec = { if (inClass.name.last == typeName) return inClass @@ -139,12 +152,12 @@ class ClassTypeProvider(classSpecs: ClassSpecs, var topClass: ClassSpec) extends case None => // let's try upper levels of hierarchy inClass.upClass match { - case Some(upClass) => resolveClassSpec(upClass, typeName) + case Some(upClass) => resolveTypeName(upClass, typeName) case None => classSpecs.get(typeName) match { case Some(spec) => spec case None => - throw new TypeNotFoundError(typeName, nowClass) + throw new TypeNotFoundInHierarchyError(typeName, nowClass) } } } diff --git a/shared/src/main/scala/io/kaitai/struct/precompile/Exceptions.scala b/shared/src/main/scala/io/kaitai/struct/precompile/Exceptions.scala index 1ac6035bb..37abe2ecf 100644 --- a/shared/src/main/scala/io/kaitai/struct/precompile/Exceptions.scala +++ b/shared/src/main/scala/io/kaitai/struct/precompile/Exceptions.scala @@ -15,12 +15,20 @@ 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) - extends NotFoundError(s"unable to find enum '$name', searching from ${curClass.nameAsStr}") + extends NotFoundError(s"unable to access '$name' in '${curClass.nameAsStr}' context") + +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)") diff --git a/shared/src/main/scala/io/kaitai/struct/precompile/ResolveTypes.scala b/shared/src/main/scala/io/kaitai/struct/precompile/ResolveTypes.scala index f6f0c888b..a59c186d6 100644 --- a/shared/src/main/scala/io/kaitai/struct/precompile/ResolveTypes.scala +++ b/shared/src/main/scala/io/kaitai/struct/precompile/ResolveTypes.scala @@ -1,8 +1,9 @@ package io.kaitai.struct.precompile -import io.kaitai.struct.Log +import io.kaitai.struct.{ClassTypeProvider, Log} import io.kaitai.struct.datatype.DataType import io.kaitai.struct.datatype.DataType.{ArrayType, EnumType, SwitchType, UserType} +import io.kaitai.struct.exprlang.Ast import io.kaitai.struct.format._ import io.kaitai.struct.problems._ @@ -19,7 +20,7 @@ class ResolveTypes(specs: ClassSpecs, topClass: ClassSpec, opaqueTypes: Boolean) * ClassSpec. * @param curClass class to start from, might be top-level class */ - def resolveUserTypes(curClass: ClassSpec): Iterable[CompilationProblem] = { + private def resolveUserTypes(curClass: ClassSpec): Iterable[CompilationProblem] = { val seqProblems: Iterable[CompilationProblem] = curClass.seq.flatMap((attr) => resolveUserTypeForMember(curClass, attr)) @@ -40,21 +41,54 @@ class ResolveTypes(specs: ClassSpecs, topClass: ClassSpec, opaqueTypes: Boolean) seqProblems ++ instancesProblems ++ paramsProblems } - def resolveUserTypeForMember(curClass: ClassSpec, attr: MemberSpec): Iterable[CompilationProblem] = + private def resolveUserTypeForMember(curClass: ClassSpec, attr: MemberSpec): Iterable[CompilationProblem] = resolveUserType(curClass, attr.dataType, attr.path) - def resolveUserType(curClass: ClassSpec, dataType: DataType, path: List[String]): Iterable[CompilationProblem] = { + private def resolveUserType(curClass: ClassSpec, dataType: DataType, path: List[String]): Iterable[CompilationProblem] = { dataType match { case ut: UserType => - val (resClassSpec, problems) = resolveUserType(curClass, ut.name, path ++ List("type")) - ut.classSpec = resClassSpec - problems - case et: EnumType => - et.enumSpec = resolveEnumSpec(curClass, et.name) - if (et.enumSpec.isEmpty) { - Some(EnumNotFoundErr(et.name, curClass, path ++ List("enum"))) - } else { + try { + val resolver = new ClassTypeProvider(specs, curClass) + val ty = resolver.resolveTypePath(curClass, ut.name) + Log.typeResolve.info(() => s" => ${ty.nameAsStr}") + ut.classSpec = Some(ty) None + } catch { + case _: TypeNotFoundError => + // Type definition not found + if (opaqueTypes) { + // Generate special "opaque placeholder" ClassSpec + Log.typeResolve.info(() => " => ??? (generating opaque type)") + ut.classSpec = Some(ClassSpec.opaquePlaceholder(ut.name)) + None + } else { + // Opaque types are disabled => that is an error + Log.typeResolve.info(() => " => ??? (opaque type are disabled => error)") + Some(TypeNotFoundErr(ut.name, curClass, path :+ "type")) + } + } + case et: EnumType => + et.name match { + case typePath :+ name => + try { + val resolver = new ClassTypeProvider(specs, curClass) + val ty = resolver.resolveEnum(Ast.typeId(false, typePath), name) + Log.enumResolve.info(() => s" => ${ty.nameAsStr}") + et.enumSpec = Some(ty) + None + } catch { + case ex: TypeNotFoundError => + Log.typeResolve.info(() => s" => ??? (while resolving enum '${et.name}'): $ex") + Log.enumResolve.info(() => s" => ??? (enclosing type not found, enum '${et.name}'): $ex") + Some(TypeNotFoundErr(typePath, curClass, path :+ "enum")) + case ex: EnumNotFoundError => + Log.enumResolve.info(() => s" => ??? (enum '${et.name}'): $ex") + Some(EnumNotFoundErr(et.name, curClass, path :+ "enum")) + } + case _ => + Log.enumResolve.info(() => s" => ??? (enum '${et.name}' without name)") + // TODO: Maybe more specific error about empty name? + Some(EnumNotFoundErr(et.name, curClass, path :+ "enum")) } case st: SwitchType => st.cases.flatMap { case (caseName, ut) => @@ -67,132 +101,4 @@ class ResolveTypes(specs: ClassSpecs, topClass: ClassSpec, opaqueTypes: Boolean) None } } - - def resolveUserType(curClass: ClassSpec, typeName: List[String], path: List[String]): (Option[ClassSpec], Option[CompilationProblem]) = { - val res = realResolveUserType(curClass, typeName, path) - - res match { - case None => - // Type definition not found - if (opaqueTypes) { - // Generate special "opaque placeholder" ClassSpec - Log.typeResolve.info(() => " => ??? (generating opaque type)") - (Some(ClassSpec.opaquePlaceholder(typeName)), None) - } else { - // Opaque types are disabled => that is an error - Log.typeResolve.info(() => " => ??? (opaque type are disabled => error)") - (None, Some(TypeNotFoundErr(typeName, curClass, path))) - } - case Some(x) => - Log.typeResolve.info(() => s" => ${x.nameAsStr}") - (res, None) - } - } - - private def realResolveUserType(curClass: ClassSpec, typeName: List[String], path: List[String]): Option[ClassSpec] = { - Log.typeResolve.info(() => s"resolveUserType: at ${curClass.name} doing ${typeName.mkString("|")}") - - // First, try to do it in current class - - // If we're seeking composite name, we only have to resolve the very first - // part of it at this stage - val firstName :: restNames = typeName - - val resolvedHere = curClass.types.get(firstName).flatMap((nestedClass) => - if (restNames.isEmpty) { - // No further names to resolve, here's our answer - Some(nestedClass) - } else { - // Try to resolve recursively - realResolveUserType(nestedClass, restNames, path) - } - ) - - resolvedHere match { - case Some(_) => resolvedHere - case None => - // No luck resolving here, let's try upper levels, if they exist - curClass.upClass match { - case Some(upClass) => - realResolveUserType(upClass, typeName, path) - case None => - // Check this class if it's top-level class - if (curClass.name.head == firstName) { - Some(curClass) - } else { - // Check if top-level specs has this name - // If there's None => no luck at all - val resolvedTop = specs.get(firstName) - resolvedTop match { - case None => None - case Some(classSpec) => if (restNames.isEmpty) { - resolvedTop - } else { - realResolveUserType(classSpec, restNames, path) - } - } - } - } - } - } - - def resolveEnumSpec(curClass: ClassSpec, typeName: List[String]): Option[EnumSpec] = { - Log.enumResolve.info(() => s"resolveEnumSpec: at ${curClass.name} doing ${typeName.mkString("|")}") - - val res = realResolveEnumSpec(curClass, typeName) - res match { - case None => { - Log.enumResolve.info(() => s" => ???") - res - } - case Some(x) => { - Log.enumResolve.info(() => s" => ${x.nameAsStr}") - res - } - } - } - - private def realResolveEnumSpec(curClass: ClassSpec, typeName: List[String]): Option[EnumSpec] = { - // First, try to do it in current class - - // If we're seeking composite name, we only have to resolve the very first - // part of it at this stage - val firstName :: restNames = typeName - - val resolvedHere = if (restNames.isEmpty) { - curClass.enums.get(firstName) - } else { - curClass.types.get(firstName).flatMap((nestedClass) => - resolveEnumSpec(nestedClass, restNames) - ) - } - - resolvedHere match { - case Some(_) => resolvedHere - case None => - // No luck resolving here, let's try upper levels, if they exist - curClass.upClass match { - case Some(upClass) => - resolveEnumSpec(upClass, typeName) - case None => - // Check this class if it's top-level class - if (curClass.name.head == firstName) { - resolveEnumSpec(curClass, restNames) - } else { - // Check if top-level specs has this name - // If there's None => no luck at all - val resolvedTop = specs.get(firstName) - resolvedTop match { - case None => None - case Some(classSpec) => if (restNames.isEmpty) { - // resolved everything, but this points to a type name, not enum name - None - } else { - resolveEnumSpec(classSpec, restNames) - } - } - } - } - } - } } diff --git a/shared/src/main/scala/io/kaitai/struct/problems/CompilationProblem.scala b/shared/src/main/scala/io/kaitai/struct/problems/CompilationProblem.scala index 2779887fb..4c277622a 100644 --- a/shared/src/main/scala/io/kaitai/struct/problems/CompilationProblem.scala +++ b/shared/src/main/scala/io/kaitai/struct/problems/CompilationProblem.scala @@ -173,7 +173,7 @@ case class ParamMismatchError(idx: Int, argType: DataType, paramName: String, pa case class TypeNotFoundErr(name: List[String], curClass: ClassSpec, path: List[String], fileName: Option[String] = None) extends CompilationProblem { - override def text = s"unable to find type '${name.mkString("::")}', searching from ${curClass.nameAsStr}" + override def text = s"unable to find type '${name.mkString("::")}', searching from '${curClass.nameAsStr}'" override val coords: ProblemCoords = ProblemCoords(fileName, Some(path)) override def localizedInFile(fileName: String): CompilationProblem = copy(fileName = Some(fileName)) @@ -183,7 +183,7 @@ case class TypeNotFoundErr(name: List[String], curClass: ClassSpec, path: List[S case class EnumNotFoundErr(name: List[String], curClass: ClassSpec, path: List[String], fileName: Option[String] = None) extends CompilationProblem { - override def text = s"unable to find enum '${name.mkString("::")}', searching from ${curClass.nameAsStr}" + override def text = s"unable to find enum '${name.mkString("::")}', searching from '${curClass.nameAsStr}'" override val coords: ProblemCoords = ProblemCoords(fileName, Some(path)) override def localizedInFile(fileName: String): CompilationProblem = copy(fileName = Some(fileName))