mirror of
https://github.com/Laupetin/OpenAssetTools.git
synced 2025-04-19 15:52:53 +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
|
||||
working-directory: ${{ github.workspace }}/build/lib/Release_x86/tests
|
||||
run: |
|
||||
$combinedExitCode = 0
|
||||
./ObjCommonTests
|
||||
$combinedExitCode = [System.Math]::max($combinedExitCode, $LASTEXITCODE)
|
||||
./ObjLoadingTests
|
||||
$combinedExitCode = [System.Math]::max($combinedExitCode, $LASTEXITCODE)
|
||||
./ParserTests
|
||||
$combinedExitCode = [System.Math]::max($combinedExitCode, $LASTEXITCODE)
|
||||
./ZoneCodeGeneratorLibTests
|
||||
$combinedExitCode = [System.Math]::max($combinedExitCode, $LASTEXITCODE)
|
||||
./ZoneCommonTests
|
||||
$combinedExitCode = [System.Math]::max($combinedExitCode, $LASTEXITCODE)
|
||||
exit $combinedExitCode
|
||||
- name: Upload artifacts
|
||||
uses: actions/upload-artifact@v4
|
||||
with:
|
||||
|
@ -123,7 +123,10 @@ DefinesStreamProxy::DefinesStreamProxy(IParserLineStream* stream, const bool ski
|
||||
: m_stream(stream),
|
||||
m_skip_directive_lines(skipDirectiveLines),
|
||||
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;
|
||||
}
|
||||
|
||||
void DefinesStreamProxy::ContinueDefine(const ParserLine& line)
|
||||
void DefinesStreamProxy::ContinueDefine(const ParserLine& line, const unsigned currentPos)
|
||||
{
|
||||
const auto lineEndEscapePos = GetLineEndEscapePos(line);
|
||||
if (lineEndEscapePos < 0)
|
||||
{
|
||||
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.IdentifyParameters(m_current_define_parameters);
|
||||
AddDefine(std::move(m_current_define));
|
||||
@ -159,49 +169,58 @@ void DefinesStreamProxy::ContinueDefine(const ParserLine& line)
|
||||
}
|
||||
else
|
||||
{
|
||||
if (line.m_line.size() > static_cast<unsigned>(lineEndEscapePos))
|
||||
m_current_define_value << line.m_line.substr(0, 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(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] != '(')
|
||||
return std::vector<std::string>();
|
||||
|
||||
parameterPosition++;
|
||||
std::vector<std::string> parameters;
|
||||
|
||||
const auto lineEndEscapePos = GetLineEndEscapePos(line);
|
||||
while (true)
|
||||
{
|
||||
if (!SkipWhitespace(line, parameterPosition) || parameterPosition >= line.m_line.size())
|
||||
throw ParsingException(CreatePos(line, parameterPosition), "Invalid define parameter list");
|
||||
if (!SkipWhitespace(line, currentPos))
|
||||
throw ParsingException(CreatePos(line, currentPos), "Invalid define parameter list");
|
||||
|
||||
const auto nameStartPos = parameterPosition;
|
||||
if (!ExtractIdentifier(line, parameterPosition))
|
||||
throw ParsingException(CreatePos(line, parameterPosition), "Cannot extract name of parameter of define");
|
||||
if (lineEndEscapePos >= 0 && currentPos >= static_cast<unsigned>(lineEndEscapePos))
|
||||
return;
|
||||
|
||||
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))
|
||||
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] == ')')
|
||||
if ((m_parameter_state == ParameterState::AFTER_OPEN || m_parameter_state == ParameterState::AFTER_PARAM) && line.m_line[currentPos] == ')')
|
||||
{
|
||||
parameterPosition++;
|
||||
break;
|
||||
currentPos++;
|
||||
m_parameter_state = ParameterState::NOT_IN_PARAMETERS;
|
||||
return;
|
||||
}
|
||||
|
||||
if (line.m_line[parameterPosition] != ',')
|
||||
throw ParsingException(CreatePos(line, parameterPosition), "Unknown symbol in define parameter list");
|
||||
|
||||
parameterPosition++;
|
||||
if (m_parameter_state == ParameterState::AFTER_PARAM && line.m_line[currentPos] == ',')
|
||||
{
|
||||
currentPos++;
|
||||
m_parameter_state = ParameterState::AFTER_COMMA;
|
||||
continue;
|
||||
}
|
||||
|
||||
return parameters;
|
||||
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;
|
||||
}
|
||||
}
|
||||
|
||||
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)
|
||||
@ -223,29 +242,14 @@ bool DefinesStreamProxy::MatchDefineDirective(const ParserLine& line, const unsi
|
||||
|
||||
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);
|
||||
if (lineEndEscapePos < 0)
|
||||
{
|
||||
std::string value;
|
||||
if (currentPos < line.m_line.size())
|
||||
value = line.m_line.substr(currentPos + 1);
|
||||
|
||||
Define define(name, value);
|
||||
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));
|
||||
}
|
||||
ContinueDefine(line, currentPos);
|
||||
|
||||
return true;
|
||||
}
|
||||
@ -276,8 +280,7 @@ bool DefinesStreamProxy::MatchUndefDirective(const ParserLine& line, const unsig
|
||||
return true;
|
||||
}
|
||||
|
||||
std::unique_ptr<ISimpleExpression>
|
||||
DefinesStreamProxy::ParseExpression(std::shared_ptr<std::string> fileName, int lineNumber, std::string expressionString) const
|
||||
std::unique_ptr<ISimpleExpression> DefinesStreamProxy::ParseExpression(std::shared_ptr<std::string> fileName, int lineNumber, std::string expressionString)
|
||||
{
|
||||
ParserLine pseudoLine(std::move(fileName), lineNumber, std::move(expressionString));
|
||||
ExpandDefinedExpressions(pseudoLine);
|
||||
@ -451,7 +454,7 @@ bool DefinesStreamProxy::MatchEndifDirective(const ParserLine& line, const unsig
|
||||
return true;
|
||||
}
|
||||
|
||||
bool DefinesStreamProxy::MatchDirectives(const ParserLine& line)
|
||||
bool DefinesStreamProxy::MatchDirectives(ParserLine& line)
|
||||
{
|
||||
unsigned directiveStartPos;
|
||||
unsigned directiveEndPos;
|
||||
@ -472,9 +475,9 @@ bool DefinesStreamProxy::MatchDirectives(const ParserLine& line)
|
||||
|| 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);
|
||||
if (foundEntry != m_defines.end())
|
||||
{
|
||||
@ -485,71 +488,122 @@ bool DefinesStreamProxy::FindDefineForWord(const ParserLine& line, const unsigne
|
||||
return false;
|
||||
}
|
||||
|
||||
void DefinesStreamProxy::ExtractParametersFromDefineUsage(const ParserLine& line,
|
||||
const unsigned parameterStart,
|
||||
unsigned& parameterEnd,
|
||||
std::vector<std::string>& parameterValues)
|
||||
void DefinesStreamProxy::ContinueMacroParameters(const ParserLine& line, unsigned& pos)
|
||||
{
|
||||
if (line.m_line[parameterStart] != '(')
|
||||
return;
|
||||
|
||||
std::ostringstream currentValue;
|
||||
auto pos = parameterStart + 1;
|
||||
auto valueHasStarted = false;
|
||||
auto parenthesisDepth = 0;
|
||||
while (true)
|
||||
const auto lineLength = line.m_line.size();
|
||||
while (m_macro_parameter_state != ParameterState::NOT_IN_PARAMETERS && pos < lineLength)
|
||||
{
|
||||
if (pos >= line.m_line.size())
|
||||
throw ParsingException(CreatePos(line, pos), "Invalid use of define");
|
||||
|
||||
const auto c = line.m_line[pos];
|
||||
|
||||
if (c == ',')
|
||||
{
|
||||
if (parenthesisDepth > 0)
|
||||
if (!m_macro_bracket_depth.empty())
|
||||
{
|
||||
valueHasStarted = true;
|
||||
currentValue << c;
|
||||
m_macro_parameter_state = ParameterState::AFTER_PARAM;
|
||||
m_current_macro_parameter << c;
|
||||
}
|
||||
else
|
||||
{
|
||||
parameterValues.emplace_back(currentValue.str());
|
||||
currentValue.clear();
|
||||
currentValue.str(std::string());
|
||||
valueHasStarted = false;
|
||||
m_macro_parameters.emplace_back(m_current_macro_parameter.str());
|
||||
m_current_macro_parameter.clear();
|
||||
m_current_macro_parameter.str(std::string());
|
||||
m_macro_parameter_state = ParameterState::AFTER_COMMA;
|
||||
}
|
||||
}
|
||||
else if (c == '(')
|
||||
else if (c == '(' || c == '[' || c == '{')
|
||||
{
|
||||
valueHasStarted = true;
|
||||
parenthesisDepth++;
|
||||
currentValue << c;
|
||||
m_macro_parameter_state = ParameterState::AFTER_PARAM;
|
||||
m_macro_bracket_depth.push(c);
|
||||
m_current_macro_parameter << c;
|
||||
}
|
||||
else if (c == ')')
|
||||
{
|
||||
if (parenthesisDepth > 0)
|
||||
if (!m_macro_bracket_depth.empty())
|
||||
{
|
||||
valueHasStarted = true;
|
||||
parenthesisDepth--;
|
||||
currentValue << c;
|
||||
if (m_macro_bracket_depth.top() != '(')
|
||||
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_COMMA)
|
||||
{
|
||||
throw ParsingException(CreatePos(line, pos), "Cannot close macro parameters after comma");
|
||||
}
|
||||
else
|
||||
{
|
||||
parameterValues.emplace_back(currentValue.str());
|
||||
parameterEnd = pos + 1;
|
||||
break;
|
||||
m_macro_parameters.emplace_back(m_current_macro_parameter.str());
|
||||
m_macro_parameter_state = ParameterState::NOT_IN_PARAMETERS;
|
||||
}
|
||||
}
|
||||
else if (valueHasStarted || !isspace(c))
|
||||
else if (c == ']' || c == '}')
|
||||
{
|
||||
valueHasStarted = true;
|
||||
currentValue << c;
|
||||
if (!m_macro_bracket_depth.empty())
|
||||
{
|
||||
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++;
|
||||
}
|
||||
}
|
||||
|
||||
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)
|
||||
{
|
||||
unsigned currentPos = pos;
|
||||
@ -601,33 +655,32 @@ void DefinesStreamProxy::ExpandDefinedExpressions(ParserLine& line) const
|
||||
}
|
||||
}
|
||||
|
||||
void DefinesStreamProxy::ExpandDefines(ParserLine& line) const
|
||||
void DefinesStreamProxy::ProcessDefine(const ParserLine& line, unsigned& pos, std::ostringstream& out)
|
||||
{
|
||||
bool usesDefines;
|
||||
auto defineIterations = 0u;
|
||||
ExtractParametersFromDefineUsage(line, pos, pos);
|
||||
|
||||
do
|
||||
if (m_macro_parameter_state == ParameterState::NOT_IN_PARAMETERS)
|
||||
{
|
||||
if (defineIterations > MAX_DEFINE_ITERATIONS)
|
||||
throw ParsingException(CreatePos(line, 1),
|
||||
"Potential define loop? Exceeded max define iterations of " + std::to_string(MAX_DEFINE_ITERATIONS) + " iterations.");
|
||||
|
||||
usesDefines = false;
|
||||
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;
|
||||
const Define* value;
|
||||
std::ostringstream str;
|
||||
|
||||
for (auto i = 0u; i < line.m_line.size(); i++)
|
||||
for (; pos < lineSize; pos++)
|
||||
{
|
||||
const auto c = line.m_line[i];
|
||||
const auto c = line[pos];
|
||||
if (!inWord)
|
||||
{
|
||||
if (isalpha(c) || c == '_')
|
||||
{
|
||||
wordStart = i;
|
||||
wordStart = pos;
|
||||
inWord = true;
|
||||
}
|
||||
}
|
||||
@ -635,23 +688,12 @@ void DefinesStreamProxy::ExpandDefines(ParserLine& line) const
|
||||
{
|
||||
if (!isalnum(c) && c != '_')
|
||||
{
|
||||
if (FindDefineForWord(line, wordStart, i, value))
|
||||
if (FindDefineForWord(line, wordStart, pos, define))
|
||||
{
|
||||
std::vector<std::string> parameterValues;
|
||||
ExtractParametersFromDefineUsage(line, i, i, parameterValues);
|
||||
const auto defineValue = value->Render(parameterValues);
|
||||
defineStart = wordStart;
|
||||
return true;
|
||||
}
|
||||
|
||||
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;
|
||||
}
|
||||
}
|
||||
@ -659,28 +701,56 @@ void DefinesStreamProxy::ExpandDefines(ParserLine& line) const
|
||||
|
||||
if (inWord)
|
||||
{
|
||||
if (FindDefineForWord(line, wordStart, line.m_line.size(), value))
|
||||
if (FindDefineForWord(line, wordStart, pos, define))
|
||||
{
|
||||
const std::vector<std::string> parameterValues;
|
||||
const auto defineValue = value->Render(parameterValues);
|
||||
defineStart = wordStart;
|
||||
return true;
|
||||
}
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
void DefinesStreamProxy::ExpandDefines(ParserLine& line)
|
||||
{
|
||||
auto defineIterations = 0u;
|
||||
bool usesDefines;
|
||||
|
||||
do
|
||||
{
|
||||
if (defineIterations > MAX_DEFINE_ITERATIONS)
|
||||
{
|
||||
throw ParsingException(CreatePos(line, 1),
|
||||
"Potential define loop? Exceeded max define iterations of " + std::to_string(MAX_DEFINE_ITERATIONS) + " iterations.");
|
||||
}
|
||||
|
||||
usesDefines = false;
|
||||
auto pos = 0u;
|
||||
auto defineStart = 0u;
|
||||
auto lastDefineEnd = 0u;
|
||||
std::ostringstream str;
|
||||
|
||||
while (FindNextDefine(line.m_line, pos, defineStart, m_current_macro))
|
||||
{
|
||||
if (!usesDefines)
|
||||
{
|
||||
str << std::string(line.m_line, 0, wordStart) << defineValue;
|
||||
usesDefines = true;
|
||||
str << std::string(line.m_line, 0, defineStart);
|
||||
}
|
||||
else
|
||||
{
|
||||
str << std::string(line.m_line, lastWordEnd, wordStart - lastWordEnd) << defineValue;
|
||||
}
|
||||
lastWordEnd = line.m_line.size();
|
||||
str << std::string(line.m_line, lastDefineEnd, defineStart - (lastDefineEnd));
|
||||
}
|
||||
|
||||
ProcessDefine(line, pos, str);
|
||||
|
||||
lastDefineEnd = pos;
|
||||
}
|
||||
|
||||
if (usesDefines)
|
||||
{
|
||||
if (lastWordEnd < line.m_line.size())
|
||||
str << std::string(line.m_line, lastWordEnd, line.m_line.size() - lastWordEnd);
|
||||
if (lastDefineEnd < line.m_line.size())
|
||||
str << std::string(line.m_line, lastDefineEnd, line.m_line.size() - lastDefineEnd);
|
||||
line.m_line = str.str();
|
||||
}
|
||||
|
||||
@ -709,7 +779,15 @@ ParserLine DefinesStreamProxy::NextLine()
|
||||
{
|
||||
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)
|
||||
{
|
||||
line.m_line = std::string();
|
||||
@ -718,6 +796,11 @@ ParserLine DefinesStreamProxy::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)
|
||||
{
|
||||
if (!m_skip_directive_lines)
|
||||
|
@ -47,13 +47,21 @@ public:
|
||||
};
|
||||
|
||||
private:
|
||||
enum class BlockMode
|
||||
enum class BlockMode : uint8_t
|
||||
{
|
||||
NOT_IN_BLOCK,
|
||||
IN_BLOCK,
|
||||
BLOCK_BLOCKED
|
||||
};
|
||||
|
||||
enum class ParameterState : uint8_t
|
||||
{
|
||||
NOT_IN_PARAMETERS,
|
||||
AFTER_OPEN,
|
||||
AFTER_PARAM,
|
||||
AFTER_COMMA
|
||||
};
|
||||
|
||||
IParserLineStream* const m_stream;
|
||||
const bool m_skip_directive_lines;
|
||||
std::map<std::string, Define> m_defines;
|
||||
@ -61,13 +69,21 @@ private:
|
||||
unsigned m_ignore_depth;
|
||||
|
||||
bool m_in_define;
|
||||
ParameterState m_parameter_state;
|
||||
Define m_current_define;
|
||||
std::ostringstream m_current_define_value;
|
||||
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 std::vector<std::string> MatchDefineParameters(const ParserLine& line, unsigned& parameterPosition);
|
||||
void ContinueDefine(const ParserLine& line);
|
||||
void MatchDefineParameters(const ParserLine& line, unsigned& currentPos);
|
||||
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 MatchUndefDirective(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 MatchElseDirective(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
|
||||
ExtractParametersFromDefineUsage(const ParserLine& line, unsigned parameterStart, unsigned& parameterEnd, std::vector<std::string>& parameterValues);
|
||||
bool FindDefineForWord(const ParserLine& line, unsigned wordStart, unsigned wordEnd, const Define*& value) const;
|
||||
void ExtractParametersFromDefineUsage(const ParserLine& line, unsigned parameterStart, unsigned& parameterEnd);
|
||||
bool FindDefineForWord(const std::string& line, unsigned wordStart, unsigned wordEnd, const Define*& value) const;
|
||||
|
||||
static bool MatchDefinedExpression(const ParserLine& line, unsigned& pos, std::string& definitionName);
|
||||
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:
|
||||
explicit DefinesStreamProxy(IParserLineStream* stream, bool skipDirectiveLines = false);
|
||||
|
||||
void AddDefine(Define define);
|
||||
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;
|
||||
bool IncludeFile(const std::string& filename) override;
|
||||
|
@ -6,7 +6,7 @@
|
||||
#include <exception>
|
||||
#include <string>
|
||||
|
||||
class ParsingException final : std::exception
|
||||
class ParsingException final : public std::exception
|
||||
{
|
||||
TokenPos m_pos;
|
||||
std::string m_message;
|
||||
|
@ -1,8 +1,14 @@
|
||||
#include "Parsing/Impl/DefinesStreamProxy.h"
|
||||
#include "Parsing/Mock/MockParserLineStream.h"
|
||||
#include "Parsing/ParsingException.h"
|
||||
|
||||
#include <catch2/catch_test_macros.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
|
||||
{
|
||||
@ -13,9 +19,21 @@ namespace test::parsing::impl::defines_stream_proxy
|
||||
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]")
|
||||
{
|
||||
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);
|
||||
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]")
|
||||
{
|
||||
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);
|
||||
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]")
|
||||
{
|
||||
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);
|
||||
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]")
|
||||
{
|
||||
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);
|
||||
DefinesStreamProxy proxy(&mockStream);
|
||||
@ -79,7 +115,15 @@ namespace test::parsing::impl::defines_stream_proxy
|
||||
|
||||
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);
|
||||
DefinesStreamProxy proxy(&mockStream);
|
||||
@ -97,7 +141,8 @@ namespace test::parsing::impl::defines_stream_proxy
|
||||
|
||||
TEST_CASE("DefinesStreamProxy: Ensure nested ifdef is working", "[parsing][parsingstream]")
|
||||
{
|
||||
const std::vector<std::string> lines{"#define ASDF",
|
||||
const std::vector<std::string> lines{
|
||||
"#define ASDF",
|
||||
"#ifdef ASDF",
|
||||
"#ifdef NONO",
|
||||
"Hello World1",
|
||||
@ -111,7 +156,8 @@ namespace test::parsing::impl::defines_stream_proxy
|
||||
"Hello World4",
|
||||
"#endif",
|
||||
"#endif",
|
||||
"Hello Galaxy"};
|
||||
"Hello Galaxy",
|
||||
};
|
||||
|
||||
MockParserLineStream mockStream(lines);
|
||||
DefinesStreamProxy proxy(&mockStream);
|
||||
@ -138,7 +184,16 @@ namespace test::parsing::impl::defines_stream_proxy
|
||||
TEST_CASE("DefinesStreamProxy: Ensure undef is working", "[parsing][parsingstream]")
|
||||
{
|
||||
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);
|
||||
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]")
|
||||
{
|
||||
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);
|
||||
DefinesStreamProxy proxy(&mockStream);
|
||||
@ -179,7 +243,13 @@ namespace test::parsing::impl::defines_stream_proxy
|
||||
|
||||
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);
|
||||
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]")
|
||||
{
|
||||
const std::vector<std::string> lines{"#define ASDF LOL", "!ASDF%"};
|
||||
const std::vector<std::string> lines{
|
||||
"#define ASDF LOL",
|
||||
"!ASDF%",
|
||||
};
|
||||
|
||||
MockParserLineStream mockStream(lines);
|
||||
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]")
|
||||
{
|
||||
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);
|
||||
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]")
|
||||
{
|
||||
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);
|
||||
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]")
|
||||
{
|
||||
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);
|
||||
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]")
|
||||
{
|
||||
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);
|
||||
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]")
|
||||
{
|
||||
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);
|
||||
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]")
|
||||
{
|
||||
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);
|
||||
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]")
|
||||
{
|
||||
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);
|
||||
DefinesStreamProxy proxy(&mockStream);
|
||||
@ -327,7 +427,10 @@ namespace test::parsing::impl::defines_stream_proxy
|
||||
|
||||
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);
|
||||
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]")
|
||||
{
|
||||
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);
|
||||
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]")
|
||||
{
|
||||
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);
|
||||
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]")
|
||||
{
|
||||
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);
|
||||
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]")
|
||||
{
|
||||
const std::vector<std::string> lines{"#define someStuff(param1) Hello param1 World",
|
||||
"someStuff(A sentence with (parenthesis and a , character) and stuff)"};
|
||||
const std::vector<std::string> lines{
|
||||
"#define someStuff(param1) Hello param1 World",
|
||||
"someStuff(A sentence with (parenthesis and a , character) and stuff)",
|
||||
};
|
||||
|
||||
MockParserLineStream mockStream(lines);
|
||||
DefinesStreamProxy proxy(&mockStream);
|
||||
@ -583,9 +697,83 @@ namespace test::parsing::impl::defines_stream_proxy
|
||||
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]")
|
||||
{
|
||||
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);
|
||||
DefinesStreamProxy proxy(&mockStream);
|
||||
@ -596,4 +784,120 @@ namespace test::parsing::impl::defines_stream_proxy
|
||||
|
||||
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
|
||||
|
Loading…
x
Reference in New Issue
Block a user