Fix some cases of value parsing under ARIA (fix Salamander)
This commit is contained in:
parent
a138b93182
commit
4b8eaebdc5
2 changed files with 69 additions and 25 deletions
|
|
@ -285,36 +285,47 @@ void Parser::processOpcode()
|
||||||
std::string valueRaw;
|
std::string valueRaw;
|
||||||
extractToEol(reader, &valueRaw);
|
extractToEol(reader, &valueRaw);
|
||||||
|
|
||||||
// if a "=" or "<" character was hit, it means we read too far
|
size_t endPosition = 0;
|
||||||
size_t position = valueRaw.find_first_of("=<");
|
|
||||||
if (position != valueRaw.npos) {
|
|
||||||
char hitChar = valueRaw[position];
|
|
||||||
|
|
||||||
// if it was "=", rewind before the opcode name and spaces preceding
|
for (size_t valueSize = valueRaw.size(); endPosition < valueSize;) {
|
||||||
if (hitChar == '=') {
|
size_t i = endPosition + 1;
|
||||||
while (position > 0 && isRawOpcodeNameChar(valueRaw[position - 1]))
|
|
||||||
--position;
|
if (isSpaceChar(valueRaw[endPosition])) {
|
||||||
while (position > 0 && isSpaceChar(valueRaw[position - 1]))
|
// check if the rest of the string is to consume or not
|
||||||
--position;
|
bool stop = false;
|
||||||
|
|
||||||
|
// consume space characters following
|
||||||
|
while (i < valueSize && isSpaceChar(valueRaw[endPosition + 1]))
|
||||||
|
++i;
|
||||||
|
|
||||||
|
// if there aren't non-space characters following, do not extract
|
||||||
|
if (i == valueSize)
|
||||||
|
stop = true;
|
||||||
|
// if a "=" or "<" character is next, a header or a directive follows
|
||||||
|
else if (valueRaw[i] == '<' || valueRaw[i] == '#')
|
||||||
|
stop = true;
|
||||||
|
// if sequence of identifier chars and then "=", an opcode follows
|
||||||
|
else if (isIdentifierChar(valueRaw[i])) {
|
||||||
|
++i;
|
||||||
|
while (i < valueSize && isIdentifierChar(valueRaw[i]))
|
||||||
|
++i;
|
||||||
|
if (i < valueSize && valueRaw[i] == '=')
|
||||||
|
stop = true;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (stop)
|
||||||
|
break;
|
||||||
}
|
}
|
||||||
|
|
||||||
absl::string_view excess(&valueRaw[position], valueRaw.size() - position);
|
endPosition = i;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (endPosition != valueRaw.size()) {
|
||||||
|
absl::string_view excess(&valueRaw[endPosition], valueRaw.size() - endPosition);
|
||||||
reader.putBackChars(excess);
|
reader.putBackChars(excess);
|
||||||
valueRaw.resize(position);
|
valueRaw.resize(endPosition);
|
||||||
|
|
||||||
// ensure that we are landing back next to a space char
|
|
||||||
if (hitChar == '=' && !reader.hasOneOfChars(" \t\r\n")) {
|
|
||||||
SourceLocation end = reader.location();
|
|
||||||
emitError({ valueStart, end }, "Unexpected `=` in opcode value.");
|
|
||||||
recover();
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
while (!valueRaw.empty() && isSpaceChar(valueRaw.back())) {
|
|
||||||
reader.putBackChar(valueRaw.back());
|
|
||||||
valueRaw.pop_back();
|
|
||||||
}
|
|
||||||
SourceLocation valueEnd = reader.location();
|
SourceLocation valueEnd = reader.location();
|
||||||
|
|
||||||
if (!_currentHeader)
|
if (!_currentHeader)
|
||||||
|
|
|
||||||
|
|
@ -629,10 +629,43 @@ TEST_CASE("[Parsing] Opcode value special character")
|
||||||
parser.setListener(&mock);
|
parser.setListener(&mock);
|
||||||
parser.parseString("/opcodeValueSpecialCharacter.sfz",
|
parser.parseString("/opcodeValueSpecialCharacter.sfz",
|
||||||
R"(<region>
|
R"(<region>
|
||||||
sample=Alto-Flute-sus-C#4-PB-loop.wav)");
|
sample=Alto-Flute-sus-C#4-PB-loop.wav
|
||||||
|
<region>
|
||||||
|
sample=foo=bar<quux.wav)");
|
||||||
|
|
||||||
std::vector<std::vector<sfz::Opcode>> expectedMembers = {
|
std::vector<std::vector<sfz::Opcode>> expectedMembers = {
|
||||||
{{"sample", "Alto-Flute-sus-C#4-PB-loop.wav"}},
|
{{"sample", "Alto-Flute-sus-C#4-PB-loop.wav"}},
|
||||||
|
{{"sample", "foo=bar<quux.wav"}},
|
||||||
|
};
|
||||||
|
std::vector<std::string> expectedHeaders = {
|
||||||
|
"region", "region"
|
||||||
|
};
|
||||||
|
std::vector<sfz::Opcode> expectedOpcodes;
|
||||||
|
|
||||||
|
for (auto& members: expectedMembers)
|
||||||
|
for (auto& opcode: members)
|
||||||
|
expectedOpcodes.push_back(opcode);
|
||||||
|
|
||||||
|
REQUIRE(mock.beginnings == 1);
|
||||||
|
REQUIRE(mock.endings == 1);
|
||||||
|
REQUIRE(mock.errors.empty());
|
||||||
|
REQUIRE(mock.warnings.empty());
|
||||||
|
REQUIRE(mock.opcodes == expectedOpcodes);
|
||||||
|
REQUIRE(mock.headers == expectedHeaders);
|
||||||
|
REQUIRE(mock.fullBlockHeaders == expectedHeaders);
|
||||||
|
REQUIRE(mock.fullBlockMembers == expectedMembers);
|
||||||
|
}
|
||||||
|
|
||||||
|
TEST_CASE("[Parsing] Opcode value with inline directives")
|
||||||
|
{
|
||||||
|
sfz::Parser parser;
|
||||||
|
ParsingMocker mock;
|
||||||
|
parser.setListener(&mock);
|
||||||
|
parser.parseString("/opcodeValueWithInlineDirective.sfz",
|
||||||
|
R"(<region>#define $VEL v1 sample=$VEL.wav #define $FOO bar)");
|
||||||
|
|
||||||
|
std::vector<std::vector<sfz::Opcode>> expectedMembers = {
|
||||||
|
{{"sample", "v1.wav"}},
|
||||||
};
|
};
|
||||||
std::vector<std::string> expectedHeaders = {
|
std::vector<std::string> expectedHeaders = {
|
||||||
"region"
|
"region"
|
||||||
|
|
|
||||||
Loading…
Add table
Reference in a new issue