From e7721cb4eacfbbde66034790fa3737b82da55e92 Mon Sep 17 00:00:00 2001 From: Mingun Date: Sat, 5 Oct 2024 20:25:09 +0500 Subject: [PATCH 1/3] Use MethodNotFoundErrorWithArg instead of MethodNotFoundError where possible Tests that need to be updated: [info] - expr_unknown_method1 *** FAILED *** [info] [expr_unknown_method1.ksy: /instances/foo/value: [info] error: don't know how to call method 'frobnicate' of object type 'byte array' [info] ] [info] did not equal [info] [expr_unknown_method1.ksy: /instances/foo/value: [info] error: don't know how to call method 'frobnicate' of object type 'CalcBytesType' [info] ] (SimpleMatchers.scala:34) [info] - expr_unknown_method2 *** FAILED *** [info] [expr_unknown_method2.ksy: /instances/foo/value: [info] error: don't know how to call method 'frobnicate' of object type 'byte array' [info] ] [info] did not equal [info] [expr_unknown_method2.ksy: /instances/foo/value: [info] error: don't know how to call method 'frobnicate' of object type 'CalcBytesType' [info] ] (SimpleMatchers.scala:34) [info] - io_on_bytes *** FAILED *** [info] [io_on_bytes.ksy: /instances/one_in_foo/io: [info] error: don't know how to call method '_io' of object type 'byte array' [info] ] [info] did not equal [info] [io_on_bytes.ksy: /instances/one_in_foo/io: [info] error: don't know how to call method '_io' of object type 'BytesLimitType(IntNum(100),None,false,None,None)' [info] ] (SimpleMatchers.scala:34) --- .../struct/translators/TypeDetector.scala | 25 +++++++++++++------ 1 file changed, 17 insertions(+), 8 deletions(-) diff --git a/shared/src/main/scala/io/kaitai/struct/translators/TypeDetector.scala b/shared/src/main/scala/io/kaitai/struct/translators/TypeDetector.scala index 49cf61ef2..6ce44f747 100644 --- a/shared/src/main/scala/io/kaitai/struct/translators/TypeDetector.scala +++ b/shared/src/main/scala/io/kaitai/struct/translators/TypeDetector.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.Identifier -import io.kaitai.struct.precompile.{MethodNotFoundError, TypeMismatchError, TypeUndecidedError} +import io.kaitai.struct.precompile.{MethodNotFoundError, MethodNotFoundErrorWithArg, TypeMismatchError, TypeUndecidedError} /** * Basic class the implements type inferring functionality for Ast.expr @@ -172,24 +172,28 @@ class TypeDetector(provider: TypeProvider) { attr.name match { case "length" | "size" => CalcIntType case "first" | "last" | "min" | "max" => Int1Type(false) - case _ => throw new MethodNotFoundError(attr.name, valType) + // MethodArgType.byDataType returns Some(...) in that case + case _ => throw new MethodNotFoundErrorWithArg(attr.name, MethodArgType.byDataType(valType).get) } case _: StrType => attr.name match { case "length" => CalcIntType case "reverse" => CalcStrType case "to_i" => CalcIntType - case _ => throw new MethodNotFoundError(attr.name, valType) + // MethodArgType.byDataType returns Some(...) in that case + case _ => throw new MethodNotFoundErrorWithArg(attr.name, MethodArgType.byDataType(valType).get) } case _: IntType => attr.name match { case "to_s" => CalcStrType - case _ => throw new MethodNotFoundError(attr.name, valType) + // MethodArgType.byDataType returns Some(...) in that case + case _ => throw new MethodNotFoundErrorWithArg(attr.name, MethodArgType.byDataType(valType).get) } case _: FloatType => attr.name match { case "to_i" => CalcIntType - case _ => throw new MethodNotFoundError(attr.name, valType) + // MethodArgType.byDataType returns Some(...) in that case + case _ => throw new MethodNotFoundErrorWithArg(attr.name, MethodArgType.byDataType(valType).get) } case ArrayTypeInStream(_) | CalcArrayType(_, _) => val inType = valType match { @@ -211,7 +215,8 @@ class TypeDetector(provider: TypeProvider) { attr.name match { case "first" | "last" | "min" | "max" => inType case "size" => CalcIntType - case _ => throw new MethodNotFoundError(attr.name, valType) + // MethodArgType.byDataType returns Some(...) in that case + case _ => throw new MethodNotFoundErrorWithArg(attr.name, MethodArgType.byDataType(valType).get) } case KaitaiStreamType | OwnedKaitaiStreamType => attr.name match { @@ -228,7 +233,8 @@ class TypeDetector(provider: TypeProvider) { case _: BooleanType => attr.name match { case "to_i" => CalcIntType - case _ => throw new MethodNotFoundError(attr.name, valType) + // MethodArgType.byDataType returns Some(...) in that case + case _ => throw new MethodNotFoundErrorWithArg(attr.name, MethodArgType.byDataType(valType).get) } case _ => throw new MethodNotFoundError(attr.name, valType) @@ -253,7 +259,10 @@ class TypeDetector(provider: TypeProvider) { case (_: StrType, "to_i") => CalcIntType case (_: BytesType, "to_s") => CalcStrType case _ => - throw new MethodNotFoundError(methodName.name, objType) + MethodArgType.byDataType(objType) match { + case Some(argType) => throw new MethodNotFoundErrorWithArg(methodName.name, argType) + case None => throw new MethodNotFoundError(methodName.name, objType) + } } } } From ed494ef699368c3f82c598166dda1eb200348e95 Mon Sep 17 00:00:00 2001 From: Mingun Date: Sat, 5 Oct 2024 20:02:09 +0500 Subject: [PATCH 2/3] Introduce StreamType as base for OwnedKaitaiStreamType and KaitaiStreamType --- .../main/scala/io/kaitai/struct/datatype/DataType.scala | 7 +++++-- .../scala/io/kaitai/struct/languages/CSharpCompiler.scala | 2 +- .../main/scala/io/kaitai/struct/languages/GoCompiler.scala | 2 +- .../scala/io/kaitai/struct/languages/JavaCompiler.scala | 4 ++-- .../scala/io/kaitai/struct/languages/NimCompiler.scala | 2 +- .../scala/io/kaitai/struct/languages/PHPCompiler.scala | 2 +- .../scala/io/kaitai/struct/translators/CommonMethods.scala | 2 +- .../scala/io/kaitai/struct/translators/TypeDetector.scala | 2 +- 8 files changed, 13 insertions(+), 10 deletions(-) diff --git a/shared/src/main/scala/io/kaitai/struct/datatype/DataType.scala b/shared/src/main/scala/io/kaitai/struct/datatype/DataType.scala index 96e6f4036..85a86765d 100644 --- a/shared/src/main/scala/io/kaitai/struct/datatype/DataType.scala +++ b/shared/src/main/scala/io/kaitai/struct/datatype/DataType.scala @@ -244,11 +244,14 @@ object DataType { case class CalcKaitaiStructType(override val isOwningInExpr: Boolean = false) extends StructType { def isOwning = false } - case object OwnedKaitaiStreamType extends ComplexDataType { + + /** Base class for streams from which types can be read or written. */ + abstract sealed class StreamType extends ComplexDataType + case object OwnedKaitaiStreamType extends StreamType { def isOwning = true override def asNonOwning(isOwningInExpr: Boolean = false): DataType = KaitaiStreamType } - case object KaitaiStreamType extends ComplexDataType { + case object KaitaiStreamType extends StreamType { def isOwning = false } diff --git a/shared/src/main/scala/io/kaitai/struct/languages/CSharpCompiler.scala b/shared/src/main/scala/io/kaitai/struct/languages/CSharpCompiler.scala index 97693c473..51ac0ed2b 100644 --- a/shared/src/main/scala/io/kaitai/struct/languages/CSharpCompiler.scala +++ b/shared/src/main/scala/io/kaitai/struct/languages/CSharpCompiler.scala @@ -685,7 +685,7 @@ object CSharpCompiler extends LanguageCompilerStatic case AnyType => "object" case KaitaiStructType | CalcKaitaiStructType(_) => kstructName - case KaitaiStreamType | OwnedKaitaiStreamType => kstreamName + case _: StreamType => kstreamName case t: UserType => types2class(t.name) case EnumType(name, _) => types2class(name) diff --git a/shared/src/main/scala/io/kaitai/struct/languages/GoCompiler.scala b/shared/src/main/scala/io/kaitai/struct/languages/GoCompiler.scala index 49e4343e1..8b5ea9678 100644 --- a/shared/src/main/scala/io/kaitai/struct/languages/GoCompiler.scala +++ b/shared/src/main/scala/io/kaitai/struct/languages/GoCompiler.scala @@ -667,7 +667,7 @@ object GoCompiler extends LanguageCompilerStatic case AnyType => "interface{}" case KaitaiStructType | CalcKaitaiStructType(_) => kstructName - case KaitaiStreamType | OwnedKaitaiStreamType => s"*$kstreamName" + case _: StreamType => s"*$kstreamName" case t: UserType => "*" + types2class(t.classSpec match { case Some(cs) => cs.name diff --git a/shared/src/main/scala/io/kaitai/struct/languages/JavaCompiler.scala b/shared/src/main/scala/io/kaitai/struct/languages/JavaCompiler.scala index ee19058d3..0b460e794 100644 --- a/shared/src/main/scala/io/kaitai/struct/languages/JavaCompiler.scala +++ b/shared/src/main/scala/io/kaitai/struct/languages/JavaCompiler.scala @@ -870,7 +870,7 @@ object JavaCompiler extends LanguageCompilerStatic case _: BytesType => "byte[]" case AnyType => "Object" - case KaitaiStreamType | OwnedKaitaiStreamType => kstreamName + case _: StreamType => kstreamName case KaitaiStructType | CalcKaitaiStructType(_) => kstructName case t: UserType => types2class(t.name) @@ -914,7 +914,7 @@ object JavaCompiler extends LanguageCompilerStatic case _: BytesType => "byte[]" case AnyType => "Object" - case KaitaiStreamType | OwnedKaitaiStreamType => kstreamName + case _: StreamType => kstreamName case KaitaiStructType | CalcKaitaiStructType(_) => kstructName case t: UserType => types2class(t.name) diff --git a/shared/src/main/scala/io/kaitai/struct/languages/NimCompiler.scala b/shared/src/main/scala/io/kaitai/struct/languages/NimCompiler.scala index 21868c146..c2f857cac 100644 --- a/shared/src/main/scala/io/kaitai/struct/languages/NimCompiler.scala +++ b/shared/src/main/scala/io/kaitai/struct/languages/NimCompiler.scala @@ -582,7 +582,7 @@ object NimCompiler extends LanguageCompilerStatic case _: BytesType => "seq[byte]" case KaitaiStructType | CalcKaitaiStructType(_) => "KaitaiStruct" - case KaitaiStreamType | OwnedKaitaiStreamType => "KaitaiStream" + case _: StreamType => "KaitaiStream" case t: UserType => namespaced(t.classSpec match { case Some(cs) => cs.name diff --git a/shared/src/main/scala/io/kaitai/struct/languages/PHPCompiler.scala b/shared/src/main/scala/io/kaitai/struct/languages/PHPCompiler.scala index c2c4d1476..24005340f 100644 --- a/shared/src/main/scala/io/kaitai/struct/languages/PHPCompiler.scala +++ b/shared/src/main/scala/io/kaitai/struct/languages/PHPCompiler.scala @@ -497,7 +497,7 @@ class PHPCompiler(typeProvider: ClassTypeProvider, config: RuntimeConfig) case _: ArrayType => "array" case KaitaiStructType | CalcKaitaiStructType(_) => kstructName - case KaitaiStreamType | OwnedKaitaiStreamType => kstreamName + case _: StreamType => kstreamName } } diff --git a/shared/src/main/scala/io/kaitai/struct/translators/CommonMethods.scala b/shared/src/main/scala/io/kaitai/struct/translators/CommonMethods.scala index 6b177d35e..b941b16a8 100644 --- a/shared/src/main/scala/io/kaitai/struct/translators/CommonMethods.scala +++ b/shared/src/main/scala/io/kaitai/struct/translators/CommonMethods.scala @@ -170,7 +170,7 @@ abstract trait CommonMethods[T] extends TypeDetector { } case ut: UserType => userTypeField(ut, value, attr.name) - case KaitaiStreamType | OwnedKaitaiStreamType => + case _: StreamType => attr.name match { case "size" => kaitaiStreamSize(value) case "eof" => kaitaiStreamEof(value) diff --git a/shared/src/main/scala/io/kaitai/struct/translators/TypeDetector.scala b/shared/src/main/scala/io/kaitai/struct/translators/TypeDetector.scala index 6ce44f747..e3de80d0c 100644 --- a/shared/src/main/scala/io/kaitai/struct/translators/TypeDetector.scala +++ b/shared/src/main/scala/io/kaitai/struct/translators/TypeDetector.scala @@ -218,7 +218,7 @@ class TypeDetector(provider: TypeProvider) { // MethodArgType.byDataType returns Some(...) in that case case _ => throw new MethodNotFoundErrorWithArg(attr.name, MethodArgType.byDataType(valType).get) } - case KaitaiStreamType | OwnedKaitaiStreamType => + case _: StreamType => attr.name match { case "size" => CalcIntType case "pos" => CalcIntType From 9896a8abcfbaf3ffaa688e73aabce6bd5b354206 Mon Sep 17 00:00:00 2001 From: Mingun Date: Sat, 5 Oct 2024 20:35:06 +0500 Subject: [PATCH 3/3] Introduce StreamArg to better typecheck the `io` type --- .../struct/translators/CommonMethods.scala | 16 ++++++++++------ .../kaitai/struct/translators/TypeDetector.scala | 3 ++- 2 files changed, 12 insertions(+), 7 deletions(-) diff --git a/shared/src/main/scala/io/kaitai/struct/translators/CommonMethods.scala b/shared/src/main/scala/io/kaitai/struct/translators/CommonMethods.scala index b941b16a8..1f751d4b9 100644 --- a/shared/src/main/scala/io/kaitai/struct/translators/CommonMethods.scala +++ b/shared/src/main/scala/io/kaitai/struct/translators/CommonMethods.scala @@ -26,6 +26,9 @@ object MethodArgType { case object ArrayArg extends MethodArgType { override def toString = "array" } + case object StreamArg extends MethodArgType { + override def toString = "io stream" + } def byDataType(dataType: DataType): Option[MethodArgType] = { dataType match { @@ -35,6 +38,7 @@ object MethodArgType { case _: BooleanType => Some(BooleanArg) case _: BytesType => Some(BytesArg) case _: ArrayType => Some(ArrayArg) + case _: StreamType => Some(StreamArg) case _ => None } } @@ -133,6 +137,12 @@ abstract trait CommonMethods[T] extends TypeDetector { MethodSig0("min", AnyType, arrayMin), MethodSig0("max", AnyType, arrayMax), ), + + StreamArg -> List( + MethodSig0("eof", CalcBooleanType, kaitaiStreamEof), + MethodSig0("pos", CalcIntType, kaitaiStreamPos), + MethodSig0("size", CalcIntType, kaitaiStreamSize), + ), ) /** @@ -170,12 +180,6 @@ abstract trait CommonMethods[T] extends TypeDetector { } case ut: UserType => userTypeField(ut, value, attr.name) - case _: StreamType => - attr.name match { - case "size" => kaitaiStreamSize(value) - case "eof" => kaitaiStreamEof(value) - case "pos" => kaitaiStreamPos(value) - } case et: EnumType => attr.name match { case "to_i" => enumToInt(value, et) diff --git a/shared/src/main/scala/io/kaitai/struct/translators/TypeDetector.scala b/shared/src/main/scala/io/kaitai/struct/translators/TypeDetector.scala index e3de80d0c..b96716896 100644 --- a/shared/src/main/scala/io/kaitai/struct/translators/TypeDetector.scala +++ b/shared/src/main/scala/io/kaitai/struct/translators/TypeDetector.scala @@ -223,7 +223,8 @@ class TypeDetector(provider: TypeProvider) { case "size" => CalcIntType case "pos" => CalcIntType case "eof" => CalcBooleanType - case _ => throw new MethodNotFoundError(attr.name, valType) + // MethodArgType.byDataType returns Some(...) in that case + case _ => throw new MethodNotFoundErrorWithArg(attr.name, MethodArgType.byDataType(valType).get) } case et: EnumType => attr.name match {