loom

Форк
0
/
CodeSupplier.cpp 
246 строк · 10.3 Кб
1
/*
2
MIT License
3

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

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

9
#include "simodo/module/CodeSupplier.h"
10

11
#include "simodo/ast/generator/FormationFlow.h"
12
#include "simodo/parser/fuze/FuzeRdp.h"
13
#include "simodo/parser/automaton/PushdownAutomaton.h"
14
#include "simodo/interpret/SemanticOperationsEnumsLoader.h"
15
#include "simodo/interpret/builtins/hosts/fuze/FuzeRunning.h"
16
#include "simodo/interpret/builtins/hosts/base/BaseRunning.h"
17
#include "simodo/interpret/builtins/modules/LexicalParametersModule.h"
18
#include "simodo/interpret/builtins/modules/AstFormationModule.h"
19
#include "simodo/interpret/builtins/AstFormationBuilder.h"
20
#include "simodo/inout/convert/functions.h"
21
#include "simodo/inout/format/fmt.h"
22

23
#include <cassert>
24

25
#if __cplusplus >= __cpp_2017
26
#include <filesystem>
27
namespace fs = std::filesystem;
28
#else
29
#include <experimental/filesystem>
30
namespace fs = std::filesystem::experimental;
31
#endif
32

33
namespace simodo::module
34
{
35
    namespace 
36
    {
37
        static parser::Grammar EMPTY_GRAMMAR_TABLE;
38
    }
39

40
    CodeSupplier::CodeSupplier( inout::Reporter_abstract & m,
41
                                std::vector<std::string> grammar_places,
42
                                inout::InputStreamSupplier_interface & stream_supplier,
43
                                interpret::InterpretFactory_interface & interpret_factory,
44
                                parser::SyntaxDataCollector_interface & syntax_data_collector)
45
        : _m(m)
46
        , _grammar_places(grammar_places)
47
        , _stream_supplier(stream_supplier)
48
        , _interpret_factory(interpret_factory)
49
        , _syntax_data_collector(syntax_data_collector)
50
    {
51
    }
52

53
    const ast::Node * CodeSupplier::getCode(const std::string & module_name,
54
                                            const inout::uri_set_t & files)
55
    {
56
        {
57
            auto it = _codes.find(module_name);
58
            if (it != _codes.end())
59
                return &(it->second);
60
        }
61

62
        fs::path    path_to_module = module_name;
63
        std::string grammar_name   = path_to_module.extension().string().substr(1);
64
        std::string grammar_file   = findGrammarFile(grammar_name);
65

66
        if (grammar_file.empty()) {
67
            _m.reportFatal(inout::fmt("Unable to find grammar '%1'").arg(grammar_name));
68
            return nullptr;
69
        }
70

71
        std::shared_ptr<inout::InputStream_interface> in = _stream_supplier.supply(module_name);
72

73
        if (!in) {
74
            _m.reportFatal(inout::fmt("Unable to load file '%1'").arg(module_name));
75
            return nullptr;
76
        }
77

78
        inout::uri_index_t uri_index = files.empty() ? 0 : files.size()-1;
79

80
        auto [it, success] = _codes.insert({module_name,{}});
81
        
82
        bool ok = parse(files,uri_index,*in,grammar_file,it->second);
83

84
        if (!ok) {
85
            _codes.erase(it);
86
            /// \note В случае ошибки удалять файл не нужно, иначе может быть некорректной 
87
            /// диагностика!
88
            // files.pop_back();
89
            return nullptr;
90
        }
91

92
        return &(it->second);
93
    }
94

95
    std::string CodeSupplier::findGrammarFile(const std::string & grammar_name) const
96
    {
97
        for(const std::string & dir_name : _grammar_places) {
98
            fs::path    path_to_grammar = dir_name;
99

100
            path_to_grammar /= grammar_name + ".fuze"; 
101

102
            if (fs::exists(path_to_grammar)) 
103
                return path_to_grammar.string();
104
        }
105

106
        return {};
107
    }
108

109
    bool CodeSupplier::parse( const inout::uri_set_t & files,
110
                              inout::uri_index_t uri_index, 
111
                              inout::InputStream_interface & stream, 
112
                              const std::string & grammar_file, 
113
                              ast::Node & code)
114
    {
115
        /// \todo Необходимо сделать приём константной ссылки на грамматику 
116
        /// + поправить конструктор parser::PushdownAutomaton
117
        parser::Grammar g = getGrammarTable(grammar_file);
118
        if (g.rules.empty())
119
            return false;
120

121
        std::string file_name = uri_index < files.size() ? files[uri_index] : "?";
122

123
        variable::VariableSet_t hosts = interpret::loadSemanticOperationsEnums(fs::path(grammar_file).parent_path().string());
124

125
        ast::Node                       null_node;
126
        std::unique_ptr<interpret::Interpret_interface>
127
                                        inter(_interpret_factory.create(interpret::InterpretType::Preview, {file_name}, null_node));
128
        interpret::builtins::BaseInterpret_abstract * 
129
                                        sbl = new interpret::builtins::BaseRunning(inter.get());
130
        interpret::builtins::AstFormationBuilder  
131
                                        builder(_m,*sbl,hosts,_syntax_data_collector);
132
        parser::PushdownAutomaton       parser(_m, g, files, builder);
133

134
        inter->instantiateSemantics({sbl});
135

136
        if (!parser.parse(stream))
137
            return false;
138

139
        const_cast<ast::Node &>(builder.ast().tree().root()).swap(code);
140
        return true;
141
    }
142

143
    const parser::Grammar & CodeSupplier::getGrammarTable(const std::string & grammar_file)
144
    {
145
        {
146
            const auto it = _grammar_tables.find(grammar_file);
147
            if (it != _grammar_tables.end())
148
                return it->second;
149
        }
150

151
        parser::Grammar     grammar_table;
152

153
        if (parser::loadGrammarDump(grammar_file,grammar_table)) {
154
            auto [it, ok] = _grammar_tables.insert({grammar_file,grammar_table});
155
            return ok ? it->second : EMPTY_GRAMMAR_TABLE;
156
        }
157

158
        ast::FormationFlow  flow;
159
        parser::FuzeRdp     fuze(_m, grammar_file, flow);
160
        
161
        if (!fuze.parse())
162
            return EMPTY_GRAMMAR_TABLE;
163

164
        if (!buildGrammarTable(fs::path(grammar_file).stem().string(),
165
                               flow.tree().files(), 
166
                               flow.tree().root(),
167
                               parser::TableBuildMethod::SLR,
168
                               grammar_table)) {
169
            if (!buildGrammarTable(fs::path(grammar_file).stem().string(),
170
                                   flow.tree().files(), 
171
                                   flow.tree().root(),
172
                                   parser::TableBuildMethod::LR1,
173
                                   grammar_table))
174
                return EMPTY_GRAMMAR_TABLE;
175
        }
176

177
        for(const auto & [name, node] : grammar_table.handlers)
178
            if (name == u"lex") {
179
                interpret::Interpret_interface *  
180
                                    inter       = _interpret_factory.create(interpret::InterpretType::Preview, flow.tree().files(), node);
181
                interpret::builtins::BaseRunning *   
182
                                    lex_runner  = new interpret::builtins::BaseRunning(inter);
183
                std::shared_ptr<interpret::builtins::LexicalParametersModule> 
184
                                    lex         = std::make_shared<interpret::builtins::LexicalParametersModule>(
185
                                                                                            grammar_table.lexical);
186

187
                /// \todo Пересмотреть странную передачу самого себя в свой же метод.
188
                /// PVS Studio: warn V678 An object is used as an argument to its own method.
189
                /// Consider checking the first actual argument of the 'instantiate' function.
190
                lex_runner->importNamespace(u"lex", lex->instantiate(lex), inout::null_token_location);
191
                inter->instantiateSemantics({lex_runner});
192
                _loom.dock(inter, true);
193
                _loom.stretch(inter);
194
            }
195
            /// \todo Фетисов 2024-07-19. Можно удалить через 3-4 месяца.
196
            // else {
197
            //     interpret::Interpret_interface *  
198
            //                         inter   = _interpret_factory.create(interpret::InterpretType::Preview, _m, _loom, flow.tree().files(), node);
199
            //     interpret::builtins::BaseRunning *   
200
            //                         runner  = new interpret::builtins::BaseRunning(inter);
201
            //     std::shared_ptr<interpret::builtins::AstFormationModule> 
202
            //                         ast     = std::make_shared<interpret::builtins::AstFormationModule>();
203

204
            //     /// \todo Пересмотреть странную передачу самого себя в свой же метод.
205
            //     /// PVS Studio: warn V678 An object is used as an argument to its own method.
206
            //     /// Consider checking the first actual argument of the 'instantiate' function.
207
            //     runner->importNamespace(u"ast", ast->instantiate(ast), inout::null_token_location);
208
            //     inter->instantiateSemantics({runner});
209
            //     _loom.dock(inter, true);
210
            //     _loom.stretch(inter);
211
            // }
212

213
        _loom.wait();
214

215
        parser::saveGrammarDump(grammar_file,grammar_table);
216

217
        auto [it, ok] = _grammar_tables.insert({grammar_file,grammar_table});
218
        return ok ? it->second : EMPTY_GRAMMAR_TABLE;
219
    }
220

221
    bool CodeSupplier::buildGrammarTable(const std::string & grammar_name,
222
                                        const inout::uri_set_t & fuze_files, 
223
                                        const ast::Node & fuze_code, 
224
                                        parser::TableBuildMethod method,
225
                                        parser::Grammar & grammar_table)
226
    {
227
        std::unique_ptr<interpret::Interpret_interface>
228
                                    inter(_interpret_factory.create(interpret::InterpretType::Preview, fuze_files, fuze_code));
229

230
        assert(inter);
231
        inter->instantiateSemantics({new interpret::builtins::FuzeRunning(
232
                                                inter.get(),
233
                                                grammar_name,
234
                                                grammar_table,
235
                                                method),
236
                                    });
237

238
        _loom.stretch(inter.get());
239
        _loom.wait();
240

241
        grammar_table.files = fuze_files;
242

243
        return !inter->errors();
244
    }
245

246
}
247

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

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

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

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