Skip to content

Commit

Permalink
Go: export user objects unconditionally in --no-auto-read mode
Browse files Browse the repository at this point in the history
  • Loading branch information
generalmimon committed Dec 26, 2024
1 parent a5813db commit b586f96
Show file tree
Hide file tree
Showing 3 changed files with 42 additions and 32 deletions.
27 changes: 16 additions & 11 deletions shared/src/main/scala/io/kaitai/struct/languages/GoCompiler.scala
Original file line number Diff line number Diff line change
Expand Up @@ -416,17 +416,8 @@ class GoCompiler(typeProvider: ClassTypeProvider, config: RuntimeConfig)
case BitsType(width: Int, bitEndian) =>
s"$io.ReadBitsInt${Utils.upperCamelCase(bitEndian.toSuffix)}($width)"
case t: UserType =>
val addArgs = if (t.isExternal(typeProvider.nowClass)) {
""
} else {
val parent = t.forcedParent match {
case Some(USER_TYPE_NO_PARENT) => "null"
case Some(fp) => translator.translate(fp)
case None => "this"
}
s", $parent, _root"
}
s"${types2class(t.name)}($io$addArgs)"
val addParams = t.args.map((a) => expression(a)).mkString(", ")
s"New${GoCompiler.types2class(t.classSpec.get.name)}($addParams)"
}
}

Expand All @@ -442,6 +433,20 @@ class GoCompiler(typeProvider: ClassTypeProvider, config: RuntimeConfig)
// expr2
// }

override def userTypeDebugRead(id: String, t: UserType, io: String): Unit = {
val (parent, root) = if (t.isExternal(typeProvider.nowClass)) {
("nil", "nil")
} else {
val parent = t.forcedParent match {
case Some(USER_TYPE_NO_PARENT) => "nil"
case Some(fp) => expression(fp)
case None => "this"
}
(parent, "this._root")
}
out.puts(s"err = $id.Read($io, $parent, $root)")
}

override def switchStart(id: Identifier, on: Ast.expr): Unit = {
out.puts(s"switch (${expression(on)}) {")
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -140,8 +140,31 @@ trait GoReads extends CommonReads with ObjectOrientedLanguage with GoSwitchOps {
io
}

val expr = translator.userType(dataType, newIO)
handleAssignment(id, expr, rep, false)
val expr = parseExpr(dataType, newIO, defEndian)
val v = ResultLocalVar(translator.allocateLocalVar())
val tempVarName = translator.resToStr(v)
// At the time of writing, our generated Go code doesn't have a clear `autoRead`/non-`autoRead`
// separation. `Read` has been always called separately, which would suggest disabled
// `autoRead`, but before 0.11, the object was always created and stored in a temporary variable
// first and then its `Read` was called, followed by an `if err != nil { return err }` block. So
// the object was assigned to an exported struct field only if `Read` succeeded, which matches
// the behavior of enabled `autoRead`.
//
// Since 0.11, we try to match the behavior of other target languages for consistency. If
// `autoRead` is enabled (default), we export the object only after the `Read`'s `err` check
// passed. Only if `autoRead` is disabled, we export the object unconditionally, but after
// calling `Read` (like other target languages).
if (config.autoRead) {
handleAssignmentTempVar(dataType, tempVarName, expr)
userTypeDebugRead(tempVarName, dataType, newIO)
translator.outAddErrCheck()
handleAssignment(id, v, rep, false)
} else {
handleAssignmentTempVar(dataType, tempVarName, expr)
userTypeDebugRead(tempVarName, dataType, newIO)
handleAssignment(id, v, rep, false)
translator.outAddErrCheck()
}
}

def handleAssignment(id: Identifier, expr: TranslatorResult, rep: RepeatSpec, isRaw: Boolean): Unit = {
Expand All @@ -159,4 +182,5 @@ trait GoReads extends CommonReads with ObjectOrientedLanguage with GoSwitchOps {
def handleAssignmentSimple(id: Identifier, expr: TranslatorResult): Unit

def parseExpr(dataType: DataType, io: String, defEndian: Option[FixedEndian]): String
def userTypeDebugRead(id: String, t: UserType, io: String): Unit
}
Original file line number Diff line number Diff line change
Expand Up @@ -476,25 +476,6 @@ class GoTranslator(out: StringLanguageOutputWriter, provider: TypeProvider, impo
ResultLocalVar(v)
}

def userType(t: UserType, io: String) = {
val v = allocateLocalVar()
val (parent, root) = if (t.isExternal(provider.nowClass)) {
("nil", "nil")
} else {
val parent = t.forcedParent match {
case Some(USER_TYPE_NO_PARENT) => "nil"
case Some(fp) => translate(fp)
case None => "this"
}
(parent, "this._root")
}
val addParams = t.args.map((a) => translate(a)).mkString(", ")
out.puts(s"${localVarName(v)} := New${GoCompiler.types2class(t.classSpec.get.name)}($addParams)")
out.puts(s"err = ${localVarName(v)}.Read($io, $parent, $root)")
outAddErrCheck()
ResultLocalVar(v)
}

def trInterpolatedStringLiteral(exprs: Seq[Ast.expr]): TranslatorResult = {
exprs match {
case Seq(Ast.expr.Str(s)) =>
Expand Down

0 comments on commit b586f96

Please sign in to comment.