loom
231 строка · 7.9 Кб
1/*
2MIT License
3
4Copyright (c) 2021 МГТУ им. Н.Э. Баумана, кафедра ИУ-6, Михаил Фетисов,
5
6https://bmstu.codes/lsx/simodo/loom
7*/
8
9#include "simodo/variable/Module_interface.h"
10#include "simodo/variable/VariableSetWrapper.h"
11#include "simodo/variable/json/Serialization.h"
12#include "simodo/inout/convert/functions.h"
13#include "simodo/inout/reporter/Reporter_abstract.h"
14#include "simodo/inout/token/Tokenizer.h"
15#include "simodo/inout/token/RefBufferStream.h"
16#include "simodo/variable/json/LexicalParametersLoader.h"
17
18#include <memory>
19#include <filesystem>
20#include <cassert>
21
22#ifdef CROSS_WIN
23// MinGW related workaround
24#define BOOST_DLL_FORCE_ALIAS_INSTANTIATION
25#endif
26
27#include <boost/dll/alias.hpp>
28
29using namespace simodo;
30using namespace simodo::variable;
31using namespace simodo::inout;
32
33namespace fs = std::filesystem;
34
35namespace
36{
37Value setup(Module_interface * host, const VariableSetWrapper & args);
38Value symbols(Module_interface * host, const VariableSetWrapper & args);
39Value comments(Module_interface * host, const VariableSetWrapper & args);
40Value produceTokens(Module_interface * host, const VariableSetWrapper & args);
41}
42
43class MainTokenizer : public Module_interface
44{
45// ModuleFactory_interface * _factory;
46LexicalParameters _lexis;
47bool _lexis_ok = false;
48
49public:
50// MainTokenizer(ModuleFactory_interface * factory) : _factory(factory) {}
51
52Value setup(const std::string & path_to_data, const std::string & language);
53Value symbols();
54Value comments();
55Value produceTokens(const std::u16string & text_to_parse, int position, context_index_t context);
56
57virtual version_t version() const override { return lib_version(); }
58
59virtual Value instantiate(std::shared_ptr<variable::Module_interface> module_object) override
60{
61return {{
62// {u"version", u"0.1"},
63{u"priority", 0},
64{u"setup", {ValueType::Function, Object {{
65{u"@", ExternalFunction {module_object, ::setup}},
66{{}, ValueType::String},
67{u"path_to_data", ValueType::String},
68{u"language", ValueType::String},
69}}}},
70{u"symbols", {ValueType::Function, Object {{
71{u"@", ExternalFunction {module_object, ::symbols}},
72{{}, ValueType::Array},
73}}}},
74{u"comments", {ValueType::Function, Object {{
75{u"@", ExternalFunction {module_object, ::comments}},
76{{}, ValueType::Array},
77}}}},
78{u"produceTokens", {ValueType::Function, Object {{
79{u"@", ExternalFunction {module_object, ::produceTokens}},
80{{}, ValueType::Object},
81{u"text_to_parse", ValueType::String},
82{u"position", ValueType::Int},
83{u"context", ValueType::Int},
84}}}},
85}};
86}
87
88// Factory method
89static std::shared_ptr<Module_interface> create() {
90return std::make_shared<MainTokenizer>();
91}
92};
93
94BOOST_DLL_ALIAS(
95MainTokenizer::create, // <-- this function is exported with...
96create_simodo_module // <-- ...this alias name
97)
98
99namespace
100{
101Value setup(Module_interface * host, const VariableSetWrapper & args)
102{
103// Эти условия должны проверяться в вызывающем коде и при необходимости выполняться преобразования
104assert(host != nullptr);
105assert(args.size() == 2);
106assert(args[0].value().type() == ValueType::String);
107assert(args[1].value().type() == ValueType::String);
108
109MainTokenizer * main = static_cast<MainTokenizer *>(host);
110return main->setup(toU8(args[0].value().getString()),
111toU8(args[1].value().getString()));
112}
113
114Value symbols(Module_interface * host, const VariableSetWrapper & )
115{
116// Эти условия должны проверяться в вызывающем коде и при необходимости выполняться преобразования
117assert(host != nullptr);
118
119MainTokenizer * main = static_cast<MainTokenizer *>(host);
120return main->symbols();
121}
122
123Value comments(Module_interface * host, const VariableSetWrapper & )
124{
125// Эти условия должны проверяться в вызывающем коде и при необходимости выполняться преобразования
126assert(host != nullptr);
127
128MainTokenizer * main = static_cast<MainTokenizer *>(host);
129return main->comments();
130}
131
132Value produceTokens(Module_interface * host, const VariableSetWrapper & args)
133{
134// Эти условия должны проверяться в вызывающем коде и при необходимости выполняться преобразования
135assert(host != nullptr);
136assert(args.size() == 3);
137assert(args[0].value().type() == ValueType::String);
138assert(args[1].value().type() == ValueType::Int);
139assert(args[2].value().type() == ValueType::Int);
140
141MainTokenizer * main = static_cast<MainTokenizer *>(host);
142context_index_t context = NO_TOKEN_CONTEXT_INDEX;
143if (args[2].value().getInt() >= 0 )
144context = static_cast<context_index_t>(args[2].value().getInt());
145
146return main->produceTokens(args[0].value().getString(), args[1].value().getInt(), context);
147}
148
149}
150
151Value MainTokenizer::setup(const std::string & path_to_data, const std::string & language)
152{
153fs::path path_to_lexis = path_to_data;
154path_to_lexis /= "lexis/" + language + ".json";
155
156if (!fs::exists(path_to_lexis))
157return u"Lexical data for " + toU16(language) + u" not found";
158
159_lexis_ok = loadLexicalParameters(path_to_lexis.string(), _lexis);
160if (!_lexis_ok)
161return u"Unable to load file '" + toU16(path_to_lexis.string()) + u"'";
162
163return u"";
164}
165
166Value MainTokenizer::symbols()
167{
168std::vector<variable::Value> result;
169
170result.reserve(_lexis.punctuation_words.size());
171
172for(const std::u16string & s : _lexis.punctuation_words)
173result.push_back(Object {{
174{u"symbol", s},
175{u"type", u"Keyword"},
176}});
177
178return result;
179}
180
181Value MainTokenizer::comments()
182{
183std::vector<variable::Value> result;
184
185for(auto & m : _lexis.markups)
186if (m.type == LexemeType::Comment && m.end.empty()) {
187result.push_back(m.start);
188break;
189}
190
191for(auto & m : _lexis.markups)
192if (m.type == LexemeType::Comment && !m.end.empty()) {
193result.push_back(m.start);
194result.push_back(m.end);
195break;
196}
197
198return result;
199}
200
201Value MainTokenizer::produceTokens(const std::u16string & text_to_parse, int position, context_index_t context)
202{
203if (!_lexis_ok)
204return Object {};
205
206RefBufferStream stream(text_to_parse.data());
207Tokenizer tokenizer(0, stream, _lexis, context);
208Token t = tokenizer.getAnyToken();
209Array tokens;
210
211context = t.context();
212while(t.type() != LexemeType::Empty) {
213const char * type = t.qualification() != TokenQualification::None
214? getQualificationName(t.qualification())
215: getLexemeTypeName(t.type());
216Object token_data {{
217{u"token", t.token()},
218{u"lexeme", t.lexeme()},
219{u"type", inout::toU16(type)},
220{u"position", position + static_cast<int64_t>(t.location().range().start().character())},
221}};
222tokens.add(token_data);
223context = t.context();
224t = tokenizer.getAnyToken();
225}
226
227return Object {{
228{u"tokens", tokens},
229{u"context", static_cast<int64_t>(context == NO_TOKEN_CONTEXT_INDEX ? -1 : context)}
230}};
231}
232
233