Add Tests for ZCG cpp

This commit is contained in:
Jan
2021-02-10 18:03:50 +01:00
parent 31497d804c
commit f9ef7cc35b
102 changed files with 502 additions and 21 deletions

View File

@ -0,0 +1,74 @@
#include "CommentRemovingStreamProxy.h"
CommentRemovingStreamProxy::CommentRemovingStreamProxy(IParserLineStream* stream)
: m_stream(stream),
m_inside_multi_line_comment(false),
m_next_line_is_comment(false)
{
}
ParserLine CommentRemovingStreamProxy::NextLine()
{
auto line = m_stream->NextLine();
if (m_next_line_is_comment)
{
m_next_line_is_comment = !line.m_line.empty() && line.m_line[line.m_line.size() - 1] == '\\';
return ParserLine(line.m_filename, line.m_line_number, std::string());
}
unsigned multiLineCommentStart = 0;
for (auto i = 0u; i < line.m_line.size(); i++)
{
const auto c = line.m_line[i];
if (m_inside_multi_line_comment)
{
if (c == '*' && i + 1 < line.m_line.size() && line.m_line[i + 1] == '/')
{
line.m_line.erase(multiLineCommentStart, i + 2 - multiLineCommentStart);
multiLineCommentStart = 0;
m_inside_multi_line_comment = false;
}
}
else
{
if(c == '/' && i + 1 < line.m_line.size())
{
const auto c1 = line.m_line[i + 1];
if (c1 == '*')
{
multiLineCommentStart = i;
m_inside_multi_line_comment = true;
}
else if(c1 == '/')
{
m_next_line_is_comment = line.m_line[line.m_line.size() - 1] == '\\';
line.m_line.erase(i);
return line;
}
}
}
}
if(m_inside_multi_line_comment)
line.m_line.erase(multiLineCommentStart);
return line;
}
bool CommentRemovingStreamProxy::IncludeFile(const std::string& filename)
{
return m_stream->IncludeFile(filename);
}
bool CommentRemovingStreamProxy::IsOpen() const
{
return m_stream->IsOpen();
}
bool CommentRemovingStreamProxy::Eof() const
{
return m_stream->Eof();
}

View File

@ -0,0 +1,18 @@
#pragma once
#include "Parsing/IParserLineStream.h"
class CommentRemovingStreamProxy final : public IParserLineStream
{
IParserLineStream* const m_stream;
bool m_inside_multi_line_comment;
bool m_next_line_is_comment;
public:
explicit CommentRemovingStreamProxy(IParserLineStream* stream);
ParserLine NextLine() override;
bool IncludeFile(const std::string& filename) override;
_NODISCARD bool IsOpen() const override;
_NODISCARD bool Eof() const override;
};

View File

@ -0,0 +1,125 @@
#include "IncludingStreamProxy.h"
#include <sstream>
#include "Parsing/ParsingException.h"
IncludingStreamProxy::IncludingStreamProxy(IParserLineStream* stream)
: m_stream(stream)
{
}
bool IncludingStreamProxy::FindIncludeDirective(const ParserLine& line, unsigned& includeDirectivePosition)
{
includeDirectivePosition = 0;
for (; includeDirectivePosition < line.m_line.size() - INCLUDE_DIRECTIVE_MINIMUM_TOTAL_LENGTH; includeDirectivePosition++)
{
const auto c = line.m_line[includeDirectivePosition];
if (isspace(c))
continue;
if (c != '#')
return false;
if (line.m_line.compare(includeDirectivePosition + 1, INCLUDE_DIRECTIVE_LENGTH, INCLUDE_DIRECTIVE) != 0)
{
return false;
}
return true;
}
return false;
}
bool IncludingStreamProxy::ExtractIncludeFilename(const ParserLine& line, const unsigned includeDirectivePosition, unsigned& filenameStartPosition, unsigned& filenameEndPosition)
{
auto currentPos = includeDirectivePosition;
bool isDoubleQuotes;
if (line.m_line[currentPos] == '"')
isDoubleQuotes = true;
else if (line.m_line[currentPos] == '<')
isDoubleQuotes = false;
else
throw ParsingException(TokenPos(line.m_filename, line.m_line_number, currentPos), INCLUDE_QUOTES_ERROR);
filenameStartPosition = ++currentPos;
filenameEndPosition = 0;
for (; currentPos < line.m_line.size(); currentPos++)
{
const auto c = line.m_line[currentPos];
if (c == '"')
{
if (!isDoubleQuotes)
throw ParsingException(TokenPos(line.m_filename, line.m_line_number, currentPos), "");
filenameEndPosition = currentPos;
return true;
}
if (c == '>')
{
if (isDoubleQuotes)
throw ParsingException(TokenPos(line.m_filename, line.m_line_number, currentPos), INCLUDE_QUOTES_ERROR);
filenameEndPosition = currentPos;
return true;
}
}
return false;
}
bool IncludingStreamProxy::MatchIncludeDirective(const ParserLine& line) const
{
unsigned includeDirectivePos;
if (!FindIncludeDirective(line, includeDirectivePos))
return false;
const auto currentPos = includeDirectivePos + INCLUDE_DIRECTIVE_LENGTH + 1;
unsigned filenameStart, filenameEnd;
if(!ExtractIncludeFilename(line, currentPos, filenameStart, filenameEnd))
throw ParsingException(TokenPos(line.m_filename, line.m_line_number, currentPos), INCLUDE_QUOTES_ERROR);
if(filenameEnd <= filenameStart)
throw ParsingException(TokenPos(line.m_filename, line.m_line_number, currentPos), "No filename specified");
const auto filename = line.m_line.substr(filenameStart, filenameEnd - filenameStart);
if(!m_stream->IncludeFile(filename))
{
std::ostringstream errorStr;
errorStr << "Could not include file \"" << filename << "\"";
throw ParsingException(TokenPos(line.m_filename, line.m_line_number, currentPos), errorStr.str());
}
return true;
}
ParserLine IncludingStreamProxy::NextLine()
{
auto line = m_stream->NextLine();
if (MatchIncludeDirective(line))
return m_stream->NextLine();
return line;
}
bool IncludingStreamProxy::IncludeFile(const std::string& filename)
{
return m_stream->IncludeFile(filename);
}
bool IncludingStreamProxy::IsOpen() const
{
return m_stream->IsOpen();
}
bool IncludingStreamProxy::Eof() const
{
return m_stream->Eof();
}

View File

@ -0,0 +1,25 @@
#pragma once
#include "Parsing/IParserLineStream.h"
class IncludingStreamProxy final : public IParserLineStream
{
static constexpr const char* INCLUDE_QUOTES_ERROR = "Invalid include directive. Expected \"\" or <>";
static constexpr const char* INCLUDE_DIRECTIVE = "include ";
static constexpr int INCLUDE_DIRECTIVE_LENGTH = std::char_traits<char>::length(INCLUDE_DIRECTIVE);
static constexpr int INCLUDE_DIRECTIVE_MINIMUM_TOTAL_LENGTH = INCLUDE_DIRECTIVE_LENGTH + 1 + 2; // #=+1 ""=+2
IParserLineStream* const m_stream;
_NODISCARD static bool FindIncludeDirective(const ParserLine& line, unsigned& includeDirectivePosition);
_NODISCARD static bool ExtractIncludeFilename(const ParserLine& line, unsigned includeDirectivePosition, unsigned& filenameStartPosition, unsigned& filenameEndPosition);
_NODISCARD bool MatchIncludeDirective(const ParserLine& line) const;
public:
explicit IncludingStreamProxy(IParserLineStream* stream);
ParserLine NextLine() override;
bool IncludeFile(const std::string& filename) override;
_NODISCARD bool IsOpen() const override;
_NODISCARD bool Eof() const override;
};

View File

@ -0,0 +1,94 @@
#include "ParserFilesystemStream.h"
#include <sstream>
#include <filesystem>
namespace fs = std::filesystem;
const std::string ParserFilesystemStream::EMPTY_FILE_NAME;
ParserFilesystemStream::FileInfo::FileInfo(std::string filePath)
: m_file_path(std::move(filePath)),
m_stream(m_file_path),
m_line_number(1)
{
}
ParserFilesystemStream::ParserFilesystemStream(std::string path)
{
m_files.emplace(FileInfo(std::move(path)));
}
bool ParserFilesystemStream::IsOpen() const
{
return !m_files.empty()
&& m_files.top().m_stream.is_open();
}
ParserLine ParserFilesystemStream::NextLine()
{
std::ostringstream str;
auto hasLength = false;
if (m_files.empty())
return ParserLine(EMPTY_FILE_NAME, 0, std::string());
while(!m_files.empty())
{
auto& fileInfo = m_files.top();
auto c = fileInfo.m_stream.get();
while (c != EOF)
{
switch (c)
{
case '\r':
c = fileInfo.m_stream.get();
if (c == '\n')
return ParserLine(fileInfo.m_file_path, fileInfo.m_line_number++, str.str());
str << '\r';
hasLength = true;
continue;
case '\n':
return ParserLine(fileInfo.m_file_path, fileInfo.m_line_number++, str.str());
default:
str << static_cast<char>(c);
hasLength = true;
break;
}
c = fileInfo.m_stream.get();
}
if(hasLength)
return ParserLine(fileInfo.m_file_path, fileInfo.m_line_number, str.str());
m_files.pop();
}
return ParserLine(EMPTY_FILE_NAME, 0, std::string());
}
bool ParserFilesystemStream::IncludeFile(const std::string& filename)
{
if (m_files.empty())
return false;
auto newFilePath = fs::path(m_files.top().m_file_path);
newFilePath.remove_filename().concat(filename);
FileInfo fileInfo(newFilePath.string());
if (!fileInfo.m_stream.is_open())
return false;
m_files.emplace(std::move(fileInfo));
return true;
}
bool ParserFilesystemStream::Eof() const
{
return m_files.empty()
|| m_files.top().m_stream.eof();
}

View File

@ -0,0 +1,30 @@
#pragma once
#include <stack>
#include <fstream>
#include "Parsing/IParserLineStream.h"
class ParserFilesystemStream final : public IParserLineStream
{
static const std::string EMPTY_FILE_NAME;
class FileInfo
{
public:
std::string m_file_path;
std::ifstream m_stream;
int m_line_number;
explicit FileInfo(std::string filePath);
};
std::stack<FileInfo> m_files;
public:
explicit ParserFilesystemStream(std::string path);
ParserLine NextLine() override;
bool IncludeFile(const std::string& filename) override;
_NODISCARD bool IsOpen() const override;
_NODISCARD bool Eof() const override;
};