StructuralJsonParser.cpp
Go to the documentation of this file.
1 /*
2 * This file is part of ArmarX.
3 *
4 * ArmarX is free software; you can redistribute it and/or modify
5 * it under the terms of the GNU General Public License version 2 as
6 * published by the Free Software Foundation.
7 *
8 * ArmarX is distributed in the hope that it will be useful, but
9 * WITHOUT ANY WARRANTY; without even the implied warranty of
10 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
11 * GNU General Public License for more details.
12 *
13 * You should have received a copy of the GNU General Public License
14 * along with this program. If not, see <http://www.gnu.org/licenses/>.
15 *
16 * @author Simon Ottenhaus (simon dot ottenhaus at kit dot edu)
17 * @copyright http://www.gnu.org/licenses/gpl-2.0.txt
18 * GNU General Public License
19 */
20 
21 
22 #include "StructuralJsonParser.h"
23 
24 #include "SimpleLexer.h"
25 
26 namespace armarx
27 {
28  StructuralJsonParser::StructuralJsonParser(const std::string& src, bool acceptSingleValue, bool accceptJsStyleKeys)
29  : lexer(new SimpleLexer(src)), acceptSingleValue(acceptSingleValue), accceptJsStyleKeys(accceptJsStyleKeys), previousTokenEndOffset(-1, -1, -1)
30  {
31  // regex taken from http://stackoverflow.com/questions/2583472/regex-to-validate-json
32 
33  lexer->addRule(eWhitespace, "Whitespace", "[\\r\\n\\s]+");
34  lexer->addRule(eOpeningCurlyBracket, "{", "\\{");
35  lexer->addRule(eClosingCurlyBracket, "}", "\\}");
36  lexer->addRule(eOpeningSquareBracket, "[", "\\[");
37  lexer->addRule(eClosingSquareBracket, "]", "\\]");
38  lexer->addRule(eComma, ",", ",");
39  lexer->addRule(eColon, ":", "\\:");
40  lexer->addRule(eNumber, "Number", "-?\\d+(\\.\\d+)?([eE][+-]?\\d+)?"); // also accept leading 0
41  lexer->addRule(eString, "String", "\"([^\\\\\\\"]|\\\\.)*\""); // use very simpe string parsing
42  lexer->addRule(eBoolean, "Boolean", "true|false");
43  lexer->addRule(eNull, "Null", "null");
44  lexer->addRule(eId, "ID", "[_A-Za-z]\\w*"); // add ID last to avoid detecting true|false|null as ID
45 
46  }
47 
49  {
50 
51  }
52 
54  {
55  lexer->reset();
56  next();
57  parsedJson = p_json();
58 
59  if (!iserr())
60  {
61  while (lexer->currentTokenId == eWhitespace)
62  {
63  lexer->nextToken();
64  }
65 
66  if (lexer->currentTokenId != lexer->tokenFin)
67  {
68  error("end of string");
69  }
70  }
71  }
72 
73  void StructuralJsonParser::next()
74  {
75  lexer->nextToken();
76  previousTokenEndOffset = lexer->getPositionInfo(lexer->pos);
77 
78  while (lexer->currentTokenId == eWhitespace)
79  {
80  lexer->nextToken();
81  }
82  }
83 
84  JsonDataPtr StructuralJsonParser::p_json()
85  {
86  if (acceptSingleValue)
87  {
88  return p_item();
89  }
90  else if (lexer->currentTokenId == eOpeningCurlyBracket)
91  {
92  return p_object();
93  }
94  else if (lexer->currentTokenId == eOpeningSquareBracket)
95  {
96  return p_array();
97  }
98  else
99  {
100  return error("{ or [");
101  }
102  }
103 
104  JsonDataPtr StructuralJsonParser::p_object()
105  {
106  JsonObjectPtr o(new JsonObject());
107  o->setLexerStartOffset(lexer->getPositionInfo(lexer->pos));
108  next(); // consume {
109 
110  if (lexer->currentTokenId == eClosingCurlyBracket)
111  {
112  next(); // consume }
113  o->setLexerEndOffset(previousTokenEndOffset);
114  return o;
115  }
116 
117  if (!accceptJsStyleKeys && lexer->currentTokenId != eString)
118  {
119  return error("String or '}'", o);
120  }
121  else if (accceptJsStyleKeys && lexer->currentTokenId != eString && lexer->currentTokenId != eId)
122  {
123  return error("String, ID or '}'", o);
124  }
125 
126  p_pair(o);
127 
128  if (iserr())
129  {
130  return o;
131  }
132 
133  while (lexer->currentTokenId == eComma)
134  {
135  next(); // consume ,
136  p_pair(o);
137 
138  if (iserr())
139  {
140  return o;
141  }
142  }
143 
144  if (lexer->currentTokenId == eClosingCurlyBracket)
145  {
146  next(); // consume }
147  o->setLexerEndOffset(previousTokenEndOffset);
148  return o;
149  }
150  else
151  {
152  return error("',' or '}'", o);
153  }
154  }
155 
156  void StructuralJsonParser::p_pair(JsonObjectPtr o)
157  {
158  if (!accceptJsStyleKeys && lexer->currentTokenId != eString)
159  {
160  error("String");
161  return;
162  }
163  else if (accceptJsStyleKeys && lexer->currentTokenId != eString && lexer->currentTokenId != eId)
164  {
165  error("String or ID");
166  return;
167  }
168 
169  std::string key;
170 
171  if (accceptJsStyleKeys && lexer->currentTokenId == eId)
172  {
173  key = lexer->currentTokenValue;
174  }
175  else if (!DequoteString(lexer->currentTokenValue, key))
176  {
177  stringerror(key);
178  return;
179  }
180 
181  next(); // consume key
182 
183  if (lexer->currentTokenId != eColon)
184  {
185  o->add(key, JsonDataPtr());
186  error("':'");
187  return;
188  }
189 
190  next(); // consue :
191  JsonDataPtr value = p_item();
192  o->add(key, value);
193 
194  if (iserr())
195  {
196  return;
197  }
198 
199  }
200 
201  JsonDataPtr StructuralJsonParser::p_array()
202  {
203  JsonArrayPtr a(new JsonArray());
204  a->setLexerStartOffset(lexer->getPositionInfo(lexer->pos));
205  next(); // consume [
206 
207  if (lexer->currentTokenId == eClosingSquareBracket)
208  {
209  next(); // consume ]
210  a->setLexerEndOffset(previousTokenEndOffset);
211  return a;
212  }
213 
214  int posBeforeItem = lexer->pos;
215  JsonDataPtr item1 = p_item();
216  a->add(item1);
217 
218  if (iserr())
219  {
220  if (posBeforeItem == lexer->pos)
221  {
222  // No Token was consumed by p_item() => add ']' to expected tokens in error message.
223  return error("']', " + expected, a);
224  }
225  else
226  {
227  return a;
228  }
229  }
230 
231  while (lexer->currentTokenId == eComma)
232  {
233  next(); // consume ,
234  JsonDataPtr item = p_item();
235  a->add(item);
236 
237  if (iserr())
238  {
239  return a;
240  }
241  }
242 
243  if (lexer->currentTokenId == eClosingSquareBracket)
244  {
245  next(); // consume ]
246  a->setLexerEndOffset(previousTokenEndOffset);
247  return a;
248  }
249  else
250  {
251  return error(", or ]", a);
252  }
253  }
254 
255  // Item = String | Number | true | false | null | Object | Array
256  JsonDataPtr StructuralJsonParser::p_item()
257  {
258  switch (lexer->currentTokenId)
259  {
260  case eString:
261  case eNumber:
262  case eBoolean:
263  case eNull:
264  return p_leaf();
265 
267  return p_object();
268 
270  return p_array();
271  break;
272 
273  default:
274  return error("'{', '[', String, Number, 'true', 'false' or 'null'");
275  }
276 
277  }
278 
279  JsonDataPtr StructuralJsonParser::p_leaf()
280  {
282  std::string val;
283 
284  switch (lexer->currentTokenId)
285  {
286  case eString:
287 
288  if (!DequoteString(lexer->currentTokenValue, val))
289  {
290  return stringerror(val);
291  }
292 
293  value.reset(new JsonValue(JsonValue::eString, val));
294  break;
295 
296  case eNumber:
297  value.reset(new JsonValue(JsonValue::eNumber, lexer->currentTokenValue));
298  break;
299 
300  case eBoolean:
301  value.reset(new JsonValue(JsonValue::eBool, lexer->currentTokenValue));
302  break;
303 
304  case eNull:
305  value.reset(new JsonValue(JsonValue::eNull, lexer->currentTokenValue));
306  break;
307 
308  default:
309  return error("String, Number, 'true', 'false' or 'null'");
310  }
311 
312  value->setLexerStartOffset(lexer->getPositionInfo(lexer->pos));
313  next(); // consume eString | eNumber | eBoolean | eNull
314  value->setLexerEndOffset(previousTokenEndOffset);
315  return value;
316  }
317 
318  JsonDataPtr StructuralJsonParser::error(const std::string& expected, const JsonDataPtr& toReturn)
319  {
320  this->err = "Unexpected Token " + lexer->tokenIdToName(lexer->currentTokenId) + " at " + getlongerrposstr() + ". Expecting " + expected + ".";
321  this->expected = expected;
322  return toReturn;
323  }
324 
325  JsonDataPtr StructuralJsonParser::stringerror(const std::string& error, const JsonDataPtr& toReturn)
326  {
327  this->err = "invalid string at " + getlongerrposstr() + ":" + error + ".";
328  this->expected = expected;
329  return toReturn;
330  }
331 
333  {
334  return err.length() > 0;
335  }
336 
338  {
339  return err;
340  }
341 
342  void StructuralJsonParser::geterrpos(int& line, int& col)
343  {
344  lexer->positionToLineAndColumn(lexer->lastPos, line, col);
345  }
346 
348  {
349  int line, col;
350  lexer->positionToLineAndColumn(lexer->lastPos, line, col);
351  return "L" + std::to_string(line) + " C" + std::to_string(col);
352  }
353 
355  {
356  int line, col;
357  lexer->positionToLineAndColumn(lexer->lastPos, line, col);
358  return "line " + std::to_string(line) + " column " + std::to_string(col);
359  }
360 
361  bool StructuralJsonParser::DequoteString(std::string s, std::string& res)
362  {
363  // *INDENT-OFF*
364  res = "";
365  std::string::const_iterator it = s.begin();
366  std::string::const_iterator end = s.end() - 1;
367 
368  if (s.length() < 1 || *it != '"')
369  {
370  res = "Missing starting \"";
371  return false;
372  }
373 
374  it++; // consume starting "
375 
376  if (s.length() < 2 || *end != '"')
377  {
378  res = "Missing ending \"";
379  return false;
380  }
381 
382  while (it < end)
383  {
384  char c = *it++;
385 
386  if (c == '\\' && it != s.end())
387  {
388  switch (*it++)
389  {
390  case '\\':
391  res += '\\';
392  break;
393 
394  case '/':
395  res += '/';
396  break;
397 
398  case '"':
399  res += '"';
400  break;
401 
402  case 'b':
403  res += '\b';
404  break;
405 
406  case 'f':
407  res += '\f';
408  break;
409 
410  case 'n':
411  res += '\n';
412  break;
413 
414  case 'r':
415  res += '\r';
416  break;
417 
418  case 't':
419  res += '\t';
420  break;
421 
422  case 'u':
423  res = "\\u is not supported";
424  return false;
425 
426  default:
427  res = "invalid escape sequence";
428  return false;
429  }
430  }
431  else
432  {
433  res += c;
434  }
435 
436  }
437 
438  return true;
439  // *INDENT-ON*
440  }
441 }
armarx::StructuralJsonParser::eOpeningSquareBracket
@ eOpeningSquareBracket
Definition: StructuralJsonParser.h:38
armarx::StructuralJsonParser::eColon
@ eColon
Definition: StructuralJsonParser.h:39
armarx::JsonValue::eNumber
@ eNumber
Definition: JsonValue.h:38
armarx::StructuralJsonParser::getlongerrposstr
std::string getlongerrposstr()
Definition: StructuralJsonParser.cpp:354
armarx::JsonValuePtr
std::shared_ptr< JsonValue > JsonValuePtr
Definition: JsonValue.h:30
armarx::JsonArrayPtr
std::shared_ptr< JsonArray > JsonArrayPtr
Definition: JsonArray.h:32
StructuralJsonParser.h
armarx::StructuralJsonParser::geterrpos
void geterrpos(int &line, int &col)
Definition: StructuralJsonParser.cpp:342
c
constexpr T c
Definition: UnscentedKalmanFilterTest.cpp:43
armarx::JsonValue::eString
@ eString
Definition: JsonValue.h:38
armarx::StructuralJsonParser::eNumber
@ eNumber
Definition: StructuralJsonParser.h:39
armarx::ctrlutil::a
double a(double t, double a0, double j)
Definition: CtrlUtil.h:45
cxxopts::value
std::shared_ptr< Value > value()
Definition: cxxopts.hpp:926
armarx::JsonValue::eNull
@ eNull
Definition: JsonValue.h:38
armarx::StructuralJsonParser::eClosingCurlyBracket
@ eClosingCurlyBracket
Definition: StructuralJsonParser.h:38
armarx::StructuralJsonParser::DequoteString
static bool DequoteString(std::string str, std::string &res)
Definition: StructuralJsonParser.cpp:361
armarx::JsonValue::eBool
@ eBool
Definition: JsonValue.h:38
armarx::StructuralJsonParser::StructuralJsonParser
StructuralJsonParser(const std::string &src, bool acceptSingleValue=true, bool accceptJsStyleKeys=true)
Definition: StructuralJsonParser.cpp:28
armarx::StructuralJsonParser::eClosingSquareBracket
@ eClosingSquareBracket
Definition: StructuralJsonParser.h:38
armarx::StructuralJsonParser::eString
@ eString
Definition: StructuralJsonParser.h:39
armarx::StructuralJsonParser::iserr
bool iserr()
Definition: StructuralJsonParser.cpp:332
armarx::to_string
const std::string & to_string(const std::string &s)
Definition: StringHelpers.h:40
armarx::StructuralJsonParser::eComma
@ eComma
Definition: StructuralJsonParser.h:39
armarx::StructuralJsonParser::geterrposstr
std::string geterrposstr()
Definition: StructuralJsonParser.cpp:347
armarx::StructuralJsonParser::parse
void parse()
Definition: StructuralJsonParser.cpp:53
armarx::StructuralJsonParser::eWhitespace
@ eWhitespace
Definition: StructuralJsonParser.h:38
armarx::SimpleLexer
Definition: SimpleLexer.h:29
armarx::StructuralJsonParser::geterr
std::string geterr()
Definition: StructuralJsonParser.cpp:337
armarx::JsonDataPtr
std::shared_ptr< JsonData > JsonDataPtr
Definition: JsonData.h:31
armarx::StructuralJsonParser::eOpeningCurlyBracket
@ eOpeningCurlyBracket
Definition: StructuralJsonParser.h:38
armarx::StructuralJsonParser::~StructuralJsonParser
~StructuralJsonParser()
Definition: StructuralJsonParser.cpp:48
armarx::StructuralJsonParser::eNull
@ eNull
Definition: StructuralJsonParser.h:39
armarx::StructuralJsonParser::parsedJson
JsonDataPtr parsedJson
Definition: StructuralJsonParser.h:47
armarx::StructuralJsonParser::eId
@ eId
Definition: StructuralJsonParser.h:39
armarx::ctrlutil::s
double s(double t, double s0, double v0, double a0, double j)
Definition: CtrlUtil.h:33
armarx
This file offers overloads of toIce() and fromIce() functions for STL container types.
Definition: ArmarXTimeserver.cpp:28
armarx::StructuralJsonParser::eBoolean
@ eBoolean
Definition: StructuralJsonParser.h:39
armarx::JsonObjectPtr
std::shared_ptr< JsonObject > JsonObjectPtr
Definition: JsonObject.h:34
SimpleLexer.h