mirror of
https://github.com/Laupetin/OpenAssetTools.git
synced 2025-04-20 00:02:55 +00:00
Merge pull request #57 from Laupetin/fix/macro-expansion-multiple-lines
Fix macro expansion and definition over multiple lines
This commit is contained in:
commit
846a9d36e8
7
.github/workflows/ci.yaml
vendored
7
.github/workflows/ci.yaml
vendored
@ -86,11 +86,18 @@ jobs:
|
|||||||
- name: Test
|
- name: Test
|
||||||
working-directory: ${{ github.workspace }}/build/lib/Release_x86/tests
|
working-directory: ${{ github.workspace }}/build/lib/Release_x86/tests
|
||||||
run: |
|
run: |
|
||||||
|
$combinedExitCode = 0
|
||||||
./ObjCommonTests
|
./ObjCommonTests
|
||||||
|
$combinedExitCode = [System.Math]::max($combinedExitCode, $LASTEXITCODE)
|
||||||
./ObjLoadingTests
|
./ObjLoadingTests
|
||||||
|
$combinedExitCode = [System.Math]::max($combinedExitCode, $LASTEXITCODE)
|
||||||
./ParserTests
|
./ParserTests
|
||||||
|
$combinedExitCode = [System.Math]::max($combinedExitCode, $LASTEXITCODE)
|
||||||
./ZoneCodeGeneratorLibTests
|
./ZoneCodeGeneratorLibTests
|
||||||
|
$combinedExitCode = [System.Math]::max($combinedExitCode, $LASTEXITCODE)
|
||||||
./ZoneCommonTests
|
./ZoneCommonTests
|
||||||
|
$combinedExitCode = [System.Math]::max($combinedExitCode, $LASTEXITCODE)
|
||||||
|
exit $combinedExitCode
|
||||||
- name: Upload artifacts
|
- name: Upload artifacts
|
||||||
uses: actions/upload-artifact@v4
|
uses: actions/upload-artifact@v4
|
||||||
with:
|
with:
|
||||||
|
@ -123,7 +123,10 @@ DefinesStreamProxy::DefinesStreamProxy(IParserLineStream* stream, const bool ski
|
|||||||
: m_stream(stream),
|
: m_stream(stream),
|
||||||
m_skip_directive_lines(skipDirectiveLines),
|
m_skip_directive_lines(skipDirectiveLines),
|
||||||
m_ignore_depth(0),
|
m_ignore_depth(0),
|
||||||
m_in_define(false)
|
m_in_define(false),
|
||||||
|
m_parameter_state(ParameterState::NOT_IN_PARAMETERS),
|
||||||
|
m_current_macro(nullptr),
|
||||||
|
m_macro_parameter_state(ParameterState::NOT_IN_PARAMETERS)
|
||||||
{
|
{
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -142,12 +145,19 @@ int DefinesStreamProxy::GetLineEndEscapePos(const ParserLine& line)
|
|||||||
return -1;
|
return -1;
|
||||||
}
|
}
|
||||||
|
|
||||||
void DefinesStreamProxy::ContinueDefine(const ParserLine& line)
|
void DefinesStreamProxy::ContinueDefine(const ParserLine& line, const unsigned currentPos)
|
||||||
{
|
{
|
||||||
const auto lineEndEscapePos = GetLineEndEscapePos(line);
|
const auto lineEndEscapePos = GetLineEndEscapePos(line);
|
||||||
if (lineEndEscapePos < 0)
|
if (lineEndEscapePos < 0)
|
||||||
{
|
{
|
||||||
m_current_define_value << line.m_line;
|
if (m_parameter_state != ParameterState::NOT_IN_PARAMETERS)
|
||||||
|
throw ParsingException(CreatePos(line, currentPos), "Unclosed macro parameters");
|
||||||
|
|
||||||
|
if (currentPos <= 0)
|
||||||
|
m_current_define_value << line.m_line;
|
||||||
|
else
|
||||||
|
m_current_define_value << line.m_line.substr(currentPos);
|
||||||
|
|
||||||
m_current_define.m_value = m_current_define_value.str();
|
m_current_define.m_value = m_current_define_value.str();
|
||||||
m_current_define.IdentifyParameters(m_current_define_parameters);
|
m_current_define.IdentifyParameters(m_current_define_parameters);
|
||||||
AddDefine(std::move(m_current_define));
|
AddDefine(std::move(m_current_define));
|
||||||
@ -159,49 +169,58 @@ void DefinesStreamProxy::ContinueDefine(const ParserLine& line)
|
|||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
if (line.m_line.size() > static_cast<unsigned>(lineEndEscapePos))
|
if (line.m_line.size() > static_cast<unsigned>(lineEndEscapePos) && currentPos < static_cast<unsigned>(lineEndEscapePos))
|
||||||
m_current_define_value << line.m_line.substr(0, static_cast<unsigned>(lineEndEscapePos));
|
m_current_define_value << line.m_line.substr(currentPos, static_cast<unsigned>(lineEndEscapePos) - currentPos);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
std::vector<std::string> DefinesStreamProxy::MatchDefineParameters(const ParserLine& line, unsigned& parameterPosition)
|
void DefinesStreamProxy::ContinueParameters(const ParserLine& line, unsigned& currentPos)
|
||||||
{
|
{
|
||||||
if (line.m_line[parameterPosition] != '(')
|
const auto lineEndEscapePos = GetLineEndEscapePos(line);
|
||||||
return std::vector<std::string>();
|
|
||||||
|
|
||||||
parameterPosition++;
|
|
||||||
std::vector<std::string> parameters;
|
|
||||||
|
|
||||||
while (true)
|
while (true)
|
||||||
{
|
{
|
||||||
if (!SkipWhitespace(line, parameterPosition) || parameterPosition >= line.m_line.size())
|
if (!SkipWhitespace(line, currentPos))
|
||||||
throw ParsingException(CreatePos(line, parameterPosition), "Invalid define parameter list");
|
throw ParsingException(CreatePos(line, currentPos), "Invalid define parameter list");
|
||||||
|
|
||||||
const auto nameStartPos = parameterPosition;
|
if (lineEndEscapePos >= 0 && currentPos >= static_cast<unsigned>(lineEndEscapePos))
|
||||||
if (!ExtractIdentifier(line, parameterPosition))
|
return;
|
||||||
throw ParsingException(CreatePos(line, parameterPosition), "Cannot extract name of parameter of define");
|
|
||||||
|
|
||||||
parameters.emplace_back(std::string(line.m_line, nameStartPos, parameterPosition - nameStartPos));
|
if (currentPos >= line.m_line.size())
|
||||||
|
throw ParsingException(CreatePos(line, currentPos), "Invalid define parameter list");
|
||||||
|
|
||||||
if (!SkipWhitespace(line, parameterPosition))
|
if ((m_parameter_state == ParameterState::AFTER_OPEN || m_parameter_state == ParameterState::AFTER_PARAM) && line.m_line[currentPos] == ')')
|
||||||
throw ParsingException(CreatePos(line, parameterPosition), "Unclosed define parameters");
|
|
||||||
|
|
||||||
if (parameterPosition >= line.m_line.size())
|
|
||||||
throw ParsingException(CreatePos(line, parameterPosition), "Unclosed define parameters");
|
|
||||||
|
|
||||||
if (line.m_line[parameterPosition] == ')')
|
|
||||||
{
|
{
|
||||||
parameterPosition++;
|
currentPos++;
|
||||||
break;
|
m_parameter_state = ParameterState::NOT_IN_PARAMETERS;
|
||||||
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (line.m_line[parameterPosition] != ',')
|
if (m_parameter_state == ParameterState::AFTER_PARAM && line.m_line[currentPos] == ',')
|
||||||
throw ParsingException(CreatePos(line, parameterPosition), "Unknown symbol in define parameter list");
|
{
|
||||||
|
currentPos++;
|
||||||
|
m_parameter_state = ParameterState::AFTER_COMMA;
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
|
||||||
parameterPosition++;
|
const auto nameStartPos = currentPos;
|
||||||
|
if (!ExtractIdentifier(line, currentPos))
|
||||||
|
throw ParsingException(CreatePos(line, currentPos), "Cannot extract name of parameter of define");
|
||||||
|
|
||||||
|
m_current_define_parameters.emplace_back(line.m_line, nameStartPos, currentPos - nameStartPos);
|
||||||
|
m_parameter_state = ParameterState::AFTER_PARAM;
|
||||||
}
|
}
|
||||||
|
}
|
||||||
|
|
||||||
return parameters;
|
void DefinesStreamProxy::MatchDefineParameters(const ParserLine& line, unsigned& currentPos)
|
||||||
|
{
|
||||||
|
m_current_define_parameters = std::vector<std::string>();
|
||||||
|
if (line.m_line[currentPos] != '(')
|
||||||
|
return;
|
||||||
|
|
||||||
|
m_parameter_state = ParameterState::AFTER_OPEN;
|
||||||
|
currentPos++;
|
||||||
|
|
||||||
|
ContinueParameters(line, currentPos);
|
||||||
}
|
}
|
||||||
|
|
||||||
bool DefinesStreamProxy::MatchDefineDirective(const ParserLine& line, const unsigned directiveStartPosition, const unsigned directiveEndPosition)
|
bool DefinesStreamProxy::MatchDefineDirective(const ParserLine& line, const unsigned directiveStartPosition, const unsigned directiveEndPosition)
|
||||||
@ -223,29 +242,14 @@ bool DefinesStreamProxy::MatchDefineDirective(const ParserLine& line, const unsi
|
|||||||
|
|
||||||
const auto name = line.m_line.substr(nameStartPos, currentPos - nameStartPos);
|
const auto name = line.m_line.substr(nameStartPos, currentPos - nameStartPos);
|
||||||
|
|
||||||
auto parameters = MatchDefineParameters(line, currentPos);
|
MatchDefineParameters(line, currentPos);
|
||||||
|
SkipWhitespace(line, currentPos);
|
||||||
|
|
||||||
const auto lineEndEscapePos = GetLineEndEscapePos(line);
|
m_in_define = true;
|
||||||
if (lineEndEscapePos < 0)
|
m_current_define = Define(name, std::string());
|
||||||
{
|
m_current_define_value.str(std::string());
|
||||||
std::string value;
|
|
||||||
if (currentPos < line.m_line.size())
|
|
||||||
value = line.m_line.substr(currentPos + 1);
|
|
||||||
|
|
||||||
Define define(name, value);
|
ContinueDefine(line, currentPos);
|
||||||
define.IdentifyParameters(parameters);
|
|
||||||
AddDefine(std::move(define));
|
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
m_in_define = true;
|
|
||||||
m_current_define = Define(name, std::string());
|
|
||||||
m_current_define_value.str(std::string());
|
|
||||||
m_current_define_parameters = std::move(parameters);
|
|
||||||
|
|
||||||
if (currentPos < line.m_line.size() && (currentPos + 1) < static_cast<unsigned>(lineEndEscapePos))
|
|
||||||
m_current_define_value << line.m_line.substr(currentPos + 1, static_cast<unsigned>(lineEndEscapePos) - (currentPos + 1));
|
|
||||||
}
|
|
||||||
|
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
@ -276,8 +280,7 @@ bool DefinesStreamProxy::MatchUndefDirective(const ParserLine& line, const unsig
|
|||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
std::unique_ptr<ISimpleExpression>
|
std::unique_ptr<ISimpleExpression> DefinesStreamProxy::ParseExpression(std::shared_ptr<std::string> fileName, int lineNumber, std::string expressionString)
|
||||||
DefinesStreamProxy::ParseExpression(std::shared_ptr<std::string> fileName, int lineNumber, std::string expressionString) const
|
|
||||||
{
|
{
|
||||||
ParserLine pseudoLine(std::move(fileName), lineNumber, std::move(expressionString));
|
ParserLine pseudoLine(std::move(fileName), lineNumber, std::move(expressionString));
|
||||||
ExpandDefinedExpressions(pseudoLine);
|
ExpandDefinedExpressions(pseudoLine);
|
||||||
@ -451,7 +454,7 @@ bool DefinesStreamProxy::MatchEndifDirective(const ParserLine& line, const unsig
|
|||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
bool DefinesStreamProxy::MatchDirectives(const ParserLine& line)
|
bool DefinesStreamProxy::MatchDirectives(ParserLine& line)
|
||||||
{
|
{
|
||||||
unsigned directiveStartPos;
|
unsigned directiveStartPos;
|
||||||
unsigned directiveEndPos;
|
unsigned directiveEndPos;
|
||||||
@ -472,9 +475,9 @@ bool DefinesStreamProxy::MatchDirectives(const ParserLine& line)
|
|||||||
|| MatchEndifDirective(line, directiveStartPos, directiveEndPos);
|
|| MatchEndifDirective(line, directiveStartPos, directiveEndPos);
|
||||||
}
|
}
|
||||||
|
|
||||||
bool DefinesStreamProxy::FindDefineForWord(const ParserLine& line, const unsigned wordStart, const unsigned wordEnd, const Define*& value) const
|
bool DefinesStreamProxy::FindDefineForWord(const std::string& line, const unsigned wordStart, const unsigned wordEnd, const Define*& value) const
|
||||||
{
|
{
|
||||||
const std::string word(line.m_line, wordStart, wordEnd - wordStart);
|
const std::string word(line, wordStart, wordEnd - wordStart);
|
||||||
const auto foundEntry = m_defines.find(word);
|
const auto foundEntry = m_defines.find(word);
|
||||||
if (foundEntry != m_defines.end())
|
if (foundEntry != m_defines.end())
|
||||||
{
|
{
|
||||||
@ -485,71 +488,122 @@ bool DefinesStreamProxy::FindDefineForWord(const ParserLine& line, const unsigne
|
|||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
void DefinesStreamProxy::ExtractParametersFromDefineUsage(const ParserLine& line,
|
void DefinesStreamProxy::ContinueMacroParameters(const ParserLine& line, unsigned& pos)
|
||||||
const unsigned parameterStart,
|
|
||||||
unsigned& parameterEnd,
|
|
||||||
std::vector<std::string>& parameterValues)
|
|
||||||
{
|
{
|
||||||
if (line.m_line[parameterStart] != '(')
|
const auto lineLength = line.m_line.size();
|
||||||
return;
|
while (m_macro_parameter_state != ParameterState::NOT_IN_PARAMETERS && pos < lineLength)
|
||||||
|
|
||||||
std::ostringstream currentValue;
|
|
||||||
auto pos = parameterStart + 1;
|
|
||||||
auto valueHasStarted = false;
|
|
||||||
auto parenthesisDepth = 0;
|
|
||||||
while (true)
|
|
||||||
{
|
{
|
||||||
if (pos >= line.m_line.size())
|
|
||||||
throw ParsingException(CreatePos(line, pos), "Invalid use of define");
|
|
||||||
|
|
||||||
const auto c = line.m_line[pos];
|
const auto c = line.m_line[pos];
|
||||||
|
|
||||||
if (c == ',')
|
if (c == ',')
|
||||||
{
|
{
|
||||||
if (parenthesisDepth > 0)
|
if (!m_macro_bracket_depth.empty())
|
||||||
{
|
{
|
||||||
valueHasStarted = true;
|
m_macro_parameter_state = ParameterState::AFTER_PARAM;
|
||||||
currentValue << c;
|
m_current_macro_parameter << c;
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
parameterValues.emplace_back(currentValue.str());
|
m_macro_parameters.emplace_back(m_current_macro_parameter.str());
|
||||||
currentValue.clear();
|
m_current_macro_parameter.clear();
|
||||||
currentValue.str(std::string());
|
m_current_macro_parameter.str(std::string());
|
||||||
valueHasStarted = false;
|
m_macro_parameter_state = ParameterState::AFTER_COMMA;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
else if (c == '(')
|
else if (c == '(' || c == '[' || c == '{')
|
||||||
{
|
{
|
||||||
valueHasStarted = true;
|
m_macro_parameter_state = ParameterState::AFTER_PARAM;
|
||||||
parenthesisDepth++;
|
m_macro_bracket_depth.push(c);
|
||||||
currentValue << c;
|
m_current_macro_parameter << c;
|
||||||
}
|
}
|
||||||
else if (c == ')')
|
else if (c == ')')
|
||||||
{
|
{
|
||||||
if (parenthesisDepth > 0)
|
if (!m_macro_bracket_depth.empty())
|
||||||
{
|
{
|
||||||
valueHasStarted = true;
|
if (m_macro_bracket_depth.top() != '(')
|
||||||
parenthesisDepth--;
|
throw ParsingException(CreatePos(line, pos), "Unbalanced brackets in macro parameters");
|
||||||
currentValue << c;
|
|
||||||
|
m_macro_bracket_depth.pop();
|
||||||
|
m_macro_parameter_state = ParameterState::AFTER_PARAM;
|
||||||
|
m_current_macro_parameter << c;
|
||||||
|
}
|
||||||
|
else if (m_macro_parameter_state == ParameterState::AFTER_COMMA)
|
||||||
|
{
|
||||||
|
throw ParsingException(CreatePos(line, pos), "Cannot close macro parameters after comma");
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
parameterValues.emplace_back(currentValue.str());
|
m_macro_parameters.emplace_back(m_current_macro_parameter.str());
|
||||||
parameterEnd = pos + 1;
|
m_macro_parameter_state = ParameterState::NOT_IN_PARAMETERS;
|
||||||
break;
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
else if (valueHasStarted || !isspace(c))
|
else if (c == ']' || c == '}')
|
||||||
{
|
{
|
||||||
valueHasStarted = true;
|
if (!m_macro_bracket_depth.empty())
|
||||||
currentValue << c;
|
{
|
||||||
|
const auto otherBracket = c == ']' ? '[' : '{';
|
||||||
|
if (m_macro_bracket_depth.top() != otherBracket)
|
||||||
|
throw ParsingException(CreatePos(line, pos), "Unbalanced brackets in macro parameters");
|
||||||
|
m_macro_bracket_depth.pop();
|
||||||
|
}
|
||||||
|
|
||||||
|
m_macro_parameter_state = ParameterState::AFTER_PARAM;
|
||||||
|
m_current_macro_parameter << c;
|
||||||
|
}
|
||||||
|
else if (m_macro_parameter_state == ParameterState::AFTER_PARAM || !isspace(c))
|
||||||
|
{
|
||||||
|
m_macro_parameter_state = ParameterState::AFTER_PARAM;
|
||||||
|
m_current_macro_parameter << c;
|
||||||
}
|
}
|
||||||
|
|
||||||
pos++;
|
pos++;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void DefinesStreamProxy::ContinueMacro(ParserLine& line)
|
||||||
|
{
|
||||||
|
auto pos = 0u;
|
||||||
|
ContinueMacroParameters(line, pos);
|
||||||
|
|
||||||
|
if (m_macro_parameter_state == ParameterState::NOT_IN_PARAMETERS)
|
||||||
|
{
|
||||||
|
const auto defineValue = m_current_macro->Render(m_macro_parameters);
|
||||||
|
|
||||||
|
if (pos < line.m_line.size())
|
||||||
|
{
|
||||||
|
std::ostringstream ss;
|
||||||
|
ss << defineValue;
|
||||||
|
ss << std::string(line.m_line, pos, line.m_line.size() - pos);
|
||||||
|
line.m_line = ss.str();
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
line.m_line = defineValue;
|
||||||
|
}
|
||||||
|
|
||||||
|
ExpandDefines(line);
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
line.m_line = "";
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void DefinesStreamProxy::ExtractParametersFromDefineUsage(const ParserLine& line, const unsigned parameterStart, unsigned& parameterEnd)
|
||||||
|
{
|
||||||
|
if (line.m_line[parameterStart] != '(')
|
||||||
|
return;
|
||||||
|
|
||||||
|
m_macro_parameter_state = ParameterState::AFTER_OPEN;
|
||||||
|
m_macro_parameters = std::vector<std::string>();
|
||||||
|
m_current_macro_parameter.clear();
|
||||||
|
m_current_macro_parameter.str(std::string());
|
||||||
|
m_macro_bracket_depth = std::stack<char>();
|
||||||
|
parameterEnd = parameterStart + 1;
|
||||||
|
|
||||||
|
ContinueMacroParameters(line, parameterEnd);
|
||||||
|
}
|
||||||
|
|
||||||
bool DefinesStreamProxy::MatchDefinedExpression(const ParserLine& line, unsigned& pos, std::string& definitionName)
|
bool DefinesStreamProxy::MatchDefinedExpression(const ParserLine& line, unsigned& pos, std::string& definitionName)
|
||||||
{
|
{
|
||||||
unsigned currentPos = pos;
|
unsigned currentPos = pos;
|
||||||
@ -601,86 +655,102 @@ void DefinesStreamProxy::ExpandDefinedExpressions(ParserLine& line) const
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
void DefinesStreamProxy::ExpandDefines(ParserLine& line) const
|
void DefinesStreamProxy::ProcessDefine(const ParserLine& line, unsigned& pos, std::ostringstream& out)
|
||||||
|
{
|
||||||
|
ExtractParametersFromDefineUsage(line, pos, pos);
|
||||||
|
|
||||||
|
if (m_macro_parameter_state == ParameterState::NOT_IN_PARAMETERS)
|
||||||
|
{
|
||||||
|
const auto defineValue = m_current_macro->Render(m_macro_parameters);
|
||||||
|
out << defineValue;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
bool DefinesStreamProxy::FindNextDefine(const std::string& line, unsigned& pos, unsigned& defineStart, const DefinesStreamProxy::Define*& define)
|
||||||
|
{
|
||||||
|
const auto lineSize = line.size();
|
||||||
|
auto wordStart = 0u;
|
||||||
|
auto lastWordEnd = 0u;
|
||||||
|
auto inWord = false;
|
||||||
|
|
||||||
|
for (; pos < lineSize; pos++)
|
||||||
|
{
|
||||||
|
const auto c = line[pos];
|
||||||
|
if (!inWord)
|
||||||
|
{
|
||||||
|
if (isalpha(c) || c == '_')
|
||||||
|
{
|
||||||
|
wordStart = pos;
|
||||||
|
inWord = true;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
if (!isalnum(c) && c != '_')
|
||||||
|
{
|
||||||
|
if (FindDefineForWord(line, wordStart, pos, define))
|
||||||
|
{
|
||||||
|
defineStart = wordStart;
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
inWord = false;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if (inWord)
|
||||||
|
{
|
||||||
|
if (FindDefineForWord(line, wordStart, pos, define))
|
||||||
|
{
|
||||||
|
defineStart = wordStart;
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
void DefinesStreamProxy::ExpandDefines(ParserLine& line)
|
||||||
{
|
{
|
||||||
bool usesDefines;
|
|
||||||
auto defineIterations = 0u;
|
auto defineIterations = 0u;
|
||||||
|
bool usesDefines;
|
||||||
|
|
||||||
do
|
do
|
||||||
{
|
{
|
||||||
if (defineIterations > MAX_DEFINE_ITERATIONS)
|
if (defineIterations > MAX_DEFINE_ITERATIONS)
|
||||||
|
{
|
||||||
throw ParsingException(CreatePos(line, 1),
|
throw ParsingException(CreatePos(line, 1),
|
||||||
"Potential define loop? Exceeded max define iterations of " + std::to_string(MAX_DEFINE_ITERATIONS) + " iterations.");
|
"Potential define loop? Exceeded max define iterations of " + std::to_string(MAX_DEFINE_ITERATIONS) + " iterations.");
|
||||||
|
}
|
||||||
|
|
||||||
usesDefines = false;
|
usesDefines = false;
|
||||||
|
auto pos = 0u;
|
||||||
auto wordStart = 0u;
|
auto defineStart = 0u;
|
||||||
auto lastWordEnd = 0u;
|
auto lastDefineEnd = 0u;
|
||||||
auto inWord = false;
|
|
||||||
const Define* value;
|
|
||||||
std::ostringstream str;
|
std::ostringstream str;
|
||||||
|
|
||||||
for (auto i = 0u; i < line.m_line.size(); i++)
|
while (FindNextDefine(line.m_line, pos, defineStart, m_current_macro))
|
||||||
{
|
{
|
||||||
const auto c = line.m_line[i];
|
if (!usesDefines)
|
||||||
if (!inWord)
|
|
||||||
{
|
{
|
||||||
if (isalpha(c) || c == '_')
|
usesDefines = true;
|
||||||
{
|
str << std::string(line.m_line, 0, defineStart);
|
||||||
wordStart = i;
|
|
||||||
inWord = true;
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
if (!isalnum(c) && c != '_')
|
str << std::string(line.m_line, lastDefineEnd, defineStart - (lastDefineEnd));
|
||||||
{
|
|
||||||
if (FindDefineForWord(line, wordStart, i, value))
|
|
||||||
{
|
|
||||||
std::vector<std::string> parameterValues;
|
|
||||||
ExtractParametersFromDefineUsage(line, i, i, parameterValues);
|
|
||||||
const auto defineValue = value->Render(parameterValues);
|
|
||||||
|
|
||||||
if (!usesDefines)
|
|
||||||
{
|
|
||||||
str << std::string(line.m_line, 0, wordStart) << defineValue;
|
|
||||||
usesDefines = true;
|
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
str << std::string(line.m_line, lastWordEnd, wordStart - lastWordEnd) << defineValue;
|
|
||||||
}
|
|
||||||
lastWordEnd = i;
|
|
||||||
}
|
|
||||||
inWord = false;
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
|
||||||
|
|
||||||
if (inWord)
|
ProcessDefine(line, pos, str);
|
||||||
{
|
|
||||||
if (FindDefineForWord(line, wordStart, line.m_line.size(), value))
|
|
||||||
{
|
|
||||||
const std::vector<std::string> parameterValues;
|
|
||||||
const auto defineValue = value->Render(parameterValues);
|
|
||||||
|
|
||||||
if (!usesDefines)
|
lastDefineEnd = pos;
|
||||||
{
|
|
||||||
str << std::string(line.m_line, 0, wordStart) << defineValue;
|
|
||||||
usesDefines = true;
|
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
str << std::string(line.m_line, lastWordEnd, wordStart - lastWordEnd) << defineValue;
|
|
||||||
}
|
|
||||||
lastWordEnd = line.m_line.size();
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
if (usesDefines)
|
if (usesDefines)
|
||||||
{
|
{
|
||||||
if (lastWordEnd < line.m_line.size())
|
if (lastDefineEnd < line.m_line.size())
|
||||||
str << std::string(line.m_line, lastWordEnd, line.m_line.size() - lastWordEnd);
|
str << std::string(line.m_line, lastDefineEnd, line.m_line.size() - lastDefineEnd);
|
||||||
line.m_line = str.str();
|
line.m_line = str.str();
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -709,7 +779,15 @@ ParserLine DefinesStreamProxy::NextLine()
|
|||||||
{
|
{
|
||||||
if (m_in_define)
|
if (m_in_define)
|
||||||
{
|
{
|
||||||
ContinueDefine(line);
|
unsigned currentPos = 0u;
|
||||||
|
|
||||||
|
if (m_parameter_state != ParameterState::NOT_IN_PARAMETERS)
|
||||||
|
{
|
||||||
|
ContinueParameters(line, currentPos);
|
||||||
|
SkipWhitespace(line, currentPos);
|
||||||
|
}
|
||||||
|
|
||||||
|
ContinueDefine(line, currentPos);
|
||||||
if (!m_skip_directive_lines)
|
if (!m_skip_directive_lines)
|
||||||
{
|
{
|
||||||
line.m_line = std::string();
|
line.m_line = std::string();
|
||||||
@ -718,6 +796,11 @@ ParserLine DefinesStreamProxy::NextLine()
|
|||||||
|
|
||||||
line = m_stream->NextLine();
|
line = m_stream->NextLine();
|
||||||
}
|
}
|
||||||
|
else if (m_macro_parameter_state != ParameterState::NOT_IN_PARAMETERS)
|
||||||
|
{
|
||||||
|
ContinueMacro(line);
|
||||||
|
return line;
|
||||||
|
}
|
||||||
else if (MatchDirectives(line) || !m_modes.empty() && m_modes.top() != BlockMode::IN_BLOCK)
|
else if (MatchDirectives(line) || !m_modes.empty() && m_modes.top() != BlockMode::IN_BLOCK)
|
||||||
{
|
{
|
||||||
if (!m_skip_directive_lines)
|
if (!m_skip_directive_lines)
|
||||||
|
@ -47,13 +47,21 @@ public:
|
|||||||
};
|
};
|
||||||
|
|
||||||
private:
|
private:
|
||||||
enum class BlockMode
|
enum class BlockMode : uint8_t
|
||||||
{
|
{
|
||||||
NOT_IN_BLOCK,
|
NOT_IN_BLOCK,
|
||||||
IN_BLOCK,
|
IN_BLOCK,
|
||||||
BLOCK_BLOCKED
|
BLOCK_BLOCKED
|
||||||
};
|
};
|
||||||
|
|
||||||
|
enum class ParameterState : uint8_t
|
||||||
|
{
|
||||||
|
NOT_IN_PARAMETERS,
|
||||||
|
AFTER_OPEN,
|
||||||
|
AFTER_PARAM,
|
||||||
|
AFTER_COMMA
|
||||||
|
};
|
||||||
|
|
||||||
IParserLineStream* const m_stream;
|
IParserLineStream* const m_stream;
|
||||||
const bool m_skip_directive_lines;
|
const bool m_skip_directive_lines;
|
||||||
std::map<std::string, Define> m_defines;
|
std::map<std::string, Define> m_defines;
|
||||||
@ -61,13 +69,21 @@ private:
|
|||||||
unsigned m_ignore_depth;
|
unsigned m_ignore_depth;
|
||||||
|
|
||||||
bool m_in_define;
|
bool m_in_define;
|
||||||
|
ParameterState m_parameter_state;
|
||||||
Define m_current_define;
|
Define m_current_define;
|
||||||
std::ostringstream m_current_define_value;
|
std::ostringstream m_current_define_value;
|
||||||
std::vector<std::string> m_current_define_parameters;
|
std::vector<std::string> m_current_define_parameters;
|
||||||
|
|
||||||
|
const Define* m_current_macro;
|
||||||
|
ParameterState m_macro_parameter_state;
|
||||||
|
std::vector<std::string> m_macro_parameters;
|
||||||
|
std::ostringstream m_current_macro_parameter;
|
||||||
|
std::stack<char> m_macro_bracket_depth;
|
||||||
|
|
||||||
static int GetLineEndEscapePos(const ParserLine& line);
|
static int GetLineEndEscapePos(const ParserLine& line);
|
||||||
static std::vector<std::string> MatchDefineParameters(const ParserLine& line, unsigned& parameterPosition);
|
void MatchDefineParameters(const ParserLine& line, unsigned& currentPos);
|
||||||
void ContinueDefine(const ParserLine& line);
|
void ContinueDefine(const ParserLine& line, unsigned currentPos);
|
||||||
|
void ContinueParameters(const ParserLine& line, unsigned& currentPos);
|
||||||
_NODISCARD bool MatchDefineDirective(const ParserLine& line, unsigned directiveStartPosition, unsigned directiveEndPosition);
|
_NODISCARD bool MatchDefineDirective(const ParserLine& line, unsigned directiveStartPosition, unsigned directiveEndPosition);
|
||||||
_NODISCARD bool MatchUndefDirective(const ParserLine& line, unsigned directiveStartPosition, unsigned directiveEndPosition);
|
_NODISCARD bool MatchUndefDirective(const ParserLine& line, unsigned directiveStartPosition, unsigned directiveEndPosition);
|
||||||
_NODISCARD bool MatchIfDirective(const ParserLine& line, unsigned directiveStartPosition, unsigned directiveEndPosition);
|
_NODISCARD bool MatchIfDirective(const ParserLine& line, unsigned directiveStartPosition, unsigned directiveEndPosition);
|
||||||
@ -75,24 +91,28 @@ private:
|
|||||||
_NODISCARD bool MatchIfdefDirective(const ParserLine& line, unsigned directiveStartPosition, unsigned directiveEndPosition);
|
_NODISCARD bool MatchIfdefDirective(const ParserLine& line, unsigned directiveStartPosition, unsigned directiveEndPosition);
|
||||||
_NODISCARD bool MatchElseDirective(const ParserLine& line, unsigned directiveStartPosition, unsigned directiveEndPosition);
|
_NODISCARD bool MatchElseDirective(const ParserLine& line, unsigned directiveStartPosition, unsigned directiveEndPosition);
|
||||||
_NODISCARD bool MatchEndifDirective(const ParserLine& line, unsigned directiveStartPosition, unsigned directiveEndPosition);
|
_NODISCARD bool MatchEndifDirective(const ParserLine& line, unsigned directiveStartPosition, unsigned directiveEndPosition);
|
||||||
_NODISCARD bool MatchDirectives(const ParserLine& line);
|
_NODISCARD bool MatchDirectives(ParserLine& line);
|
||||||
|
|
||||||
static void
|
void ExtractParametersFromDefineUsage(const ParserLine& line, unsigned parameterStart, unsigned& parameterEnd);
|
||||||
ExtractParametersFromDefineUsage(const ParserLine& line, unsigned parameterStart, unsigned& parameterEnd, std::vector<std::string>& parameterValues);
|
bool FindDefineForWord(const std::string& line, unsigned wordStart, unsigned wordEnd, const Define*& value) const;
|
||||||
bool FindDefineForWord(const ParserLine& line, unsigned wordStart, unsigned wordEnd, const Define*& value) const;
|
|
||||||
|
|
||||||
static bool MatchDefinedExpression(const ParserLine& line, unsigned& pos, std::string& definitionName);
|
static bool MatchDefinedExpression(const ParserLine& line, unsigned& pos, std::string& definitionName);
|
||||||
void ExpandDefinedExpressions(ParserLine& line) const;
|
void ExpandDefinedExpressions(ParserLine& line) const;
|
||||||
|
|
||||||
|
void ContinueMacroParameters(const ParserLine& line, unsigned& pos);
|
||||||
|
void ContinueMacro(ParserLine& line);
|
||||||
|
void ProcessDefine(const ParserLine& line, unsigned& pos, std::ostringstream& out);
|
||||||
|
bool FindNextDefine(const std::string& line, unsigned& pos, unsigned& defineStart, const DefinesStreamProxy::Define*& define);
|
||||||
|
|
||||||
public:
|
public:
|
||||||
explicit DefinesStreamProxy(IParserLineStream* stream, bool skipDirectiveLines = false);
|
explicit DefinesStreamProxy(IParserLineStream* stream, bool skipDirectiveLines = false);
|
||||||
|
|
||||||
void AddDefine(Define define);
|
void AddDefine(Define define);
|
||||||
void Undefine(const std::string& name);
|
void Undefine(const std::string& name);
|
||||||
|
|
||||||
void ExpandDefines(ParserLine& line) const;
|
void ExpandDefines(ParserLine& line);
|
||||||
|
|
||||||
_NODISCARD std::unique_ptr<ISimpleExpression> ParseExpression(std::shared_ptr<std::string> fileName, int lineNumber, std::string expressionString) const;
|
_NODISCARD std::unique_ptr<ISimpleExpression> ParseExpression(std::shared_ptr<std::string> fileName, int lineNumber, std::string expressionString);
|
||||||
|
|
||||||
ParserLine NextLine() override;
|
ParserLine NextLine() override;
|
||||||
bool IncludeFile(const std::string& filename) override;
|
bool IncludeFile(const std::string& filename) override;
|
||||||
|
@ -6,7 +6,7 @@
|
|||||||
#include <exception>
|
#include <exception>
|
||||||
#include <string>
|
#include <string>
|
||||||
|
|
||||||
class ParsingException final : std::exception
|
class ParsingException final : public std::exception
|
||||||
{
|
{
|
||||||
TokenPos m_pos;
|
TokenPos m_pos;
|
||||||
std::string m_message;
|
std::string m_message;
|
||||||
|
@ -1,8 +1,14 @@
|
|||||||
#include "Parsing/Impl/DefinesStreamProxy.h"
|
#include "Parsing/Impl/DefinesStreamProxy.h"
|
||||||
#include "Parsing/Mock/MockParserLineStream.h"
|
#include "Parsing/Mock/MockParserLineStream.h"
|
||||||
|
#include "Parsing/ParsingException.h"
|
||||||
|
|
||||||
#include <catch2/catch_test_macros.hpp>
|
#include <catch2/catch_test_macros.hpp>
|
||||||
#include <catch2/generators/catch_generators.hpp>
|
#include <catch2/generators/catch_generators.hpp>
|
||||||
|
#include <catch2/matchers/catch_matchers.hpp>
|
||||||
|
#include <catch2/matchers/catch_matchers_exception.hpp>
|
||||||
|
#include <catch2/matchers/catch_matchers_string.hpp>
|
||||||
|
|
||||||
|
using namespace Catch::Matchers;
|
||||||
|
|
||||||
namespace test::parsing::impl::defines_stream_proxy
|
namespace test::parsing::impl::defines_stream_proxy
|
||||||
{
|
{
|
||||||
@ -13,9 +19,21 @@ namespace test::parsing::impl::defines_stream_proxy
|
|||||||
REQUIRE(line.m_line == value);
|
REQUIRE(line.m_line == value);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void ExpectErrorInLine(IParserLineStream* stream, const int lineNumber, const int columnNumber)
|
||||||
|
{
|
||||||
|
REQUIRE_THROWS_MATCHES(
|
||||||
|
stream->NextLine(), ParsingException, MessageMatches(ContainsSubstring("L" + std::to_string(lineNumber) + ":" + std::to_string(columnNumber))));
|
||||||
|
}
|
||||||
|
|
||||||
TEST_CASE("DefinesStreamProxy: Ensure simple define and positive ifdef is working", "[parsing][parsingstream]")
|
TEST_CASE("DefinesStreamProxy: Ensure simple define and positive ifdef is working", "[parsing][parsingstream]")
|
||||||
{
|
{
|
||||||
const std::vector<std::string> lines{"#define ASDF", "#ifdef ASDF", "Hello World", "#endif", "Hello Galaxy"};
|
const std::vector<std::string> lines{
|
||||||
|
"#define ASDF",
|
||||||
|
"#ifdef ASDF",
|
||||||
|
"Hello World",
|
||||||
|
"#endif",
|
||||||
|
"Hello Galaxy",
|
||||||
|
};
|
||||||
|
|
||||||
MockParserLineStream mockStream(lines);
|
MockParserLineStream mockStream(lines);
|
||||||
DefinesStreamProxy proxy(&mockStream);
|
DefinesStreamProxy proxy(&mockStream);
|
||||||
@ -31,7 +49,13 @@ namespace test::parsing::impl::defines_stream_proxy
|
|||||||
|
|
||||||
TEST_CASE("DefinesStreamProxy: Ensure simple define and negative ifdef is working", "[parsing][parsingstream]")
|
TEST_CASE("DefinesStreamProxy: Ensure simple define and negative ifdef is working", "[parsing][parsingstream]")
|
||||||
{
|
{
|
||||||
const std::vector<std::string> lines{"#define ASDF", "#ifdef NONO", "Hello World", "#endif", "Hello Galaxy"};
|
const std::vector<std::string> lines{
|
||||||
|
"#define ASDF",
|
||||||
|
"#ifdef NONO",
|
||||||
|
"Hello World",
|
||||||
|
"#endif",
|
||||||
|
"Hello Galaxy",
|
||||||
|
};
|
||||||
|
|
||||||
MockParserLineStream mockStream(lines);
|
MockParserLineStream mockStream(lines);
|
||||||
DefinesStreamProxy proxy(&mockStream);
|
DefinesStreamProxy proxy(&mockStream);
|
||||||
@ -47,7 +71,13 @@ namespace test::parsing::impl::defines_stream_proxy
|
|||||||
|
|
||||||
TEST_CASE("DefinesStreamProxy: Ensure simple define and positive ifndef is working", "[parsing][parsingstream]")
|
TEST_CASE("DefinesStreamProxy: Ensure simple define and positive ifndef is working", "[parsing][parsingstream]")
|
||||||
{
|
{
|
||||||
const std::vector<std::string> lines{"#define ASDF", "#ifndef NONO", "Hello World", "#endif", "Hello Galaxy"};
|
const std::vector<std::string> lines{
|
||||||
|
"#define ASDF",
|
||||||
|
"#ifndef NONO",
|
||||||
|
"Hello World",
|
||||||
|
"#endif",
|
||||||
|
"Hello Galaxy",
|
||||||
|
};
|
||||||
|
|
||||||
MockParserLineStream mockStream(lines);
|
MockParserLineStream mockStream(lines);
|
||||||
DefinesStreamProxy proxy(&mockStream);
|
DefinesStreamProxy proxy(&mockStream);
|
||||||
@ -63,7 +93,13 @@ namespace test::parsing::impl::defines_stream_proxy
|
|||||||
|
|
||||||
TEST_CASE("DefinesStreamProxy: Ensure simple define and negative ifndef is working", "[parsing][parsingstream]")
|
TEST_CASE("DefinesStreamProxy: Ensure simple define and negative ifndef is working", "[parsing][parsingstream]")
|
||||||
{
|
{
|
||||||
const std::vector<std::string> lines{"#define ASDF", "#ifndef ASDF", "Hello World", "#endif", "Hello Galaxy"};
|
const std::vector<std::string> lines{
|
||||||
|
"#define ASDF",
|
||||||
|
"#ifndef ASDF",
|
||||||
|
"Hello World",
|
||||||
|
"#endif",
|
||||||
|
"Hello Galaxy",
|
||||||
|
};
|
||||||
|
|
||||||
MockParserLineStream mockStream(lines);
|
MockParserLineStream mockStream(lines);
|
||||||
DefinesStreamProxy proxy(&mockStream);
|
DefinesStreamProxy proxy(&mockStream);
|
||||||
@ -79,7 +115,15 @@ namespace test::parsing::impl::defines_stream_proxy
|
|||||||
|
|
||||||
TEST_CASE("DefinesStreamProxy: Ensure else is working", "[parsing][parsingstream]")
|
TEST_CASE("DefinesStreamProxy: Ensure else is working", "[parsing][parsingstream]")
|
||||||
{
|
{
|
||||||
const std::vector<std::string> lines{"#define ASDF", "#ifdef NONO", "Hello World1", "#else", "Hello World2", "#endif", "Hello Galaxy"};
|
const std::vector<std::string> lines{
|
||||||
|
"#define ASDF",
|
||||||
|
"#ifdef NONO",
|
||||||
|
"Hello World1",
|
||||||
|
"#else",
|
||||||
|
"Hello World2",
|
||||||
|
"#endif",
|
||||||
|
"Hello Galaxy",
|
||||||
|
};
|
||||||
|
|
||||||
MockParserLineStream mockStream(lines);
|
MockParserLineStream mockStream(lines);
|
||||||
DefinesStreamProxy proxy(&mockStream);
|
DefinesStreamProxy proxy(&mockStream);
|
||||||
@ -97,21 +141,23 @@ namespace test::parsing::impl::defines_stream_proxy
|
|||||||
|
|
||||||
TEST_CASE("DefinesStreamProxy: Ensure nested ifdef is working", "[parsing][parsingstream]")
|
TEST_CASE("DefinesStreamProxy: Ensure nested ifdef is working", "[parsing][parsingstream]")
|
||||||
{
|
{
|
||||||
const std::vector<std::string> lines{"#define ASDF",
|
const std::vector<std::string> lines{
|
||||||
"#ifdef ASDF",
|
"#define ASDF",
|
||||||
"#ifdef NONO",
|
"#ifdef ASDF",
|
||||||
"Hello World1",
|
"#ifdef NONO",
|
||||||
"#else",
|
"Hello World1",
|
||||||
"Hello World2",
|
"#else",
|
||||||
"#endif",
|
"Hello World2",
|
||||||
"#else",
|
"#endif",
|
||||||
"#ifdef ASDF",
|
"#else",
|
||||||
"Hello World3",
|
"#ifdef ASDF",
|
||||||
"#else",
|
"Hello World3",
|
||||||
"Hello World4",
|
"#else",
|
||||||
"#endif",
|
"Hello World4",
|
||||||
"#endif",
|
"#endif",
|
||||||
"Hello Galaxy"};
|
"#endif",
|
||||||
|
"Hello Galaxy",
|
||||||
|
};
|
||||||
|
|
||||||
MockParserLineStream mockStream(lines);
|
MockParserLineStream mockStream(lines);
|
||||||
DefinesStreamProxy proxy(&mockStream);
|
DefinesStreamProxy proxy(&mockStream);
|
||||||
@ -138,7 +184,16 @@ namespace test::parsing::impl::defines_stream_proxy
|
|||||||
TEST_CASE("DefinesStreamProxy: Ensure undef is working", "[parsing][parsingstream]")
|
TEST_CASE("DefinesStreamProxy: Ensure undef is working", "[parsing][parsingstream]")
|
||||||
{
|
{
|
||||||
const std::vector<std::string> lines{
|
const std::vector<std::string> lines{
|
||||||
"#define ASDF", "#ifdef ASDF", "Hello World", "#endif", "#undef ASDF", "#ifdef ASDF", "Hello World", "#endif", "Hello Galaxy"};
|
"#define ASDF",
|
||||||
|
"#ifdef ASDF",
|
||||||
|
"Hello World",
|
||||||
|
"#endif",
|
||||||
|
"#undef ASDF",
|
||||||
|
"#ifdef ASDF",
|
||||||
|
"Hello World",
|
||||||
|
"#endif",
|
||||||
|
"Hello Galaxy",
|
||||||
|
};
|
||||||
|
|
||||||
MockParserLineStream mockStream(lines);
|
MockParserLineStream mockStream(lines);
|
||||||
DefinesStreamProxy proxy(&mockStream);
|
DefinesStreamProxy proxy(&mockStream);
|
||||||
@ -159,7 +214,16 @@ namespace test::parsing::impl::defines_stream_proxy
|
|||||||
TEST_CASE("DefinesStreamProxy: Ensure undef does not undefine everything", "[parsing][parsingstream]")
|
TEST_CASE("DefinesStreamProxy: Ensure undef does not undefine everything", "[parsing][parsingstream]")
|
||||||
{
|
{
|
||||||
const std::vector<std::string> lines{
|
const std::vector<std::string> lines{
|
||||||
"#define ASDF", "#ifdef ASDF", "Hello World", "#endif", "#undef NONO", "#ifdef ASDF", "Hello World", "#endif", "Hello Galaxy"};
|
"#define ASDF",
|
||||||
|
"#ifdef ASDF",
|
||||||
|
"Hello World",
|
||||||
|
"#endif",
|
||||||
|
"#undef NONO",
|
||||||
|
"#ifdef ASDF",
|
||||||
|
"Hello World",
|
||||||
|
"#endif",
|
||||||
|
"Hello Galaxy",
|
||||||
|
};
|
||||||
|
|
||||||
MockParserLineStream mockStream(lines);
|
MockParserLineStream mockStream(lines);
|
||||||
DefinesStreamProxy proxy(&mockStream);
|
DefinesStreamProxy proxy(&mockStream);
|
||||||
@ -179,7 +243,13 @@ namespace test::parsing::impl::defines_stream_proxy
|
|||||||
|
|
||||||
TEST_CASE("DefinesStreamProxy: Ensure simple defines are working", "[parsing][parsingstream]")
|
TEST_CASE("DefinesStreamProxy: Ensure simple defines are working", "[parsing][parsingstream]")
|
||||||
{
|
{
|
||||||
const std::vector<std::string> lines{"#define ASDF LOL", "ASDF", "A ASDF B", "ASDF B", "A ASDF"};
|
const std::vector<std::string> lines{
|
||||||
|
"#define ASDF LOL",
|
||||||
|
"ASDF",
|
||||||
|
"A ASDF B",
|
||||||
|
"ASDF B",
|
||||||
|
"A ASDF",
|
||||||
|
};
|
||||||
|
|
||||||
MockParserLineStream mockStream(lines);
|
MockParserLineStream mockStream(lines);
|
||||||
DefinesStreamProxy proxy(&mockStream);
|
DefinesStreamProxy proxy(&mockStream);
|
||||||
@ -195,7 +265,10 @@ namespace test::parsing::impl::defines_stream_proxy
|
|||||||
|
|
||||||
TEST_CASE("DefinesStreamProxy: Ensure defines can be surrounded by symbols", "[parsing][parsingstream]")
|
TEST_CASE("DefinesStreamProxy: Ensure defines can be surrounded by symbols", "[parsing][parsingstream]")
|
||||||
{
|
{
|
||||||
const std::vector<std::string> lines{"#define ASDF LOL", "!ASDF%"};
|
const std::vector<std::string> lines{
|
||||||
|
"#define ASDF LOL",
|
||||||
|
"!ASDF%",
|
||||||
|
};
|
||||||
|
|
||||||
MockParserLineStream mockStream(lines);
|
MockParserLineStream mockStream(lines);
|
||||||
DefinesStreamProxy proxy(&mockStream);
|
DefinesStreamProxy proxy(&mockStream);
|
||||||
@ -208,7 +281,11 @@ namespace test::parsing::impl::defines_stream_proxy
|
|||||||
|
|
||||||
TEST_CASE("DefinesStreamProxy: Ensure can use multiple defines in one line", "[parsing][parsingstream]")
|
TEST_CASE("DefinesStreamProxy: Ensure can use multiple defines in one line", "[parsing][parsingstream]")
|
||||||
{
|
{
|
||||||
const std::vector<std::string> lines{"#define A Hello", "#define B world", "A my dear B!"};
|
const std::vector<std::string> lines{
|
||||||
|
"#define A Hello",
|
||||||
|
"#define B world",
|
||||||
|
"A my dear B!",
|
||||||
|
};
|
||||||
|
|
||||||
MockParserLineStream mockStream(lines);
|
MockParserLineStream mockStream(lines);
|
||||||
DefinesStreamProxy proxy(&mockStream);
|
DefinesStreamProxy proxy(&mockStream);
|
||||||
@ -222,7 +299,12 @@ namespace test::parsing::impl::defines_stream_proxy
|
|||||||
|
|
||||||
TEST_CASE("DefinesStreamProxy: Ensure defines in disabled block are ignored", "[parsing][parsingstream]")
|
TEST_CASE("DefinesStreamProxy: Ensure defines in disabled block are ignored", "[parsing][parsingstream]")
|
||||||
{
|
{
|
||||||
const std::vector<std::string> lines{"#ifdef LOLO", "#define hello world", "#endif", "hello"};
|
const std::vector<std::string> lines{
|
||||||
|
"#ifdef LOLO",
|
||||||
|
"#define hello world",
|
||||||
|
"#endif",
|
||||||
|
"hello",
|
||||||
|
};
|
||||||
|
|
||||||
MockParserLineStream mockStream(lines);
|
MockParserLineStream mockStream(lines);
|
||||||
DefinesStreamProxy proxy(&mockStream);
|
DefinesStreamProxy proxy(&mockStream);
|
||||||
@ -237,7 +319,13 @@ namespace test::parsing::impl::defines_stream_proxy
|
|||||||
|
|
||||||
TEST_CASE("DefinesStreamProxy: Ensure undefs in disabled block are ignored", "[parsing][parsingstream]")
|
TEST_CASE("DefinesStreamProxy: Ensure undefs in disabled block are ignored", "[parsing][parsingstream]")
|
||||||
{
|
{
|
||||||
const std::vector<std::string> lines{"#define hello world", "#ifdef LOLO", "#undef hello", "#endif", "hello"};
|
const std::vector<std::string> lines{
|
||||||
|
"#define hello world",
|
||||||
|
"#ifdef LOLO",
|
||||||
|
"#undef hello",
|
||||||
|
"#endif",
|
||||||
|
"hello",
|
||||||
|
};
|
||||||
|
|
||||||
MockParserLineStream mockStream(lines);
|
MockParserLineStream mockStream(lines);
|
||||||
DefinesStreamProxy proxy(&mockStream);
|
DefinesStreamProxy proxy(&mockStream);
|
||||||
@ -253,7 +341,10 @@ namespace test::parsing::impl::defines_stream_proxy
|
|||||||
|
|
||||||
TEST_CASE("DefinesStreamProxy: Ensure can define name with underscores and digits", "[parsing][parsingstream]")
|
TEST_CASE("DefinesStreamProxy: Ensure can define name with underscores and digits", "[parsing][parsingstream]")
|
||||||
{
|
{
|
||||||
const std::vector<std::string> lines{"#define __int16 short", "unsigned __int16 value;"};
|
const std::vector<std::string> lines{
|
||||||
|
"#define __int16 short",
|
||||||
|
"unsigned __int16 value;",
|
||||||
|
};
|
||||||
|
|
||||||
MockParserLineStream mockStream(lines);
|
MockParserLineStream mockStream(lines);
|
||||||
DefinesStreamProxy proxy(&mockStream);
|
DefinesStreamProxy proxy(&mockStream);
|
||||||
@ -288,7 +379,10 @@ namespace test::parsing::impl::defines_stream_proxy
|
|||||||
|
|
||||||
TEST_CASE("DefinesStreamProxy: Ensure can add define with parameters", "[parsing][parsingstream]")
|
TEST_CASE("DefinesStreamProxy: Ensure can add define with parameters", "[parsing][parsingstream]")
|
||||||
{
|
{
|
||||||
const std::vector<std::string> lines{"#define test(x) alignas(x)", "struct test(1337) test_struct"};
|
const std::vector<std::string> lines{
|
||||||
|
"#define test(x) alignas(x)",
|
||||||
|
"struct test(1337) test_struct",
|
||||||
|
};
|
||||||
|
|
||||||
MockParserLineStream mockStream(lines);
|
MockParserLineStream mockStream(lines);
|
||||||
DefinesStreamProxy proxy(&mockStream);
|
DefinesStreamProxy proxy(&mockStream);
|
||||||
@ -301,7 +395,10 @@ namespace test::parsing::impl::defines_stream_proxy
|
|||||||
|
|
||||||
TEST_CASE("DefinesStreamProxy: Ensure can use parameter multiple times", "[parsing][parsingstream]")
|
TEST_CASE("DefinesStreamProxy: Ensure can use parameter multiple times", "[parsing][parsingstream]")
|
||||||
{
|
{
|
||||||
const std::vector<std::string> lines{"#define test(x) x|x|x|x", "struct test(1337) test_struct"};
|
const std::vector<std::string> lines{
|
||||||
|
"#define test(x) x|x|x|x",
|
||||||
|
"struct test(1337) test_struct",
|
||||||
|
};
|
||||||
|
|
||||||
MockParserLineStream mockStream(lines);
|
MockParserLineStream mockStream(lines);
|
||||||
DefinesStreamProxy proxy(&mockStream);
|
DefinesStreamProxy proxy(&mockStream);
|
||||||
@ -314,7 +411,10 @@ namespace test::parsing::impl::defines_stream_proxy
|
|||||||
|
|
||||||
TEST_CASE("DefinesStreamProxy: Ensure can use parameterized define in between symbols", "[parsing][parsingstream]")
|
TEST_CASE("DefinesStreamProxy: Ensure can use parameterized define in between symbols", "[parsing][parsingstream]")
|
||||||
{
|
{
|
||||||
const std::vector<std::string> lines{"#define test(x) x|x|x|x", "%test(5)%"};
|
const std::vector<std::string> lines{
|
||||||
|
"#define test(x) x|x|x|x",
|
||||||
|
"%test(5)%",
|
||||||
|
};
|
||||||
|
|
||||||
MockParserLineStream mockStream(lines);
|
MockParserLineStream mockStream(lines);
|
||||||
DefinesStreamProxy proxy(&mockStream);
|
DefinesStreamProxy proxy(&mockStream);
|
||||||
@ -327,7 +427,10 @@ namespace test::parsing::impl::defines_stream_proxy
|
|||||||
|
|
||||||
TEST_CASE("DefinesStreamProxy: Ensure can define multiple parameters", "[parsing][parsingstream]")
|
TEST_CASE("DefinesStreamProxy: Ensure can define multiple parameters", "[parsing][parsingstream]")
|
||||||
{
|
{
|
||||||
const std::vector<std::string> lines{"#define test(a1, a2, a3) a1 + a2 = a3", "make calc test(1, 2, 3);"};
|
const std::vector<std::string> lines{
|
||||||
|
"#define test(a1, a2, a3) a1 + a2 = a3",
|
||||||
|
"make calc test(1, 2, 3);",
|
||||||
|
};
|
||||||
|
|
||||||
MockParserLineStream mockStream(lines);
|
MockParserLineStream mockStream(lines);
|
||||||
DefinesStreamProxy proxy(&mockStream);
|
DefinesStreamProxy proxy(&mockStream);
|
||||||
@ -340,7 +443,10 @@ namespace test::parsing::impl::defines_stream_proxy
|
|||||||
|
|
||||||
TEST_CASE("DefinesStreamProxy: Ensure can define multiple parameters without spacing", "[parsing][parsingstream]")
|
TEST_CASE("DefinesStreamProxy: Ensure can define multiple parameters without spacing", "[parsing][parsingstream]")
|
||||||
{
|
{
|
||||||
const std::vector<std::string> lines{"#define test(a1,a2,a3) a1+a2=a3", "make calc test(1,2,3);"};
|
const std::vector<std::string> lines{
|
||||||
|
"#define test(a1,a2,a3) a1+a2=a3",
|
||||||
|
"make calc test(1,2,3);",
|
||||||
|
};
|
||||||
|
|
||||||
MockParserLineStream mockStream(lines);
|
MockParserLineStream mockStream(lines);
|
||||||
DefinesStreamProxy proxy(&mockStream);
|
DefinesStreamProxy proxy(&mockStream);
|
||||||
@ -353,7 +459,10 @@ namespace test::parsing::impl::defines_stream_proxy
|
|||||||
|
|
||||||
TEST_CASE("DefinesStreamProxy: Ensure can define parameters with underscore", "[parsing][parsingstream]")
|
TEST_CASE("DefinesStreamProxy: Ensure can define parameters with underscore", "[parsing][parsingstream]")
|
||||||
{
|
{
|
||||||
const std::vector<std::string> lines{"#define test(test_parameter) this is test_parameter", "Apparently test(a very cool text);"};
|
const std::vector<std::string> lines{
|
||||||
|
"#define test(test_parameter) this is test_parameter",
|
||||||
|
"Apparently test(a very cool text);",
|
||||||
|
};
|
||||||
|
|
||||||
MockParserLineStream mockStream(lines);
|
MockParserLineStream mockStream(lines);
|
||||||
DefinesStreamProxy proxy(&mockStream);
|
DefinesStreamProxy proxy(&mockStream);
|
||||||
@ -558,7 +667,10 @@ namespace test::parsing::impl::defines_stream_proxy
|
|||||||
|
|
||||||
TEST_CASE("DefinesStreamProxy: Ensure can use parenthesis in parameters values", "[parsing][parsingstream]")
|
TEST_CASE("DefinesStreamProxy: Ensure can use parenthesis in parameters values", "[parsing][parsingstream]")
|
||||||
{
|
{
|
||||||
const std::vector<std::string> lines{"#define someStuff(param1) Hello param1 World", "someStuff(A sentence with (parenthesis) and stuff)"};
|
const std::vector<std::string> lines{
|
||||||
|
"#define someStuff(param1) Hello param1 World",
|
||||||
|
"someStuff(A sentence with (parenthesis) and stuff)",
|
||||||
|
};
|
||||||
|
|
||||||
MockParserLineStream mockStream(lines);
|
MockParserLineStream mockStream(lines);
|
||||||
DefinesStreamProxy proxy(&mockStream);
|
DefinesStreamProxy proxy(&mockStream);
|
||||||
@ -571,8 +683,10 @@ namespace test::parsing::impl::defines_stream_proxy
|
|||||||
|
|
||||||
TEST_CASE("DefinesStreamProxy: Ensure can use comma in parenthesis in parameters values", "[parsing][parsingstream]")
|
TEST_CASE("DefinesStreamProxy: Ensure can use comma in parenthesis in parameters values", "[parsing][parsingstream]")
|
||||||
{
|
{
|
||||||
const std::vector<std::string> lines{"#define someStuff(param1) Hello param1 World",
|
const std::vector<std::string> lines{
|
||||||
"someStuff(A sentence with (parenthesis and a , character) and stuff)"};
|
"#define someStuff(param1) Hello param1 World",
|
||||||
|
"someStuff(A sentence with (parenthesis and a , character) and stuff)",
|
||||||
|
};
|
||||||
|
|
||||||
MockParserLineStream mockStream(lines);
|
MockParserLineStream mockStream(lines);
|
||||||
DefinesStreamProxy proxy(&mockStream);
|
DefinesStreamProxy proxy(&mockStream);
|
||||||
@ -583,9 +697,83 @@ namespace test::parsing::impl::defines_stream_proxy
|
|||||||
REQUIRE(proxy.Eof());
|
REQUIRE(proxy.Eof());
|
||||||
}
|
}
|
||||||
|
|
||||||
|
TEST_CASE("DefinesStreamProxy: Ensure can use comma in square brackets in parameters values", "[parsing][parsingstream]")
|
||||||
|
{
|
||||||
|
const std::vector<std::string> lines{
|
||||||
|
"#define someStuff(param1) Hello param1 World",
|
||||||
|
"someStuff(A sentence with [brackets and a , character] and stuff)",
|
||||||
|
};
|
||||||
|
|
||||||
|
MockParserLineStream mockStream(lines);
|
||||||
|
DefinesStreamProxy proxy(&mockStream);
|
||||||
|
|
||||||
|
ExpectLine(&proxy, 1, "");
|
||||||
|
ExpectLine(&proxy, 2, "Hello A sentence with [brackets and a , character] and stuff World");
|
||||||
|
|
||||||
|
REQUIRE(proxy.Eof());
|
||||||
|
}
|
||||||
|
|
||||||
|
TEST_CASE("DefinesStreamProxy: Ensure can use comma in curly braces in parameters values", "[parsing][parsingstream]")
|
||||||
|
{
|
||||||
|
const std::vector<std::string> lines{
|
||||||
|
"#define someStuff(param1) Hello param1 World",
|
||||||
|
"someStuff(A sentence with {braces and a , character} and stuff)",
|
||||||
|
};
|
||||||
|
|
||||||
|
MockParserLineStream mockStream(lines);
|
||||||
|
DefinesStreamProxy proxy(&mockStream);
|
||||||
|
|
||||||
|
ExpectLine(&proxy, 1, "");
|
||||||
|
ExpectLine(&proxy, 2, "Hello A sentence with {braces and a , character} and stuff World");
|
||||||
|
|
||||||
|
REQUIRE(proxy.Eof());
|
||||||
|
}
|
||||||
|
|
||||||
|
TEST_CASE("DefinesStreamProxy: Ensure throws error on unclosed parenthesis in params", "[parsing][parsingstream]")
|
||||||
|
{
|
||||||
|
const std::vector<std::string> lines{
|
||||||
|
"#define someStuff(param1) Hello param1 World",
|
||||||
|
"someStuff(A sentence with [brackets and a , character and stuff)",
|
||||||
|
"someStuff(A sentence with {braces and a , character and stuff)",
|
||||||
|
};
|
||||||
|
|
||||||
|
MockParserLineStream mockStream(lines);
|
||||||
|
DefinesStreamProxy proxy(&mockStream);
|
||||||
|
|
||||||
|
ExpectLine(&proxy, 1, "");
|
||||||
|
ExpectErrorInLine(&proxy, 2, 64);
|
||||||
|
ExpectErrorInLine(&proxy, 3, 62);
|
||||||
|
|
||||||
|
REQUIRE(proxy.Eof());
|
||||||
|
}
|
||||||
|
|
||||||
|
TEST_CASE("DefinesStreamProxy: Ensure throws error on parenthesis in params closed with wrong equivalent", "[parsing][parsingstream]")
|
||||||
|
{
|
||||||
|
const std::vector<std::string> lines{
|
||||||
|
"#define someStuff(param1) Hello param1 World",
|
||||||
|
"someStuff(A sentence with (parenthesis and a , character] and stuff)",
|
||||||
|
"someStuff(A sentence with [brackets and a , character} and stuff)",
|
||||||
|
"someStuff(A sentence with {braces and a , character) and stuff)",
|
||||||
|
};
|
||||||
|
|
||||||
|
MockParserLineStream mockStream(lines);
|
||||||
|
DefinesStreamProxy proxy(&mockStream);
|
||||||
|
|
||||||
|
ExpectLine(&proxy, 1, "");
|
||||||
|
ExpectErrorInLine(&proxy, 2, 57);
|
||||||
|
ExpectErrorInLine(&proxy, 3, 54);
|
||||||
|
ExpectErrorInLine(&proxy, 4, 52);
|
||||||
|
|
||||||
|
REQUIRE(proxy.Eof());
|
||||||
|
}
|
||||||
|
|
||||||
TEST_CASE("DefinesStreamProxy: Ensure defines can go over multiple lines", "[parsing][parsingstream]")
|
TEST_CASE("DefinesStreamProxy: Ensure defines can go over multiple lines", "[parsing][parsingstream]")
|
||||||
{
|
{
|
||||||
const std::vector<std::string> lines{"#define someStuff(param1) Hello param1 World \\", "and hello universe", "someStuff(lovely)"};
|
const std::vector<std::string> lines{
|
||||||
|
"#define someStuff(param1) Hello param1 World \\",
|
||||||
|
"and hello universe",
|
||||||
|
"someStuff(lovely)",
|
||||||
|
};
|
||||||
|
|
||||||
MockParserLineStream mockStream(lines);
|
MockParserLineStream mockStream(lines);
|
||||||
DefinesStreamProxy proxy(&mockStream);
|
DefinesStreamProxy proxy(&mockStream);
|
||||||
@ -596,4 +784,120 @@ namespace test::parsing::impl::defines_stream_proxy
|
|||||||
|
|
||||||
REQUIRE(proxy.Eof());
|
REQUIRE(proxy.Eof());
|
||||||
}
|
}
|
||||||
|
|
||||||
|
TEST_CASE("DefinesStreamProxy: Macro definition can span multiple lines when used with backslash", "[parsing][parsingstream]")
|
||||||
|
{
|
||||||
|
const std::vector<std::string> lines{
|
||||||
|
"#define testMacro( \\",
|
||||||
|
" a, \\",
|
||||||
|
" b, \\",
|
||||||
|
" c) a + b - c",
|
||||||
|
"testMacro(1, 2, 3)",
|
||||||
|
};
|
||||||
|
|
||||||
|
MockParserLineStream mockStream(lines);
|
||||||
|
DefinesStreamProxy proxy(&mockStream);
|
||||||
|
|
||||||
|
ExpectLine(&proxy, 1, "");
|
||||||
|
ExpectLine(&proxy, 2, "");
|
||||||
|
ExpectLine(&proxy, 3, "");
|
||||||
|
ExpectLine(&proxy, 4, "");
|
||||||
|
ExpectLine(&proxy, 5, "1 + 2 - 3");
|
||||||
|
|
||||||
|
REQUIRE(proxy.Eof());
|
||||||
|
}
|
||||||
|
|
||||||
|
TEST_CASE("DefinesStreamProxy: Macro definition that has unclosed parameters throws an error", "[parsing][parsingstream]")
|
||||||
|
{
|
||||||
|
const std::vector<std::string> lines{
|
||||||
|
"#define testMacro(",
|
||||||
|
" a,",
|
||||||
|
" b,",
|
||||||
|
" c) a + b - c",
|
||||||
|
"testMacro(1, 2, 3)",
|
||||||
|
};
|
||||||
|
|
||||||
|
MockParserLineStream mockStream(lines);
|
||||||
|
DefinesStreamProxy proxy(&mockStream);
|
||||||
|
|
||||||
|
ExpectErrorInLine(&proxy, 1, 19);
|
||||||
|
}
|
||||||
|
|
||||||
|
TEST_CASE("DefinesStreamProxy: Macro usages can span multiple lines if they have args", "[parsing][parsingstream]")
|
||||||
|
{
|
||||||
|
const std::vector<std::string> lines{
|
||||||
|
"#define testMacro(a, b, c) Hello a, this is b. Lets meet at c!",
|
||||||
|
"testMacro(",
|
||||||
|
"Peter,",
|
||||||
|
"Anna,",
|
||||||
|
"the cinema",
|
||||||
|
")",
|
||||||
|
};
|
||||||
|
|
||||||
|
MockParserLineStream mockStream(lines);
|
||||||
|
DefinesStreamProxy proxy(&mockStream);
|
||||||
|
|
||||||
|
ExpectLine(&proxy, 1, "");
|
||||||
|
ExpectLine(&proxy, 2, "");
|
||||||
|
ExpectLine(&proxy, 3, "");
|
||||||
|
ExpectLine(&proxy, 4, "");
|
||||||
|
ExpectLine(&proxy, 5, "");
|
||||||
|
ExpectLine(&proxy, 6, "Hello Peter, this is Anna. Lets meet at the cinema!");
|
||||||
|
|
||||||
|
REQUIRE(proxy.Eof());
|
||||||
|
}
|
||||||
|
|
||||||
|
TEST_CASE("DefinesStreamProxy: Can use second macro after multi-line macro", "[parsing][parsingstream]")
|
||||||
|
{
|
||||||
|
const std::vector<std::string> lines{
|
||||||
|
"#define LOL HAHA",
|
||||||
|
"#define testMacro(a, b) a likes b",
|
||||||
|
"testMacro(",
|
||||||
|
"Peter,",
|
||||||
|
"Anna",
|
||||||
|
") LOL funny",
|
||||||
|
};
|
||||||
|
|
||||||
|
MockParserLineStream mockStream(lines);
|
||||||
|
DefinesStreamProxy proxy(&mockStream);
|
||||||
|
|
||||||
|
ExpectLine(&proxy, 1, "");
|
||||||
|
ExpectLine(&proxy, 2, "");
|
||||||
|
ExpectLine(&proxy, 3, "");
|
||||||
|
ExpectLine(&proxy, 4, "");
|
||||||
|
ExpectLine(&proxy, 5, "");
|
||||||
|
ExpectLine(&proxy, 6, "Peter likes Anna HAHA funny");
|
||||||
|
|
||||||
|
REQUIRE(proxy.Eof());
|
||||||
|
}
|
||||||
|
|
||||||
|
TEST_CASE("DefinesStreamProxy: Can use second multi-line macro after multi-line macro", "[parsing][parsingstream]")
|
||||||
|
{
|
||||||
|
const std::vector<std::string> lines{
|
||||||
|
"#define LOL HAHA",
|
||||||
|
"#define testMacro(a, b) a likes b",
|
||||||
|
"testMacro(",
|
||||||
|
"Peter,",
|
||||||
|
"Anna",
|
||||||
|
") and testMacro(",
|
||||||
|
"Anna,",
|
||||||
|
"Peter",
|
||||||
|
")",
|
||||||
|
};
|
||||||
|
|
||||||
|
MockParserLineStream mockStream(lines);
|
||||||
|
DefinesStreamProxy proxy(&mockStream);
|
||||||
|
|
||||||
|
ExpectLine(&proxy, 1, "");
|
||||||
|
ExpectLine(&proxy, 2, "");
|
||||||
|
ExpectLine(&proxy, 3, "");
|
||||||
|
ExpectLine(&proxy, 4, "");
|
||||||
|
ExpectLine(&proxy, 5, "");
|
||||||
|
ExpectLine(&proxy, 6, "Peter likes Anna and ");
|
||||||
|
ExpectLine(&proxy, 7, "");
|
||||||
|
ExpectLine(&proxy, 8, "");
|
||||||
|
ExpectLine(&proxy, 9, "Anna likes Peter");
|
||||||
|
|
||||||
|
REQUIRE(proxy.Eof());
|
||||||
|
}
|
||||||
} // namespace test::parsing::impl::defines_stream_proxy
|
} // namespace test::parsing::impl::defines_stream_proxy
|
||||||
|
Loading…
x
Reference in New Issue
Block a user