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
23
24#include "SimpleLexer.h"
25
26namespace 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
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
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
constexpr T c
StructuralJsonParser(const std::string &src, bool acceptSingleValue=true, bool accceptJsStyleKeys=true)
void geterrpos(int &line, int &col)
static bool DequoteString(std::string str, std::string &res)
double a(double t, double a0, double j)
Definition CtrlUtil.h:45
This file offers overloads of toIce() and fromIce() functions for STL container types.
std::shared_ptr< JsonValue > JsonValuePtr
Definition JsonValue.h:30
std::shared_ptr< JsonObject > JsonObjectPtr
Definition JsonObject.h:34
std::shared_ptr< JsonData > JsonDataPtr
Definition JsonData.h:31
std::shared_ptr< JsonArray > JsonArrayPtr
Definition JsonArray.h:32
std::shared_ptr< Value > value()
Definition cxxopts.hpp:855