| #include <cstdio> | |
| #include <sstream> | |
| #include "directives.h" // IWYU pragma: keep | |
| #include "scanner.h" // IWYU pragma: keep | |
| #include "singledocparser.h" | |
| #include "token.h" | |
| #include "yaml-cpp/exceptions.h" // IWYU pragma: keep | |
| #include "yaml-cpp/parser.h" | |
| namespace YAML { | |
| class EventHandler; | |
| Parser::Parser() : m_pScanner{}, m_pDirectives{} {} | |
| Parser::Parser(std::istream& in) : Parser() { Load(in); } | |
| Parser::~Parser() = default; | |
| Parser::operator bool() const { return m_pScanner && !m_pScanner->empty(); } | |
| void Parser::Load(std::istream& in) { | |
| m_pScanner.reset(new Scanner(in)); | |
| m_pDirectives.reset(new Directives); | |
| } | |
| bool Parser::HandleNextDocument(EventHandler& eventHandler) { | |
| if (!m_pScanner) | |
| return false; | |
| ParseDirectives(); | |
| if (m_pScanner->empty()) { | |
| return false; | |
| } | |
| SingleDocParser sdp(*m_pScanner, *m_pDirectives); | |
| sdp.HandleDocument(eventHandler); | |
| return true; | |
| } | |
| void Parser::ParseDirectives() { | |
| bool readDirective = false; | |
| while (!m_pScanner->empty()) { | |
| Token& token = m_pScanner->peek(); | |
| if (token.type != Token::DIRECTIVE) { | |
| break; | |
| } | |
| // we keep the directives from the last document if none are specified; | |
| // but if any directives are specific, then we reset them | |
| if (!readDirective) { | |
| m_pDirectives.reset(new Directives); | |
| } | |
| readDirective = true; | |
| HandleDirective(token); | |
| m_pScanner->pop(); | |
| } | |
| } | |
| void Parser::HandleDirective(const Token& token) { | |
| if (token.value == "YAML") { | |
| HandleYamlDirective(token); | |
| } else if (token.value == "TAG") { | |
| HandleTagDirective(token); | |
| } | |
| } | |
| void Parser::HandleYamlDirective(const Token& token) { | |
| if (token.params.size() != 1) { | |
| throw ParserException(token.mark, ErrorMsg::YAML_DIRECTIVE_ARGS); | |
| } | |
| if (!m_pDirectives->version.isDefault) { | |
| throw ParserException(token.mark, ErrorMsg::REPEATED_YAML_DIRECTIVE); | |
| } | |
| std::stringstream str(token.params[0]); | |
| str.imbue(std::locale::classic()); | |
| str >> m_pDirectives->version.major; | |
| str.get(); | |
| str >> m_pDirectives->version.minor; | |
| if (!str || str.peek() != EOF) { | |
| throw ParserException( | |
| token.mark, std::string(ErrorMsg::YAML_VERSION) + token.params[0]); | |
| } | |
| if (m_pDirectives->version.major > 1) { | |
| throw ParserException(token.mark, ErrorMsg::YAML_MAJOR_VERSION); | |
| } | |
| m_pDirectives->version.isDefault = false; | |
| // TODO: warning on major == 1, minor > 2? | |
| } | |
| void Parser::HandleTagDirective(const Token& token) { | |
| if (token.params.size() != 2) | |
| throw ParserException(token.mark, ErrorMsg::TAG_DIRECTIVE_ARGS); | |
| const std::string& handle = token.params[0]; | |
| const std::string& prefix = token.params[1]; | |
| if (m_pDirectives->tags.find(handle) != m_pDirectives->tags.end()) { | |
| throw ParserException(token.mark, ErrorMsg::REPEATED_TAG_DIRECTIVE); | |
| } | |
| m_pDirectives->tags[handle] = prefix; | |
| } | |
| void Parser::PrintTokens(std::ostream& out) { | |
| if (!m_pScanner) { | |
| return; | |
| } | |
| while (!m_pScanner->empty()) { | |
| out << m_pScanner->peek() << "\n"; | |
| m_pScanner->pop(); | |
| } | |
| } | |
| } // namespace YAML |