loom

Форк
0
/
Json5Rdp.cpp 
320 строк · 10.7 Кб
1
/*
2
MIT License
3

4
Copyright (c) 2021 МГТУ им. Н.Э. Баумана, кафедра ИУ-6, Михаил Фетисов,
5

6
https://bmstu.codes/lsx/simodo
7
*/
8

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"
13

14
#include <fstream>
15
#include <algorithm>
16

17
namespace simodo::variable
18
{
19

20
namespace {
21

22
    class JsonAnalyzeDataBuilder_dummy : public JsonAnalyzeDataBuilder_interface
23
    {
24
    public:
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 {}
28
    };
29

30
    static JsonAnalyzeDataBuilder_dummy dummy_builder;
31
}
32

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)
37
    , _value(value)
38
{
39
    _files.push_back(json_file);
40
}
41

42
Json5Rdp::Json5Rdp(inout::Reporter_abstract & m, JsonAnalyzeDataBuilder_interface & builder, const std::string json_file, Value & value) 
43
    : inout::RdpBaseSugar(m,_files) 
44
    , _builder(builder)
45
    , _json_file(json_file)
46
    , _value(value)
47
{
48
    _files.push_back(json_file);
49
}
50

51
bool Json5Rdp::parse() 
52
{
53
    SIMODO_INOUT_STD_IFSTREAM(in, _json_file);
54

55
    if (!in) {
56
        reporter().reportFatal(inout::fmt("Ошибка при открытии файла '%1'").arg(_json_file));
57
        return false;
58
    }
59

60
    inout::InputStream stream(in);
61

62
    return parse(stream);
63
}
64

65
bool Json5Rdp::parse(inout::InputStream_interface &stream) 
66
{
67
    inout::LexicalParameters lex;
68

69
    lex.markups = {
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},
74
    };
75
    lex.masks = {
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},
81
    };
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;
89

90
    _tokenizer = std::make_unique<inout::Tokenizer>(0, stream, lex);
91

92
    inout::Token t = _tokenizer->getToken();
93

94
    if (t.type() == inout::LexemeType::Empty)
95
        return true;
96

97
    parseValue(t, _value);
98

99
    return _ok;
100
}
101

102
void Json5Rdp::parseValue(const inout::Token & value_token, Value & value) const
103
{
104
    if (value_token.type() == inout::LexemeType::Punctuation)
105
    {
106
        if (value_token.lexeme() == u"{") {
107
            parseObject(value_token, value);
108
            return;
109
        }
110

111
        if (value_token.lexeme() == u"[") {
112
            parseArray(value_token, value);
113
            return;
114
        }
115

116
        if (value_token.lexeme() == u"true" || value_token.lexeme() == u"false")
117
        {
118
            value = Value(value_token.lexeme() == u"true");
119
            _builder.addConst(value_token);
120
            return;
121
        }
122

123
        if (value_token.lexeme() == u"null")
124
        {
125
            value = Value();
126
            _builder.addConst(value_token);
127
            return;
128
        }
129
    }
130
    else if (value_token.type() == inout::LexemeType::Annotation || value_token.type() == inout::LexemeType::Id)
131
    {
132
        value = Value(value_token.lexeme());
133
        _builder.addConst(value_token);
134
        return;
135
    }
136
    else if (value_token.type() == inout::LexemeType::Number)
137
    {
138
        try
139
        {
140
            if (value_token.qualification() == inout::TokenQualification::RealNumber)
141
                value = Value(stod(inout::toU8(value_token.lexeme())));
142
            else
143
                value = Value(int64_t(stol(inout::toU8(value_token.lexeme()))));
144
        }
145
        catch(const std::exception & ex)
146
        {
147
            reporter().reportError(value_token.makeLocation(files()), inout::fmt("The numeric value is formatted incorrectly"));
148
        }
149
        _builder.addConst(value_token);
150
        return;
151
    }
152

153
    _ok = reportUnexpected(value_token, inout::fmt("number, string constant, identifier, '{', '[', 'true', 'false' or 'null'"));
154

155
    // 1. Встречено , ] } - пропущено значение
156
    if (value_token.lexeme() == u"," || value_token.lexeme() == u"}" || value_token.lexeme() == u"]") {
157
        reporter().reportInformation(inout::fmt("Пропущено значение"));
158
        value = Value();
159
        return;
160
    }
161

162
    // 2. Встречено : - ?
163
    reporter().reportInformation("?");
164
    value = Value();
165
}
166

167
void Json5Rdp::parseObject(const inout::Token & open_brace_token, Value & value) const
168
{
169
    VariableSet_t member_list;
170

171
    inout::Token t = _tokenizer->getToken();
172

173
    if (t.type() == inout::LexemeType::Punctuation && t.lexeme() == u"}")
174
    {
175
        value = Value(member_list);
176
        _builder.addGroup(open_brace_token, t);
177
        return;
178
    }
179

180
    while(t.type() != inout::LexemeType::Empty)
181
    {
182
        if (t.type() == inout::LexemeType::Punctuation && t.lexeme() == u"}") // Лишняя запятая "," перед "}" в разбираемом Object
183
        {
184
            value = Value(member_list);
185
            _builder.addGroup(open_brace_token, t);
186
            return;
187
        }
188

189
        std::u16string variable_name;
190
        bool colon = true;
191
        if (t.type() != inout::LexemeType::Annotation && t.type() != inout::LexemeType::Id) {
192
            _ok = reportUnexpected(t, "member name (string)");
193
            if (t.lexeme() == u":") {
194
            }
195
            else {
196
                // Восстановление после ошибки методом "паники" до символов "," и "}"
197
                t = _tokenizer->getToken();
198
                while(t.type() != inout::LexemeType::Empty && t.lexeme() != u"," && t.lexeme() != u"}")
199
                    t = _tokenizer->getToken();
200
                colon = false;
201
                if (t.type() == inout::LexemeType::Empty)
202
                    return;
203
            }
204
        }
205
        else
206
        {
207
            auto it = find_if(member_list.begin(), member_list.end(),
208
                                [t](const Variable & var)
209
                                {
210
                                    return t.lexeme() == var.name();
211
                                });
212

213
            if (it != member_list.end())
214
            {
215
                reporter().reportError(t.makeLocation(files()), 
216
                                        inout::fmt("Member '%1' is duplicated").arg(t.lexeme()));
217
            }
218
        }
219

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 (лексема ":")
225

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)
233
                    return;
234
            }
235
            else {
236
                t = _tokenizer->getToken();
237

238
                Value variable_value;
239

240
                parseValue(t,variable_value);
241

242
                member_list.push_back(Variable {variable_name, variable_value});
243

244
                t = _tokenizer->getToken(); // Токен после variable_value (либо ",", либо "}", либо другой токен)
245
            }
246
        }
247

248
        if (t.type() == inout::LexemeType::Punctuation && t.lexeme() == u"}")
249
        {
250
            value = Value(member_list);
251
            _builder.addGroup(open_brace_token, t);
252
            return;
253
        }
254

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)
262
                return;
263
            if (t.type() == inout::LexemeType::Annotation || t.type() == inout::LexemeType::Id)
264
                continue;
265
            value = Value(member_list);
266
            _builder.addGroup(open_brace_token, t);
267
            return;
268
        }
269

270
        t = _tokenizer->getToken();
271
    }
272
}
273

274
void Json5Rdp::parseArray(const inout::Token & open_brace_token, Value & value) const
275
{
276
    std::vector<Value> value_list;
277

278
    inout::Token t = _tokenizer->getToken();
279

280
    if (t.type() == inout::LexemeType::Punctuation && t.lexeme() == u"]")
281
    {
282
        value = Value(value_list);
283
        _builder.addGroup(open_brace_token, t);
284
        return;
285
    }
286

287
    while(t.type() != inout::LexemeType::Empty)
288
    {
289
        if (t.type() == inout::LexemeType::Punctuation && t.lexeme() == u"]") // Лишняя запятая "," перед "]" в разбираемом Array
290
        {
291
            value = Value(value_list);
292
            _builder.addGroup(open_brace_token, t);
293
            return;
294
        }
295

296
        Value array_element_value;
297

298
        parseValue(t,array_element_value);
299

300
        value_list.push_back(array_element_value);
301

302
        t = _tokenizer->getToken();
303

304
        if (t.type() == inout::LexemeType::Punctuation && t.lexeme() == u"]")
305
        {
306
            value = Value(value_list);
307
            _builder.addGroup(open_brace_token, t);
308
            return;
309
        }
310

311
        if (t.type() != inout::LexemeType::Punctuation || t.lexeme() != u",") // Заходим внутрь, если t это НЕ токен Punctuation с лексемой ","
312
            break;
313

314
        t = _tokenizer->getToken();
315
    }
316

317
    _ok = reportUnexpected(t);
318
}
319

320
}

Использование cookies

Мы используем файлы cookie в соответствии с Политикой конфиденциальности и Политикой использования cookies.

Нажимая кнопку «Принимаю», Вы даете АО «СберТех» согласие на обработку Ваших персональных данных в целях совершенствования нашего веб-сайта и Сервиса GitVerse, а также повышения удобства их использования.

Запретить использование cookies Вы можете самостоятельно в настройках Вашего браузера.