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 6d6e9f00e..bb2cf307d 100644 --- a/shared/src/main/scala/io/kaitai/struct/datatype/DataType.scala +++ b/shared/src/main/scala/io/kaitai/struct/datatype/DataType.scala @@ -32,14 +32,58 @@ object DataType { def apiCall(defEndian: Option[FixedEndian]): String } + /** A generic number type. */ abstract sealed class NumericType extends DataType + /** A generic boolean type. */ abstract sealed class BooleanType extends DataType + /** A generic integer type. */ abstract sealed class IntType extends NumericType + /** + * An integer type that occupies undecided number of bytes in the stream. + * + * If it possible to determine, the more narrow `Int1Type` will be inferred + * for an expression instead of this type. + * + * Represents a type of the following constructions: + * + * - `sizeof<>` and `bitsizeof<>` built-in operators + * - `_sizeof` special property of fields and self object + * - `size` and `pos` properties of streams + * - `to_i` result when converting other types (strings, floats, enums, and booleans) to integers + * - `length` and `size` properties of arrays + * - `length` property of strings + * - `_index` context variable + */ case object CalcIntType extends IntType + /** + * An integer type that fit into the byte and therefore can represent element + * of the byte array. + * + * Parameters have this type when it's declared with `type: u1` or `type: s1`. + * + * Represents a type of the following constructions: + * + * - `Int1Type(true)` -- a constant in the [0..127] range + * - `Int1Type(false)` -- a constant in the [128..255] range + * - element type of byte arrays + * - `first`, `last`, `min`, and `max` properties of byte arrays + * - result of the `[]` operator of byte arrays + * + * @param signed Determines if most significant bit of number contains sign + */ case class Int1Type(signed: Boolean) extends IntType with ReadableType { override def apiCall(defEndian: Option[FixedEndian]): String = if (signed) "s1" else "u1" } + /** + * An integer type that occupies some predefined size in bytes in the stream. + * + * Parameters have this type when it's declared with `type: u` or `type: s`. + * + * @param signed Determines if most significant bit of number contains sign + * @param width Size of type in bytes + * @param endian Byte order used to represent the number + */ case class IntMultiType(signed: Boolean, width: IntWidth, endian: Option[FixedEndian]) extends IntType with ReadableType { override def apiCall(defEndian: Option[FixedEndian]): String = { val ch1 = if (signed) 's' else 'u' @@ -47,11 +91,34 @@ object DataType { s"$ch1${width.width}${finalEnd.map(_.toSuffix).getOrElse("")}" } } + /** + * A boolean type that occupies one bit in the stream. + * + * Parameters have this type when it's declared with `type: b1`. + */ case class BitsType1(bitEndian: BitEndianness) extends BooleanType + /** + * An integer number type that occupies some predefined size in _bits_ in the stream. + * + * Parameters have this type when it's declared with `type: bX`. + * + * @param width Size of type in bits + * @param bitEndian Bit order inside of byte used to represent the number + */ case class BitsType(width: Int, bitEndian: BitEndianness) extends IntType + /** A generic floating-point number type. */ abstract sealed class FloatType extends NumericType + /** A floating-point number type that occupies undecided number of bytes in the stream. */ case object CalcFloatType extends FloatType + /** + * A floating-point number type that occupies some predefined size in bytes in the stream. + * + * Parameters have this type when it's declared with `type: fX`. + * + * @param width Size of type in bytes + * @param endian Byte order used to represent the number + */ case class FloatMultiType(width: IntWidth, endian: Option[FixedEndian]) extends FloatType with ReadableType { override def apiCall(defEndian: Option[FixedEndian]): String = { val finalEnd = endian.orElse(defEndian) @@ -63,7 +130,13 @@ object DataType { def process: Option[ProcessExpr] } + /** A generic raw bytes type. */ abstract sealed class BytesType extends DataType with Processing + /** + * A raw bytes type that occupies undecided number of bytes in the stream. + * + * Parameters have this type when it's declared with `type: bytes`. + */ case object CalcBytesType extends BytesType { override def process = None } @@ -88,10 +161,27 @@ object DataType { override val process: Option[ProcessExpr] ) extends BytesType + /** A generic string type. */ abstract sealed class StrType extends DataType + /** + * A pure string type that occupies undecided number of bytes in the stream. + * + * Parameters have this type when it's declared with `type: str`. + */ case object CalcStrType extends StrType + /** + * A type that have the `str` and `strz` built-in Kaitai types. + * + * @param bytes An underlying bytes of the string + * @param encoding An encoding used to convert byte array into string + */ case class StrFromBytesType(bytes: BytesType, encoding: String) extends StrType + /** + * A boolean type that occupies undecided number of bytes in the stream. + * + * Parameters have this type when it's declared with `type: bool`. + */ case object CalcBooleanType extends BooleanType /** @@ -133,6 +223,7 @@ object DataType { cs.isTopLevel || cs.meta.isOpaque } } + /** User type which isn't restricted in size (i.e. without `size`, `terminator`, or `size-eos`). */ case class UserTypeInstream( _name: List[String], _forcedParent: Option[Ast.expr], @@ -145,6 +236,7 @@ object DataType { r } } + /** User type which is restricted in size either via `size`, `terminator`, or `size-eos`. */ case class UserTypeFromBytes( _name: List[String], _forcedParent: Option[Ast.expr], @@ -159,6 +251,12 @@ object DataType { r } } + /** + * Reference to the user type which isn't restricted in size (i.e. without + * `size`, `terminator`, or `size-eos`). + * + * Parameters have this type when it's declared with any non-built-in type. + */ case class CalcUserType( _name: List[String], _forcedParent: Option[Ast.expr], @@ -166,6 +264,10 @@ object DataType { ) extends UserType(_name, _forcedParent, _args) { override def isOwning = false } + /** + * Reference to the user type which restricted in size either via `size`, + * `terminator`, or `size-eos`. + */ case class CalcUserTypeFromBytes( _name: List[String], _forcedParent: Option[Ast.expr], @@ -176,30 +278,75 @@ object DataType { override def isOwning = false } + /** + * A generic collection type. + * + * @param elType Type of elements in the collection + */ abstract sealed class ArrayType(val elType: DataType) extends ComplexDataType - + /** + * An owned slice of array type. This type is used for holding data in attributes + * with `repeat` key. Number of elements in that type is unknown + * + * @param _elType Type of elements in the slice + */ case class ArrayTypeInStream(_elType: DataType) extends ArrayType(_elType) { override def isOwning: Boolean = true override def asNonOwning: CalcArrayType = CalcArrayType(elType) } + /** + * A borrowed slice of an array. This type is used when array is passed as a + * parameter to the user type (parameter have type `bytes` or haven't any + * explicitly defined type). Number of elements in that type is unknown + * + * @param _elType Type of elements in the slice + */ case class CalcArrayType(_elType: DataType) extends ArrayType(_elType) { override def isOwning: Boolean = false } val USER_TYPE_NO_PARENT = Ast.expr.Bool(false) + /** + * A very generic type that can hold any other type. Used when type of expression + * is completely unknown to the compiler. + * + * Parameters have this type when it's declared with `type: any`. + */ case object AnyType extends DataType + + /** + * A type that can hold any Kaitai generated type. Can be used as common ancestor + * of `switch-on` types, when all alternative types is owned. + */ case object KaitaiStructType extends StructType { def isOwning = true override def asNonOwning: DataType = CalcKaitaiStructType } + /** + * A type that can hold any Kaitai generated type. Can be used as common ancestor + * of `switch-on` types, when at least one of the alternative types is borrowed. + * + * Parameters have this type when it's declared with `type: struct`. + */ case object CalcKaitaiStructType extends StructType { def isOwning = false } + /** + * A type that hold and own Kaitai stream object. This type is used when a new IO object + * is allocated (i.e. when new sub-stream is created for types with `size`, `terminator`, + * or `size-eos: true` attributes). + */ case object OwnedKaitaiStreamType extends ComplexDataType { def isOwning = true override def asNonOwning: DataType = KaitaiStreamType } + /** + * A type that hold and borrow Kaitai stream object. This type is used + * when an IO object is passed as parameter to the user type. + * + * Parameters have this type when it's declared with `type: io`. + */ case object KaitaiStreamType extends ComplexDataType { def isOwning = false } @@ -377,6 +524,8 @@ object DataType { StrFromBytesType(bat, enc) case _ => val typeWithArgs = Expressions.parseTypeRef(dt) + // if `size`, `terminator` and `size-eos: true` isn't defined, + // user type uses parent stream, otherwise creates an own stream if (arg.size.isEmpty && !arg.sizeEos && arg.terminator.isEmpty) { if (arg.process.isDefined) throw KSYParseError(s"user type '$dt': need 'size' / 'size-eos' / 'terminator' if 'process' is used", path).toException