/* * This project is licensed under the MIT license. For more information see the * LICENSE file. */ #pragma once // ----------------------------------------------------------------------------- #include #include // ----------------------------------------------------------------------------- namespace maddy { // ----------------------------------------------------------------------------- /** * BlockParser * * The code expects every child to have the following static function to be * implemented: * `static bool IsStartingLine(const std::string& line)` * * @class */ class BlockParser { public: /** * ctor * * @method * @param {std::function} parseLineCallback * @param {std::function(const std::string& line)>} getBlockParserForLineCallback */ BlockParser( std::function parseLineCallback, std::function(const std::string& line)> getBlockParserForLineCallback ) : result("", std::ios_base::ate | std::ios_base::in | std::ios_base::out) , childParser(nullptr) , parseLineCallback(parseLineCallback) , getBlockParserForLineCallback(getBlockParserForLineCallback) {} /** * AddLine * * Adding a line which has to be parsed. * * @method * @param {std::string&} line * @return {void} */ virtual void AddLine(std::string& line) { this->parseBlock(line); if (this->isInlineBlockAllowed() && !this->childParser) { this->childParser = this->getBlockParserForLine(line); } if (this->childParser) { this->childParser->AddLine(line); if (this->childParser->IsFinished()) { this->result << this->childParser->GetResult().str(); this->childParser = nullptr; } return; } if (this->isLineParserAllowed()) { this->parseLine(line); } this->result << line; } /** * IsFinished * * Check if the BlockParser is done * * @method * @return {bool} */ virtual bool IsFinished() const = 0; /** * GetResult * * Get the parsed HTML output. * * @method * @return {std::stringstream} */ std::stringstream& GetResult() { return this->result; } /** * Clear * * Clear the result to reuse the parser object. * * It is only used by one test for now. * * @method * @return {void} */ void Clear() { this->result.str(""); } protected: std::stringstream result; std::shared_ptr childParser; virtual bool isInlineBlockAllowed() const = 0; virtual bool isLineParserAllowed() const = 0; virtual void parseBlock(std::string& line) = 0; void parseLine(std::string& line) { if (parseLineCallback) { parseLineCallback(line); } } uint32_t getIndentationWidth(const std::string& line) const { bool hasMetNonSpace = false; uint32_t indentation = std::count_if( line.begin(), line.end(), [&hasMetNonSpace](unsigned char c) { if (hasMetNonSpace) { return false; } if (std::isspace(c)) { return true; } hasMetNonSpace = true; return false; } ); return indentation; } std::shared_ptr getBlockParserForLine(const std::string& line) { if (getBlockParserForLineCallback) { return getBlockParserForLineCallback(line); } return nullptr; } private: std::function parseLineCallback; std::function(const std::string& line)> getBlockParserForLineCallback; }; // class BlockParser // ----------------------------------------------------------------------------- } // namespace maddy