4
Copyright (c) 2021 МГТУ им. Н.Э. Баумана, кафедра ИУ-6, Михаил Фетисов,
6
https://bmstu.codes/lsx/simodo
9
#include "simodo/variable/json/parser/Json5Rdp.h"
10
#include "simodo/inout/convert/functions.h"
11
#include "simodo/inout/token/FileStream.h"
12
#include "simodo/inout/format/fmt.h"
17
namespace simodo::variable
22
class JsonAnalyzeDataBuilder_dummy : public JsonAnalyzeDataBuilder_interface
25
virtual void addGroup(const inout::Token & , const inout::Token & ) override {}
26
virtual void addVariable(const inout::Token & ) override {}
27
virtual void addConst(const inout::Token & ) override {}
30
static JsonAnalyzeDataBuilder_dummy dummy_builder;
33
Json5Rdp::Json5Rdp(inout::Reporter_abstract & m, const std::string json_file, Value & value)
34
: inout::RdpBaseSugar(m,_files)
35
, _builder(dummy_builder)
36
, _json_file(json_file)
39
_files.push_back(json_file);
42
Json5Rdp::Json5Rdp(inout::Reporter_abstract & m, JsonAnalyzeDataBuilder_interface & builder, const std::string json_file, Value & value)
43
: inout::RdpBaseSugar(m,_files)
45
, _json_file(json_file)
48
_files.push_back(json_file);
53
SIMODO_INOUT_STD_IFSTREAM(in, _json_file);
56
reporter().reportFatal(inout::fmt("Ошибка при открытии файла '%1'").arg(_json_file));
60
inout::InputStream stream(in);
65
bool Json5Rdp::parse(inout::InputStream_interface &stream)
67
inout::LexicalParameters lex;
70
{u"//", u"", u"", inout::LexemeType::Comment},
71
{u"/*", u"*/", u"", inout::LexemeType::Comment},
72
{u"\"", u"\"", u"\\", inout::LexemeType::Annotation},
73
{u"\'", u"\'", u"\\", inout::LexemeType::Annotation},
76
{u"0bN", inout::LexemeType::Number, 2},
77
{u"0oN", inout::LexemeType::Number, 8},
78
{u"0xN", inout::LexemeType::Number, 16},
79
{u".N", inout::LexemeType::Number, 10},
80
{inout::BUILDING_NUMBER, inout::LexemeType::Number, 10},
82
lex.punctuation_chars = u"{}[],:";
83
lex.punctuation_words = {u"true", u"false", u"null"};
84
lex.national_alphabet = u"";
85
lex.id_extra_symbols = u"_";
86
lex.may_national_letters_use = false;
87
lex.may_national_letters_mix = false;
88
lex.is_case_sensitive = true;
90
_tokenizer = std::make_unique<inout::Tokenizer>(0, stream, lex);
92
inout::Token t = _tokenizer->getToken();
94
if (t.type() == inout::LexemeType::Empty)
97
parseValue(t, _value);
102
void Json5Rdp::parseValue(const inout::Token & value_token, Value & value) const
104
if (value_token.type() == inout::LexemeType::Punctuation)
106
if (value_token.lexeme() == u"{") {
107
parseObject(value_token, value);
111
if (value_token.lexeme() == u"[") {
112
parseArray(value_token, value);
116
if (value_token.lexeme() == u"true" || value_token.lexeme() == u"false")
118
value = Value(value_token.lexeme() == u"true");
119
_builder.addConst(value_token);
123
if (value_token.lexeme() == u"null")
126
_builder.addConst(value_token);
130
else if (value_token.type() == inout::LexemeType::Annotation || value_token.type() == inout::LexemeType::Id)
132
value = Value(value_token.lexeme());
133
_builder.addConst(value_token);
136
else if (value_token.type() == inout::LexemeType::Number)
140
if (value_token.qualification() == inout::TokenQualification::RealNumber)
141
value = Value(stod(inout::toU8(value_token.lexeme())));
143
value = Value(int64_t(stol(inout::toU8(value_token.lexeme()))));
145
catch(const std::exception & ex)
147
reporter().reportError(value_token.makeLocation(files()), inout::fmt("The numeric value is formatted incorrectly"));
149
_builder.addConst(value_token);
153
_ok = reportUnexpected(value_token, inout::fmt("number, string constant, identifier, '{', '[', 'true', 'false' or 'null'"));
155
// 1. Встречено , ] } - пропущено значение
156
if (value_token.lexeme() == u"," || value_token.lexeme() == u"}" || value_token.lexeme() == u"]") {
157
reporter().reportInformation(inout::fmt("Пропущено значение"));
162
// 2. Встречено : - ?
163
reporter().reportInformation("?");
167
void Json5Rdp::parseObject(const inout::Token & open_brace_token, Value & value) const
169
VariableSet_t member_list;
171
inout::Token t = _tokenizer->getToken();
173
if (t.type() == inout::LexemeType::Punctuation && t.lexeme() == u"}")
175
value = Value(member_list);
176
_builder.addGroup(open_brace_token, t);
180
while(t.type() != inout::LexemeType::Empty)
182
if (t.type() == inout::LexemeType::Punctuation && t.lexeme() == u"}") // Лишняя запятая "," перед "}" в разбираемом Object
184
value = Value(member_list);
185
_builder.addGroup(open_brace_token, t);
189
std::u16string variable_name;
191
if (t.type() != inout::LexemeType::Annotation && t.type() != inout::LexemeType::Id) {
192
_ok = reportUnexpected(t, "member name (string)");
193
if (t.lexeme() == u":") {
196
// Восстановление после ошибки методом "паники" до символов "," и "}"
197
t = _tokenizer->getToken();
198
while(t.type() != inout::LexemeType::Empty && t.lexeme() != u"," && t.lexeme() != u"}")
199
t = _tokenizer->getToken();
201
if (t.type() == inout::LexemeType::Empty)
207
auto it = find_if(member_list.begin(), member_list.end(),
208
[t](const Variable & var)
210
return t.lexeme() == var.name();
213
if (it != member_list.end())
215
reporter().reportError(t.makeLocation(files()),
216
inout::fmt("Member '%1' is duplicated").arg(t.lexeme()));
220
if (colon) { // Если colon = true (т. е. попадаем внутрь блока) -> тогда t это токен Annotation (или Id) или токен Punctuation (лексема ":")
221
_builder.addVariable(t);
222
variable_name = t.lexeme();
223
if (t.lexeme() != u":")
224
t = _tokenizer->getToken(); // Теперь t это токен после токена Annotation (или Id) или сам токен Punctuation (лексема ":")
226
if (t.type() != inout::LexemeType::Punctuation || t.lexeme() != u":") {
227
_ok = reportUnexpected(t, ":");
228
// Восстановление после ошибки методом "паники" до символов "," и "}"
229
t = _tokenizer->getToken();
230
while(t.type() != inout::LexemeType::Empty && t.lexeme() != u"," && t.lexeme() != u"}")
231
t = _tokenizer->getToken();
232
if (t.type() == inout::LexemeType::Empty)
236
t = _tokenizer->getToken();
238
Value variable_value;
240
parseValue(t,variable_value);
242
member_list.push_back(Variable {variable_name, variable_value});
244
t = _tokenizer->getToken(); // Токен после variable_value (либо ",", либо "}", либо другой токен)
248
if (t.type() == inout::LexemeType::Punctuation && t.lexeme() == u"}")
250
value = Value(member_list);
251
_builder.addGroup(open_brace_token, t);
255
if (t.type() != inout::LexemeType::Punctuation || t.lexeme() != u",") { // Заходим внутрь, если t это НЕ токен Punctuation с лексемой ","
256
_ok = reportUnexpected(t, ",");
257
// Восстановление после ошибки методом "паники" до символов СТРОКОВАЯ_КОНСТАНТА и "}"
258
t = _tokenizer->getToken();
259
while(t.type() != inout::LexemeType::Empty && t.type() != inout::LexemeType::Annotation && t.type() != inout::LexemeType::Id && t.lexeme() != u"}")
260
t = _tokenizer->getToken();
261
if (t.type() == inout::LexemeType::Empty)
263
if (t.type() == inout::LexemeType::Annotation || t.type() == inout::LexemeType::Id)
265
value = Value(member_list);
266
_builder.addGroup(open_brace_token, t);
270
t = _tokenizer->getToken();
274
void Json5Rdp::parseArray(const inout::Token & open_brace_token, Value & value) const
276
std::vector<Value> value_list;
278
inout::Token t = _tokenizer->getToken();
280
if (t.type() == inout::LexemeType::Punctuation && t.lexeme() == u"]")
282
value = Value(value_list);
283
_builder.addGroup(open_brace_token, t);
287
while(t.type() != inout::LexemeType::Empty)
289
if (t.type() == inout::LexemeType::Punctuation && t.lexeme() == u"]") // Лишняя запятая "," перед "]" в разбираемом Array
291
value = Value(value_list);
292
_builder.addGroup(open_brace_token, t);
296
Value array_element_value;
298
parseValue(t,array_element_value);
300
value_list.push_back(array_element_value);
302
t = _tokenizer->getToken();
304
if (t.type() == inout::LexemeType::Punctuation && t.lexeme() == u"]")
306
value = Value(value_list);
307
_builder.addGroup(open_brace_token, t);
311
if (t.type() != inout::LexemeType::Punctuation || t.lexeme() != u",") // Заходим внутрь, если t это НЕ токен Punctuation с лексемой ","
314
t = _tokenizer->getToken();
317
_ok = reportUnexpected(t);