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.
|
// TODO(dneto): Allow escaping.
|
||||||
if (len < 2 || textValue[0] != '"' || textValue[len - 1] != '"')
|
if (len < 2 || textValue[0] != '"' || textValue[len - 1] != '"')
|
||||||
return SPV_FAILED_MATCH;
|
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;
|
pLiteral->type = SPV_LITERAL_TYPE_STRING;
|
||||||
// Need room for the null-terminator.
|
pLiteral->value.str[write_index] = '\0';
|
||||||
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;
|
|
||||||
} else if (numPeriods == 1) {
|
} else if (numPeriods == 1) {
|
||||||
double d = std::strtod(textValue, nullptr);
|
double d = std::strtod(textValue, nullptr);
|
||||||
float f = (float)d;
|
float f = (float)d;
|
||||||
|
|
|
@ -54,10 +54,10 @@ typedef struct spv_literal_t {
|
||||||
uint64_t u64;
|
uint64_t u64;
|
||||||
float f;
|
float f;
|
||||||
double d;
|
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
|
// TODO(dneto): This is a very large array. We should use a
|
||||||
// different kind of container.
|
// different kind of container.
|
||||||
char str[SPV_LIMIT_LITERAL_STRING_BYTES_MAX + 3];
|
char str[SPV_LIMIT_LITERAL_STRING_BYTES_MAX + 1];
|
||||||
} value;
|
} value;
|
||||||
} spv_literal_t;
|
} 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 opcode names and expected operands are described in section 3 of
|
||||||
the SPIR-V specification. An operand is one of:
|
the SPIR-V specification. An operand is one of:
|
||||||
* a literal integer: A decimal integer, or a hexadecimal integer.
|
* a literal integer: A decimal integer, or a hexadecimal integer
|
||||||
A hexadecimal integer is indicated by a leading `0x` or `0X`. A hex
|
(indicated by a leading `0x`).
|
||||||
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 floating point number.
|
* a literal floating point number.
|
||||||
* a literal string, surrounded by double-quotes `"`. TODO: describe quoting and
|
* a literal string.
|
||||||
escaping rules.
|
* 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,
|
* a named enumerated value, specific to that operand position. For example,
|
||||||
the `OpMemoryModel` takes a named Addressing Model operand (e.g. `Logical` or
|
the `OpMemoryModel` takes a named Addressing Model operand (e.g. `Logical` or
|
||||||
`Physical32`), and a named Memory Model operand (e.g. `Simple` or `OpenCL`).
|
`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
|
The assembler processes the tokens encountered in alternate parsing mode as
|
||||||
follows:
|
follows:
|
||||||
|
|
||||||
* If the token is a number literal, since context may be lost, the number
|
* If the token is a number literal, it outputs that number as one or more words,
|
||||||
is interpreted as a 32-bit value and output as a single word. In order to
|
as defined in the SPIR-V specification for Literal Number. The number must
|
||||||
specify multiple-word literals in alternate-parsing mode, further uses of
|
fit within the unsigned 32-bit range. All formats supported by `strtoul()`
|
||||||
`!<integer>` tokens may be required.
|
are accepted.
|
||||||
All formats supported by `strtoul()` are accepted.
|
|
||||||
* If the token is a string literal, it outputs a sequence of words representing
|
* 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.
|
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.
|
* 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));
|
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;
|
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_EQ(SPV_LITERAL_TYPE_STRING, l.type);
|
||||||
EXPECT_STREQ("-", l.value.str);
|
EXPECT_STREQ(std::get<1>(GetParam()), 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.
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#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) {
|
TEST(TextLiteral, StringTooLong) {
|
||||||
spv_literal_t l;
|
spv_literal_t l;
|
||||||
std::string too_long = std::string("\"") +
|
std::string too_long = std::string("\"") +
|
||||||
|
|
Загрузка…
Ссылка в новой задаче