Made Parser seekable for easier maintenance.
This commit is contained in:
		@@ -28,7 +28,7 @@ class Description
 | 
			
		||||
		const Domain &domain() const;
 | 
			
		||||
 | 
			
		||||
	private:
 | 
			
		||||
		Description(std::istream &istream);
 | 
			
		||||
		Description();
 | 
			
		||||
 | 
			
		||||
		void parseContent();
 | 
			
		||||
		void parseSection();
 | 
			
		||||
 
 | 
			
		||||
@@ -47,6 +47,8 @@ class Description
 | 
			
		||||
	private:
 | 
			
		||||
		Description();
 | 
			
		||||
 | 
			
		||||
		void parseContent(utils::Parser &parser);
 | 
			
		||||
 | 
			
		||||
		void parseVersionSection(utils::Parser &parser) const;
 | 
			
		||||
		void parseMetricSection(utils::Parser &parser);
 | 
			
		||||
		void parseVariablesSection(utils::Parser &parser);
 | 
			
		||||
 
 | 
			
		||||
@@ -23,7 +23,7 @@ class Logger
 | 
			
		||||
 | 
			
		||||
		void setPedantic(bool isPedantic = true);
 | 
			
		||||
 | 
			
		||||
		void parserWarning(const Parser &parser, const std::string &text);
 | 
			
		||||
		void parserWarning(const Parser &parser, const std::string &message);
 | 
			
		||||
 | 
			
		||||
	private:
 | 
			
		||||
		bool m_isPedantic;
 | 
			
		||||
 
 | 
			
		||||
@@ -3,8 +3,11 @@
 | 
			
		||||
 | 
			
		||||
#include <iostream>
 | 
			
		||||
#include <iterator>
 | 
			
		||||
#include <sstream>
 | 
			
		||||
#include <vector>
 | 
			
		||||
 | 
			
		||||
#include <boost/filesystem.hpp>
 | 
			
		||||
 | 
			
		||||
namespace plasp
 | 
			
		||||
{
 | 
			
		||||
namespace utils
 | 
			
		||||
@@ -19,22 +22,39 @@ namespace utils
 | 
			
		||||
class Parser
 | 
			
		||||
{
 | 
			
		||||
	public:
 | 
			
		||||
		explicit Parser(std::istream &istream);
 | 
			
		||||
		using Position = std::stringstream::pos_type;
 | 
			
		||||
 | 
			
		||||
		void setFileName(std::string fileName);
 | 
			
		||||
		const std::string &fileName() const;
 | 
			
		||||
		struct Coordinate
 | 
			
		||||
		{
 | 
			
		||||
			std::string sectionName;
 | 
			
		||||
			size_t row;
 | 
			
		||||
			size_t column;
 | 
			
		||||
		};
 | 
			
		||||
 | 
			
		||||
		void resetPosition();
 | 
			
		||||
		struct StreamDelimiter
 | 
			
		||||
		{
 | 
			
		||||
			Position position;
 | 
			
		||||
			std::string sectionName;
 | 
			
		||||
		};
 | 
			
		||||
 | 
			
		||||
		size_t row() const;
 | 
			
		||||
		size_t column() const;
 | 
			
		||||
	public:
 | 
			
		||||
		explicit Parser();
 | 
			
		||||
		explicit Parser(std::string streamName, std::istream &istream);
 | 
			
		||||
 | 
			
		||||
		void readStream(std::string streamName, std::istream &istream);
 | 
			
		||||
		void readFile(const boost::filesystem::path &path);
 | 
			
		||||
 | 
			
		||||
		void reset();
 | 
			
		||||
		void seek(Position position);
 | 
			
		||||
		Position position() const;
 | 
			
		||||
		Coordinate coordinate() const;
 | 
			
		||||
 | 
			
		||||
		void setCaseSensitive(bool isCaseInsensitive = true);
 | 
			
		||||
 | 
			
		||||
		char currentCharacter() const;
 | 
			
		||||
		void advance();
 | 
			
		||||
		bool advanceIf(char expectedCharacter);
 | 
			
		||||
		bool atEndOfFile() const;
 | 
			
		||||
		bool atEndOfStream() const;
 | 
			
		||||
 | 
			
		||||
		template<typename Type>
 | 
			
		||||
		Type parse();
 | 
			
		||||
@@ -64,16 +84,11 @@ class Parser
 | 
			
		||||
 | 
			
		||||
		uint64_t parseIntegerBody();
 | 
			
		||||
 | 
			
		||||
		std::istream &m_istream;
 | 
			
		||||
		std::string m_fileName;
 | 
			
		||||
		std::istreambuf_iterator<char> m_position;
 | 
			
		||||
		mutable std::stringstream m_stream;
 | 
			
		||||
 | 
			
		||||
		size_t m_row;
 | 
			
		||||
		size_t m_column;
 | 
			
		||||
		std::vector<StreamDelimiter> m_streamDelimiters;
 | 
			
		||||
 | 
			
		||||
		bool m_isCaseSensitive;
 | 
			
		||||
 | 
			
		||||
		bool m_atEndOfFile;
 | 
			
		||||
};
 | 
			
		||||
 | 
			
		||||
////////////////////////////////////////////////////////////////////////////////////////////////////
 | 
			
		||||
@@ -116,7 +131,7 @@ void Parser::skipWhiteSpace(WhiteSpacePredicate whiteSpacePredicate)
 | 
			
		||||
{
 | 
			
		||||
	checkStream();
 | 
			
		||||
 | 
			
		||||
	while (!atEndOfFile() && whiteSpacePredicate(currentCharacter()))
 | 
			
		||||
	while (!atEndOfStream() && whiteSpacePredicate(currentCharacter()))
 | 
			
		||||
		advance();
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
 
 | 
			
		||||
@@ -31,8 +31,10 @@ class ParserException: public std::exception
 | 
			
		||||
		}
 | 
			
		||||
 | 
			
		||||
		explicit ParserException(const utils::Parser &parser, const std::string &message)
 | 
			
		||||
		:	m_message{parser.fileName() + ":" + std::to_string(parser.row()) + ":" + std::to_string(parser.column()) + " " + message}
 | 
			
		||||
		{
 | 
			
		||||
			const auto coordinate = parser.coordinate();
 | 
			
		||||
 | 
			
		||||
			m_message = coordinate.sectionName + ":" + std::to_string(coordinate.row) + ":" + std::to_string(coordinate.column) + " " + message;
 | 
			
		||||
		}
 | 
			
		||||
 | 
			
		||||
		~ParserException() throw()
 | 
			
		||||
 
 | 
			
		||||
@@ -31,8 +31,10 @@ class ParserWarning: public std::exception
 | 
			
		||||
		}
 | 
			
		||||
 | 
			
		||||
		explicit ParserWarning(const utils::Parser &parser, const std::string &message)
 | 
			
		||||
		:	m_message{parser.fileName() + ":" + std::to_string(parser.row()) + ":" + std::to_string(parser.column()) + " " + message}
 | 
			
		||||
		{
 | 
			
		||||
			const auto coordinate = parser.coordinate();
 | 
			
		||||
 | 
			
		||||
			m_message = coordinate.sectionName + ":" + std::to_string(coordinate.row) + ":" + std::to_string(coordinate.column) + " " + message;
 | 
			
		||||
		}
 | 
			
		||||
 | 
			
		||||
		~ParserWarning() throw()
 | 
			
		||||
 
 | 
			
		||||
@@ -18,9 +18,8 @@ namespace pddl
 | 
			
		||||
//
 | 
			
		||||
////////////////////////////////////////////////////////////////////////////////////////////////////
 | 
			
		||||
 | 
			
		||||
Description::Description(std::istream &istream)
 | 
			
		||||
:	m_parser(istream),
 | 
			
		||||
	m_context(m_parser),
 | 
			
		||||
Description::Description()
 | 
			
		||||
:	m_context(m_parser),
 | 
			
		||||
	m_domain{std::make_unique<Domain>(Domain(m_context))},
 | 
			
		||||
	m_problem{std::make_unique<Problem>(Problem(m_context, *m_domain))}
 | 
			
		||||
{
 | 
			
		||||
@@ -31,9 +30,9 @@ Description::Description(std::istream &istream)
 | 
			
		||||
 | 
			
		||||
Description Description::fromStream(std::istream &istream)
 | 
			
		||||
{
 | 
			
		||||
	Description description(istream);
 | 
			
		||||
	Description description;
 | 
			
		||||
 | 
			
		||||
	description.m_parser.setFileName("std::cin");
 | 
			
		||||
	description.m_parser.readStream("std::cin", istream);
 | 
			
		||||
 | 
			
		||||
	description.parseContent();
 | 
			
		||||
	description.checkConsistency();
 | 
			
		||||
@@ -47,29 +46,15 @@ Description Description::fromFiles(const std::vector<std::string> &paths)
 | 
			
		||||
{
 | 
			
		||||
	BOOST_ASSERT(!paths.empty());
 | 
			
		||||
 | 
			
		||||
	std::for_each(paths.cbegin(), paths.cend(),
 | 
			
		||||
		[&](const auto &path)
 | 
			
		||||
		{
 | 
			
		||||
			if (!boost::filesystem::is_regular_file(path))
 | 
			
		||||
				throw std::runtime_error("File does not exist: \"" + path + "\"");
 | 
			
		||||
		});
 | 
			
		||||
 | 
			
		||||
	std::ifstream fileStream;
 | 
			
		||||
	Description description(fileStream);
 | 
			
		||||
	Description description;
 | 
			
		||||
 | 
			
		||||
	std::for_each(paths.cbegin(), paths.cend(),
 | 
			
		||||
		[&](const auto &path)
 | 
			
		||||
		{
 | 
			
		||||
			fileStream.close();
 | 
			
		||||
			fileStream.clear();
 | 
			
		||||
			fileStream.open(path, std::ios::in);
 | 
			
		||||
 | 
			
		||||
			description.m_parser.setFileName(path);
 | 
			
		||||
			description.m_parser.resetPosition();
 | 
			
		||||
 | 
			
		||||
			description.parseContent();
 | 
			
		||||
			description.m_parser.readFile(path);
 | 
			
		||||
		});
 | 
			
		||||
 | 
			
		||||
	description.parseContent();
 | 
			
		||||
	description.checkConsistency();
 | 
			
		||||
 | 
			
		||||
	return description;
 | 
			
		||||
@@ -92,7 +77,7 @@ void Description::parseContent()
 | 
			
		||||
	{
 | 
			
		||||
		m_context.parser.skipWhiteSpace();
 | 
			
		||||
 | 
			
		||||
		if (m_context.parser.atEndOfFile())
 | 
			
		||||
		if (m_context.parser.atEndOfStream())
 | 
			
		||||
			return;
 | 
			
		||||
 | 
			
		||||
		m_context.parser.expect<std::string>("(");
 | 
			
		||||
 
 | 
			
		||||
@@ -30,18 +30,11 @@ Description::Description()
 | 
			
		||||
 | 
			
		||||
Description Description::fromStream(std::istream &istream)
 | 
			
		||||
{
 | 
			
		||||
	utils::Parser parser;
 | 
			
		||||
	parser.readStream("std::cin", istream);
 | 
			
		||||
 | 
			
		||||
	Description description;
 | 
			
		||||
 | 
			
		||||
	utils::Parser parser(istream);
 | 
			
		||||
 | 
			
		||||
	description.parseVersionSection(parser);
 | 
			
		||||
	description.parseMetricSection(parser);
 | 
			
		||||
	description.parseVariablesSection(parser);
 | 
			
		||||
	description.parseMutexSection(parser);
 | 
			
		||||
	description.parseInitialStateSection(parser);
 | 
			
		||||
	description.parseGoalSection(parser);
 | 
			
		||||
	description.parseOperatorSection(parser);
 | 
			
		||||
	description.parseAxiomSection(parser);
 | 
			
		||||
	description.parseContent(parser);
 | 
			
		||||
 | 
			
		||||
	return description;
 | 
			
		||||
}
 | 
			
		||||
@@ -53,9 +46,13 @@ Description Description::fromFile(const boost::filesystem::path &path)
 | 
			
		||||
	if (!boost::filesystem::is_regular_file(path))
 | 
			
		||||
		throw std::runtime_error("File does not exist: \"" + path.string() + "\"");
 | 
			
		||||
 | 
			
		||||
	std::ifstream fileStream(path.string(), std::ios::in);
 | 
			
		||||
	utils::Parser parser;
 | 
			
		||||
	parser.readFile(path);
 | 
			
		||||
 | 
			
		||||
	return Description::fromStream(fileStream);
 | 
			
		||||
	Description description;
 | 
			
		||||
	description.parseContent(parser);
 | 
			
		||||
 | 
			
		||||
	return description;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
////////////////////////////////////////////////////////////////////////////////////////////////////
 | 
			
		||||
@@ -146,6 +143,20 @@ bool Description::usesConditionalEffects() const
 | 
			
		||||
 | 
			
		||||
////////////////////////////////////////////////////////////////////////////////////////////////////
 | 
			
		||||
 | 
			
		||||
void Description::parseContent(utils::Parser &parser)
 | 
			
		||||
{
 | 
			
		||||
	parseVersionSection(parser);
 | 
			
		||||
	parseMetricSection(parser);
 | 
			
		||||
	parseVariablesSection(parser);
 | 
			
		||||
	parseMutexSection(parser);
 | 
			
		||||
	parseInitialStateSection(parser);
 | 
			
		||||
	parseGoalSection(parser);
 | 
			
		||||
	parseOperatorSection(parser);
 | 
			
		||||
	parseAxiomSection(parser);
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
////////////////////////////////////////////////////////////////////////////////////////////////////
 | 
			
		||||
 | 
			
		||||
void Description::parseVersionSection(utils::Parser &parser) const
 | 
			
		||||
{
 | 
			
		||||
	parser.expect<std::string>("begin_version");
 | 
			
		||||
 
 | 
			
		||||
@@ -27,12 +27,16 @@ void Logger::setPedantic(bool isPedantic)
 | 
			
		||||
 | 
			
		||||
////////////////////////////////////////////////////////////////////////////////////////////////////
 | 
			
		||||
 | 
			
		||||
void Logger::parserWarning(const Parser &parser, const std::string &text)
 | 
			
		||||
void Logger::parserWarning(const Parser &parser, const std::string &message)
 | 
			
		||||
{
 | 
			
		||||
	if (m_isPedantic)
 | 
			
		||||
		throw ParserWarning(parser, text);
 | 
			
		||||
		throw ParserWarning(parser, message);
 | 
			
		||||
 | 
			
		||||
	std::cerr << "Warning: " << parser.fileName() << ":" << parser.row() << ":" << parser.column() << " " << text << std::endl;
 | 
			
		||||
	const auto coordinate = parser.coordinate();
 | 
			
		||||
 | 
			
		||||
	std::cerr << "Warning: " << coordinate.sectionName << ":"
 | 
			
		||||
		<< std::to_string(coordinate.row) + ":" + std::to_string(coordinate.column)
 | 
			
		||||
		<< " " << message << std::endl;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
////////////////////////////////////////////////////////////////////////////////////////////////////
 | 
			
		||||
 
 | 
			
		||||
@@ -1,6 +1,7 @@
 | 
			
		||||
#include <plasp/utils/Parser.h>
 | 
			
		||||
 | 
			
		||||
#include <algorithm>
 | 
			
		||||
#include <fstream>
 | 
			
		||||
 | 
			
		||||
#include <boost/assert.hpp>
 | 
			
		||||
 | 
			
		||||
@@ -21,56 +22,116 @@ const std::istreambuf_iterator<char> Parser::EndOfFile = std::istreambuf_iterato
 | 
			
		||||
 | 
			
		||||
////////////////////////////////////////////////////////////////////////////////////////////////////
 | 
			
		||||
 | 
			
		||||
Parser::Parser(std::istream &istream)
 | 
			
		||||
:	m_istream(istream),
 | 
			
		||||
	m_position(m_istream),
 | 
			
		||||
	m_row{1},
 | 
			
		||||
	m_column{1},
 | 
			
		||||
	m_isCaseSensitive{true},
 | 
			
		||||
	m_atEndOfFile{false}
 | 
			
		||||
Parser::Parser()
 | 
			
		||||
:	m_isCaseSensitive{true}
 | 
			
		||||
{
 | 
			
		||||
	std::setlocale(LC_NUMERIC, "C");
 | 
			
		||||
 | 
			
		||||
	// Don’t skip whitespace
 | 
			
		||||
	istream.exceptions(std::istream::badbit);
 | 
			
		||||
	m_stream.exceptions(std::istream::badbit);
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
////////////////////////////////////////////////////////////////////////////////////////////////////
 | 
			
		||||
 | 
			
		||||
void Parser::setFileName(std::string fileName)
 | 
			
		||||
Parser::Parser(std::string streamName, std::istream &istream)
 | 
			
		||||
:	Parser()
 | 
			
		||||
{
 | 
			
		||||
	m_fileName = fileName;
 | 
			
		||||
	readStream(streamName, istream);
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
////////////////////////////////////////////////////////////////////////////////////////////////////
 | 
			
		||||
 | 
			
		||||
const std::string &Parser::fileName() const
 | 
			
		||||
void Parser::readStream(std::string streamName, std::istream &istream)
 | 
			
		||||
{
 | 
			
		||||
	return m_fileName;
 | 
			
		||||
	// Store position of new section
 | 
			
		||||
	const auto position = m_stream.tellp();
 | 
			
		||||
 | 
			
		||||
	m_streamDelimiters.push_back({position, streamName});
 | 
			
		||||
 | 
			
		||||
	m_stream << istream.rdbuf();
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
////////////////////////////////////////////////////////////////////////////////////////////////////
 | 
			
		||||
 | 
			
		||||
void Parser::resetPosition()
 | 
			
		||||
void Parser::readFile(const boost::filesystem::path &path)
 | 
			
		||||
{
 | 
			
		||||
	m_row = 1;
 | 
			
		||||
	m_column = 1;
 | 
			
		||||
	m_atEndOfFile = false;
 | 
			
		||||
	m_position = std::istreambuf_iterator<char>(m_istream);
 | 
			
		||||
	if (!boost::filesystem::is_regular_file(path))
 | 
			
		||||
		throw std::runtime_error("File does not exist: \"" + path.string() + "\"");
 | 
			
		||||
 | 
			
		||||
	std::ifstream fileStream(path.string(), std::ios::in);
 | 
			
		||||
 | 
			
		||||
	readStream(path.string(), fileStream);
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
////////////////////////////////////////////////////////////////////////////////////////////////////
 | 
			
		||||
 | 
			
		||||
size_t Parser::row() const
 | 
			
		||||
void Parser::reset()
 | 
			
		||||
{
 | 
			
		||||
	return m_row;
 | 
			
		||||
	m_stream.clear();
 | 
			
		||||
	seek(std::ios::beg);
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
////////////////////////////////////////////////////////////////////////////////////////////////////
 | 
			
		||||
 | 
			
		||||
size_t Parser::column() const
 | 
			
		||||
void Parser::seek(Position position)
 | 
			
		||||
{
 | 
			
		||||
	return m_column;
 | 
			
		||||
	m_stream.clear();
 | 
			
		||||
	m_stream.seekg(position);
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
////////////////////////////////////////////////////////////////////////////////////////////////////
 | 
			
		||||
 | 
			
		||||
Parser::Position Parser::position() const
 | 
			
		||||
{
 | 
			
		||||
	return m_stream.tellg();
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
////////////////////////////////////////////////////////////////////////////////////////////////////
 | 
			
		||||
 | 
			
		||||
Parser::Coordinate Parser::coordinate() const
 | 
			
		||||
{
 | 
			
		||||
	const auto currentPosition = position();
 | 
			
		||||
 | 
			
		||||
	// Find current section
 | 
			
		||||
	auto currentFile = std::find_if(m_streamDelimiters.crbegin(), m_streamDelimiters.crend(),
 | 
			
		||||
		[&](const auto &fileDelimiter)
 | 
			
		||||
		{
 | 
			
		||||
			return currentPosition >= fileDelimiter.position;
 | 
			
		||||
		});
 | 
			
		||||
 | 
			
		||||
	// If the parser is at the end of the stream, still count from the beginning of the last section
 | 
			
		||||
	if (currentFile == m_streamDelimiters.crend())
 | 
			
		||||
		currentFile = m_streamDelimiters.crbegin();
 | 
			
		||||
 | 
			
		||||
	// Go back to beginning of section
 | 
			
		||||
	m_stream.clear();
 | 
			
		||||
	m_stream.seekg(currentFile->position);
 | 
			
		||||
 | 
			
		||||
	size_t row = 1;
 | 
			
		||||
	size_t column = 1;
 | 
			
		||||
 | 
			
		||||
	// Compute the coordinate character by character
 | 
			
		||||
	while (true)
 | 
			
		||||
	{
 | 
			
		||||
		if (currentPosition == -1 && atEndOfStream())
 | 
			
		||||
			break;
 | 
			
		||||
		else if (currentPosition >= 0 && position() >= currentPosition)
 | 
			
		||||
			break;
 | 
			
		||||
 | 
			
		||||
		const auto character = currentCharacter();
 | 
			
		||||
 | 
			
		||||
		if (character == '\n')
 | 
			
		||||
		{
 | 
			
		||||
			row++;
 | 
			
		||||
			column = 1;
 | 
			
		||||
		}
 | 
			
		||||
		else if (std::isblank(character) || std::isprint(character))
 | 
			
		||||
			column++;
 | 
			
		||||
 | 
			
		||||
		m_stream.ignore(1);
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	return {currentFile->sectionName, row, column};
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
////////////////////////////////////////////////////////////////////////////////////////////////////
 | 
			
		||||
@@ -84,29 +145,27 @@ void Parser::setCaseSensitive(bool isCaseSensitive)
 | 
			
		||||
 | 
			
		||||
char Parser::currentCharacter() const
 | 
			
		||||
{
 | 
			
		||||
	checkStream();
 | 
			
		||||
 | 
			
		||||
	if (m_isCaseSensitive)
 | 
			
		||||
		return *m_position;
 | 
			
		||||
		return m_stream.peek();
 | 
			
		||||
 | 
			
		||||
	return std::tolower(*m_position);
 | 
			
		||||
	return std::tolower(m_stream.peek());
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
////////////////////////////////////////////////////////////////////////////////////////////////////
 | 
			
		||||
 | 
			
		||||
bool Parser::atEndOfFile() const
 | 
			
		||||
bool Parser::atEndOfStream() const
 | 
			
		||||
{
 | 
			
		||||
	return m_position.equal(EndOfFile);
 | 
			
		||||
	return position() == -1;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
////////////////////////////////////////////////////////////////////////////////////////////////////
 | 
			
		||||
 | 
			
		||||
void Parser::checkStream() const
 | 
			
		||||
{
 | 
			
		||||
	if (atEndOfFile())
 | 
			
		||||
	if (atEndOfStream())
 | 
			
		||||
		throw ParserException(*this, "Reading past end of file");
 | 
			
		||||
 | 
			
		||||
	if (m_istream.fail())
 | 
			
		||||
	if (m_stream.fail())
 | 
			
		||||
		throw ParserException(*this);
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
@@ -115,18 +174,7 @@ void Parser::checkStream() const
 | 
			
		||||
void Parser::advance()
 | 
			
		||||
{
 | 
			
		||||
	checkStream();
 | 
			
		||||
 | 
			
		||||
	const auto character = currentCharacter();
 | 
			
		||||
 | 
			
		||||
	if (character == '\n')
 | 
			
		||||
	{
 | 
			
		||||
		m_row++;
 | 
			
		||||
		m_column = 1;
 | 
			
		||||
	}
 | 
			
		||||
	else if (std::isblank(character) || std::isprint(character))
 | 
			
		||||
		m_column++;
 | 
			
		||||
 | 
			
		||||
	m_position++;
 | 
			
		||||
	m_stream.ignore(1);
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
////////////////////////////////////////////////////////////////////////////////////////////////////
 | 
			
		||||
@@ -246,7 +294,7 @@ uint64_t Parser::parseIntegerBody()
 | 
			
		||||
 | 
			
		||||
	uint64_t value = 0;
 | 
			
		||||
 | 
			
		||||
	while (!atEndOfFile())
 | 
			
		||||
	while (!atEndOfStream())
 | 
			
		||||
	{
 | 
			
		||||
		const auto character = currentCharacter();
 | 
			
		||||
 | 
			
		||||
 
 | 
			
		||||
@@ -9,7 +9,7 @@
 | 
			
		||||
TEST(UtilsTests, ParseSimple)
 | 
			
		||||
{
 | 
			
		||||
	std::stringstream s("identifier  5   \n-51\t 0 1 expected unexpected");
 | 
			
		||||
	plasp::utils::Parser p(s);
 | 
			
		||||
	plasp::utils::Parser p("input", s);
 | 
			
		||||
 | 
			
		||||
	ASSERT_EQ(p.parse<std::string>(), "identifier");
 | 
			
		||||
	ASSERT_EQ(p.parse<size_t>(), 5u);
 | 
			
		||||
@@ -19,6 +19,8 @@ TEST(UtilsTests, ParseSimple)
 | 
			
		||||
 | 
			
		||||
	ASSERT_NO_THROW(p.expect<std::string>("expected"));
 | 
			
		||||
	ASSERT_THROW(p.expect<std::string>("expected"), plasp::utils::ParserException);
 | 
			
		||||
 | 
			
		||||
	// TODO: test case-insensitive input
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
////////////////////////////////////////////////////////////////////////////////////////////////////
 | 
			
		||||
@@ -26,7 +28,7 @@ TEST(UtilsTests, ParseSimple)
 | 
			
		||||
TEST(UtilsTests, ParseUnsignedNumbers)
 | 
			
		||||
{
 | 
			
		||||
	std::stringstream s("100 200 -300 -400");
 | 
			
		||||
	plasp::utils::Parser p(s);
 | 
			
		||||
	plasp::utils::Parser p("input", s);
 | 
			
		||||
 | 
			
		||||
	ASSERT_EQ(p.parse<int>(), 100);
 | 
			
		||||
	ASSERT_EQ(p.parse<size_t>(), 200u);
 | 
			
		||||
@@ -39,13 +41,13 @@ TEST(UtilsTests, ParseUnsignedNumbers)
 | 
			
		||||
TEST(UtilsTests, ParseEndOfFile)
 | 
			
		||||
{
 | 
			
		||||
	std::stringstream s1("test");
 | 
			
		||||
	plasp::utils::Parser p1(s1);
 | 
			
		||||
	plasp::utils::Parser p1("input", s1);
 | 
			
		||||
 | 
			
		||||
	ASSERT_NO_THROW(p1.expect<std::string>("test"));
 | 
			
		||||
	ASSERT_THROW(p1.parse<std::string>(), plasp::utils::ParserException);
 | 
			
		||||
 | 
			
		||||
	std::stringstream s2("test1 test2 test3");
 | 
			
		||||
	plasp::utils::Parser p2(s2);
 | 
			
		||||
	plasp::utils::Parser p2("input", s2);
 | 
			
		||||
 | 
			
		||||
	ASSERT_NO_THROW(p2.expect<std::string>("test1"));
 | 
			
		||||
	ASSERT_NO_THROW(p2.expect<std::string>("test2"));
 | 
			
		||||
@@ -53,13 +55,13 @@ TEST(UtilsTests, ParseEndOfFile)
 | 
			
		||||
	ASSERT_THROW(p2.parse<std::string>(), plasp::utils::ParserException);
 | 
			
		||||
 | 
			
		||||
	std::stringstream s3("-127");
 | 
			
		||||
	plasp::utils::Parser p3(s3);
 | 
			
		||||
	plasp::utils::Parser p3("input", s3);
 | 
			
		||||
 | 
			
		||||
	p3.expect<int>(-127);
 | 
			
		||||
	ASSERT_THROW(p3.parse<int>(), plasp::utils::ParserException);
 | 
			
		||||
 | 
			
		||||
	std::stringstream s4("128 -1023 -4095");
 | 
			
		||||
	plasp::utils::Parser p4(s4);
 | 
			
		||||
	plasp::utils::Parser p4("input", s4);
 | 
			
		||||
 | 
			
		||||
	ASSERT_NO_THROW(p4.expect<size_t>(128));
 | 
			
		||||
	ASSERT_NO_THROW(p4.expect<int>(-1023));
 | 
			
		||||
@@ -67,13 +69,13 @@ TEST(UtilsTests, ParseEndOfFile)
 | 
			
		||||
	ASSERT_THROW(p4.parse<int>(), plasp::utils::ParserException);
 | 
			
		||||
 | 
			
		||||
	std::stringstream s5("0");
 | 
			
		||||
	plasp::utils::Parser p5(s5);
 | 
			
		||||
	plasp::utils::Parser p5("input", s5);
 | 
			
		||||
 | 
			
		||||
	p5.expect<bool>(false);
 | 
			
		||||
	ASSERT_THROW(p5.parse<bool>(), plasp::utils::ParserException);
 | 
			
		||||
 | 
			
		||||
	std::stringstream s6("0 1 0");
 | 
			
		||||
	plasp::utils::Parser p6(s6);
 | 
			
		||||
	plasp::utils::Parser p6("input", s6);
 | 
			
		||||
 | 
			
		||||
	ASSERT_NO_THROW(p6.expect<bool>(false));
 | 
			
		||||
	ASSERT_NO_THROW(p6.expect<bool>(true));
 | 
			
		||||
@@ -86,74 +88,90 @@ TEST(UtilsTests, ParseEndOfFile)
 | 
			
		||||
TEST(UtilsTests, ParserPosition)
 | 
			
		||||
{
 | 
			
		||||
	std::stringstream s("123 \n4\ntest1\n test2\ntest3 \ntest4\n\n\n\n");
 | 
			
		||||
	plasp::utils::Parser p(s);
 | 
			
		||||
	plasp::utils::Parser p("input", s);
 | 
			
		||||
 | 
			
		||||
	ASSERT_EQ(p.row(), 1u);
 | 
			
		||||
	ASSERT_EQ(p.column(), 1u);
 | 
			
		||||
	plasp::utils::Parser::Coordinate c;
 | 
			
		||||
 | 
			
		||||
	c = p.coordinate();
 | 
			
		||||
	ASSERT_EQ(c.row, 1u);
 | 
			
		||||
	ASSERT_EQ(c.column, 1u);
 | 
			
		||||
	ASSERT_EQ(p.currentCharacter(), '1');
 | 
			
		||||
 | 
			
		||||
	ASSERT_NO_THROW(p.advance());
 | 
			
		||||
 | 
			
		||||
	ASSERT_EQ(p.row(), 1u);
 | 
			
		||||
	ASSERT_EQ(p.column(), 2u);
 | 
			
		||||
	c = p.coordinate();
 | 
			
		||||
	ASSERT_EQ(c.row, 1u);
 | 
			
		||||
	ASSERT_EQ(c.column, 2u);
 | 
			
		||||
	ASSERT_EQ(p.currentCharacter(), '2');
 | 
			
		||||
 | 
			
		||||
	ASSERT_NO_THROW(p.advance());
 | 
			
		||||
 | 
			
		||||
	ASSERT_EQ(p.row(), 1u);
 | 
			
		||||
	ASSERT_EQ(p.column(), 3u);
 | 
			
		||||
	c = p.coordinate();
 | 
			
		||||
	ASSERT_EQ(c.row, 1u);
 | 
			
		||||
	ASSERT_EQ(c.column, 3u);
 | 
			
		||||
	ASSERT_EQ(p.currentCharacter(), '3');
 | 
			
		||||
 | 
			
		||||
	ASSERT_NO_THROW(p.advance());
 | 
			
		||||
 | 
			
		||||
	ASSERT_EQ(p.row(), 1u);
 | 
			
		||||
	ASSERT_EQ(p.column(), 4u);
 | 
			
		||||
	c = p.coordinate();
 | 
			
		||||
	ASSERT_EQ(c.row, 1u);
 | 
			
		||||
	ASSERT_EQ(c.column, 4u);
 | 
			
		||||
	ASSERT_EQ(p.currentCharacter(), ' ');
 | 
			
		||||
 | 
			
		||||
	ASSERT_NO_THROW(p.advance());
 | 
			
		||||
 | 
			
		||||
	ASSERT_EQ(p.row(), 1u);
 | 
			
		||||
	ASSERT_EQ(p.column(), 5u);
 | 
			
		||||
	c = p.coordinate();
 | 
			
		||||
	ASSERT_EQ(c.row, 1u);
 | 
			
		||||
	ASSERT_EQ(c.column, 5u);
 | 
			
		||||
	ASSERT_EQ(p.currentCharacter(), '\n');
 | 
			
		||||
 | 
			
		||||
	ASSERT_NO_THROW(p.advance());
 | 
			
		||||
 | 
			
		||||
	ASSERT_EQ(p.row(), 2u);
 | 
			
		||||
	ASSERT_EQ(p.column(), 1u);
 | 
			
		||||
	c = p.coordinate();
 | 
			
		||||
	ASSERT_EQ(c.row, 2u);
 | 
			
		||||
	ASSERT_EQ(c.column, 1u);
 | 
			
		||||
	ASSERT_EQ(p.currentCharacter(), '4');
 | 
			
		||||
 | 
			
		||||
	ASSERT_NO_THROW(p.advance());
 | 
			
		||||
 | 
			
		||||
	ASSERT_NO_THROW(p.expect<std::string>("test1"));
 | 
			
		||||
 | 
			
		||||
	ASSERT_EQ(p.row(), 3u);
 | 
			
		||||
	ASSERT_EQ(p.column(), 6u);
 | 
			
		||||
	c = p.coordinate();
 | 
			
		||||
	ASSERT_EQ(c.row, 3u);
 | 
			
		||||
	ASSERT_EQ(c.column, 6u);
 | 
			
		||||
 | 
			
		||||
	ASSERT_NO_THROW(p.expect<std::string>("test2"));
 | 
			
		||||
 | 
			
		||||
	ASSERT_EQ(p.row(), 4u);
 | 
			
		||||
	ASSERT_EQ(p.column(), 7u);
 | 
			
		||||
	c = p.coordinate();
 | 
			
		||||
	ASSERT_EQ(c.row, 4u);
 | 
			
		||||
	ASSERT_EQ(c.column, 7u);
 | 
			
		||||
 | 
			
		||||
	ASSERT_NO_THROW(p.expect<std::string>("test3"));
 | 
			
		||||
 | 
			
		||||
	ASSERT_EQ(p.row(), 5u);
 | 
			
		||||
	ASSERT_EQ(p.column(), 6u);
 | 
			
		||||
	c = p.coordinate();
 | 
			
		||||
	ASSERT_EQ(c.row, 5u);
 | 
			
		||||
	ASSERT_EQ(c.column, 6u);
 | 
			
		||||
 | 
			
		||||
	ASSERT_NO_THROW(p.skipLine());
 | 
			
		||||
 | 
			
		||||
	ASSERT_EQ(p.row(), 6u);
 | 
			
		||||
	ASSERT_EQ(p.column(), 1u);
 | 
			
		||||
	c = p.coordinate();
 | 
			
		||||
	ASSERT_EQ(c.row, 6u);
 | 
			
		||||
	ASSERT_EQ(c.column, 1u);
 | 
			
		||||
 | 
			
		||||
	ASSERT_NO_THROW(p.skipLine());
 | 
			
		||||
 | 
			
		||||
	ASSERT_EQ(p.row(), 7u);
 | 
			
		||||
	ASSERT_EQ(p.column(), 1u);
 | 
			
		||||
	c = p.coordinate();
 | 
			
		||||
	ASSERT_EQ(c.row, 7u);
 | 
			
		||||
	ASSERT_EQ(c.column, 1u);
 | 
			
		||||
 | 
			
		||||
	ASSERT_NO_THROW(p.skipWhiteSpace());
 | 
			
		||||
 | 
			
		||||
	ASSERT_TRUE(p.atEndOfFile());
 | 
			
		||||
	ASSERT_EQ(p.row(), 10u);
 | 
			
		||||
	ASSERT_EQ(p.column(), 1u);
 | 
			
		||||
	c = p.coordinate();
 | 
			
		||||
	ASSERT_EQ(c.row, 10u);
 | 
			
		||||
	ASSERT_EQ(c.column, 1u);
 | 
			
		||||
	ASSERT_TRUE(p.atEndOfStream());
 | 
			
		||||
 | 
			
		||||
	// TODO: test parser with multiple sections
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
////////////////////////////////////////////////////////////////////////////////////////////////////
 | 
			
		||||
 
 | 
			
		||||
		Reference in New Issue
	
	Block a user