Closed zachcran closed 2 years ago
One more note, double quotes seem to be honored in user-defined CMake functions as well, so this does seem to be a CMakePPLang issue. For example:
function(print_str message)
message("Message received: ${message}")
endfunction()
print_str("String \"with quotes\"")
# Output
# Message received: String "with quotes"
With CMake the number of escapes depends on how many functions you're trying to pass the string through (each function call consumes a round of escapes). I'm pretty sure that CMakePPLang doesn't directly pass the arguments to the decorated function, so assuming it needs to go through more than one function you're going to need some atrocious escape sequence. I believe it's \\\"
to go through two functions, \\\\\\\"
to go through three functions, etc. (if n
is the number of slashes to go through n-1
functions it should take 2n+1
slashes to go through n
functions, i.e., n
slashes to protect the original n
slashes and 1 additional slash to protect the double quotes).
That said, it'd be nice to fix this issue (ideally without more than one escape). Conceivably we could call a macro right on the other side of the MyClass
function to protect the slashes (regex them to something like ASCII character 7, the BEL character) and then unprotect them (regex them back to \
) when they're ready to be processed.
Forgive me, I am still trying to wrap my head around how everything works in CMakePPLang implementation (and CMake in general). Do you think it would be reasonable to encode the escaped double quotes before the cpp_assert_signature
call here? Entering that _cpp_object_call
macro seems to be where the backslash escaping the quotes get stripped.
For decoding the escaped double quotes again, it looks like it would be best to decode the arguments before they are written to the file to be executed here, decoding the encoded escaped quotes as something like \\\"
to account for the function writing to the file.
Let me know if that sounds reasonable!
So are you saying that \"hi\"
makes it to just inside _cpp_object_call
as "hi"
? Or that it makes it there as \"hi\"
?
I think the ideal situation has us encode the quotes as close to the user as possible. So in your above example I'd try to encode them in the body of the MyClass
function. IIRC that function is autogenerated based off a template file so you'd have to add the protection to the template file.
WRT to decoding I think that's the right place.
FWIW this is going to be a problem for other special characters too (like if a user passes \$
or \;
) so you may as well encode them too while you're at it.
There seems to be a long-standing bug (known since at least 2007) where macros remove (more) escape protection from special characters. Both functions and macros remove escapes, but this but certainly doesn't help.
Describe the bug When a string with escaped double quotes (
\"
) is passed as a string (str
) parameter to a member function, the escaped double quotes are not honored, instead seeming to indicate the end of the argument.To Reproduce Here is a unit test I wrote to verify the issue was happening: member_functions.cmake.txt. Put the file in
CMakePPLang/tests/class
, rename the file tomember_functions.cmake
, and run the tests to reproduce it easily.Alternatively, here are steps to reproduce the behavior:
cpp_class(MyClass) cpp_member(print_str MyClass str) function("${print_str}" self a) message("Message received: ${a}") endfunction() cpp_end_class()
Expected behavior I expected the escaped double quotes to remain in the string and be passed along to the member function. I tested this with
message()
andstring(APPEND
from vanilla CMake, and they honored the escaped double quotes.In my expected behavior, the output in the above code example would be
Message received: String "with quotes"
, notMessage received: String
.Additional context As shown in the attached file above, I have tried passing the variable containing escaped double quotes both surrounded by quotes (
"${var}"
) and not surrounded by quotes (${var}
), as well as the string itself instead of a variable. None of these worked.