/src/yaml-cpp/src/parser.cpp
Line | Count | Source |
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 | 6.15k | Parser::Parser() : m_pScanner{}, m_pDirectives{} {} |
15 | | |
16 | 6.15k | Parser::Parser(std::istream& in) : Parser() { Load(in); } |
17 | | |
18 | 6.15k | Parser::~Parser() = default; |
19 | | |
20 | 0 | Parser::operator bool() const { return m_pScanner && !m_pScanner->empty(); } |
21 | | |
22 | 6.15k | void Parser::Load(std::istream& in) { |
23 | 6.15k | m_pScanner.reset(new Scanner(in)); |
24 | 6.15k | m_pDirectives.reset(new Directives); |
25 | 6.15k | } |
26 | | |
27 | 342k | bool Parser::HandleNextDocument(EventHandler& eventHandler) { |
28 | 342k | if (!m_pScanner) |
29 | 0 | return false; |
30 | | |
31 | 342k | ParseDirectives(); |
32 | 342k | if (m_pScanner->empty()) { |
33 | 2.67k | return false; |
34 | 2.67k | } |
35 | | |
36 | 340k | auto oldPos = m_pScanner->peek().mark.pos; |
37 | | |
38 | 340k | SingleDocParser sdp(*m_pScanner, *m_pDirectives); |
39 | 340k | sdp.HandleDocument(eventHandler); |
40 | | |
41 | | // checks if progress was made |
42 | | // 1. if scanner has no more tokens, progress was made |
43 | 340k | if (m_pScanner->empty()) { |
44 | 1.97k | return true; |
45 | 1.97k | } |
46 | | |
47 | | // 2. if token position has changed, progress was made |
48 | 338k | auto newPos = m_pScanner->peek().mark.pos; |
49 | 338k | if (newPos != oldPos) { |
50 | 334k | return true; |
51 | 334k | } |
52 | | // No progress was made, no further processing |
53 | 3.47k | return false; |
54 | 338k | } |
55 | | |
56 | 342k | void Parser::ParseDirectives() { |
57 | 342k | bool readDirective = false; |
58 | | |
59 | 354k | while (!m_pScanner->empty()) { |
60 | 350k | Token& token = m_pScanner->peek(); |
61 | 350k | if (token.type != Token::DIRECTIVE) { |
62 | 339k | break; |
63 | 339k | } |
64 | | |
65 | | // we keep the directives from the last document if none are specified; |
66 | | // but if any directives are specific, then we reset them |
67 | 11.4k | if (!readDirective) { |
68 | 3.78k | m_pDirectives.reset(new Directives); |
69 | 3.78k | } |
70 | | |
71 | 11.4k | readDirective = true; |
72 | 11.4k | HandleDirective(token); |
73 | 11.4k | m_pScanner->pop(); |
74 | 11.4k | } |
75 | 342k | } |
76 | | |
77 | 11.4k | void Parser::HandleDirective(const Token& token) { |
78 | 11.4k | if (token.value == "YAML") { |
79 | 1.22k | HandleYamlDirective(token); |
80 | 10.2k | } else if (token.value == "TAG") { |
81 | 5.86k | HandleTagDirective(token); |
82 | 5.86k | } |
83 | 11.4k | } |
84 | | |
85 | 1.22k | void Parser::HandleYamlDirective(const Token& token) { |
86 | 1.22k | if (token.params.size() != 1) { |
87 | 19 | throw ParserException(token.mark, ErrorMsg::YAML_DIRECTIVE_ARGS); |
88 | 19 | } |
89 | | |
90 | 1.20k | if (!m_pDirectives->version.isDefault) { |
91 | 3 | throw ParserException(token.mark, ErrorMsg::REPEATED_YAML_DIRECTIVE); |
92 | 3 | } |
93 | | |
94 | 1.20k | std::stringstream str(token.params[0]); |
95 | 1.20k | str.imbue(std::locale::classic()); |
96 | 1.20k | str >> m_pDirectives->version.major; |
97 | 1.20k | str.get(); |
98 | 1.20k | str >> m_pDirectives->version.minor; |
99 | 1.20k | if (!str || str.peek() != EOF) { |
100 | 27 | throw ParserException( |
101 | 27 | token.mark, std::string(ErrorMsg::YAML_VERSION) + token.params[0]); |
102 | 27 | } |
103 | | |
104 | 1.17k | if (m_pDirectives->version.major > 1) { |
105 | 11 | throw ParserException(token.mark, ErrorMsg::YAML_MAJOR_VERSION); |
106 | 11 | } |
107 | | |
108 | 1.16k | m_pDirectives->version.isDefault = false; |
109 | | // TODO: warning on major == 1, minor > 2? |
110 | 1.16k | } |
111 | | |
112 | 5.86k | void Parser::HandleTagDirective(const Token& token) { |
113 | 5.86k | if (token.params.size() != 2) |
114 | 25 | throw ParserException(token.mark, ErrorMsg::TAG_DIRECTIVE_ARGS); |
115 | | |
116 | 5.83k | const std::string& handle = token.params[0]; |
117 | 5.83k | const std::string& prefix = token.params[1]; |
118 | 5.83k | if (m_pDirectives->tags.find(handle) != m_pDirectives->tags.end()) { |
119 | 8 | throw ParserException(token.mark, ErrorMsg::REPEATED_TAG_DIRECTIVE); |
120 | 8 | } |
121 | | |
122 | 5.82k | m_pDirectives->tags[handle] = prefix; |
123 | 5.82k | } |
124 | | |
125 | 0 | void Parser::PrintTokens(std::ostream& out) { |
126 | 0 | if (!m_pScanner) { |
127 | 0 | return; |
128 | 0 | } |
129 | | |
130 | 0 | while (!m_pScanner->empty()) { |
131 | 0 | out << m_pScanner->peek() << "\n"; |
132 | 0 | m_pScanner->pop(); |
133 | 0 | } |
134 | 0 | } |
135 | | } // namespace YAML |