Updated string escaping in the assembler.
Strings are now escaped correctly when assembling. TODO dissassembler support for strange strings (newlines for example).
This commit is contained in:
Родитель
daf493b202
Коммит
3e69cd1b9f
|
@ -110,11 +110,23 @@ spv_result_t spvTextToLiteral(const char* textValue, spv_literal_t* pLiteral) {
|
|||
// TODO(dneto): Allow escaping.
|
||||
if (len < 2 || textValue[0] != '"' || textValue[len - 1] != '"')
|
||||
return SPV_FAILED_MATCH;
|
||||
bool escaping = false;
|
||||
size_t write_index = 0;
|
||||
for(const char* val = textValue + 1; val != textValue + len - 1; ++val) {
|
||||
if ((*val == '\\') && (!escaping)) {
|
||||
escaping = true;
|
||||
} else {
|
||||
// Have to save space for the null-terminator
|
||||
if (write_index >= sizeof(pLiteral->value.str) - 1)
|
||||
return SPV_ERROR_OUT_OF_MEMORY;
|
||||
pLiteral->value.str[write_index] = *val;
|
||||
escaping = false;
|
||||
++write_index;
|
||||
}
|
||||
}
|
||||
|
||||
pLiteral->type = SPV_LITERAL_TYPE_STRING;
|
||||
// Need room for the null-terminator.
|
||||
if (len >= sizeof(pLiteral->value.str)) return SPV_ERROR_OUT_OF_MEMORY;
|
||||
strncpy(pLiteral->value.str, textValue + 1, len - 2);
|
||||
pLiteral->value.str[len - 2] = 0;
|
||||
pLiteral->value.str[write_index] = '\0';
|
||||
} else if (numPeriods == 1) {
|
||||
double d = std::strtod(textValue, nullptr);
|
||||
float f = (float)d;
|
||||
|
|
|
@ -54,10 +54,10 @@ typedef struct spv_literal_t {
|
|||
uint64_t u64;
|
||||
float f;
|
||||
double d;
|
||||
// Allow room for the null terminator, and two surrounding quotes.
|
||||
// Allow room for the null terminator
|
||||
// TODO(dneto): This is a very large array. We should use a
|
||||
// different kind of container.
|
||||
char str[SPV_LIMIT_LITERAL_STRING_BYTES_MAX + 3];
|
||||
char str[SPV_LIMIT_LITERAL_STRING_BYTES_MAX + 1];
|
||||
} value;
|
||||
} spv_literal_t;
|
||||
|
||||
|
|
25
syntax.md
25
syntax.md
|
@ -27,14 +27,16 @@ but the assembler does not enforce this rule.
|
|||
|
||||
The opcode names and expected operands are described in section 3 of
|
||||
the SPIR-V specification. An operand is one of:
|
||||
* a literal integer: A decimal integer, or a hexadecimal integer.
|
||||
A hexadecimal integer is indicated by a leading `0x` or `0X`. A hex
|
||||
integer supplied for a signed integer value will be sign-extended.
|
||||
For example, `0xffff` supplied as the literal for an `OpConstant`
|
||||
on a signed 16-bit integer type will be interpreted as the value `-1`.
|
||||
* a literal integer: A decimal integer, or a hexadecimal integer
|
||||
(indicated by a leading `0x`).
|
||||
* a literal floating point number.
|
||||
* a literal string, surrounded by double-quotes `"`. TODO: describe quoting and
|
||||
escaping rules.
|
||||
* a literal string.
|
||||
* A literal string is everything following a double-quote `"` until the
|
||||
following un-escaped double-quote, this includes special characters such as
|
||||
newlines.
|
||||
* A backslash `\` may be used to escape characters in the string. The `\`
|
||||
may be used to escape a double-quote or a `\` but is simply ignored when
|
||||
preceding any other character.
|
||||
* a named enumerated value, specific to that operand position. For example,
|
||||
the `OpMemoryModel` takes a named Addressing Model operand (e.g. `Logical` or
|
||||
`Physical32`), and a named Memory Model operand (e.g. `Simple` or `OpenCL`).
|
||||
|
@ -154,11 +156,10 @@ instruction.)
|
|||
The assembler processes the tokens encountered in alternate parsing mode as
|
||||
follows:
|
||||
|
||||
* If the token is a number literal, since context may be lost, the number
|
||||
is interpreted as a 32-bit value and output as a single word. In order to
|
||||
specify multiple-word literals in alternate-parsing mode, further uses of
|
||||
`!<integer>` tokens may be required.
|
||||
All formats supported by `strtoul()` are accepted.
|
||||
* If the token is a number literal, it outputs that number as one or more words,
|
||||
as defined in the SPIR-V specification for Literal Number. The number must
|
||||
fit within the unsigned 32-bit range. All formats supported by `strtoul()`
|
||||
are accepted.
|
||||
* If the token is a string literal, it outputs a sequence of words representing
|
||||
the string as defined in the SPIR-V specification for Literal String.
|
||||
* If the token is an ID, it outputs the ID's internal number.
|
||||
|
|
|
@ -105,32 +105,37 @@ TEST(TextLiteral, BadString) {
|
|||
EXPECT_EQ(SPV_FAILED_MATCH, spvTextToLiteral("a\"", &l));
|
||||
}
|
||||
|
||||
TEST(TextLiteral, GoodString) {
|
||||
class GoodStringTest
|
||||
: public ::testing::TestWithParam<std::pair<const char*, const char*>> {};
|
||||
|
||||
TEST_P(GoodStringTest, GoodStrings) {
|
||||
spv_literal_t l;
|
||||
|
||||
ASSERT_EQ(SPV_SUCCESS, spvTextToLiteral("\"-\"", &l));
|
||||
ASSERT_EQ(SPV_SUCCESS, spvTextToLiteral(std::get<0>(GetParam()), &l));
|
||||
EXPECT_EQ(SPV_LITERAL_TYPE_STRING, l.type);
|
||||
EXPECT_STREQ("-", l.value.str);
|
||||
|
||||
ASSERT_EQ(SPV_SUCCESS, spvTextToLiteral("\"--\"", &l));
|
||||
EXPECT_EQ(SPV_LITERAL_TYPE_STRING, l.type);
|
||||
EXPECT_STREQ("--", l.value.str);
|
||||
|
||||
ASSERT_EQ(SPV_SUCCESS, spvTextToLiteral("\"1-2\"", &l));
|
||||
EXPECT_EQ(SPV_LITERAL_TYPE_STRING, l.type);
|
||||
EXPECT_STREQ("1-2", l.value.str);
|
||||
|
||||
ASSERT_EQ(SPV_SUCCESS, spvTextToLiteral("\"123a\"", &l));
|
||||
EXPECT_EQ(SPV_LITERAL_TYPE_STRING, l.type);
|
||||
EXPECT_STREQ("123a", l.value.str);
|
||||
|
||||
ASSERT_EQ(SPV_SUCCESS, spvTextToLiteral("\"12.2.3\"", &l));
|
||||
EXPECT_EQ(SPV_LITERAL_TYPE_STRING, l.type);
|
||||
EXPECT_STREQ("12.2.3", l.value.str);
|
||||
|
||||
// TODO(dneto): escaping in strings is not supported yet.
|
||||
EXPECT_STREQ(std::get<1>(GetParam()), l.value.str);
|
||||
}
|
||||
|
||||
#define CASE(NAME) spv::Decoration##NAME, #NAME
|
||||
INSTANTIATE_TEST_CASE_P(
|
||||
TextLiteral, GoodStringTest,
|
||||
::testing::ValuesIn(std::vector<std::pair<const char*, const char*>>{
|
||||
{R"("-")", "-"},
|
||||
{R"("--")", "--"},
|
||||
{R"("1-2")", "1-2"},
|
||||
{R"("123a")", "123a"},
|
||||
{R"("12.2.3")", "12.2.3"},
|
||||
{R"("\"")", "\""},
|
||||
{R"("\\")", "\\"},
|
||||
{"\"\\foo\nbar\"", "foo\nbar"},
|
||||
{"\"\\foo\\\nbar\"", "foo\nbar"},
|
||||
{"\"\U00E4BAB2\"", "\U00E4BAB2"},
|
||||
{"\"\\\U00E4BAB2\"", "\U00E4BAB2"},
|
||||
{"\"this \\\" and this \\\\ and \\\U00E4BAB2\"",
|
||||
"this \" and this \\ and \U00E4BAB2"}
|
||||
}));
|
||||
#undef CASE
|
||||
|
||||
TEST(TextLiteral, StringTooLong) {
|
||||
spv_literal_t l;
|
||||
std::string too_long = std::string("\"") +
|
||||
|
|
Загрузка…
Ссылка в новой задаче