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 | 123 | 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), |
111 | | m_observer(observer) |
112 | 87 | {} |
113 | | |
114 | | /** |
115 | | * Parses single JSON element from the text stream. |
116 | | * |
117 | | * \return True when end-of-file is reached, false otherwise (i.e. another JSON element is present). |
118 | | * \throw JsonParserException When parsing fails. |
119 | | */ |
120 | | bool parse() |
121 | 94 | { |
122 | 94 | if (m_tokenizer.getToken() == JsonToken::BEGIN_OF_FILE) |
123 | 86 | { |
124 | 86 | m_tokenizer.next(); |
125 | 86 | } |
126 | | |
127 | 94 | if (m_tokenizer.getToken() == JsonToken::END_OF_FILE) |
128 | 1 | { |
129 | 1 | return true; |
130 | 1 | } |
131 | | |
132 | 93 | parseElement(); |
133 | | |
134 | 93 | return m_tokenizer.getToken() == JsonToken::END_OF_FILE; |
135 | 94 | } |
136 | | |
137 | | /** |
138 | | * Gets current line number. |
139 | | * |
140 | | * \return Line number. |
141 | | */ |
142 | | size_t getLine() const |
143 | 35 | { |
144 | 35 | return m_tokenizer.getLine(); |
145 | 35 | } |
146 | | |
147 | | /** |
148 | | * Gets current column number. |
149 | | * |
150 | | * \return Column number. |
151 | | */ |
152 | | size_t getColumn() const |
153 | 35 | { |
154 | 35 | return m_tokenizer.getColumn(); |
155 | 35 | } |
156 | | |
157 | | private: |
158 | | void parseElement(); |
159 | | void parseObject(); |
160 | | void parseMembers(); |
161 | | void parseMember(); |
162 | | void parseArray(); |
163 | | void parseElements(); |
164 | | |
165 | | void parseValue(); |
166 | | void visitValue() const; |
167 | | |
168 | | void checkToken(JsonToken token); |
169 | | void consumeToken(JsonToken token); |
170 | | JsonParserException createUnexpectedTokenException(Span<const JsonToken> expecting) const; |
171 | | |
172 | | static const std::array<JsonToken, 3> ELEMENT_TOKENS; |
173 | | |
174 | | BasicJsonTokenizer<ALLOC> m_tokenizer; |
175 | | IObserver& m_observer; |
176 | | }; |
177 | | |
178 | | template <typename ALLOC> |
179 | | const std::array<JsonToken, 3> BasicJsonParser<ALLOC>::ELEMENT_TOKENS = { |
180 | | JsonToken::BEGIN_OBJECT, JsonToken::BEGIN_ARRAY, JsonToken::VALUE}; |
181 | | |
182 | | template <typename ALLOC> |
183 | | void BasicJsonParser<ALLOC>::parseElement() |
184 | 393 | { |
185 | 393 | JsonToken token = m_tokenizer.getToken(); |
186 | | |
187 | 393 | if (token == JsonToken::BEGIN_ARRAY) |
188 | 43 | { |
189 | 43 | parseArray(); |
190 | 43 | } |
191 | 350 | else if (token == JsonToken::BEGIN_OBJECT) |
192 | 156 | { |
193 | 156 | parseObject(); |
194 | 156 | } |
195 | 194 | else if (token == JsonToken::VALUE) |
196 | 193 | { |
197 | 193 | parseValue(); |
198 | 193 | } |
199 | 1 | else |
200 | 1 | { |
201 | 1 | throw createUnexpectedTokenException(ELEMENT_TOKENS); |
202 | 1 | } |
203 | 393 | } |
204 | | |
205 | | template <typename ALLOC> |
206 | | void BasicJsonParser<ALLOC>::parseObject() |
207 | 156 | { |
208 | 156 | consumeToken(JsonToken::BEGIN_OBJECT); |
209 | 156 | m_observer.beginObject(); |
210 | | |
211 | 156 | if (m_tokenizer.getToken() == JsonToken::VALUE) |
212 | 152 | { |
213 | 152 | parseMembers(); |
214 | 152 | } |
215 | | |
216 | 156 | consumeToken(JsonToken::END_OBJECT); |
217 | 156 | m_observer.endObject(); |
218 | 156 | } |
219 | | |
220 | | template <typename ALLOC> |
221 | | void BasicJsonParser<ALLOC>::parseMembers() |
222 | 152 | { |
223 | 152 | parseMember(); |
224 | 240 | while (m_tokenizer.getToken() == JsonToken::ITEM_SEPARATOR) |
225 | 88 | { |
226 | 88 | m_tokenizer.next(); |
227 | 88 | parseMember(); |
228 | 88 | } |
229 | 152 | } |
230 | | |
231 | | template <typename ALLOC> |
232 | | void BasicJsonParser<ALLOC>::parseMember() |
233 | 240 | { |
234 | 240 | checkToken(JsonToken::VALUE); |
235 | 240 | const AnyHolder<ALLOC>& key = m_tokenizer.getValue(); |
236 | 240 | if (!key.template isType<string<ALLOC>>()) |
237 | 1 | { |
238 | 1 | throw JsonParserException("JsonParser:") |
239 | 1 | << getLine() << ":" << getColumn() << ": Key must be a string value!"; |
240 | 1 | } |
241 | 239 | m_observer.visitKey(key.template get<string<ALLOC>>()); |
242 | 239 | m_tokenizer.next(); |
243 | | |
244 | 239 | consumeToken(JsonToken::KEY_SEPARATOR); |
245 | | |
246 | 239 | parseElement(); |
247 | 239 | } |
248 | | |
249 | | template <typename ALLOC> |
250 | | void BasicJsonParser<ALLOC>::parseArray() |
251 | 43 | { |
252 | 43 | consumeToken(JsonToken::BEGIN_ARRAY); |
253 | 43 | m_observer.beginArray(); |
254 | | |
255 | 43 | if (std::find(ELEMENT_TOKENS.begin(), ELEMENT_TOKENS.end(), m_tokenizer.getToken()) != ELEMENT_TOKENS.end()) |
256 | 39 | { |
257 | 39 | parseElements(); |
258 | 39 | } |
259 | | |
260 | 43 | consumeToken(JsonToken::END_ARRAY); |
261 | 43 | m_observer.endArray(); |
262 | 43 | } |
263 | | |
264 | | template <typename ALLOC> |
265 | | void BasicJsonParser<ALLOC>::parseElements() |
266 | 39 | { |
267 | 39 | parseElement(); |
268 | 64 | while (m_tokenizer.getToken() == JsonToken::ITEM_SEPARATOR) |
269 | 25 | { |
270 | 25 | m_tokenizer.next(); |
271 | 25 | parseElement(); |
272 | 25 | } |
273 | 39 | } |
274 | | |
275 | | template <typename ALLOC> |
276 | | void BasicJsonParser<ALLOC>::parseValue() |
277 | 193 | { |
278 | 193 | visitValue(); |
279 | 193 | m_tokenizer.next(); |
280 | 193 | } |
281 | | |
282 | | template <typename ALLOC> |
283 | | void BasicJsonParser<ALLOC>::visitValue() const |
284 | 193 | { |
285 | 193 | const AnyHolder<ALLOC>& value = m_tokenizer.getValue(); |
286 | | |
287 | 193 | if (value.template isType<std::nullptr_t>()) |
288 | 3 | { |
289 | 3 | m_observer.visitValue(nullptr); |
290 | 3 | } |
291 | 190 | else if (value.template isType<bool>()) |
292 | 3 | { |
293 | 3 | m_observer.visitValue(value.template get<bool>()); |
294 | 3 | } |
295 | 187 | else if (value.template isType<int64_t>()) |
296 | 6 | { |
297 | 6 | m_observer.visitValue(value.template get<int64_t>()); |
298 | 6 | } |
299 | 181 | else if (value.template isType<uint64_t>()) |
300 | 97 | { |
301 | 97 | m_observer.visitValue(value.template get<uint64_t>()); |
302 | 97 | } |
303 | 84 | else if (value.template isType<double>()) |
304 | 3 | { |
305 | 3 | m_observer.visitValue(value.template get<double>()); |
306 | 3 | } |
307 | 81 | else |
308 | 81 | { |
309 | 81 | m_observer.visitValue(value.template get<string<ALLOC>>()); |
310 | 81 | } |
311 | 193 | } |
312 | | |
313 | | template <typename ALLOC> |
314 | | void BasicJsonParser<ALLOC>::checkToken(JsonToken token) |
315 | 803 | { |
316 | 803 | if (m_tokenizer.getToken() != token) |
317 | 5 | { |
318 | 5 | throw createUnexpectedTokenException({{token}}); |
319 | 5 | } |
320 | 803 | } |
321 | | |
322 | | template <typename ALLOC> |
323 | | void BasicJsonParser<ALLOC>::consumeToken(JsonToken token) |
324 | 563 | { |
325 | 563 | checkToken(token); |
326 | 563 | m_tokenizer.next(); |
327 | 563 | } |
328 | | |
329 | | template <typename ALLOC> |
330 | | JsonParserException BasicJsonParser<ALLOC>::createUnexpectedTokenException( |
331 | | Span<const JsonToken> expecting) const |
332 | 6 | { |
333 | 6 | JsonParserException error("JsonParser:"); |
334 | 6 | error << getLine() << ":" << getColumn() << ": unexpected token: " << m_tokenizer.getToken(); |
335 | 6 | if (expecting.size() == 1) |
336 | 5 | { |
337 | 5 | error << ", expecting " << expecting[0] << "!"; |
338 | 5 | } |
339 | 1 | else |
340 | 1 | { |
341 | 1 | error << ", expecting one of ["; |
342 | 4 | for (size_t i = 0; i < expecting.size(); ++i3 ) |
343 | 3 | { |
344 | 3 | if (i > 0) |
345 | 2 | { |
346 | 2 | error << ", "; |
347 | 2 | } |
348 | 3 | error << expecting[i]; |
349 | 3 | } |
350 | 1 | error << "]!"; |
351 | 1 | } |
352 | 6 | return error; |
353 | 6 | } |
354 | | |
355 | | /** Typedef to Json Parser provided for convenience - using default std::allocator<uint8_t>. */ |
356 | | using JsonParser = BasicJsonParser<>; |
357 | | |
358 | | } // namespace zserio |
359 | | |
360 | | #endif // ZSERIO_JSON_PARSER_H_INC |