Line | Count | Source |
1 | | #ifndef ZSERIO_JSON_PARSER_H_INC |
2 | | #define ZSERIO_JSON_PARSER_H_INC |
3 | | |
4 | | #include "zserio/AnyHolder.h" |
5 | | #include "zserio/JsonDecoder.h" |
6 | | #include "zserio/JsonTokenizer.h" |
7 | | #include "zserio/Span.h" |
8 | | |
9 | | namespace zserio |
10 | | { |
11 | | |
12 | | /** |
13 | | * Json Parser. |
14 | | * |
15 | | * Parses the JSON on the fly and calls an observer. |
16 | | */ |
17 | | template <typename ALLOC = std::allocator<uint8_t>> |
18 | | class BasicJsonParser |
19 | | { |
20 | | public: |
21 | | /** |
22 | | * Json Parser Observer. |
23 | | */ |
24 | | class IObserver |
25 | | { |
26 | | public: |
27 | | /** |
28 | | * Destructor. |
29 | | */ |
30 | 117 | virtual ~IObserver() = default; |
31 | | |
32 | | /** |
33 | | * Called when a JSON object begins - i.e. on '{'. |
34 | | */ |
35 | | virtual void beginObject() = 0; |
36 | | |
37 | | /** |
38 | | * Called when a JSON objects ends - i.e. on '}'. |
39 | | */ |
40 | | virtual void endObject() = 0; |
41 | | |
42 | | /** |
43 | | * Called when a JSON array begins - i.e. on '['. |
44 | | */ |
45 | | virtual void beginArray() = 0; |
46 | | |
47 | | /** |
48 | | * Called when a JSON array ends - i.e. on ']'. |
49 | | */ |
50 | | virtual void endArray() = 0; |
51 | | |
52 | | /** |
53 | | * Called on a JSON key. |
54 | | * |
55 | | * \param key String view to the key name. |
56 | | */ |
57 | | virtual void visitKey(StringView key) = 0; |
58 | | |
59 | | /** |
60 | | * Call on a JSON null value. |
61 | | * |
62 | | * \param nullValue Null value. |
63 | | */ |
64 | | virtual void visitValue(std::nullptr_t nullValue) = 0; |
65 | | |
66 | | /** |
67 | | * Call on a JSON bool value. |
68 | | * |
69 | | * \param boolValue Bool value. |
70 | | */ |
71 | | virtual void visitValue(bool boolValue) = 0; |
72 | | |
73 | | /** |
74 | | * Call on a JSON signed integer value. |
75 | | * |
76 | | * \param intValue Signed integer value. |
77 | | */ |
78 | | virtual void visitValue(int64_t intValue) = 0; |
79 | | |
80 | | /** |
81 | | * Call on a JSON unsigned integer value. |
82 | | * |
83 | | * \param uintValue Unsigned integer value. |
84 | | */ |
85 | | virtual void visitValue(uint64_t uintValue) = 0; |
86 | | |
87 | | /** |
88 | | * Call on a JSON floating point value. |
89 | | * |
90 | | * \param doubleValue Floating point value. |
91 | | */ |
92 | | virtual void visitValue(double doubleValue) = 0; |
93 | | |
94 | | /** |
95 | | * Call on a JSON string value. |
96 | | * |
97 | | * \param stringValue String view to the string value. |
98 | | */ |
99 | | virtual void visitValue(StringView stringValue) = 0; |
100 | | }; |
101 | | |
102 | | /** |
103 | | * Constructor. |
104 | | * |
105 | | * \param in Text stream to parse. |
106 | | * \param observer Observer to use. |
107 | | * \param allocator Allocator to use. |
108 | | */ |
109 | | BasicJsonParser(std::istream& in, IObserver& observer, const ALLOC& allocator = ALLOC()) : |
110 | | m_tokenizer(in, allocator), m_observer(observer) |
111 | 85 | {} |
112 | | |
113 | | /** |
114 | | * Parses single JSON element from the text stream. |
115 | | * |
116 | | * \return True when end-of-file is reached, false otherwise (i.e. another JSON element is present). |
117 | | * \throw JsonParserException When parsing fails. |
118 | | */ |
119 | | bool parse() |
120 | 92 | { |
121 | 92 | if (m_tokenizer.getToken() == JsonToken::BEGIN_OF_FILE) |
122 | 84 | m_tokenizer.next(); |
123 | | |
124 | 92 | if (m_tokenizer.getToken() == JsonToken::END_OF_FILE) |
125 | 1 | return true; |
126 | | |
127 | 91 | parseElement(); |
128 | | |
129 | 91 | return m_tokenizer.getToken() == JsonToken::END_OF_FILE; |
130 | 92 | } |
131 | | |
132 | | /** |
133 | | * Gets current line number. |
134 | | * |
135 | | * \return Line number. |
136 | | */ |
137 | | size_t getLine() const |
138 | 35 | { |
139 | 35 | return m_tokenizer.getLine(); |
140 | 35 | } |
141 | | |
142 | | /** |
143 | | * Gets current column number. |
144 | | * |
145 | | * \return Column number. |
146 | | */ |
147 | | size_t getColumn() const |
148 | 35 | { |
149 | 35 | return m_tokenizer.getColumn(); |
150 | 35 | } |
151 | | |
152 | | private: |
153 | | void parseElement(); |
154 | | void parseObject(); |
155 | | void parseMembers(); |
156 | | void parseMember(); |
157 | | void parseArray(); |
158 | | void parseElements(); |
159 | | |
160 | | void parseValue(); |
161 | | void visitValue() const; |
162 | | |
163 | | void checkToken(JsonToken token); |
164 | | void consumeToken(JsonToken token); |
165 | | JsonParserException createUnexpectedTokenException(Span<const JsonToken> expecting) const; |
166 | | |
167 | | static const std::array<JsonToken, 3> ELEMENT_TOKENS; |
168 | | |
169 | | BasicJsonTokenizer<ALLOC> m_tokenizer; |
170 | | IObserver& m_observer; |
171 | | }; |
172 | | |
173 | | template <typename ALLOC> |
174 | | const std::array<JsonToken, 3> BasicJsonParser<ALLOC>::ELEMENT_TOKENS = { |
175 | | JsonToken::BEGIN_OBJECT, |
176 | | JsonToken::BEGIN_ARRAY, |
177 | | JsonToken::VALUE |
178 | | }; |
179 | | |
180 | | template <typename ALLOC> |
181 | | void BasicJsonParser<ALLOC>::parseElement() |
182 | 367 | { |
183 | 367 | JsonToken token = m_tokenizer.getToken(); |
184 | | |
185 | 367 | if (token == JsonToken::BEGIN_ARRAY) |
186 | 39 | parseArray(); |
187 | 328 | else if (token == JsonToken::BEGIN_OBJECT) |
188 | 148 | parseObject(); |
189 | 180 | else if (token == JsonToken::VALUE) |
190 | 179 | parseValue(); |
191 | 1 | else |
192 | 1 | throw createUnexpectedTokenException(ELEMENT_TOKENS); |
193 | 367 | } |
194 | | |
195 | | template <typename ALLOC> |
196 | | void BasicJsonParser<ALLOC>::parseObject() |
197 | 148 | { |
198 | 148 | consumeToken(JsonToken::BEGIN_OBJECT); |
199 | 148 | m_observer.beginObject(); |
200 | | |
201 | 148 | if (m_tokenizer.getToken() == JsonToken::VALUE) |
202 | 144 | parseMembers(); |
203 | | |
204 | 148 | consumeToken(JsonToken::END_OBJECT); |
205 | 148 | m_observer.endObject(); |
206 | 148 | } |
207 | | |
208 | | template <typename ALLOC> |
209 | | void BasicJsonParser<ALLOC>::parseMembers() |
210 | 144 | { |
211 | 144 | parseMember(); |
212 | 218 | while (m_tokenizer.getToken() == JsonToken::ITEM_SEPARATOR) |
213 | 74 | { |
214 | 74 | m_tokenizer.next(); |
215 | 74 | parseMember(); |
216 | 74 | } |
217 | 144 | } |
218 | | |
219 | | template <typename ALLOC> |
220 | | void BasicJsonParser<ALLOC>::parseMember() |
221 | 218 | { |
222 | 218 | checkToken(JsonToken::VALUE); |
223 | 218 | const AnyHolder<ALLOC>& key = m_tokenizer.getValue(); |
224 | 218 | if (!key.template isType<string<ALLOC>>()) |
225 | 1 | { |
226 | 1 | throw JsonParserException("JsonParser:") << getLine() << ":" << getColumn() << |
227 | 1 | ": Key must be a string value!"; |
228 | 1 | } |
229 | 217 | m_observer.visitKey(key.template get<string<ALLOC>>()); |
230 | 217 | m_tokenizer.next(); |
231 | | |
232 | 217 | consumeToken(JsonToken::KEY_SEPARATOR); |
233 | | |
234 | 217 | parseElement(); |
235 | 217 | } |
236 | | |
237 | | template <typename ALLOC> |
238 | | void BasicJsonParser<ALLOC>::parseArray() |
239 | 39 | { |
240 | 39 | consumeToken(JsonToken::BEGIN_ARRAY); |
241 | 39 | m_observer.beginArray(); |
242 | | |
243 | 39 | if (std::find(ELEMENT_TOKENS.begin(), ELEMENT_TOKENS.end(), m_tokenizer.getToken()) != ELEMENT_TOKENS.end()) |
244 | 38 | parseElements(); |
245 | | |
246 | 39 | consumeToken(JsonToken::END_ARRAY); |
247 | 39 | m_observer.endArray(); |
248 | 39 | } |
249 | | |
250 | | template <typename ALLOC> |
251 | | void BasicJsonParser<ALLOC>::parseElements() |
252 | 38 | { |
253 | 38 | parseElement(); |
254 | 62 | while (m_tokenizer.getToken() == JsonToken::ITEM_SEPARATOR) |
255 | 24 | { |
256 | 24 | m_tokenizer.next(); |
257 | 24 | parseElement(); |
258 | 24 | } |
259 | 38 | } |
260 | | |
261 | | template <typename ALLOC> |
262 | | void BasicJsonParser<ALLOC>::parseValue() |
263 | 179 | { |
264 | 179 | visitValue(); |
265 | 179 | m_tokenizer.next(); |
266 | 179 | } |
267 | | |
268 | | template <typename ALLOC> |
269 | | void BasicJsonParser<ALLOC>::visitValue() const |
270 | 179 | { |
271 | 179 | const AnyHolder<ALLOC>& value = m_tokenizer.getValue(); |
272 | | |
273 | 179 | if (value.template isType<std::nullptr_t>()) |
274 | 3 | { |
275 | 3 | m_observer.visitValue(nullptr); |
276 | 3 | } |
277 | 176 | else if (value.template isType<bool>()) |
278 | 3 | { |
279 | 3 | m_observer.visitValue(value.template get<bool>()); |
280 | 3 | } |
281 | 173 | else if (value.template isType<int64_t>()) |
282 | 4 | { |
283 | 4 | m_observer.visitValue(value.template get<int64_t>()); |
284 | 4 | } |
285 | 169 | else if (value.template isType<uint64_t>()) |
286 | 87 | { |
287 | 87 | m_observer.visitValue(value.template get<uint64_t>()); |
288 | 87 | } |
289 | 82 | else if (value.template isType<double>()) |
290 | 3 | { |
291 | 3 | m_observer.visitValue(value.template get<double>()); |
292 | 3 | } |
293 | 79 | else |
294 | 79 | { |
295 | 79 | m_observer.visitValue(value.template get<string<ALLOC>>()); |
296 | 79 | } |
297 | 179 | } |
298 | | |
299 | | template <typename ALLOC> |
300 | | void BasicJsonParser<ALLOC>::checkToken(JsonToken token) |
301 | 735 | { |
302 | 735 | if (m_tokenizer.getToken() != token) |
303 | 5 | throw createUnexpectedTokenException({{token}}); |
304 | 735 | } |
305 | | |
306 | | template <typename ALLOC> |
307 | | void BasicJsonParser<ALLOC>::consumeToken(JsonToken token) |
308 | 517 | { |
309 | 517 | checkToken(token); |
310 | 517 | m_tokenizer.next(); |
311 | 517 | } |
312 | | |
313 | | template <typename ALLOC> |
314 | | JsonParserException BasicJsonParser<ALLOC>::createUnexpectedTokenException( |
315 | | Span<const JsonToken> expecting) const |
316 | 6 | { |
317 | 6 | JsonParserException error("JsonParser:"); |
318 | 6 | error << getLine() << ":" << getColumn() << ": unexpected token: " << m_tokenizer.getToken(); |
319 | 6 | if (expecting.size() == 1) |
320 | 5 | { |
321 | 5 | error << ", expecting " << expecting[0] << "!"; |
322 | 5 | } |
323 | 1 | else |
324 | 1 | { |
325 | 1 | error << ", expecting one of ["; |
326 | 4 | for (size_t i = 0; i < expecting.size(); ++i3 ) |
327 | 3 | { |
328 | 3 | if (i > 0) |
329 | 2 | error << ", "; |
330 | 3 | error << expecting[i]; |
331 | 3 | } |
332 | 1 | error << "]!"; |
333 | 1 | } |
334 | 6 | return error; |
335 | 6 | } |
336 | | |
337 | | /** Typedef to Json Parser provided for convenience - using default std::allocator<uint8_t>. */ |
338 | | using JsonParser = BasicJsonParser<>; |
339 | | |
340 | | } // namespace |
341 | | |
342 | | #endif // ZSERIO_JSON_PARSER_H_INC |