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