parser.cpp (3020B)
1 #include <cstdio> 2 #include <sstream> 3 4 #include "directives.h" // IWYU pragma: keep 5 #include "scanner.h" // IWYU pragma: keep 6 #include "singledocparser.h" 7 #include "token.h" 8 #include "yaml-cpp/exceptions.h" // IWYU pragma: keep 9 #include "yaml-cpp/parser.h" 10 11 namespace YAML { 12 class EventHandler; 13 14 Parser::Parser() : m_pScanner{}, m_pDirectives{} {} 15 16 Parser::Parser(std::istream& in) : Parser() { Load(in); } 17 18 Parser::~Parser() = default; 19 20 Parser::operator bool() const { return m_pScanner && !m_pScanner->empty(); } 21 22 void Parser::Load(std::istream& in) { 23 m_pScanner.reset(new Scanner(in)); 24 m_pDirectives.reset(new Directives); 25 } 26 27 bool Parser::HandleNextDocument(EventHandler& eventHandler) { 28 if (!m_pScanner) 29 return false; 30 31 ParseDirectives(); 32 if (m_pScanner->empty()) { 33 return false; 34 } 35 36 SingleDocParser sdp(*m_pScanner, *m_pDirectives); 37 sdp.HandleDocument(eventHandler); 38 return true; 39 } 40 41 void Parser::ParseDirectives() { 42 bool readDirective = false; 43 44 while (!m_pScanner->empty()) { 45 Token& token = m_pScanner->peek(); 46 if (token.type != Token::DIRECTIVE) { 47 break; 48 } 49 50 // we keep the directives from the last document if none are specified; 51 // but if any directives are specific, then we reset them 52 if (!readDirective) { 53 m_pDirectives.reset(new Directives); 54 } 55 56 readDirective = true; 57 HandleDirective(token); 58 m_pScanner->pop(); 59 } 60 } 61 62 void Parser::HandleDirective(const Token& token) { 63 if (token.value == "YAML") { 64 HandleYamlDirective(token); 65 } else if (token.value == "TAG") { 66 HandleTagDirective(token); 67 } 68 } 69 70 void Parser::HandleYamlDirective(const Token& token) { 71 if (token.params.size() != 1) { 72 throw ParserException(token.mark, ErrorMsg::YAML_DIRECTIVE_ARGS); 73 } 74 75 if (!m_pDirectives->version.isDefault) { 76 throw ParserException(token.mark, ErrorMsg::REPEATED_YAML_DIRECTIVE); 77 } 78 79 std::stringstream str(token.params[0]); 80 str >> m_pDirectives->version.major; 81 str.get(); 82 str >> m_pDirectives->version.minor; 83 if (!str || str.peek() != EOF) { 84 throw ParserException( 85 token.mark, std::string(ErrorMsg::YAML_VERSION) + token.params[0]); 86 } 87 88 if (m_pDirectives->version.major > 1) { 89 throw ParserException(token.mark, ErrorMsg::YAML_MAJOR_VERSION); 90 } 91 92 m_pDirectives->version.isDefault = false; 93 // TODO: warning on major == 1, minor > 2? 94 } 95 96 void Parser::HandleTagDirective(const Token& token) { 97 if (token.params.size() != 2) 98 throw ParserException(token.mark, ErrorMsg::TAG_DIRECTIVE_ARGS); 99 100 const std::string& handle = token.params[0]; 101 const std::string& prefix = token.params[1]; 102 if (m_pDirectives->tags.find(handle) != m_pDirectives->tags.end()) { 103 throw ParserException(token.mark, ErrorMsg::REPEATED_TAG_DIRECTIVE); 104 } 105 106 m_pDirectives->tags[handle] = prefix; 107 } 108 109 void Parser::PrintTokens(std::ostream& out) { 110 if (!m_pScanner) { 111 return; 112 } 113 114 while (!m_pScanner->empty()) { 115 out << m_pScanner->peek() << "\n"; 116 m_pScanner->pop(); 117 } 118 } 119 } // namespace YAML