diff --git a/shared/src/main/scala/io/kaitai/struct/datatype/NeedRaw.scala b/shared/src/main/scala/io/kaitai/struct/datatype/NeedRaw.scala deleted file mode 100644 index 494ea92e3..000000000 --- a/shared/src/main/scala/io/kaitai/struct/datatype/NeedRaw.scala +++ /dev/null @@ -1,24 +0,0 @@ -package io.kaitai.struct.datatype - -sealed trait NeedRaw { - val level: Int - val hasIO: Boolean = false - val hasRaw: Boolean = false -} - -case object NotRaw extends NeedRaw { - val level = 0 -} -case object RawIo extends NeedRaw { - val level = 1 - override val hasIO = true -} -case object RawProcess extends NeedRaw { - val level = 1 - override val hasRaw = true -} -case object RawIoProcess extends NeedRaw { - val level = 2 - override val hasIO = true - override val hasRaw = true -} 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 2487a64e3..b2731e557 100644 --- a/shared/src/main/scala/io/kaitai/struct/languages/CSharpCompiler.scala +++ b/shared/src/main/scala/io/kaitai/struct/languages/CSharpCompiler.scala @@ -270,13 +270,9 @@ class CSharpCompiler(typeProvider: ClassTypeProvider, config: RuntimeConfig) override def condIfFooter: Unit = fileFooter(null) - override def condRepeatCommonInit(id: Identifier, dataType: DataType, needRaw: NeedRaw): Unit = { + override def condRepeatInitAttr(id: Identifier, dataType: DataType): Unit = { importList.add("System.Collections.Generic") - if (needRaw.level >= 1) - out.puts(s"${privateMemberName(RawIdentifier(id))} = new List();") - if (needRaw.level >= 2) - out.puts(s"${privateMemberName(RawIdentifier(RawIdentifier(id)))} = new List();") out.puts(s"${privateMemberName(id)} = new ${kaitaiType2NativeType(ArrayTypeInStream(dataType))}();") } diff --git a/shared/src/main/scala/io/kaitai/struct/languages/CppCompiler.scala b/shared/src/main/scala/io/kaitai/struct/languages/CppCompiler.scala index 60a19cf9a..b6d93d31e 100644 --- a/shared/src/main/scala/io/kaitai/struct/languages/CppCompiler.scala +++ b/shared/src/main/scala/io/kaitai/struct/languages/CppCompiler.scala @@ -386,87 +386,43 @@ class CppCompiler( outSrc.inc } - val needRaw = this.needRaw(attr.dataType) - val innerType = attr.dataType match { - case st: SwitchType => st.combinedType - case t => t + (ExtraAttrs.forAttr(attr, this) ++ List(attr)).foreach { (attr) => + val innerType = attr.dataType match { + case st: SwitchType => combineSwitchType(st) + case t => t + } + destructMember(attr.id, innerType, attr.isArray) } - destructMember(id, innerType, attr.isArray, needRaw) - if (checks.nonEmpty) { outSrc.dec outSrc.puts("}") } } - def destructMember(id: Identifier, innerType: DataType, isArray: Boolean, needRaw: NeedRaw): Unit = { - def destructWithSafeguardHeader(ptr: String): Unit = { - outSrc.puts(s"if ($ptr) {") - outSrc.inc - } - def destructWithSafeguardFooter(ptr: String): Unit = { - outSrc.puts(s"delete $ptr; $ptr = $nullPtr;") - outSrc.dec - outSrc.puts("}") - } - def destructWithSafeguardSimple(ptr: String): Unit = { - destructWithSafeguardHeader(ptr) - destructWithSafeguardFooter(ptr) - } - if (config.cppConfig.pointers == CppRuntimeConfig.RawPointers) { - if (isArray) { - // raw is std::vector*, no need to delete its contents, but we - // need to clean up the vector pointer itself - if (needRaw.level >= 1) { - destructWithSafeguardSimple(privateMemberName(RawIdentifier(id))) - - // IO is std::vector*, needs destruction of both members - // and the vector pointer itself - if (needRaw.hasIO) { - val ioVar = privateMemberName(IoStorageIdentifier(RawIdentifier(id))) - destructWithSafeguardHeader(ioVar) - destructVector(s"$kstreamName*", ioVar) - destructWithSafeguardFooter(ioVar) - } - } - if (needRaw.level >= 2) { - // m__raw__raw_* is also std::vector*, we just clean up the vector pointer - destructWithSafeguardSimple(privateMemberName(RawIdentifier(RawIdentifier(id)))) - } - - val arrVar = privateMemberName(id) - destructWithSafeguardHeader(arrVar) + def destructMember(id: Identifier, innerType: DataType, isArray: Boolean): Unit = { + if (config.cppConfig.pointers != CppRuntimeConfig.RawPointers) + return - // main member contents - if (needsDestruction(innerType)) { - // C++ specific substitution: AnyType results from generic struct + raw bytes - // so we would assume that only generic struct needs to be cleaned up - val realType = innerType match { - case AnyType => KaitaiStructType - case _ => innerType - } + val ptr = privateMemberName(id) + val innerNeedsDestruct = needsDestruction(innerType) - destructVector(kaitaiType2NativeType(realType), arrVar) - } + if (!isArray && !innerNeedsDestruct) + return - // main member is a std::vector of something, always needs destruction - destructWithSafeguardFooter(arrVar) - } else { - // raw is just a string, no need to cleanup => we ignore `needRaw.hasRaw` + outSrc.puts(s"if ($ptr) {") + outSrc.inc - // but needRaw.hasIO is important - if (needRaw.hasIO) - destructWithSafeguardSimple(privateMemberName(IoStorageIdentifier(RawIdentifier(id)))) + if (isArray && innerNeedsDestruct) + destructVector(kaitaiType2NativeType(innerType), ptr) - if (needsDestruction(innerType)) - destructWithSafeguardSimple(privateMemberName(id)) - } - } + outSrc.puts(s"delete $ptr; $ptr = $nullPtr;") + outSrc.dec + outSrc.puts("}") } def needsDestruction(t: DataType): Boolean = t match { - case _: UserType | _: ArrayTypeInStream | KaitaiStructType | AnyType => true + case _: UserType | _: ArrayTypeInStream | KaitaiStructType | AnyType | OwnedKaitaiStreamType => true case _ => false } @@ -615,18 +571,9 @@ class CppCompiler( outSrc.puts("}") } - override def condRepeatCommonInit(id: Identifier, dataType: DataType, needRaw: NeedRaw): Unit = { + override def condRepeatInitAttr(id: Identifier, dataType: DataType): Unit = { importListHdr.addSystem("vector") - if (needRaw.level >= 1) { - outSrc.puts(s"${privateMemberName(RawIdentifier(id))} = ${newVector(CalcBytesType)};") - if (needRaw.hasIO) { - outSrc.puts(s"${privateMemberName(IoStorageIdentifier(RawIdentifier(id)))} = ${newVector(OwnedKaitaiStreamType)};") - } - } - if (needRaw.level >= 2) { - outSrc.puts(s"${privateMemberName(RawIdentifier(RawIdentifier(id)))} = ${newVector(CalcBytesType)};") - } outSrc.puts(s"${privateMemberName(id)} = ${newVector(dataType)};") } @@ -908,14 +855,24 @@ class CppCompiler( outSrc.puts(s"return ${nonOwningPointer(instName, attrType)};") override def instanceCalculate(instName: Identifier, dataType: DataType, value: Ast.expr): Unit = { - if (config.readStoresPos) + if (attrDebugNeeded(instName)) attrDebugStart(instName, dataType, None, NoRepeat) val valExpr = expression(value) val isOwningInExpr = dataType match { case ct: ComplexDataType => ct.isOwningInExpr case _ => false } - handleAssignmentSimple(instName, if (isOwningInExpr) s"$valExpr.get()" else valExpr) + val valExprConverted = if (isOwningInExpr) { + config.cppConfig.pointers match { + case RawPointers => + valExpr + case UniqueAndRawPointers => + s"$valExpr.get()" + } + } else { + valExpr + } + handleAssignmentSimple(instName, valExprConverted) } override def enumDeclaration(curClass: List[String], enumName: String, enumColl: Seq[(Long, EnumValueSpec)]): Unit = { 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 2c8b00cc2..90b4d1637 100644 --- a/shared/src/main/scala/io/kaitai/struct/languages/GoCompiler.scala +++ b/shared/src/main/scala/io/kaitai/struct/languages/GoCompiler.scala @@ -274,7 +274,7 @@ class GoCompiler(typeProvider: ClassTypeProvider, config: RuntimeConfig) out.inc } - override def condRepeatCommonInit(id: Identifier, dataType: DataType, needRaw: NeedRaw): Unit = { + override def condRepeatInitAttr(id: Identifier, dataType: DataType): Unit = { // slices don't have to be manually initialized in Go: the built-in append() // function works even on `nil` slices (https://go.dev/tour/moretypes/15) } 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 cb9dc4d5e..9e1780d1e 100644 --- a/shared/src/main/scala/io/kaitai/struct/languages/JavaCompiler.scala +++ b/shared/src/main/scala/io/kaitai/struct/languages/JavaCompiler.scala @@ -501,10 +501,7 @@ class JavaCompiler(typeProvider: ClassTypeProvider, config: RuntimeConfig) override def attrDebugStart(attrId: Identifier, attrType: DataType, ios: Option[String], rep: RepeatSpec): Unit = { ios.foreach { (io) => - val name = attrId match { - case _: RawIdentifier | _: SpecialIdentifier => return - case _ => idToStr(attrId) - } + val name = idToStr(attrId) rep match { case NoRepeat => out.puts("_attrStart.put(\"" + name + "\", " + io + ".pos());") @@ -514,11 +511,12 @@ class JavaCompiler(typeProvider: ClassTypeProvider, config: RuntimeConfig) } } + override def attrDebugArrInit(attrName: Identifier, attrType: DataType): Unit = { + // no _debug[$name]['arr'] initialization needed in Java + } + override def attrDebugEnd(attrId: Identifier, attrType: DataType, io: String, rep: RepeatSpec): Unit = { - val name = attrId match { - case _: RawIdentifier | _: SpecialIdentifier => return - case _ => idToStr(attrId) - } + val name = idToStr(attrId) rep match { case NoRepeat => out.puts("_attrEnd.put(\"" + name + "\", " + io + ".pos());") @@ -547,30 +545,8 @@ class JavaCompiler(typeProvider: ClassTypeProvider, config: RuntimeConfig) out.inc } - override def condRepeatCommonInit(id: Identifier, dataType: DataType, needRaw: NeedRaw): Unit = { - if (needRaw.level >= 1) - out.puts(s"${privateMemberName(RawIdentifier(id))} = new ArrayList();") - if (needRaw.level >= 2) - out.puts(s"${privateMemberName(RawIdentifier(RawIdentifier(id)))} = new ArrayList();") - if (config.readWrite) { - dataType match { - case utb: UserTypeFromBytes => - if (writeNeedsOuterSize(utb.bytes)) - out.puts(s"${privateMemberName(OuterSizeIdentifier(id))} = new ArrayList();") - if (writeNeedsInnerSize(utb.bytes)) - out.puts(s"${privateMemberName(InnerSizeIdentifier(id))} = new ArrayList();") - case _ => // do nothing - } - } + override def condRepeatInitAttr(id: Identifier, dataType: DataType): Unit = out.puts(s"${privateMemberName(id)} = new ${kaitaiType2JavaType(ArrayTypeInStream(dataType))}();") - } - - override def condRepeatCommonWriteInit(id: Identifier, dataType: DataType, needRaw: NeedRaw): Unit = { - if (needRaw.level >= 1) - out.puts(s"${privateMemberName(RawIdentifier(id))} = new ArrayList();") - if (needRaw.level >= 2) - out.puts(s"${privateMemberName(RawIdentifier(RawIdentifier(id)))} = new ArrayList();") - } override def condRepeatEosHeader(id: Identifier, io: String, dataType: DataType): Unit = { out.puts("{") @@ -688,9 +664,9 @@ class JavaCompiler(typeProvider: ClassTypeProvider, config: RuntimeConfig) castIfNeeded(expr, dataType, assignType) } - override def createSubstreamFixedSize(id: Identifier, sizeExpr: Ast.expr, io: String): String = { + override def createSubstreamFixedSize(id: Identifier, blt: BytesLimitType, io: String, rep: RepeatSpec, defEndian: Option[FixedEndian]): String = { val ioName = idToStr(IoStorageIdentifier(id)) - handleAssignmentTempVar(KaitaiStreamType, ioName, s"$io.substream(${translator.translate(sizeExpr)});") + handleAssignmentTempVar(KaitaiStreamType, ioName, s"$io.substream(${translator.translate(blt.size)})") ioName } diff --git a/shared/src/main/scala/io/kaitai/struct/languages/JavaScriptCompiler.scala b/shared/src/main/scala/io/kaitai/struct/languages/JavaScriptCompiler.scala index de0872fde..31b07acfe 100644 --- a/shared/src/main/scala/io/kaitai/struct/languages/JavaScriptCompiler.scala +++ b/shared/src/main/scala/io/kaitai/struct/languages/JavaScriptCompiler.scala @@ -254,9 +254,6 @@ class JavaScriptCompiler(typeProvider: ClassTypeProvider, config: RuntimeConfig) out.puts(s"$io.alignToByte();") override def attrDebugStart(attrId: Identifier, attrType: DataType, io: Option[String], rep: RepeatSpec): Unit = { - if (!attrDebugNeeded(attrId)) - return - val debugName = attrDebugName(attrId, rep, false) val ioProps = io match { @@ -272,9 +269,10 @@ class JavaScriptCompiler(typeProvider: ClassTypeProvider, config: RuntimeConfig) out.puts(s"$debugName = { $ioProps${if (ioProps != "" && enumNameProps != "") ", " else ""}$enumNameProps };") } + override def attrDebugArrInit(id: Identifier, attrType: DataType): Unit = + out.puts(s"this._debug.${idToStr(id)}.arr = [];") + override def attrDebugEnd(attrId: Identifier, attrType: DataType, io: String, rep: RepeatSpec): Unit = { - if (!attrDebugNeeded(attrId)) - return val debugName = attrDebugName(attrId, rep, true) out.puts(s"$debugName.end = $io.pos;") @@ -291,15 +289,8 @@ class JavaScriptCompiler(typeProvider: ClassTypeProvider, config: RuntimeConfig) out.puts("}") } - override def condRepeatCommonInit(id: Identifier, dataType: DataType, needRaw: NeedRaw): Unit = { - if (needRaw.level >= 1) - out.puts(s"${privateMemberName(RawIdentifier(id))} = [];") - if (needRaw.level >= 2) - out.puts(s"${privateMemberName(RawIdentifier(RawIdentifier(id)))} = [];") + override def condRepeatInitAttr(id: Identifier, dataType: DataType): Unit = out.puts(s"${privateMemberName(id)} = [];") - if (config.readStoresPos) - out.puts(s"this._debug.${idToStr(id)}.arr = [];") - } override def condRepeatEosHeader(id: Identifier, io: String, dataType: DataType): Unit = { out.puts("var i = 0;") @@ -578,12 +569,6 @@ class JavaScriptCompiler(typeProvider: ClassTypeProvider, config: RuntimeConfig) out.puts("}") } - private - def attrDebugNeeded(attrId: Identifier) = attrId match { - case _: NamedIdentifier | _: NumberedIdentifier | _: InstanceIdentifier => true - case _: RawIdentifier | _: SpecialIdentifier => false - } - def attrDebugName(attrId: Identifier, rep: RepeatSpec, end: Boolean) = { val arrIndexExpr = rep match { case NoRepeat => "" diff --git a/shared/src/main/scala/io/kaitai/struct/languages/LuaCompiler.scala b/shared/src/main/scala/io/kaitai/struct/languages/LuaCompiler.scala index 6ccb47506..bf8065a18 100644 --- a/shared/src/main/scala/io/kaitai/struct/languages/LuaCompiler.scala +++ b/shared/src/main/scala/io/kaitai/struct/languages/LuaCompiler.scala @@ -1,7 +1,7 @@ package io.kaitai.struct.languages import io.kaitai.struct.{ClassTypeProvider, RuntimeConfig, Utils} -import io.kaitai.struct.datatype.{DataType, FixedEndian, InheritedEndian, KSError, ValidationNotEqualError, NeedRaw} +import io.kaitai.struct.datatype.{DataType, FixedEndian, InheritedEndian, KSError, ValidationNotEqualError} import io.kaitai.struct.datatype.DataType._ import io.kaitai.struct.exprlang.Ast import io.kaitai.struct.format._ @@ -158,11 +158,7 @@ class LuaCompiler(typeProvider: ClassTypeProvider, config: RuntimeConfig) out.puts("end") } - override def condRepeatCommonInit(id: Identifier, dataType: DataType, needRaw: NeedRaw): Unit = { - if (needRaw.level >= 1) - out.puts(s"${privateMemberName(RawIdentifier(id))} = {}") - if (needRaw.level >= 2) - out.puts(s"${privateMemberName(RawIdentifier(RawIdentifier(id)))} = {}") + override def condRepeatInitAttr(id: Identifier, dataType: DataType): Unit = { out.puts(s"${privateMemberName(id)} = {}") } 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 aaa36c579..87bc33b7d 100644 --- a/shared/src/main/scala/io/kaitai/struct/languages/NimCompiler.scala +++ b/shared/src/main/scala/io/kaitai/struct/languages/NimCompiler.scala @@ -149,7 +149,7 @@ class NimCompiler(typeProvider: ClassTypeProvider, config: RuntimeConfig) universalFooter } - override def condRepeatCommonInit(id: Identifier, dataType: DataType, needRaw: NeedRaw): Unit = { + override def condRepeatInitAttr(id: Identifier, dataType: DataType): Unit = { // sequences don't have to be manually initialized in Nim - they're automatically initialized as // empty sequences (see https://narimiran.github.io/nim-basics/#_result_variable) } 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 5e182535a..6a50fc8ce 100644 --- a/shared/src/main/scala/io/kaitai/struct/languages/PHPCompiler.scala +++ b/shared/src/main/scala/io/kaitai/struct/languages/PHPCompiler.scala @@ -1,7 +1,7 @@ package io.kaitai.struct.languages import io.kaitai.struct.datatype.DataType._ -import io.kaitai.struct.datatype.{CalcEndian, DataType, FixedEndian, InheritedEndian, KSError, NeedRaw, UndecidedEndiannessError} +import io.kaitai.struct.datatype.{CalcEndian, DataType, FixedEndian, InheritedEndian, KSError, UndecidedEndiannessError} import io.kaitai.struct.exprlang.Ast import io.kaitai.struct.format.{NoRepeat, RepeatEos, RepeatExpr, RepeatSpec, _} import io.kaitai.struct.languages.components._ @@ -263,13 +263,8 @@ class PHPCompiler(typeProvider: ClassTypeProvider, config: RuntimeConfig) out.inc } - override def condRepeatCommonInit(id: Identifier, dataType: DataType, needRaw: NeedRaw): Unit = { - if (needRaw.level >= 1) - out.puts(s"${privateMemberName(RawIdentifier(id))} = [];") - if (needRaw.level >= 2) - out.puts(s"${privateMemberName(RawIdentifier(RawIdentifier(id)))} = [];") + override def condRepeatInitAttr(id: Identifier, dataType: DataType): Unit = out.puts(s"${privateMemberName(id)} = [];") - } override def condRepeatEosHeader(id: Identifier, io: String, dataType: DataType): Unit = { out.puts("$i = 0;") diff --git a/shared/src/main/scala/io/kaitai/struct/languages/PerlCompiler.scala b/shared/src/main/scala/io/kaitai/struct/languages/PerlCompiler.scala index 952a1ec89..5b0b8badb 100644 --- a/shared/src/main/scala/io/kaitai/struct/languages/PerlCompiler.scala +++ b/shared/src/main/scala/io/kaitai/struct/languages/PerlCompiler.scala @@ -1,6 +1,6 @@ package io.kaitai.struct.languages -import io.kaitai.struct.datatype.{DataType, FixedEndian, InheritedEndian, KSError, NeedRaw} +import io.kaitai.struct.datatype.{DataType, FixedEndian, InheritedEndian, KSError} import io.kaitai.struct.datatype.DataType._ import io.kaitai.struct.exprlang.Ast import io.kaitai.struct.exprlang.Ast.expr @@ -231,13 +231,8 @@ class PerlCompiler(typeProvider: ClassTypeProvider, config: RuntimeConfig) out.inc } - override def condRepeatCommonInit(id: Identifier, dataType: DataType, needRaw: NeedRaw): Unit = { - if (needRaw.level >= 1) - out.puts(s"${privateMemberName(RawIdentifier(id))} = [];") - if (needRaw.level >= 2) - out.puts(s"${privateMemberName(RawIdentifier(RawIdentifier(id)))} = [];") + override def condRepeatInitAttr(id: Identifier, dataType: DataType): Unit = out.puts(s"${privateMemberName(id)} = [];") - } override def condRepeatEosHeader(id: Identifier, io: String, dataType: DataType): Unit = { out.puts(s"while (!$io->is_eof()) {") diff --git a/shared/src/main/scala/io/kaitai/struct/languages/PythonCompiler.scala b/shared/src/main/scala/io/kaitai/struct/languages/PythonCompiler.scala index 728d63069..b58912f17 100644 --- a/shared/src/main/scala/io/kaitai/struct/languages/PythonCompiler.scala +++ b/shared/src/main/scala/io/kaitai/struct/languages/PythonCompiler.scala @@ -490,30 +490,21 @@ class PythonCompiler(typeProvider: ClassTypeProvider, config: RuntimeConfig) override def attrDebugStart(attrId: Identifier, attrType: DataType, ios: Option[String], rep: RepeatSpec): Unit = { ios.foreach { (io) => - val name = attrId match { - case _: RawIdentifier | _: SpecialIdentifier => return - case _ => idToStr(attrId) - } + val name = idToStr(attrId) rep match { case NoRepeat => out.puts(s"self._debug['$name']['start'] = $io.pos()") case _: RepeatExpr | RepeatEos | _: RepeatUntil => - /** TODO: move array initialization to [[condRepeatCommonInit]] - see - * [[JavaScriptCompiler.condRepeatCommonInit]] for inspiration */ - out.puts(s"if not 'arr' in self._debug['$name']:") - out.inc - out.puts(s"self._debug['$name']['arr'] = []") - out.dec out.puts(s"self._debug['$name']['arr'].append({'start': $io.pos()})") } } } + override def attrDebugArrInit(attrId: Identifier, attrType: DataType): Unit = + out.puts(s"self._debug['${idToStr(attrId)}']['arr'] = []") + override def attrDebugEnd(attrId: Identifier, attrType: DataType, io: String, rep: RepeatSpec): Unit = { - val name = attrId match { - case _: RawIdentifier | _: SpecialIdentifier => return - case _ => idToStr(attrId) - } + val name = idToStr(attrId) rep match { case NoRepeat => out.puts(s"self._debug['$name']['end'] = $io.pos()") @@ -530,30 +521,8 @@ class PythonCompiler(typeProvider: ClassTypeProvider, config: RuntimeConfig) out.puts("pass") } - override def condRepeatCommonInit(id: Identifier, dataType: DataType, needRaw: NeedRaw): Unit = { - if (needRaw.level >= 1) - out.puts(s"${privateMemberName(RawIdentifier(id))} = []") - if (needRaw.level >= 2) - out.puts(s"${privateMemberName(RawIdentifier(RawIdentifier(id)))} = []") - if (config.readWrite) { - dataType match { - case utb: UserTypeFromBytes => - if (writeNeedsOuterSize(utb.bytes)) - out.puts(s"${privateMemberName(OuterSizeIdentifier(id))} = []") - if (writeNeedsInnerSize(utb.bytes)) - out.puts(s"${privateMemberName(InnerSizeIdentifier(id))} = []") - case _ => // do nothing - } - } + override def condRepeatInitAttr(id: Identifier, dataType: DataType): Unit = out.puts(s"${privateMemberName(id)} = []") - } - - override def condRepeatCommonWriteInit(id: Identifier, dataType: DataType, needRaw: NeedRaw): Unit = { - if (needRaw.level >= 1) - out.puts(s"${privateMemberName(RawIdentifier(id))} = []") - if (needRaw.level >= 2) - out.puts(s"${privateMemberName(RawIdentifier(RawIdentifier(id)))} = []") - } override def condRepeatEosHeader(id: Identifier, io: String, dataType: DataType): Unit = { out.puts("i = 0") diff --git a/shared/src/main/scala/io/kaitai/struct/languages/RubyCompiler.scala b/shared/src/main/scala/io/kaitai/struct/languages/RubyCompiler.scala index 539bf7182..b38f572c4 100644 --- a/shared/src/main/scala/io/kaitai/struct/languages/RubyCompiler.scala +++ b/shared/src/main/scala/io/kaitai/struct/languages/RubyCompiler.scala @@ -239,26 +239,23 @@ class RubyCompiler(typeProvider: ClassTypeProvider, config: RuntimeConfig) override def attrDebugStart(attrId: Identifier, attrType: DataType, ios: Option[String], rep: RepeatSpec): Unit = { ios.foreach { (io) => - val name = attrId match { - case _: RawIdentifier | _: SpecialIdentifier => return - case _ => idToStr(attrId) - } + val name = idToStr(attrId) rep match { case NoRepeat => out.puts(s"(@_debug['$name'] ||= {})[:start] = $io.pos") case _: RepeatExpr => - out.puts(s"(@_debug['$name'][:arr] ||= [])[i] = {:start => $io.pos}") + out.puts(s"@_debug['$name'][:arr][i] = {:start => $io.pos}") case RepeatEos | _: RepeatUntil => - out.puts(s"(@_debug['$name'][:arr] ||= [])[${privateMemberName(attrId)}.size] = {:start => $io.pos}") + out.puts(s"@_debug['$name'][:arr][${privateMemberName(attrId)}.size] = {:start => $io.pos}") } } } + override def attrDebugArrInit(attrId: Identifier, attrType: DataType): Unit = + out.puts(s"@_debug['${idToStr(attrId)}'][:arr] = []") + override def attrDebugEnd(attrId: Identifier, attrType: DataType, io: String, rep: RepeatSpec): Unit = { - val name = attrId match { - case _: RawIdentifier | _: SpecialIdentifier => return - case _ => idToStr(attrId) - } + val name = idToStr(attrId) rep match { case NoRepeat => out.puts(s"(@_debug['$name'] ||= {})[:end] = $io.pos") @@ -274,13 +271,8 @@ class RubyCompiler(typeProvider: ClassTypeProvider, config: RuntimeConfig) out.inc } - override def condRepeatCommonInit(id: Identifier, dataType: DataType, needRaw: NeedRaw): Unit = { - if (needRaw.level >= 1) - out.puts(s"${privateMemberName(RawIdentifier(id))} = []") - if (needRaw.level >= 2) - out.puts(s"${privateMemberName(RawIdentifier(RawIdentifier(id)))} = []") + override def condRepeatInitAttr(id: Identifier, dataType: DataType): Unit = out.puts(s"${privateMemberName(id)} = []") - } override def condRepeatEosHeader(id: Identifier, io: String, dataType: DataType): Unit = { out.puts("i = 0") @@ -366,9 +358,9 @@ class RubyCompiler(typeProvider: ClassTypeProvider, config: RuntimeConfig) } } - override def createSubstreamFixedSize(id: Identifier, sizeExpr: Ast.expr, io: String): String = { + override def createSubstreamFixedSize(id: Identifier, blt: BytesLimitType, io: String, rep: RepeatSpec, defEndian: Option[FixedEndian]): String = { val ioName = s"_io_${idToStr(id)}" - out.puts(s"$ioName = $io.substream(${translator.translate(sizeExpr)})") + out.puts(s"$ioName = $io.substream(${translator.translate(blt.size)})") ioName } diff --git a/shared/src/main/scala/io/kaitai/struct/languages/RustCompiler.scala b/shared/src/main/scala/io/kaitai/struct/languages/RustCompiler.scala index cc696f693..8afcc65cb 100644 --- a/shared/src/main/scala/io/kaitai/struct/languages/RustCompiler.scala +++ b/shared/src/main/scala/io/kaitai/struct/languages/RustCompiler.scala @@ -1,7 +1,7 @@ package io.kaitai.struct.languages import io.kaitai.struct.datatype.DataType._ -import io.kaitai.struct.datatype.{DataType, FixedEndian, InheritedEndian, KSError, NeedRaw} +import io.kaitai.struct.datatype.{DataType, FixedEndian, InheritedEndian, KSError} import io.kaitai.struct.exprlang.Ast import io.kaitai.struct.format.{NoRepeat, RepeatEos, RepeatExpr, RepeatSpec, _} import io.kaitai.struct.languages.components._ @@ -249,13 +249,8 @@ class RustCompiler(typeProvider: ClassTypeProvider, config: RuntimeConfig) out.inc } - override def condRepeatCommonInit(id: Identifier, dataType: DataType, needRaw: NeedRaw): Unit = { - if (needRaw.level >= 1) - out.puts(s"${privateMemberName(RawIdentifier(id))} = vec!();") - if (needRaw.level >= 2) - out.puts(s"${privateMemberName(RawIdentifier(RawIdentifier(id)))} = vec!();") + override def condRepeatInitAttr(id: Identifier, dataType: DataType): Unit = out.puts(s"${privateMemberName(id)} = vec!();") - } override def condRepeatEosHeader(id: Identifier, io: String, dataType: DataType): Unit = { out.puts(s"while !$io.isEof() {") diff --git a/shared/src/main/scala/io/kaitai/struct/languages/components/AllocateAndStoreIO.scala b/shared/src/main/scala/io/kaitai/struct/languages/components/AllocateAndStoreIO.scala index 2166071dc..33fe36608 100644 --- a/shared/src/main/scala/io/kaitai/struct/languages/components/AllocateAndStoreIO.scala +++ b/shared/src/main/scala/io/kaitai/struct/languages/components/AllocateAndStoreIO.scala @@ -11,12 +11,6 @@ import io.kaitai.struct.format._ trait AllocateAndStoreIO extends ExtraAttrs { def allocateIO(id: Identifier, rep: RepeatSpec): String - override def extraAttrForIO(id: Identifier, rep: RepeatSpec): List[AttrSpec] = { - val ioId = IoStorageIdentifier(id) - val ioType = rep match { - case NoRepeat => OwnedKaitaiStreamType - case _ => ArrayTypeInStream(OwnedKaitaiStreamType) - } - List(AttrSpec(List(), ioId, ioType)) - } + override def extraAttrForIO(id: Identifier, rep: RepeatSpec): List[AttrSpec] = + List(AttrSpec(List(), IoStorageIdentifier(id), OwnedKaitaiStreamType, ConditionalSpec(None, rep))) } diff --git a/shared/src/main/scala/io/kaitai/struct/languages/components/CommonReads.scala b/shared/src/main/scala/io/kaitai/struct/languages/components/CommonReads.scala index c95762e53..41ae7adf6 100644 --- a/shared/src/main/scala/io/kaitai/struct/languages/components/CommonReads.scala +++ b/shared/src/main/scala/io/kaitai/struct/languages/components/CommonReads.scala @@ -1,7 +1,6 @@ package io.kaitai.struct.languages.components import io.kaitai.struct.datatype._ -import io.kaitai.struct.datatype.DataType.{SwitchType, UserTypeFromBytes, BytesType} import io.kaitai.struct.exprlang.Ast import io.kaitai.struct.format._ @@ -26,8 +25,11 @@ trait CommonReads extends LanguageCompiler { normalIO } - if (config.readStoresPos) + if (attrDebugNeeded(id)) { attrDebugStart(id, attr.dataType, Some(io), NoRepeat) + if (attr.cond.repeat != NoRepeat) + attrDebugArrInit(id, attr.dataType) + } defEndian match { case Some(_: CalcEndian) | Some(InheritedEndian) => @@ -64,7 +66,7 @@ trait CommonReads extends LanguageCompiler { def attrParse0(id: Identifier, attr: AttrLikeSpec, io: String, defEndian: Option[FixedEndian]): Unit = { if (attr.cond.repeat != NoRepeat) - condRepeatCommonInit(id, attr.dataType, needRaw(attr.dataType)) + (ExtraAttrs.forAttr(attr, this) ++ List(attr)).foreach(a => condRepeatInitAttr(a.id, a.dataType)) attr.cond.repeat match { case RepeatEos => condRepeatEosHeader(id, io, attr.dataType) @@ -88,28 +90,12 @@ trait CommonReads extends LanguageCompiler { def attrParse2(id: Identifier, dataType: DataType, io: String, rep: RepeatSpec, isRaw: Boolean, defEndian: Option[FixedEndian], assignType: Option[DataType] = None): Unit - def needRaw(dataType: DataType): NeedRaw = { - val rawIo = dataType match { - case _: UserTypeFromBytes => true - case st: SwitchType => st.hasSize - case _ => false - } - val rawProcess = dataType match { - case bt: BytesType => bt.process.nonEmpty - case utfb: UserTypeFromBytes => utfb.bytes.process.nonEmpty - case _ => false - } - (rawIo, rawProcess) match { - case (true, false) => RawIo - case (false, true) => RawProcess - case (true, true) => RawIoProcess - case _ => NotRaw - } - } - - def attrDebugStart(attrName: Identifier, attrType: DataType, io: Option[String], repeat: RepeatSpec): Unit = {} + def attrDebugStart(attrId: Identifier, attrType: DataType, io: Option[String], repeat: RepeatSpec): Unit = {} + def attrDebugArrInit(attrId: Identifier, attrType: DataType): Unit = {} def attrDebugEnd(attrName: Identifier, attrType: DataType, io: String, repeat: RepeatSpec): Unit = {} + def attrDebugNeeded(attrId: Identifier): Boolean = false + /** * Runs all validation procedures requested for an attribute. * @param attr attribute to run validations for diff --git a/shared/src/main/scala/io/kaitai/struct/languages/components/EveryReadIsExpression.scala b/shared/src/main/scala/io/kaitai/struct/languages/components/EveryReadIsExpression.scala index 4ac252fc8..97dd86ab2 100644 --- a/shared/src/main/scala/io/kaitai/struct/languages/components/EveryReadIsExpression.scala +++ b/shared/src/main/scala/io/kaitai/struct/languages/components/EveryReadIsExpression.scala @@ -31,8 +31,9 @@ trait EveryReadIsExpression assignTypeOpt: Option[DataType] = None ): Unit = { val assignType = assignTypeOpt.getOrElse(dataType) + val needsDebug = attrDebugNeeded(id) && rep != NoRepeat - if (config.readStoresPos && rep != NoRepeat) + if (needsDebug) attrDebugStart(id, dataType, Some(io), rep) dataType match { @@ -61,7 +62,7 @@ trait EveryReadIsExpression handleAssignment(id, expr, rep, isRaw) } - if (config.readStoresPos && rep != NoRepeat) + if (needsDebug) attrDebugEnd(id, dataType, io, rep) } @@ -140,18 +141,18 @@ trait EveryReadIsExpression * @param defEndian default endianness specification * @return string reference to a freshly created substream */ - def createSubstream(id: Identifier, byteType: BytesType, io: String, rep: RepeatSpec, defEndian: Option[FixedEndian]): String = { + def createSubstream(id: Identifier, bt: BytesType, io: String, rep: RepeatSpec, defEndian: Option[FixedEndian]): String = { if (config.zeroCopySubstream) { - byteType match { - case BytesLimitType(sizeExpr, None, _, None, None) => - createSubstreamFixedSize(id, sizeExpr, io) + bt match { + case blt @ BytesLimitType(_, None, _, None, None) => + createSubstreamFixedSize(id, blt, io, rep, defEndian) case _ => // fall back to buffered implementation - createSubstreamBuffered(id, byteType, io, rep, defEndian) + createSubstreamBuffered(id, bt, io, rep, defEndian) } } else { // if zero-copy substreams were declined, always use buffered implementation - createSubstreamBuffered(id, byteType, io, rep, defEndian) + createSubstreamBuffered(id, bt, io, rep, defEndian) } } @@ -167,14 +168,8 @@ trait EveryReadIsExpression * @param io parent stream to derive substream from * @return string reference to a freshly created substream */ - def createSubstreamFixedSize(id: Identifier, sizeExpr: Ast.expr, io: String): String = - createSubstreamBuffered( - id, - BytesLimitType(sizeExpr, None, false, None, None), - io, - NoRepeat, - None - ) + def createSubstreamFixedSize(id: Identifier, blt: BytesLimitType, io: String, rep: RepeatSpec, defEndian: Option[FixedEndian]): String = + createSubstreamBuffered(id, blt, io, rep, defEndian) /** * Creates a substream by reading bytes that will comprise the stream first into a buffer in @@ -286,11 +281,21 @@ trait EveryReadIsExpression def userTypeDebugRead(id: String, dataType: DataType, assignType: DataType): Unit = ??? def instanceCalculate(instName: Identifier, dataType: DataType, value: Ast.expr): Unit = { - if (config.readStoresPos) + if (attrDebugNeeded(instName)) attrDebugStart(instName, dataType, None, NoRepeat) handleAssignmentSimple(instName, expression(value)) } + override def attrDebugNeeded(attrId: Identifier): Boolean = { + if (!config.readStoresPos) + return false + + attrId match { + case _: NamedIdentifier | _: NumberedIdentifier | _: InstanceIdentifier => true + case _ => super.attrDebugNeeded(attrId) + } + } + def itemExpr(id: Identifier, rep: RepeatSpec): Ast.expr = { val astId = Ast.expr.InternalName(id) rep match { diff --git a/shared/src/main/scala/io/kaitai/struct/languages/components/EveryWriteIsExpression.scala b/shared/src/main/scala/io/kaitai/struct/languages/components/EveryWriteIsExpression.scala index 6248f24e7..dec964d13 100644 --- a/shared/src/main/scala/io/kaitai/struct/languages/components/EveryWriteIsExpression.scala +++ b/shared/src/main/scala/io/kaitai/struct/languages/components/EveryWriteIsExpression.scala @@ -73,7 +73,9 @@ trait EveryWriteIsExpression checksShouldDependOnIo: Option[Boolean] ): Unit = { if (attr.cond.repeat != NoRepeat) - condRepeatCommonWriteInit(id, attr.dataType, needRaw(attr.dataType)) + ExtraAttrs.forAttr(attr, this) + .filter(a => a.id.isInstanceOf[RawIdentifier]) + .foreach(a => condRepeatInitAttr(a.id, a.dataType)) attr.cond.repeat match { case RepeatEos => case RepeatExpr(repeatExpr: Ast.expr) => diff --git a/shared/src/main/scala/io/kaitai/struct/languages/components/ExtraAttrs.scala b/shared/src/main/scala/io/kaitai/struct/languages/components/ExtraAttrs.scala index 71f4d9fbb..487bfa45e 100644 --- a/shared/src/main/scala/io/kaitai/struct/languages/components/ExtraAttrs.scala +++ b/shared/src/main/scala/io/kaitai/struct/languages/components/ExtraAttrs.scala @@ -28,8 +28,7 @@ trait ExtraAttrs { case None => List() case Some(_) => val rawId = RawIdentifier(id) - List(AttrSpec(List(), rawId, bt, condSpec)) ++ - extraAttrForIO(id, condSpec.repeat) + List(AttrSpec(List(), rawId, bt, condSpec)) } case utb: UserTypeFromBytes => // User type in a substream diff --git a/shared/src/main/scala/io/kaitai/struct/languages/components/LanguageCompiler.scala b/shared/src/main/scala/io/kaitai/struct/languages/components/LanguageCompiler.scala index 13c194a47..18368ad88 100644 --- a/shared/src/main/scala/io/kaitai/struct/languages/components/LanguageCompiler.scala +++ b/shared/src/main/scala/io/kaitai/struct/languages/components/LanguageCompiler.scala @@ -1,6 +1,6 @@ package io.kaitai.struct.languages.components -import io.kaitai.struct.datatype.{DataType, Endianness, FixedEndian, InheritedEndian, NeedRaw} +import io.kaitai.struct.datatype.{DataType, Endianness, FixedEndian, InheritedEndian} import io.kaitai.struct.exprlang.Ast import io.kaitai.struct.format._ import io.kaitai.struct.translators.AbstractTranslator @@ -148,8 +148,7 @@ abstract class LanguageCompiler( def condIfHeader(expr: Ast.expr): Unit def condIfFooter: Unit - def condRepeatCommonInit(id: Identifier, dataType: DataType, needRaw: NeedRaw): Unit - def condRepeatCommonWriteInit(id: Identifier, dataType: DataType, needRaw: NeedRaw): Unit = ??? + def condRepeatInitAttr(id: Identifier, dataType: DataType): Unit def condRepeatEosHeader(id: Identifier, io: String, dataType: DataType): Unit def condRepeatEosFooter: Unit