loom

Форк
0
/
FuzeDocumentOperation.cpp 
512 строк · 24.0 Кб
1
#include "FuzeDocumentOperation.h"
2

3
#include "ReporterWithReducibleSeverity.h"
4
#include "InputSupplier.h"
5
#include "simodo/inout/convert/functions.h"
6
#include "simodo/interpret/builtins/hosts/base/BaseAnalyzer.h"
7
#include "simodo/interpret/builtins/hosts/fuze/FuzeAnalyzer.h"
8
#include "simodo/interpret/builtins/modules/LexicalParametersModule.h"
9
#include "simodo/interpret/builtins/modules/AstFormationModule.h"
10
#include "simodo/inout/token/RefBufferStream.h"
11

12
#include "simodo/lsp-client/SimodoCommandResult.h"
13
#include "simodo/lsp-client/CompletionItemKind.h"
14
#include "simodo/lsp-client/LspEnums.h"
15
#include "simodo/utility/grammatize.h"
16
#include "simodo/inout/reporter/StreamReporter.h"
17

18
#include "simodo/interpret/SemanticOperationsEnumsLoader.h"
19

20
using namespace simodo;
21

22
FuzeDocumentOperation::FuzeDocumentOperation(lsp::DocumentContext & doc, const DocumentOperationFactory & factory, const std::string & languageId) 
23
        : ScriptDocumentOperation(doc, factory, languageId)
24
        , _doc(doc) 
25
        , _grammar_dir(factory.grammar_dir())
26
{
27
    _hosts_and_operations = interpret::loadSemanticOperationsEnums(_grammar_dir);
28
}
29

30
bool FuzeDocumentOperation::analyze(const std::u16string & text, inout::Reporter_abstract & reporter)
31
{
32
    ReporterWithReducibleSeverity   m(reporter);
33
    ast::FormationFlow              flow;
34
    InputSupplier                   input_supplier(_doc.server(), _doc.file_name(), text);
35
    SemanticDataCollector           data_collector;
36
    parser::FuzeRdp                 fuze(m, _doc.file_name(), flow, input_supplier, data_collector);
37
    inout::RefBufferStream          buffer_stream(text.data());
38

39
    bool ok = fuze.parse(buffer_stream);
40

41
    _files = flow.tree().files();
42

43
    if (ok) {
44
        interpret::builtins::FuzeAnalyzer * analyzer = nullptr;
45

46
        _grammar = parser::Grammar();
47

48
        {
49
            interpret::Interpret    inter(interpret::InterpretType::Analyzer, m, _loom, flow.tree().files(), flow.tree().root(), 
50
                                        {
51
                                            analyzer = new interpret::builtins::FuzeAnalyzer(
52
                                                                        &inter,
53
                                                                        data_collector,
54
                                                                        fs::path(_doc.file_name()).stem().string(),
55
                                                                        _grammar,
56
                                                                        parser::TableBuildMethod::LR1
57
                                                                        ),
58
                                        });
59

60
            _loom.stretch(&inter);
61
            _loom.finish();
62

63
            analyzer->swapProductions(_productions);
64
            analyzer->swapDirections(_directions);
65
        }
66

67
        m.reduceSeverity();
68

69
        for(const auto & [name, node] : _grammar.handlers)
70
        {
71
            interpret::Interpret *              inter       = new interpret::Interpret(interpret::InterpretType::Analyzer, m, _loom, flow.tree().files(), node);
72
            interpret::builtins::BaseAnalyzer * lexAnalyzer = new interpret::builtins::BaseAnalyzer(inter, data_collector);
73
            std::shared_ptr<interpret::builtins::LexicalParametersModule> 
74
                                                lex         = std::make_shared<interpret::builtins::LexicalParametersModule>(_grammar.lexical);
75

76
            lexAnalyzer->importNamespace(u"lex", lex->instantiate(lex), inout::null_token_location);
77
            inter->instantiateSemantics({lexAnalyzer});
78
            _loom.dock(inter, true);
79
            _loom.stretch(inter);
80
            /// \note Убрал параллельную обработку из-за нежелания контролировать гонку за data_collector
81
            _loom.finish();
82
        }
83

84
        for(const parser::GrammarRule & r : _grammar.rules) 
85
        {
86
            interpret::Interpret *              inter       = new interpret::Interpret(interpret::InterpretType::Analyzer, m, _loom, flow.tree().files(), r.reduce_action);
87
            interpret::builtins::BaseAnalyzer * astAnalyzer = new interpret::builtins::BaseAnalyzer(inter, data_collector);
88
            std::shared_ptr<interpret::builtins::AstFormationModule> 
89
                                                ast         = std::make_shared<interpret::builtins::AstFormationModule>(_hosts_and_operations);
90

91
            astAnalyzer->importNamespace(u"ast", ast->instantiate(ast), inout::null_token_location);
92
            inter->instantiateSemantics({astAnalyzer});
93
            _loom.dock(inter, true);
94
            _loom.stretch(inter);
95
            /// \note Убрал параллельную обработку из-за нежелания контролировать гонку за data_collector
96
            _loom.finish();
97
        }
98

99
        /// \note Убрал параллельную обработку из-за нежелания контролировать гонку за data_collector
100
        // _loom.wait();
101

102
        data_collector.swap(_semantic_data);
103
    }
104

105
    return true;
106
}
107

108
bool FuzeDocumentOperation::checkDependency(const std::string & uri) const
109
{
110
    auto it = std::find(_files.begin(), _files.end(), uri);
111
    if (it != _files.end())
112
        return true;
113

114
    return ScriptDocumentOperation::checkDependency(uri);
115
}
116

117
variable::Value FuzeDocumentOperation::produceSimodoCommandResponse(const std::u16string & command_name, std::u16string text) const 
118
{
119
    if (command_name.empty())
120
        return {};
121

122
    parser::TableBuildMethod method = parser::TableBuildMethod::none;
123

124
    if (command_name == SLR_method_report)
125
        method = parser::TableBuildMethod::SLR;
126
    else if (command_name == LR1_method_report)
127
        method = parser::TableBuildMethod::LR1;
128
    else    
129
        return ScriptDocumentOperation::produceSimodoCommandResponse(command_name, text);
130

131
    inout::RefBufferStream  buffer_stream(text.data());
132
    std::ostringstream      out;
133
    inout::StreamReporter   m(out);
134
    parser::Grammar         grammar;
135

136
    utility::grammatize(    _doc.file_name(),
137
                            buffer_stream,
138
                            out,
139
                            m,
140
                            "",   //json_file_name,
141
                            "",   //st_dot_file_name,
142
                            method, // grammar_builder_method,
143
                            "",   //dot_file_name,
144
                            true, //need_state_transitions_info,
145
                            true, //need_rules_info,
146
                            false,//need_st_info,
147
                            false,//need_time_intervals,
148
                            true, //need_silence,
149
                            true, //need_build_grammar,
150
                            false,//need_load_grammar
151
                            true, //need_analyze_handles
152
                            false,//need_analyze_inserts
153
                            grammar
154
                        );
155

156
    return variable::Object {{
157
                {u"uri",            inout::toU16(_doc.file_name())},
158
                {u"commandResult",  variable::Object {{
159
                    {u"id",         u"grammar-report"},
160
                    {u"title",      u"'" + fs::path(_doc.file_name()).stem().u16string() + u"' " + command_name},
161
                    {u"type",       static_cast<int64_t>(lsp::SimodoCommandReportType::plainText)},
162
                    {u"text",       inout::encodeSpecialChars(inout::toU16(out.str()))},
163
                }}},
164
            }};
165
}
166

167
variable::Value FuzeDocumentOperation::produceHoverResponse(const lsp::Position & pos) const
168
{
169
    for(const auto & [p_key, p_pair] : _productions) {
170
        const auto & [prod, pattern] = p_pair;
171
        if (prod.location().range().start().line() == pos.line()
172
         && prod.location().uri_index() == 0) {
173
            if (prod.location().range().start().character() <= pos.character()
174
             && prod.location().range().end().character() > pos.character()) {
175
                return variable::Object {{
176
                            {u"contents",   variable::Object {{
177
                                {u"kind",       u"plaintext"},
178
                                {u"value",      inout::encodeSpecialChars(makeHover(prod))},
179
                            }}},
180
                            {u"range",      _doc.makeRange(prod.location().range())},
181
                        }};
182
            }
183
        }
184
        for(const inout::Token & t : pattern)
185
            if (t.location().range().start().line() == pos.line()
186
             && t.location().uri_index() == 0) {
187
                if (t.location().range().start().character() <= pos.character()
188
                 && t.location().range().end().character() > pos.character()) {
189
                    return variable::Object {{
190
                                {u"contents",   variable::Object {{
191
                                    {u"kind",       u"plaintext"},
192
                                    {u"value",      inout::encodeSpecialChars(makeHover(t))},
193
                                }}},
194
                                {u"range",      _doc.makeRange(t.location().range())},
195
                            }};
196
                }
197
            }
198
    }
199

200
    for(const inout::Token & dt : _directions)
201
        if (dt.location().range().start().line() == pos.line()
202
         && dt.location().uri_index() == 0
203
         && dt.location().range().start().character() <= pos.character()
204
         && dt.location().range().end().character() > pos.character())
205
            return variable::Object {{
206
                        {u"contents",   variable::Object {{
207
                            {u"kind",       u"plaintext"},
208
                            {u"value",      inout::encodeSpecialChars(dt.lexeme() + u" - управляющий символ предотвращения несогласованности грамматики типа R|S")},
209
                        }}},
210
                        {u"range",      _doc.makeRange(dt.location().range())},
211
                    }};
212

213
    // for(const auto & [token, ref] : _refs)
214
    //     if (token.location().range().start().line() == pos.line()
215
    //      && token.location().uri_index() == 0
216
    //      && token.location().range().start().character() <= pos.character()
217
    //      && token.location().range().end().character() > pos.character())
218
    //         return variable::Object {{
219
    //                     {u"contents",   variable::Object {{
220
    //                         {u"kind",       u"plaintext"},
221
    //                         {u"value",      inout::encodeSpecialChars(ref)},
222
    //                     }}},
223
    //                     {u"range",      _doc.makeRange(token.location().range())},
224
    //                 }};
225

226
    return ScriptDocumentOperation::produceHoverResponse(pos);
227
}
228

229
variable::Value FuzeDocumentOperation::produceGotoDeclarationResponse(const lsp::Position & pos) const
230
{
231
    return produceGotoDefinitionResponse(pos);
232
}
233

234
variable::Value FuzeDocumentOperation::produceGotoDefinitionResponse(const lsp::Position & pos) const
235
{
236
    for(const auto & [p_key, p_pair] : _productions) {
237
        const auto & [prod, pattern] = p_pair;
238
        if (prod.location().range().start().line() == pos.line()
239
         && prod.location().uri_index() == 0) {
240
            if (prod.location().range().start().character() <= pos.character()
241
             && prod.location().range().end().character() >= pos.character()) {
242
                auto it = _productions.find(prod.lexeme());
243
                if (it == _productions.end())
244
                    return {};
245
                const auto & [t_prod, t_pattern] = it->second;
246
                std::u16string uri = t_prod.location().uri_index() < _files.size() 
247
                                        ? inout::toU16(_files[t_prod.location().uri_index()])
248
                                        : inout::toU16(_doc.file_name());
249
                return variable::Object {{
250
                            {u"uri",    uri},
251
                            {u"range",  _doc.makeRange(t_prod.location().range())},
252
                        }};
253
            }
254
        }
255
        for(const inout::Token & t : pattern)
256
            if (t.location().range().start().line() == pos.line()
257
             && t.location().uri_index() == 0) {
258
                if (t.location().range().start().character() <= pos.character()
259
                 && t.location().range().end().character() >= pos.character()) {
260
                    auto it = _productions.find(t.lexeme());
261
                    if (it == _productions.end())
262
                        return {};
263
                    const auto & [t_prod, t_pattern] = it->second;
264
                    std::u16string uri = t_prod.location().uri_index() < _files.size() 
265
                                         ? inout::toU16(_files[t_prod.location().uri_index()])
266
                                         : inout::toU16(_doc.file_name());
267
                    return variable::Object {{
268
                                {u"uri",    uri},
269
                                {u"range",  _doc.makeRange(t_prod.location().range())},
270
                            }};
271
                }
272
            }
273
    }
274

275
    // for(const auto & [t, ref] : _refs)
276
    //     if (t.location().range().start().line() == pos.line()
277
    //       && t.location().uri_index() == 0) {
278
    //         if (t.location().range().start().character() <= pos.character()
279
    //           && t.location().range().end().character() >= pos.character()) {
280
    //             return variable::Object {{
281
    //                         {u"uri",    ref},
282
    //                         {u"range",  _doc.makeRange({0,0},{0,0})},
283
    //                     }};
284
    //         }
285
    //     }
286

287
    return ScriptDocumentOperation::produceGotoDefinitionResponse(pos);
288
}
289

290
variable::Value FuzeDocumentOperation::produceCompletionResponse(const lsp::CompletionParams & completionParams) const
291
{
292
    bool scoped = false;
293

294
    _doc.server().log().debug("FuzeDocumentOperation::produceCompletionResponse: completionParams.position = [" 
295
                                + std::to_string(completionParams.position.line())
296
                                + ", " + std::to_string(completionParams.position.character()) + "]");
297

298
    for(const auto & [oped_scope, close_scope] : _semantic_data.scoped())
299
        if (oped_scope.uri_index() == 0) {
300
            _doc.server().log().debug("FuzeDocumentOperation::produceCompletionResponse: scope = [" 
301
                                        + std::to_string(oped_scope.range().start().line())
302
                                        + ", " + std::to_string(oped_scope.range().start().character()) + "] - ["
303
                                        + std::to_string(close_scope.range().end().line())
304
                                        + ", " + std::to_string(close_scope.range().end().character()) + "]");
305

306
            if (completionParams.position >= oped_scope.range().start()
307
             && completionParams.position <= close_scope.range().end()) {
308
                _doc.server().log().debug("FuzeDocumentOperation::produceCompletionResponse: found!");
309
                scoped = true;
310
                break;
311
            }
312
        }
313

314
    if (scoped)
315
        return ScriptDocumentOperation::produceCompletionResponse(completionParams);
316

317
    std::vector<variable::Value> completion_items;
318

319
    std::u16string last_production;
320
    for(const auto & [key, value] : _productions)
321
        if (last_production != key) {
322
            completion_items.push_back(makeCompletionItem(key, u"production", u"", int64_t(lsp::CompletionItemKind::Variable)));
323
            last_production = key;
324
        }
325
    
326
    std::vector<std::u16string> keywords {
327
        u"main", u"include", u"remove",
328
    };
329
    for(const std::u16string & w : keywords)
330
        completion_items.push_back(makeCompletionItem(w, u"keyword", u"", int64_t(lsp::CompletionItemKind::Keyword)));
331

332
    return completion_items;
333
}
334

335
variable::Value FuzeDocumentOperation::produceSemanticTokensResponse() const
336
{
337
    std::function<int64_t(inout::LexemeType)> makeType = [](inout::LexemeType type){
338
        switch (type)
339
        {
340
        case inout::LexemeType::Compound:
341
            return 0;
342
        case inout::LexemeType::Punctuation:
343
        case inout::LexemeType::Annotation:
344
        case inout::LexemeType::Id:
345
        case inout::LexemeType::Number:
346
            return 1;
347
        default:
348
            break;
349
        }
350
        return 0;
351
    };
352
    std::function<int64_t(inout::LexemeType)> makeModifiers = [](inout::LexemeType type){
353
        int64_t modifiers = 0;
354
        if (type == inout::LexemeType::Compound)
355
            modifiers += 1;
356
        else if (type != inout::LexemeType::Punctuation)
357
            modifiers += 2;
358
        return modifiers;
359
    };
360

361
    struct TokenInfo { int64_t length, type, modifiers; };
362
    struct TokenComp {
363
        bool operator() (const std::pair<int64_t,int64_t> & x1, const std::pair<int64_t,int64_t> & x2) const {
364
            return x1.first < x2.first || (x1.first == x2.first && x1.second < x2.second);
365
        }
366
    };    
367

368
    std::map<std::pair<int64_t,int64_t>, TokenInfo, TokenComp> tokens;
369

370
    for(const auto & [p_key, p_pair] : _productions) {
371
        const auto & [prod, pattern] = p_pair;
372
        if (prod.location().uri_index() == 0) {
373
            int64_t line      = static_cast<int64_t>(prod.location().range().start().line());
374
            int64_t character = static_cast<int64_t>(prod.location().range().start().character());
375
            int64_t length    = static_cast<int64_t>(prod.location().range().end().character()-character);
376
            int64_t modifiers = static_cast<int64_t>(3);
377
            tokens.insert({ {line, character}, {length, 0, modifiers}});
378

379
            for(const inout::Token & t : pattern) {
380
                int64_t line      = static_cast<int64_t>(t.location().range().start().line());
381
                int64_t character = static_cast<int64_t>(t.location().range().start().character());
382
                int64_t length    = static_cast<int64_t>(t.location().range().end().character()-character);
383
                int64_t modifiers = makeModifiers(t.type());
384
                tokens.insert({ {line, character}, {length, makeType(t.type()), modifiers}});
385
            }
386
        }
387
    }
388

389
    for(const inout::Token & t : _directions) 
390
        if (t.location().uri_index() == 0) {
391
            int64_t line      = static_cast<int64_t>(t.location().range().start().line());
392
            int64_t character = static_cast<int64_t>(t.location().range().start().character());
393
            int64_t length    = static_cast<int64_t>(t.location().range().end().character()-character);
394
            int64_t modifiers = static_cast<int64_t>(2);
395
            tokens.insert({ {line, character}, {length, 2, modifiers}});
396
        }
397

398
    // for(const auto & [t, ref] : _refs) 
399
    //     if (t.location().uri_index() == 0) {
400
    //         int64_t line      = static_cast<int64_t>(t.location().range().start().line());
401
    //         int64_t character = static_cast<int64_t>(t.location().range().start().character());
402
    //         int64_t length    = static_cast<int64_t>(t.location().range().end().character()-character);
403
    //         int64_t modifiers = static_cast<int64_t>(1);
404
    //         tokens.insert({ {line, character}, {length, 7, modifiers}});
405
    //     }
406

407
    std::vector<variable::Value> sem_tokens;
408

409
    for(const auto & [p,t] : tokens) {
410
        sem_tokens.push_back(p.first);
411
        sem_tokens.push_back(p.second);
412
        sem_tokens.push_back(t.length);
413
        sem_tokens.push_back(t.type);
414
        sem_tokens.push_back(t.modifiers);
415
    }
416
    
417
    const variable::Value   script_response_value = ScriptDocumentOperation::produceSemanticTokensResponse();
418
    if (script_response_value.type() == variable::ValueType::Object) {
419
        const variable::Value & script_response_data = script_response_value.getObject()->find(u"data");
420
        if (script_response_data.type() == variable::ValueType::Array) {
421
            const std::vector<variable::Value> & script_response_array = script_response_data.getArray()->values();
422
            sem_tokens.insert(sem_tokens.end(), script_response_array.begin(), script_response_array.end());
423
        }
424
    }
425

426
    return variable::Object {{{u"data", sem_tokens}}};
427
}
428

429
variable::Value FuzeDocumentOperation::produceDocumentSymbolsResponse() const
430
{
431
    std::vector<variable::Value> doc_symbols;
432
    std::multimap<uint64_t,std::pair<inout::Token, std::vector<inout::Token>>> prods_by_pos;
433

434
    if (_productions.empty())
435
        return doc_symbols;
436

437
    for(const auto & [p_key, p_pair] : _productions)
438
        if (p_pair.first.location().uri_index() == 0)
439
            prods_by_pos.insert({p_pair.first.location().range().start().line()*uint64_t(1000),p_pair});
440

441
    inout::Token    current_prod(inout::LexemeType::Empty, u"", inout::null_token_location);
442
    inout::Position current_prod_end;
443
    std::u16string  current_pattern_str;
444

445
    for(const inout::Token & t : prods_by_pos.begin()->second.second) 
446
        current_pattern_str += u" " + t.token();
447

448
    for(const auto & [p_line, p_pair] : prods_by_pos) {
449
        const auto & [prod, pattern] = p_pair;
450

451
        if (prod.token() != current_prod.token()) {
452
            if (current_prod.type() != inout::LexemeType::Empty) {
453
                uint32_t end_line = prod.location().range().start().line();
454
                uint32_t end_char = prod.location().range().start().character();
455

456
                end_line = (end_char == 0) ? end_line - 1 : end_line;
457
                end_char = (end_char == 0) ? 1000 : end_char - 1;
458

459
                doc_symbols.push_back(variable::Object {{
460
                    {u"name",           current_prod.token()},
461
                    {u"detail",         current_prod.token() + u" =" + current_pattern_str},
462
                    {u"kind",           int64_t(lsp::SymbolKind::Variable)},
463
                    {u"range",          _doc.makeRange({current_prod.location().range().start(), inout::Position(end_line,end_char)})},
464
                    {u"selectionRange", _doc.makeRange(current_prod.location().range())},
465
                }});
466
            }
467
            current_prod = prod;
468
            current_pattern_str.clear();
469
        }
470

471
        if (!current_pattern_str.empty())       current_pattern_str += u" |";
472
        for(const inout::Token & t : pattern)   current_pattern_str += u" " + t.token();
473

474
        current_prod_end = pattern.back().location().range().end();
475
    }
476

477
    doc_symbols.push_back(variable::Object {{
478
        {u"name",           current_prod.token()},
479
        {u"detail",         current_prod.token() + u" =" + current_pattern_str},
480
        {u"kind",           int64_t(lsp::SymbolKind::Variable)},
481
        {u"range",          _doc.makeRange({current_prod.location().range().start(), inout::Position(current_prod_end.line()+1000,0)})},
482
        {u"selectionRange", _doc.makeRange(current_prod.location().range())},
483
    }});
484

485
    // \todo Использование ScriptDocumentOperation::produceDocumentSymbolsResponse кидает ассерт, так как тот код не предназначен для семантики fuze:
486
    //       при обработке `lex { ... }` getFunctionBodyRange, кажется, иногда не может найти закрывающую скобку,
487
    //       но в целом мне вообще не понятно, для чего использовать DocumentSymbols из ScriptDocumentOperation для fuze
488
    // variable::Value script_response_value = ScriptDocumentOperation::produceDocumentSymbolsResponse();
489
    // if (script_response_value.type() == variable::ValueType::Array) {
490
    //     const std::vector<variable::Value> & array = script_response_value.getArray()->values();
491
    //     doc_symbols.insert(doc_symbols.end(), array.begin(), array.end());
492
    // }
493

494
    return doc_symbols;
495
}
496

497
std::u16string FuzeDocumentOperation::makeHover(const inout::Token & t) const
498
{
499
    std::u16string  text    = t.lexeme();
500
    auto            range   = _productions.equal_range(text);
501

502
    if (range.first == range.second)
503
        text += u" - терминальный символ грамматики";
504
    else
505
        for(auto it = range.first; it != range.second; ++it) {
506
            text += u"\n→";
507
            for(const inout::Token & t : it->second.second)
508
                text += u" " + t.token();
509
        }
510

511
    return text;
512
}
513

514

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

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

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

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