Zserio C++17 runtime library  0.5.0
Built for Zserio 2.17.0
JsonParser.h
Go to the documentation of this file.
1 #ifndef ZSERIO_JSON_PARSER_H_INC
2 #define ZSERIO_JSON_PARSER_H_INC
3 
4 #include <string_view>
5 
6 #include "zserio/Any.h"
7 #include "zserio/JsonDecoder.h"
8 #include "zserio/JsonTokenizer.h"
9 #include "zserio/Span.h"
10 #include "zserio/String.h"
11 
12 namespace zserio
13 {
14 
20 template <typename ALLOC = std::allocator<uint8_t>>
22 {
23 public:
27  class IObserver
28  {
29  public:
33  virtual ~IObserver() = default;
34 
38  virtual void beginObject() = 0;
39 
43  virtual void endObject() = 0;
44 
48  virtual void beginArray() = 0;
49 
53  virtual void endArray() = 0;
54 
60  virtual void visitKey(std::string_view key) = 0;
61 
67  virtual void visitValue(std::nullptr_t nullValue) = 0;
68 
74  virtual void visitValue(bool boolValue) = 0;
75 
81  virtual void visitValue(int64_t intValue) = 0;
82 
88  virtual void visitValue(uint64_t uintValue) = 0;
89 
95  virtual void visitValue(double doubleValue) = 0;
96 
102  virtual void visitValue(std::string_view stringValue) = 0;
103  };
104 
112  BasicJsonParser(std::istream& in, IObserver& observer, const ALLOC& allocator = ALLOC()) :
113  m_tokenizer(in, allocator),
114  m_observer(observer)
115  {}
116 
123  bool parse()
124  {
125  if (m_tokenizer.getToken() == JsonToken::BEGIN_OF_FILE)
126  {
127  m_tokenizer.next();
128  }
129 
130  if (m_tokenizer.getToken() == JsonToken::END_OF_FILE)
131  {
132  return true;
133  }
134 
135  parseElement();
136 
137  return m_tokenizer.getToken() == JsonToken::END_OF_FILE;
138  }
139 
145  size_t getLine() const
146  {
147  return m_tokenizer.getLine();
148  }
149 
155  size_t getColumn() const
156  {
157  return m_tokenizer.getColumn();
158  }
159 
160 private:
161  void parseElement();
162  void parseObject();
163  void parseMembers();
164  void parseMember();
165  void parseArray();
166  void parseElements();
167 
168  void parseValue();
169  void visitValue() const;
170 
171  void checkToken(JsonToken token);
172  void consumeToken(JsonToken token);
173  JsonParserException createUnexpectedTokenException(Span<const JsonToken> expecting) const;
174 
175  static const std::array<JsonToken, 3> ELEMENT_TOKENS;
176 
177  BasicJsonTokenizer<ALLOC> m_tokenizer;
178  IObserver& m_observer;
179 };
180 
181 template <typename ALLOC>
182 const std::array<JsonToken, 3> BasicJsonParser<ALLOC>::ELEMENT_TOKENS = {
184 
185 template <typename ALLOC>
186 void BasicJsonParser<ALLOC>::parseElement()
187 {
188  JsonToken token = m_tokenizer.getToken();
189 
190  if (token == JsonToken::BEGIN_ARRAY)
191  {
192  parseArray();
193  }
194  else if (token == JsonToken::BEGIN_OBJECT)
195  {
196  parseObject();
197  }
198  else if (token == JsonToken::VALUE)
199  {
200  parseValue();
201  }
202  else
203  {
204  throw createUnexpectedTokenException(ELEMENT_TOKENS);
205  }
206 }
207 
208 template <typename ALLOC>
209 void BasicJsonParser<ALLOC>::parseObject()
210 {
211  consumeToken(JsonToken::BEGIN_OBJECT);
212  m_observer.beginObject();
213 
214  if (m_tokenizer.getToken() == JsonToken::VALUE)
215  {
216  parseMembers();
217  }
218 
219  consumeToken(JsonToken::END_OBJECT);
220  m_observer.endObject();
221 }
222 
223 template <typename ALLOC>
224 void BasicJsonParser<ALLOC>::parseMembers()
225 {
226  parseMember();
227  while (m_tokenizer.getToken() == JsonToken::ITEM_SEPARATOR)
228  {
229  m_tokenizer.next();
230  parseMember();
231  }
232 }
233 
234 template <typename ALLOC>
235 void BasicJsonParser<ALLOC>::parseMember()
236 {
237  checkToken(JsonToken::VALUE);
238  const BasicAny<ALLOC>& key = m_tokenizer.getValue();
239  if (!key.template isType<BasicString<RebindAlloc<ALLOC, char>>>())
240  {
241  throw JsonParserException("JsonParser:")
242  << getLine() << ":" << getColumn() << ": Key must be a string value!";
243  }
244  m_observer.visitKey(key.template get<BasicString<RebindAlloc<ALLOC, char>>>());
245  m_tokenizer.next();
246 
247  consumeToken(JsonToken::KEY_SEPARATOR);
248 
249  parseElement();
250 }
251 
252 template <typename ALLOC>
253 void BasicJsonParser<ALLOC>::parseArray()
254 {
255  consumeToken(JsonToken::BEGIN_ARRAY);
256  m_observer.beginArray();
257 
258  if (std::find(ELEMENT_TOKENS.begin(), ELEMENT_TOKENS.end(), m_tokenizer.getToken()) != ELEMENT_TOKENS.end())
259  {
260  parseElements();
261  }
262 
263  consumeToken(JsonToken::END_ARRAY);
264  m_observer.endArray();
265 }
266 
267 template <typename ALLOC>
268 void BasicJsonParser<ALLOC>::parseElements()
269 {
270  parseElement();
271  while (m_tokenizer.getToken() == JsonToken::ITEM_SEPARATOR)
272  {
273  m_tokenizer.next();
274  parseElement();
275  }
276 }
277 
278 template <typename ALLOC>
279 void BasicJsonParser<ALLOC>::parseValue()
280 {
281  visitValue();
282  m_tokenizer.next();
283 }
284 
285 template <typename ALLOC>
286 void BasicJsonParser<ALLOC>::visitValue() const
287 {
288  const BasicAny<ALLOC>& value = m_tokenizer.getValue();
289 
290  if (value.template isType<std::nullptr_t>())
291  {
292  m_observer.visitValue(nullptr);
293  }
294  else if (value.template isType<bool>())
295  {
296  m_observer.visitValue(value.template get<bool>());
297  }
298  else if (value.template isType<int64_t>())
299  {
300  m_observer.visitValue(value.template get<int64_t>());
301  }
302  else if (value.template isType<uint64_t>())
303  {
304  m_observer.visitValue(value.template get<uint64_t>());
305  }
306  else if (value.template isType<double>())
307  {
308  m_observer.visitValue(value.template get<double>());
309  }
310  else
311  {
312  m_observer.visitValue(value.template get<BasicString<RebindAlloc<ALLOC, char>>>());
313  }
314 }
315 
316 template <typename ALLOC>
317 void BasicJsonParser<ALLOC>::checkToken(JsonToken token)
318 {
319  if (m_tokenizer.getToken() != token)
320  {
321  throw createUnexpectedTokenException({{token}});
322  }
323 }
324 
325 template <typename ALLOC>
326 void BasicJsonParser<ALLOC>::consumeToken(JsonToken token)
327 {
328  checkToken(token);
329  m_tokenizer.next();
330 }
331 
332 template <typename ALLOC>
333 JsonParserException BasicJsonParser<ALLOC>::createUnexpectedTokenException(
334  Span<const JsonToken> expecting) const
335 {
336  JsonParserException error("JsonParser:");
337  error << getLine() << ":" << getColumn() << ": unexpected token: " << m_tokenizer.getToken();
338  if (expecting.size() == 1)
339  {
340  error << ", expecting " << expecting[0] << "!";
341  }
342  else
343  {
344  error << ", expecting one of [";
345  for (size_t i = 0; i < expecting.size(); ++i)
346  {
347  if (i > 0)
348  {
349  error << ", ";
350  }
351  error << expecting[i];
352  }
353  error << "]!";
354  }
355  return error;
356 }
357 
360 
361 } // namespace zserio
362 
363 #endif // ZSERIO_JSON_PARSER_H_INC
virtual void visitValue(uint64_t uintValue)=0
virtual void visitValue(int64_t intValue)=0
virtual void visitKey(std::string_view key)=0
virtual void visitValue(std::nullptr_t nullValue)=0
virtual void visitValue(double doubleValue)=0
virtual void visitValue(bool boolValue)=0
virtual void visitValue(std::string_view stringValue)=0
size_t getLine() const
Definition: JsonParser.h:145
size_t getColumn() const
Definition: JsonParser.h:155
BasicJsonParser(std::istream &in, IObserver &observer, const ALLOC &allocator=ALLOC())
Definition: JsonParser.h:112
std::basic_string< char, std::char_traits< char >, ALLOC > BasicString
Definition: String.h:17
decltype(auto) get(BasicVariant< ALLOC, INDEX, T... > &var)
Definition: Variant.h:812