loom

Форк
0
/
tokenizer-doxygen.cpp 
181 строка · 7.3 Кб
1
/*
2
MIT License
3

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

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

9
#include "simodo/variable/Module_interface.h"
10
#include "simodo/variable/VariableSetWrapper.h"
11
#include "simodo/inout/convert/functions.h"
12

13
#include <memory>
14
#include <filesystem>
15
#include <cassert>
16

17
#ifdef CROSS_WIN
18
// MinGW related workaround
19
#define BOOST_DLL_FORCE_ALIAS_INSTANTIATION
20
#endif
21

22
#include <boost/dll/alias.hpp>
23

24
using namespace simodo;
25
using namespace simodo::variable;
26
using namespace simodo::inout;
27

28
namespace fs = std::filesystem;
29

30
namespace
31
{
32
    Value setup(Module_interface * host, const VariableSetWrapper & args);
33
    Value produceTokens(Module_interface * host, const VariableSetWrapper & args);
34
}
35

36
class MainTokenizer : public Module_interface
37
{
38
    // ModuleFactory_interface *   _factory;
39

40
public:
41
    // MainTokenizer(ModuleFactory_interface * factory) : _factory(factory) {}
42

43
    Value setup(const std::string & path_to_data, const std::string & language);
44
    Value produceTokens(const std::u16string & text_to_parse, int position, context_index_t context);
45

46
    virtual version_t version() const override { return lib_version(); }
47

48
    virtual Object instantiate(std::shared_ptr<variable::Module_interface> module_object) override
49
    {
50
        return Object {{
51
            // {u"version", u"0.1"},
52
            {u"specialization", u"Comment"},
53
            {u"setup", {ValueType::Function, Object {{
54
                {u"@", ExternalFunction {module_object, ::setup}},
55
                {{}, ValueType::String},
56
                {u"path_to_data", ValueType::String},
57
                {u"language", ValueType::String},
58
            }}}},
59
            {u"produceTokens", {ValueType::Function, Object {{
60
                {u"@", ExternalFunction {module_object, ::produceTokens}},
61
                {{}, ValueType::Object},
62
                {u"text_to_parse", ValueType::String},
63
                {u"position", ValueType::Int},
64
                {u"context", ValueType::Int},
65
            }}}},
66
        }};
67
    }
68

69
    // virtual ModuleFactory_interface * factory() override { return _factory; }
70

71
    // Factory method
72
    static std::shared_ptr<Module_interface> create() {
73
        return std::make_shared<MainTokenizer>();
74
    }
75
};
76

77
BOOST_DLL_ALIAS(
78
    MainTokenizer::create,    // <-- this function is exported with...
79
    create_simodo_module      // <-- ...this alias name
80
)
81

82
namespace
83
{
84
    Value setup(Module_interface * host, const VariableSetWrapper & args)
85
    {
86
        // Эти условия должны проверяться в вызывающем коде и при необходимости выполняться преобразования
87
        assert(host != nullptr);
88
        assert(args.size() == 2);
89
        assert(args[0].value().type() == ValueType::String);
90
        assert(args[1].value().type() == ValueType::String);
91

92
        MainTokenizer * main = static_cast<MainTokenizer *>(host);
93
        return main->setup(toU8(args[0].value().getString()),
94
                           toU8(args[1].value().getString()));
95
    }
96

97
    Value produceTokens(Module_interface * host, const VariableSetWrapper & args)
98
    {
99
        // Эти условия должны проверяться в вызывающем коде и при необходимости выполняться преобразования
100
        assert(host != nullptr);
101
        assert(args.size() == 3);
102
        assert(args[0].value().type() == ValueType::String);
103
        assert(args[1].value().type() == ValueType::Int);
104
        assert(args[2].value().type() == ValueType::Int);
105

106
        MainTokenizer *        main = static_cast<MainTokenizer *>(host);
107
        context_index_t context = NO_TOKEN_CONTEXT_INDEX;
108
        if (args[2].value().getInt() >= 0 )
109
            context = static_cast<context_index_t>(args[2].value().getInt());
110

111
        return main->produceTokens(args[0].value().getString(), args[1].value().getInt(), context);
112
    }
113

114
}
115

116
Value MainTokenizer::setup(const std::string & /*path_to_data*/, const std::string & language)
117
{
118
    /// @todo Дополнить список поддерживаемых языков
119
    /// @todo Вынести перечень поддерживаемых языков в JSON-файл.
120
    using namespace std::literals;
121
    for(const std::string & ext : {"cpp"s, "java"s})
122
        if (ext == language)
123
            return u""; // ОК
124

125
    return {}; // Не ОК
126
}
127

128
Value MainTokenizer::produceTokens(const std::u16string & text_to_parse, int position, context_index_t )
129
{
130
    /// @todo Нужно проверять только DOXYGEN-комментарии.
131
    /// Не забыть учесть разрывы комментариев на несколько строк.
132

133
    /// @todo Нужно дополнить список ключевых слов DOXYGEN.
134
    /// @todo Нужно вынести ключевые слова в JSON-файл. Для этого использовать метод setup.
135
    std::vector<std::u16string> doxy_keys {
136
        u"brief", u"todo", u"details", u"attention", u"note", u"file", u"author", u"version",
137
        u"date", u"copyright", u"param", u"return", u"deprecated",
138
    };
139

140
    std::u16string::size_type pos;
141
    for(pos=0; pos < text_to_parse.size(); ++pos)
142
        if (text_to_parse[pos] == u'\\' || text_to_parse[pos] == u'@') {
143
            ++pos;
144
            break;
145
        }
146

147
    /// @todo Вообще-то, нужно анализировать не только ключевые слова, но и элементы форматирования.
148
    /// Хотя, вероятно, это будет задача для отдельного токенайзера.
149

150
    Array tokens;
151
    while(pos < text_to_parse.size()) {
152
        for(const std::u16string & key : doxy_keys)
153
            /// @todo Сейчас проверяется только нижний регистр. Нужно уточнить: является ли
154
            /// DOXYGEN регистрозависимым.
155
            if (text_to_parse.substr(pos,key.size()) == key) {
156
                /// @todo Вообще-то, нужно весь комментарий DOXYGEN выделять, как документ,
157
                /// а не как обычный комментарий (у простого комментария и документа семантика разная).
158
                /// Сейчас подсвечиваются только ключевые слова.
159
                /// Но для этого нужно выделять только DOXYGEN-комментарии (см. todo выше).
160
                Object token_data {{
161
                    {u"token",    text_to_parse.substr(pos-1, key.size()+1)},
162
                    {u"type",     u"Doxygen-keyword"},
163
                    {u"position", position + static_cast<int64_t>(pos-1)},
164
                    }};
165
                tokens.values().emplace_back(token_data);
166
                pos += key.size();
167
                break;
168
            }
169

170
        /// @todo Дублирование кода (см. выше), нужно ли убирать?
171
        for(; pos < text_to_parse.size(); ++pos)
172
            if (text_to_parse[pos] == u'\\' || text_to_parse[pos] == u'@') {
173
                ++pos;
174
                break;
175
            }
176
    }
177

178
    return Object {{
179
        {u"tokens", tokens},
180
        }};
181
}
182

183

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

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

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

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