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 {
29  bool acceptSingleValue,
30  bool accceptJsStyleKeys) :
31  lexer(new SimpleLexer(src)),
32  acceptSingleValue(acceptSingleValue),
33  accceptJsStyleKeys(accceptJsStyleKeys),
34  previousTokenEndOffset(-1, -1, -1)
35  {
36  // regex taken from http://stackoverflow.com/questions/2583472/regex-to-validate-json
37 
38  lexer->addRule(eWhitespace, "Whitespace", "[\\r\\n\\s]+");
39  lexer->addRule(eOpeningCurlyBracket, "{", "\\{");
40  lexer->addRule(eClosingCurlyBracket, "}", "\\}");
41  lexer->addRule(eOpeningSquareBracket, "[", "\\[");
42  lexer->addRule(eClosingSquareBracket, "]", "\\]");
43  lexer->addRule(eComma, ",", ",");
44  lexer->addRule(eColon, ":", "\\:");
45  lexer->addRule(
46  eNumber, "Number", "-?\\d+(\\.\\d+)?([eE][+-]?\\d+)?"); // also accept leading 0
47  lexer->addRule(
48  eString, "String", "\"([^\\\\\\\"]|\\\\.)*\""); // use very simpe string parsing
49  lexer->addRule(eBoolean, "Boolean", "true|false");
50  lexer->addRule(eNull, "Null", "null");
51  lexer->addRule(
52  eId, "ID", "[_A-Za-z]\\w*"); // add ID last to avoid detecting true|false|null as ID
53  }
54 
56  {
57  }
58 
59  void
61  {
62  lexer->reset();
63  next();
64  parsedJson = p_json();
65 
66  if (!iserr())
67  {
68  while (lexer->currentTokenId == eWhitespace)
69  {
70  lexer->nextToken();
71  }
72 
73  if (lexer->currentTokenId != lexer->tokenFin)
74  {
75  error("end of string");
76  }
77  }
78  }
79 
80  void
81  StructuralJsonParser::next()
82  {
83  lexer->nextToken();
84  previousTokenEndOffset = lexer->getPositionInfo(lexer->pos);
85 
86  while (lexer->currentTokenId == eWhitespace)
87  {
88  lexer->nextToken();
89  }
90  }
91 
93  StructuralJsonParser::p_json()
94  {
95  if (acceptSingleValue)
96  {
97  return p_item();
98  }
99  else if (lexer->currentTokenId == eOpeningCurlyBracket)
100  {
101  return p_object();
102  }
103  else if (lexer->currentTokenId == eOpeningSquareBracket)
104  {
105  return p_array();
106  }
107  else
108  {
109  return error("{ or [");
110  }
111  }
112 
114  StructuralJsonParser::p_object()
115  {
116  JsonObjectPtr o(new JsonObject());
117  o->setLexerStartOffset(lexer->getPositionInfo(lexer->pos));
118  next(); // consume {
119 
120  if (lexer->currentTokenId == eClosingCurlyBracket)
121  {
122  next(); // consume }
123  o->setLexerEndOffset(previousTokenEndOffset);
124  return o;
125  }
126 
127  if (!accceptJsStyleKeys && lexer->currentTokenId != eString)
128  {
129  return error("String or '}'", o);
130  }
131  else if (accceptJsStyleKeys && lexer->currentTokenId != eString &&
132  lexer->currentTokenId != eId)
133  {
134  return error("String, ID or '}'", o);
135  }
136 
137  p_pair(o);
138 
139  if (iserr())
140  {
141  return o;
142  }
143 
144  while (lexer->currentTokenId == eComma)
145  {
146  next(); // consume ,
147  p_pair(o);
148 
149  if (iserr())
150  {
151  return o;
152  }
153  }
154 
155  if (lexer->currentTokenId == eClosingCurlyBracket)
156  {
157  next(); // consume }
158  o->setLexerEndOffset(previousTokenEndOffset);
159  return o;
160  }
161  else
162  {
163  return error("',' or '}'", o);
164  }
165  }
166 
167  void
168  StructuralJsonParser::p_pair(JsonObjectPtr o)
169  {
170  if (!accceptJsStyleKeys && lexer->currentTokenId != eString)
171  {
172  error("String");
173  return;
174  }
175  else if (accceptJsStyleKeys && lexer->currentTokenId != eString &&
176  lexer->currentTokenId != eId)
177  {
178  error("String or ID");
179  return;
180  }
181 
182  std::string key;
183 
184  if (accceptJsStyleKeys && lexer->currentTokenId == eId)
185  {
186  key = lexer->currentTokenValue;
187  }
188  else if (!DequoteString(lexer->currentTokenValue, key))
189  {
190  stringerror(key);
191  return;
192  }
193 
194  next(); // consume key
195 
196  if (lexer->currentTokenId != eColon)
197  {
198  o->add(key, JsonDataPtr());
199  error("':'");
200  return;
201  }
202 
203  next(); // consue :
204  JsonDataPtr value = p_item();
205  o->add(key, value);
206 
207  if (iserr())
208  {
209  return;
210  }
211  }
212 
214  StructuralJsonParser::p_array()
215  {
216  JsonArrayPtr a(new JsonArray());
217  a->setLexerStartOffset(lexer->getPositionInfo(lexer->pos));
218  next(); // consume [
219 
220  if (lexer->currentTokenId == eClosingSquareBracket)
221  {
222  next(); // consume ]
223  a->setLexerEndOffset(previousTokenEndOffset);
224  return a;
225  }
226 
227  int posBeforeItem = lexer->pos;
228  JsonDataPtr item1 = p_item();
229  a->add(item1);
230 
231  if (iserr())
232  {
233  if (posBeforeItem == lexer->pos)
234  {
235  // No Token was consumed by p_item() => add ']' to expected tokens in error message.
236  return error("']', " + expected, a);
237  }
238  else
239  {
240  return a;
241  }
242  }
243 
244  while (lexer->currentTokenId == eComma)
245  {
246  next(); // consume ,
247  JsonDataPtr item = p_item();
248  a->add(item);
249 
250  if (iserr())
251  {
252  return a;
253  }
254  }
255 
256  if (lexer->currentTokenId == eClosingSquareBracket)
257  {
258  next(); // consume ]
259  a->setLexerEndOffset(previousTokenEndOffset);
260  return a;
261  }
262  else
263  {
264  return error(", or ]", a);
265  }
266  }
267 
268  // Item = String | Number | true | false | null | Object | Array
270  StructuralJsonParser::p_item()
271  {
272  switch (lexer->currentTokenId)
273  {
274  case eString:
275  case eNumber:
276  case eBoolean:
277  case eNull:
278  return p_leaf();
279 
281  return p_object();
282 
284  return p_array();
285  break;
286 
287  default:
288  return error("'{', '[', String, Number, 'true', 'false' or 'null'");
289  }
290  }
291 
293  StructuralJsonParser::p_leaf()
294  {
296  std::string val;
297 
298  switch (lexer->currentTokenId)
299  {
300  case eString:
301 
302  if (!DequoteString(lexer->currentTokenValue, val))
303  {
304  return stringerror(val);
305  }
306 
307  value.reset(new JsonValue(JsonValue::eString, val));
308  break;
309 
310  case eNumber:
311  value.reset(new JsonValue(JsonValue::eNumber, lexer->currentTokenValue));
312  break;
313 
314  case eBoolean:
315  value.reset(new JsonValue(JsonValue::eBool, lexer->currentTokenValue));
316  break;
317 
318  case eNull:
319  value.reset(new JsonValue(JsonValue::eNull, lexer->currentTokenValue));
320  break;
321 
322  default:
323  return error("String, Number, 'true', 'false' or 'null'");
324  }
325 
326  value->setLexerStartOffset(lexer->getPositionInfo(lexer->pos));
327  next(); // consume eString | eNumber | eBoolean | eNull
328  value->setLexerEndOffset(previousTokenEndOffset);
329  return value;
330  }
331 
333  StructuralJsonParser::error(const std::string& expected, const JsonDataPtr& toReturn)
334  {
335  this->err = "Unexpected Token " + lexer->tokenIdToName(lexer->currentTokenId) + " at " +
336  getlongerrposstr() + ". Expecting " + expected + ".";
337  this->expected = expected;
338  return toReturn;
339  }
340 
342  StructuralJsonParser::stringerror(const std::string& error, const JsonDataPtr& toReturn)
343  {
344  this->err = "invalid string at " + getlongerrposstr() + ":" + error + ".";
345  this->expected = expected;
346  return toReturn;
347  }
348 
349  bool
351  {
352  return err.length() > 0;
353  }
354 
355  std::string
357  {
358  return err;
359  }
360 
361  void
362  StructuralJsonParser::geterrpos(int& line, int& col)
363  {
364  lexer->positionToLineAndColumn(lexer->lastPos, line, col);
365  }
366 
367  std::string
369  {
370  int line, col;
371  lexer->positionToLineAndColumn(lexer->lastPos, line, col);
372  return "L" + std::to_string(line) + " C" + std::to_string(col);
373  }
374 
375  std::string
377  {
378  int line, col;
379  lexer->positionToLineAndColumn(lexer->lastPos, line, col);
380  return "line " + std::to_string(line) + " column " + std::to_string(col);
381  }
382 
383  bool
384  StructuralJsonParser::DequoteString(std::string s, std::string& res)
385  {
386  // *INDENT-OFF*
387  res = "";
388  std::string::const_iterator it = s.begin();
389  std::string::const_iterator end = s.end() - 1;
390 
391  if (s.length() < 1 || *it != '"')
392  {
393  res = "Missing starting \"";
394  return false;
395  }
396 
397  it++; // consume starting "
398 
399  if (s.length() < 2 || *end != '"')
400  {
401  res = "Missing ending \"";
402  return false;
403  }
404 
405  while (it < end)
406  {
407  char c = *it++;
408 
409  if (c == '\\' && it != s.end())
410  {
411  switch (*it++)
412  {
413  case '\\':
414  res += '\\';
415  break;
416 
417  case '/':
418  res += '/';
419  break;
420 
421  case '"':
422  res += '"';
423  break;
424 
425  case 'b':
426  res += '\b';
427  break;
428 
429  case 'f':
430  res += '\f';
431  break;
432 
433  case 'n':
434  res += '\n';
435  break;
436 
437  case 'r':
438  res += '\r';
439  break;
440 
441  case 't':
442  res += '\t';
443  break;
444 
445  case 'u':
446  res = "\\u is not supported";
447  return false;
448 
449  default:
450  res = "invalid escape sequence";
451  return false;
452  }
453  }
454  else
455  {
456  res += c;
457  }
458  }
459 
460  return true;
461  // *INDENT-ON*
462  }
463 } // namespace armarx
armarx::StructuralJsonParser::eOpeningSquareBracket
@ eOpeningSquareBracket
Definition: StructuralJsonParser.h:43
armarx::StructuralJsonParser::eColon
@ eColon
Definition: StructuralJsonParser.h:45
armarx::JsonValue::eNumber
@ eNumber
Definition: JsonValue.h:42
armarx::StructuralJsonParser::getlongerrposstr
std::string getlongerrposstr()
Definition: StructuralJsonParser.cpp:376
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:362
c
constexpr T c
Definition: UnscentedKalmanFilterTest.cpp:46
armarx::JsonValue::eString
@ eString
Definition: JsonValue.h:41
armarx::StructuralJsonParser::eNumber
@ eNumber
Definition: StructuralJsonParser.h:49
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:855
armarx::JsonValue::eNull
@ eNull
Definition: JsonValue.h:44
armarx::StructuralJsonParser::eClosingCurlyBracket
@ eClosingCurlyBracket
Definition: StructuralJsonParser.h:42
armarx::StructuralJsonParser::DequoteString
static bool DequoteString(std::string str, std::string &res)
Definition: StructuralJsonParser.cpp:384
armarx::JsonValue::eBool
@ eBool
Definition: JsonValue.h:43
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:44
armarx::StructuralJsonParser::eString
@ eString
Definition: StructuralJsonParser.h:48
armarx::StructuralJsonParser::iserr
bool iserr()
Definition: StructuralJsonParser.cpp:350
armarx::to_string
const std::string & to_string(const std::string &s)
Definition: StringHelpers.h:41
armarx::StructuralJsonParser::eComma
@ eComma
Definition: StructuralJsonParser.h:46
armarx::StructuralJsonParser::geterrposstr
std::string geterrposstr()
Definition: StructuralJsonParser.cpp:368
armarx::StructuralJsonParser::parse
void parse()
Definition: StructuralJsonParser.cpp:60
armarx::StructuralJsonParser::eWhitespace
@ eWhitespace
Definition: StructuralJsonParser.h:40
armarx::SimpleLexer
Definition: SimpleLexer.h:31
armarx::StructuralJsonParser::geterr
std::string geterr()
Definition: StructuralJsonParser.cpp:356
armarx::JsonDataPtr
std::shared_ptr< JsonData > JsonDataPtr
Definition: JsonData.h:31
armarx::StructuralJsonParser::eOpeningCurlyBracket
@ eOpeningCurlyBracket
Definition: StructuralJsonParser.h:41
armarx::StructuralJsonParser::~StructuralJsonParser
~StructuralJsonParser()
Definition: StructuralJsonParser.cpp:55
armarx::StructuralJsonParser::eNull
@ eNull
Definition: StructuralJsonParser.h:51
armarx::StructuralJsonParser::parsedJson
JsonDataPtr parsedJson
Definition: StructuralJsonParser.h:62
armarx::StructuralJsonParser::eId
@ eId
Definition: StructuralJsonParser.h:47
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:27
armarx::StructuralJsonParser::eBoolean
@ eBoolean
Definition: StructuralJsonParser.h:50
armarx::JsonObjectPtr
std::shared_ptr< JsonObject > JsonObjectPtr
Definition: JsonObject.h:34
SimpleLexer.h