-
Notifications
You must be signed in to change notification settings - Fork 155
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Implement doByteArrayNonLiteral
for Lua and C++
#281
Implement doByteArrayNonLiteral
for Lua and C++
#281
Conversation
override def doByteArrayNonLiteral(values: Seq[Ast.expr]): String = | ||
doArrayLiteral(DataType.Int1Type(false), values) |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I don't think this is correct. It looks like you're generating a true array literal here, not a byte array literal. Byte arrays are translated as std::string
in C++ (see doByteArrayLiteral
right above).
If we consider a real-world example where this would be used, which is the EDID spec - hardware/edid.ksy:261-268
:
instances:
mfg_id_ch1:
value: '(mfg_bytes & 0b0111110000000000) >> 10'
mfg_id_ch2:
value: '(mfg_bytes & 0b0000001111100000) >> 5'
mfg_id_ch3:
value: '(mfg_bytes & 0b0000000000011111)'
mfg_str:
value: '[mfg_id_ch1 + 0x40, mfg_id_ch2 + 0x40, mfg_id_ch3 + 0x40].as<bytes>.to_s("ASCII")'
I guess the code generation in C++ could look more like this:
std::string bytes_literal_t::mfg_str() {
if (f_mfg_str)
return m_mfg_str;
m_mfg_str = kaitai::kstream::bytes_to_str(std::string({ mfg_id_ch1() + 0x40, mfg_id_ch2() + 0x40, mfg_id_ch3() + 0x40 }), "ASCII");
f_mfg_str = true;
return m_mfg_str;
}
Note the std::string
.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Unfortunately, doByteArrayLiteral
should produce an expression, but without initializer lists it is possible to use only statement to create a byte array and then std::string
from it:
const char bytes[] = {
char(mfg_id_ch1() + 0x40),
char(mfg_id_ch2() + 0x40),
char(mfg_id_ch3() + 0x40),
};
std::string(bytes, sizeof(bytes));
https://godbolt.org/z/1Y8Ec9f7K
Because anyway C++98 target is not fully implemented, I've implemented only initializer_list
solution (so only since C++11).
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
In all fairness, there's nothing terribly wrong with getting our CppTranslator closer to GoTranslator in a sense that it might also use temporary variables allocated on stack to make things like that separate const char bytes[] = { ... };
work for C++98. We already do that for Go, we will likely do that for C.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Indeed we should do that, but not in this PR
override def doByteArrayNonLiteral(values: Seq[Ast.expr]): String = | ||
"{" + values.map(translate).mkString(", ") + "}" |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
This also doesn't look like a byte array.
Note that the runtime type you generate here in doByteArrayNonLiteral
must be the same as the runtime type generated in doByteArrayLiteral
. This is not the case with this implementation, as you can check at https://tio.run/##yylN/P@/oCgzr0SjpLIgVUMpxsDMNMbI1DTGwNxUSVOTC0mu2sxURwEopaNgblqrqfn/PwA:
print(type("\065\255\075")) -- => string
print(type({65, 255, 75})) -- => table
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Ok, the Lua stuff was simple
1c22828
to
3b14bb0
Compare
e4500bc
to
d30fd3a
Compare
override def doByteArrayNonLiteral(values: Seq[Ast.expr]): String = { | ||
// It is assumed that every expression produces integer in the range [0; 255] | ||
if (config.cppConfig.useListInitializers) { | ||
"std::string({" + values.map(value => s"char(${translate(value)})").mkString(", ") + "})" |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
char(x)
is what's called functional-style cast. It's not C-style cast, but it is equally implicit and can mean a lot of things.
I wonder if using static_cast<char>(...)
will make more sense here?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Now static_cast<char>(...)
is used
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Now
static_cast<char>(...)
is used
According to the latest commit 69856bb on this PR, this is not the case:
kaitai_struct_compiler/shared/src/main/scala/io/kaitai/struct/translators/CppTranslator.scala
Line 125 in 69856bb
"std::string({" + values.map(value => s"char(${translate(value)})").mkString(", ") + "})" |
Apparently, static_cast<char>(...)
was reverted back to char(...)
in the last force push: 222472e..69856bb
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Oops... now really fixed
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Generally looks good, let's just close on whether we want static_cast
or functional-style casts.
d30fd3a
to
73ec6d8
Compare
jvm/src/test/scala/io/kaitai/struct/translators/TranslatorSpec.scala
Outdated
Show resolved
Hide resolved
73ec6d8
to
5b78d53
Compare
shared/src/main/scala/io/kaitai/struct/translators/CppTranslator.scala
Outdated
Show resolved
Hide resolved
shared/src/main/scala/io/kaitai/struct/translators/CppTranslator.scala
Outdated
Show resolved
Hide resolved
3f574b5
to
b0c2a5d
Compare
@generalmimon, what is your conclusion? |
b0c2a5d
to
717ee21
Compare
222472e
to
69856bb
Compare
69856bb
to
3605b6a
Compare
…f `bytes` type Expressions of this type are created using: - omitting the `type:` field in attributes and parse instances - declaring parameters with `type: bytes` - using `.as<bytes>` cast Fixes test ``` [info] - lua:[0 + 1, 5].as<bytes> *** FAILED *** [info] scala.NotImplementedError: an implementation is missing [info] at scala.Predef$.$qmark$qmark$qmark(Predef.scala:344) [info] at io.kaitai.struct.translators.BaseTranslator.doByteArrayNonLiteral(BaseTranslator.scala:179) [info] at io.kaitai.struct.translators.BaseTranslator.doByteArrayNonLiteral(BaseTranslator.scala:28) [info] at io.kaitai.struct.translators.CommonArraysAndCast.doByteArray(CommonArraysAndCast.scala:85) [info] at io.kaitai.struct.translators.CommonArraysAndCast.doCastOrArray(CommonArraysAndCast.scala:62) [info] at io.kaitai.struct.translators.CommonArraysAndCast.doCastOrArray$(CommonArraysAndCast.scala:53) [info] at io.kaitai.struct.translators.BaseTranslator.doCastOrArray(BaseTranslator.scala:28) [info] at io.kaitai.struct.translators.BaseTranslator.translate(BaseTranslator.scala:147) [info] at io.kaitai.struct.translators.AbstractTranslator.translate(AbstractTranslator.scala:25) [info] at io.kaitai.struct.translators.AbstractTranslator.translate$(AbstractTranslator.scala:25) [info] ... ```
…f `bytes` type Expressions of this type are created using: - omitting the `type:` field in attributes and parse instances - declaring parameters with `type: bytes` - using `.as<bytes>` cast Ghostly fixes test ``` [info] - cpp_stl:[0 + 1, 5].as<bytes> *** FAILED *** [info] scala.NotImplementedError: an implementation is missing [info] at scala.Predef$.$qmark$qmark$qmark(Predef.scala:344) [info] at io.kaitai.struct.translators.BaseTranslator.doByteArrayNonLiteral(BaseTranslator.scala:179) [info] at io.kaitai.struct.translators.BaseTranslator.doByteArrayNonLiteral(BaseTranslator.scala:28) [info] at io.kaitai.struct.translators.CommonArraysAndCast.doByteArray(CommonArraysAndCast.scala:85) [info] at io.kaitai.struct.translators.CommonArraysAndCast.doCastOrArray(CommonArraysAndCast.scala:62) [info] at io.kaitai.struct.translators.CommonArraysAndCast.doCastOrArray$(CommonArraysAndCast.scala:53) [info] at io.kaitai.struct.translators.BaseTranslator.doCastOrArray(BaseTranslator.scala:28) [info] at io.kaitai.struct.translators.BaseTranslator.translate(BaseTranslator.scala:147) [info] at io.kaitai.struct.translators.AbstractTranslator.translate(AbstractTranslator.scala:25) [info] at io.kaitai.struct.translators.AbstractTranslator.translate$(AbstractTranslator.scala:25) [info] ... ``` (actually, test is failing because option `useListInitializers` in C++ backend is not set in tests and code generation without it is not unimplemented right now)
3605b6a
to
c8bd711
Compare
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
@Mingun Thanks!
Fixes the test:
Looking at existing implementations for other languages I suspect that the missing implementation in both cases was just an oversight when
doByteArrayNonLiteral
was added.C++ test
now converted to another failure
which is because of unimplemented feature (tracked in kaitai-io/kaitai_struct#932).
Note, that it would be worth to test targets with options, such as C++, with different set of options. Right now only default options are used.